diff --git a/.gitignore b/.gitignore index 92368d784d..2b2ae770ee 100644 --- a/.gitignore +++ b/.gitignore @@ -135,3 +135,4 @@ client_secrets.json dependency-reduced-pom.xml mage-bundle +/Mage.Client/game-*.json diff --git a/Mage.Client/pom.xml b/Mage.Client/pom.xml index c37a0646de..40fcfe1b91 100644 --- a/Mage.Client/pom.xml +++ b/Mage.Client/pom.xml @@ -15,6 +15,7 @@ Mage Client + org.mage mage @@ -68,6 +69,11 @@ jetlang 0.2.9 + + com.amazonaws + aws-java-sdk-s3 + 1.11.286 + com.jgoodies forms @@ -147,14 +153,9 @@ https://stackoverflow.com/questions/714243/sax2-driver-class-org-apache-crimson-parser-xmlreaderimpl-not-found-when-using --> - batik - batik-transcoder - 1.6-1 - - - crimson - crimson - 1.1.3 + org.apache.xmlgraphics + batik-transcoder + 1.7 diff --git a/Mage.Client/src/main/java/mage/client/deckeditor/CardSelector.form b/Mage.Client/src/main/java/mage/client/deckeditor/CardSelector.form index e9b349e111..17513f7a0d 100644 --- a/Mage.Client/src/main/java/mage/client/deckeditor/CardSelector.form +++ b/Mage.Client/src/main/java/mage/client/deckeditor/CardSelector.form @@ -645,6 +645,8 @@ + + @@ -659,6 +661,7 @@ + @@ -846,6 +849,29 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Mage.Client/src/main/java/mage/client/deckeditor/CardSelector.java b/Mage.Client/src/main/java/mage/client/deckeditor/CardSelector.java index d23a409824..f6fc566cef 100644 --- a/Mage.Client/src/main/java/mage/client/deckeditor/CardSelector.java +++ b/Mage.Client/src/main/java/mage/client/deckeditor/CardSelector.java @@ -232,7 +232,7 @@ public class CardSelector extends javax.swing.JPanel implements ComponentListene FilterCard filter = new FilterCard(); String name = jTextFieldSearch.getText().trim(); - filter.add(new CardTextPredicate(name, chkNames.isSelected(), chkTypes.isSelected(), chkRules.isSelected())); + filter.add(new CardTextPredicate(name, chkNames.isSelected(), chkTypes.isSelected(), chkRules.isSelected(), chkUnique.isSelected())); if (limited) { ArrayList> predicates = new ArrayList<>(); @@ -543,6 +543,7 @@ public class CardSelector extends javax.swing.JPanel implements ComponentListene chkNames = new javax.swing.JCheckBox(); chkTypes = new javax.swing.JCheckBox(); chkRules = new javax.swing.JCheckBox(); + chkUnique = new javax.swing.JCheckBox(); jButtonSearch = new javax.swing.JButton(); jButtonClean = new javax.swing.JButton(); cardCountLabel = new javax.swing.JLabel(); @@ -1062,6 +1063,22 @@ public class CardSelector extends javax.swing.JPanel implements ComponentListene chkRulesActionPerformed(evt); } }); + + chkUnique.setSelected(true); + chkUnique.setText("Unique"); + chkUnique.setToolTipText("Singleton results only."); + chkUnique.setFocusable(false); + chkUnique.setHorizontalTextPosition(javax.swing.SwingConstants.RIGHT); + chkUnique.setMaximumSize(new java.awt.Dimension(69, 16)); + chkUnique.setMinimumSize(new java.awt.Dimension(69, 16)); + chkUnique.setPreferredSize(new java.awt.Dimension(69, 16)); + chkUnique.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + chkUnique.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + chkUniqueActionPerformed(evt); + } + }); + jButtonSearch.setText("Search"); jButtonSearch.setToolTipText("Performs the search."); @@ -1109,6 +1126,8 @@ public class CardSelector extends javax.swing.JPanel implements ComponentListene .addComponent(chkTypes, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(chkRules, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(chkUnique, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addGap(5, 5, 5) .addComponent(cardCountLabel) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) @@ -1122,6 +1141,7 @@ public class CardSelector extends javax.swing.JPanel implements ComponentListene .addGroup(cardSelectorBottomPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addComponent(chkTypes, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addComponent(chkRules, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(chkUnique, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addComponent(chkNames, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addGroup(cardSelectorBottomPanelLayout.createSequentialGroup() .addGroup(cardSelectorBottomPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) @@ -1341,6 +1361,10 @@ public class CardSelector extends javax.swing.JPanel implements ComponentListene // TODO add your handling code here: }//GEN-LAST:event_chkRulesActionPerformed + private void chkUniqueActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_chkRulesActionPerformed + // TODO add your handling code here: + }//GEN-LAST:event_chkRulesActionPerformed + private void btnExpansionSearchActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnExpansionSearchActionPerformed FastSearchUtil.showFastSearchForStringComboBox(cbExpansionSet, "Select set or expansion"); }//GEN-LAST:event_btnExpansionSearchActionPerformed @@ -1418,6 +1442,7 @@ public class CardSelector extends javax.swing.JPanel implements ComponentListene private javax.swing.JCheckBox chkPennyDreadful; private javax.swing.JCheckBox chkPiles; private javax.swing.JCheckBox chkRules; + private javax.swing.JCheckBox chkUnique; private javax.swing.JCheckBox chkTypes; private javax.swing.JButton jButtonAddToMain; private javax.swing.JButton jButtonAddToSideboard; diff --git a/Mage.Client/src/main/java/mage/client/dialog/NewTableDialog.form b/Mage.Client/src/main/java/mage/client/dialog/NewTableDialog.form index a5a176504e..ff7ddd6845 100644 --- a/Mage.Client/src/main/java/mage/client/dialog/NewTableDialog.form +++ b/Mage.Client/src/main/java/mage/client/dialog/NewTableDialog.form @@ -41,6 +41,9 @@ + + + @@ -152,6 +155,7 @@ + @@ -274,6 +278,13 @@ + + + + + + + diff --git a/Mage.Client/src/main/java/mage/client/dialog/NewTableDialog.java b/Mage.Client/src/main/java/mage/client/dialog/NewTableDialog.java index 10413c6787..337475674e 100644 --- a/Mage.Client/src/main/java/mage/client/dialog/NewTableDialog.java +++ b/Mage.Client/src/main/java/mage/client/dialog/NewTableDialog.java @@ -102,6 +102,7 @@ public class NewTableDialog extends MageDialog { lblGameType = new javax.swing.JLabel(); cbGameType = new javax.swing.JComboBox(); chkRollbackTurnsAllowed = new javax.swing.JCheckBox(); + chkSpectatorsAllowed = new javax.swing.JCheckBox(); chkRated = new javax.swing.JCheckBox(); lblFreeMulligans = new javax.swing.JLabel(); spnFreeMulligans = new javax.swing.JSpinner(); @@ -151,6 +152,9 @@ public class NewTableDialog extends MageDialog { chkRollbackTurnsAllowed.setText("Allow rollbacks"); chkRollbackTurnsAllowed.setToolTipText("Allow to rollback to the start of previous turns
\nif all players agree.\n"); + chkSpectatorsAllowed.setText("Allow Spectators"); + chkSpectatorsAllowed.setToolTipText("Allow spectators to watch.\n"); + chkRated.setText("Rated"); chkRated.setToolTipText("Indicates if matches will be rated."); @@ -231,7 +235,9 @@ public class NewTableDialog extends MageDialog { .addGap(13, 13, 13) .addComponent(lblFreeMulligans) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(spnFreeMulligans, javax.swing.GroupLayout.PREFERRED_SIZE, 50, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addComponent(spnFreeMulligans, javax.swing.GroupLayout.PREFERRED_SIZE, 50, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGap(13, 13, 13) + .addComponent(chkSpectatorsAllowed)) .addGroup(layout.createSequentialGroup() .addComponent(txtName, javax.swing.GroupLayout.PREFERRED_SIZE, 178, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) @@ -325,7 +331,8 @@ public class NewTableDialog extends MageDialog { .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addComponent(spnFreeMulligans, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(lblFreeMulligans) - .addComponent(chkRollbackTurnsAllowed)) + .addComponent(chkRollbackTurnsAllowed) + .addComponent(chkSpectatorsAllowed)) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addComponent(cbGameType, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(lblGameType))) @@ -401,6 +408,7 @@ public class NewTableDialog extends MageDialog { options.setRange((RangeOfInfluence) this.cbRange.getSelectedItem()); options.setWinsNeeded((Integer) this.spnNumWins.getValue()); options.setRollbackTurnsAllowed(chkRollbackTurnsAllowed.isSelected()); + options.setSpectatorsAllowed(chkSpectatorsAllowed.isSelected()); options.setRated(chkRated.isSelected()); options.setFreeMulligans((Integer) this.spnFreeMulligans.getValue()); options.setPassword(this.txtPassword.getText()); @@ -658,6 +666,7 @@ public class NewTableDialog extends MageDialog { } this.spnNumWins.setValue(Integer.parseInt(PreferencesDialog.getCachedValue(PreferencesDialog.KEY_NEW_TABLE_NUMBER_OF_WINS + versionStr, "2"))); this.chkRollbackTurnsAllowed.setSelected(PreferencesDialog.getCachedValue(PreferencesDialog.KEY_NEW_TABLE_ROLLBACK_TURNS_ALLOWED + versionStr, "Yes").equals("Yes")); + this.chkSpectatorsAllowed.setSelected(PreferencesDialog.getCachedValue(PreferencesDialog.KEY_NEW_TABLE_SPECTATORS_ALLOWED + versionStr, "Yes").equals("Yes")); this.chkRated.setSelected(PreferencesDialog.getCachedValue(PreferencesDialog.KEY_NEW_TABLE_RATED + versionStr, "No").equals("Yes")); this.spnFreeMulligans.setValue(Integer.parseInt(PreferencesDialog.getCachedValue(PreferencesDialog.KEY_NEW_TABLE_NUMBER_OF_FREE_MULLIGANS + versionStr, "0"))); @@ -739,6 +748,7 @@ public class NewTableDialog extends MageDialog { private javax.swing.JComboBox cbSkillLevel; private javax.swing.JComboBox cbTimeLimit; private javax.swing.JCheckBox chkRollbackTurnsAllowed; + private javax.swing.JCheckBox chkSpectatorsAllowed; private javax.swing.JCheckBox chkRated; private javax.swing.JLabel jLabel1; private javax.swing.JLabel jLabel2; diff --git a/Mage.Client/src/main/java/mage/client/dialog/PreferencesDialog.java b/Mage.Client/src/main/java/mage/client/dialog/PreferencesDialog.java index 831900e297..869694af4f 100644 --- a/Mage.Client/src/main/java/mage/client/dialog/PreferencesDialog.java +++ b/Mage.Client/src/main/java/mage/client/dialog/PreferencesDialog.java @@ -229,6 +229,7 @@ public class PreferencesDialog extends javax.swing.JDialog { public static final String KEY_NEW_TABLE_GAME_TYPE = "newTableGameType"; public static final String KEY_NEW_TABLE_NUMBER_OF_WINS = "newTableNumberOfWins"; public static final String KEY_NEW_TABLE_ROLLBACK_TURNS_ALLOWED = "newTableRollbackTurnsAllowed"; + public static final String KEY_NEW_TABLE_SPECTATORS_ALLOWED = "newTableSpectatorsAllowed"; public static final String KEY_NEW_TABLE_NUMBER_OF_FREE_MULLIGANS = "newTableNumberOfFreeMulligans"; public static final String KEY_NEW_TABLE_DECK_FILE = "newTableDeckFile"; public static final String KEY_NEW_TABLE_RANGE = "newTableRange"; diff --git a/Mage.Client/src/main/java/mage/client/game/FeedbackPanel.java b/Mage.Client/src/main/java/mage/client/game/FeedbackPanel.java index 5992f5a424..de2eb91505 100644 --- a/Mage.Client/src/main/java/mage/client/game/FeedbackPanel.java +++ b/Mage.Client/src/main/java/mage/client/game/FeedbackPanel.java @@ -64,7 +64,6 @@ public class FeedbackPanel extends javax.swing.JPanel { private static final Logger LOGGER = Logger.getLogger(FeedbackPanel.class); public enum FeedbackMode { - INFORM, QUESTION, CONFIRM, CANCEL, SELECT, END } diff --git a/Mage.Client/src/main/java/mage/client/game/HelperPanel.java b/Mage.Client/src/main/java/mage/client/game/HelperPanel.java index 04ccc0db76..1bd86d7a3d 100644 --- a/Mage.Client/src/main/java/mage/client/game/HelperPanel.java +++ b/Mage.Client/src/main/java/mage/client/game/HelperPanel.java @@ -394,7 +394,7 @@ public class HelperPanel extends JPanel { } } else { // inform about other players - this.setOpaque(false); + this.mainPanel.setOpaque(false); } if (buttons.size() == 0) { diff --git a/Mage.Client/src/main/java/mage/client/remote/CallbackClientImpl.java b/Mage.Client/src/main/java/mage/client/remote/CallbackClientImpl.java index 386c2156a6..758758e7ae 100644 --- a/Mage.Client/src/main/java/mage/client/remote/CallbackClientImpl.java +++ b/Mage.Client/src/main/java/mage/client/remote/CallbackClientImpl.java @@ -47,6 +47,8 @@ import mage.client.util.audio.AudioManager; import mage.client.util.object.SaveObjectUtil; import mage.interfaces.callback.CallbackClient; import mage.interfaces.callback.ClientCallback; +import mage.remote.ActionData; +import mage.remote.Session; import mage.utils.CompressUtil; import mage.view.*; import mage.view.ChatMessage.MessageType; @@ -102,7 +104,6 @@ public class CallbackClientImpl implements CallbackClient { break; case CHATMESSAGE: { ChatMessage message = (ChatMessage) callback.getData(); - // Drop messages from ignored users if (message.getUsername() != null && IgnoreList.IGNORED_MESSAGE_TYPES.contains(message.getMessageType())) { final String serverAddress = SessionHandler.getSession().getServerHostname().orElseGet(() -> ""); @@ -183,13 +184,22 @@ public class CallbackClientImpl implements CallbackClient { case GAME_INIT: { GamePanel panel = MageFrame.getGame(callback.getObjectId()); if (panel != null) { + appendJsonEvent("GAME_INIT", callback.getObjectId(), (GameView) callback.getData()); panel.init((GameView) callback.getData()); } break; } case GAME_OVER: { + GamePanel panel = MageFrame.getGame(callback.getObjectId()); + if (panel != null) { + appendJsonEvent("GAME_OVER", callback.getObjectId(), callback.getData()); + ActionData actionData = appendJsonEvent("GAME_OVER", callback.getObjectId(), callback.getData()); + String logFileName = "game-" + actionData.gameId + ".json"; + + S3Uploader.upload(logFileName, actionData.gameId.toString()); + panel.endMessage((String) callback.getData(), callback.getMessageId()); } break; @@ -201,6 +211,7 @@ public class CallbackClientImpl implements CallbackClient { GameClientMessage message = (GameClientMessage) callback.getData(); GamePanel panel = MageFrame.getGame(callback.getObjectId()); if (panel != null) { + appendJsonEvent("GAME_ASK", callback.getObjectId(), message); panel.ask(message.getMessage(), message.getGameView(), callback.getMessageId(), message.getOptions()); } break; @@ -208,8 +219,10 @@ public class CallbackClientImpl implements CallbackClient { case GAME_TARGET: // e.g. Pick triggered ability { GameClientMessage message = (GameClientMessage) callback.getData(); + GamePanel panel = MageFrame.getGame(callback.getObjectId()); if (panel != null) { + appendJsonEvent("GAME_TARGET", callback.getObjectId(), message); panel.pickTarget(message.getMessage(), message.getCardsView(), message.getGameView(), message.getTargets(), message.isFlag(), message.getOptions(), callback.getMessageId()); } @@ -217,8 +230,10 @@ public class CallbackClientImpl implements CallbackClient { } case GAME_SELECT: { GameClientMessage message = (GameClientMessage) callback.getData(); + GamePanel panel = MageFrame.getGame(callback.getObjectId()); if (panel != null) { + appendJsonEvent("GAME_SELECT", callback.getObjectId(), message); panel.select(message.getMessage(), message.getGameView(), callback.getMessageId(), message.getOptions()); } break; @@ -226,6 +241,7 @@ public class CallbackClientImpl implements CallbackClient { case GAME_CHOOSE_ABILITY: { GamePanel panel = MageFrame.getGame(callback.getObjectId()); if (panel != null) { + appendJsonEvent("GAME_CHOOSE_PILE", callback.getObjectId(), callback.getData()); panel.pickAbility((AbilityPickerView) callback.getData()); } break; @@ -234,15 +250,18 @@ public class CallbackClientImpl implements CallbackClient { GameClientMessage message = (GameClientMessage) callback.getData(); GamePanel panel = MageFrame.getGame(callback.getObjectId()); if (panel != null) { + appendJsonEvent("GAME_CHOOSE_PILE", callback.getObjectId(), message); panel.pickPile(message.getMessage(), message.getPile1(), message.getPile2()); } break; } case GAME_CHOOSE_CHOICE: { GameClientMessage message = (GameClientMessage) callback.getData(); + GamePanel panel = MageFrame.getGame(callback.getObjectId()); if (panel != null) { + appendJsonEvent("GAME_CHOOSE_CHOICE", callback.getObjectId(), message); panel.getChoice(message.getChoice(), callback.getObjectId()); } break; @@ -251,35 +270,45 @@ public class CallbackClientImpl implements CallbackClient { GameClientMessage message = (GameClientMessage) callback.getData(); GamePanel panel = MageFrame.getGame(callback.getObjectId()); if (panel != null) { + appendJsonEvent("GAME_PLAY_MANA", callback.getObjectId(), message); panel.playMana(message.getMessage(), message.getGameView(), message.getOptions(), callback.getMessageId()); } break; } case GAME_PLAY_XMANA: { GameClientMessage message = (GameClientMessage) callback.getData(); + GamePanel panel = MageFrame.getGame(callback.getObjectId()); if (panel != null) { + appendJsonEvent("GAME_PLAY_XMANA", callback.getObjectId(), message); panel.playXMana(message.getMessage(), message.getGameView(), callback.getMessageId()); } break; } case GAME_GET_AMOUNT: { GameClientMessage message = (GameClientMessage) callback.getData(); + GamePanel panel = MageFrame.getGame(callback.getObjectId()); if (panel != null) { + appendJsonEvent("GAME_GET_AMOUNT", callback.getObjectId(), message); + panel.getAmount(message.getMin(), message.getMax(), message.getMessage()); } break; } case GAME_UPDATE: { GamePanel panel = MageFrame.getGame(callback.getObjectId()); + if (panel != null) { + appendJsonEvent("GAME_UPDATE", callback.getObjectId(), callback.getData()); + panel.updateGame((GameView) callback.getData()); } break; } case END_GAME_INFO: MageFrame.getInstance().showGameEndDialog((GameEndView) callback.getData()); + break; case SHOW_USERMESSAGE: List messageData = (List) callback.getData(); @@ -293,6 +322,7 @@ public class CallbackClientImpl implements CallbackClient { GameClientMessage message = (GameClientMessage) callback.getData(); GamePanel panel = MageFrame.getGame(callback.getObjectId()); if (panel != null) { + appendJsonEvent("GAME_INFORM", callback.getObjectId(), message); panel.inform(message.getMessage(), message.getGameView(), callback.getMessageId()); } } @@ -376,6 +406,14 @@ public class CallbackClientImpl implements CallbackClient { }); } + private ActionData appendJsonEvent(String name, UUID gameId, Object value) { + Session session = SessionHandler.getSession(); + ActionData actionData = new ActionData(name, gameId); + actionData.value = value; + session.appendJsonLog(actionData); + return actionData; + } + private void createChatStartMessage(ChatPanelBasic chatPanel) { chatPanel.setStartMessageDone(true); ChatPanelBasic usedPanel = chatPanel; diff --git a/Mage.Client/src/main/java/mage/client/remote/S3Uploader.java b/Mage.Client/src/main/java/mage/client/remote/S3Uploader.java new file mode 100644 index 0000000000..35a1b538ce --- /dev/null +++ b/Mage.Client/src/main/java/mage/client/remote/S3Uploader.java @@ -0,0 +1,45 @@ +package mage.client.remote; + +import com.amazonaws.AmazonClientException; +import com.amazonaws.auth.BasicAWSCredentials; +import com.amazonaws.services.s3.transfer.TransferManager; +import com.amazonaws.services.s3.transfer.Upload; +import java.io.File; +import org.apache.log4j.Logger; + +public class S3Uploader { + + private static final Logger logger = Logger.getLogger(S3Uploader.class); + + public static Boolean upload(String filePath, String keyName) throws Exception { + String existingBucketName = System.getenv("S3_BUCKET") != null ? System.getenv("S3_BUCKET") + : "xmage-game-logs-dev"; + + String accessKeyId = System.getenv("AWS_ACCESS_ID"); + String secretKeyId = System.getenv("AWS_SECRET_KEY"); + + if (accessKeyId == null || "".equals(accessKeyId) + || secretKeyId == null || "".equals(secretKeyId) + || existingBucketName == null || "".equals(existingBucketName)) { + logger.info("Aborting json log sync."); + return false; + } + + String path = new File("./" + filePath).getCanonicalPath(); + logger.info("Syncing " + path + " to bucket: " + existingBucketName + " with AWS Access Id: " + accessKeyId); + + BasicAWSCredentials awsCreds = new BasicAWSCredentials(accessKeyId, secretKeyId); + TransferManager tm = new TransferManager(awsCreds); + Upload upload = tm.upload(existingBucketName, "/game/" + keyName + ".json", new File(path)); + + try { + upload.waitForUploadResult(); + logger.info("Sync Complete For " + path + " to bucket: " + existingBucketName + " with AWS Access Id: " + accessKeyId); + new File(path); + return true; + } catch (AmazonClientException amazonClientException) { + logger.fatal("Unable to upload file, upload was aborted.", amazonClientException); + return false; + } + } +} diff --git a/Mage.Client/src/main/java/mage/client/table/TablesPanel.java b/Mage.Client/src/main/java/mage/client/table/TablesPanel.java index 547282f16d..5c11b3c6dc 100644 --- a/Mage.Client/src/main/java/mage/client/table/TablesPanel.java +++ b/Mage.Client/src/main/java/mage/client/table/TablesPanel.java @@ -1444,11 +1444,14 @@ class TableTableModel extends AbstractTableModel { if (tables[arg0].isTournament()) { return "Show"; } else { - owner = tables[arg0].getControllerName(); + owner = tables[arg0].getControllerName(); if (SessionHandler.getSession() != null && owner.equals(SessionHandler.getUserName())) { return ""; } - return "Watch"; + if (tables[arg0].getSpectatorsAllowed()) { + return "Watch"; + } + return ""; } default: return ""; diff --git a/Mage.Client/src/main/java/org/mage/card/arcane/CardPanelRenderImpl.java b/Mage.Client/src/main/java/org/mage/card/arcane/CardPanelRenderImpl.java index 950069c3fb..498778c2b3 100644 --- a/Mage.Client/src/main/java/org/mage/card/arcane/CardPanelRenderImpl.java +++ b/Mage.Client/src/main/java/org/mage/card/arcane/CardPanelRenderImpl.java @@ -302,7 +302,7 @@ public class CardPanelRenderImpl extends CardPanel { = new CardPanelAttributes(cardWidth, cardHeight, isChoosable(), isSelected()); // Draw card itself - cardRenderer.draw(g2d, attribs); + cardRenderer.draw(g2d, attribs, image); // Done g2d.dispose(); diff --git a/Mage.Client/src/main/java/org/mage/card/arcane/CardRenderer.java b/Mage.Client/src/main/java/org/mage/card/arcane/CardRenderer.java index 35ec4fc214..d32fa0cdd0 100644 --- a/Mage.Client/src/main/java/org/mage/card/arcane/CardRenderer.java +++ b/Mage.Client/src/main/java/org/mage/card/arcane/CardRenderer.java @@ -17,10 +17,10 @@ import mage.view.PermanentView; import java.awt.*; import java.awt.geom.Rectangle2D; -import java.awt.image.BufferedImage; import java.awt.image.RasterFormatException; import java.util.ArrayList; import java.util.List; +import java.awt.image.BufferedImage; /** * @author stravant@gmail.com @@ -201,7 +201,8 @@ public abstract class CardRenderer { // The Draw Method // The draw method takes the information caculated by the constructor // and uses it to draw to a concrete size of card and graphics. - public void draw(Graphics2D g, CardPanelAttributes attribs) { + public void draw(Graphics2D g, CardPanelAttributes attribs, BufferedImage image) { + // Pre template method layout, to calculate shared layout info layout(attribs.cardWidth, attribs.cardHeight); isSelected = attribs.isSelected; @@ -211,7 +212,7 @@ public abstract class CardRenderer { drawBorder(g); drawBackground(g); drawArt(g); - drawFrame(g); + drawFrame(g, image); if (!cardView.isAbility()) { drawOverlays(g); drawCounters(g); @@ -226,7 +227,7 @@ public abstract class CardRenderer { protected abstract void drawArt(Graphics2D g); - protected abstract void drawFrame(Graphics2D g); + protected abstract void drawFrame(Graphics2D g, BufferedImage image); // Template methods that are possible to override, but unlikely to be // overridden. @@ -462,22 +463,44 @@ public abstract class CardRenderer { } } else { StringBuilder sbType = new StringBuilder(); - for (SuperType superType : cardView.getSuperTypes()) { - sbType.append(superType).append(' '); - } - for (CardType cardType : cardView.getCardTypes()) { - sbType.append(cardType.toString()).append(' '); - } - if (!cardView.getSubTypes().isEmpty()) { - sbType.append("- "); - for (SubType subType : cardView.getSubTypes()) { - sbType.append(subType).append(' '); + String spType = getCardSuperTypeLine(); + String subType = getCardSubTypeLine(); + if (spType.equalsIgnoreCase("")) { + sbType.append(subType); + } else { + sbType.append(spType); + if (!subType.equalsIgnoreCase("")) { + sbType.append("- "); + sbType.append(subType); } } + return sbType.toString(); } } + protected String getCardSuperTypeLine() { + StringBuilder spType = new StringBuilder(); + for (SuperType superType : cardView.getSuperTypes()) { + spType.append(superType).append(' '); + } + for (CardType cardType : cardView.getCardTypes()) { + spType.append(cardType.toString()).append(' '); + } + return spType.toString(); + } + + protected String getCardSubTypeLine() { + StringBuilder subType = new StringBuilder(); + + if (!cardView.getSubTypes().isEmpty()) { + for (SubType sType : cardView.getSubTypes()) { + subType.append(sType).append(' '); + } + } + return subType.toString(); + } + // Set the card art image (CardPanel will give it to us when it // is loaded and ready) public void setArtImage(Image image) { diff --git a/Mage.Client/src/main/java/org/mage/card/arcane/CardRendererUtils.java b/Mage.Client/src/main/java/org/mage/card/arcane/CardRendererUtils.java index eca040234f..3702f176cb 100644 --- a/Mage.Client/src/main/java/org/mage/card/arcane/CardRendererUtils.java +++ b/Mage.Client/src/main/java/org/mage/card/arcane/CardRendererUtils.java @@ -51,8 +51,8 @@ public final class CardRendererUtils { // Return the buffered image return bimage; } - - private static Color abitbrighter(Color c) { + + public static Color abitbrighter(Color c) { int r = c.getRed(); int g = c.getGreen(); int b = c.getBlue(); @@ -68,7 +68,7 @@ public final class CardRendererUtils { alpha); } - private static Color abitdarker(Color c) { + public static Color abitdarker(Color c) { int r = c.getRed(); int g = c.getGreen(); int b = c.getBlue(); @@ -108,6 +108,35 @@ public final class CardRendererUtils { g.drawLine(x + 1 + bevel, y + h - 2, x + 1 + bevel + w - 2 * bevel - 2, y + h - 2); } + public static void drawZendikarLandBox(Graphics2D g, int x, int y, int w, int h, int bevel, Paint border, Paint fill) { + g.setColor(new Color(0, 0, 0, 150)); + + g.drawOval(x - 1, y, bevel * 2, h); + g.setPaint(border); + g.drawOval(x, y, bevel * 2 - 1, h - 1); + g.drawOval(x + w - bevel * 2, y, bevel * 2 - 1, h - 1); + g.drawOval(x + 1, y + 1, bevel * 2 - 3, h - 3); + g.drawOval(x + 1 + w - bevel * 2, y + 1, bevel * 2 - 3, h - 3); + + // The big circle in the middle.. (diameter=2+1/4 of height) - 3/4 above line, 1/2 below 0.75 + .5 + 1= 2.25 = 9/4 + g.drawOval(x + w / 2 - h - h / 8, y - 3 * h / 4, 9 * h / 4, 9 * h / 4); + + g.drawRect(x + bevel, y, w - 2 * bevel, h - 1); + g.drawRect(x + 1 + bevel, y + 1, w - 2 * bevel - 2, h - 3); + g.setPaint(fill); + g.setColor(abitbrighter(g.getColor())); + g.drawLine(x + 1 + bevel, y + 1, x + 1 + bevel + w - 2 * bevel - 2, y + 1); + g.setPaint(fill); + g.setColor(abitdarker(g.getColor())); + g.drawLine(x + 1 + bevel, y + h - 2, x + 1 + bevel + w - 2 * bevel - 2, y + h - 2); + + g.fillOval(x + 2, y + 2, bevel * 2 - 4, h - 4); + g.fillOval(x + 2 + w - bevel * 2, y + 2, bevel * 2 - 4, h - 4); + g.fillRect(x + bevel, y + 2, w - 2 * bevel, h - 4); + + g.fillOval(x + w / 2 - h - h / 8, y - 3 * h / 4, 9 * h / 4, 9 * h / 4); + } + // Get the width of a mana cost rendered with ManaSymbols.draw public static int getManaCostWidth(String manaCost, int symbolSize) { int width = 0; diff --git a/Mage.Client/src/main/java/org/mage/card/arcane/ModernCardRenderer.java b/Mage.Client/src/main/java/org/mage/card/arcane/ModernCardRenderer.java index a75c12fe63..67e5192061 100644 --- a/Mage.Client/src/main/java/org/mage/card/arcane/ModernCardRenderer.java +++ b/Mage.Client/src/main/java/org/mage/card/arcane/ModernCardRenderer.java @@ -7,7 +7,11 @@ package org.mage.card.arcane; import java.awt.*; import java.awt.font.*; +import java.awt.geom.Arc2D; +import java.awt.geom.Area; +import java.awt.geom.Path2D; import java.awt.geom.Rectangle2D; +import java.awt.geom.RoundRectangle2D; import java.awt.image.BufferedImage; import java.io.IOException; import java.io.InputStream; @@ -68,6 +72,13 @@ public class ModernCardRenderer extends CardRenderer { BufferedImage img = CardRendererUtils.toBufferedImage(icon.getImage()); return new TexturePaint(img, new Rectangle(0, 0, img.getWidth(), img.getHeight())); } + + private static BufferedImage loadBackgroundImage(String name) { + URL url = ModernCardRenderer.class.getResource("/cardrender/background_texture_" + name + ".png"); + ImageIcon icon = new ImageIcon(url); + BufferedImage img = CardRendererUtils.toBufferedImage(icon.getImage()); + return img; + } private static BufferedImage loadFramePart(String name) { URL url = ModernCardRenderer.class.getResource("/cardrender/" + name + ".png"); @@ -97,7 +108,18 @@ public class ModernCardRenderer extends CardRenderer { public static final Paint BG_TEXTURE_ARTIFACT = loadBackgroundTexture("artifact"); public static final Paint BG_TEXTURE_LAND = loadBackgroundTexture("land"); public static final Paint BG_TEXTURE_VEHICLE = loadBackgroundTexture("vehicle"); - + + public static final BufferedImage BG_IMG_WHITE = loadBackgroundImage("white"); + public static final BufferedImage BG_IMG_BLUE = loadBackgroundImage("blue"); + public static final BufferedImage BG_IMG_BLACK = loadBackgroundImage("black"); + public static final BufferedImage BG_IMG_RED = loadBackgroundImage("red"); + public static final BufferedImage BG_IMG_GREEN = loadBackgroundImage("green"); + public static final BufferedImage BG_IMG_GOLD = loadBackgroundImage("gold"); + public static final BufferedImage BG_IMG_ARTIFACT = loadBackgroundImage("artifact"); + public static final BufferedImage BG_IMG_LAND = loadBackgroundImage("land"); + public static final BufferedImage BG_IMG_VEHICLE = loadBackgroundImage("vehicle"); + public static final BufferedImage BG_IMG_COLORLESS = loadBackgroundImage("colorless"); + public static final BufferedImage FRAME_INVENTION = loadFramePart("invention_frame"); public static final Color BORDER_WHITE = new Color(216, 203, 188); @@ -279,27 +301,30 @@ public class ModernCardRenderer extends CardRenderer { // Just draw a brown rectangle drawCardBack(g); } else { - BufferedImage bufferedImage = new BufferedImage(300, 300, BufferedImage.TYPE_INT_RGB); - - // Set texture to paint with - g.setPaint(getBackgroundPaint(cardView.getColor(), cardView.getCardTypes(), cardView.getSubTypes())); + BufferedImage bg = getBackgroundImage(cardView.getColor(), cardView.getCardTypes(), cardView.getSubTypes()); + if (bg == null) { + return; + } + int bgw = bg.getWidth(); + int bgh = bg.getHeight(); // Draw main part (most of card) - g.fillRoundRect( - borderWidth, borderWidth, + RoundRectangle2D rr = new RoundRectangle2D.Double(borderWidth, borderWidth, cardWidth - borderWidth * 2, cardHeight - borderWidth * 4 - cornerRadius * 2, cornerRadius - 1, cornerRadius - 1); + Area a = new Area(rr); - // Draw the M15 rounded "swoosh" at the bottom - g.fillRoundRect( - borderWidth, cardHeight - borderWidth * 4 - cornerRadius * 4, + RoundRectangle2D rr2 = new RoundRectangle2D.Double(borderWidth, cardHeight - borderWidth * 4 - cornerRadius * 4, cardWidth - borderWidth * 2, cornerRadius * 4, cornerRadius * 2, cornerRadius * 2); - - // Draw the cutout into the "swoosh" for the textbox to lie over - g.fillRect( - borderWidth + contentInset, cardHeight - borderWidth * 5, - cardWidth - borderWidth * 2 - contentInset * 2, borderWidth * 2); + a.add(new Area(rr2)); + + // Draw the M15 rounded "swoosh" at the bottom + Rectangle r = new Rectangle(borderWidth + contentInset, cardHeight - borderWidth * 5, cardWidth - borderWidth * 2 - contentInset * 2, borderWidth * 2); + a.add(new Area(r)); + g.setClip(a); + g.drawImage(bg, 0, 0, cardWidth, cardHeight, 0, 0, bgw, bgh, BOX_BLUE, null); + g.setClip(null); } } @@ -312,6 +337,8 @@ public class ModernCardRenderer extends CardRenderer { Rectangle2D rect; if (useInventionFrame()) { rect = new Rectangle2D.Float(0, 0, 1, 1); + } else if (isZendikarFullArtLand()) { + rect = new Rectangle2D.Float(.079f, .11f, .84f, .84f); } else if (cardView.getFrameStyle().isFullArt() || (cardView.isToken())) { rect = new Rectangle2D.Float(.079f, .11f, .84f, .63f); } else { @@ -330,6 +357,10 @@ public class ModernCardRenderer extends CardRenderer { } } + private boolean isZendikarFullArtLand() { + return cardView.getFrameStyle() == FrameStyle.BFZ_FULL_ART_BASIC || cardView.getFrameStyle() == FrameStyle.ZEN_FULL_ART_BASIC; + } + protected boolean isSourceArtFullArt() { int color = artImage.getRGB(0, artImage.getHeight() / 2); return (((color & 0x00FF0000) > 0x00200000) @@ -352,7 +383,7 @@ public class ModernCardRenderer extends CardRenderer { if (artImage != null && !cardView.isFaceDown()) { boolean useFaceArt = false; - if (faceArtImage != null) { + if (faceArtImage != null && !isZendikarFullArtLand()) { useFaceArt = true; } @@ -395,7 +426,7 @@ public class ModernCardRenderer extends CardRenderer { totalContentInset + 1, totalContentInset + boxHeight, contentWidth - 2, typeLineY - totalContentInset - boxHeight, sourceRect, shouldPreserveAspect); - } else { + } else if (!isZendikarFullArtLand()) { drawArtIntoRect(g, totalContentInset + 1, totalContentInset + boxHeight, contentWidth - 2, typeLineY - totalContentInset - boxHeight, @@ -405,7 +436,7 @@ public class ModernCardRenderer extends CardRenderer { } @Override - protected void drawFrame(Graphics2D g) { + protected void drawFrame(Graphics2D g, BufferedImage image) { // Get the card colors to base the frame on ObjectColor frameColors = getFrameObjectColor(); @@ -421,12 +452,13 @@ public class ModernCardRenderer extends CardRenderer { // Draw the main card content border g.setPaint(borderPaint); + if (cardView.getFrameStyle() == FrameStyle.KLD_INVENTION) { g.drawImage(FRAME_INVENTION, 0, 0, cardWidth, cardHeight, null); g.drawRect( totalContentInset, typeLineY, contentWidth - 1, cardHeight - borderWidth * 3 - typeLineY - 1); - } else { + } else if (!isZendikarFullArtLand()) { g.drawRect( totalContentInset, totalContentInset, contentWidth - 1, cardHeight - borderWidth * 3 - totalContentInset - 1); @@ -437,11 +469,13 @@ public class ModernCardRenderer extends CardRenderer { g.setPaint(new Color(255, 255, 255, 150)); } else { g.setPaint(textboxPaint); - } - g.fillRect( - totalContentInset + 1, typeLineY, - contentWidth - 2, cardHeight - borderWidth * 3 - typeLineY - 1); + + if (!isZendikarFullArtLand()) { + g.fillRect( + totalContentInset + 1, typeLineY, + contentWidth - 2, cardHeight - borderWidth * 3 - typeLineY - 1); + } // If it's a planeswalker, extend the textbox left border by some if (cardView.isPlanesWalker()) { @@ -451,7 +485,7 @@ public class ModernCardRenderer extends CardRenderer { cardWidth / 16, cardHeight - typeLineY - boxHeight - borderWidth * 3); } - if (cardView.getFrameStyle() != FrameStyle.KLD_INVENTION) { + if (cardView.getFrameStyle() != FrameStyle.KLD_INVENTION && !isZendikarFullArtLand()) { // Draw a shadow highlight at the right edge of the content frame g.setColor(new Color(0, 0, 0, 100)); g.fillRect( @@ -470,26 +504,31 @@ public class ModernCardRenderer extends CardRenderer { cardWidth - 2 * borderWidth, boxHeight, contentInset, borderPaint, boxColor); - // Draw the type line box - CardRendererUtils.drawRoundedBox(g, - borderWidth, typeLineY, - cardWidth - 2 * borderWidth, boxHeight, - contentInset, - borderPaint, boxColor); + if (!isZendikarFullArtLand()) { + CardRendererUtils.drawRoundedBox(g, + borderWidth, typeLineY, + cardWidth - 2 * borderWidth, boxHeight, + contentInset, + borderPaint, boxColor); - // Draw a small separator between the type line and box, and shadow - // at the left of the texbox, and above the name line - g.setColor(new Color(0, 0, 0, 150)); - g.fillRect( - totalContentInset - 1, totalContentInset - 1, - contentWidth + 1, 1); - g.fillRect( - totalContentInset + 1, typeLineY + boxHeight, - contentWidth - 2, 1); - g.fillRect( - cardWidth - totalContentInset - 1, typeLineY + boxHeight, - 1, cardHeight - borderWidth * 3 - typeLineY - boxHeight); + // Draw a small separator between the type line and box, and shadow + // at the left of the texbox, and above the name line + g.setColor(new Color(0, 0, 0, 150)); + g.fillRect( + totalContentInset - 1, totalContentInset - 1, + contentWidth + 1, 1); + g.fillRect( + totalContentInset + 1, typeLineY + boxHeight, + contentWidth - 2, 1); + g.fillRect( + cardWidth - totalContentInset - 1, typeLineY + boxHeight, + 1, cardHeight - borderWidth * 3 - typeLineY - boxHeight); + // Draw the type line + drawTypeLine(g, getCardTypeLine(), + totalContentInset, typeLineY, + contentWidth, boxHeight, true); + } // Draw the transform circle int nameOffset = drawTransformationCircle(g, borderPaint); @@ -502,20 +541,163 @@ public class ModernCardRenderer extends CardRenderer { totalContentInset + nameOffset, totalContentInset, contentWidth - nameOffset, boxHeight); - // Draw the type line - drawTypeLine(g, getCardTypeLine(), - totalContentInset, typeLineY, - contentWidth, boxHeight); - // Draw the textbox rules - drawRulesText(g, textboxKeywords, textboxRules, - totalContentInset + 2, typeLineY + boxHeight + 2, - contentWidth - 4, cardHeight - typeLineY - boxHeight - 4 - borderWidth * 3); + if (!isZendikarFullArtLand()) { + drawRulesText(g, textboxKeywords, textboxRules, + totalContentInset + 2, typeLineY + boxHeight + 2, + contentWidth - 4, cardHeight - typeLineY - boxHeight - 4 - borderWidth * 3); + } else { + int x = totalContentInset; + int y = typeLineY + boxHeight + (cardHeight - typeLineY - boxHeight - 4 - borderWidth * 3) / 2 - contentInset; + int w = contentWidth; + int h = boxHeight - 4; + + CardRendererUtils.drawZendikarLandBox(g, + x, y, w, h, + contentInset, + borderPaint, boxColor); + drawTypeLine(g, getCardSuperTypeLine(), + totalContentInset + contentInset, typeLineY + boxHeight + (cardHeight - typeLineY - boxHeight - 4 - borderWidth * 3) / 2 - contentInset, + contentWidth / 2 - boxHeight, boxHeight - 4, false); + drawTypeLine(g, getCardSubTypeLine(), + totalContentInset + 4 * contentWidth / 7 + boxHeight, typeLineY + boxHeight + (cardHeight - typeLineY - boxHeight - 4 - borderWidth * 3) / 2 - contentInset, + 3 * contentWidth / 7 - boxHeight - contentInset, boxHeight - 4, true); + + if (cardView.getFrameStyle() == FrameStyle.ZEN_FULL_ART_BASIC) { + // Draw curved lines (old Zendikar land style) - bigger (around 6%) inset on curve on bottom than inset (around 4.5%) on top... + int x2 = x + contentWidth; + int y2 = y; + int thisy = totalContentInset + boxHeight; + drawZendikarCurvedFace(g, image, x, thisy, x2, y2, + boxColor, borderPaint); + } else if (cardView.getFrameStyle() == FrameStyle.BFZ_FULL_ART_BASIC) { + // Draw curved lines (BFZ land style) + int y2 = y; + int yb = totalContentInset + boxHeight; + int topxdelta = 45 * contentWidth / 1000; + int endydelta = 60 * (totalContentInset + y2) / 265; + int x2 = x + contentWidth; + + // Curve ends at 60 out of 265 + drawBFZCurvedFace(g, image, x, yb, x2, y2, + topxdelta, endydelta, + boxColor, borderPaint); + } + + drawRulesText(g, textboxKeywords, textboxRules, + x, y, + w, h); + } // Draw the bottom right stuff drawBottomRight(g, borderPaint, boxColor); } + public void drawZendikarCurvedFace(Graphics2D g2, BufferedImage image, int x, int y, int x2, int y2, + Color boxColor, Paint paint) { + + BufferedImage artToUse = faceArtImage; + boolean hadToUseFullArt = false; + if (faceArtImage == null) { + if (artImage == null) { + return; + } + hadToUseFullArt = true; + artToUse = artImage; + } + int srcW = artToUse.getWidth(); + int srcH = artToUse.getHeight(); + + if (hadToUseFullArt) { + // Get a box based on the standard scan from gatherer. + // Width = 185/223 pixels (centered) + // Height = 220/310, 38 pixels from top + int subx = 19 * srcW / 223; + int suby = 38 * srcH / 310; + artToUse = artImage.getSubimage(subx, suby, 185 * srcW / 223, 220 * srcH / 310); + } + + Path2D.Double curve = new Path2D.Double(); + + int ew = x2 - x; + int eh = 700 * (y2 - y) / 335; + Arc2D arc = new Arc2D.Double(x, y - 197 * eh / 700, ew, eh, 0, 360, Arc2D.OPEN); + Arc2D innerarc = new Arc2D.Double(x + 1, y - 197 * eh / 700 + 1, ew - 2, eh - 2, 0, 360, Arc2D.OPEN); + + curve.append(new Rectangle2D.Double(x, y, x2 - x, y2 - y), false); + g2.setClip(new Rectangle2D.Double(x, y, x2 - x, y2 - y)); + g2.setClip(arc); + + Rectangle2D r = curve.getBounds2D(); + g2.drawImage(artToUse, x, y, x2 - x, y2 - y, null); + g2.setClip(null); + g2.setClip(new Rectangle2D.Double(x, y, x2 - x, y2 - y)); + + g2.setColor(CardRendererUtils.abitdarker(boxColor)); + g2.draw(arc); + g2.setColor(Color.black); + g2.draw(innerarc); + + g2.setClip(null); + } + + public void drawBFZCurvedFace(Graphics2D g2, BufferedImage image, int x, int y, int x2, int y2, + int topxdelta, int endydelta, + Color boxColor, Paint paint) { + BufferedImage artToUse = faceArtImage; + boolean hadToUseFullArt = false; + if (faceArtImage == null) { + if (artImage == null) { + return; + } + hadToUseFullArt = true; + artToUse = artImage; + } + int srcW = artToUse.getWidth(); + int srcH = artToUse.getHeight(); + + if (hadToUseFullArt) { + // Get a box based on the standard scan from gatherer. + // Width = 185/223 pixels (centered) + // Height = 220/310, 38 pixels from top + int subx = 19 * srcW / 223; + int suby = 38 * srcH / 310; + artToUse = artImage.getSubimage(subx, suby, 185 * srcW / 223, 220 * srcH / 310); + } + + Path2D.Double curve = new Path2D.Double(); + curve.moveTo(x + topxdelta, y); + curve.quadTo(x, y + endydelta / 2, x, y + endydelta); + curve.lineTo(x, y2); + curve.lineTo(x2, y2); + curve.lineTo(x2, y + endydelta); + curve.quadTo(x2, y + endydelta / 2, x2 - topxdelta, y); + curve.lineTo(x + topxdelta, y); + + Path2D.Double innercurve = new Path2D.Double(); + innercurve.moveTo(x + topxdelta, y + 1); + innercurve.quadTo(x + 1, y + endydelta / 2, x + 1, y + endydelta); + innercurve.lineTo(x + 1, y2 - 1); + innercurve.lineTo(x2 - 1, y2 - 1); + innercurve.lineTo(x2 - 1, y + endydelta); + innercurve.quadTo(x2 - 1, y + endydelta / 2, x2 - topxdelta, y + 1); + innercurve.lineTo(x + topxdelta, y + 1); + + Rectangle2D r = curve.getBounds2D(); + int minX = (int) r.getX(); + + g2.setClip(curve); + g2.drawImage(artToUse, minX, y, (x2 - x) + (x - minX) * 2, y2 - y, null); + + g2.setClip(null); + g2.setColor(CardRendererUtils.abitdarker(boxColor)); + g2.setPaint(paint); + g2.draw(curve); + + g2.setColor(Color.black); + g2.draw(innercurve); + } + // Draw the name line protected void drawNameLine(Graphics2D g, String baseName, String manaCost, int x, int y, int w, int h) { // Width of the mana symbols @@ -566,13 +748,13 @@ public class ModernCardRenderer extends CardRenderer { } // Draw the type line (color indicator, types, and expansion symbol) - protected void drawTypeLine(Graphics2D g, String baseTypeLine, int x, int y, int w, int h) { + protected void drawTypeLine(Graphics2D g, String baseTypeLine, int x, int y, int w, int h, boolean withSymbol) { // Draw expansion symbol - int expansionSymbolWidth; + int expansionSymbolWidth = 0; if (PreferencesDialog.getCachedValue(PreferencesDialog.KEY_CARD_RENDERING_SET_SYMBOL, "false").equals("false")) { if (cardView.isAbility()) { expansionSymbolWidth = 0; - } else { + } else if (withSymbol) { expansionSymbolWidth = drawExpansionSymbol(g, x, y, w, h); } } else { @@ -792,9 +974,21 @@ public class ModernCardRenderer extends CardRenderer { } // Basic mana draw mana symbol in textbox (for basic lands) - if (allRules.size() == 1 && (allRules.get(0) instanceof TextboxBasicManaRule) && cardView.isLand()) { - drawBasicManaTextbox(g, x, y, w, h, ((TextboxBasicManaRule) allRules.get(0)).getBasicManaSymbol()); - return; + if (allRules.size() == 1 && (allRules.get(0) instanceof TextboxBasicManaRule) && cardView.isLand() || isZendikarFullArtLand()) { + if (!isZendikarFullArtLand()) { + drawBasicManaTextbox(g, x, y, w, h, ((TextboxBasicManaRule) allRules.get(0)).getBasicManaSymbol()); + return; + } else // Big circle in the middle for Zendikar lands + if (allRules.size() == 1) { + // Size of mana symbol = 9/4 * h, 3/4h above line + drawBasicManaSymbol(g, x + w / 2 - 9 * h / 8 + 1, y - 3 * h / 4, 9 * h / 4, 9 * h / 4, ((TextboxBasicManaRule) allRules.get(0)).getBasicManaSymbol()); + return; + } else { + if (allRules.size() > 1) { + drawBasicManaSymbol(g, x + w / 2 - h - h / 8, y - 3 * h / 4, 9 * h / 4, 9 * h / 4, cardView.getFrameColor().toString()); + } + return; + } } // Go through possible font sizes in descending order to find the best fit @@ -847,6 +1041,11 @@ public class ModernCardRenderer extends CardRenderer { ManaSymbols.draw(g, symbs, x + (w - manaCostWidth) / 2, y + (h - symbHeight) / 2, symbHeight, Color.black, 2); } + private void drawBasicManaSymbol(Graphics2D g, int x, int y, int w, int h, String symbol) { + String symbs = symbol; + ManaSymbols.draw(g, symbs, x, y, w, Color.black, 2); + } + // Get the first line of the textbox, the keyword string private static String getKeywordRulesString(ArrayList keywords) { StringBuilder builder = new StringBuilder(); @@ -1073,7 +1272,34 @@ public class ModernCardRenderer extends CardRenderer { return new Color(71, 86, 101); } } - + + // Determine which background image to use from a set of colors + // and the current card. + protected static BufferedImage getBackgroundImage(ObjectColor colors, Collection types, SubTypeList subTypes) { + if (subTypes.contains(SubType.VEHICLE)) { + return BG_IMG_VEHICLE; + } else if (types.contains(CardType.LAND)) { + return BG_IMG_LAND; + } else if (types.contains(CardType.ARTIFACT)) { + return BG_IMG_ARTIFACT; + } else if (colors.isMulticolored()) { + return BG_IMG_GOLD; + } else if (colors.isWhite()) { + return BG_IMG_WHITE; + } else if (colors.isBlue()) { + return BG_IMG_BLUE; + } else if (colors.isBlack()) { + return BG_IMG_BLACK; + } else if (colors.isRed()) { + return BG_IMG_RED; + } else if (colors.isGreen()) { + return BG_IMG_GREEN; + } else { + // Colorless + return BG_IMG_COLORLESS; + } + } + // Get the box color for the given colors protected Color getBoxColor(ObjectColor colors, Collection types, boolean isNightCard) { if (cardView.isAbility()) { diff --git a/Mage.Client/src/main/java/org/mage/card/arcane/ModernSplitCardRenderer.java b/Mage.Client/src/main/java/org/mage/card/arcane/ModernSplitCardRenderer.java index 98d01254c6..0310d8e3ac 100644 --- a/Mage.Client/src/main/java/org/mage/card/arcane/ModernSplitCardRenderer.java +++ b/Mage.Client/src/main/java/org/mage/card/arcane/ModernSplitCardRenderer.java @@ -8,6 +8,7 @@ import mage.view.CardView; import java.awt.*; import java.awt.geom.Rectangle2D; +import java.awt.image.BufferedImage; import java.util.ArrayList; import java.util.List; @@ -17,6 +18,7 @@ import java.util.List; public class ModernSplitCardRenderer extends ModernCardRenderer { private class HalfCardProps { + int x, y, w, h, cw, ch; String name; @@ -27,7 +29,11 @@ public class ModernSplitCardRenderer extends ModernCardRenderer { ArrayList keywords = new ArrayList<>(); } - private static ArrayList ONLY_LAND_TYPE = new ArrayList() {{add(CardType.LAND);}}; + private static ArrayList ONLY_LAND_TYPE = new ArrayList() { + { + add(CardType.LAND); + } + }; // Right and left halves of the card content private HalfCardProps rightHalf = new HalfCardProps(); @@ -88,20 +94,20 @@ public class ModernSplitCardRenderer extends ModernCardRenderer { // Decide size of divider if (isAftermath()) { dividerSize = borderWidth; - dividerAt = (int)(cardHeight*0.54); + dividerAt = (int) (cardHeight * 0.54); } else { - int availHeight = cardHeight - totalContentInset - 3*borderWidth; - dividerSize = borderWidth*2; - dividerAt = (int)(totalContentInset + availHeight * 0.5 - borderWidth); + int availHeight = cardHeight - totalContentInset - 3 * borderWidth; + dividerSize = borderWidth * 2; + dividerAt = (int) (totalContentInset + availHeight * 0.5 - borderWidth); } // Decide size of each halves box rightHalf.x = leftHalf.x = totalContentInset; - rightHalf.w = leftHalf.w = cardWidth - 2*totalContentInset; + rightHalf.w = leftHalf.w = cardWidth - 2 * totalContentInset; leftHalf.y = totalContentInset; leftHalf.h = dividerAt - totalContentInset; rightHalf.y = dividerAt + dividerSize; - rightHalf.h = cardHeight - rightHalf.y - borderWidth*3; + rightHalf.h = cardHeight - rightHalf.y - borderWidth * 3; // Content width / height (Exchanged from width / height if the card part is rotated) if (isAftermath()) { @@ -126,7 +132,7 @@ public class ModernSplitCardRenderer extends ModernCardRenderer { private ObjectColor getColorFromManaCostHack(ManaCosts costs) { ObjectColor c = new ObjectColor(); List symbols = costs.getSymbols(); - for (String symbol: symbols) { + for (String symbol : symbols) { if (symbol.contains("W")) { c.setWhite(true); } else if (symbol.contains("U")) { @@ -154,18 +160,18 @@ public class ModernSplitCardRenderer extends ModernCardRenderer { // Draw main part (most of card) g.fillRoundRect( borderWidth, borderWidth, - cardWidth - 2*borderWidth, leftHalf.h + contentInset - borderWidth - 2*cornerRadius + (cornerRadius - 1), + cardWidth - 2 * borderWidth, leftHalf.h + contentInset - borderWidth - 2 * cornerRadius + (cornerRadius - 1), cornerRadius - 1, cornerRadius - 1); // Draw the M15 rounded "swoosh" at the bottom g.fillRoundRect( - borderWidth, dividerAt - borderWidth - 4*cornerRadius, - cardWidth - 2*borderWidth, cornerRadius * 4, + borderWidth, dividerAt - borderWidth - 4 * cornerRadius, + cardWidth - 2 * borderWidth, cornerRadius * 4, cornerRadius * 2, cornerRadius * 2); // Draw the cutout into the "swoosh" for the textbox to lie over g.fillRect( - borderWidth + contentInset, dividerAt - 2*borderWidth, + borderWidth + contentInset, dividerAt - 2 * borderWidth, cardWidth - borderWidth * 2 - contentInset * 2, borderWidth * 2); } @@ -176,8 +182,8 @@ public class ModernSplitCardRenderer extends ModernCardRenderer { // Draw the M15 rounded "swoosh"es at the top and bottom g.fillRoundRect( borderWidth, dividerAt + dividerSize + borderWidth, - cardWidth - 2*borderWidth, rightHalf.h - 2*borderWidth, - cornerRadius*2, cornerRadius*2); + cardWidth - 2 * borderWidth, rightHalf.h - 2 * borderWidth, + cornerRadius * 2, cornerRadius * 2); // Draw the cutout into the "swoosh" for the textbox to lie over g.fillRect( @@ -236,8 +242,8 @@ public class ModernSplitCardRenderer extends ModernCardRenderer { // Background of textbox g.setPaint(textboxPaint); g.fillRect( - 1, typeLineY, - half.cw - 2, half.ch - typeLineY - 1); + 1, typeLineY, + half.cw - 2, half.ch - typeLineY - 1); // Draw the name line box CardRendererUtils.drawRoundedBox(g, @@ -261,7 +267,7 @@ public class ModernSplitCardRenderer extends ModernCardRenderer { // Draw the type line drawTypeLine(g, half.typeLineString, 0, typeLineY, - half.cw, boxHeight - 4); + half.cw, boxHeight - 4, true); // Draw the textbox rules drawRulesText(g, half.keywords, half.rules, @@ -270,13 +276,13 @@ public class ModernSplitCardRenderer extends ModernCardRenderer { } private Graphics2D getUnmodifiedHalfContext(Graphics2D g) { - Graphics2D g2 = (Graphics2D)g.create(); + Graphics2D g2 = (Graphics2D) g.create(); g2.translate(leftHalf.x, leftHalf.y); return g2; } private Graphics2D getAftermathHalfContext(Graphics2D g) { - Graphics2D g2 = (Graphics2D)g.create(); + Graphics2D g2 = (Graphics2D) g.create(); g2.translate(rightHalf.x, rightHalf.y); g2.rotate(Math.PI / 2); g2.translate(0, -rightHalf.w); @@ -284,7 +290,7 @@ public class ModernSplitCardRenderer extends ModernCardRenderer { } private Graphics2D getLeftHalfContext(Graphics2D g) { - Graphics2D g2 = (Graphics2D)g.create(); + Graphics2D g2 = (Graphics2D) g.create(); g2.translate(leftHalf.x, leftHalf.y); g2.rotate(-Math.PI / 2); g2.translate(-leftHalf.cw, 0); @@ -292,7 +298,7 @@ public class ModernSplitCardRenderer extends ModernCardRenderer { } private Graphics2D getRightHalfContext(Graphics2D g) { - Graphics2D g2 = (Graphics2D)g.create(); + Graphics2D g2 = (Graphics2D) g.create(); g2.translate(rightHalf.x, rightHalf.y); g2.rotate(-Math.PI / 2); g2.translate(-rightHalf.cw, 0); @@ -300,13 +306,13 @@ public class ModernSplitCardRenderer extends ModernCardRenderer { } @Override - protected void drawFrame(Graphics2D g) { + protected void drawFrame(Graphics2D g, BufferedImage image) { if (isAftermath()) { - drawSplitHalfFrame(getUnmodifiedHalfContext(g), leftHalf, (int)(leftHalf.ch * TYPE_LINE_Y_FRAC)); + drawSplitHalfFrame(getUnmodifiedHalfContext(g), leftHalf, (int) (leftHalf.ch * TYPE_LINE_Y_FRAC)); drawSplitHalfFrame(getAftermathHalfContext(g), rightHalf, (rightHalf.ch - boxHeight) / 2); } else { - drawSplitHalfFrame(getLeftHalfContext(g), leftHalf, (int)(leftHalf.ch * TYPE_LINE_Y_FRAC)); - drawSplitHalfFrame(getRightHalfContext(g), rightHalf, (int)(rightHalf.ch * TYPE_LINE_Y_FRAC)); + drawSplitHalfFrame(getLeftHalfContext(g), leftHalf, (int) (leftHalf.ch * TYPE_LINE_Y_FRAC)); + drawSplitHalfFrame(getRightHalfContext(g), rightHalf, (int) (rightHalf.ch * TYPE_LINE_Y_FRAC)); if (isFuse()) { Graphics2D g2 = getRightHalfContext(g); int totalFuseBoxWidth = rightHalf.cw * 2 + 2 * borderWidth + dividerSize; @@ -319,7 +325,7 @@ public class ModernSplitCardRenderer extends ModernCardRenderer { borderPaint, boxColor); drawNameLine(g2, "Fuse (You may cast both halves from your hand)", "", 0, rightHalf.ch, - totalFuseBoxWidth - 2*borderWidth, boxHeight); + totalFuseBoxWidth - 2 * borderWidth, boxHeight); } } } diff --git a/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/GathererSets.java b/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/GathererSets.java index 38b5ff2b43..385204f822 100644 --- a/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/GathererSets.java +++ b/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/GathererSets.java @@ -66,7 +66,7 @@ public class GathererSets implements Iterable { //"APAC" -- gatherer do not have that set, scrly have PALP //"ARENA" -- is't many set with different codes, not one "CLASH", "CP", "DD3GVL", "DPA", "EURO", "FNMP", "GPX", "GRC", "GUR", "H17", "JR", "MBP", "MGDC", "MLP", "MPRP", "MPS-AKH", "PTC", "S00", "S99", "SUS", "SWS", "UGIN", "UGL", "V10", "V17", "WMCQ", // need to fix - "H09", "PD2", "PD3", "UNH", "CM1", "E02", "V11", "M25", "UST", "IMA", "DD2", "EVG", "DDC", "DDE", "DDD", "DDT", "8EB", "9EB", "CHR" // ok + "H09", "PD2", "PD3", "UNH", "CM1", "E02", "V11", "A25", "UST", "IMA", "DD2", "EVG", "DDC", "DDE", "DDD", "DDT", "8EB", "9EB", "CHR" // ok // current testing }; diff --git a/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/ScryfallImageSource.java b/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/ScryfallImageSource.java index 6f664975ff..aafb2d1568 100644 --- a/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/ScryfallImageSource.java +++ b/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/ScryfallImageSource.java @@ -208,7 +208,7 @@ public enum ScryfallImageSource implements CardImageSource { supportedSets.add("RIX"); supportedSets.add("WMCQ"); supportedSets.add("PPRO"); -// supportedSets.add("A25"); + supportedSets.add("A25"); // supportedSets.add("DOM"); // supportedSets.add("M19"); diff --git a/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/WizardCardsImageSource.java b/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/WizardCardsImageSource.java index f13d7fbf1c..db32e1f151 100644 --- a/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/WizardCardsImageSource.java +++ b/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/WizardCardsImageSource.java @@ -268,7 +268,7 @@ public enum WizardCardsImageSource implements CardImageSource { supportedSets.add("V17"); // From the Vault: Transform supportedSets.add("UST"); // Unstable supportedSets.add("RIX"); // Rivals of Ixalan -// supportedSets.add("A25"); // Masters 25 + supportedSets.add("A25"); // Masters 25 // supportedSets.add("DOM"); // Dominaria // supportedSets.add("M19"); // Core 2019 diff --git a/Mage.Client/src/main/resources/cardrender/background_texture_colorless.png b/Mage.Client/src/main/resources/cardrender/background_texture_colorless.png new file mode 100644 index 0000000000..9a27821dab Binary files /dev/null and b/Mage.Client/src/main/resources/cardrender/background_texture_colorless.png differ diff --git a/Mage.Client/src/main/resources/cardrender/background_texture_vehicle.png b/Mage.Client/src/main/resources/cardrender/background_texture_vehicle.png index 2f58f34a36..87282e34bc 100644 Binary files a/Mage.Client/src/main/resources/cardrender/background_texture_vehicle.png and b/Mage.Client/src/main/resources/cardrender/background_texture_vehicle.png differ diff --git a/Mage.Client/src/main/resources/image.url.properties b/Mage.Client/src/main/resources/image.url.properties index 63ffa1a49a..3aba474b2f 100644 --- a/Mage.Client/src/main/resources/image.url.properties +++ b/Mage.Client/src/main/resources/image.url.properties @@ -73,6 +73,6 @@ dd3evg=ddaevg dd3gvl=ddagvl dd3jvc=ddajvc # Remove setname as soon as the images can be downloaded -ignore.urls=TOK,M19,M25,DOM,H17 +ignore.urls=TOK,M19,DOM,H17 # sets ordered by release time (newest goes first) -token.lookup.order=M19,M25,DOM,E02,RIX,UST,XLN,IMA,H17,C17,V17,E01,DDT,CMA,HOU,MM3,DDS,AKH,DD3DVD,DD3EVG,DD3GVL,DD3JVC,H09,AER,PCA,C16,V16,MPS,KLD,DDR,CN2,EMN,EMA,SOI,DDQ,CP,CMA,ARENA,SUS,APAC,EURO,UGIN,C15,OGW,EXP,DDP,BFZ,DRB,V09,V10,V11,V12,V13,V14,V15,TPR,MPRP,DD3,DDO,ORI,MM2,PTC,DTK,FRF,KTK,M15,VMA,CNS,JOU,BNG,THS,DDL,M14,MMA,DGM,GTC,RTR,M13,AVR,DDI,DKA,ISD,M12,NPH,MBS,SOM,M11,ROE,DDE,WWK,ZEN,M10,GVL,ARB,DVD,CFX,JVC,ALA,EVE,SHM,EVG,MOR,LRW,10E,CLS,CHK,GRC \ No newline at end of file +token.lookup.order=M19,A25,DOM,E02,RIX,UST,XLN,IMA,H17,C17,V17,E01,DDT,CMA,HOU,MM3,DDS,AKH,DD3DVD,DD3EVG,DD3GVL,DD3JVC,H09,AER,PCA,C16,V16,MPS,KLD,DDR,CN2,EMN,EMA,SOI,DDQ,CP,CMA,ARENA,SUS,APAC,EURO,UGIN,C15,OGW,EXP,DDP,BFZ,DRB,V09,V10,V11,V12,V13,V14,V15,TPR,MPRP,DD3,DDO,ORI,MM2,PTC,DTK,FRF,KTK,M15,VMA,CNS,JOU,BNG,THS,DDL,M14,MMA,DGM,GTC,RTR,M13,AVR,DDI,DKA,ISD,M12,NPH,MBS,SOM,M11,ROE,DDE,WWK,ZEN,M10,GVL,ARB,DVD,CFX,JVC,ALA,EVE,SHM,EVG,MOR,LRW,10E,CLS,CHK,GRC \ No newline at end of file diff --git a/Mage.Common/pom.xml b/Mage.Common/pom.xml index 27914c196d..17075941d0 100644 --- a/Mage.Common/pom.xml +++ b/Mage.Common/pom.xml @@ -25,6 +25,7 @@ jspf-core 0.9.1
+ org.jboss.remoting jboss-remoting @@ -50,7 +51,11 @@ trove 1.0.2 - + + com.google.code.gson + gson + 2.8.2 +
diff --git a/Mage.Common/src/main/java/mage/remote/ActionData.java b/Mage.Common/src/main/java/mage/remote/ActionData.java new file mode 100644 index 0000000000..51d079a0ac --- /dev/null +++ b/Mage.Common/src/main/java/mage/remote/ActionData.java @@ -0,0 +1,138 @@ +/* + * Copyright 2018 nanarpuss_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.remote; + +import com.google.gson.ExclusionStrategy; +import com.google.gson.FieldAttributes; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.annotations.Expose; +import java.util.UUID; + +public class ActionData { + + @Expose + public UUID gameId; + @Expose + public String sessionId; + @Expose + public String type; + @Expose + public Object value; + @Expose + public String message; + + public String toJson() { + GsonBuilder gsonBuilder = new GsonBuilder(); + Gson gson = gsonBuilder.setExclusionStrategies(new CustomExclusionStrategy()).create(); + + return gson.toJson(this); + } + + public ActionData(String type, UUID gameId, String sessionId) { + this.type = type; + this.sessionId = sessionId; + this.gameId = gameId; + } + + public ActionData(String type, UUID gameId) { + this.type = type; + this.gameId = gameId; + } + + public class CustomExclusionStrategy implements ExclusionStrategy { + + // FIXME: Very crude way of whitelisting, as it applies to all levels of the JSON tree. + private final java.util.Set KEEP = new java.util.HashSet<>( + java.util.Arrays.asList( + new String[]{ + "id", + "choice", + "damage", + "abilityType", + "ability", + "abilities", + "method", + "data", + "options", + "life", + "players", + "zone", + "step", + "phase", + "attackers", + "blockers", + "tapped", + "damage", + "combat", + "paid", + "hand", + "stack", + "convertedManaCost", + "gameId", + "canPlayInHand", + "gameView", + "sessionId", + "power", + "choices", + "targets", + "loyalty", + "toughness", + "power", + "type", + "priorityTime", + "manaCost", + "value", + "message", + "cardsView", + "name", + "count", + "counters", + "battlefield", + "parentId" + })); + + public CustomExclusionStrategy() { + } + + // This method is called for all fields. if the method returns true the + // field is excluded from serialization + @Override + public boolean shouldSkipField(FieldAttributes f) { + String name = f.getName(); + return !KEEP.contains(name); + } + + // This method is called for all classes. If the method returns true the + // class is excluded. + @Override + public boolean shouldSkipClass(Class clazz) { + return false; + } + } +} diff --git a/Mage.Common/src/main/java/mage/remote/Session.java b/Mage.Common/src/main/java/mage/remote/Session.java index 8cb062c63e..e7f04049ca 100644 --- a/Mage.Common/src/main/java/mage/remote/Session.java +++ b/Mage.Common/src/main/java/mage/remote/Session.java @@ -24,8 +24,7 @@ * The views and conclusions contained in the software and documentation are those of the * authors and should not be interpreted as representing official policies, either expressed * or implied, of BetaSteward_at_googlemail.com. -*/ - + */ package mage.remote; import mage.remote.interfaces.ChatSession; @@ -46,4 +45,5 @@ import mage.remote.interfaces.Testable; */ public interface Session extends ClientData, Connect, GamePlay, GameTypes, ServerState, ChatSession, Feedback, PlayerActions, Replays, Testable { + public void appendJsonLog(ActionData actionData); } diff --git a/Mage.Common/src/main/java/mage/remote/SessionImpl.java b/Mage.Common/src/main/java/mage/remote/SessionImpl.java index 187b8179c1..318e628f38 100644 --- a/Mage.Common/src/main/java/mage/remote/SessionImpl.java +++ b/Mage.Common/src/main/java/mage/remote/SessionImpl.java @@ -27,12 +27,14 @@ */ package mage.remote; +import java.io.BufferedWriter; +import java.io.FileWriter; import java.io.IOException; +import java.io.PrintWriter; import java.lang.reflect.UndeclaredThrowableException; import java.net.*; import java.util.*; import java.util.concurrent.TimeUnit; -import javax.swing.*; import mage.MageException; import mage.cards.decks.DeckCardLists; import mage.cards.repository.CardInfo; @@ -799,6 +801,9 @@ public class SessionImpl implements Session { public boolean sendPlayerUUID(UUID gameId, UUID data) { try { if (isConnected()) { + ActionData actionData = new ActionData("SEND_PLAYER_UUID", gameId, getSessionId()); + actionData.value = data; + appendJsonLog(actionData); server.sendPlayerUUID(gameId, sessionId, data); return true; } @@ -814,6 +819,10 @@ public class SessionImpl implements Session { public boolean sendPlayerBoolean(UUID gameId, boolean data) { try { if (isConnected()) { + ActionData actionData = new ActionData("SEND_PLAYER_BOOLEAN", gameId, getSessionId()); + actionData.value = data; + appendJsonLog(actionData); + server.sendPlayerBoolean(gameId, sessionId, data); return true; } @@ -829,6 +838,10 @@ public class SessionImpl implements Session { public boolean sendPlayerInteger(UUID gameId, int data) { try { if (isConnected()) { + ActionData actionData = new ActionData("SEND_PLAYER_INTEGER", gameId, getSessionId()); + actionData.value = data; + appendJsonLog(actionData); + server.sendPlayerInteger(gameId, sessionId, data); return true; } @@ -844,6 +857,10 @@ public class SessionImpl implements Session { public boolean sendPlayerString(UUID gameId, String data) { try { if (isConnected()) { + ActionData actionData = new ActionData("SEND_PLAYER_STRING", gameId, getSessionId()); + actionData.value = data; + appendJsonLog(actionData); + server.sendPlayerString(gameId, sessionId, data); return true; } @@ -859,6 +876,9 @@ public class SessionImpl implements Session { public boolean sendPlayerManaType(UUID gameId, UUID playerId, ManaType data) { try { if (isConnected()) { + ActionData actionData = new ActionData("SEND_PLAYER_MANA_TYPE", gameId, getSessionId()); + actionData.value = data; + appendJsonLog(actionData); server.sendPlayerManaType(gameId, playerId, sessionId, data); return true; } @@ -870,6 +890,17 @@ public class SessionImpl implements Session { return false; } + @Override + public void appendJsonLog(ActionData actionData) { + actionData.sessionId = getSessionId(); + String logFileName = "game-" + actionData.gameId + ".json"; + try (PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter(logFileName, true)))) { + out.println(actionData.toJson()); + } catch (IOException e) { + System.err.println(e); + } + } + @Override public DraftPickView sendCardPick(UUID draftId, UUID cardId, Set hiddenCards) { try { @@ -1275,6 +1306,11 @@ public class SessionImpl implements Session { public boolean sendPlayerAction(PlayerAction passPriorityAction, UUID gameId, Object data) { try { if (isConnected()) { + ActionData actionData = new ActionData("SEND_PLAYER_ACTION", gameId, getSessionId()); + + actionData.value = data; + appendJsonLog(actionData); + server.sendPlayerAction(passPriorityAction, gameId, sessionId, data); return true; } @@ -1437,12 +1473,9 @@ public class SessionImpl implements Session { @Override public boolean endUserSession(String userSessionId) { try { - if (JOptionPane.showConfirmDialog(null, "Are you sure you mean to end userSessionId " + userSessionId + '?', "WARNING", - JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION) { - if (isConnected()) { - server.endUserSession(sessionId, userSessionId); - return true; - } + if (isConnected()) { + server.endUserSession(sessionId, userSessionId); + return true; } } catch (MageException ex) { handleMageException(ex); @@ -1455,12 +1488,9 @@ public class SessionImpl implements Session { @Override public boolean muteUserChat(String userName, long durationMinutes) { try { - if (JOptionPane.showConfirmDialog(null, "Are you sure you mean to mute user " + userName + " for " + durationMinutes + " minutes?", "WARNING", - JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION) { - if (isConnected()) { - server.muteUser(sessionId, userName, durationMinutes); - return true; - } + if (isConnected()) { + server.muteUser(sessionId, userName, durationMinutes); + return true; } } catch (MageException ex) { handleMageException(ex); @@ -1473,12 +1503,9 @@ public class SessionImpl implements Session { @Override public boolean setActivation(String userName, boolean active) { try { - if (JOptionPane.showConfirmDialog(null, "Are you sure you mean to set active to " + active + " for user: " + userName + '?', "WARNING", - JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION) { - if (isConnected()) { - server.setActivation(sessionId, userName, active); - return true; - } + if (isConnected()) { + server.setActivation(sessionId, userName, active); + return true; } } catch (MageException ex) { handleMageException(ex); @@ -1491,20 +1518,9 @@ public class SessionImpl implements Session { @Override public boolean toggleActivation(String userName) { try { - if (JOptionPane.showConfirmDialog(null, "Did you want to set user: " + userName + " to active?", "WARNING", - JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION) { - return setActivation(userName, true); - } - if (JOptionPane.showConfirmDialog(null, "Did you want to set user: " + userName + " to INactive?", "WARNING", - JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION) { - return setActivation(userName, false); - } - if (JOptionPane.showConfirmDialog(null, "Are you sure you mean to toggle activation for user: " + userName + '?', "WARNING", - JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION) { - if (isConnected()) { - server.toggleActivation(sessionId, userName); - return true; - } + if (isConnected()) { + server.toggleActivation(sessionId, userName); + return true; } } catch (MageException ex) { handleMageException(ex); @@ -1517,12 +1533,9 @@ public class SessionImpl implements Session { @Override public boolean lockUser(String userName, long durationMinute) { try { - if (JOptionPane.showConfirmDialog(null, "Are you sure you mean to lock user: " + userName + " for " + durationMinute + " minutes?", "WARNING", - JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION) { - if (isConnected()) { - server.lockUser(sessionId, userName, durationMinute); - return true; - } + if (isConnected()) { + server.lockUser(sessionId, userName, durationMinute); + return true; } } catch (MageException ex) { handleMageException(ex); diff --git a/Mage.Common/src/main/java/mage/view/CardView.java b/Mage.Common/src/main/java/mage/view/CardView.java index d9154f7418..b2ed194eb8 100644 --- a/Mage.Common/src/main/java/mage/view/CardView.java +++ b/Mage.Common/src/main/java/mage/view/CardView.java @@ -53,6 +53,8 @@ import mage.target.Target; import mage.target.Targets; import mage.util.SubTypeList; +import com.google.gson.annotations.Expose; + /** * @author BetaSteward_at_googlemail.com */ @@ -61,11 +63,17 @@ public class CardView extends SimpleCardView { private static final long serialVersionUID = 1L; protected UUID parentId; + @Expose protected String name; + @Expose protected String displayName; + @Expose protected List rules; + @Expose protected String power; + @Expose protected String toughness; + @Expose protected String loyalty = ""; protected String startingLoyalty; protected EnumSet cardTypes; @@ -110,7 +118,6 @@ public class CardView extends SimpleCardView { protected ArtRect artRect = ArtRect.NORMAL; protected List targets; - protected UUID pairedCard; protected List bandedCards; protected boolean paid; diff --git a/Mage.Common/src/main/java/mage/view/GameClientMessage.java b/Mage.Common/src/main/java/mage/view/GameClientMessage.java index 33af5e25e9..1774c766f9 100644 --- a/Mage.Common/src/main/java/mage/view/GameClientMessage.java +++ b/Mage.Common/src/main/java/mage/view/GameClientMessage.java @@ -32,6 +32,11 @@ import java.io.Serializable; import java.util.Map; import java.util.Set; import java.util.UUID; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.annotations.Expose; + import mage.choices.Choice; /** @@ -39,18 +44,29 @@ import mage.choices.Choice; * @author BetaSteward_at_googlemail.com */ public class GameClientMessage implements Serializable { + @Expose private static final long serialVersionUID = 1L; - + @Expose private GameView gameView; + @Expose private CardsView cardsView; + @Expose private CardsView cardsView2; + @Expose private String message; + @Expose private boolean flag; + @Expose private String[] strings; + @Expose private Set targets; + @Expose private int min; + @Expose private int max; + @Expose private Map options; + @Expose private Choice choice; public GameClientMessage(GameView gameView) { @@ -155,4 +171,11 @@ public class GameClientMessage implements Serializable { return choice; } + public String toJson() { + Gson gson = new GsonBuilder() + .excludeFieldsWithoutExposeAnnotation() + .create(); + return gson.toJson(this); + } + } diff --git a/Mage.Common/src/main/java/mage/view/GameView.java b/Mage.Common/src/main/java/mage/view/GameView.java index 2e16415ad6..b354503c56 100644 --- a/Mage.Common/src/main/java/mage/view/GameView.java +++ b/Mage.Common/src/main/java/mage/view/GameView.java @@ -28,11 +28,17 @@ package mage.view; import java.io.Serializable; +import java.io.BufferedWriter; +import java.io.PrintWriter; +import java.io.FileWriter; +import java.io.IOException; + import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Set; import java.util.UUID; + import mage.MageObject; import mage.abilities.costs.Cost; import mage.cards.Card; @@ -54,6 +60,8 @@ import mage.game.stack.StackObject; import mage.players.Player; import mage.watchers.common.CastSpellLastTurnWatcher; import org.apache.log4j.Logger; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; /** * @@ -64,7 +72,6 @@ public class GameView implements Serializable { private static final long serialVersionUID = 1L; private static final Logger LOGGER = Logger.getLogger(GameView.class); - private final int priorityTime; private final List players = new ArrayList<>(); private CardsView hand; @@ -351,4 +358,8 @@ public class GameView implements Serializable { return rollbackTurnsAllowed; } + public String toJson() { + Gson gson = new GsonBuilder().create(); + return gson.toJson(this); + } } diff --git a/Mage.Common/src/main/java/mage/view/SimpleCardView.java b/Mage.Common/src/main/java/mage/view/SimpleCardView.java index 709e45ad83..a137f0ca0e 100644 --- a/Mage.Common/src/main/java/mage/view/SimpleCardView.java +++ b/Mage.Common/src/main/java/mage/view/SimpleCardView.java @@ -28,6 +28,8 @@ package mage.view; +import com.google.gson.annotations.Expose; + import java.io.Serializable; import java.util.UUID; @@ -36,6 +38,7 @@ import java.util.UUID; * @author BetaSteward_at_googlemail.com */ public class SimpleCardView implements Serializable { + @Expose protected UUID id; protected String expansionSetCode; protected String tokenSetCode; diff --git a/Mage.Common/src/main/java/mage/view/TableView.java b/Mage.Common/src/main/java/mage/view/TableView.java index dd7de79d34..3480328b61 100644 --- a/Mage.Common/src/main/java/mage/view/TableView.java +++ b/Mage.Common/src/main/java/mage/view/TableView.java @@ -65,6 +65,7 @@ public class TableView implements Serializable { private final boolean limited; private final boolean rated; private final boolean passworded; + private final boolean spectatorsAllowed; public TableView(Table table) { this.tableId = table.getId(); @@ -139,6 +140,7 @@ public class TableView implements Serializable { this.limited = table.getMatch().getOptions().isLimited(); this.rated = table.getMatch().getOptions().isRated(); this.passworded = !table.getMatch().getOptions().getPassword().isEmpty(); + this.spectatorsAllowed = table.getMatch().getOptions().isSpectatorsAllowed(); } else { // TOURNAMENT if (table.getTournament().getOptions().getNumberRounds() > 0) { @@ -186,6 +188,7 @@ public class TableView implements Serializable { this.limited = table.getTournament().getOptions().getMatchOptions().isLimited(); this.rated = table.getTournament().getOptions().getMatchOptions().isRated(); this.passworded = !table.getTournament().getOptions().getPassword().isEmpty(); + this.spectatorsAllowed = table.getTournament().getOptions().isWatchingAllowed(); } } @@ -200,6 +203,11 @@ public class TableView implements Serializable { public String getControllerName() { return controllerName; } + + public boolean getSpectatorsAllowed() { + return spectatorsAllowed; + } + public String getGameType() { return gameType; diff --git a/Mage.Server.Console/src/main/java/mage/server/console/ConsolePanel.java b/Mage.Server.Console/src/main/java/mage/server/console/ConsolePanel.java index dd5e8b70a7..4b729539d8 100644 --- a/Mage.Server.Console/src/main/java/mage/server/console/ConsolePanel.java +++ b/Mage.Server.Console/src/main/java/mage/server/console/ConsolePanel.java @@ -345,22 +345,53 @@ public class ConsolePanel extends javax.swing.JPanel { private void btnEndSessionActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnEndSessionActionPerformed int row = this.tblUsers.convertRowIndexToModel(tblUsers.getSelectedRow()); - ConsoleFrame.getSession().endUserSession((String) tableUserModel.getValueAt(row, TableUserModel.POS_GAME_INFO)); + String userSessionId = (String) tableUserModel.getValueAt(row, TableUserModel.POS_GAME_INFO); + + if (JOptionPane.showConfirmDialog(null, "Are you sure you mean to end userSessionId " + userSessionId + '?', "WARNING", + JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION) { + ConsoleFrame.getSession().endUserSession(userSessionId); + } }//GEN-LAST:event_btnEndSessionActionPerformed private void btnMuteUserActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnMuteUserActionPerformed - int row = this.tblUsers.convertRowIndexToModel(tblUsers.getSelectedRow()); - ConsoleFrame.getSession().muteUserChat((String) tableUserModel.getValueAt(row, TableUserModel.POS_USER_NAME), ((Number) spinnerMuteDurationMinutes.getValue()).longValue()); + int row = this.tblUsers.convertRowIndexToModel(tblUsers.getSelectedRow()); + String userName = (String) tableUserModel.getValueAt(row, TableUserModel.POS_USER_NAME); + long durationMinute = ((Number) spinnerMuteDurationMinutes.getValue()).longValue(); + if (JOptionPane.showConfirmDialog(null, "Are you sure you mean to mute user: " + userName + " for " + durationMinute + " minutes?", "WARNING", + JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION) { + ConsoleFrame.getSession().muteUserChat(userName, durationMinute); + } }//GEN-LAST:event_btnMuteUserActionPerformed private void btnDeActivateActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnDeActivateActionPerformed int row = this.tblUsers.convertRowIndexToModel(tblUsers.getSelectedRow()); - ConsoleFrame.getSession().toggleActivation((String) tableUserModel.getValueAt(row, TableUserModel.POS_USER_NAME)); + String userName = (String) tableUserModel.getValueAt(row, TableUserModel.POS_USER_NAME); + + if (JOptionPane.showConfirmDialog(null, "Did you want to set user: " + userName + " to active?", "WARNING", + JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION) { + ConsoleFrame.getSession().setActivation(userName, true); + return; + } + if (JOptionPane.showConfirmDialog(null, "Did you want to set user: " + userName + " to inactive?", "WARNING", + JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION) { + ConsoleFrame.getSession().setActivation(userName, false); + return; + } + if (JOptionPane.showConfirmDialog(null, "Are you sure you mean to toggle activation for user: " + userName + '?', "WARNING", + JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION) { + ConsoleFrame.getSession().toggleActivation(userName); + return; + } }//GEN-LAST:event_btnDeActivateActionPerformed private void btnLockUserActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnLockUserActionPerformed int row = this.tblUsers.convertRowIndexToModel(tblUsers.getSelectedRow()); - ConsoleFrame.getSession().lockUser((String) tableUserModel.getValueAt(row, TableUserModel.POS_USER_NAME), ((Number) spinnerMuteDurationMinutes.getValue()).longValue()); + String userName = (String) tableUserModel.getValueAt(row, TableUserModel.POS_USER_NAME); + long durationMinute = ((Number) spinnerMuteDurationMinutes.getValue()).longValue(); + if (JOptionPane.showConfirmDialog(null, "Are you sure you mean to lock user: " + userName + " for " + durationMinute + " minutes?", "WARNING", + JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION) { + ConsoleFrame.getSession().lockUser(userName, durationMinute); + } }//GEN-LAST:event_btnLockUserActionPerformed private void btnRemoveTableActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnRemoveTableActionPerformed diff --git a/Mage.Server/pom.xml b/Mage.Server/pom.xml index f756f0f7c1..20899230cc 100644 --- a/Mage.Server/pom.xml +++ b/Mage.Server/pom.xml @@ -76,6 +76,12 @@ ${project.version} runtime + + org.apache.commons + commons-compress + 1.16.1 + + ${project.groupId} mage-game-commanderfreeforall diff --git a/Mage.Server/src/main/java/mage/server/TableController.java b/Mage.Server/src/main/java/mage/server/TableController.java index c45f07adc4..7015788472 100644 --- a/Mage.Server/src/main/java/mage/server/TableController.java +++ b/Mage.Server/src/main/java/mage/server/TableController.java @@ -990,7 +990,7 @@ public class TableController { || !match.isDoneSideboarding() || (!matchPlayer.hasQuit() && match.getGame() != null && matchPlayer.getPlayer().isInGame())) { Optional user = UserManager.instance.getUser(userPlayerEntry.getKey()); - if (!user.isPresent() || user.get().isActive()) { + if (!user.isPresent() || !user.get().isActive()) { logger.warn("- Active user of match is missing: " + matchPlayer.getName()); logger.warn("-- matchId:" + match.getId()); logger.warn("-- userId:" + userPlayerEntry.getKey()); diff --git a/Mage.Sets/src/mage/cards/a/ActOfAuthority.java b/Mage.Sets/src/mage/cards/a/ActOfAuthority.java index 913dc43fbb..38dcd6ca16 100644 --- a/Mage.Sets/src/mage/cards/a/ActOfAuthority.java +++ b/Mage.Sets/src/mage/cards/a/ActOfAuthority.java @@ -94,9 +94,12 @@ class ActOfAuthorityEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Permanent targetPermanent = game.getPermanent(this.getTargetPointer().getFirst(game, source)); if (targetPermanent != null && new ExileTargetEffect().apply(game, source)) { - ContinuousEffect effect = new ActOfAuthorityGainControlEffect(Duration.Custom, targetPermanent.getControllerId()); - effect.setTargetPointer(new FixedTarget(source.getSourceId())); - game.addEffect(effect, source); + Permanent sourcePermanent = source.getSourcePermanentIfItStillExists(game); + if (sourcePermanent != null) { + ContinuousEffect effect = new ActOfAuthorityGainControlEffect(Duration.Custom, targetPermanent.getControllerId()); + effect.setTargetPointer(new FixedTarget(sourcePermanent, game)); + game.addEffect(effect, source); + } return true; } return false; diff --git a/Mage.Sets/src/mage/cards/a/AdarkarValkyrie.java b/Mage.Sets/src/mage/cards/a/AdarkarValkyrie.java index ae3abfebab..0fccaadd0d 100644 --- a/Mage.Sets/src/mage/cards/a/AdarkarValkyrie.java +++ b/Mage.Sets/src/mage/cards/a/AdarkarValkyrie.java @@ -109,7 +109,7 @@ class AdarkarValkyrieEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - DelayedTriggeredAbility delayedAbility = new AdarkarValkyrieDelayedTriggeredAbility(new FixedTarget(this.getTargetPointer().getFirst(game, source))); + DelayedTriggeredAbility delayedAbility = new AdarkarValkyrieDelayedTriggeredAbility(getTargetPointer().getFixedTarget(game, source)); game.addDelayedTriggeredAbility(delayedAbility, source); return false; } diff --git a/Mage.Sets/src/mage/cards/a/AmbuscadeShaman.java b/Mage.Sets/src/mage/cards/a/AmbuscadeShaman.java index ec6cf2b57a..ce6a6d5522 100644 --- a/Mage.Sets/src/mage/cards/a/AmbuscadeShaman.java +++ b/Mage.Sets/src/mage/cards/a/AmbuscadeShaman.java @@ -51,17 +51,17 @@ import mage.target.targetpointer.FixedTarget; public class AmbuscadeShaman extends CardImpl { public AmbuscadeShaman(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}"); this.subtype.add(SubType.ORC); this.subtype.add(SubType.SHAMAN); this.power = new MageInt(2); this.toughness = new MageInt(2); // Whenever Ambuscade Shaman or another creature enters the battlefield under your control, that creature gets +2/+2 until end of turn. - Effect effect = new BoostTargetEffect(2,2, Duration.EndOfTurn); + Effect effect = new BoostTargetEffect(2, 2, Duration.EndOfTurn); effect.setText("that creature gets +2/+2 until end of turn"); this.addAbility(new AmbuscadeShamanTriggeredAbility(effect)); - + // Dash {3}{B} (You may cast this spell for its dash cost. If you do, it gains haste, and it's returned from the battlefield to its owner's hand at the beginning of the next end step.)); this.addAbility(new DashAbility(this, "{3}{B}")); @@ -103,9 +103,7 @@ class AmbuscadeShamanTriggeredAbility extends TriggeredAbilityImpl { Permanent permanent = game.getPermanent(targetId); if (permanent.getControllerId().equals(this.controllerId) && permanent.isCreature()) { - for (Effect effect : this.getEffects()) { - effect.setTargetPointer(new FixedTarget(event.getTargetId())); - } + this.getEffects().setTargetPointer(new FixedTarget(permanent, game)); return true; } return false; @@ -115,4 +113,4 @@ class AmbuscadeShamanTriggeredAbility extends TriggeredAbilityImpl { public String getRule() { return "Whenever {this} or another creature enters the battlefield under your control, that creature gets +2/+2 until end of turn."; } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/cards/a/AnkhOfMishra.java b/Mage.Sets/src/mage/cards/a/AnkhOfMishra.java index 38272e1e8e..a31aa9dbf4 100644 --- a/Mage.Sets/src/mage/cards/a/AnkhOfMishra.java +++ b/Mage.Sets/src/mage/cards/a/AnkhOfMishra.java @@ -45,16 +45,16 @@ import mage.target.targetpointer.FixedTarget; /** * * @author KholdFuzion - + * */ public class AnkhOfMishra extends CardImpl { - + public AnkhOfMishra(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{2}"); + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{2}"); // Whenever a land enters the battlefield, Ankh of Mishra deals 2 damage to that land's controller. this.addAbility(new AnkhOfMishraAbility()); - + } public AnkhOfMishra(final AnkhOfMishra card) { @@ -70,16 +70,16 @@ public class AnkhOfMishra extends CardImpl { class AnkhOfMishraAbility extends TriggeredAbilityImpl { public AnkhOfMishraAbility() { - super(Zone.BATTLEFIELD, new DamageTargetEffect(2)); + super(Zone.BATTLEFIELD, new DamageTargetEffect(2)); } AnkhOfMishraAbility(final AnkhOfMishraAbility ability) { - super(ability); + super(ability); } @Override public AnkhOfMishraAbility copy() { - return new AnkhOfMishraAbility(this); + return new AnkhOfMishraAbility(this); } @Override @@ -104,6 +104,6 @@ class AnkhOfMishraAbility extends TriggeredAbilityImpl { @Override public String getRule() { - return "Whenever a land enters the battlefield, Ankh of Mishra deals 2 damage to that land's controller."; + return "Whenever a land enters the battlefield, {this} deals 2 damage to that land's controller."; } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/cards/a/ArbiterOfTheIdeal.java b/Mage.Sets/src/mage/cards/a/ArbiterOfTheIdeal.java index 31453ff15b..de172fddb1 100644 --- a/Mage.Sets/src/mage/cards/a/ArbiterOfTheIdeal.java +++ b/Mage.Sets/src/mage/cards/a/ArbiterOfTheIdeal.java @@ -29,6 +29,7 @@ package mage.cards.a; import java.util.UUID; import mage.MageInt; +import mage.MageObject; import mage.abilities.Ability; import mage.abilities.effects.ContinuousEffect; import mage.abilities.effects.OneShotEffect; @@ -53,7 +54,7 @@ import mage.target.targetpointer.FixedTarget; public class ArbiterOfTheIdeal extends CardImpl { public ArbiterOfTheIdeal(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{4}{U}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{U}{U}"); this.subtype.add(SubType.SPHINX); this.power = new MageInt(4); @@ -79,6 +80,7 @@ public class ArbiterOfTheIdeal extends CardImpl { class ArbiterOfTheIdealEffect extends OneShotEffect { private static final FilterCard filter = new FilterCard(); + static { filter.add(Predicates.or( new CardTypePredicate(CardType.ARTIFACT), @@ -102,32 +104,25 @@ class ArbiterOfTheIdealEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); - if (player == null) { + Player controller = game.getPlayer(source.getControllerId()); + MageObject sourceObject = source.getSourceObject(game); + if (controller == null || sourceObject == null) { return false; } - - if (player.getLibrary().hasCards()) { - Card card = player.getLibrary().getFromTop(game); - Cards cards = new CardsImpl(); - cards.add(card); - player.revealCards("Arbiter of the Ideal", cards, game); - - if (card != null) { - if (filter.match(card, game) && player.chooseUse(outcome, new StringBuilder("Put ").append(card.getName()).append("onto battlefield?").toString(), source, game)) { - card.putOntoBattlefield(game, Zone.LIBRARY, source.getSourceId(), source.getControllerId()); - Permanent permanent = game.getPermanent(card.getId()); - if (permanent != null) { - permanent.addCounters(new Counter("Manifestation"), source, game); - ContinuousEffect effect = new AddCardTypeTargetEffect(Duration.Custom, CardType.ENCHANTMENT); - effect.setTargetPointer(new FixedTarget(permanent.getId())); - game.addEffect(effect, source); - } + Card card = controller.getLibrary().getFromTop(game); + if (card != null) { + controller.revealCards(sourceObject.getIdName(), new CardsImpl(card), game); + if (filter.match(card, game) && controller.chooseUse(outcome, "Put " + card.getName() + "onto battlefield?", source, game)) { + controller.moveCards(card, Zone.BATTLEFIELD, source, game); + Permanent permanent = game.getPermanent(card.getId()); + if (permanent != null) { + permanent.addCounters(new Counter("Manifestation"), source, game); + ContinuousEffect effect = new AddCardTypeTargetEffect(Duration.Custom, CardType.ENCHANTMENT); + effect.setTargetPointer(new FixedTarget(permanent, game)); + game.addEffect(effect, source); } } - return true; } - - return false; + return true; } } diff --git a/Mage.Sets/src/mage/cards/a/ArchonOfRedemption.java b/Mage.Sets/src/mage/cards/a/ArchonOfRedemption.java index 6b3507d348..50342b73b4 100644 --- a/Mage.Sets/src/mage/cards/a/ArchonOfRedemption.java +++ b/Mage.Sets/src/mage/cards/a/ArchonOfRedemption.java @@ -29,23 +29,18 @@ package mage.cards.a; import java.util.UUID; import mage.MageInt; -import mage.abilities.Ability; import mage.abilities.TriggeredAbilityImpl; -import mage.abilities.effects.Effect; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.GainLifeEffect; import mage.abilities.keyword.FlyingAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Outcome; import mage.constants.SubType; import mage.constants.Zone; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.events.GameEvent.EventType; import mage.game.permanent.Permanent; -import mage.players.Player; -import mage.target.targetpointer.FixedTarget; /** * @author Loki @@ -53,7 +48,7 @@ import mage.target.targetpointer.FixedTarget; public class ArchonOfRedemption extends CardImpl { public ArchonOfRedemption(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{W}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{W}{W}"); this.subtype.add(SubType.ARCHON); this.power = new MageInt(3); @@ -75,8 +70,9 @@ public class ArchonOfRedemption extends CardImpl { } class ArchonOfRedemptionTriggeredAbility extends TriggeredAbilityImpl { + ArchonOfRedemptionTriggeredAbility() { - super(Zone.BATTLEFIELD, new ArchonOfRedemptionEffect(), true); + super(Zone.BATTLEFIELD, null, true); } ArchonOfRedemptionTriggeredAbility(final ArchonOfRedemptionTriggeredAbility ability) { @@ -95,15 +91,13 @@ class ArchonOfRedemptionTriggeredAbility extends TriggeredAbilityImpl { @Override public boolean checkTrigger(GameEvent event, Game game) { - UUID targetId = event.getTargetId(); - Permanent permanent = game.getPermanent(targetId); - if (permanent.getControllerId().equals(this.controllerId) + Permanent permanent = game.getPermanent(event.getTargetId()); + if (permanent.getControllerId().equals(getControllerId()) && permanent.isCreature() - && (targetId.equals(this.getSourceId()) - || (permanent.getAbilities().contains(FlyingAbility.getInstance()) && !targetId.equals(this.getSourceId())))) { - for (Effect effect : this.getEffects()) { - effect.setTargetPointer(new FixedTarget(event.getTargetId())); - } + && (permanent.getId().equals(getSourceId()) + || (permanent.getAbilities().contains(FlyingAbility.getInstance())))) { + this.getEffects().clear(); + this.addEffect(new GainLifeEffect(permanent.getPower().getValue())); return true; } return false; @@ -111,35 +105,6 @@ class ArchonOfRedemptionTriggeredAbility extends TriggeredAbilityImpl { @Override public String getRule() { - return "Whenever {this} or another creature with flying enters the battlefield under your control, you may gain life equal to that creature's power"; + return "Whenever {this} or another creature with flying enters the battlefield under your control, you may gain life equal to that creature's power."; } } - -class ArchonOfRedemptionEffect extends OneShotEffect { - ArchonOfRedemptionEffect() { - super(Outcome.GainLife); - } - - ArchonOfRedemptionEffect(final ArchonOfRedemptionEffect effect) { - super(effect); - } - - @Override - public boolean apply(Game game, Ability source) { - Permanent p = game.getPermanent(targetPointer.getFirst(game, source)); - Player player = game.getPlayer(source.getControllerId()); - if (p == null) { - p = (Permanent) game.getLastKnownInformation(targetPointer.getFirst(game, source), Zone.BATTLEFIELD); - } - if (p != null && player != null) { - player.gainLife(p.getPower().getValue(), game); - return true; - } - return false; - } - - @Override - public ArchonOfRedemptionEffect copy() { - return new ArchonOfRedemptionEffect(this); - } -} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/a/ArchwingDragon.java b/Mage.Sets/src/mage/cards/a/ArchwingDragon.java index c2f8751e51..1067f47a1a 100644 --- a/Mage.Sets/src/mage/cards/a/ArchwingDragon.java +++ b/Mage.Sets/src/mage/cards/a/ArchwingDragon.java @@ -29,7 +29,7 @@ package mage.cards.a; import java.util.UUID; import mage.MageInt; -import mage.abilities.common.OnEventTriggeredAbility; +import mage.abilities.common.BeginningOfEndStepTriggeredAbility; import mage.abilities.effects.common.ReturnToHandSourceEffect; import mage.abilities.keyword.FlyingAbility; import mage.abilities.keyword.HasteAbility; @@ -37,7 +37,7 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.game.events.GameEvent; +import mage.constants.TargetController; /** * @@ -46,7 +46,7 @@ import mage.game.events.GameEvent; public class ArchwingDragon extends CardImpl { public ArchwingDragon(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{R}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{R}{R}"); this.subtype.add(SubType.DRAGON); this.power = new MageInt(4); @@ -54,8 +54,10 @@ public class ArchwingDragon extends CardImpl { this.addAbility(FlyingAbility.getInstance()); this.addAbility(HasteAbility.getInstance()); + // At the beginning of the end step, return Archwing Dragon to its owner's hand. - this.addAbility(new OnEventTriggeredAbility(GameEvent.EventType.END_TURN_STEP_PRE, "beginning of the end step", new ReturnToHandSourceEffect(true), false)); + this.addAbility(new BeginningOfEndStepTriggeredAbility(new ReturnToHandSourceEffect(true), TargetController.ANY, false)); + } public ArchwingDragon(final ArchwingDragon card) { diff --git a/Mage.Sets/src/mage/cards/a/ArrogantBloodlord.java b/Mage.Sets/src/mage/cards/a/ArrogantBloodlord.java index e6c1110059..0aa16e9cfe 100644 --- a/Mage.Sets/src/mage/cards/a/ArrogantBloodlord.java +++ b/Mage.Sets/src/mage/cards/a/ArrogantBloodlord.java @@ -53,7 +53,7 @@ import mage.target.targetpointer.FixedTarget; public class ArrogantBloodlord extends CardImpl { public ArrogantBloodlord(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{B}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{B}{B}"); this.subtype.add(SubType.VAMPIRE); this.subtype.add(SubType.KNIGHT); @@ -104,11 +104,8 @@ class ArrogantBloodlordTriggeredAbility extends TriggeredAbilityImpl { && Objects.equals(blocked, arrogantBloodlord)) { return true; } - if (blocker != null && Objects.equals(blocker, arrogantBloodlord) - && game.getPermanent(event.getTargetId()).getPower().getValue() < 2) { - return true; - } - return false; + return blocker != null && Objects.equals(blocker, arrogantBloodlord) + && game.getPermanent(event.getTargetId()).getPower().getValue() < 2; } @Override @@ -133,7 +130,7 @@ class ArrogantBloodlordEffect extends OneShotEffect { Permanent permanent = game.getPermanent(source.getSourceId()); if (permanent != null) { AtTheEndOfCombatDelayedTriggeredAbility delayedAbility = new AtTheEndOfCombatDelayedTriggeredAbility(new DestroyTargetEffect()); - delayedAbility.getEffects().get(0).setTargetPointer(new FixedTarget(source.getSourceId())); + delayedAbility.getEffects().get(0).setTargetPointer(new FixedTarget(permanent, game)); game.addDelayedTriggeredAbility(delayedAbility, source); return true; } diff --git a/Mage.Sets/src/mage/cards/a/AyeshaTanaka.java b/Mage.Sets/src/mage/cards/a/AyeshaTanaka.java index d16fa76af3..f6e44e5283 100644 --- a/Mage.Sets/src/mage/cards/a/AyeshaTanaka.java +++ b/Mage.Sets/src/mage/cards/a/AyeshaTanaka.java @@ -37,16 +37,13 @@ import mage.abilities.effects.common.CounterUnlessPaysEffect; import mage.abilities.keyword.BandingAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.AbilityType; import mage.constants.CardType; import mage.constants.SubType; import mage.constants.SuperType; import mage.constants.Zone; -import mage.filter.FilterStackObject; -import mage.filter.predicate.Predicate; -import mage.game.Game; -import mage.game.stack.StackAbility; -import mage.target.common.TargetActivatedOrTriggeredAbility; +import mage.filter.FilterAbility; +import mage.filter.predicate.ability.ArtifactSourcePredicate; +import mage.target.common.TargetActivatedAbility; /** * @@ -54,26 +51,26 @@ import mage.target.common.TargetActivatedOrTriggeredAbility; */ public class AyeshaTanaka extends CardImpl { - private final static FilterStackObject filter = new FilterStackObject("activated ability from an artifact source"); + private final static FilterAbility filter = new FilterAbility("activated ability from an artifact source"); static { filter.add(new ArtifactSourcePredicate()); } public AyeshaTanaka(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{W}{W}{U}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{W}{W}{U}{U}"); addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.ARTIFICER); this.power = new MageInt(2); this.toughness = new MageInt(2); - + // Banding this.addAbility(BandingAbility.getInstance()); // {T}: Counter target activated ability from an artifact source unless that ability's controller pays {W}. Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new CounterUnlessPaysEffect(new ManaCostsImpl("{W}")), new TapSourceCost()); - ability.addTarget(new TargetActivatedOrTriggeredAbility(filter)); + ability.addTarget(new TargetActivatedAbility(filter)); this.addAbility(ability); } @@ -86,22 +83,3 @@ public class AyeshaTanaka extends CardImpl { return new AyeshaTanaka(this); } } - -class ArtifactSourcePredicate implements Predicate { - - public ArtifactSourcePredicate() { - } - - @Override - public boolean apply(Ability input, Game game) { - if (input instanceof StackAbility) { - return input.getSourceObject(game).isArtifact() && input.getAbilityType() == AbilityType.ACTIVATED; - } - return false; - } - - @Override - public String toString() { - return "Source(Artifact)"; - } -} diff --git a/Mage.Sets/src/mage/cards/b/BlazeOfGlory.java b/Mage.Sets/src/mage/cards/b/BlazeOfGlory.java new file mode 100644 index 0000000000..c8e22ca563 --- /dev/null +++ b/Mage.Sets/src/mage/cards/b/BlazeOfGlory.java @@ -0,0 +1,127 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.cards.b; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.CastOnlyDuringPhaseStepSourceAbility; +import mage.abilities.condition.common.BeforeBlockersAreDeclaredCondition; +import mage.abilities.effects.RequirementEffect; +import mage.abilities.effects.common.combat.CanBlockAdditionalCreatureTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.TurnPhase; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.ObjectPlayer; +import mage.filter.predicate.ObjectPlayerPredicate; +import mage.game.Controllable; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author L_J + */ +public class BlazeOfGlory extends CardImpl { + + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creature defending player controls"); + + static { + filter.add(new BlazeOfGloryDefendingPlayerControlsPredicate()); + } + + public BlazeOfGlory(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{W}"); + + // Cast Blaze of Glory only during combat before blockers are declared. + this.addAbility(new CastOnlyDuringPhaseStepSourceAbility(TurnPhase.COMBAT, BeforeBlockersAreDeclaredCondition.instance)); + + // Target creature defending player controls can block any number of creatures this turn. It blocks each attacking creature this turn if able. + this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); + this.getSpellAbility().addEffect(new CanBlockAdditionalCreatureTargetEffect(Duration.EndOfTurn, 0)); + this.getSpellAbility().addEffect(new BlazeOfGloryRequirementEffect()); + } + + public BlazeOfGlory(final BlazeOfGlory card) { + super(card); + } + + @Override + public BlazeOfGlory copy() { + return new BlazeOfGlory(this); + } +} + +class BlazeOfGloryDefendingPlayerControlsPredicate implements ObjectPlayerPredicate> { + + @Override + public boolean apply(ObjectPlayer input, Game game) { + return game.getCombat().getPlayerDefenders(game).contains(input.getObject().getControllerId()); + } +} + +class BlazeOfGloryRequirementEffect extends RequirementEffect { + + public BlazeOfGloryRequirementEffect() { + super(Duration.EndOfTurn); + this.staticText = "It blocks each attacking creature this turn if able"; + } + + public BlazeOfGloryRequirementEffect(final BlazeOfGloryRequirementEffect effect) { + super(effect); + } + + @Override + public boolean applies(Permanent permanent, Ability source, Game game) { + return permanent.getId().equals(targetPointer.getFirst(game, source)); + } + + @Override + public boolean mustAttack(Game game) { + return false; + } + + @Override + public boolean mustBlock(Game game) { + return true; + } + + @Override + public boolean mustBlockAllAttackers(Game game) { + return true; + } + + @Override + public BlazeOfGloryRequirementEffect copy() { + return new BlazeOfGloryRequirementEffect(this); + } + +} diff --git a/Mage.Sets/src/mage/cards/b/BrassTalonChimera.java b/Mage.Sets/src/mage/cards/b/BrassTalonChimera.java index fc3b22aba5..7620727df5 100644 --- a/Mage.Sets/src/mage/cards/b/BrassTalonChimera.java +++ b/Mage.Sets/src/mage/cards/b/BrassTalonChimera.java @@ -53,7 +53,7 @@ import java.util.UUID; */ public class BrassTalonChimera extends CardImpl { - private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("Chimera creature you control"); + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("Chimera creature"); static { filter.add(new SubtypePredicate(SubType.CHIMERA)); diff --git a/Mage.Sets/src/mage/cards/b/BrownOuphe.java b/Mage.Sets/src/mage/cards/b/BrownOuphe.java index 1810831dd0..06bc31afbf 100644 --- a/Mage.Sets/src/mage/cards/b/BrownOuphe.java +++ b/Mage.Sets/src/mage/cards/b/BrownOuphe.java @@ -27,6 +27,7 @@ */ package mage.cards.b; +import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; @@ -35,17 +36,12 @@ import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.common.CounterTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.AbilityType; import mage.constants.CardType; import mage.constants.SubType; import mage.constants.Zone; -import mage.filter.FilterStackObject; -import mage.filter.predicate.Predicate; -import mage.game.Game; -import mage.game.stack.StackAbility; -import mage.target.common.TargetActivatedOrTriggeredAbility; - -import java.util.UUID; +import mage.filter.FilterAbility; +import mage.filter.predicate.ability.ArtifactSourcePredicate; +import mage.target.common.TargetActivatedAbility; /** * @@ -53,7 +49,7 @@ import java.util.UUID; */ public class BrownOuphe extends CardImpl { - private final static FilterStackObject filter = new FilterStackObject("activated ability from an artifact source"); + private final static FilterAbility filter = new FilterAbility("activated ability from an artifact source"); static { filter.add(new ArtifactSourcePredicate()); @@ -69,7 +65,7 @@ public class BrownOuphe extends CardImpl { // {1}{G}, {tap}: Counter target activated ability from an artifact source. Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new CounterTargetEffect(), new ManaCostsImpl<>("{1}{G}")); ability.addCost(new TapSourceCost()); - ability.addTarget(new TargetActivatedOrTriggeredAbility(filter)); + ability.addTarget(new TargetActivatedAbility(filter)); this.addAbility(ability); } @@ -82,22 +78,3 @@ public class BrownOuphe extends CardImpl { return new BrownOuphe(this); } } - -class ArtifactSourcePredicate implements Predicate { - - public ArtifactSourcePredicate() { - } - - @Override - public boolean apply(Ability input, Game game) { - if (input instanceof StackAbility) { - return input.getSourceObject(game).isArtifact() && input.getAbilityType() == AbilityType.ACTIVATED; - } - return false; - } - - @Override - public String toString() { - return "Source(Artifact)"; - } -} diff --git a/Mage.Sets/src/mage/cards/b/BuildersBane.java b/Mage.Sets/src/mage/cards/b/BuildersBane.java new file mode 100644 index 0000000000..2dc7950731 --- /dev/null +++ b/Mage.Sets/src/mage/cards/b/BuildersBane.java @@ -0,0 +1,121 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.cards.b; + +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.SpellAbility; +import mage.abilities.effects.OneShotEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Zone; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.common.TargetArtifactPermanent; + +/** + * + * @author sinsedrix + */ +public class BuildersBane extends CardImpl { + + public BuildersBane(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{X}{X}{R}"); + + // Destroy X target artifacts. Builder's Bane deals damage to each player equal to the number of artifacts he or she controlled put into a graveyard this way. + this.getSpellAbility().addTarget(new TargetArtifactPermanent()); + this.getSpellAbility().addEffect(new BuildersBaneEffect()); + } + + @Override + public void adjustTargets(Ability ability, Game game) { + if (ability instanceof SpellAbility) { + ability.getTargets().clear(); + int xValue = ability.getManaCostsToPay().getX(); + ability.addTarget(new TargetArtifactPermanent(xValue, xValue)); + } + } + + public BuildersBane(final BuildersBane card) { + super(card); + } + + @Override + public BuildersBane copy() { + return new BuildersBane(this); + } +} + +class BuildersBaneEffect extends OneShotEffect { + + public BuildersBaneEffect() { + super(Outcome.DestroyPermanent); + this.staticText = "Destroy X target artifacts. {this} deals damage to each player equal to the number of artifacts he or she controlled put into a graveyard this way"; + } + + public BuildersBaneEffect(final BuildersBaneEffect effect) { + super(effect); + } + + @Override + public BuildersBaneEffect copy() { + return new BuildersBaneEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Map destroyedArtifactPerPlayer = new HashMap<>(); + + // Destroy X target artifacts. + for (UUID targetID : this.targetPointer.getTargets(game, source)) { + Permanent permanent = game.getPermanent(targetID); + if (permanent != null) { + if (permanent.destroy(source.getSourceId(), game, false)) { + if (game.getState().getZone(permanent.getId()) == Zone.GRAVEYARD) { + destroyedArtifactPerPlayer.merge(permanent.getControllerId(), 1, Integer::sum); + } + } + } + } + + // Builder's Bane deals damage to each player equal to the number of artifacts he or she controlled put into a graveyard this way. + for (Map.Entry entry : destroyedArtifactPerPlayer.entrySet()) { + Player player = game.getPlayer(entry.getKey()); + if(player != null) { + player.damage(entry.getValue(), source.getSourceId(), game, false, true); + } + } + + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/c/CallToGlory.java b/Mage.Sets/src/mage/cards/c/CallToGlory.java index 9d678be515..b2c31e6112 100644 --- a/Mage.Sets/src/mage/cards/c/CallToGlory.java +++ b/Mage.Sets/src/mage/cards/c/CallToGlory.java @@ -28,21 +28,16 @@ package mage.cards.c; import java.util.UUID; -import mage.abilities.Ability; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.UntapAllEffect; import mage.abilities.effects.common.continuous.BoostControlledEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; -import mage.constants.Outcome; import mage.constants.SubType; import mage.filter.StaticFilters; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.SubtypePredicate; -import mage.game.Game; -import mage.game.permanent.Permanent; -import mage.players.Player; /** * @author Loki @@ -57,8 +52,9 @@ public class CallToGlory extends CardImpl { public CallToGlory(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{W}"); - - this.getSpellAbility().addEffect(new CalltoGloryFirstEffect()); + + //Untap all creatures you control. Samurai creatures you control get +1/+1 until end of turn. + this.getSpellAbility().addEffect(new UntapAllEffect(StaticFilters.FILTER_CONTROLLED_CREATURE)); this.getSpellAbility().addEffect(new BoostControlledEffect(1, 1, Duration.EndOfTurn, filter, false)); } @@ -70,35 +66,4 @@ public class CallToGlory extends CardImpl { public CallToGlory copy() { return new CallToGlory(this); } - -} - -class CalltoGloryFirstEffect extends OneShotEffect { - - public CalltoGloryFirstEffect() { - super(Outcome.Untap); - staticText = "Untap all creatures you control"; - } - - public CalltoGloryFirstEffect(final CalltoGloryFirstEffect effect) { - super(effect); - } - - @Override - public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); - if (player != null) { - for (Permanent creature : game.getBattlefield().getAllActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, player.getId(), game)) { - creature.untap(game); - } - return true; - } - return false; - } - - @Override - public CalltoGloryFirstEffect copy() { - return new CalltoGloryFirstEffect(this); - } - } diff --git a/Mage.Sets/src/mage/cards/c/CityOfSolitude.java b/Mage.Sets/src/mage/cards/c/CityOfSolitude.java index 03cef0637f..dbcc7129ba 100644 --- a/Mage.Sets/src/mage/cards/c/CityOfSolitude.java +++ b/Mage.Sets/src/mage/cards/c/CityOfSolitude.java @@ -28,6 +28,7 @@ package mage.cards.c; import java.util.UUID; +import mage.MageObject; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.ContinuousRuleModifyingEffectImpl; @@ -48,7 +49,7 @@ import mage.game.events.GameEvent.EventType; public class CityOfSolitude extends CardImpl { public CityOfSolitude(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{2}{G}"); + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{G}"); // Players can cast spells and activate abilities only during their own turns. this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new CityOfSolitudeEffect())); @@ -74,12 +75,22 @@ class CityOfSolitudeEffect extends ContinuousRuleModifyingEffectImpl { CityOfSolitudeEffect(final CityOfSolitudeEffect effect) { super(effect); } - + @Override public boolean checksEventType(GameEvent event, Game game) { return event.getType() == EventType.CAST_SPELL || event.getType() == EventType.ACTIVATE_ABILITY; } - + + @Override + public String getInfoMessage(Ability source, GameEvent event, Game game) { + MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject eventObject = game.getObject(event.getSourceId()); + if (sourceObject != null && eventObject != null) { + return "You can cast or activate anability of " + eventObject.getIdName() + " only during your own turns (" + sourceObject.getIdName() + "). "; + } + return null; + } + @Override public boolean applies(GameEvent event, Ability source, Game game) { return !game.getActivePlayerId().equals(event.getPlayerId()); @@ -89,4 +100,4 @@ class CityOfSolitudeEffect extends ContinuousRuleModifyingEffectImpl { public CityOfSolitudeEffect copy() { return new CityOfSolitudeEffect(this); } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/cards/c/CoffinQueen.java b/Mage.Sets/src/mage/cards/c/CoffinQueen.java index ca66fe8f4a..c7ea4503d5 100644 --- a/Mage.Sets/src/mage/cards/c/CoffinQueen.java +++ b/Mage.Sets/src/mage/cards/c/CoffinQueen.java @@ -41,9 +41,9 @@ import mage.abilities.effects.common.ReturnFromGraveyardToBattlefieldTargetEffec import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Duration; import mage.constants.Outcome; +import mage.constants.SubType; import mage.constants.Zone; import mage.filter.common.FilterCreatureCard; import mage.game.Game; @@ -60,7 +60,7 @@ import mage.target.targetpointer.FixedTarget; public class CoffinQueen extends CardImpl { public CoffinQueen(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}"); this.subtype.add(SubType.ZOMBIE); this.subtype.add(SubType.WIZARD); this.power = new MageInt(1); @@ -68,14 +68,14 @@ public class CoffinQueen extends CardImpl { // You may choose not to untap Coffin Queen during your untap step. this.addAbility(new SkipUntapOptionalAbility()); - + // {2}{B}, {tap}: Put target creature card from a graveyard onto the battlefield under your control. When Coffin Queen becomes untapped or you lose control of Coffin Queen, exile that creature. Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new ReturnFromGraveyardToBattlefieldTargetEffect(), new ManaCostsImpl("{2}{B}")); ability.addCost(new TapSourceCost()); ability.addTarget(new TargetCardInGraveyard(new FilterCreatureCard("creature card from a graveyard"))); - ability.addEffect(new CoffinQueenCreateDelayedTriggerEffect()); + ability.addEffect(new CoffinQueenCreateDelayedTriggerEffect()); this.addAbility(ability); - + } public CoffinQueen(final CoffinQueen card) { @@ -87,33 +87,30 @@ public class CoffinQueen extends CardImpl { return new CoffinQueen(this); } } + class CoffinQueenCreateDelayedTriggerEffect extends OneShotEffect { - + public CoffinQueenCreateDelayedTriggerEffect() { super(Outcome.Detriment); - this.staticText = "When Coffin Queen becomes untapped or you lose control of Coffin Queen, exile that creature"; + this.staticText = "When {this} becomes untapped or you lose control of {this}, exile that creature."; } - + public CoffinQueenCreateDelayedTriggerEffect(final CoffinQueenCreateDelayedTriggerEffect effect) { super(effect); } - + @Override public CoffinQueenCreateDelayedTriggerEffect copy() { return new CoffinQueenCreateDelayedTriggerEffect(this); } - + @Override public boolean apply(Game game, Ability source) { Permanent controlledCreature = game.getPermanent(source.getFirstTarget()); if (controlledCreature != null) { DelayedTriggeredAbility delayedAbility = new CoffinQueenDelayedTriggeredAbility(); - delayedAbility.getEffects().get(0).setTargetPointer(new FixedTarget(controlledCreature.getId())); - delayedAbility.setSourceId(source.getSourceId()); - delayedAbility.setControllerId(source.getControllerId()); - delayedAbility.setSourceObject(source.getSourceObject(game), game); - delayedAbility.init(game); - game.addDelayedTriggeredAbility(delayedAbility); + delayedAbility.getEffects().get(0).setTargetPointer(new FixedTarget(controlledCreature, game)); + game.addDelayedTriggeredAbility(delayedAbility, source); return true; } return false; @@ -123,7 +120,7 @@ class CoffinQueenCreateDelayedTriggerEffect extends OneShotEffect { class CoffinQueenDelayedTriggeredAbility extends DelayedTriggeredAbility { CoffinQueenDelayedTriggeredAbility() { - super(new ExileTargetEffect(), Duration.EndOfGame, true); + super(new ExileTargetEffect(), Duration.EndOfGame, true); } CoffinQueenDelayedTriggeredAbility(CoffinQueenDelayedTriggeredAbility ability) { @@ -136,7 +133,6 @@ class CoffinQueenDelayedTriggeredAbility extends DelayedTriggeredAbility { || event.getType() == EventType.UNTAPPED; } - @Override public boolean checkTrigger(GameEvent event, Game game) { if (EventType.LOST_CONTROL == event.getType() @@ -146,14 +142,14 @@ class CoffinQueenDelayedTriggeredAbility extends DelayedTriggeredAbility { return EventType.UNTAPPED == event.getType() && event.getTargetId() != null && event.getTargetId().equals(getSourceId()); } - + @Override public CoffinQueenDelayedTriggeredAbility copy() { return new CoffinQueenDelayedTriggeredAbility(this); } - + @Override public String getRule() { - return "When {this} becomes untapped or you lose control of {this}, exile that creature"; + return "When {this} becomes untapped or you lose control of {this}, exile that creature."; } } diff --git a/Mage.Sets/src/mage/cards/c/ConduitOfRuin.java b/Mage.Sets/src/mage/cards/c/ConduitOfRuin.java index b24a933ae8..5ea158c1f4 100644 --- a/Mage.Sets/src/mage/cards/c/ConduitOfRuin.java +++ b/Mage.Sets/src/mage/cards/c/ConduitOfRuin.java @@ -81,7 +81,7 @@ public class ConduitOfRuin extends CardImpl { // The first creature spell you cast each turn costs {2} less to cast. Effect effect = new SpellsCostReductionControllerEffect(filterCost, 2); - effect.setText("The first creature spell you cast each turn costs {2} less to cast"); + effect.setText("The first creature spell you cast each turn costs {2} less to cast."); this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, effect), new ConduitOfRuinWatcher()); } diff --git a/Mage.Sets/src/mage/cards/c/CruelFate.java b/Mage.Sets/src/mage/cards/c/CruelFate.java new file mode 100644 index 0000000000..ce16987c8f --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/CruelFate.java @@ -0,0 +1,142 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.cards.c; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.cards.Cards; +import mage.cards.CardsImpl; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Zone; +import mage.filter.FilterCard; +import mage.game.Game; +import mage.players.Player; +import mage.target.TargetCard; +import mage.target.common.TargetOpponent; + +/** + * + * @author TheElk801 & L_J + */ +public class CruelFate extends CardImpl { + + public CruelFate(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{4}{U}"); + + // Look at the top five cards of target opponent's library. Put one of those cards into that player's graveyard and the rest on top of his or her library in any order. + this.getSpellAbility().addEffect(new CruelFateEffect()); + this.getSpellAbility().addTarget(new TargetOpponent()); + + } + + public CruelFate(final CruelFate card) { + super(card); + } + + @Override + public CruelFate copy() { + return new CruelFate(this); + } +} + +class CruelFateEffect extends OneShotEffect { + + public CruelFateEffect() { + super(Outcome.DrawCard); + this.staticText = "Look at the top five cards of target opponent's library. Put one of those cards into that player's graveyard and the rest on top of his or her library in any order"; + } + + public CruelFateEffect(final CruelFateEffect effect) { + super(effect); + } + + @Override + public CruelFateEffect copy() { + return new CruelFateEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Card sourceCard = game.getCard(source.getSourceId()); + if (sourceCard != null) { + Player you = game.getPlayer(source.getControllerId()); + Player player = game.getPlayer(source.getFirstTarget()); + if (player != null && you != null) { + Cards cards = new CardsImpl(); + int count = Math.min(player.getLibrary().size(), 5); + for (int i = 0; i < count; i++) { + Card card = player.getLibrary().removeFromTop(game); + if (card != null) { + cards.add(card); + } + } + + you.lookAtCards(sourceCard.getIdName(), cards, game); + + // card to put into opponent's graveyard + TargetCard target = new TargetCard(Zone.LIBRARY, new FilterCard("card to put into target opponent's graveyard")); + if (player.canRespond()) { + if (cards.size() > 1) { + you.choose(Outcome.Detriment, cards, target, game); + Card card = cards.get(target.getFirstTarget(), game); + if (card != null) { + cards.remove(card); + card.moveToZone(Zone.GRAVEYARD, source.getSourceId(), game, true); + } + } + else if (cards.size() == 1) { + Card card = cards.get(cards.iterator().next(), game); + card.moveToZone(Zone.GRAVEYARD, source.getSourceId(), game, true); + } + } + // cards to put on the top of opponent's library + TargetCard target2 = new TargetCard(Zone.LIBRARY, new FilterCard("card to put on the top of target opponent's library")); + while (player.canRespond() && cards.size() > 1) { + you.choose(Outcome.Neutral, cards, target2, game); + Card card = cards.get(target2.getFirstTarget(), game); + if (card != null) { + cards.remove(card); + card.moveToZone(Zone.LIBRARY, source.getSourceId(), game, true); + } + target2.clearChosen(); + } + if (cards.size() == 1) { + Card card = cards.get(cards.iterator().next(), game); + card.moveToZone(Zone.LIBRARY, source.getSourceId(), game, true); + } + return true; + } + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/d/DeepWood.java b/Mage.Sets/src/mage/cards/d/DeepWood.java new file mode 100644 index 0000000000..bb1d3a1405 --- /dev/null +++ b/Mage.Sets/src/mage/cards/d/DeepWood.java @@ -0,0 +1,110 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.cards.d; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.CastOnlyDuringPhaseStepSourceAbility; +import mage.abilities.condition.common.AttackedThisStepCondition; +import mage.abilities.effects.PreventionEffectImpl; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.PhaseStep; +import mage.constants.TurnPhase; +import mage.filter.common.FilterAttackingCreature; +import mage.game.Game; +import mage.game.events.DamagePlayerEvent; +import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; +import mage.watchers.common.PlayerAttackedStepWatcher; + +/** + * + * @author L_J + */ +public class DeepWood extends CardImpl { + + public DeepWood(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{G}"); + + // Cast Deep Wood only during the declare attackers step and only if you've been attacked this step. + Ability ability = new CastOnlyDuringPhaseStepSourceAbility( + TurnPhase.COMBAT, PhaseStep.DECLARE_ATTACKERS, AttackedThisStepCondition.instance, + "Cast {this} only during the declare attackers step and only if you've been attacked this step." + ); + ability.addWatcher(new PlayerAttackedStepWatcher()); + this.addAbility(ability); + + // Prevent all damage that would be dealt to you this turn by attacking creatures. + this.getSpellAbility().addEffect(new DeepWoodEffect()); + } + + public DeepWood(final DeepWood card) { + super(card); + } + + @Override + public DeepWood copy() { + return new DeepWood(this); + } +} + +class DeepWoodEffect extends PreventionEffectImpl { + + private static final FilterAttackingCreature filter = new FilterAttackingCreature(); + + DeepWoodEffect() { + super(Duration.EndOfTurn, Integer.MAX_VALUE, false); + staticText = "Prevent all damage that would be dealt to you this turn by attacking creatures"; + } + + DeepWoodEffect(final DeepWoodEffect effect) { + super(effect); + } + + @Override + public DeepWoodEffect copy() { + return new DeepWoodEffect(this); + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + if (super.applies(event, source, game) && event instanceof DamagePlayerEvent && event.getAmount() > 0) { + DamagePlayerEvent damageEvent = (DamagePlayerEvent) event; + if (event.getTargetId().equals(source.getControllerId())) { + Permanent permanent = game.getPermanentOrLKIBattlefield(damageEvent.getSourceId()); + if (permanent != null && filter.match(permanent, game)) { + return true; + } + } + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/d/DefiantVanguard.java b/Mage.Sets/src/mage/cards/d/DefiantVanguard.java index 3b28b8d6dc..0a5c3decb5 100644 --- a/Mage.Sets/src/mage/cards/d/DefiantVanguard.java +++ b/Mage.Sets/src/mage/cards/d/DefiantVanguard.java @@ -124,7 +124,7 @@ class DefiantVanguardEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - Permanent thisCreature = game.getPermanentOrLKIBattlefield(source.getId()); + Permanent thisCreature = game.getPermanentOrLKIBattlefield(source.getSourceId()); if (controller != null && thisCreature != null) { BlockedAttackerWatcher watcher = (BlockedAttackerWatcher) game.getState().getWatchers().get(BlockedAttackerWatcher.class.getSimpleName()); if (watcher != null) { @@ -136,10 +136,10 @@ class DefiantVanguardEffect extends OneShotEffect { } } } + thisCreature.destroy(source.getSourceId(), game, false); for (Permanent creature : toDestroy) { creature.destroy(source.getSourceId(), game, false); } - thisCreature.destroy(source.getSourceId(), game, false); return true; } } diff --git a/Mage.Sets/src/mage/cards/d/DinosaurHunter.java b/Mage.Sets/src/mage/cards/d/DinosaurHunter.java index 9711eb8b51..3e76380422 100644 --- a/Mage.Sets/src/mage/cards/d/DinosaurHunter.java +++ b/Mage.Sets/src/mage/cards/d/DinosaurHunter.java @@ -28,17 +28,14 @@ package mage.cards.d; import java.util.UUID; - import mage.MageInt; import mage.abilities.TriggeredAbilityImpl; import mage.abilities.effects.common.*; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.*; -import mage.filter.common.*; -import mage.filter.predicate.mageobject.SubtypePredicate; -import mage.filter.predicate.permanent.AnotherPredicate; import mage.game.Game; +import mage.game.events.DamageEvent; import mage.game.events.GameEvent; import mage.game.permanent.Permanent; import mage.target.targetpointer.FixedTarget; @@ -48,12 +45,6 @@ import mage.target.targetpointer.FixedTarget; */ public class DinosaurHunter extends CardImpl { - private static final FilterControlledCreaturePermanent filterAnotherDino = new FilterControlledCreaturePermanent(); - static { - filterAnotherDino.add(new AnotherPredicate()); - filterAnotherDino.add(new SubtypePredicate(SubType.DINOSAUR)); - } - public DinosaurHunter(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{B}"); @@ -78,11 +69,6 @@ public class DinosaurHunter extends CardImpl { class DinosaurHunterAbility extends TriggeredAbilityImpl { - private static final FilterCreaturePermanent filter = new FilterCreaturePermanent(); - static { - filter.add(new SubtypePredicate(SubType.DINOSAUR)); - } - DinosaurHunterAbility() { super(Zone.BATTLEFIELD, new DestroyTargetEffect()); } @@ -103,11 +89,13 @@ class DinosaurHunterAbility extends TriggeredAbilityImpl { @Override public boolean checkTrigger(GameEvent event, Game game) { - Permanent sourcePermanet = game.getPermanent(event.getSourceId()); - Permanent targetPermanet = game.getPermanent(event.getTargetId()); - if (sourcePermanet != null && targetPermanet != null && event.getSourceId().equals(sourceId) && filter.match(targetPermanet, game)) { - getEffects().get(0).setTargetPointer(new FixedTarget(event.getTargetId())); - return true; + if (((DamageEvent) event).isCombatDamage() + && event.getSourceId().equals(getSourceId())) { + Permanent targetPermanet = game.getPermanentOrLKIBattlefield(event.getTargetId()); + if (targetPermanet.hasSubtype(SubType.DINOSAUR, game)) { + getEffects().get(0).setTargetPointer(new FixedTarget(targetPermanet, game)); + return true; + } } return false; } @@ -116,4 +104,4 @@ class DinosaurHunterAbility extends TriggeredAbilityImpl { public String getRule() { return "Whenever {this} deals combat damage to a Dinosaur, destroy that creature."; } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/cards/d/DjinnIlluminatus.java b/Mage.Sets/src/mage/cards/d/DjinnIlluminatus.java index 94c30a7feb..4eb5d4f1f0 100644 --- a/Mage.Sets/src/mage/cards/d/DjinnIlluminatus.java +++ b/Mage.Sets/src/mage/cards/d/DjinnIlluminatus.java @@ -108,7 +108,8 @@ class DjinnIlluminatusGainReplicateEffect extends ContinuousEffectImpl { if ((stackObject instanceof Spell) && !stackObject.isCopy() && stackObject.getControllerId().equals(source.getControllerId()) - && djinn.getControllerId().equals(source.getControllerId())) { // verify that the controller of the djinn cast that spell + && djinn.getControllerId().equals(source.getControllerId()) // verify that the controller of the djinn cast that spell + && !stackObject.getManaCost().isEmpty()) { //handle cases like Ancestral Vision Spell spell = (Spell) stackObject; if (filter.match(stackObject, game)) { ReplicateAbility replicateAbility = replicateAbilities.computeIfAbsent(spell.getId(), k -> new ReplicateAbility(spell.getCard(), spell.getSpellAbility().getManaCosts().getText())); diff --git a/Mage.Sets/src/mage/cards/d/Dread.java b/Mage.Sets/src/mage/cards/d/Dread.java index d1bdce0952..a2ec93af04 100644 --- a/Mage.Sets/src/mage/cards/d/Dread.java +++ b/Mage.Sets/src/mage/cards/d/Dread.java @@ -31,7 +31,6 @@ import java.util.UUID; import mage.MageInt; import mage.abilities.TriggeredAbilityImpl; import mage.abilities.common.PutIntoGraveFromAnywhereSourceTriggeredAbility; -import mage.abilities.effects.Effect; import mage.abilities.effects.common.DestroyTargetEffect; import mage.abilities.effects.common.ShuffleIntoLibrarySourceEffect; import mage.abilities.keyword.FearAbility; @@ -105,11 +104,7 @@ class DreadTriggeredAbility extends TriggeredAbilityImpl { if (event.getPlayerId().equals(this.getControllerId())) { Permanent permanent = game.getPermanent(event.getSourceId()); if (permanent != null && permanent.isCreature()) { - for (Effect effect : this.getEffects()) { - if (effect instanceof DestroyTargetEffect) { - effect.setTargetPointer(new FixedTarget(event.getSourceId())); - } - } + this.getEffects().setTargetPointer(new FixedTarget(permanent, game)); return true; } } diff --git a/Mage.Sets/src/mage/cards/d/DreadCharge.java b/Mage.Sets/src/mage/cards/d/DreadCharge.java new file mode 100644 index 0000000000..e7c8819cbf --- /dev/null +++ b/Mage.Sets/src/mage/cards/d/DreadCharge.java @@ -0,0 +1,73 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.cards.d; + +import java.util.UUID; +import mage.ObjectColor; +import mage.abilities.effects.common.combat.CantBeBlockedByCreaturesAllEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.TargetController; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.ColorPredicate; +import mage.filter.predicate.permanent.ControllerPredicate; + +/** + * + * @author L_J + */ +public class DreadCharge extends CardImpl { + + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("Black creatures you control"); + private static final FilterCreaturePermanent filter2 = new FilterCreaturePermanent("except by black creatures"); + + static { + filter.add(new ColorPredicate(ObjectColor.BLACK)); + filter2.add(Predicates.not(new ColorPredicate(ObjectColor.BLACK))); + filter.add(new ControllerPredicate(TargetController.YOU)); + } + + public DreadCharge(UUID ownerId, CardSetInfo setInfo) { + super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{3}{B}"); + + // Black creatures you control can't be blocked this turn except by black creatures. + this.getSpellAbility().addEffect(new CantBeBlockedByCreaturesAllEffect(filter, filter2, Duration.EndOfTurn)); + } + + public DreadCharge(final DreadCharge card) { + super(card); + } + + @Override + public DreadCharge copy() { + return new DreadCharge(this); + } +} diff --git a/Mage.Sets/src/mage/cards/e/EunuchsIntrigues.java b/Mage.Sets/src/mage/cards/e/EunuchsIntrigues.java new file mode 100644 index 0000000000..7592c51744 --- /dev/null +++ b/Mage.Sets/src/mage/cards/e/EunuchsIntrigues.java @@ -0,0 +1,145 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.cards.e; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.RestrictionEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.permanent.ControllerIdPredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.Target; +import mage.target.TargetPermanent; +import mage.target.common.TargetOpponent; + +/** + * + * @author TheElk801 & L_J + */ +public class EunuchsIntrigues extends CardImpl { + + public EunuchsIntrigues(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{R}"); + + // Target opponent chooses a creature he or she controls. Other creatures he or she controls can't block this turn. + this.getSpellAbility().addEffect(new EunuchsIntriguesEffect()); + this.getSpellAbility().addTarget(new TargetOpponent()); + } + + public EunuchsIntrigues(final EunuchsIntrigues card) { + super(card); + } + + @Override + public EunuchsIntrigues copy() { + return new EunuchsIntrigues(this); + } +} + +class EunuchsIntriguesEffect extends OneShotEffect { + + EunuchsIntriguesEffect() { + super(Outcome.Benefit); + this.staticText = "Target opponent chooses a creature he or she controls. Other creatures he or she controls can't block this turn."; + } + + EunuchsIntriguesEffect(final EunuchsIntriguesEffect effect) { + super(effect); + } + + @Override + public EunuchsIntriguesEffect copy() { + return new EunuchsIntriguesEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getFirstTarget()); + if (player == null) { + return false; + } + FilterCreaturePermanent filter = new FilterCreaturePermanent("creature you control"); + filter.add(new ControllerIdPredicate(player.getId())); + Target target = new TargetPermanent(1, 1, filter, true); + if (target.canChoose(source.getSourceId(), player.getId(), game)) { + while (!target.isChosen() && target.canChoose(player.getId(), game) && player.canRespond()) { + player.chooseTarget(Outcome.DestroyPermanent, target, source, game); + } + Permanent permanent = game.getPermanent(target.getFirstTarget()); + if (permanent != null) { + game.informPlayers(player.getLogName() + " has chosen " + permanent.getLogName() + " as his only creature able to block this turn"); + } + } + game.addEffect(new EunuchsIntriguesRestrictionEffect(target.getFirstTarget()), source); + return true; + } +} + +class EunuchsIntriguesRestrictionEffect extends RestrictionEffect { + + protected UUID targetId; + + public EunuchsIntriguesRestrictionEffect(UUID targetId) { + super(Duration.EndOfTurn); + this.targetId = targetId; + } + + public EunuchsIntriguesRestrictionEffect(final EunuchsIntriguesRestrictionEffect effect) { + super(effect); + targetId = effect.targetId; + } + + @Override + public EunuchsIntriguesRestrictionEffect copy() { + return new EunuchsIntriguesRestrictionEffect(this); + } + + @Override + public boolean applies(Permanent permanent, Ability source, Game game) { + if (permanent.getControllerId().equals(source.getFirstTarget())) { + return true; + } + return false; + } + + @Override + public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game) { + if (targetId != null && blocker.getId().equals(targetId)) { + return true; + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/e/ExaltedDragon.java b/Mage.Sets/src/mage/cards/e/ExaltedDragon.java index 55ee01bf79..941f15b0e4 100644 --- a/Mage.Sets/src/mage/cards/e/ExaltedDragon.java +++ b/Mage.Sets/src/mage/cards/e/ExaltedDragon.java @@ -80,7 +80,7 @@ class ExaltedDragonCostToAttackBlockEffect extends PayCostToAttackBlockEffectImp ExaltedDragonCostToAttackBlockEffect() { super(Duration.WhileOnBattlefield, Outcome.Detriment, RestrictType.ATTACK, new SacrificeTargetCost(new TargetControlledPermanent(new FilterControlledLandPermanent("a land")))); - staticText = "{this} can't attack unless you sacrifice a land (This cost is paid as attackers are declared.)"; + staticText = "{this} can't attack unless you sacrifice a land. (This cost is paid as attackers are declared.)"; } ExaltedDragonCostToAttackBlockEffect(ExaltedDragonCostToAttackBlockEffect effect) { diff --git a/Mage.Sets/src/mage/cards/e/Exhume.java b/Mage.Sets/src/mage/cards/e/Exhume.java index 678d17dddc..a06a50309e 100644 --- a/Mage.Sets/src/mage/cards/e/Exhume.java +++ b/Mage.Sets/src/mage/cards/e/Exhume.java @@ -94,6 +94,7 @@ class ExhumeEffect extends OneShotEffect { FilterCreatureCard filterCreatureCard = new FilterCreatureCard("creature card from your graveyard"); filterCreatureCard.add(new OwnerIdPredicate(playerId)); TargetCardInGraveyard target = new TargetCardInGraveyard(filterCreatureCard); + target.setNotTarget(true); if (target.canChoose(playerId, game) && player.chooseTarget(outcome, target, source, game)) { Card card = game.getCard(target.getFirstTarget()); diff --git a/Mage.Sets/src/mage/cards/e/EyeForAnEye.java b/Mage.Sets/src/mage/cards/e/EyeForAnEye.java index 08245b25ab..9c62933fbf 100644 --- a/Mage.Sets/src/mage/cards/e/EyeForAnEye.java +++ b/Mage.Sets/src/mage/cards/e/EyeForAnEye.java @@ -28,24 +28,22 @@ package mage.cards.e; import java.util.UUID; -import mage.MageObject; import mage.abilities.Ability; -import mage.abilities.TriggeredAbilityImpl; -import mage.abilities.effects.Effect; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.ReplacementEffectImpl; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; +import mage.constants.Duration; import mage.constants.Outcome; -import mage.constants.Zone; import mage.game.Game; +import mage.game.events.DamageEvent; import mage.game.events.GameEvent; import mage.players.Player; -import mage.target.targetpointer.FixedTarget; +import mage.target.TargetSource; /** - * - * @author MarcoMarin + * + * @author L_J */ public class EyeForAnEye extends CardImpl { @@ -53,8 +51,7 @@ public class EyeForAnEye extends CardImpl { super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{W}{W}"); // The next time a source of your choice would deal damage to you this turn, instead that source deals that much damage to you and Eye for an Eye deals that much damage to that source's controller. - this.addAbility(new EyeForAnEyeTriggeredAbility(new EyeForAnEyeEffect())); - + this.getSpellAbility().addEffect(new EyeForAnEyeEffect()); } public EyeForAnEye(final EyeForAnEye card) { @@ -67,48 +64,19 @@ public class EyeForAnEye extends CardImpl { } } -class EyeForAnEyeTriggeredAbility extends TriggeredAbilityImpl { +class EyeForAnEyeEffect extends ReplacementEffectImpl { - public EyeForAnEyeTriggeredAbility(Effect effect) { - super(Zone.BATTLEFIELD, effect); - } - - public EyeForAnEyeTriggeredAbility(final EyeForAnEyeTriggeredAbility ability) { - super(ability); - } - - @Override - public EyeForAnEyeTriggeredAbility copy() { - return new EyeForAnEyeTriggeredAbility(this); - } - - @Override - public boolean checkEventType(GameEvent event, Game game) { - return event.getType() == GameEvent.EventType.DAMAGED_PLAYER; - } - - @Override - public boolean checkTrigger(GameEvent event, Game game) { - MageObject sourceObject = game.getObject(event.getSourceId()); - this.getEffects().get(0).setValue("damageAmount", event.getAmount()); - this.getEffects().get(0).setTargetPointer(new FixedTarget(game.getControllerId(sourceObject.getId()))); - return true; - } - - @Override - public String getRule() { - return "The next time a source of your choice would deal damage to you this turn, instead that source deals that much damage to you and {this} deals that much damage to that source's controller."; - } -} - -class EyeForAnEyeEffect extends OneShotEffect { + private final TargetSource damageSource; public EyeForAnEyeEffect() { - super(Outcome.Damage); + super(Duration.EndOfTurn, Outcome.RedirectDamage); + staticText = "The next time a source of your choice would deal damage to you this turn, instead that source deals that much damage to you and {this} deals that much damage to that source's controller"; + this.damageSource = new TargetSource(); } public EyeForAnEyeEffect(final EyeForAnEyeEffect effect) { super(effect); + this.damageSource = effect.damageSource.copy(); } @Override @@ -116,15 +84,48 @@ class EyeForAnEyeEffect extends OneShotEffect { return new EyeForAnEyeEffect(this); } + @Override + public void init(Ability source, Game game) { + this.damageSource.choose(Outcome.PreventDamage, source.getControllerId(), source.getSourceId(), game); + super.init(source, game); + } + + @Override + public boolean checksEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.DAMAGE_PLAYER; + } + @Override public boolean apply(Game game, Ability source) { - Integer damageAmount = (Integer) this.getValue("damageAmount"); - UUID targetId = this.targetPointer.getFirst(game, source); - if (damageAmount != null && targetId != null) { - Player player = game.getPlayer(targetId); - if (player != null) { - player.damage(damageAmount, targetId, game, false, true); + return true; + } + + @Override + public boolean replaceEvent(GameEvent event, Ability source, Game game) { + Player controller = game.getPlayer(source.getControllerId()); + DamageEvent damageEvent = (DamageEvent) event; + if (controller != null) { + controller.damage(damageEvent.getAmount(), damageEvent.getSourceId(), game, damageEvent.isCombatDamage(), damageEvent.isPreventable(), damageEvent.getAppliedEffects()); + UUID sourceControllerId = game.getControllerId(damageEvent.getSourceId()); + if (sourceControllerId != null) { + Player sourceController = game.getPlayer(sourceControllerId); + if (sourceController != null) { + sourceController.damage(damageEvent.getAmount(), source.getSourceId(), game, false, true); return true; + } + } + } + return false; + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + Player controller = game.getPlayer(source.getControllerId()); + DamageEvent damageEvent = (DamageEvent) event; + if (controller != null) { + if (controller.getId() == damageEvent.getTargetId() && damageEvent.getSourceId().equals(damageSource.getFirstTarget())) { + this.discard(); + return true; } } return false; diff --git a/Mage.Sets/src/mage/cards/f/Foreshadow.java b/Mage.Sets/src/mage/cards/f/Foreshadow.java new file mode 100644 index 0000000000..54db650304 --- /dev/null +++ b/Mage.Sets/src/mage/cards/f/Foreshadow.java @@ -0,0 +1,110 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.cards.f; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.delayed.AtTheBeginOfNextUpkeepDelayedTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.NameACardEffect; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Zone; +import mage.game.Game; +import mage.players.Player; +import mage.target.common.TargetOpponent; + +/** + * + * @author Quercitron & L_J + */ +public class Foreshadow extends CardImpl { + + public Foreshadow(UUID ownerId, CardSetInfo setInfo) { + super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{1}{U}"); + + // Choose a card name, then target opponent puts the top card of his or her library into his or her graveyard. If that card has the chosen name, you draw a card. + this.getSpellAbility().addEffect(new NameACardEffect(NameACardEffect.TypeOfName.ALL)); + this.getSpellAbility().addEffect(new ForeshadowEffect()); + this.getSpellAbility().addTarget(new TargetOpponent()); + + // Draw a card at the beginning of the next turn's upkeep. + this.getSpellAbility().addEffect(new CreateDelayedTriggeredAbilityEffect( + new AtTheBeginOfNextUpkeepDelayedTriggeredAbility(new DrawCardSourceControllerEffect(1)), false)); + } + + public Foreshadow(final Foreshadow card) { + super(card); + } + + @Override + public Foreshadow copy() { + return new Foreshadow(this); + } +} + +class ForeshadowEffect extends OneShotEffect { + + public ForeshadowEffect() { + super(Outcome.DrawCard); + this.staticText = ", then target opponent puts the top card of his or her library into his or her graveyard. If that card has the chosen name, you draw a card"; + } + + public ForeshadowEffect(final ForeshadowEffect effect) { + super(effect); + } + + @Override + public ForeshadowEffect copy() { + return new ForeshadowEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + Player targetPlayer = game.getPlayer(source.getFirstTarget()); + String cardName = (String) game.getState().getValue(source.getSourceId().toString() + NameACardEffect.INFO_KEY); + if (controller != null && targetPlayer != null && cardName != null && !cardName.isEmpty()) { + Card card = targetPlayer.getLibrary().getFromTop(game); + if (card != null) { + controller.moveCards(card, Zone.GRAVEYARD, source, game); + if (card.getName().equals(cardName)) { + controller.drawCards(1, game); + } + } + return true; + } + return false; + } + +} diff --git a/Mage.Sets/src/mage/cards/g/GlyphOfDoom.java b/Mage.Sets/src/mage/cards/g/GlyphOfDoom.java new file mode 100644 index 0000000000..748661c0a0 --- /dev/null +++ b/Mage.Sets/src/mage/cards/g/GlyphOfDoom.java @@ -0,0 +1,153 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.cards.g; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; +import mage.MageObjectReference; +import mage.abilities.Ability; +import mage.abilities.common.delayed.AtTheEndOfCombatDelayedTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.InfoEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.Outcome; +import mage.filter.StaticFilters; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.mageobject.SubtypePredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.common.TargetCreaturePermanent; +import mage.watchers.common.BlockedAttackerWatcher; + +/** + * + * @author LevelX2 & L_J + */ +public class GlyphOfDoom extends CardImpl { + + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("Wall creature"); + + static { + filter.add(new SubtypePredicate(SubType.WALL)); + } + + public GlyphOfDoom(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{B}"); + + // Choose target Wall creature. At this turn's next end of combat, destroy all creatures that were blocked by that creature this turn. + this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); + this.getSpellAbility().addEffect(new InfoEffect("Choose target Wall creature")); + this.getSpellAbility().addEffect(new GlyphOfDoomCreateDelayedTriggeredAbilityEffect()); + this.getSpellAbility().addWatcher(new BlockedAttackerWatcher()); + } + + public GlyphOfDoom(final GlyphOfDoom card) { + super(card); + } + + @Override + public GlyphOfDoom copy() { + return new GlyphOfDoom(this); + } +} + +class GlyphOfDoomCreateDelayedTriggeredAbilityEffect extends OneShotEffect { + + public GlyphOfDoomCreateDelayedTriggeredAbilityEffect() { + super(Outcome.Benefit); + this.staticText = "At this turn's next end of combat, destroy all creatures that were blocked by that creature this turn"; + } + + public GlyphOfDoomCreateDelayedTriggeredAbilityEffect(final GlyphOfDoomCreateDelayedTriggeredAbilityEffect effect) { + super(effect); + } + + @Override + public GlyphOfDoomCreateDelayedTriggeredAbilityEffect copy() { + return new GlyphOfDoomCreateDelayedTriggeredAbilityEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + if (!source.getTargets().isEmpty() && source.getFirstTarget() != null) { + MageObjectReference mor = new MageObjectReference(source.getFirstTarget(), game); + AtTheEndOfCombatDelayedTriggeredAbility delayedAbility = new AtTheEndOfCombatDelayedTriggeredAbility(new GlyphOfDoomEffect(mor)); + game.addDelayedTriggeredAbility(delayedAbility, source); + return true; + } + return false; + } +} + +class GlyphOfDoomEffect extends OneShotEffect { + + MageObjectReference targetCreature; + + public GlyphOfDoomEffect(MageObjectReference targetCreature) { + super(Outcome.DestroyPermanent); + this.targetCreature = targetCreature; + } + + public GlyphOfDoomEffect(final GlyphOfDoomEffect effect) { + super(effect); + targetCreature = effect.targetCreature; + } + + @Override + public GlyphOfDoomEffect copy() { + return new GlyphOfDoomEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller != null && targetCreature != null) { + BlockedAttackerWatcher watcher = (BlockedAttackerWatcher) game.getState().getWatchers().get(BlockedAttackerWatcher.class.getSimpleName()); + if (watcher != null) { + List toDestroy = new ArrayList<>(); + for (Permanent creature : game.getBattlefield().getActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, source.getControllerId(), source.getSourceId(), game)) { + if (!creature.getId().equals(targetCreature.getSourceId())) { + if (watcher.creatureHasBlockedAttacker(new MageObjectReference(creature, game), targetCreature, game)) { + toDestroy.add(creature); + } + } + } + for (Permanent creature : toDestroy) { + creature.destroy(source.getSourceId(), game, false); + } + return true; + } + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/g/GoblinWarCry.java b/Mage.Sets/src/mage/cards/g/GoblinWarCry.java new file mode 100644 index 0000000000..a1d6a1939a --- /dev/null +++ b/Mage.Sets/src/mage/cards/g/GoblinWarCry.java @@ -0,0 +1,145 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.cards.g; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.RestrictionEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.permanent.ControllerIdPredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.Target; +import mage.target.TargetPermanent; +import mage.target.common.TargetOpponent; + +/** + * + * @author TheElk801 & L_J + */ +public class GoblinWarCry extends CardImpl { + + public GoblinWarCry(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{R}"); + + // Target opponent chooses a creature he or she controls. Other creatures he or she controls can't block this turn. + this.getSpellAbility().addEffect(new GoblinWarCryEffect()); + this.getSpellAbility().addTarget(new TargetOpponent()); + } + + public GoblinWarCry(final GoblinWarCry card) { + super(card); + } + + @Override + public GoblinWarCry copy() { + return new GoblinWarCry(this); + } +} + +class GoblinWarCryEffect extends OneShotEffect { + + GoblinWarCryEffect() { + super(Outcome.Benefit); + this.staticText = "Target opponent chooses a creature he or she controls. Other creatures he or she controls can't block this turn."; + } + + GoblinWarCryEffect(final GoblinWarCryEffect effect) { + super(effect); + } + + @Override + public GoblinWarCryEffect copy() { + return new GoblinWarCryEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getFirstTarget()); + if (player == null) { + return false; + } + FilterCreaturePermanent filter = new FilterCreaturePermanent("creature you control"); + filter.add(new ControllerIdPredicate(player.getId())); + Target target = new TargetPermanent(1, 1, filter, true); + if (target.canChoose(source.getSourceId(), player.getId(), game)) { + while (!target.isChosen() && target.canChoose(player.getId(), game) && player.canRespond()) { + player.chooseTarget(Outcome.DestroyPermanent, target, source, game); + } + Permanent permanent = game.getPermanent(target.getFirstTarget()); + if (permanent != null) { + game.informPlayers(player.getLogName() + " has chosen " + permanent.getLogName() + " as his only creature able to block this turn"); + } + } + game.addEffect(new GoblinWarCryRestrictionEffect(target.getFirstTarget()), source); + return true; + } +} + +class GoblinWarCryRestrictionEffect extends RestrictionEffect { + + protected UUID targetId; + + public GoblinWarCryRestrictionEffect(UUID targetId) { + super(Duration.EndOfTurn); + this.targetId = targetId; + } + + public GoblinWarCryRestrictionEffect(final GoblinWarCryRestrictionEffect effect) { + super(effect); + targetId = effect.targetId; + } + + @Override + public GoblinWarCryRestrictionEffect copy() { + return new GoblinWarCryRestrictionEffect(this); + } + + @Override + public boolean applies(Permanent permanent, Ability source, Game game) { + if (permanent.getControllerId().equals(source.getFirstTarget())) { + return true; + } + return false; + } + + @Override + public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game) { + if (targetId != null && blocker.getId().equals(targetId)) { + return true; + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/h/HarshJustice.java b/Mage.Sets/src/mage/cards/h/HarshJustice.java new file mode 100644 index 0000000000..bfbf9c70af --- /dev/null +++ b/Mage.Sets/src/mage/cards/h/HarshJustice.java @@ -0,0 +1,170 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.cards.h; + +import java.util.UUID; +import mage.MageObject; +import mage.abilities.Ability; +import mage.abilities.DelayedTriggeredAbility; +import mage.abilities.common.CastOnlyDuringPhaseStepSourceAbility; +import mage.abilities.condition.common.AttackedThisStepCondition; +import mage.abilities.effects.Effect; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.PhaseStep; +import mage.constants.TurnPhase; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.permanent.AttackingPredicate; +import mage.game.Game; +import mage.game.events.DamagedPlayerEvent; +import mage.game.events.GameEvent; +import mage.game.events.GameEvent.EventType; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.watchers.common.PlayerAttackedStepWatcher; + +/** + * + * @author LevelX2 & L_J + */ +public class HarshJustice extends CardImpl { + + public HarshJustice(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{W}"); + + // Cast Harsh Justice only during the declare attackers step and only if you've been attacked this step. + Ability ability = new CastOnlyDuringPhaseStepSourceAbility( + TurnPhase.COMBAT, PhaseStep.DECLARE_ATTACKERS, AttackedThisStepCondition.instance, + "Cast {this} only during the declare attackers step and only if you've been attacked this step." + ); + ability.addWatcher(new PlayerAttackedStepWatcher()); + this.addAbility(ability); + + // This turn, whenever an attacking creature deals combat damage to you, it deals that much damage to its controller. + this.getSpellAbility().addEffect(new CreateDelayedTriggeredAbilityEffect(new HarshJusticeTriggeredAbility())); + } + + public HarshJustice(final HarshJustice card) { + super(card); + } + + @Override + public HarshJustice copy() { + return new HarshJustice(this); + } +} + +class HarshJusticeTriggeredAbility extends DelayedTriggeredAbility { + + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("attacking creature"); + + static { + filter.add(new AttackingPredicate()); + } + + public HarshJusticeTriggeredAbility() { + super(new HarshJusticeEffect(), Duration.EndOfTurn, false); + } + + public HarshJusticeTriggeredAbility(final HarshJusticeTriggeredAbility ability) { + super(ability); + } + + @Override + public HarshJusticeTriggeredAbility copy() { + return new HarshJusticeTriggeredAbility(this); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == EventType.DAMAGED_PLAYER; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + Player controller = game.getPlayer(this.getControllerId()); + DamagedPlayerEvent damageEvent = (DamagedPlayerEvent) event; + Permanent damagePermanent = game.getPermanentOrLKIBattlefield(damageEvent.getSourceId()); + if (controller != null && damagePermanent != null) { + if (damageEvent.isCombatDamage() && controller.getId().equals(damageEvent.getTargetId()) && filter.match(damagePermanent, game)) { + for (Effect effect : this.getEffects()) { + effect.setValue("damage", damageEvent.getAmount()); + effect.setValue("sourceId", damageEvent.getSourceId()); + } + return true; + } + } + return false; + } + + @Override + public String getRule() { + return "This turn, whenever an attacking creature deals combat damage to you, " + super.getRule(); + } +} + +class HarshJusticeEffect extends OneShotEffect { + + public HarshJusticeEffect() { + super(Outcome.Benefit); + this.staticText = "it deals that much damage to its controller"; + } + + public HarshJusticeEffect(final HarshJusticeEffect effect) { + super(effect); + } + + @Override + public HarshJusticeEffect copy() { + return new HarshJusticeEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + int damage = (Integer) this.getValue("damage"); + UUID sourceId = (UUID) this.getValue("sourceId"); + MageObject sourceObject = game.getObject(source.getSourceId()); + if (sourceObject != null && damage > 0 && sourceId != null) { + Permanent targetObject = game.getPermanentOrLKIBattlefield(sourceId); + if (targetObject != null) { + Player controller = game.getPlayer(targetObject.getControllerId()); + if (controller != null) { + game.informPlayers(sourceObject.getLogName() + ": " + targetObject.getLogName() + " deals " + damage + " damage to " + controller.getLogName()); + controller.damage(damage, sourceId, game, false, true); + return true; + } + } + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/h/HeatShimmer.java b/Mage.Sets/src/mage/cards/h/HeatShimmer.java index 68967ad6ab..80fb54d109 100644 --- a/Mage.Sets/src/mage/cards/h/HeatShimmer.java +++ b/Mage.Sets/src/mage/cards/h/HeatShimmer.java @@ -29,10 +29,9 @@ package mage.cards.h; import java.util.UUID; import mage.abilities.Ability; -import mage.abilities.common.delayed.AtTheEndOfTurnStepPostDelayedTriggeredAbility; -import mage.abilities.effects.Effect; +import mage.abilities.DelayedTriggeredAbility; +import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbility; import mage.abilities.effects.OneShotEffect; -import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect; import mage.abilities.effects.common.ExileTargetEffect; import mage.abilities.effects.common.CreateTokenCopyTargetEffect; import mage.cards.CardImpl; @@ -52,7 +51,7 @@ import mage.target.targetpointer.FixedTarget; public class HeatShimmer extends CardImpl { public HeatShimmer(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{2}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{R}"); // Create a token that's a copy of target creature. That token has haste and "At the beginning of the end step, exile this permanent." this.getSpellAbility().addEffect(new HeatShimmerEffect()); @@ -89,15 +88,15 @@ class HeatShimmerEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); Permanent permanent = game.getPermanentOrLKIBattlefield(getTargetPointer().getFirst(game, source)); - if (controller != null && permanent != null) { + if (controller != null + && permanent != null) { CreateTokenCopyTargetEffect effect = new CreateTokenCopyTargetEffect(source.getControllerId(), null, true); effect.setTargetPointer(new FixedTarget(permanent, game)); effect.apply(game, source); - for (Permanent addedToken : effect.getAddedPermanent()) { - Effect exileEffect = new ExileTargetEffect(); - exileEffect.setTargetPointer(new FixedTarget(addedToken, game)); - new CreateDelayedTriggeredAbilityEffect(new AtTheEndOfTurnStepPostDelayedTriggeredAbility(exileEffect), false).apply(game, source); - } + ExileTargetEffect exileEffect = new ExileTargetEffect(); + exileEffect.setTargetPointer(new FixedTarget(effect.getAddedPermanent().get(0), game)); + DelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(exileEffect); + game.addDelayedTriggeredAbility(delayedAbility, source); return true; } return false; diff --git a/Mage.Sets/src/mage/cards/h/HeavyFog.java b/Mage.Sets/src/mage/cards/h/HeavyFog.java new file mode 100644 index 0000000000..e69e57ebf0 --- /dev/null +++ b/Mage.Sets/src/mage/cards/h/HeavyFog.java @@ -0,0 +1,110 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.cards.h; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.CastOnlyDuringPhaseStepSourceAbility; +import mage.abilities.condition.common.AttackedThisStepCondition; +import mage.abilities.effects.PreventionEffectImpl; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.PhaseStep; +import mage.constants.TurnPhase; +import mage.filter.common.FilterAttackingCreature; +import mage.game.Game; +import mage.game.events.DamagePlayerEvent; +import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; +import mage.watchers.common.PlayerAttackedStepWatcher; + +/** + * + * @author L_J + */ +public class HeavyFog extends CardImpl { + + public HeavyFog(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{G}"); + + // Cast Deep Wood only during the declare attackers step and only if you've been attacked this step. + Ability ability = new CastOnlyDuringPhaseStepSourceAbility( + TurnPhase.COMBAT, PhaseStep.DECLARE_ATTACKERS, AttackedThisStepCondition.instance, + "Cast {this} only during the declare attackers step and only if you've been attacked this step." + ); + ability.addWatcher(new PlayerAttackedStepWatcher()); + this.addAbility(ability); + + // Prevent all damage that would be dealt to you this turn by attacking creatures. + this.getSpellAbility().addEffect(new HeavyFogEffect()); + } + + public HeavyFog(final HeavyFog card) { + super(card); + } + + @Override + public HeavyFog copy() { + return new HeavyFog(this); + } +} + +class HeavyFogEffect extends PreventionEffectImpl { + + private static final FilterAttackingCreature filter = new FilterAttackingCreature(); + + HeavyFogEffect() { + super(Duration.EndOfTurn, Integer.MAX_VALUE, false); + staticText = "Prevent all damage that would be dealt to you this turn by attacking creatures"; + } + + HeavyFogEffect(final HeavyFogEffect effect) { + super(effect); + } + + @Override + public HeavyFogEffect copy() { + return new HeavyFogEffect(this); + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + if (super.applies(event, source, game) && event instanceof DamagePlayerEvent && event.getAmount() > 0) { + DamagePlayerEvent damageEvent = (DamagePlayerEvent) event; + if (event.getTargetId().equals(source.getControllerId())) { + Permanent permanent = game.getPermanentOrLKIBattlefield(damageEvent.getSourceId()); + if (permanent != null && filter.match(permanent, game)) { + return true; + } + } + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/h/HeraldOfThePantheon.java b/Mage.Sets/src/mage/cards/h/HeraldOfThePantheon.java index 6c31a6de0a..4fdc337841 100644 --- a/Mage.Sets/src/mage/cards/h/HeraldOfThePantheon.java +++ b/Mage.Sets/src/mage/cards/h/HeraldOfThePantheon.java @@ -48,7 +48,7 @@ import mage.filter.predicate.mageobject.CardTypePredicate; */ public class HeraldOfThePantheon extends CardImpl { - private static final FilterCard filter = new FilterCard("enchantment spells"); + private static final FilterCard filter = new FilterCard("Enchantment spells"); private static final FilterSpell filter2 = new FilterSpell("an enchantment spell"); static { diff --git a/Mage.Sets/src/mage/cards/h/HonorablePassage.java b/Mage.Sets/src/mage/cards/h/HonorablePassage.java new file mode 100644 index 0000000000..585d6256e0 --- /dev/null +++ b/Mage.Sets/src/mage/cards/h/HonorablePassage.java @@ -0,0 +1,108 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.cards.h; + +import java.util.UUID; +import mage.MageObject; +import mage.abilities.Ability; +import mage.abilities.Mode; +import mage.abilities.effects.PreventionEffectData; +import mage.abilities.effects.common.PreventNextDamageFromChosenSourceToTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.players.Player; +import mage.target.common.TargetCreatureOrPlayer; + +/** + * + * @author L_J + */ +public class HonorablePassage extends CardImpl { + + public HonorablePassage(UUID ownerId, CardSetInfo setInfo) { + super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{1}{W}"); + + // The next time a source of your choice would deal damage to target creature or player this turn, prevent that damage. If damage from a red source is prevented this way, Honorable Passage deals that much damage to the source's controller. + this.getSpellAbility().addEffect(new HonorablePassageEffect()); + this.getSpellAbility().addTarget(new TargetCreatureOrPlayer()); + } + + public HonorablePassage(final HonorablePassage card) { + super(card); + } + + @Override + public HonorablePassage copy() { + return new HonorablePassage(this); + } +} + +class HonorablePassageEffect extends PreventNextDamageFromChosenSourceToTargetEffect { + + public HonorablePassageEffect() { + super(Duration.EndOfTurn); + } + + public HonorablePassageEffect(final HonorablePassageEffect effect) { + super(effect); + } + + @Override + public HonorablePassageEffect copy() { + return new HonorablePassageEffect(this); + } + + @Override + public boolean replaceEvent(GameEvent event, Ability source, Game game) { + int damage = event.getAmount(); + PreventionEffectData preventEffectData = preventDamageAction(event, source, game); + if (preventEffectData.getPreventedDamage() > 0) { + MageObject sourceObject = game.getObject(event.getSourceId()); + if (sourceObject != null && sourceObject.getColor(game).isRed()) { + UUID sourceControllerId = game.getControllerId(event.getSourceId()); + if (sourceControllerId != null) { + Player sourceController = game.getPlayer(sourceControllerId); + if (sourceController != null) { + sourceController.damage(damage, source.getSourceId(), game, false, true); + } + } + } + this.used = true; + } + return false; + } + + @Override + public String getText(Mode mode) { + return "The next time a source of your choice would deal damage to target creature or player this turn, prevent that damage. If damage from a red source is prevented this way, {this} deals that much damage to the source's controller"; + } +} diff --git a/Mage.Sets/src/mage/cards/h/HostageTaker.java b/Mage.Sets/src/mage/cards/h/HostageTaker.java index 92605814ab..73bc0f278c 100644 --- a/Mage.Sets/src/mage/cards/h/HostageTaker.java +++ b/Mage.Sets/src/mage/cards/h/HostageTaker.java @@ -41,10 +41,10 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.AsThoughEffectType; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Duration; import mage.constants.ManaType; import mage.constants.Outcome; +import mage.constants.SubType; import mage.constants.Zone; import mage.filter.FilterPermanent; import mage.filter.predicate.Predicates; @@ -118,8 +118,8 @@ class HostageTakerExileEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Permanent card = game.getPermanent(targetPointer.getFirst(game, source)); - Permanent permanent = game.getPermanent(source.getSourceId()); + Permanent card = game.getPermanent(getTargetPointer().getFirst(game, source)); + Permanent permanent = game.getPermanentOrLKIBattlefield(source.getSourceId()); if (permanent != null && card != null) { Player controller = game.getPlayer(card.getControllerId()); if (controller != null) { diff --git a/Mage.Sets/src/mage/cards/h/HotSoup.java b/Mage.Sets/src/mage/cards/h/HotSoup.java index 149fc23d68..969b778c72 100644 --- a/Mage.Sets/src/mage/cards/h/HotSoup.java +++ b/Mage.Sets/src/mage/cards/h/HotSoup.java @@ -104,10 +104,7 @@ class HotSoupTriggeredAbility extends TriggeredAbilityImpl { Permanent equipment = game.getPermanent(this.getSourceId()); if (equipment != null && equipment.getAttachedTo() != null) { if (Objects.equals(event.getTargetId(), equipment.getAttachedTo())) { - for(Effect effect : this.getEffects()) - { - effect.setTargetPointer(new FixedTarget(equipment.getAttachedTo())); - } + this.getEffects().setTargetPointer(new FixedTarget(equipment.getAttachedTo(), game)); return true; } } @@ -118,4 +115,4 @@ class HotSoupTriggeredAbility extends TriggeredAbilityImpl { public String getRule() { return "Whenever equipped creature is dealt damage, " + super.getRule(); } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/cards/h/HushwingGryff.java b/Mage.Sets/src/mage/cards/h/HushwingGryff.java index b3316468dc..97eac84084 100644 --- a/Mage.Sets/src/mage/cards/h/HushwingGryff.java +++ b/Mage.Sets/src/mage/cards/h/HushwingGryff.java @@ -31,6 +31,7 @@ import java.util.UUID; import mage.MageInt; import mage.MageObject; import mage.abilities.Ability; +import mage.abilities.TriggeredAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.ContinuousRuleModifyingEffectImpl; import mage.abilities.keyword.FlashAbility; @@ -39,9 +40,9 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.AbilityType; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Duration; import mage.constants.Outcome; +import mage.constants.SubType; import mage.constants.Zone; import mage.game.Game; import mage.game.events.EntersTheBattlefieldEvent; @@ -55,7 +56,7 @@ import mage.game.permanent.Permanent; public class HushwingGryff extends CardImpl { public HushwingGryff(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{W}"); this.subtype.add(SubType.HIPPOGRIFF); this.power = new MageInt(2); @@ -92,10 +93,15 @@ class HushwingGryffEffect extends ContinuousRuleModifyingEffectImpl { @Override public String getInfoMessage(Ability source, GameEvent event, Game game) { - MageObject mageObject = game.getObject(event.getSourceId()); + MageObject enteringObject = game.getObject(event.getSourceId()); MageObject sourceObject = game.getObject(source.getSourceId()); - if (mageObject != null && sourceObject != null) { - return sourceObject.getLogName() + " prevented ability of " + mageObject.getLogName() + " to trigger"; + Ability ability = (Ability) getValue("targetAbility"); + if (enteringObject != null && sourceObject != null && ability != null) { + MageObject abilitObject = game.getObject(ability.getSourceId()); + if (abilitObject != null) { + return sourceObject.getLogName() + " prevented ability of " + abilitObject.getLogName() + + " to trigger for " + enteringObject.getLogName() + " entering the battlefield."; + } } return null; } @@ -111,7 +117,7 @@ class HushwingGryffEffect extends ContinuousRuleModifyingEffectImpl { if (ability != null && ability.getAbilityType() == AbilityType.TRIGGERED) { Permanent permanent = ((EntersTheBattlefieldEvent) event).getTarget(); if (permanent != null && permanent.isCreature()) { - return true; + return (((TriggeredAbility) ability).checkTrigger(event, game)); } } return false; diff --git a/Mage.Sets/src/mage/cards/i/Interdict.java b/Mage.Sets/src/mage/cards/i/Interdict.java index 5fcc1c5244..4ae659f513 100644 --- a/Mage.Sets/src/mage/cards/i/Interdict.java +++ b/Mage.Sets/src/mage/cards/i/Interdict.java @@ -28,6 +28,7 @@ package mage.cards.i; import java.util.UUID; +import mage.MageObject; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.RestrictionEffect; @@ -88,7 +89,7 @@ class InterdictPredicate implements Predicate { @Override public boolean apply(Ability input, Game game) { if (input instanceof StackAbility && input.getAbilityType() == AbilityType.ACTIVATED) { - Permanent sourceObject = game.getPermanentOrLKIBattlefield(input.getSourceId()); + MageObject sourceObject = input.getSourceObject(game); if (sourceObject != null) { return (sourceObject.isArtifact() || sourceObject.isEnchantment() @@ -120,9 +121,12 @@ class InterdictCounterEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { StackObject stackObject = game.getStack().getStackObject(source.getFirstTarget()); if (stackObject != null && game.getStack().counter(source.getFirstTarget(), source.getSourceId(), game)) { - InterdictCantActivateEffect effect = new InterdictCantActivateEffect(); - effect.setTargetPointer(new FixedTarget(stackObject.getSourceId())); - game.getContinuousEffects().addEffect(effect, source); + Permanent sourcePermanent = stackObject.getStackAbility().getSourcePermanentIfItStillExists(game); + if (sourcePermanent != null) { + InterdictCantActivateEffect effect = new InterdictCantActivateEffect(); + effect.setTargetPointer(new FixedTarget(sourcePermanent, game)); + game.getContinuousEffects().addEffect(effect, source); + } return true; } return false; @@ -143,7 +147,7 @@ class InterdictCantActivateEffect extends RestrictionEffect { @Override public boolean applies(Permanent permanent, Ability source, Game game) { - return getTargetPointer().getFirst(game, source).equals(permanent.getId()); + return permanent.getId().equals(getTargetPointer().getFirst(game, source)); } @Override diff --git a/Mage.Sets/src/mage/cards/j/JacesSanctum.java b/Mage.Sets/src/mage/cards/j/JacesSanctum.java index 717038e90b..0acd517e84 100644 --- a/Mage.Sets/src/mage/cards/j/JacesSanctum.java +++ b/Mage.Sets/src/mage/cards/j/JacesSanctum.java @@ -48,7 +48,7 @@ import mage.filter.predicate.mageobject.CardTypePredicate; public class JacesSanctum extends CardImpl { - private static final FilterCard filter = new FilterCard("instant and sorcery spells"); + private static final FilterCard filter = new FilterCard("Instant and sorcery spells"); private static final FilterSpell filter2 = new FilterSpell("an instant or sorcery spell"); diff --git a/Mage.Sets/src/mage/cards/j/JustFate.java b/Mage.Sets/src/mage/cards/j/JustFate.java new file mode 100644 index 0000000000..214396cd31 --- /dev/null +++ b/Mage.Sets/src/mage/cards/j/JustFate.java @@ -0,0 +1,73 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.cards.j; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.CastOnlyDuringPhaseStepSourceAbility; +import mage.abilities.condition.common.AttackedThisStepCondition; +import mage.abilities.effects.common.DestroyTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.PhaseStep; +import mage.constants.TurnPhase; +import mage.target.common.TargetAttackingCreature; +import mage.watchers.common.PlayerAttackedStepWatcher; + +/** + * + * @author TheElk801 + */ +public class JustFate extends CardImpl { + + public JustFate(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{W}"); + + // Cast Just Fate only during the declare attackers step and only if you've been attacked this step. + Ability ability = new CastOnlyDuringPhaseStepSourceAbility( + TurnPhase.COMBAT, PhaseStep.DECLARE_ATTACKERS, AttackedThisStepCondition.instance, + "Cast {this} only during the declare attackers step and only if you've been attacked this step." + ); + ability.addWatcher(new PlayerAttackedStepWatcher()); + this.addAbility(ability); + + // Destroy target attacking creature. + this.getSpellAbility().addEffect(new DestroyTargetEffect()); + this.getSpellAbility().addTarget(new TargetAttackingCreature()); + } + + public JustFate(final JustFate card) { + super(card); + } + + @Override + public JustFate copy() { + return new JustFate(this); + } +} diff --git a/Mage.Sets/src/mage/cards/k/KaerveksSpite.java b/Mage.Sets/src/mage/cards/k/KaerveksSpite.java index 349fa1ccf8..8602a8c41b 100644 --- a/Mage.Sets/src/mage/cards/k/KaerveksSpite.java +++ b/Mage.Sets/src/mage/cards/k/KaerveksSpite.java @@ -16,7 +16,7 @@ public class KaerveksSpite extends CardImpl { super(ownerId, cardSetInfo, new CardType[]{CardType.INSTANT}, "{B}{B}{B}"); // As an additional cost to cast Kaervek's Spite, sacrifice all permanents you control and discard your hand. - this.getSpellAbility().addCost(new SacrificeAllCost(new FilterControlledPermanent("all permanents you control"))); + this.getSpellAbility().addCost(new SacrificeAllCost(new FilterControlledPermanent("permanents you control"))); this.getSpellAbility().addCost(new DiscardHandCost()); // Target player loses 5 life. diff --git a/Mage.Sets/src/mage/cards/k/KaronasZealot.java b/Mage.Sets/src/mage/cards/k/KaronasZealot.java new file mode 100644 index 0000000000..6e07f81e71 --- /dev/null +++ b/Mage.Sets/src/mage/cards/k/KaronasZealot.java @@ -0,0 +1,75 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.cards.k; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.TurnedFaceUpSourceTriggeredAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.RedirectDamageFromSourceToTargetEffect; +import mage.abilities.keyword.MorphAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.Duration; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author L_J + */ +public class KaronasZealot extends CardImpl { + + public KaronasZealot(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{W}"); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.CLERIC); + this.power = new MageInt(2); + this.toughness = new MageInt(5); + + // Morph {3}{W}{W} + this.addAbility(new MorphAbility(this, new ManaCostsImpl("{3}{W}{W}"))); + + // When Karona's Zealot is turned face up, all damage that would be dealt to it this turn is dealt to target creature instead. + Ability ability = new TurnedFaceUpSourceTriggeredAbility(new RedirectDamageFromSourceToTargetEffect(Duration.EndOfTurn, Integer.MAX_VALUE, false) + .setText("all damage that would be dealt to it this turn is dealt to target creature instead")); + ability.addTarget(new TargetCreaturePermanent()); + this.addAbility(ability); + } + + public KaronasZealot(final KaronasZealot card) { + super(card); + } + + @Override + public KaronasZealot copy() { + return new KaronasZealot(this); + } +} diff --git a/Mage.Sets/src/mage/cards/k/KongmingsContraptions.java b/Mage.Sets/src/mage/cards/k/KongmingsContraptions.java new file mode 100644 index 0000000000..d03db0bfd1 --- /dev/null +++ b/Mage.Sets/src/mage/cards/k/KongmingsContraptions.java @@ -0,0 +1,80 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.cards.k; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.condition.CompoundCondition; +import mage.abilities.condition.common.AttackedThisStepCondition; +import mage.abilities.condition.common.IsStepCondition; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.decorator.ConditionalActivatedAbility; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.PhaseStep; +import mage.constants.Zone; +import mage.filter.common.FilterAttackingCreature; +import mage.target.TargetPermanent; +import mage.watchers.common.PlayerAttackedStepWatcher; + +/** + * + * @author L_J + */ +public class KongmingsContraptions extends CardImpl { + + public KongmingsContraptions(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{W}"); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.SOLDIER); + this.power = new MageInt(2); + this.toughness = new MageInt(4); + + // {T}: Kongming's Contraptions deals 2 damage to target attacking creature. Activate this ability only during the declare attackers step and only if you've been attacked this step. + Ability ability = new ConditionalActivatedAbility(Zone.BATTLEFIELD, new DamageTargetEffect(2), new TapSourceCost(), + new CompoundCondition("during the declare attackers step and only if you've been attacked this step", + new IsStepCondition(PhaseStep.DECLARE_ATTACKERS, false), AttackedThisStepCondition.instance) + ); + ability.addTarget(new TargetPermanent(new FilterAttackingCreature())); + this.addAbility(ability, new PlayerAttackedStepWatcher()); + } + + public KongmingsContraptions(final KongmingsContraptions card) { + super(card); + } + + @Override + public KongmingsContraptions copy() { + return new KongmingsContraptions(this); + } + +} diff --git a/Mage.Sets/src/mage/cards/k/KrosanDrover.java b/Mage.Sets/src/mage/cards/k/KrosanDrover.java index b8237a2beb..7bd3c7d341 100644 --- a/Mage.Sets/src/mage/cards/k/KrosanDrover.java +++ b/Mage.Sets/src/mage/cards/k/KrosanDrover.java @@ -30,6 +30,7 @@ package mage.cards.k; import java.util.UUID; import mage.MageInt; import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.Effect; import mage.abilities.effects.common.cost.SpellsCostReductionControllerEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -61,7 +62,9 @@ public class KrosanDrover extends CardImpl { this.toughness = new MageInt(2); // Creature spells you cast with converted mana cost 6 or greater cost {2} less to cast. - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new SpellsCostReductionControllerEffect(filter, 2))); + Effect effect = new SpellsCostReductionControllerEffect(filter, 2); + effect.setText("Creature spells you cast with converted mana cost 6 or greater cost {2} less to cast."); + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, effect)); } public KrosanDrover(final KrosanDrover card) { diff --git a/Mage.Sets/src/mage/cards/l/LaquatussChampion.java b/Mage.Sets/src/mage/cards/l/LaquatussChampion.java index 0e91897a87..909d6a6231 100644 --- a/Mage.Sets/src/mage/cards/l/LaquatussChampion.java +++ b/Mage.Sets/src/mage/cards/l/LaquatussChampion.java @@ -35,7 +35,6 @@ import mage.abilities.common.LeavesBattlefieldTriggeredAbility; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.AdjustingSourceCosts; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.effects.Effect; import mage.abilities.effects.common.GainLifeTargetEffect; import mage.abilities.effects.common.LoseLifeTargetEffect; import mage.abilities.effects.common.RegenerateSourceEffect; @@ -58,7 +57,7 @@ import mage.util.CardUtil; public class LaquatussChampion extends CardImpl { public LaquatussChampion(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{4}{B}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{B}{B}"); this.subtype.add(SubType.NIGHTMARE); this.subtype.add(SubType.HORROR); @@ -126,9 +125,7 @@ class LaquatussChampionLeavesBattlefieldTriggeredAbility extends LeavesBattlefie String key = CardUtil.getCardZoneString("targetPlayer", this.getSourceId(), game, true); Object object = game.getState().getValue(key); if (object instanceof UUID) { - for (Effect effect : this.getEffects()) { - effect.setTargetPointer(new FixedTarget((UUID) object)); - } + this.getEffects().setTargetPointer(new FixedTarget((UUID) object)); return true; } } diff --git a/Mage.Sets/src/mage/cards/l/Leviathan.java b/Mage.Sets/src/mage/cards/l/Leviathan.java index cf79670e67..7f5d4b1cb2 100644 --- a/Mage.Sets/src/mage/cards/l/Leviathan.java +++ b/Mage.Sets/src/mage/cards/l/Leviathan.java @@ -118,7 +118,7 @@ class LeviathanCostToAttackBlockEffect extends PayCostToAttackBlockEffectImpl { LeviathanCostToAttackBlockEffect() { super(Duration.WhileOnBattlefield, Outcome.Detriment, RestrictType.ATTACK, new SacrificeTargetCost(new TargetControlledPermanent(2, 2, filter, false))); - staticText = "{this} can't attack unless you sacrifice two Islands (This cost is paid as attackers are declared.)"; + staticText = "{this} can't attack unless you sacrifice two Islands. (This cost is paid as attackers are declared.)"; } LeviathanCostToAttackBlockEffect(LeviathanCostToAttackBlockEffect effect) { diff --git a/Mage.Sets/src/mage/cards/l/LyevDecree.java b/Mage.Sets/src/mage/cards/l/LyevDecree.java index c332e4bf09..70326ded26 100644 --- a/Mage.Sets/src/mage/cards/l/LyevDecree.java +++ b/Mage.Sets/src/mage/cards/l/LyevDecree.java @@ -47,7 +47,7 @@ import mage.target.common.TargetCreaturePermanent; public class LyevDecree extends CardImpl { - private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creatures your opponent controls"); + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creatures your opponents control"); static { filter.add(new ControllerPredicate(TargetController.OPPONENT)); } @@ -56,7 +56,7 @@ public class LyevDecree extends CardImpl { super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{1}{W}"); - // Detain up to two target creatures your opponent controls. + // Detain up to two target creatures your opponents control. this.getSpellAbility().addEffect(new DetainTargetEffect()); Target target = new TargetCreaturePermanent(0,2,filter,false); this.getSpellAbility().addTarget(target); diff --git a/Mage.Sets/src/mage/cards/m/ManaMatrix.java b/Mage.Sets/src/mage/cards/m/ManaMatrix.java index e2e0fac2c5..1777b831fd 100644 --- a/Mage.Sets/src/mage/cards/m/ManaMatrix.java +++ b/Mage.Sets/src/mage/cards/m/ManaMatrix.java @@ -44,7 +44,7 @@ import mage.filter.predicate.mageobject.CardTypePredicate; */ public class ManaMatrix extends CardImpl { - private static final FilterCard filter = new FilterCard("instant and enchantment spells"); + private static final FilterCard filter = new FilterCard("Instant and enchantment spells"); static { filter.add(Predicates.or( diff --git a/Mage.Sets/src/mage/cards/m/MercadiasDownfall.java b/Mage.Sets/src/mage/cards/m/MercadiasDownfall.java new file mode 100644 index 0000000000..c905d973c0 --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/MercadiasDownfall.java @@ -0,0 +1,112 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.cards.m; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.dynamicvalue.common.StaticValue; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.continuous.BoostAllEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SuperType; +import mage.filter.common.FilterAttackingCreature; +import mage.filter.common.FilterLandPermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.SupertypePredicate; +import mage.game.Game; +import mage.game.combat.CombatGroup; +import mage.game.permanent.Permanent; + +/** + * + * @author jeffwadsworth + */ +public class MercadiasDownfall extends CardImpl { + + private static String rule = "Each attacking creature gets +1/+0 until end of turn for each nonbasic land defending player controls"; + + public MercadiasDownfall(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{R}"); + + // Each attacking creature gets +1/+0 until end of turn for each nonbasic land defending player controls. + this.getSpellAbility().addEffect(new BoostAllEffect(new DefendersNonBasicLandCount(), new StaticValue(0), Duration.EndOfTurn, new FilterAttackingCreature(), true, rule)); + + } + + public MercadiasDownfall(final MercadiasDownfall card) { + super(card); + } + + @Override + public MercadiasDownfall copy() { + return new MercadiasDownfall(this); + } + + class DefendersNonBasicLandCount implements DynamicValue { + + UUID defenderId; + + @Override + public int calculate(Game game, Ability sourceAbility, Effect effect) { + for (CombatGroup group : game.getCombat().getGroups()) { + defenderId = group.getDefenderId(); + if (group.isDefenderIsPlaneswalker()) { + Permanent permanent = game.getPermanent(defenderId); + if (permanent != null) { + defenderId = permanent.getControllerId(); + } + } + FilterLandPermanent filter = new FilterLandPermanent("nonbasic land"); + filter.add(Predicates.not(new SupertypePredicate(SuperType.BASIC))); + System.out.println("The number of nonbasic lands is " + game.getBattlefield().countAll(filter, defenderId, game)); + return game.getBattlefield().countAll(filter, defenderId, game); + } + return 0; + } + + @Override + public DynamicValue copy() { + return new DefendersNonBasicLandCount(); + } + + @Override + public String toString() { + return "X"; + } + + @Override + public String getMessage() { + return "the number of nonbasic lands defending player controls"; + } + } + +} diff --git a/Mage.Sets/src/mage/cards/m/MerfolkRaiders.java b/Mage.Sets/src/mage/cards/m/MerfolkRaiders.java index 21611866db..09e408b51b 100644 --- a/Mage.Sets/src/mage/cards/m/MerfolkRaiders.java +++ b/Mage.Sets/src/mage/cards/m/MerfolkRaiders.java @@ -50,10 +50,10 @@ public class MerfolkRaiders extends CardImpl { this.power = new MageInt(2); this.toughness = new MageInt(3); - // Phasing - this.addAbility(PhasingAbility.getInstance()); // Islandwalk this.addAbility(new IslandwalkAbility()); + // Phasing + this.addAbility(PhasingAbility.getInstance()); } public MerfolkRaiders(final MerfolkRaiders card) { diff --git a/Mage.Sets/src/mage/cards/m/MilitantInquisitor.java b/Mage.Sets/src/mage/cards/m/MilitantInquisitor.java index 05df6afc78..9b3e812798 100644 --- a/Mage.Sets/src/mage/cards/m/MilitantInquisitor.java +++ b/Mage.Sets/src/mage/cards/m/MilitantInquisitor.java @@ -49,7 +49,7 @@ import mage.filter.predicate.mageobject.SubtypePredicate; */ public class MilitantInquisitor extends CardImpl { - private static final FilterControlledPermanent filter = new FilterControlledPermanent("equipment you control"); + private static final FilterControlledPermanent filter = new FilterControlledPermanent("Equipment you control"); static { filter.add(new CardTypePredicate(CardType.ARTIFACT)); diff --git a/Mage.Sets/src/mage/cards/m/MinionOfTheWastes.java b/Mage.Sets/src/mage/cards/m/MinionOfTheWastes.java index 35064a7591..2714adcea4 100644 --- a/Mage.Sets/src/mage/cards/m/MinionOfTheWastes.java +++ b/Mage.Sets/src/mage/cards/m/MinionOfTheWastes.java @@ -105,7 +105,7 @@ class MinionOfTheWastesEffect extends OneShotEffect { controller.loseLife(payAmount, game, false); game.informPlayers(new StringBuilder(sourceCard.getLogName()).append(": ").append(controller.getLogName()) .append(" pays ").append(payAmount).append(" life").toString()); - game.addEffect(new SetPowerToughnessSourceEffect(payAmount, payAmount, Duration.WhileOnBattlefield, SubLayer.SetPT_7b), source); + game.addEffect(new SetPowerToughnessSourceEffect(payAmount, payAmount, Duration.Custom, SubLayer.SetPT_7b), source); return true; } return false; diff --git a/Mage.Sets/src/mage/cards/m/MoralityShift.java b/Mage.Sets/src/mage/cards/m/MoralityShift.java new file mode 100644 index 0000000000..23ab1dea3a --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/MoralityShift.java @@ -0,0 +1,99 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.cards.m; + +import java.util.List; +import java.util.Set; +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.game.Game; +import mage.players.Player; + +/** + * + * @author jeffwadsworth + */ +public class MoralityShift extends CardImpl { + + public MoralityShift(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{5}{B}{B}"); + + + // Exchange your graveyard and library. Then shuffle your library. + this.getSpellAbility().addEffect(new MoralityShiftEffect()); + + } + + public MoralityShift(final MoralityShift card) { + super(card); + } + + @Override + public MoralityShift copy() { + return new MoralityShift(this); + } +} + +class MoralityShiftEffect extends OneShotEffect { + + MoralityShiftEffect() { + super(Outcome.AIDontUseIt); + staticText = "Exchange your graveyard and library. Then shuffle your library."; + } + + MoralityShiftEffect(MoralityShiftEffect effect) { + super(effect); + } + + @Override + public MoralityShiftEffect copy() { + return new MoralityShiftEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller != null) { + List copyLibrary = controller.getLibrary().getCards(game); + Set copyGraveyard = controller.getGraveyard().getCards(game); + controller.getLibrary().clear(); + controller.getGraveyard().clear(); + controller.getGraveyard().addAll(copyLibrary); + controller.getLibrary().addAll(copyGraveyard, game); + controller.shuffleLibrary(source, game); + return true; + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/m/MoxLotus.java b/Mage.Sets/src/mage/cards/m/MoxLotus.java new file mode 100644 index 0000000000..ced2a724b6 --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/MoxLotus.java @@ -0,0 +1,70 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.cards.m; + +import java.util.UUID; +import mage.Mana; +import mage.abilities.Ability; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.AddManaOfAnyColorEffect; +import mage.abilities.mana.SimpleManaAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Zone; + +/** + * + * @author spjspj/psjpsj + */ +public class MoxLotus extends CardImpl { + + public MoxLotus(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{15}"); + + // {t}: Add infinity (or 1*10^9 to account for a potential mana reflection) to your mana pool. + this.addAbility(new SimpleManaAbility(Zone.BATTLEFIELD, Mana.ColorlessMana(1000000000), new TapSourceCost())); + + // {100}: Add one mana of any color to your mana pool. + Ability ability = new SimpleManaAbility(Zone.BATTLEFIELD, new AddManaOfAnyColorEffect(1), new ManaCostsImpl("{100}")); + this.addAbility(ability); + + // You don't lose life due to mana burn. + // Situation normal?? + } + + public MoxLotus(final MoxLotus card) { + super(card); + } + + @Override + public MoxLotus copy() { + return new MoxLotus(this); + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/n/NamelessRace.java b/Mage.Sets/src/mage/cards/n/NamelessRace.java index 0f413268eb..615f1a48fc 100644 --- a/Mage.Sets/src/mage/cards/n/NamelessRace.java +++ b/Mage.Sets/src/mage/cards/n/NamelessRace.java @@ -128,7 +128,7 @@ class NamelessRaceEffect extends OneShotEffect { controller.loseLife(payAmount, game, false); game.informPlayers(new StringBuilder(sourceCard.getLogName()).append(": ").append(controller.getLogName()) .append(" pays ").append(payAmount).append(" life").toString()); - game.addEffect(new SetPowerToughnessSourceEffect(payAmount, payAmount, Duration.WhileOnBattlefield, SubLayer.SetPT_7b), source); + game.addEffect(new SetPowerToughnessSourceEffect(payAmount, payAmount, Duration.Custom, SubLayer.SetPT_7b), source); return true; } return false; diff --git a/Mage.Sets/src/mage/cards/n/NivMizzetTheFiremind.java b/Mage.Sets/src/mage/cards/n/NivMizzetTheFiremind.java index e4b3cc805c..486e8cfd29 100644 --- a/Mage.Sets/src/mage/cards/n/NivMizzetTheFiremind.java +++ b/Mage.Sets/src/mage/cards/n/NivMizzetTheFiremind.java @@ -51,18 +51,23 @@ import mage.target.common.TargetCreatureOrPlayer; public class NivMizzetTheFiremind extends CardImpl { public NivMizzetTheFiremind(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{U}{U}{R}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{U}{U}{R}{R}"); addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.DRAGON); this.subtype.add(SubType.WIZARD); - this.power = new MageInt(4); this.toughness = new MageInt(4); + + // Flying this.addAbility(FlyingAbility.getInstance()); + + // Whenever you draw a card, Niv-Mizzet, the Firemind deals 1 damage to target creature or player. Ability ability = new DrawCardControllerTriggeredAbility(new DamageTargetEffect(1), false); ability.addTarget(new TargetCreatureOrPlayer()); this.addAbility(ability); + + // {T}: Draw a card. this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new DrawCardSourceControllerEffect(1), new TapSourceCost())); } diff --git a/Mage.Sets/src/mage/cards/n/NoMercy.java b/Mage.Sets/src/mage/cards/n/NoMercy.java index 59815c6adb..7c4d0079f4 100644 --- a/Mage.Sets/src/mage/cards/n/NoMercy.java +++ b/Mage.Sets/src/mage/cards/n/NoMercy.java @@ -29,7 +29,6 @@ package mage.cards.n; import java.util.UUID; import mage.abilities.TriggeredAbilityImpl; -import mage.abilities.effects.Effect; import mage.abilities.effects.common.DestroyTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -48,7 +47,7 @@ import mage.target.targetpointer.FixedTarget; public class NoMercy extends CardImpl { public NoMercy(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{2}{B}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{B}{B}"); // Whenever a creature deals damage to you, destroy it. this.addAbility(new NoMercyTriggeredAbility()); @@ -88,9 +87,7 @@ public class NoMercy extends CardImpl { if (event.getPlayerId().equals(this.getControllerId())) { Permanent permanent = game.getPermanent(event.getSourceId()); if (permanent != null && permanent.isCreature()) { - for (Effect effect : this.getEffects()) { - effect.setTargetPointer(new FixedTarget(event.getSourceId())); - } + this.getEffects().setTargetPointer(new FixedTarget(permanent, game)); return true; } } diff --git a/Mage.Sets/src/mage/cards/o/OrimsPrayer.java b/Mage.Sets/src/mage/cards/o/OrimsPrayer.java new file mode 100644 index 0000000000..4ad6e297a7 --- /dev/null +++ b/Mage.Sets/src/mage/cards/o/OrimsPrayer.java @@ -0,0 +1,94 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.cards.o; + +import java.util.UUID; +import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.dynamicvalue.common.AttackingCreatureCount; +import mage.abilities.effects.common.GainLifeEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Zone; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.events.GameEvent.EventType; + +/** + * + * @author L_J + */ +public class OrimsPrayer extends CardImpl { + + public OrimsPrayer(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{W}{W}"); + + // Whenever one or more creatures attack you, you gain 1 life for each attacking creature. + this.addAbility(new OrimsPrayerTriggeredAbility()); + } + + public OrimsPrayer(final OrimsPrayer card) { + super(card); + } + + @Override + public OrimsPrayer copy() { + return new OrimsPrayer(this); + } +} + +class OrimsPrayerTriggeredAbility extends TriggeredAbilityImpl { + + public OrimsPrayerTriggeredAbility() { + super(Zone.BATTLEFIELD, new GainLifeEffect(new AttackingCreatureCount())); + } + + public OrimsPrayerTriggeredAbility(final OrimsPrayerTriggeredAbility ability) { + super(ability); + } + + @Override + public OrimsPrayerTriggeredAbility copy() { + return new OrimsPrayerTriggeredAbility(this); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == EventType.DECLARED_ATTACKERS; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + return game.getCombat().getDefenders().contains(getControllerId()); + } + + @Override + public String getRule() { + return "Whenever one or more creatures attack you, " + super.getRule(); + } +} diff --git a/Mage.Sets/src/mage/cards/p/Pandemonium.java b/Mage.Sets/src/mage/cards/p/Pandemonium.java index 433002b154..38802297f5 100644 --- a/Mage.Sets/src/mage/cards/p/Pandemonium.java +++ b/Mage.Sets/src/mage/cards/p/Pandemonium.java @@ -107,11 +107,11 @@ class PandemoniumEffect extends OneShotEffect { if (enteringCreature != null) { Permanent targetPermanent = game.getPermanent(source.getTargets().getFirstTarget()); if (targetPermanent != null) { - targetPermanent.damage(enteringCreature.getPower().getValue(), source.getSourceId(), game, false, true); + targetPermanent.damage(enteringCreature.getPower().getValue(), enteringCreature.getId(), game, false, true); } else { Player targetPlayer = game.getPlayer(source.getTargets().getFirstTarget()); if (targetPlayer != null) { - targetPlayer.damage(enteringCreature.getPower().getValue(), source.getSourceId(), game, false, true); + targetPlayer.damage(enteringCreature.getPower().getValue(), enteringCreature.getId(), game, false, true); } } return true; diff --git a/Mage.Sets/src/mage/cards/p/ParallelThoughts.java b/Mage.Sets/src/mage/cards/p/ParallelThoughts.java new file mode 100644 index 0000000000..8a803ed86f --- /dev/null +++ b/Mage.Sets/src/mage/cards/p/ParallelThoughts.java @@ -0,0 +1,181 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.cards.p; + +import java.util.Arrays; +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.ReplacementEffectImpl; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.cards.Cards; +import mage.cards.CardsImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.Zone; +import mage.filter.FilterCard; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.events.GameEvent.EventType; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.common.TargetCardInLibrary; +import mage.util.CardUtil; +import mage.util.RandomUtil; + +/** + * + * @author jeffwadsworth + */ +public class ParallelThoughts extends CardImpl { + + public ParallelThoughts(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{3}{U}{U}"); + + // When Parallel Thoughts enters the battlefield, search your library for seven cards, exile them in a face-down pile, and shuffle that pile. Then shuffle your library. + this.addAbility(new EntersBattlefieldTriggeredAbility(new ParallelThoughtsSearchEffect())); + + // If you would draw a card, you may instead put the top card of the pile you exiled into your hand. + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new ParallelThoughtsReplacementEffect())); + + } + + public ParallelThoughts(final ParallelThoughts card) { + super(card); + } + + @Override + public ParallelThoughts copy() { + return new ParallelThoughts(this); + } +} + +class ParallelThoughtsSearchEffect extends OneShotEffect { + + ParallelThoughtsSearchEffect() { + super(Outcome.Neutral); + this.staticText = "search your library for seven cards, exile them in a face-down pile, and shuffle that pile. Then shuffle your library"; + } + + ParallelThoughtsSearchEffect(final ParallelThoughtsSearchEffect effect) { + super(effect); + } + + @Override + public ParallelThoughtsSearchEffect copy() { + return new ParallelThoughtsSearchEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + Permanent permanent = game.getPermanentOrLKIBattlefield(source.getSourceId()); + Cards cardsInExilePile = new CardsImpl(); + if (controller != null + && permanent != null) { + TargetCardInLibrary target = new TargetCardInLibrary(7, new FilterCard()); + if (controller.searchLibrary(target, game)) { + for (UUID targetId : target.getTargets()) { + Card card = controller.getLibrary().getCard(targetId, game); + if (card != null) { + cardsInExilePile.add(card); + } + } + // shuffle that exiled pile + + UUID[] shuffled = cardsInExilePile.toArray(new UUID[0]); + for (int n = shuffled.length - 1; n > 0; n--) { + int r = RandomUtil.nextInt(n + 1); + UUID temp = shuffled[n]; + shuffled[n] = shuffled[r]; + shuffled[r] = temp; + } + cardsInExilePile.clear(); + cardsInExilePile.addAll(Arrays.asList(shuffled)); + + // move to exile zone and turn face down + + for (Card card : cardsInExilePile.getCards(game)) { + controller.moveCardsToExile(card, source, game, false, CardUtil.getCardExileZoneId(game, source), permanent.getLogName()); + card.setFaceDown(true, game); + } + + // shuffle controller library + + controller.shuffleLibrary(source, game); + } + return true; + } + return false; + } +} + +class ParallelThoughtsReplacementEffect extends ReplacementEffectImpl { + + ParallelThoughtsReplacementEffect() { + super(Duration.WhileOnBattlefield, Outcome.DrawCard); + staticText = "If you would draw a card, you may instead put the top card of the pile you exiled with Parallel Thoughts into your hand"; + } + + ParallelThoughtsReplacementEffect(final ParallelThoughtsReplacementEffect effect) { + super(effect); + } + + @Override + public ParallelThoughtsReplacementEffect copy() { + return new ParallelThoughtsReplacementEffect(this); + } + + @Override + public boolean replaceEvent(GameEvent event, Ability source, Game game) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller != null + && !game.getExile().getExileZone(CardUtil.getCardExileZoneId(game, source)).getCards(game).isEmpty()) { + Card card = game.getExile().getExileZone(CardUtil.getCardExileZoneId(game, source)).getCards(game).iterator().next(); + if (card != null) { + controller.moveCards(card, Zone.HAND, source, game); + } + } + return true; + } + + @Override + public boolean checksEventType(GameEvent event, Game game) { + return event.getType() == EventType.DRAW_CARD; + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + return source.getControllerId().equals(event.getPlayerId()); + } +} diff --git a/Mage.Sets/src/mage/cards/p/Penance.java b/Mage.Sets/src/mage/cards/p/Penance.java new file mode 100644 index 0000000000..45616fedf3 --- /dev/null +++ b/Mage.Sets/src/mage/cards/p/Penance.java @@ -0,0 +1,115 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.cards.p; + +import java.util.UUID; +import mage.ObjectColor; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.PutCardFromHandOnTopOfLibraryCost; +import mage.abilities.effects.PreventionEffectImpl; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.Zone; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.target.TargetSource; + +/** + * + * @author jeffwadsworth + */ +public class Penance extends CardImpl { + + public Penance(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{W}"); + + // Put a card from your hand on top of your library: The next time a black or red source of your choice would deal damage this turn, prevent that damage. + this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new PenanceEffect(), new PutCardFromHandOnTopOfLibraryCost())); + + } + + public Penance(final Penance card) { + super(card); + } + + @Override + public Penance copy() { + return new Penance(this); + } +} + +class PenanceEffect extends PreventionEffectImpl { + + private final TargetSource target; + + public PenanceEffect() { + super(Duration.EndOfTurn, Integer.MAX_VALUE, false, false); + this.staticText = "The next time a black or red source of your choice would deal damage to you this turn, prevent that damage."; + this.target = new TargetSource(); + } + + public PenanceEffect(final PenanceEffect effect) { + super(effect); + this.target = effect.target.copy(); + } + + @Override + public PenanceEffect copy() { + return new PenanceEffect(this); + } + + @Override + public void init(Ability source, Game game) { + this.target.choose(Outcome.PreventDamage, source.getControllerId(), source.getSourceId(), game); + super.init(source, game); + } + + @Override + public boolean replaceEvent(GameEvent event, Ability source, Game game) { + this.used = true; + this.discard(); // only one use + return true; + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + if (!this.used + && super.applies(event, source, game)) { + if (event.getTargetId().equals(source.getControllerId()) + && event.getSourceId().equals(target.getFirstTarget())) { + return (game.getObject(target.getFirstTarget()).getColor(game).contains(ObjectColor.BLACK) + || game.getObject(target.getFirstTarget()).getColor(game).contains(ObjectColor.RED)); + } + } + return false; + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/p/PlanarGate.java b/Mage.Sets/src/mage/cards/p/PlanarGate.java index 8ef656f71f..42cea9d0df 100644 --- a/Mage.Sets/src/mage/cards/p/PlanarGate.java +++ b/Mage.Sets/src/mage/cards/p/PlanarGate.java @@ -46,7 +46,7 @@ public class PlanarGate extends CardImpl { super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{6}"); // Creature spells you cast cost up to {2} less to cast. - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new SpellsCostReductionControllerEffect(new FilterCreatureCard("creature spells"), 2, true))); + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new SpellsCostReductionControllerEffect(new FilterCreatureCard("Creature spells"), 2, true))); } public PlanarGate(final PlanarGate card) { diff --git a/Mage.Sets/src/mage/cards/p/Progenitus.java b/Mage.Sets/src/mage/cards/p/Progenitus.java index ecfc73fa50..afec039d10 100644 --- a/Mage.Sets/src/mage/cards/p/Progenitus.java +++ b/Mage.Sets/src/mage/cards/p/Progenitus.java @@ -93,11 +93,6 @@ class ProgenitusProtectionAbility extends ProtectionAbility { return new ProgenitusProtectionAbility(this); } - @Override - public String getRule() { - return "Protection from everything"; - } - @Override public boolean canTarget(MageObject source, Game game) { return false; diff --git a/Mage.Sets/src/mage/cards/p/ProtectiveSphere.java b/Mage.Sets/src/mage/cards/p/ProtectiveSphere.java new file mode 100644 index 0000000000..61b8104232 --- /dev/null +++ b/Mage.Sets/src/mage/cards/p/ProtectiveSphere.java @@ -0,0 +1,134 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.cards.p; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; +import mage.Mana; +import mage.ObjectColor; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.PayLifeCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.PreventionEffectImpl; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.TargetSource; +import mage.util.CardUtil; + +/** + * + * @author jeffwadsworth + */ +public class ProtectiveSphere extends CardImpl { + + public ProtectiveSphere(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{W}"); + + // {1}, Pay 1 life: Prevent all damage that would be dealt to you this turn by a source of your choice that shares a color with the mana spent on this activation cost. + Ability ability = new SimpleActivatedAbility(new ProtectiveSphereEffect(), new ManaCostsImpl("{1}")); + ability.addCost(new PayLifeCost(1)); + this.addAbility(ability); + + } + + public ProtectiveSphere(final ProtectiveSphere card) { + super(card); + } + + @Override + public ProtectiveSphere copy() { + return new ProtectiveSphere(this); + } +} + +class ProtectiveSphereEffect extends PreventionEffectImpl { + + private final TargetSource target; + private static Mana manaUsed; + private static List colorsOfChosenSource = new ArrayList<>(); + + public ProtectiveSphereEffect() { + super(Duration.EndOfTurn, Integer.MAX_VALUE, false, false); + this.staticText = "Prevent all damage that would be dealt to you this turn by a source of your choice that shares a color with the mana spent on this activation cost."; + this.target = new TargetSource(); + } + + public ProtectiveSphereEffect(final ProtectiveSphereEffect effect) { + super(effect); + this.target = effect.target.copy(); + } + + @Override + public ProtectiveSphereEffect copy() { + return new ProtectiveSphereEffect(this); + } + + @Override + public void init(Ability source, Game game) { + target.setNotTarget(true); + target.setRequired(false); + Player controller = game.getPlayer(source.getControllerId()); + Permanent protectiveSphere = game.getPermanent(source.getSourceId()); + if (controller != null + && protectiveSphere != null) { + game.getState().setValue("ProtectiveSphere" + source.getSourceId().toString(), source.getManaCostsToPay().getUsedManaToPay()); //store the mana used to pay + protectiveSphere.addInfo("MANA USED", CardUtil.addToolTipMarkTags("Last mana used for protective ability: " + source.getManaCostsToPay().getUsedManaToPay()), game); + } + this.target.choose(Outcome.PreventDamage, source.getControllerId(), source.getSourceId(), game); + super.init(source, game); + } + + @Override + public boolean replaceEvent(GameEvent event, Ability source, Game game) { + return true; + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + manaUsed = (Mana) game.getState().getValue("ProtectiveSphere" + source.getSourceId().toString()); + if (super.applies(event, source, game)) { + if (event.getTargetId().equals(source.getControllerId()) + && event.getSourceId().equals(target.getFirstTarget())) { + colorsOfChosenSource = game.getObject(target.getFirstTarget()).getColor(game).getColors(); + if (colorsOfChosenSource.stream().anyMatch((c) -> (manaUsed.getColor(c.getColoredManaSymbol()) > 0))) { + return true; + } + } + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/p/ProteusMachine.java b/Mage.Sets/src/mage/cards/p/ProteusMachine.java new file mode 100644 index 0000000000..6fbff759cc --- /dev/null +++ b/Mage.Sets/src/mage/cards/p/ProteusMachine.java @@ -0,0 +1,70 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.cards.p; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.TurnedFaceUpSourceTriggeredAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.continuous.BecomesChosenCreatureTypeSourceEffect; +import mage.abilities.keyword.MorphAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.Duration; +import mage.constants.SubType; + +/** + * + * @author L_J + */ +public class ProteusMachine extends CardImpl { + + public ProteusMachine(UUID ownerId, CardSetInfo setInfo) { + super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT,CardType.CREATURE},"{3}"); + this.subtype.add(SubType.SHAPESHIFTER); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // Morph {0} + this.addAbility(new MorphAbility(this, new ManaCostsImpl("{0}"))); + + // When Proteus Machine is turned face up, it becomes the creature type of your choice. (This effect lasts indefinitely.) + this.addAbility(new TurnedFaceUpSourceTriggeredAbility(new BecomesChosenCreatureTypeSourceEffect(false, Duration.Custom))); + } + + public ProteusMachine(final ProteusMachine card) { + super(card); + } + + @Override + public ProteusMachine copy() { + return new ProteusMachine(this); + } +} diff --git a/Mage.Sets/src/mage/cards/r/Rust.java b/Mage.Sets/src/mage/cards/r/Rust.java index 21dd121bf9..9bf2bac561 100644 --- a/Mage.Sets/src/mage/cards/r/Rust.java +++ b/Mage.Sets/src/mage/cards/r/Rust.java @@ -28,17 +28,13 @@ package mage.cards.r; import java.util.UUID; -import mage.abilities.Ability; import mage.abilities.effects.common.CounterTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.AbilityType; import mage.constants.CardType; -import mage.filter.FilterStackObject; -import mage.filter.predicate.Predicate; -import mage.game.Game; -import mage.game.stack.StackAbility; -import mage.target.common.TargetActivatedOrTriggeredAbility; +import mage.filter.FilterAbility; +import mage.filter.predicate.ability.ArtifactSourcePredicate; +import mage.target.common.TargetActivatedAbility; /** * @@ -46,7 +42,7 @@ import mage.target.common.TargetActivatedOrTriggeredAbility; */ public class Rust extends CardImpl { - private final static FilterStackObject filter = new FilterStackObject("activated ability from an artifact source"); + private final static FilterAbility filter = new FilterAbility("activated ability from an artifact source"); static { filter.add(new ArtifactSourcePredicate()); @@ -57,7 +53,7 @@ public class Rust extends CardImpl { // Counter target activated ability from an artifact source. this.getSpellAbility().addEffect(new CounterTargetEffect()); - this.getSpellAbility().addTarget(new TargetActivatedOrTriggeredAbility(filter)); + this.getSpellAbility().addTarget(new TargetActivatedAbility(filter)); } public Rust(final Rust card) { @@ -69,22 +65,3 @@ public class Rust extends CardImpl { return new Rust(this); } } - -class ArtifactSourcePredicate implements Predicate { - - public ArtifactSourcePredicate() { - } - - @Override - public boolean apply(Ability input, Game game) { - if (input instanceof StackAbility) { - return input.getSourceObject(game).isArtifact() && input.getAbilityType() == AbilityType.ACTIVATED; - } - return false; - } - - @Override - public String toString() { - return "Source(Artifact)"; - } -} diff --git a/Mage.Sets/src/mage/cards/s/SpireTracer.java b/Mage.Sets/src/mage/cards/s/SpireTracer.java index 8c36e4d18c..7846832cbf 100644 --- a/Mage.Sets/src/mage/cards/s/SpireTracer.java +++ b/Mage.Sets/src/mage/cards/s/SpireTracer.java @@ -76,7 +76,7 @@ class CantBeBlockedExceptByCreaturesWithFlyingOrReachEffect extends RestrictionE public CantBeBlockedExceptByCreaturesWithFlyingOrReachEffect() { super(Duration.WhileOnBattlefield); - staticText = "Can't be blocked except by creatures with flying or reach"; + staticText = "{this} can't be blocked except by creatures with flying or reach"; } public CantBeBlockedExceptByCreaturesWithFlyingOrReachEffect(final CantBeBlockedExceptByCreaturesWithFlyingOrReachEffect effect) { diff --git a/Mage.Sets/src/mage/cards/s/SpiritCairn.java b/Mage.Sets/src/mage/cards/s/SpiritCairn.java index 0153958df4..1d1f92e0b4 100644 --- a/Mage.Sets/src/mage/cards/s/SpiritCairn.java +++ b/Mage.Sets/src/mage/cards/s/SpiritCairn.java @@ -51,7 +51,7 @@ public class SpiritCairn extends CardImpl { // Whenever a player discards a card, you may pay {W}. If you do, create a 1/1 white Spirit creature token with flying. this.addAbility(new SimpleTriggeredAbility(Zone.BATTLEFIELD, GameEvent.EventType.DISCARDED_CARD, new DoIfCostPaid(new CreateTokenEffect(new SpiritWhiteToken()), new ManaCostsImpl("{W}")), - "Whenever a player discards a card, you ", + "Whenever a player discards a card, ", false, false)); } diff --git a/Mage.Sets/src/mage/cards/s/SpiritMirror.java b/Mage.Sets/src/mage/cards/s/SpiritMirror.java index 77edaee312..e9c03b254c 100644 --- a/Mage.Sets/src/mage/cards/s/SpiritMirror.java +++ b/Mage.Sets/src/mage/cards/s/SpiritMirror.java @@ -66,7 +66,7 @@ public class SpiritMirror extends CardImpl { this.addAbility(new ConditionalTriggeredAbility( new BeginningOfUpkeepTriggeredAbility(new CreateTokenEffect(new ReflectionToken()), TargetController.YOU, false), new PermanentsOnTheBattlefieldCondition(filterToken, ComparisonType.EQUAL_TO, 0, false), - "At the beginning of your upkeep, if there are no Reflection tokens on the battlefield, create a 2/2 white Reflection creature token")); + "At the beginning of your upkeep, if there are no Reflection tokens on the battlefield, create a 2/2 white Reflection creature token.")); // {0}: Destroy target Reflection. Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DestroyTargetEffect(), new GenericManaCost(0)); diff --git a/Mage.Sets/src/mage/cards/s/StuffyDoll.java b/Mage.Sets/src/mage/cards/s/StuffyDoll.java index 5a7a8986ac..99f01cfe7e 100644 --- a/Mage.Sets/src/mage/cards/s/StuffyDoll.java +++ b/Mage.Sets/src/mage/cards/s/StuffyDoll.java @@ -41,8 +41,8 @@ import mage.abilities.keyword.IndestructibleAbility; 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.constants.Zone; import mage.game.Game; import mage.game.events.GameEvent; @@ -56,7 +56,7 @@ import mage.players.Player; public class StuffyDoll extends CardImpl { public StuffyDoll(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT,CardType.CREATURE},"{5}"); + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{5}"); this.subtype.add(SubType.CONSTRUCT); this.power = new MageInt(0); this.toughness = new MageInt(1); @@ -67,7 +67,7 @@ public class StuffyDoll extends CardImpl { this.addAbility(IndestructibleAbility.getInstance()); // Whenever Stuffy Doll is dealt damage, it deals that much damage to the chosen player. this.addAbility(new StuffyDollTriggeredAbility()); - // {tap}: Stuffy Doll deals 1 damage to itself. + // {T}: Stuffy Doll deals 1 damage to itself. this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new DamageSelfEffect(1), new TapSourceCost())); } diff --git a/Mage.Sets/src/mage/cards/t/TeferisProtection.java b/Mage.Sets/src/mage/cards/t/TeferisProtection.java index 98701104c9..ec5de97c6b 100644 --- a/Mage.Sets/src/mage/cards/t/TeferisProtection.java +++ b/Mage.Sets/src/mage/cards/t/TeferisProtection.java @@ -141,12 +141,7 @@ class TeferisProtectionAbility extends ProtectionAbility { public TeferisProtectionAbility copy() { return new TeferisProtectionAbility(this); } - - @Override - public String getRule() { - return "Protection from everything"; - } - + @Override public boolean canTarget(MageObject source, Game game) { return false; diff --git a/Mage.Sets/src/mage/cards/t/TelekineticBonds.java b/Mage.Sets/src/mage/cards/t/TelekineticBonds.java new file mode 100644 index 0000000000..7f77b77987 --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TelekineticBonds.java @@ -0,0 +1,66 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.cards.t; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.DiscardsACardPlayerTriggeredAbility; +import mage.abilities.effects.common.DoIfCostPaid; +import mage.abilities.effects.common.MayTapOrUntapTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.target.TargetPermanent; + +/** + * + * @author jeffwadsworth + */ +public class TelekineticBonds extends CardImpl { + + public TelekineticBonds(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{U}{U}{U}"); + + + // Whenever a player discards a card, you may pay {1}{U}. If you do, you may tap or untap target permanent. + Ability ability = new DiscardsACardPlayerTriggeredAbility(new DoIfCostPaid(new MayTapOrUntapTargetEffect(), new ManaCostsImpl("{1}{U}")), true); + ability.addTarget(new TargetPermanent()); + this.addAbility(ability); + + } + + public TelekineticBonds(final TelekineticBonds card) { + super(card); + } + + @Override + public TelekineticBonds copy() { + return new TelekineticBonds(this); + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/t/TemporaryTruce.java b/Mage.Sets/src/mage/cards/t/TemporaryTruce.java new file mode 100644 index 0000000000..0efb4ea8dd --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TemporaryTruce.java @@ -0,0 +1,95 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.cards.t; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.game.Game; +import mage.players.Player; + +/** + * + * @author L_J + */ +public class TemporaryTruce extends CardImpl { + + public TemporaryTruce(UUID ownerId, CardSetInfo setInfo) { + super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{1}{W}"); + + // Each player may draw up to two cards. For each card less than two a player draws this way, that player gains 2 life. + this.getSpellAbility().addEffect(new TemporaryTruceEffect()); + } + + public TemporaryTruce(final TemporaryTruce card) { + super(card); + } + + @Override + public TemporaryTruce copy() { + return new TemporaryTruce(this); + } +} + +class TemporaryTruceEffect extends OneShotEffect { + + TemporaryTruceEffect() { + super(Outcome.DrawCard); + this.staticText = "Each player may draw up to two cards. For each card less than two a player draws this way, that player gains 2 life"; + } + + TemporaryTruceEffect(final TemporaryTruceEffect effect) { + super(effect); + } + + @Override + public TemporaryTruceEffect copy() { + return new TemporaryTruceEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller != null) { + for (UUID playerId : game.getState().getPlayersInRange(source.getControllerId(), game)) { + Player player = game.getPlayer(playerId); + if (player != null) { + int cardsToDraw = player.getAmount(0, 2, "Draw how many cards?", game); + player.drawCards(cardsToDraw, game); + player.gainLife((2 - cardsToDraw) * 2, game); + } + } + return true; + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/t/TheImmortalSun.java b/Mage.Sets/src/mage/cards/t/TheImmortalSun.java index 4b1fa19c8a..8b303e3e38 100644 --- a/Mage.Sets/src/mage/cards/t/TheImmortalSun.java +++ b/Mage.Sets/src/mage/cards/t/TheImmortalSun.java @@ -68,7 +68,7 @@ public class TheImmortalSun extends CardImpl { this.addAbility(new BeginningOfDrawTriggeredAbility(new DrawCardSourceControllerEffect(1) .setText("draw an additional card"), TargetController.YOU, false)); // Spells you cast cost {1} less to cast. - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new SpellsCostReductionControllerEffect(new FilterCard("Spells you cast"), 1))); + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new SpellsCostReductionControllerEffect(new FilterCard("Spells"), 1))); // Creatures you control get +1/+1. this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostControlledEffect(1, 1, Duration.WhileOnBattlefield))); } diff --git a/Mage.Sets/src/mage/cards/t/TormentOfHailfire.java b/Mage.Sets/src/mage/cards/t/TormentOfHailfire.java index 504c68648c..79e9e389ec 100644 --- a/Mage.Sets/src/mage/cards/t/TormentOfHailfire.java +++ b/Mage.Sets/src/mage/cards/t/TormentOfHailfire.java @@ -86,7 +86,7 @@ class TormentOfHailfireEffect extends OneShotEffect { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { int repeat = source.getManaCostsToPay().getX(); - for (int i = 0; i < repeat; i++) { + for (int i = 1; i <= repeat; i++) { for (UUID opponentId : game.getOpponents(source.getControllerId())) { Player opponent = game.getPlayer(opponentId); if (opponent != null) { @@ -97,8 +97,9 @@ class TormentOfHailfireEffect extends OneShotEffect { if (opponent.choose(outcome, target, source.getSourceId(), game)) { Permanent permanent = game.getPermanent(target.getFirstTarget()); if (permanent != null) { - permanent.sacrifice(source.getSourceId(), game); - continue; + if (permanent.sacrifice(source.getSourceId(), game)) { + continue; + } } } } diff --git a/Mage.Sets/src/mage/cards/t/TorporOrb.java b/Mage.Sets/src/mage/cards/t/TorporOrb.java index 8aafc5c297..8375b7c62a 100644 --- a/Mage.Sets/src/mage/cards/t/TorporOrb.java +++ b/Mage.Sets/src/mage/cards/t/TorporOrb.java @@ -30,6 +30,7 @@ package mage.cards.t; import java.util.UUID; import mage.MageObject; import mage.abilities.Ability; +import mage.abilities.TriggeredAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.ContinuousRuleModifyingEffectImpl; import mage.cards.CardImpl; @@ -51,7 +52,7 @@ import mage.game.permanent.Permanent; public class TorporOrb extends CardImpl { public TorporOrb(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{2}"); + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{2}"); // Creatures entering the battlefield don't cause abilities to trigger. this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new TorporOrbEffect())); @@ -89,7 +90,7 @@ class TorporOrbEffect extends ContinuousRuleModifyingEffectImpl { if (ability != null && ability.getAbilityType() == AbilityType.TRIGGERED) { Permanent permanent = ((EntersTheBattlefieldEvent) event).getTarget(); if (permanent != null && permanent.isCreature()) { - return true; + return (((TriggeredAbility) ability).checkTrigger(event, game)); } } return false; @@ -97,10 +98,15 @@ class TorporOrbEffect extends ContinuousRuleModifyingEffectImpl { @Override public String getInfoMessage(Ability source, GameEvent event, Game game) { - MageObject mageObject = game.getObject(event.getSourceId()); + MageObject enteringObject = game.getObject(event.getSourceId()); MageObject sourceObject = game.getObject(source.getSourceId()); - if (mageObject != null && sourceObject != null) { - return sourceObject.getLogName() + " prevented ability of " + mageObject.getLogName() + " to trigger"; + Ability ability = (Ability) getValue("targetAbility"); + if (enteringObject != null && sourceObject != null && ability != null) { + MageObject abilitObject = game.getObject(ability.getSourceId()); + if (abilitObject != null) { + return sourceObject.getLogName() + " prevented ability of " + abilitObject.getLogName() + + " to trigger for " + enteringObject.getLogName() + " entering the battlefield."; + } } return null; } diff --git a/Mage.Sets/src/mage/cards/u/UphillBattle.java b/Mage.Sets/src/mage/cards/u/UphillBattle.java new file mode 100644 index 0000000000..86ed97b472 --- /dev/null +++ b/Mage.Sets/src/mage/cards/u/UphillBattle.java @@ -0,0 +1,168 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.cards.u; + +import java.util.HashSet; +import java.util.Set; +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.ReplacementEffectImpl; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.game.Game; +import mage.game.events.EntersTheBattlefieldEvent; +import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; +import mage.watchers.Watcher; +import mage.watchers.common.CreatureWasCastWatcher; + +/** + * + * @author chrvanorle + */ +public class UphillBattle extends CardImpl { + + public UphillBattle(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{R}"); + + // Creatures played by your opponents enter the battlefield tapped. + Ability tapAbility = new SimpleStaticAbility(Zone.BATTLEFIELD, new UphillBattleTapEffect()); + tapAbility.addWatcher(new CreatureWasCastWatcher()); + tapAbility.addWatcher(new PlayCreatureLandWatcher()); + addAbility(tapAbility); + } + + public UphillBattle(final UphillBattle card) { + super(card); + } + + @Override + public UphillBattle copy() { + return new UphillBattle(this); + } +} + +class PlayCreatureLandWatcher extends Watcher { + + final Set playerPlayedLand = new HashSet<>(); // player that played land + final Set landPlayed = new HashSet<>(); // land played + + public PlayCreatureLandWatcher() { + super(PlayCreatureLandWatcher.class.getSimpleName(), WatcherScope.GAME); + } + + public PlayCreatureLandWatcher(final PlayCreatureLandWatcher watcher) { + super(watcher); + playerPlayedLand.addAll(watcher.playerPlayedLand); + landPlayed.addAll(watcher.landPlayed); + } + + @Override + public PlayCreatureLandWatcher copy() { + return new PlayCreatureLandWatcher(this); + } + + @Override + public void watch(GameEvent event, Game game) { + if (event.getType() == GameEvent.EventType.PLAY_LAND) { + Card card = game.getCard(event.getTargetId()); + if (card != null + && card.isLand() + && card.isCreature() + && !playerPlayedLand.contains(event.getPlayerId())) { + playerPlayedLand.add(event.getPlayerId()); + landPlayed.add(event.getTargetId()); + } + } + } + + @Override + public void reset() { + playerPlayedLand.clear(); + landPlayed.clear(); + super.reset(); + } + + public boolean landPlayed(UUID playerId) { + return playerPlayedLand.contains(playerId); + } + + public boolean wasLandPlayed(UUID landId) { + return landPlayed.contains(landId); + } +} + +class UphillBattleTapEffect extends ReplacementEffectImpl { + + UphillBattleTapEffect() { + super(Duration.WhileOnBattlefield, Outcome.Tap); + staticText = "Creatures played by your opponents enter the battlefield tapped"; + } + + UphillBattleTapEffect(final UphillBattleTapEffect effect) { + super(effect); + } + + @Override + public boolean replaceEvent(GameEvent event, Ability source, Game game) { + Permanent target = ((EntersTheBattlefieldEvent) event).getTarget(); + CreatureWasCastWatcher creatureSpellWatcher = (CreatureWasCastWatcher) game.getState().getWatchers().get(CreatureWasCastWatcher.class.getSimpleName()); + PlayCreatureLandWatcher landWatcher = (PlayCreatureLandWatcher) game.getState().getWatchers().get(PlayCreatureLandWatcher.class.getSimpleName()); + + if (target != null + && ((creatureSpellWatcher != null && creatureSpellWatcher.wasCreatureCastThisTurn(target.getId())) + || (landWatcher != null && landWatcher.wasLandPlayed(target.getId())))) { + target.setTapped(true); + } + return false; + } + + @Override + public boolean checksEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.ENTERS_THE_BATTLEFIELD; + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + if (game.getOpponents(source.getControllerId()).contains(event.getPlayerId())) { + Permanent permanent = ((EntersTheBattlefieldEvent) event).getTarget(); + if (permanent != null && permanent.isCreature()) { + return true; + } + } + return false; + } + + @Override + public UphillBattleTapEffect copy() { + return new UphillBattleTapEffect(this); + } +} diff --git a/Mage.Sets/src/mage/cards/v/VodalianWarMachine.java b/Mage.Sets/src/mage/cards/v/VodalianWarMachine.java new file mode 100644 index 0000000000..68cbfa766d --- /dev/null +++ b/Mage.Sets/src/mage/cards/v/VodalianWarMachine.java @@ -0,0 +1,253 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.cards.v; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; +import java.util.UUID; +import mage.MageInt; +import mage.MageObjectReference; +import mage.abilities.Ability; +import mage.abilities.common.DiesTriggeredAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.Cost; +import mage.abilities.costs.common.TapTargetCost; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.combat.CanAttackAsThoughItDidntHaveDefenderSourceEffect; +import mage.abilities.effects.common.continuous.BoostSourceEffect; +import mage.abilities.keyword.DefenderAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.constants.WatcherScope; +import mage.constants.Zone; +import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.SubtypePredicate; +import mage.filter.predicate.permanent.TappedPredicate; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.events.ZoneChangeEvent; +import mage.game.permanent.Permanent; +import mage.game.stack.StackAbility; +import mage.target.common.TargetControlledCreaturePermanent; +import mage.watchers.Watcher; + +/** + * + * @author L_J + */ +public class VodalianWarMachine extends CardImpl { + + private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("untapped Merfolk you control"); + + static { + filter.add(Predicates.not(new TappedPredicate())); + filter.add(new SubtypePredicate(SubType.MERFOLK)); + } + + public VodalianWarMachine(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{U}{U}"); + this.subtype.add(SubType.WALL); + this.power = new MageInt(0); + this.toughness = new MageInt(4); + + // Defender + this.addAbility(DefenderAbility.getInstance()); + + // Tap an untapped Merfolk you control: Vodalian War Machine can attack this turn as though it didn't have defender. + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new CanAttackAsThoughItDidntHaveDefenderSourceEffect(Duration.EndOfTurn), new TapTargetCost(new TargetControlledCreaturePermanent(1, 1, filter, true))); + this.addAbility(ability); + + // Tap an untapped Merfolk you control: Vodalian War Machine gets +2/+1 until end of turn. + this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new BoostSourceEffect(2, 1, Duration.EndOfTurn), new TapTargetCost(new TargetControlledCreaturePermanent(1, 1, filter, true)))); + + // When Vodalian War Machine dies, destroy all Merfolk tapped this turn to pay for its abilities. + this.addAbility(new VodalianWarMachineTriggeredAbility(), new VodalianWarMachineWatcher()); + } + + public VodalianWarMachine(final VodalianWarMachine card) { + super(card); + } + + @Override + public VodalianWarMachine copy() { + return new VodalianWarMachine(this); + } +} + +class VodalianWarMachineTriggeredAbility extends DiesTriggeredAbility { + + public VodalianWarMachineTriggeredAbility() { + super(new VodalianWarMachineEffect(), false); + } + + public VodalianWarMachineTriggeredAbility(VodalianWarMachineTriggeredAbility ability) { + super(ability); + } + + @Override + public VodalianWarMachineTriggeredAbility copy() { + return new VodalianWarMachineTriggeredAbility(this); + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + Permanent before = ((ZoneChangeEvent) event).getTarget(); + if (before == null) { + return false; + } + if (super.checkTrigger(event, game)) { + ZoneChangeEvent zEvent = (ZoneChangeEvent) event; + if (zEvent.getTarget().isTransformable()) { + if (!zEvent.getTarget().getAbilities().contains(this)) { + return false; + } + } + return true; + } + return false; + } + +} + +class VodalianWarMachineEffect extends OneShotEffect { + + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("Merfolk tapped this turn to pay for its abilities"); + + static { + filter.add(new SubtypePredicate(SubType.MERFOLK)); + } + + public VodalianWarMachineEffect() { + super(Outcome.Detriment); + staticText = "destroy all " + filter.getMessage(); + } + + public VodalianWarMachineEffect(final VodalianWarMachineEffect effect) { + super(effect); + } + + @Override + public VodalianWarMachineEffect copy() { + return new VodalianWarMachineEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent sourcePermanent = game.getPermanentOrLKIBattlefield(source.getSourceId()); + if (sourcePermanent != null) { + VodalianWarMachineWatcher watcher = (VodalianWarMachineWatcher) game.getState().getWatchers().get(VodalianWarMachineWatcher.class.getSimpleName()); + if (watcher != null && watcher.getTappedMerfolkIds(sourcePermanent, game) != null) { + for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game)) { + if (watcher.getTappedMerfolkIds(sourcePermanent, game).contains(new MageObjectReference(permanent, game))) { + permanent.destroy(source.getSourceId(), game, false); + } + } + return true; + } + } + return false; + } + +} + +class VodalianWarMachineWatcher extends Watcher { + + public Map> tappedMerfolkIds = new HashMap<>(); + + public VodalianWarMachineWatcher() { + super(VodalianWarMachineWatcher.class.getSimpleName(), WatcherScope.GAME); + } + + public VodalianWarMachineWatcher(final VodalianWarMachineWatcher watcher) { + super(watcher); + // We have for sure to use copied collections, but there is no need to copy the MageObjectReference objects. + for (Entry> entry : watcher.tappedMerfolkIds.entrySet()) { + this.tappedMerfolkIds.put(entry.getKey(), new HashSet<>(entry.getValue())); + } + } + + @Override + public VodalianWarMachineWatcher copy() { + return new VodalianWarMachineWatcher(this); + } + + public Set getTappedMerfolkIds(Permanent permanent, Game game) { + return tappedMerfolkIds.get(new MageObjectReference(permanent, game)); + } + + @Override + public void watch(GameEvent event, Game game) { + if (event.getType() == GameEvent.EventType.ACTIVATED_ABILITY) { + if (event.getSourceId() != null) { + Permanent sourcePermanent = game.getPermanentOrLKIBattlefield(event.getSourceId()); + if (sourcePermanent != null) { + StackAbility stackAbility = (StackAbility) game.getStack().getStackObject(event.getSourceId()); + if (stackAbility != null) { + Ability ability = stackAbility.getStackAbility(); + if (ability != null) { + for (Cost cost : ability.getCosts()) { + if (cost instanceof TapTargetCost && cost.isPaid()) { + TapTargetCost tapCost = (TapTargetCost) cost; + if (tapCost.getTarget().isChosen()) { + MageObjectReference mor = new MageObjectReference(sourcePermanent.getId(), sourcePermanent.getZoneChangeCounter(game), game); + Set toAdd; + if (tappedMerfolkIds.get(mor) == null) { + toAdd = new HashSet<>(); + } else { + toAdd = tappedMerfolkIds.get(mor); + } + for (UUID targetId : tapCost.getTarget().getTargets()) { + toAdd.add(new MageObjectReference(targetId, game)); + } + tappedMerfolkIds.put(mor, toAdd); + break; + } + } + } + } + } + } + } + } + } + + @Override + public void reset() { + super.reset(); + tappedMerfolkIds.clear(); + } +} diff --git a/Mage.Sets/src/mage/cards/w/WarriorsStand.java b/Mage.Sets/src/mage/cards/w/WarriorsStand.java new file mode 100644 index 0000000000..52b4327e47 --- /dev/null +++ b/Mage.Sets/src/mage/cards/w/WarriorsStand.java @@ -0,0 +1,72 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.cards.w; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.CastOnlyDuringPhaseStepSourceAbility; +import mage.abilities.condition.common.AttackedThisStepCondition; +import mage.abilities.effects.common.continuous.BoostControlledEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.PhaseStep; +import mage.constants.TurnPhase; +import mage.filter.StaticFilters; +import mage.watchers.common.PlayerAttackedStepWatcher; +/** + * + * @author L_J + */ +public class WarriorsStand extends CardImpl { + + public WarriorsStand(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{W}"); + + // Cast Warrior's Stand only during the declare attackers step and only if you've been attacked this step. + Ability ability = new CastOnlyDuringPhaseStepSourceAbility( + TurnPhase.COMBAT, PhaseStep.DECLARE_ATTACKERS, AttackedThisStepCondition.instance, + "Cast {this} only during the declare attackers step and only if you've been attacked this step." + ); + ability.addWatcher(new PlayerAttackedStepWatcher()); + this.addAbility(ability); + + // Creatures you control get +2/+2 until end of turn. + this.getSpellAbility().addEffect(new BoostControlledEffect(2, 2, Duration.EndOfTurn, StaticFilters.FILTER_PERMANENT_CREATURE, false)); + } + + public WarriorsStand(final WarriorsStand card) { + super(card); + } + + @Override + public WarriorsStand copy() { + return new WarriorsStand(this); + } +} diff --git a/Mage.Sets/src/mage/cards/w/WindShear.java b/Mage.Sets/src/mage/cards/w/WindShear.java new file mode 100644 index 0000000000..4d70f93c00 --- /dev/null +++ b/Mage.Sets/src/mage/cards/w/WindShear.java @@ -0,0 +1,69 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.cards.w; + +import java.util.UUID; +import mage.abilities.effects.common.continuous.BoostAllEffect; +import mage.abilities.effects.common.continuous.LoseAbilityAllEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.filter.common.FilterAttackingCreature; +import mage.filter.predicate.mageobject.AbilityPredicate; + +/** + * + * @author L_J + */ +public class WindShear extends CardImpl { + + private static final FilterAttackingCreature filter = new FilterAttackingCreature("Attacking creatures with flying"); + + static { + filter.add(new AbilityPredicate(FlyingAbility.class)); + } + + public WindShear(UUID ownerId, CardSetInfo setInfo) { + super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{2}{G}"); + + // Attacking creatures with flying get -2/-2 and lose flying until end of turn. + this.getSpellAbility().addEffect(new BoostAllEffect(-2, -2, Duration.EndOfTurn, filter, false).setText("Attacking creatures with flying get -2/-2")); + this.getSpellAbility().addEffect(new LoseAbilityAllEffect(FlyingAbility.getInstance(), Duration.EndOfTurn, filter).setText("and lose flying until end of turn")); + } + + public WindShear(final WindShear card) { + super(card); + } + + @Override + public WindShear copy() { + return new WindShear(this); + } +} diff --git a/Mage.Sets/src/mage/cards/w/WoodElemental.java b/Mage.Sets/src/mage/cards/w/WoodElemental.java new file mode 100644 index 0000000000..ac6bc424c7 --- /dev/null +++ b/Mage.Sets/src/mage/cards/w/WoodElemental.java @@ -0,0 +1,133 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.cards.w; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.AsEntersBattlefieldAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.InfoEffect; +import mage.abilities.effects.common.continuous.SetPowerToughnessSourceEffect; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.SubLayer; +import mage.constants.Zone; +import mage.filter.common.FilterControlledPermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.SubtypePredicate; +import mage.filter.predicate.permanent.TappedPredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.Target; +import mage.target.common.TargetControlledPermanent; + +/** + * + * @author L_J + */ +public class WoodElemental extends CardImpl { + + public WoodElemental(UUID ownerId, CardSetInfo setInfo) { + super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{G}"); + this.subtype.add(SubType.ELEMENTAL); + this.power = new MageInt(0); + this.toughness = new MageInt(0); + + // As Wood Elemental enters the battlefield, sacrifice any number of untapped Forests. + this.addAbility(new AsEntersBattlefieldAbility(new WoodElementalEffect())); + + // Wood Elemental's power and toughness are each equal to the number of Forests sacrificed as it entered the battlefield. + this.addAbility(new SimpleStaticAbility(Zone.ALL, new InfoEffect("{this}'s power and toughness are each equal to the number of Forests sacrificed as it entered the battlefield"))); + } + + public WoodElemental(final WoodElemental card) { + super(card); + } + + @Override + public WoodElemental copy() { + return new WoodElemental(this); + } +} + +class WoodElementalEffect extends OneShotEffect { + + private static final FilterControlledPermanent filter = new FilterControlledPermanent("untapped Forests you control"); + + static { + filter.add(Predicates.not(new TappedPredicate())); + filter.add(new SubtypePredicate(SubType.FOREST)); + } + + public WoodElementalEffect() { + super(Outcome.Sacrifice); + staticText = "sacrifice any number of untapped Forests"; + } + + public WoodElementalEffect(final WoodElementalEffect effect) { + super(effect); + } + + @Override + public WoodElementalEffect copy() { + return new WoodElementalEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + Card sourceCard = game.getCard(source.getSourceId()); + if (controller != null && sourceCard != null) { + Target target = new TargetControlledPermanent(0, Integer.MAX_VALUE, filter, true); + if (target.canChoose(source.getSourceId(), source.getControllerId(), game) + && controller.chooseTarget(Outcome.Detriment, target, source, game)) { + if (!target.getTargets().isEmpty()) { + int sacrificedForests = target.getTargets().size(); + game.informPlayers(controller.getLogName() + " sacrifices " + sacrificedForests + " untapped Forests for " + sourceCard.getLogName()); + for (UUID targetId : target.getTargets()) { + Permanent targetPermanent = game.getPermanent(targetId); + if (targetPermanent != null) { + targetPermanent.sacrifice(source.getSourceId(), game); + } + } + game.addEffect(new SetPowerToughnessSourceEffect(sacrificedForests, sacrificedForests, Duration.Custom, SubLayer.SetPT_7b), source); + return true; + } + } + } + return false; + } +} diff --git a/Mage.Sets/src/mage/sets/Exodus.java b/Mage.Sets/src/mage/sets/Exodus.java index 851bd91649..7c4066522a 100644 --- a/Mage.Sets/src/mage/sets/Exodus.java +++ b/Mage.Sets/src/mage/sets/Exodus.java @@ -123,6 +123,7 @@ public class Exodus extends ExpansionSet { cards.add(new SetCardInfo("Pandemonium", 93, Rarity.RARE, mage.cards.p.Pandemonium.class)); cards.add(new SetCardInfo("Peace of Mind", 13, Rarity.UNCOMMON, mage.cards.p.PeaceOfMind.class)); cards.add(new SetCardInfo("Pegasus Stampede", 14, Rarity.UNCOMMON, mage.cards.p.PegasusStampede.class)); + cards.add(new SetCardInfo("Penance", 15, Rarity.UNCOMMON, mage.cards.p.Penance.class)); cards.add(new SetCardInfo("Pit Spawn", 70, Rarity.RARE, mage.cards.p.PitSpawn.class)); cards.add(new SetCardInfo("Plaguebearer", 71, Rarity.RARE, mage.cards.p.Plaguebearer.class)); cards.add(new SetCardInfo("Plated Rootwalla", 116, Rarity.COMMON, mage.cards.p.PlatedRootwalla.class)); diff --git a/Mage.Sets/src/mage/sets/FallenEmpires.java b/Mage.Sets/src/mage/sets/FallenEmpires.java index 224a062831..a6a5870493 100644 --- a/Mage.Sets/src/mage/sets/FallenEmpires.java +++ b/Mage.Sets/src/mage/sets/FallenEmpires.java @@ -268,6 +268,7 @@ public class FallenEmpires extends ExpansionSet { cards.add(new SetCardInfo("Vodalian Soldiers", 63, Rarity.COMMON, VodalianSoldiers.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Vodalian Soldiers", 64, Rarity.COMMON, VodalianSoldiers.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Vodalian Soldiers", 65, Rarity.COMMON, VodalianSoldiers.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Vodalian War Machine", 66, Rarity.RARE, mage.cards.v.VodalianWarMachine.class)); cards.add(new SetCardInfo("Zelyon Sword", 176, Rarity.RARE, mage.cards.z.ZelyonSword.class)); } } diff --git a/Mage.Sets/src/mage/sets/Invasion.java b/Mage.Sets/src/mage/sets/Invasion.java index 5e88651b8f..8e7acf64f8 100644 --- a/Mage.Sets/src/mage/sets/Invasion.java +++ b/Mage.Sets/src/mage/sets/Invasion.java @@ -1,387 +1,388 @@ -/* - * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, are - * permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this list of - * conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list - * of conditions and the following disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND - * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * The views and conclusions contained in the software and documentation are those of the - * authors and should not be interpreted as representing official policies, either expressed - * or implied, of BetaSteward_at_googlemail.com. - */ -package mage.sets; - -import mage.cards.ExpansionSet; -import mage.constants.Rarity; -import mage.constants.SetType; - -/** - * - * @author North - */ -public class Invasion extends ExpansionSet { - - private static final Invasion instance = new Invasion(); - - public static Invasion getInstance() { - return instance; - } - - private Invasion() { - super("Invasion", "INV", ExpansionSet.buildDate(2000, 9, 2), SetType.EXPANSION); - this.blockName = "Invasion"; - this.hasBoosters = true; - this.numBoosterLands = 0; - this.numBoosterCommon = 11; - this.numBoosterUncommon = 3; - this.numBoosterRare = 1; - this.ratioBoosterMythic = 0; - cards.add(new SetCardInfo("Absorb", 226, Rarity.RARE, mage.cards.a.Absorb.class)); - cards.add(new SetCardInfo("Addle", 91, Rarity.UNCOMMON, mage.cards.a.Addle.class)); - cards.add(new SetCardInfo("Aether Rift", 227, Rarity.RARE, mage.cards.a.AetherRift.class)); - cards.add(new SetCardInfo("Aggressive Urge", 181, Rarity.COMMON, mage.cards.a.AggressiveUrge.class)); - cards.add(new SetCardInfo("Agonizing Demise", 92, Rarity.COMMON, mage.cards.a.AgonizingDemise.class)); - cards.add(new SetCardInfo("Alabaster Leech", 1, Rarity.RARE, mage.cards.a.AlabasterLeech.class)); - cards.add(new SetCardInfo("Alloy Golem", 297, Rarity.UNCOMMON, mage.cards.a.AlloyGolem.class)); - cards.add(new SetCardInfo("Ancient Kavu", 136, Rarity.COMMON, mage.cards.a.AncientKavu.class)); - cards.add(new SetCardInfo("Ancient Spring", 319, Rarity.COMMON, mage.cards.a.AncientSpring.class)); - cards.add(new SetCardInfo("Andradite Leech", 93, Rarity.RARE, mage.cards.a.AndraditeLeech.class)); - cards.add(new SetCardInfo("Angelic Shield", 228, Rarity.UNCOMMON, mage.cards.a.AngelicShield.class)); - cards.add(new SetCardInfo("Angel of Mercy", 2, Rarity.UNCOMMON, mage.cards.a.AngelOfMercy.class)); - cards.add(new SetCardInfo("Annihilate", 94, Rarity.UNCOMMON, mage.cards.a.Annihilate.class)); - cards.add(new SetCardInfo("Archaeological Dig", 320, Rarity.UNCOMMON, mage.cards.a.ArchaeologicalDig.class)); - cards.add(new SetCardInfo("Ardent Soldier", 3, Rarity.COMMON, mage.cards.a.ArdentSoldier.class)); - cards.add(new SetCardInfo("Armadillo Cloak", 229, Rarity.COMMON, mage.cards.a.ArmadilloCloak.class)); - cards.add(new SetCardInfo("Armored Guardian", 230, Rarity.RARE, mage.cards.a.ArmoredGuardian.class)); - cards.add(new SetCardInfo("Artifact Mutation", 231, Rarity.RARE, mage.cards.a.ArtifactMutation.class)); - cards.add(new SetCardInfo("Assault // Battery", 295, Rarity.UNCOMMON, mage.cards.a.AssaultBattery.class)); - cards.add(new SetCardInfo("Atalya, Samite Master", 4, Rarity.RARE, mage.cards.a.AtalyaSamiteMaster.class)); - cards.add(new SetCardInfo("Aura Mutation", 232, Rarity.RARE, mage.cards.a.AuraMutation.class)); - cards.add(new SetCardInfo("Aura Shards", 233, Rarity.UNCOMMON, mage.cards.a.AuraShards.class)); - cards.add(new SetCardInfo("Backlash", 234, Rarity.UNCOMMON, mage.cards.b.Backlash.class)); - cards.add(new SetCardInfo("Barrin's Spite", 235, Rarity.RARE, mage.cards.b.BarrinsSpite.class)); - cards.add(new SetCardInfo("Barrin's Unmaking", 46, Rarity.COMMON, mage.cards.b.BarrinsUnmaking.class)); - cards.add(new SetCardInfo("Benalish Emissary", 5, Rarity.UNCOMMON, mage.cards.b.BenalishEmissary.class)); - cards.add(new SetCardInfo("Benalish Heralds", 6, Rarity.UNCOMMON, mage.cards.b.BenalishHeralds.class)); - cards.add(new SetCardInfo("Benalish Lancer", 7, Rarity.COMMON, mage.cards.b.BenalishLancer.class)); - cards.add(new SetCardInfo("Benalish Trapper", 8, Rarity.COMMON, mage.cards.b.BenalishTrapper.class)); - cards.add(new SetCardInfo("Bind", 182, Rarity.RARE, mage.cards.b.Bind.class)); - cards.add(new SetCardInfo("Blazing Specter", 236, Rarity.RARE, mage.cards.b.BlazingSpecter.class)); - cards.add(new SetCardInfo("Blinding Light", 9, Rarity.UNCOMMON, mage.cards.b.BlindingLight.class)); - cards.add(new SetCardInfo("Blind Seer", 47, Rarity.RARE, mage.cards.b.BlindSeer.class)); - cards.add(new SetCardInfo("Bloodstone Cameo", 298, Rarity.UNCOMMON, mage.cards.b.BloodstoneCameo.class)); - cards.add(new SetCardInfo("Blurred Mongoose", 183, Rarity.RARE, mage.cards.b.BlurredMongoose.class)); - cards.add(new SetCardInfo("Bog Initiate", 95, Rarity.COMMON, mage.cards.b.BogInitiate.class)); - cards.add(new SetCardInfo("Breaking Wave", 48, Rarity.RARE, mage.cards.b.BreakingWave.class)); - cards.add(new SetCardInfo("Breath of Darigaaz", 138, Rarity.UNCOMMON, mage.cards.b.BreathOfDarigaaz.class)); - cards.add(new SetCardInfo("Callous Giant", 139, Rarity.RARE, mage.cards.c.CallousGiant.class)); - cards.add(new SetCardInfo("Canopy Surge", 184, Rarity.UNCOMMON, mage.cards.c.CanopySurge.class)); - cards.add(new SetCardInfo("Capashen Unicorn", 10, Rarity.COMMON, mage.cards.c.CapashenUnicorn.class)); - cards.add(new SetCardInfo("Captain Sisay", 237, Rarity.RARE, mage.cards.c.CaptainSisay.class)); - cards.add(new SetCardInfo("Cauldron Dance", 238, Rarity.UNCOMMON, mage.cards.c.CauldronDance.class)); - cards.add(new SetCardInfo("Chaotic Strike", 140, Rarity.UNCOMMON, mage.cards.c.ChaoticStrike.class)); - cards.add(new SetCardInfo("Charging Troll", 239, Rarity.UNCOMMON, mage.cards.c.ChargingTroll.class)); - cards.add(new SetCardInfo("Chromatic Sphere", 299, Rarity.UNCOMMON, mage.cards.c.ChromaticSphere.class)); - cards.add(new SetCardInfo("Cinder Shade", 240, Rarity.UNCOMMON, mage.cards.c.CinderShade.class)); - cards.add(new SetCardInfo("Coalition Victory", 241, Rarity.RARE, mage.cards.c.CoalitionVictory.class)); - cards.add(new SetCardInfo("Coastal Tower", 321, Rarity.UNCOMMON, mage.cards.c.CoastalTower.class)); - cards.add(new SetCardInfo("Collapsing Borders", 141, Rarity.RARE, mage.cards.c.CollapsingBorders.class)); - cards.add(new SetCardInfo("Collective Restraint", 49, Rarity.RARE, mage.cards.c.CollectiveRestraint.class)); - cards.add(new SetCardInfo("Cremate", 96, Rarity.UNCOMMON, mage.cards.c.Cremate.class)); - cards.add(new SetCardInfo("Crimson Acolyte", 11, Rarity.COMMON, mage.cards.c.CrimsonAcolyte.class)); - cards.add(new SetCardInfo("Crosis's Attendant", 300, Rarity.UNCOMMON, mage.cards.c.CrosissAttendant.class)); - cards.add(new SetCardInfo("Crosis, the Purger", 242, Rarity.RARE, mage.cards.c.CrosisThePurger.class)); - cards.add(new SetCardInfo("Crown of Flames", 142, Rarity.COMMON, mage.cards.c.CrownOfFlames.class)); - cards.add(new SetCardInfo("Crusading Knight", 12, Rarity.RARE, mage.cards.c.CrusadingKnight.class)); - cards.add(new SetCardInfo("Crypt Angel", 97, Rarity.RARE, mage.cards.c.CryptAngel.class)); - cards.add(new SetCardInfo("Cursed Flesh", 98, Rarity.COMMON, mage.cards.c.CursedFlesh.class)); - cards.add(new SetCardInfo("Darigaaz's Attendant", 301, Rarity.UNCOMMON, mage.cards.d.DarigaazsAttendant.class)); - cards.add(new SetCardInfo("Darigaaz, the Igniter", 243, Rarity.RARE, mage.cards.d.DarigaazTheIgniter.class)); - cards.add(new SetCardInfo("Defiling Tears", 99, Rarity.UNCOMMON, mage.cards.d.DefilingTears.class)); - cards.add(new SetCardInfo("Devouring Strossus", 101, Rarity.RARE, mage.cards.d.DevouringStrossus.class)); - cards.add(new SetCardInfo("Dismantling Blow", 14, Rarity.COMMON, mage.cards.d.DismantlingBlow.class)); - cards.add(new SetCardInfo("Disrupt", 51, Rarity.UNCOMMON, mage.cards.d.Disrupt.class)); - cards.add(new SetCardInfo("Distorting Wake", 52, Rarity.RARE, mage.cards.d.DistortingWake.class)); - cards.add(new SetCardInfo("Divine Presence", 15, Rarity.RARE, mage.cards.d.DivinePresence.class)); - cards.add(new SetCardInfo("Do or Die", 102, Rarity.RARE, mage.cards.d.DoOrDie.class)); - cards.add(new SetCardInfo("Drake-Skull Cameo", 302, Rarity.UNCOMMON, mage.cards.d.DrakeSkullCameo.class)); - cards.add(new SetCardInfo("Dream Thrush", 53, Rarity.COMMON, mage.cards.d.DreamThrush.class)); - cards.add(new SetCardInfo("Dredge", 103, Rarity.UNCOMMON, mage.cards.d.Dredge.class)); - cards.add(new SetCardInfo("Dromar's Attendant", 303, Rarity.UNCOMMON, mage.cards.d.DromarsAttendant.class)); - cards.add(new SetCardInfo("Dromar, the Banisher", 244, Rarity.RARE, mage.cards.d.DromarTheBanisher.class)); - cards.add(new SetCardInfo("Dueling Grounds", 245, Rarity.RARE, mage.cards.d.DuelingGrounds.class)); - cards.add(new SetCardInfo("Duskwalker", 104, Rarity.COMMON, mage.cards.d.Duskwalker.class)); - cards.add(new SetCardInfo("Elfhame Palace", 322, Rarity.UNCOMMON, mage.cards.e.ElfhamePalace.class)); - cards.add(new SetCardInfo("Elfhame Sanctuary", 185, Rarity.UNCOMMON, mage.cards.e.ElfhameSanctuary.class)); - cards.add(new SetCardInfo("Elvish Champion", 186, Rarity.RARE, mage.cards.e.ElvishChampion.class)); - cards.add(new SetCardInfo("Empress Galina", 54, Rarity.RARE, mage.cards.e.EmpressGalina.class)); - cards.add(new SetCardInfo("Exclude", 56, Rarity.COMMON, mage.cards.e.Exclude.class)); - cards.add(new SetCardInfo("Exotic Curse", 105, Rarity.COMMON, mage.cards.e.ExoticCurse.class)); - cards.add(new SetCardInfo("Explosive Growth", 187, Rarity.COMMON, mage.cards.e.ExplosiveGrowth.class)); - cards.add(new SetCardInfo("Fact or Fiction", 57, Rarity.UNCOMMON, mage.cards.f.FactOrFiction.class)); - cards.add(new SetCardInfo("Faerie Squadron", 58, Rarity.COMMON, mage.cards.f.FaerieSquadron.class)); - cards.add(new SetCardInfo("Fertile Ground", 188, Rarity.COMMON, mage.cards.f.FertileGround.class)); - cards.add(new SetCardInfo("Firebrand Ranger", 143, Rarity.UNCOMMON, mage.cards.f.FirebrandRanger.class)); - cards.add(new SetCardInfo("Firescreamer", 106, Rarity.COMMON, mage.cards.f.Firescreamer.class)); - cards.add(new SetCardInfo("Fires of Yavimaya", 246, Rarity.UNCOMMON, mage.cards.f.FiresOfYavimaya.class)); - cards.add(new SetCardInfo("Forest", 347, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Forest", 348, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Forest", 349, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Forest", 350, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Frenzied Tilling", 247, Rarity.COMMON, mage.cards.f.FrenziedTilling.class)); - cards.add(new SetCardInfo("Galina's Knight", 248, Rarity.COMMON, mage.cards.g.GalinasKnight.class)); - cards.add(new SetCardInfo("Geothermal Crevice", 323, Rarity.COMMON, mage.cards.g.GeothermalCrevice.class)); - cards.add(new SetCardInfo("Ghitu Fire", 144, Rarity.RARE, mage.cards.g.GhituFire.class)); - cards.add(new SetCardInfo("Glimmering Angel", 17, Rarity.COMMON, mage.cards.g.GlimmeringAngel.class)); - cards.add(new SetCardInfo("Global Ruin", 18, Rarity.RARE, mage.cards.g.GlobalRuin.class)); - cards.add(new SetCardInfo("Goblin Spy", 145, Rarity.UNCOMMON, mage.cards.g.GoblinSpy.class)); - cards.add(new SetCardInfo("Goham Djinn", 107, Rarity.UNCOMMON, mage.cards.g.GohamDjinn.class)); - cards.add(new SetCardInfo("Halam Djinn", 146, Rarity.UNCOMMON, mage.cards.h.HalamDjinn.class)); - cards.add(new SetCardInfo("Hanna, Ship's Navigator", 249, Rarity.RARE, mage.cards.h.HannaShipsNavigator.class)); - cards.add(new SetCardInfo("Harrow", 189, Rarity.COMMON, mage.cards.h.Harrow.class)); - cards.add(new SetCardInfo("Harsh Judgment", 19, Rarity.RARE, mage.cards.h.HarshJudgment.class)); - cards.add(new SetCardInfo("Hate Weaver", 108, Rarity.UNCOMMON, mage.cards.h.HateWeaver.class)); - cards.add(new SetCardInfo("Heroes' Reunion", 250, Rarity.UNCOMMON, mage.cards.h.HeroesReunion.class)); - cards.add(new SetCardInfo("Holy Day", 20, Rarity.COMMON, mage.cards.h.HolyDay.class)); - cards.add(new SetCardInfo("Hooded Kavu", 147, Rarity.COMMON, mage.cards.h.HoodedKavu.class)); - cards.add(new SetCardInfo("Horned Cheetah", 251, Rarity.UNCOMMON, mage.cards.h.HornedCheetah.class)); - cards.add(new SetCardInfo("Hunting Kavu", 252, Rarity.UNCOMMON, mage.cards.h.HuntingKavu.class)); - cards.add(new SetCardInfo("Hypnotic Cloud", 109, Rarity.COMMON, mage.cards.h.HypnoticCloud.class)); - cards.add(new SetCardInfo("Irrigation Ditch", 324, Rarity.COMMON, mage.cards.i.IrrigationDitch.class)); - cards.add(new SetCardInfo("Island", 335, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Island", 336, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Island", 337, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Island", 338, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Jade Leech", 190, Rarity.RARE, mage.cards.j.JadeLeech.class)); - cards.add(new SetCardInfo("Juntu Stakes", 304, Rarity.RARE, mage.cards.j.JuntuStakes.class)); - cards.add(new SetCardInfo("Kangee, Aerie Keeper", 253, Rarity.RARE, mage.cards.k.KangeeAerieKeeper.class)); - cards.add(new SetCardInfo("Kavu Aggressor", 148, Rarity.COMMON, mage.cards.k.KavuAggressor.class)); - cards.add(new SetCardInfo("Kavu Chameleon", 191, Rarity.UNCOMMON, mage.cards.k.KavuChameleon.class)); - cards.add(new SetCardInfo("Kavu Climber", 192, Rarity.COMMON, mage.cards.k.KavuClimber.class)); - cards.add(new SetCardInfo("Kavu Lair", 193, Rarity.RARE, mage.cards.k.KavuLair.class)); - cards.add(new SetCardInfo("Kavu Monarch", 149, Rarity.RARE, mage.cards.k.KavuMonarch.class)); - cards.add(new SetCardInfo("Kavu Runner", 150, Rarity.UNCOMMON, mage.cards.k.KavuRunner.class)); - cards.add(new SetCardInfo("Kavu Scout", 151, Rarity.COMMON, mage.cards.k.KavuScout.class)); - cards.add(new SetCardInfo("Kavu Titan", 194, Rarity.RARE, mage.cards.k.KavuTitan.class)); - cards.add(new SetCardInfo("Keldon Necropolis", 325, Rarity.RARE, mage.cards.k.KeldonNecropolis.class)); - cards.add(new SetCardInfo("Liberate", 21, Rarity.UNCOMMON, mage.cards.l.Liberate.class)); - cards.add(new SetCardInfo("Lightning Dart", 152, Rarity.UNCOMMON, mage.cards.l.LightningDart.class)); - cards.add(new SetCardInfo("Llanowar Cavalry", 195, Rarity.COMMON, mage.cards.l.LlanowarCavalry.class)); - cards.add(new SetCardInfo("Llanowar Elite", 196, Rarity.COMMON, mage.cards.l.LlanowarElite.class)); - cards.add(new SetCardInfo("Llanowar Knight", 254, Rarity.COMMON, mage.cards.l.LlanowarKnight.class)); - cards.add(new SetCardInfo("Llanowar Vanguard", 197, Rarity.COMMON, mage.cards.l.LlanowarVanguard.class)); - cards.add(new SetCardInfo("Lobotomy", 255, Rarity.UNCOMMON, mage.cards.l.Lobotomy.class)); - cards.add(new SetCardInfo("Lotus Guardian", 305, Rarity.RARE, mage.cards.l.LotusGuardian.class)); - cards.add(new SetCardInfo("Mana Maze", 59, Rarity.RARE, mage.cards.m.ManaMaze.class)); - cards.add(new SetCardInfo("Maniacal Rage", 155, Rarity.COMMON, mage.cards.m.ManiacalRage.class)); - cards.add(new SetCardInfo("Manipulate Fate", 60, Rarity.UNCOMMON, mage.cards.m.ManipulateFate.class)); - cards.add(new SetCardInfo("Marauding Knight", 110, Rarity.RARE, mage.cards.m.MaraudingKnight.class)); - cards.add(new SetCardInfo("Metathran Transport", 62, Rarity.UNCOMMON, mage.cards.m.MetathranTransport.class)); - cards.add(new SetCardInfo("Metathran Zombie", 63, Rarity.COMMON, mage.cards.m.MetathranZombie.class)); - cards.add(new SetCardInfo("Meteor Storm", 256, Rarity.RARE, mage.cards.m.MeteorStorm.class)); - cards.add(new SetCardInfo("Might Weaver", 198, Rarity.UNCOMMON, mage.cards.m.MightWeaver.class)); - cards.add(new SetCardInfo("Molimo, Maro-Sorcerer", 199, Rarity.RARE, mage.cards.m.MolimoMaroSorcerer.class)); - cards.add(new SetCardInfo("Mountain", 343, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Mountain", 344, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Mountain", 345, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Mountain", 346, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Mourning", 111, Rarity.COMMON, mage.cards.m.Mourning.class)); - cards.add(new SetCardInfo("Nightscape Apprentice", 112, Rarity.COMMON, mage.cards.n.NightscapeApprentice.class)); - cards.add(new SetCardInfo("Nightscape Master", 113, Rarity.RARE, mage.cards.n.NightscapeMaster.class)); - cards.add(new SetCardInfo("Noble Panther", 257, Rarity.RARE, mage.cards.n.NoblePanther.class)); - cards.add(new SetCardInfo("Nomadic Elf", 200, Rarity.COMMON, mage.cards.n.NomadicElf.class)); - cards.add(new SetCardInfo("Obliterate", 156, Rarity.RARE, mage.cards.o.Obliterate.class)); - cards.add(new SetCardInfo("Obsidian Acolyte", 22, Rarity.COMMON, mage.cards.o.ObsidianAcolyte.class)); - cards.add(new SetCardInfo("Opt", 64, Rarity.COMMON, mage.cards.o.Opt.class)); - cards.add(new SetCardInfo("Ordered Migration", 258, Rarity.UNCOMMON, mage.cards.o.OrderedMigration.class)); - cards.add(new SetCardInfo("Orim's Touch", 23, Rarity.COMMON, mage.cards.o.OrimsTouch.class)); - cards.add(new SetCardInfo("Overabundance", 259, Rarity.RARE, mage.cards.o.Overabundance.class)); - cards.add(new SetCardInfo("Overload", 157, Rarity.COMMON, mage.cards.o.Overload.class)); - cards.add(new SetCardInfo("Pain // Suffering", 294, Rarity.UNCOMMON, mage.cards.p.PainSuffering.class)); - cards.add(new SetCardInfo("Phantasmal Terrain", 65, Rarity.COMMON, mage.cards.p.PhantasmalTerrain.class)); - cards.add(new SetCardInfo("Phyrexian Altar", 306, Rarity.RARE, mage.cards.p.PhyrexianAltar.class)); - cards.add(new SetCardInfo("Phyrexian Battleflies", 114, Rarity.COMMON, mage.cards.p.PhyrexianBattleflies.class)); - cards.add(new SetCardInfo("Phyrexian Delver", 115, Rarity.RARE, mage.cards.p.PhyrexianDelver.class)); - cards.add(new SetCardInfo("Phyrexian Infiltrator", 116, Rarity.RARE, mage.cards.p.PhyrexianInfiltrator.class)); - cards.add(new SetCardInfo("Phyrexian Lens", 307, Rarity.RARE, mage.cards.p.PhyrexianLens.class)); - cards.add(new SetCardInfo("Phyrexian Reaper", 117, Rarity.COMMON, mage.cards.p.PhyrexianReaper.class)); - cards.add(new SetCardInfo("Phyrexian Slayer", 118, Rarity.COMMON, mage.cards.p.PhyrexianSlayer.class)); - cards.add(new SetCardInfo("Pincer Spider", 201, Rarity.COMMON, mage.cards.p.PincerSpider.class)); - cards.add(new SetCardInfo("Plague Spitter", 119, Rarity.UNCOMMON, mage.cards.p.PlagueSpitter.class)); - cards.add(new SetCardInfo("Plague Spores", 260, Rarity.COMMON, mage.cards.p.PlagueSpores.class)); - cards.add(new SetCardInfo("Plains", 331, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Plains", 332, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Plains", 333, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Plains", 334, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Planar Portal", 308, Rarity.RARE, mage.cards.p.PlanarPortal.class)); - cards.add(new SetCardInfo("Pouncing Kavu", 158, Rarity.COMMON, mage.cards.p.PouncingKavu.class)); - cards.add(new SetCardInfo("Power Armor", 309, Rarity.UNCOMMON, mage.cards.p.PowerArmor.class)); - cards.add(new SetCardInfo("Prison Barricade", 25, Rarity.COMMON, mage.cards.p.PrisonBarricade.class)); - cards.add(new SetCardInfo("Probe", 66, Rarity.COMMON, mage.cards.p.Probe.class)); - cards.add(new SetCardInfo("Prohibit", 67, Rarity.COMMON, mage.cards.p.Prohibit.class)); - cards.add(new SetCardInfo("Pure Reflection", 27, Rarity.RARE, mage.cards.p.PureReflection.class)); - cards.add(new SetCardInfo("Pyre Zombie", 261, Rarity.RARE, mage.cards.p.PyreZombie.class)); - cards.add(new SetCardInfo("Quirion Elves", 203, Rarity.COMMON, mage.cards.q.QuirionElves.class)); - cards.add(new SetCardInfo("Quirion Sentinel", 204, Rarity.COMMON, mage.cards.q.QuirionSentinel.class)); - cards.add(new SetCardInfo("Quirion Trailblazer", 205, Rarity.COMMON, mage.cards.q.QuirionTrailblazer.class)); - cards.add(new SetCardInfo("Rage Weaver", 159, Rarity.UNCOMMON, mage.cards.r.RageWeaver.class)); - cards.add(new SetCardInfo("Raging Kavu", 262, Rarity.RARE, mage.cards.r.RagingKavu.class)); - cards.add(new SetCardInfo("Rainbow Crow", 69, Rarity.UNCOMMON, mage.cards.r.RainbowCrow.class)); - cards.add(new SetCardInfo("Rampant Elephant", 28, Rarity.COMMON, mage.cards.r.RampantElephant.class)); - cards.add(new SetCardInfo("Ravenous Rats", 120, Rarity.COMMON, mage.cards.r.RavenousRats.class)); - cards.add(new SetCardInfo("Razorfoot Griffin", 29, Rarity.COMMON, mage.cards.r.RazorfootGriffin.class)); - cards.add(new SetCardInfo("Reckless Assault", 263, Rarity.RARE, mage.cards.r.RecklessAssault.class)); - cards.add(new SetCardInfo("Reckless Spite", 121, Rarity.UNCOMMON, mage.cards.r.RecklessSpite.class)); - cards.add(new SetCardInfo("Recoil", 264, Rarity.COMMON, mage.cards.r.Recoil.class)); - cards.add(new SetCardInfo("Recover", 122, Rarity.COMMON, mage.cards.r.Recover.class)); - cards.add(new SetCardInfo("Repulse", 70, Rarity.COMMON, mage.cards.r.Repulse.class)); - cards.add(new SetCardInfo("Restock", 206, Rarity.RARE, mage.cards.r.Restock.class)); - cards.add(new SetCardInfo("Restrain", 30, Rarity.COMMON, mage.cards.r.Restrain.class)); - cards.add(new SetCardInfo("Reviving Dose", 31, Rarity.COMMON, mage.cards.r.RevivingDose.class)); - cards.add(new SetCardInfo("Reviving Vapors", 265, Rarity.UNCOMMON, mage.cards.r.RevivingVapors.class)); - cards.add(new SetCardInfo("Rewards of Diversity", 32, Rarity.UNCOMMON, mage.cards.r.RewardsOfDiversity.class)); - cards.add(new SetCardInfo("Reya Dawnbringer", 33, Rarity.RARE, mage.cards.r.ReyaDawnbringer.class)); - cards.add(new SetCardInfo("Riptide Crab", 266, Rarity.UNCOMMON, mage.cards.r.RiptideCrab.class)); - cards.add(new SetCardInfo("Rith's Attendant", 310, Rarity.UNCOMMON, mage.cards.r.RithsAttendant.class)); - cards.add(new SetCardInfo("Rith, the Awakener", 267, Rarity.RARE, mage.cards.r.RithTheAwakener.class)); - cards.add(new SetCardInfo("Rogue Kavu", 160, Rarity.COMMON, mage.cards.r.RogueKavu.class)); - cards.add(new SetCardInfo("Rooting Kavu", 207, Rarity.UNCOMMON, mage.cards.r.RootingKavu.class)); - cards.add(new SetCardInfo("Rout", 34, Rarity.RARE, mage.cards.r.Rout.class)); - cards.add(new SetCardInfo("Ruby Leech", 161, Rarity.RARE, mage.cards.r.RubyLeech.class)); - cards.add(new SetCardInfo("Ruham Djinn", 35, Rarity.UNCOMMON, mage.cards.r.RuhamDjinn.class)); - cards.add(new SetCardInfo("Sabertooth Nishoba", 268, Rarity.RARE, mage.cards.s.SabertoothNishoba.class)); - cards.add(new SetCardInfo("Salt Marsh", 326, Rarity.UNCOMMON, mage.cards.s.SaltMarsh.class)); - cards.add(new SetCardInfo("Samite Archer", 269, Rarity.UNCOMMON, mage.cards.s.SamiteArcher.class)); - cards.add(new SetCardInfo("Sapphire Leech", 71, Rarity.RARE, mage.cards.s.SapphireLeech.class)); - cards.add(new SetCardInfo("Saproling Symbiosis", 209, Rarity.RARE, mage.cards.s.SaprolingSymbiosis.class)); - cards.add(new SetCardInfo("Savage Offensive", 162, Rarity.COMMON, mage.cards.s.SavageOffensive.class)); - cards.add(new SetCardInfo("Scarred Puma", 163, Rarity.COMMON, mage.cards.s.ScarredPuma.class)); - cards.add(new SetCardInfo("Scavenged Weaponry", 123, Rarity.COMMON, mage.cards.s.ScavengedWeaponry.class)); - cards.add(new SetCardInfo("Scorching Lava", 164, Rarity.COMMON, mage.cards.s.ScorchingLava.class)); - cards.add(new SetCardInfo("Scouting Trek", 210, Rarity.UNCOMMON, mage.cards.s.ScoutingTrek.class)); - cards.add(new SetCardInfo("Seashell Cameo", 311, Rarity.UNCOMMON, mage.cards.s.SeashellCameo.class)); - cards.add(new SetCardInfo("Seer's Vision", 270, Rarity.UNCOMMON, mage.cards.s.SeersVision.class)); - cards.add(new SetCardInfo("Serpentine Kavu", 211, Rarity.COMMON, mage.cards.s.SerpentineKavu.class)); - cards.add(new SetCardInfo("Shackles", 37, Rarity.COMMON, mage.cards.s.Shackles.class)); - cards.add(new SetCardInfo("Shimmering Wings", 72, Rarity.COMMON, mage.cards.s.ShimmeringWings.class)); - cards.add(new SetCardInfo("Shivan Emissary", 166, Rarity.UNCOMMON, mage.cards.s.ShivanEmissary.class)); - cards.add(new SetCardInfo("Shivan Harvest", 167, Rarity.UNCOMMON, mage.cards.s.ShivanHarvest.class)); - cards.add(new SetCardInfo("Shivan Oasis", 327, Rarity.UNCOMMON, mage.cards.s.ShivanOasis.class)); - cards.add(new SetCardInfo("Shivan Zombie", 271, Rarity.COMMON, mage.cards.s.ShivanZombie.class)); - cards.add(new SetCardInfo("Shoreline Raider", 73, Rarity.COMMON, mage.cards.s.ShorelineRaider.class)); - cards.add(new SetCardInfo("Simoon", 272, Rarity.UNCOMMON, mage.cards.s.Simoon.class)); - cards.add(new SetCardInfo("Skittish Kavu", 168, Rarity.UNCOMMON, mage.cards.s.SkittishKavu.class)); - cards.add(new SetCardInfo("Skizzik", 169, Rarity.RARE, mage.cards.s.Skizzik.class)); - cards.add(new SetCardInfo("Sky Weaver", 74, Rarity.UNCOMMON, mage.cards.s.SkyWeaver.class)); - cards.add(new SetCardInfo("Sleeper's Robe", 273, Rarity.UNCOMMON, mage.cards.s.SleepersRobe.class)); - cards.add(new SetCardInfo("Slimy Kavu", 170, Rarity.COMMON, mage.cards.s.SlimyKavu.class)); - cards.add(new SetCardInfo("Slinking Serpent", 274, Rarity.UNCOMMON, mage.cards.s.SlinkingSerpent.class)); - cards.add(new SetCardInfo("Smoldering Tar", 275, Rarity.UNCOMMON, mage.cards.s.SmolderingTar.class)); - cards.add(new SetCardInfo("Soul Burn", 124, Rarity.COMMON, mage.cards.s.SoulBurn.class)); - cards.add(new SetCardInfo("Sparring Golem", 312, Rarity.UNCOMMON, mage.cards.s.SparringGolem.class)); - cards.add(new SetCardInfo("Spinal Embrace", 276, Rarity.RARE, mage.cards.s.SpinalEmbrace.class)); - cards.add(new SetCardInfo("Spirit of Resistance", 38, Rarity.RARE, mage.cards.s.SpiritOfResistance.class)); - cards.add(new SetCardInfo("Spirit Weaver", 39, Rarity.UNCOMMON, mage.cards.s.SpiritWeaver.class)); - cards.add(new SetCardInfo("Spite // Malice", 293, Rarity.UNCOMMON, mage.cards.s.SpiteMalice.class)); - cards.add(new SetCardInfo("Spreading Plague", 125, Rarity.RARE, mage.cards.s.SpreadingPlague.class)); - cards.add(new SetCardInfo("Stalking Assassin", 277, Rarity.RARE, mage.cards.s.StalkingAssassin.class)); - cards.add(new SetCardInfo("Stand // Deliver", 292, Rarity.UNCOMMON, mage.cards.s.StandDeliver.class)); - cards.add(new SetCardInfo("Sterling Grove", 278, Rarity.UNCOMMON, mage.cards.s.SterlingGrove.class)); - cards.add(new SetCardInfo("Stormscape Apprentice", 75, Rarity.COMMON, mage.cards.s.StormscapeApprentice.class)); - cards.add(new SetCardInfo("Stormscape Master", 76, Rarity.RARE, mage.cards.s.StormscapeMaster.class)); - cards.add(new SetCardInfo("Strength of Unity", 40, Rarity.COMMON, mage.cards.s.StrengthOfUnity.class)); - cards.add(new SetCardInfo("Stun", 172, Rarity.COMMON, mage.cards.s.Stun.class)); - cards.add(new SetCardInfo("Sulam Djinn", 212, Rarity.UNCOMMON, mage.cards.s.SulamDjinn.class)); - cards.add(new SetCardInfo("Sulfur Vent", 328, Rarity.COMMON, mage.cards.s.SulfurVent.class)); - cards.add(new SetCardInfo("Sunscape Apprentice", 41, Rarity.COMMON, mage.cards.s.SunscapeApprentice.class)); - cards.add(new SetCardInfo("Sunscape Master", 42, Rarity.RARE, mage.cards.s.SunscapeMaster.class)); - cards.add(new SetCardInfo("Swamp", 339, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Swamp", 340, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Swamp", 341, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Swamp", 342, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Sway of Illusion", 77, Rarity.UNCOMMON, mage.cards.s.SwayOfIllusion.class)); - cards.add(new SetCardInfo("Tainted Well", 126, Rarity.COMMON, mage.cards.t.TaintedWell.class)); - cards.add(new SetCardInfo("Tangle", 213, Rarity.UNCOMMON, mage.cards.t.Tangle.class)); - cards.add(new SetCardInfo("Tectonic Instability", 173, Rarity.RARE, mage.cards.t.TectonicInstability.class)); - cards.add(new SetCardInfo("Teferi's Care", 43, Rarity.UNCOMMON, mage.cards.t.TeferisCare.class)); - cards.add(new SetCardInfo("Teferi's Moat", 279, Rarity.RARE, mage.cards.t.TeferisMoat.class)); - cards.add(new SetCardInfo("Teferi's Response", 78, Rarity.RARE, mage.cards.t.TeferisResponse.class)); - cards.add(new SetCardInfo("Tek", 313, Rarity.RARE, mage.cards.t.Tek.class)); - cards.add(new SetCardInfo("Temporal Distortion", 79, Rarity.RARE, mage.cards.t.TemporalDistortion.class)); - cards.add(new SetCardInfo("Thicket Elemental", 214, Rarity.RARE, mage.cards.t.ThicketElemental.class)); - cards.add(new SetCardInfo("Thornscape Apprentice", 215, Rarity.COMMON, mage.cards.t.ThornscapeApprentice.class)); - cards.add(new SetCardInfo("Thornscape Master", 216, Rarity.RARE, mage.cards.t.ThornscapeMaster.class)); - cards.add(new SetCardInfo("Thunderscape Apprentice", 174, Rarity.COMMON, mage.cards.t.ThunderscapeApprentice.class)); - cards.add(new SetCardInfo("Thunderscape Master", 175, Rarity.RARE, mage.cards.t.ThunderscapeMaster.class)); - cards.add(new SetCardInfo("Tidal Visionary", 80, Rarity.COMMON, mage.cards.t.TidalVisionary.class)); - cards.add(new SetCardInfo("Tigereye Cameo", 314, Rarity.UNCOMMON, mage.cards.t.TigereyeCameo.class)); - cards.add(new SetCardInfo("Tinder Farm", 329, Rarity.COMMON, mage.cards.t.TinderFarm.class)); - cards.add(new SetCardInfo("Tolarian Emissary", 81, Rarity.UNCOMMON, mage.cards.t.TolarianEmissary.class)); - cards.add(new SetCardInfo("Tower Drake", 82, Rarity.COMMON, mage.cards.t.TowerDrake.class)); - cards.add(new SetCardInfo("Tranquility", 217, Rarity.COMMON, mage.cards.t.Tranquility.class)); - cards.add(new SetCardInfo("Traveler's Cloak", 83, Rarity.COMMON, mage.cards.t.TravelersCloak.class)); - cards.add(new SetCardInfo("Treefolk Healer", 218, Rarity.UNCOMMON, mage.cards.t.TreefolkHealer.class)); - cards.add(new SetCardInfo("Trench Wurm", 127, Rarity.UNCOMMON, mage.cards.t.TrenchWurm.class)); - cards.add(new SetCardInfo("Treva's Attendant", 315, Rarity.UNCOMMON, mage.cards.t.TrevasAttendant.class)); - cards.add(new SetCardInfo("Treva, the Renewer", 280, Rarity.RARE, mage.cards.t.TrevaTheRenewer.class)); - cards.add(new SetCardInfo("Tribal Flames", 176, Rarity.COMMON, mage.cards.t.TribalFlames.class)); - cards.add(new SetCardInfo("Troll-Horn Cameo", 316, Rarity.UNCOMMON, mage.cards.t.TrollHornCameo.class)); - cards.add(new SetCardInfo("Tsabo's Assassin", 128, Rarity.RARE, mage.cards.t.TsabosAssassin.class)); - cards.add(new SetCardInfo("Tsabo's Decree", 129, Rarity.RARE, mage.cards.t.TsabosDecree.class)); - cards.add(new SetCardInfo("Tsabo's Web", 317, Rarity.RARE, mage.cards.t.TsabosWeb.class)); - cards.add(new SetCardInfo("Tsabo Tavoc", 281, Rarity.RARE, mage.cards.t.TsaboTavoc.class)); - cards.add(new SetCardInfo("Turf Wound", 177, Rarity.COMMON, mage.cards.t.TurfWound.class)); - cards.add(new SetCardInfo("Twilight's Call", 130, Rarity.RARE, mage.cards.t.TwilightsCall.class)); - cards.add(new SetCardInfo("Undermine", 282, Rarity.RARE, mage.cards.u.Undermine.class)); - cards.add(new SetCardInfo("Urborg Drake", 283, Rarity.UNCOMMON, mage.cards.u.UrborgDrake.class)); - cards.add(new SetCardInfo("Urborg Emissary", 131, Rarity.UNCOMMON, mage.cards.u.UrborgEmissary.class)); - cards.add(new SetCardInfo("Urborg Phantom", 132, Rarity.COMMON, mage.cards.u.UrborgPhantom.class)); - cards.add(new SetCardInfo("Urborg Shambler", 133, Rarity.UNCOMMON, mage.cards.u.UrborgShambler.class)); - cards.add(new SetCardInfo("Urborg Skeleton", 134, Rarity.COMMON, mage.cards.u.UrborgSkeleton.class)); - cards.add(new SetCardInfo("Urborg Volcano", 330, Rarity.UNCOMMON, mage.cards.u.UrborgVolcano.class)); - cards.add(new SetCardInfo("Urza's Filter", 318, Rarity.RARE, mage.cards.u.UrzasFilter.class)); - cards.add(new SetCardInfo("Urza's Rage", 178, Rarity.RARE, mage.cards.u.UrzasRage.class)); - cards.add(new SetCardInfo("Utopia Tree", 219, Rarity.RARE, mage.cards.u.UtopiaTree.class)); - cards.add(new SetCardInfo("Verdeloth the Ancient", 220, Rarity.RARE, mage.cards.v.VerdelothTheAncient.class)); - cards.add(new SetCardInfo("Verduran Emissary", 221, Rarity.UNCOMMON, mage.cards.v.VerduranEmissary.class)); - cards.add(new SetCardInfo("Viashino Grappler", 179, Rarity.COMMON, mage.cards.v.ViashinoGrappler.class)); - cards.add(new SetCardInfo("Vicious Kavu", 284, Rarity.UNCOMMON, mage.cards.v.ViciousKavu.class)); - cards.add(new SetCardInfo("Vile Consumption", 285, Rarity.RARE, mage.cards.v.VileConsumption.class)); - cards.add(new SetCardInfo("Vodalian Hypnotist", 84, Rarity.UNCOMMON, mage.cards.v.VodalianHypnotist.class)); - cards.add(new SetCardInfo("Vodalian Merchant", 85, Rarity.COMMON, mage.cards.v.VodalianMerchant.class)); - cards.add(new SetCardInfo("Vodalian Serpent", 86, Rarity.COMMON, mage.cards.v.VodalianSerpent.class)); - cards.add(new SetCardInfo("Vodalian Zombie", 286, Rarity.COMMON, mage.cards.v.VodalianZombie.class)); - cards.add(new SetCardInfo("Void", 287, Rarity.RARE, mage.cards.v.Void.class)); - cards.add(new SetCardInfo("Voracious Cobra", 288, Rarity.UNCOMMON, mage.cards.v.VoraciousCobra.class)); - cards.add(new SetCardInfo("Wallop", 223, Rarity.UNCOMMON, mage.cards.w.Wallop.class)); - cards.add(new SetCardInfo("Wandering Stream", 224, Rarity.COMMON, mage.cards.w.WanderingStream.class)); - cards.add(new SetCardInfo("Wash Out", 87, Rarity.UNCOMMON, mage.cards.w.WashOut.class)); - cards.add(new SetCardInfo("Wax // Wane", 296, Rarity.UNCOMMON, mage.cards.w.WaxWane.class)); - cards.add(new SetCardInfo("Wayfaring Giant", 44, Rarity.UNCOMMON, mage.cards.w.WayfaringGiant.class)); - cards.add(new SetCardInfo("Whip Silk", 225, Rarity.COMMON, mage.cards.w.WhipSilk.class)); - cards.add(new SetCardInfo("Wings of Hope", 289, Rarity.COMMON, mage.cards.w.WingsOfHope.class)); - cards.add(new SetCardInfo("Winnow", 45, Rarity.RARE, mage.cards.w.Winnow.class)); - cards.add(new SetCardInfo("Worldly Counsel", 89, Rarity.COMMON, mage.cards.w.WorldlyCounsel.class)); - cards.add(new SetCardInfo("Yavimaya Barbarian", 290, Rarity.COMMON, mage.cards.y.YavimayaBarbarian.class)); - cards.add(new SetCardInfo("Yavimaya Kavu", 291, Rarity.UNCOMMON, mage.cards.y.YavimayaKavu.class)); - cards.add(new SetCardInfo("Yawgmoth's Agenda", 135, Rarity.RARE, mage.cards.y.YawgmothsAgenda.class)); - cards.add(new SetCardInfo("Zanam Djinn", 90, Rarity.UNCOMMON, mage.cards.z.ZanamDjinn.class)); - cards.add(new SetCardInfo("Zap", 180, Rarity.COMMON, mage.cards.z.Zap.class)); - } -} +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets; + +import mage.cards.ExpansionSet; +import mage.constants.Rarity; +import mage.constants.SetType; + +/** + * + * @author North + */ +public class Invasion extends ExpansionSet { + + private static final Invasion instance = new Invasion(); + + public static Invasion getInstance() { + return instance; + } + + private Invasion() { + super("Invasion", "INV", ExpansionSet.buildDate(2000, 9, 2), SetType.EXPANSION); + this.blockName = "Invasion"; + this.hasBoosters = true; + this.numBoosterLands = 0; + this.numBoosterCommon = 11; + this.numBoosterUncommon = 3; + this.numBoosterRare = 1; + this.ratioBoosterMythic = 0; + cards.add(new SetCardInfo("Absorb", 226, Rarity.RARE, mage.cards.a.Absorb.class)); + cards.add(new SetCardInfo("Addle", 91, Rarity.UNCOMMON, mage.cards.a.Addle.class)); + cards.add(new SetCardInfo("Aether Rift", 227, Rarity.RARE, mage.cards.a.AetherRift.class)); + cards.add(new SetCardInfo("Aggressive Urge", 181, Rarity.COMMON, mage.cards.a.AggressiveUrge.class)); + cards.add(new SetCardInfo("Agonizing Demise", 92, Rarity.COMMON, mage.cards.a.AgonizingDemise.class)); + cards.add(new SetCardInfo("Alabaster Leech", 1, Rarity.RARE, mage.cards.a.AlabasterLeech.class)); + cards.add(new SetCardInfo("Alloy Golem", 297, Rarity.UNCOMMON, mage.cards.a.AlloyGolem.class)); + cards.add(new SetCardInfo("Ancient Kavu", 136, Rarity.COMMON, mage.cards.a.AncientKavu.class)); + cards.add(new SetCardInfo("Ancient Spring", 319, Rarity.COMMON, mage.cards.a.AncientSpring.class)); + cards.add(new SetCardInfo("Andradite Leech", 93, Rarity.RARE, mage.cards.a.AndraditeLeech.class)); + cards.add(new SetCardInfo("Angelic Shield", 228, Rarity.UNCOMMON, mage.cards.a.AngelicShield.class)); + cards.add(new SetCardInfo("Angel of Mercy", 2, Rarity.UNCOMMON, mage.cards.a.AngelOfMercy.class)); + cards.add(new SetCardInfo("Annihilate", 94, Rarity.UNCOMMON, mage.cards.a.Annihilate.class)); + cards.add(new SetCardInfo("Archaeological Dig", 320, Rarity.UNCOMMON, mage.cards.a.ArchaeologicalDig.class)); + cards.add(new SetCardInfo("Ardent Soldier", 3, Rarity.COMMON, mage.cards.a.ArdentSoldier.class)); + cards.add(new SetCardInfo("Armadillo Cloak", 229, Rarity.COMMON, mage.cards.a.ArmadilloCloak.class)); + cards.add(new SetCardInfo("Armored Guardian", 230, Rarity.RARE, mage.cards.a.ArmoredGuardian.class)); + cards.add(new SetCardInfo("Artifact Mutation", 231, Rarity.RARE, mage.cards.a.ArtifactMutation.class)); + cards.add(new SetCardInfo("Assault // Battery", 295, Rarity.UNCOMMON, mage.cards.a.AssaultBattery.class)); + cards.add(new SetCardInfo("Atalya, Samite Master", 4, Rarity.RARE, mage.cards.a.AtalyaSamiteMaster.class)); + cards.add(new SetCardInfo("Aura Mutation", 232, Rarity.RARE, mage.cards.a.AuraMutation.class)); + cards.add(new SetCardInfo("Aura Shards", 233, Rarity.UNCOMMON, mage.cards.a.AuraShards.class)); + cards.add(new SetCardInfo("Backlash", 234, Rarity.UNCOMMON, mage.cards.b.Backlash.class)); + cards.add(new SetCardInfo("Barrin's Spite", 235, Rarity.RARE, mage.cards.b.BarrinsSpite.class)); + cards.add(new SetCardInfo("Barrin's Unmaking", 46, Rarity.COMMON, mage.cards.b.BarrinsUnmaking.class)); + cards.add(new SetCardInfo("Benalish Emissary", 5, Rarity.UNCOMMON, mage.cards.b.BenalishEmissary.class)); + cards.add(new SetCardInfo("Benalish Heralds", 6, Rarity.UNCOMMON, mage.cards.b.BenalishHeralds.class)); + cards.add(new SetCardInfo("Benalish Lancer", 7, Rarity.COMMON, mage.cards.b.BenalishLancer.class)); + cards.add(new SetCardInfo("Benalish Trapper", 8, Rarity.COMMON, mage.cards.b.BenalishTrapper.class)); + cards.add(new SetCardInfo("Bind", 182, Rarity.RARE, mage.cards.b.Bind.class)); + cards.add(new SetCardInfo("Blazing Specter", 236, Rarity.RARE, mage.cards.b.BlazingSpecter.class)); + cards.add(new SetCardInfo("Blinding Light", 9, Rarity.UNCOMMON, mage.cards.b.BlindingLight.class)); + cards.add(new SetCardInfo("Blind Seer", 47, Rarity.RARE, mage.cards.b.BlindSeer.class)); + cards.add(new SetCardInfo("Bloodstone Cameo", 298, Rarity.UNCOMMON, mage.cards.b.BloodstoneCameo.class)); + cards.add(new SetCardInfo("Blurred Mongoose", 183, Rarity.RARE, mage.cards.b.BlurredMongoose.class)); + cards.add(new SetCardInfo("Bog Initiate", 95, Rarity.COMMON, mage.cards.b.BogInitiate.class)); + cards.add(new SetCardInfo("Breaking Wave", 48, Rarity.RARE, mage.cards.b.BreakingWave.class)); + cards.add(new SetCardInfo("Breath of Darigaaz", 138, Rarity.UNCOMMON, mage.cards.b.BreathOfDarigaaz.class)); + cards.add(new SetCardInfo("Callous Giant", 139, Rarity.RARE, mage.cards.c.CallousGiant.class)); + cards.add(new SetCardInfo("Canopy Surge", 184, Rarity.UNCOMMON, mage.cards.c.CanopySurge.class)); + cards.add(new SetCardInfo("Capashen Unicorn", 10, Rarity.COMMON, mage.cards.c.CapashenUnicorn.class)); + cards.add(new SetCardInfo("Captain Sisay", 237, Rarity.RARE, mage.cards.c.CaptainSisay.class)); + cards.add(new SetCardInfo("Cauldron Dance", 238, Rarity.UNCOMMON, mage.cards.c.CauldronDance.class)); + cards.add(new SetCardInfo("Chaotic Strike", 140, Rarity.UNCOMMON, mage.cards.c.ChaoticStrike.class)); + cards.add(new SetCardInfo("Charging Troll", 239, Rarity.UNCOMMON, mage.cards.c.ChargingTroll.class)); + cards.add(new SetCardInfo("Chromatic Sphere", 299, Rarity.UNCOMMON, mage.cards.c.ChromaticSphere.class)); + cards.add(new SetCardInfo("Cinder Shade", 240, Rarity.UNCOMMON, mage.cards.c.CinderShade.class)); + cards.add(new SetCardInfo("Coalition Victory", 241, Rarity.RARE, mage.cards.c.CoalitionVictory.class)); + cards.add(new SetCardInfo("Coastal Tower", 321, Rarity.UNCOMMON, mage.cards.c.CoastalTower.class)); + cards.add(new SetCardInfo("Collapsing Borders", 141, Rarity.RARE, mage.cards.c.CollapsingBorders.class)); + cards.add(new SetCardInfo("Collective Restraint", 49, Rarity.RARE, mage.cards.c.CollectiveRestraint.class)); + cards.add(new SetCardInfo("Cremate", 96, Rarity.UNCOMMON, mage.cards.c.Cremate.class)); + cards.add(new SetCardInfo("Crimson Acolyte", 11, Rarity.COMMON, mage.cards.c.CrimsonAcolyte.class)); + cards.add(new SetCardInfo("Crosis's Attendant", 300, Rarity.UNCOMMON, mage.cards.c.CrosissAttendant.class)); + cards.add(new SetCardInfo("Crosis, the Purger", 242, Rarity.RARE, mage.cards.c.CrosisThePurger.class)); + cards.add(new SetCardInfo("Crown of Flames", 142, Rarity.COMMON, mage.cards.c.CrownOfFlames.class)); + cards.add(new SetCardInfo("Crusading Knight", 12, Rarity.RARE, mage.cards.c.CrusadingKnight.class)); + cards.add(new SetCardInfo("Crypt Angel", 97, Rarity.RARE, mage.cards.c.CryptAngel.class)); + cards.add(new SetCardInfo("Cursed Flesh", 98, Rarity.COMMON, mage.cards.c.CursedFlesh.class)); + cards.add(new SetCardInfo("Darigaaz's Attendant", 301, Rarity.UNCOMMON, mage.cards.d.DarigaazsAttendant.class)); + cards.add(new SetCardInfo("Darigaaz, the Igniter", 243, Rarity.RARE, mage.cards.d.DarigaazTheIgniter.class)); + cards.add(new SetCardInfo("Defiling Tears", 99, Rarity.UNCOMMON, mage.cards.d.DefilingTears.class)); + cards.add(new SetCardInfo("Devouring Strossus", 101, Rarity.RARE, mage.cards.d.DevouringStrossus.class)); + cards.add(new SetCardInfo("Dismantling Blow", 14, Rarity.COMMON, mage.cards.d.DismantlingBlow.class)); + cards.add(new SetCardInfo("Disrupt", 51, Rarity.UNCOMMON, mage.cards.d.Disrupt.class)); + cards.add(new SetCardInfo("Distorting Wake", 52, Rarity.RARE, mage.cards.d.DistortingWake.class)); + cards.add(new SetCardInfo("Divine Presence", 15, Rarity.RARE, mage.cards.d.DivinePresence.class)); + cards.add(new SetCardInfo("Do or Die", 102, Rarity.RARE, mage.cards.d.DoOrDie.class)); + cards.add(new SetCardInfo("Drake-Skull Cameo", 302, Rarity.UNCOMMON, mage.cards.d.DrakeSkullCameo.class)); + cards.add(new SetCardInfo("Dream Thrush", 53, Rarity.COMMON, mage.cards.d.DreamThrush.class)); + cards.add(new SetCardInfo("Dredge", 103, Rarity.UNCOMMON, mage.cards.d.Dredge.class)); + cards.add(new SetCardInfo("Dromar's Attendant", 303, Rarity.UNCOMMON, mage.cards.d.DromarsAttendant.class)); + cards.add(new SetCardInfo("Dromar, the Banisher", 244, Rarity.RARE, mage.cards.d.DromarTheBanisher.class)); + cards.add(new SetCardInfo("Dueling Grounds", 245, Rarity.RARE, mage.cards.d.DuelingGrounds.class)); + cards.add(new SetCardInfo("Duskwalker", 104, Rarity.COMMON, mage.cards.d.Duskwalker.class)); + cards.add(new SetCardInfo("Elfhame Palace", 322, Rarity.UNCOMMON, mage.cards.e.ElfhamePalace.class)); + cards.add(new SetCardInfo("Elfhame Sanctuary", 185, Rarity.UNCOMMON, mage.cards.e.ElfhameSanctuary.class)); + cards.add(new SetCardInfo("Elvish Champion", 186, Rarity.RARE, mage.cards.e.ElvishChampion.class)); + cards.add(new SetCardInfo("Empress Galina", 54, Rarity.RARE, mage.cards.e.EmpressGalina.class)); + cards.add(new SetCardInfo("Exclude", 56, Rarity.COMMON, mage.cards.e.Exclude.class)); + cards.add(new SetCardInfo("Exotic Curse", 105, Rarity.COMMON, mage.cards.e.ExoticCurse.class)); + cards.add(new SetCardInfo("Explosive Growth", 187, Rarity.COMMON, mage.cards.e.ExplosiveGrowth.class)); + cards.add(new SetCardInfo("Fact or Fiction", 57, Rarity.UNCOMMON, mage.cards.f.FactOrFiction.class)); + cards.add(new SetCardInfo("Faerie Squadron", 58, Rarity.COMMON, mage.cards.f.FaerieSquadron.class)); + cards.add(new SetCardInfo("Fertile Ground", 188, Rarity.COMMON, mage.cards.f.FertileGround.class)); + cards.add(new SetCardInfo("Firebrand Ranger", 143, Rarity.UNCOMMON, mage.cards.f.FirebrandRanger.class)); + cards.add(new SetCardInfo("Firescreamer", 106, Rarity.COMMON, mage.cards.f.Firescreamer.class)); + cards.add(new SetCardInfo("Fires of Yavimaya", 246, Rarity.UNCOMMON, mage.cards.f.FiresOfYavimaya.class)); + cards.add(new SetCardInfo("Forest", 347, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Forest", 348, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Forest", 349, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Forest", 350, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Frenzied Tilling", 247, Rarity.COMMON, mage.cards.f.FrenziedTilling.class)); + cards.add(new SetCardInfo("Galina's Knight", 248, Rarity.COMMON, mage.cards.g.GalinasKnight.class)); + cards.add(new SetCardInfo("Geothermal Crevice", 323, Rarity.COMMON, mage.cards.g.GeothermalCrevice.class)); + cards.add(new SetCardInfo("Ghitu Fire", 144, Rarity.RARE, mage.cards.g.GhituFire.class)); + cards.add(new SetCardInfo("Glimmering Angel", 17, Rarity.COMMON, mage.cards.g.GlimmeringAngel.class)); + cards.add(new SetCardInfo("Global Ruin", 18, Rarity.RARE, mage.cards.g.GlobalRuin.class)); + cards.add(new SetCardInfo("Goblin Spy", 145, Rarity.UNCOMMON, mage.cards.g.GoblinSpy.class)); + cards.add(new SetCardInfo("Goham Djinn", 107, Rarity.UNCOMMON, mage.cards.g.GohamDjinn.class)); + cards.add(new SetCardInfo("Halam Djinn", 146, Rarity.UNCOMMON, mage.cards.h.HalamDjinn.class)); + cards.add(new SetCardInfo("Hanna, Ship's Navigator", 249, Rarity.RARE, mage.cards.h.HannaShipsNavigator.class)); + cards.add(new SetCardInfo("Harrow", 189, Rarity.COMMON, mage.cards.h.Harrow.class)); + cards.add(new SetCardInfo("Harsh Judgment", 19, Rarity.RARE, mage.cards.h.HarshJudgment.class)); + cards.add(new SetCardInfo("Hate Weaver", 108, Rarity.UNCOMMON, mage.cards.h.HateWeaver.class)); + cards.add(new SetCardInfo("Heroes' Reunion", 250, Rarity.UNCOMMON, mage.cards.h.HeroesReunion.class)); + cards.add(new SetCardInfo("Holy Day", 20, Rarity.COMMON, mage.cards.h.HolyDay.class)); + cards.add(new SetCardInfo("Hooded Kavu", 147, Rarity.COMMON, mage.cards.h.HoodedKavu.class)); + cards.add(new SetCardInfo("Horned Cheetah", 251, Rarity.UNCOMMON, mage.cards.h.HornedCheetah.class)); + cards.add(new SetCardInfo("Hunting Kavu", 252, Rarity.UNCOMMON, mage.cards.h.HuntingKavu.class)); + cards.add(new SetCardInfo("Hypnotic Cloud", 109, Rarity.COMMON, mage.cards.h.HypnoticCloud.class)); + cards.add(new SetCardInfo("Irrigation Ditch", 324, Rarity.COMMON, mage.cards.i.IrrigationDitch.class)); + cards.add(new SetCardInfo("Island", 335, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Island", 336, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Island", 337, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Island", 338, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Jade Leech", 190, Rarity.RARE, mage.cards.j.JadeLeech.class)); + cards.add(new SetCardInfo("Juntu Stakes", 304, Rarity.RARE, mage.cards.j.JuntuStakes.class)); + cards.add(new SetCardInfo("Kangee, Aerie Keeper", 253, Rarity.RARE, mage.cards.k.KangeeAerieKeeper.class)); + cards.add(new SetCardInfo("Kavu Aggressor", 148, Rarity.COMMON, mage.cards.k.KavuAggressor.class)); + cards.add(new SetCardInfo("Kavu Chameleon", 191, Rarity.UNCOMMON, mage.cards.k.KavuChameleon.class)); + cards.add(new SetCardInfo("Kavu Climber", 192, Rarity.COMMON, mage.cards.k.KavuClimber.class)); + cards.add(new SetCardInfo("Kavu Lair", 193, Rarity.RARE, mage.cards.k.KavuLair.class)); + cards.add(new SetCardInfo("Kavu Monarch", 149, Rarity.RARE, mage.cards.k.KavuMonarch.class)); + cards.add(new SetCardInfo("Kavu Runner", 150, Rarity.UNCOMMON, mage.cards.k.KavuRunner.class)); + cards.add(new SetCardInfo("Kavu Scout", 151, Rarity.COMMON, mage.cards.k.KavuScout.class)); + cards.add(new SetCardInfo("Kavu Titan", 194, Rarity.RARE, mage.cards.k.KavuTitan.class)); + cards.add(new SetCardInfo("Keldon Necropolis", 325, Rarity.RARE, mage.cards.k.KeldonNecropolis.class)); + cards.add(new SetCardInfo("Liberate", 21, Rarity.UNCOMMON, mage.cards.l.Liberate.class)); + cards.add(new SetCardInfo("Lightning Dart", 152, Rarity.UNCOMMON, mage.cards.l.LightningDart.class)); + cards.add(new SetCardInfo("Llanowar Cavalry", 195, Rarity.COMMON, mage.cards.l.LlanowarCavalry.class)); + cards.add(new SetCardInfo("Llanowar Elite", 196, Rarity.COMMON, mage.cards.l.LlanowarElite.class)); + cards.add(new SetCardInfo("Llanowar Knight", 254, Rarity.COMMON, mage.cards.l.LlanowarKnight.class)); + cards.add(new SetCardInfo("Llanowar Vanguard", 197, Rarity.COMMON, mage.cards.l.LlanowarVanguard.class)); + cards.add(new SetCardInfo("Lobotomy", 255, Rarity.UNCOMMON, mage.cards.l.Lobotomy.class)); + cards.add(new SetCardInfo("Lotus Guardian", 305, Rarity.RARE, mage.cards.l.LotusGuardian.class)); + cards.add(new SetCardInfo("Mana Maze", 59, Rarity.RARE, mage.cards.m.ManaMaze.class)); + cards.add(new SetCardInfo("Maniacal Rage", 155, Rarity.COMMON, mage.cards.m.ManiacalRage.class)); + cards.add(new SetCardInfo("Manipulate Fate", 60, Rarity.UNCOMMON, mage.cards.m.ManipulateFate.class)); + cards.add(new SetCardInfo("Marauding Knight", 110, Rarity.RARE, mage.cards.m.MaraudingKnight.class)); + cards.add(new SetCardInfo("Metathran Transport", 62, Rarity.UNCOMMON, mage.cards.m.MetathranTransport.class)); + cards.add(new SetCardInfo("Metathran Zombie", 63, Rarity.COMMON, mage.cards.m.MetathranZombie.class)); + cards.add(new SetCardInfo("Meteor Storm", 256, Rarity.RARE, mage.cards.m.MeteorStorm.class)); + cards.add(new SetCardInfo("Might Weaver", 198, Rarity.UNCOMMON, mage.cards.m.MightWeaver.class)); + cards.add(new SetCardInfo("Molimo, Maro-Sorcerer", 199, Rarity.RARE, mage.cards.m.MolimoMaroSorcerer.class)); + cards.add(new SetCardInfo("Mountain", 343, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Mountain", 344, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Mountain", 345, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Mountain", 346, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Mourning", 111, Rarity.COMMON, mage.cards.m.Mourning.class)); + cards.add(new SetCardInfo("Nightscape Apprentice", 112, Rarity.COMMON, mage.cards.n.NightscapeApprentice.class)); + cards.add(new SetCardInfo("Nightscape Master", 113, Rarity.RARE, mage.cards.n.NightscapeMaster.class)); + cards.add(new SetCardInfo("Noble Panther", 257, Rarity.RARE, mage.cards.n.NoblePanther.class)); + cards.add(new SetCardInfo("Nomadic Elf", 200, Rarity.COMMON, mage.cards.n.NomadicElf.class)); + cards.add(new SetCardInfo("Obliterate", 156, Rarity.RARE, mage.cards.o.Obliterate.class)); + cards.add(new SetCardInfo("Obsidian Acolyte", 22, Rarity.COMMON, mage.cards.o.ObsidianAcolyte.class)); + cards.add(new SetCardInfo("Opt", 64, Rarity.COMMON, mage.cards.o.Opt.class)); + cards.add(new SetCardInfo("Ordered Migration", 258, Rarity.UNCOMMON, mage.cards.o.OrderedMigration.class)); + cards.add(new SetCardInfo("Orim's Touch", 23, Rarity.COMMON, mage.cards.o.OrimsTouch.class)); + cards.add(new SetCardInfo("Overabundance", 259, Rarity.RARE, mage.cards.o.Overabundance.class)); + cards.add(new SetCardInfo("Overload", 157, Rarity.COMMON, mage.cards.o.Overload.class)); + cards.add(new SetCardInfo("Pain // Suffering", 294, Rarity.UNCOMMON, mage.cards.p.PainSuffering.class)); + cards.add(new SetCardInfo("Phantasmal Terrain", 65, Rarity.COMMON, mage.cards.p.PhantasmalTerrain.class)); + cards.add(new SetCardInfo("Phyrexian Altar", 306, Rarity.RARE, mage.cards.p.PhyrexianAltar.class)); + cards.add(new SetCardInfo("Phyrexian Battleflies", 114, Rarity.COMMON, mage.cards.p.PhyrexianBattleflies.class)); + cards.add(new SetCardInfo("Phyrexian Delver", 115, Rarity.RARE, mage.cards.p.PhyrexianDelver.class)); + cards.add(new SetCardInfo("Phyrexian Infiltrator", 116, Rarity.RARE, mage.cards.p.PhyrexianInfiltrator.class)); + cards.add(new SetCardInfo("Phyrexian Lens", 307, Rarity.RARE, mage.cards.p.PhyrexianLens.class)); + cards.add(new SetCardInfo("Phyrexian Reaper", 117, Rarity.COMMON, mage.cards.p.PhyrexianReaper.class)); + cards.add(new SetCardInfo("Phyrexian Slayer", 118, Rarity.COMMON, mage.cards.p.PhyrexianSlayer.class)); + cards.add(new SetCardInfo("Pincer Spider", 201, Rarity.COMMON, mage.cards.p.PincerSpider.class)); + cards.add(new SetCardInfo("Plague Spitter", 119, Rarity.UNCOMMON, mage.cards.p.PlagueSpitter.class)); + cards.add(new SetCardInfo("Plague Spores", 260, Rarity.COMMON, mage.cards.p.PlagueSpores.class)); + cards.add(new SetCardInfo("Plains", 331, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Plains", 332, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Plains", 333, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Plains", 334, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Planar Portal", 308, Rarity.RARE, mage.cards.p.PlanarPortal.class)); + cards.add(new SetCardInfo("Pouncing Kavu", 158, Rarity.COMMON, mage.cards.p.PouncingKavu.class)); + cards.add(new SetCardInfo("Power Armor", 309, Rarity.UNCOMMON, mage.cards.p.PowerArmor.class)); + cards.add(new SetCardInfo("Prison Barricade", 25, Rarity.COMMON, mage.cards.p.PrisonBarricade.class)); + cards.add(new SetCardInfo("Probe", 66, Rarity.COMMON, mage.cards.p.Probe.class)); + cards.add(new SetCardInfo("Prohibit", 67, Rarity.COMMON, mage.cards.p.Prohibit.class)); + cards.add(new SetCardInfo("Protective Sphere", 26, Rarity.COMMON, mage.cards.p.ProtectiveSphere.class)); + cards.add(new SetCardInfo("Pure Reflection", 27, Rarity.RARE, mage.cards.p.PureReflection.class)); + cards.add(new SetCardInfo("Pyre Zombie", 261, Rarity.RARE, mage.cards.p.PyreZombie.class)); + cards.add(new SetCardInfo("Quirion Elves", 203, Rarity.COMMON, mage.cards.q.QuirionElves.class)); + cards.add(new SetCardInfo("Quirion Sentinel", 204, Rarity.COMMON, mage.cards.q.QuirionSentinel.class)); + cards.add(new SetCardInfo("Quirion Trailblazer", 205, Rarity.COMMON, mage.cards.q.QuirionTrailblazer.class)); + cards.add(new SetCardInfo("Rage Weaver", 159, Rarity.UNCOMMON, mage.cards.r.RageWeaver.class)); + cards.add(new SetCardInfo("Raging Kavu", 262, Rarity.RARE, mage.cards.r.RagingKavu.class)); + cards.add(new SetCardInfo("Rainbow Crow", 69, Rarity.UNCOMMON, mage.cards.r.RainbowCrow.class)); + cards.add(new SetCardInfo("Rampant Elephant", 28, Rarity.COMMON, mage.cards.r.RampantElephant.class)); + cards.add(new SetCardInfo("Ravenous Rats", 120, Rarity.COMMON, mage.cards.r.RavenousRats.class)); + cards.add(new SetCardInfo("Razorfoot Griffin", 29, Rarity.COMMON, mage.cards.r.RazorfootGriffin.class)); + cards.add(new SetCardInfo("Reckless Assault", 263, Rarity.RARE, mage.cards.r.RecklessAssault.class)); + cards.add(new SetCardInfo("Reckless Spite", 121, Rarity.UNCOMMON, mage.cards.r.RecklessSpite.class)); + cards.add(new SetCardInfo("Recoil", 264, Rarity.COMMON, mage.cards.r.Recoil.class)); + cards.add(new SetCardInfo("Recover", 122, Rarity.COMMON, mage.cards.r.Recover.class)); + cards.add(new SetCardInfo("Repulse", 70, Rarity.COMMON, mage.cards.r.Repulse.class)); + cards.add(new SetCardInfo("Restock", 206, Rarity.RARE, mage.cards.r.Restock.class)); + cards.add(new SetCardInfo("Restrain", 30, Rarity.COMMON, mage.cards.r.Restrain.class)); + cards.add(new SetCardInfo("Reviving Dose", 31, Rarity.COMMON, mage.cards.r.RevivingDose.class)); + cards.add(new SetCardInfo("Reviving Vapors", 265, Rarity.UNCOMMON, mage.cards.r.RevivingVapors.class)); + cards.add(new SetCardInfo("Rewards of Diversity", 32, Rarity.UNCOMMON, mage.cards.r.RewardsOfDiversity.class)); + cards.add(new SetCardInfo("Reya Dawnbringer", 33, Rarity.RARE, mage.cards.r.ReyaDawnbringer.class)); + cards.add(new SetCardInfo("Riptide Crab", 266, Rarity.UNCOMMON, mage.cards.r.RiptideCrab.class)); + cards.add(new SetCardInfo("Rith's Attendant", 310, Rarity.UNCOMMON, mage.cards.r.RithsAttendant.class)); + cards.add(new SetCardInfo("Rith, the Awakener", 267, Rarity.RARE, mage.cards.r.RithTheAwakener.class)); + cards.add(new SetCardInfo("Rogue Kavu", 160, Rarity.COMMON, mage.cards.r.RogueKavu.class)); + cards.add(new SetCardInfo("Rooting Kavu", 207, Rarity.UNCOMMON, mage.cards.r.RootingKavu.class)); + cards.add(new SetCardInfo("Rout", 34, Rarity.RARE, mage.cards.r.Rout.class)); + cards.add(new SetCardInfo("Ruby Leech", 161, Rarity.RARE, mage.cards.r.RubyLeech.class)); + cards.add(new SetCardInfo("Ruham Djinn", 35, Rarity.UNCOMMON, mage.cards.r.RuhamDjinn.class)); + cards.add(new SetCardInfo("Sabertooth Nishoba", 268, Rarity.RARE, mage.cards.s.SabertoothNishoba.class)); + cards.add(new SetCardInfo("Salt Marsh", 326, Rarity.UNCOMMON, mage.cards.s.SaltMarsh.class)); + cards.add(new SetCardInfo("Samite Archer", 269, Rarity.UNCOMMON, mage.cards.s.SamiteArcher.class)); + cards.add(new SetCardInfo("Sapphire Leech", 71, Rarity.RARE, mage.cards.s.SapphireLeech.class)); + cards.add(new SetCardInfo("Saproling Symbiosis", 209, Rarity.RARE, mage.cards.s.SaprolingSymbiosis.class)); + cards.add(new SetCardInfo("Savage Offensive", 162, Rarity.COMMON, mage.cards.s.SavageOffensive.class)); + cards.add(new SetCardInfo("Scarred Puma", 163, Rarity.COMMON, mage.cards.s.ScarredPuma.class)); + cards.add(new SetCardInfo("Scavenged Weaponry", 123, Rarity.COMMON, mage.cards.s.ScavengedWeaponry.class)); + cards.add(new SetCardInfo("Scorching Lava", 164, Rarity.COMMON, mage.cards.s.ScorchingLava.class)); + cards.add(new SetCardInfo("Scouting Trek", 210, Rarity.UNCOMMON, mage.cards.s.ScoutingTrek.class)); + cards.add(new SetCardInfo("Seashell Cameo", 311, Rarity.UNCOMMON, mage.cards.s.SeashellCameo.class)); + cards.add(new SetCardInfo("Seer's Vision", 270, Rarity.UNCOMMON, mage.cards.s.SeersVision.class)); + cards.add(new SetCardInfo("Serpentine Kavu", 211, Rarity.COMMON, mage.cards.s.SerpentineKavu.class)); + cards.add(new SetCardInfo("Shackles", 37, Rarity.COMMON, mage.cards.s.Shackles.class)); + cards.add(new SetCardInfo("Shimmering Wings", 72, Rarity.COMMON, mage.cards.s.ShimmeringWings.class)); + cards.add(new SetCardInfo("Shivan Emissary", 166, Rarity.UNCOMMON, mage.cards.s.ShivanEmissary.class)); + cards.add(new SetCardInfo("Shivan Harvest", 167, Rarity.UNCOMMON, mage.cards.s.ShivanHarvest.class)); + cards.add(new SetCardInfo("Shivan Oasis", 327, Rarity.UNCOMMON, mage.cards.s.ShivanOasis.class)); + cards.add(new SetCardInfo("Shivan Zombie", 271, Rarity.COMMON, mage.cards.s.ShivanZombie.class)); + cards.add(new SetCardInfo("Shoreline Raider", 73, Rarity.COMMON, mage.cards.s.ShorelineRaider.class)); + cards.add(new SetCardInfo("Simoon", 272, Rarity.UNCOMMON, mage.cards.s.Simoon.class)); + cards.add(new SetCardInfo("Skittish Kavu", 168, Rarity.UNCOMMON, mage.cards.s.SkittishKavu.class)); + cards.add(new SetCardInfo("Skizzik", 169, Rarity.RARE, mage.cards.s.Skizzik.class)); + cards.add(new SetCardInfo("Sky Weaver", 74, Rarity.UNCOMMON, mage.cards.s.SkyWeaver.class)); + cards.add(new SetCardInfo("Sleeper's Robe", 273, Rarity.UNCOMMON, mage.cards.s.SleepersRobe.class)); + cards.add(new SetCardInfo("Slimy Kavu", 170, Rarity.COMMON, mage.cards.s.SlimyKavu.class)); + cards.add(new SetCardInfo("Slinking Serpent", 274, Rarity.UNCOMMON, mage.cards.s.SlinkingSerpent.class)); + cards.add(new SetCardInfo("Smoldering Tar", 275, Rarity.UNCOMMON, mage.cards.s.SmolderingTar.class)); + cards.add(new SetCardInfo("Soul Burn", 124, Rarity.COMMON, mage.cards.s.SoulBurn.class)); + cards.add(new SetCardInfo("Sparring Golem", 312, Rarity.UNCOMMON, mage.cards.s.SparringGolem.class)); + cards.add(new SetCardInfo("Spinal Embrace", 276, Rarity.RARE, mage.cards.s.SpinalEmbrace.class)); + cards.add(new SetCardInfo("Spirit of Resistance", 38, Rarity.RARE, mage.cards.s.SpiritOfResistance.class)); + cards.add(new SetCardInfo("Spirit Weaver", 39, Rarity.UNCOMMON, mage.cards.s.SpiritWeaver.class)); + cards.add(new SetCardInfo("Spite // Malice", 293, Rarity.UNCOMMON, mage.cards.s.SpiteMalice.class)); + cards.add(new SetCardInfo("Spreading Plague", 125, Rarity.RARE, mage.cards.s.SpreadingPlague.class)); + cards.add(new SetCardInfo("Stalking Assassin", 277, Rarity.RARE, mage.cards.s.StalkingAssassin.class)); + cards.add(new SetCardInfo("Stand // Deliver", 292, Rarity.UNCOMMON, mage.cards.s.StandDeliver.class)); + cards.add(new SetCardInfo("Sterling Grove", 278, Rarity.UNCOMMON, mage.cards.s.SterlingGrove.class)); + cards.add(new SetCardInfo("Stormscape Apprentice", 75, Rarity.COMMON, mage.cards.s.StormscapeApprentice.class)); + cards.add(new SetCardInfo("Stormscape Master", 76, Rarity.RARE, mage.cards.s.StormscapeMaster.class)); + cards.add(new SetCardInfo("Strength of Unity", 40, Rarity.COMMON, mage.cards.s.StrengthOfUnity.class)); + cards.add(new SetCardInfo("Stun", 172, Rarity.COMMON, mage.cards.s.Stun.class)); + cards.add(new SetCardInfo("Sulam Djinn", 212, Rarity.UNCOMMON, mage.cards.s.SulamDjinn.class)); + cards.add(new SetCardInfo("Sulfur Vent", 328, Rarity.COMMON, mage.cards.s.SulfurVent.class)); + cards.add(new SetCardInfo("Sunscape Apprentice", 41, Rarity.COMMON, mage.cards.s.SunscapeApprentice.class)); + cards.add(new SetCardInfo("Sunscape Master", 42, Rarity.RARE, mage.cards.s.SunscapeMaster.class)); + cards.add(new SetCardInfo("Swamp", 339, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Swamp", 340, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Swamp", 341, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Swamp", 342, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Sway of Illusion", 77, Rarity.UNCOMMON, mage.cards.s.SwayOfIllusion.class)); + cards.add(new SetCardInfo("Tainted Well", 126, Rarity.COMMON, mage.cards.t.TaintedWell.class)); + cards.add(new SetCardInfo("Tangle", 213, Rarity.UNCOMMON, mage.cards.t.Tangle.class)); + cards.add(new SetCardInfo("Tectonic Instability", 173, Rarity.RARE, mage.cards.t.TectonicInstability.class)); + cards.add(new SetCardInfo("Teferi's Care", 43, Rarity.UNCOMMON, mage.cards.t.TeferisCare.class)); + cards.add(new SetCardInfo("Teferi's Moat", 279, Rarity.RARE, mage.cards.t.TeferisMoat.class)); + cards.add(new SetCardInfo("Teferi's Response", 78, Rarity.RARE, mage.cards.t.TeferisResponse.class)); + cards.add(new SetCardInfo("Tek", 313, Rarity.RARE, mage.cards.t.Tek.class)); + cards.add(new SetCardInfo("Temporal Distortion", 79, Rarity.RARE, mage.cards.t.TemporalDistortion.class)); + cards.add(new SetCardInfo("Thicket Elemental", 214, Rarity.RARE, mage.cards.t.ThicketElemental.class)); + cards.add(new SetCardInfo("Thornscape Apprentice", 215, Rarity.COMMON, mage.cards.t.ThornscapeApprentice.class)); + cards.add(new SetCardInfo("Thornscape Master", 216, Rarity.RARE, mage.cards.t.ThornscapeMaster.class)); + cards.add(new SetCardInfo("Thunderscape Apprentice", 174, Rarity.COMMON, mage.cards.t.ThunderscapeApprentice.class)); + cards.add(new SetCardInfo("Thunderscape Master", 175, Rarity.RARE, mage.cards.t.ThunderscapeMaster.class)); + cards.add(new SetCardInfo("Tidal Visionary", 80, Rarity.COMMON, mage.cards.t.TidalVisionary.class)); + cards.add(new SetCardInfo("Tigereye Cameo", 314, Rarity.UNCOMMON, mage.cards.t.TigereyeCameo.class)); + cards.add(new SetCardInfo("Tinder Farm", 329, Rarity.COMMON, mage.cards.t.TinderFarm.class)); + cards.add(new SetCardInfo("Tolarian Emissary", 81, Rarity.UNCOMMON, mage.cards.t.TolarianEmissary.class)); + cards.add(new SetCardInfo("Tower Drake", 82, Rarity.COMMON, mage.cards.t.TowerDrake.class)); + cards.add(new SetCardInfo("Tranquility", 217, Rarity.COMMON, mage.cards.t.Tranquility.class)); + cards.add(new SetCardInfo("Traveler's Cloak", 83, Rarity.COMMON, mage.cards.t.TravelersCloak.class)); + cards.add(new SetCardInfo("Treefolk Healer", 218, Rarity.UNCOMMON, mage.cards.t.TreefolkHealer.class)); + cards.add(new SetCardInfo("Trench Wurm", 127, Rarity.UNCOMMON, mage.cards.t.TrenchWurm.class)); + cards.add(new SetCardInfo("Treva's Attendant", 315, Rarity.UNCOMMON, mage.cards.t.TrevasAttendant.class)); + cards.add(new SetCardInfo("Treva, the Renewer", 280, Rarity.RARE, mage.cards.t.TrevaTheRenewer.class)); + cards.add(new SetCardInfo("Tribal Flames", 176, Rarity.COMMON, mage.cards.t.TribalFlames.class)); + cards.add(new SetCardInfo("Troll-Horn Cameo", 316, Rarity.UNCOMMON, mage.cards.t.TrollHornCameo.class)); + cards.add(new SetCardInfo("Tsabo's Assassin", 128, Rarity.RARE, mage.cards.t.TsabosAssassin.class)); + cards.add(new SetCardInfo("Tsabo's Decree", 129, Rarity.RARE, mage.cards.t.TsabosDecree.class)); + cards.add(new SetCardInfo("Tsabo's Web", 317, Rarity.RARE, mage.cards.t.TsabosWeb.class)); + cards.add(new SetCardInfo("Tsabo Tavoc", 281, Rarity.RARE, mage.cards.t.TsaboTavoc.class)); + cards.add(new SetCardInfo("Turf Wound", 177, Rarity.COMMON, mage.cards.t.TurfWound.class)); + cards.add(new SetCardInfo("Twilight's Call", 130, Rarity.RARE, mage.cards.t.TwilightsCall.class)); + cards.add(new SetCardInfo("Undermine", 282, Rarity.RARE, mage.cards.u.Undermine.class)); + cards.add(new SetCardInfo("Urborg Drake", 283, Rarity.UNCOMMON, mage.cards.u.UrborgDrake.class)); + cards.add(new SetCardInfo("Urborg Emissary", 131, Rarity.UNCOMMON, mage.cards.u.UrborgEmissary.class)); + cards.add(new SetCardInfo("Urborg Phantom", 132, Rarity.COMMON, mage.cards.u.UrborgPhantom.class)); + cards.add(new SetCardInfo("Urborg Shambler", 133, Rarity.UNCOMMON, mage.cards.u.UrborgShambler.class)); + cards.add(new SetCardInfo("Urborg Skeleton", 134, Rarity.COMMON, mage.cards.u.UrborgSkeleton.class)); + cards.add(new SetCardInfo("Urborg Volcano", 330, Rarity.UNCOMMON, mage.cards.u.UrborgVolcano.class)); + cards.add(new SetCardInfo("Urza's Filter", 318, Rarity.RARE, mage.cards.u.UrzasFilter.class)); + cards.add(new SetCardInfo("Urza's Rage", 178, Rarity.RARE, mage.cards.u.UrzasRage.class)); + cards.add(new SetCardInfo("Utopia Tree", 219, Rarity.RARE, mage.cards.u.UtopiaTree.class)); + cards.add(new SetCardInfo("Verdeloth the Ancient", 220, Rarity.RARE, mage.cards.v.VerdelothTheAncient.class)); + cards.add(new SetCardInfo("Verduran Emissary", 221, Rarity.UNCOMMON, mage.cards.v.VerduranEmissary.class)); + cards.add(new SetCardInfo("Viashino Grappler", 179, Rarity.COMMON, mage.cards.v.ViashinoGrappler.class)); + cards.add(new SetCardInfo("Vicious Kavu", 284, Rarity.UNCOMMON, mage.cards.v.ViciousKavu.class)); + cards.add(new SetCardInfo("Vile Consumption", 285, Rarity.RARE, mage.cards.v.VileConsumption.class)); + cards.add(new SetCardInfo("Vodalian Hypnotist", 84, Rarity.UNCOMMON, mage.cards.v.VodalianHypnotist.class)); + cards.add(new SetCardInfo("Vodalian Merchant", 85, Rarity.COMMON, mage.cards.v.VodalianMerchant.class)); + cards.add(new SetCardInfo("Vodalian Serpent", 86, Rarity.COMMON, mage.cards.v.VodalianSerpent.class)); + cards.add(new SetCardInfo("Vodalian Zombie", 286, Rarity.COMMON, mage.cards.v.VodalianZombie.class)); + cards.add(new SetCardInfo("Void", 287, Rarity.RARE, mage.cards.v.Void.class)); + cards.add(new SetCardInfo("Voracious Cobra", 288, Rarity.UNCOMMON, mage.cards.v.VoraciousCobra.class)); + cards.add(new SetCardInfo("Wallop", 223, Rarity.UNCOMMON, mage.cards.w.Wallop.class)); + cards.add(new SetCardInfo("Wandering Stream", 224, Rarity.COMMON, mage.cards.w.WanderingStream.class)); + cards.add(new SetCardInfo("Wash Out", 87, Rarity.UNCOMMON, mage.cards.w.WashOut.class)); + cards.add(new SetCardInfo("Wax // Wane", 296, Rarity.UNCOMMON, mage.cards.w.WaxWane.class)); + cards.add(new SetCardInfo("Wayfaring Giant", 44, Rarity.UNCOMMON, mage.cards.w.WayfaringGiant.class)); + cards.add(new SetCardInfo("Whip Silk", 225, Rarity.COMMON, mage.cards.w.WhipSilk.class)); + cards.add(new SetCardInfo("Wings of Hope", 289, Rarity.COMMON, mage.cards.w.WingsOfHope.class)); + cards.add(new SetCardInfo("Winnow", 45, Rarity.RARE, mage.cards.w.Winnow.class)); + cards.add(new SetCardInfo("Worldly Counsel", 89, Rarity.COMMON, mage.cards.w.WorldlyCounsel.class)); + cards.add(new SetCardInfo("Yavimaya Barbarian", 290, Rarity.COMMON, mage.cards.y.YavimayaBarbarian.class)); + cards.add(new SetCardInfo("Yavimaya Kavu", 291, Rarity.UNCOMMON, mage.cards.y.YavimayaKavu.class)); + cards.add(new SetCardInfo("Yawgmoth's Agenda", 135, Rarity.RARE, mage.cards.y.YawgmothsAgenda.class)); + cards.add(new SetCardInfo("Zanam Djinn", 90, Rarity.UNCOMMON, mage.cards.z.ZanamDjinn.class)); + cards.add(new SetCardInfo("Zap", 180, Rarity.COMMON, mage.cards.z.Zap.class)); + } +} diff --git a/Mage.Sets/src/mage/sets/Judgment.java b/Mage.Sets/src/mage/sets/Judgment.java index 9007e49c9e..3ba00a1bfa 100644 --- a/Mage.Sets/src/mage/sets/Judgment.java +++ b/Mage.Sets/src/mage/sets/Judgment.java @@ -130,6 +130,7 @@ public class Judgment extends ExpansionSet { cards.add(new SetCardInfo("Mirari's Wake", 139, Rarity.RARE, mage.cards.m.MirarisWake.class)); cards.add(new SetCardInfo("Mirror Wall", 47, Rarity.COMMON, mage.cards.m.MirrorWall.class)); cards.add(new SetCardInfo("Mist of Stagnation", 48, Rarity.RARE, mage.cards.m.MistOfStagnation.class)); + cards.add(new SetCardInfo("Morality Shift", 70, Rarity.RARE, mage.cards.m.MoralityShift.class)); cards.add(new SetCardInfo("Nantuko Monastery", 142, Rarity.UNCOMMON, mage.cards.n.NantukoMonastery.class)); cards.add(new SetCardInfo("Nantuko Tracer", 125, Rarity.COMMON, mage.cards.n.NantukoTracer.class)); cards.add(new SetCardInfo("Nomad Mythmaker", 15, Rarity.RARE, mage.cards.n.NomadMythmaker.class)); @@ -163,6 +164,7 @@ public class Judgment extends ExpansionSet { cards.add(new SetCardInfo("Swelter", 101, Rarity.UNCOMMON, mage.cards.s.Swelter.class)); cards.add(new SetCardInfo("Swirling Sandstorm", 102, Rarity.COMMON, mage.cards.s.SwirlingSandstorm.class)); cards.add(new SetCardInfo("Sylvan Safekeeper", 133, Rarity.RARE, mage.cards.s.SylvanSafekeeper.class)); + cards.add(new SetCardInfo("Telekinetic Bonds", 52, Rarity.RARE, mage.cards.t.TelekineticBonds.class)); cards.add(new SetCardInfo("Test of Endurance", 29, Rarity.RARE, mage.cards.t.TestOfEndurance.class)); cards.add(new SetCardInfo("Thriss, Nantuko Primus", 134, Rarity.RARE, mage.cards.t.ThrissNantukoPrimus.class)); cards.add(new SetCardInfo("Toxic Stench", 74, Rarity.COMMON, mage.cards.t.ToxicStench.class)); diff --git a/Mage.Sets/src/mage/sets/Legends.java b/Mage.Sets/src/mage/sets/Legends.java index ffd0535857..779015f3cd 100644 --- a/Mage.Sets/src/mage/sets/Legends.java +++ b/Mage.Sets/src/mage/sets/Legends.java @@ -133,6 +133,7 @@ public class Legends extends ExpansionSet { cards.add(new SetCardInfo("Giant Strength", 147, Rarity.COMMON, mage.cards.g.GiantStrength.class)); cards.add(new SetCardInfo("Giant Turtle", 102, Rarity.COMMON, mage.cards.g.GiantTurtle.class)); cards.add(new SetCardInfo("Glyph of Destruction", 148, Rarity.COMMON, mage.cards.g.GlyphOfDestruction.class)); + cards.add(new SetCardInfo("Glyph of Doom", 14, Rarity.COMMON, mage.cards.g.GlyphOfDoom.class)); cards.add(new SetCardInfo("Glyph of Life", 184, Rarity.COMMON, mage.cards.g.GlyphOfLife.class)); cards.add(new SetCardInfo("Gravity Sphere", 149, Rarity.RARE, mage.cards.g.GravitySphere.class)); cards.add(new SetCardInfo("Great Defender", 185, Rarity.UNCOMMON, mage.cards.g.GreatDefender.class)); @@ -299,6 +300,7 @@ public class Legends extends ExpansionSet { cards.add(new SetCardInfo("Winds of Change", 169, Rarity.UNCOMMON, mage.cards.w.WindsOfChange.class)); cards.add(new SetCardInfo("Winter Blast", 127, Rarity.RARE, mage.cards.w.WinterBlast.class)); cards.add(new SetCardInfo("Wolverine Pack", 128, Rarity.COMMON, mage.cards.w.WolverinePack.class)); + cards.add(new SetCardInfo("Wood Elemental", 129, Rarity.RARE, mage.cards.w.WoodElemental.class)); cards.add(new SetCardInfo("Xira Arien", 310, Rarity.RARE, mage.cards.x.XiraArien.class)); cards.add(new SetCardInfo("Zephyr Falcon", 86, Rarity.COMMON, mage.cards.z.ZephyrFalcon.class)); } diff --git a/Mage.Sets/src/mage/sets/LimitedEditionAlpha.java b/Mage.Sets/src/mage/sets/LimitedEditionAlpha.java index 4a87e3baac..8b7de5a757 100644 --- a/Mage.Sets/src/mage/sets/LimitedEditionAlpha.java +++ b/Mage.Sets/src/mage/sets/LimitedEditionAlpha.java @@ -44,6 +44,7 @@ public class LimitedEditionAlpha extends ExpansionSet { cards.add(new SetCardInfo("Black Lotus", 232, Rarity.RARE, mage.cards.b.BlackLotus.class)); cards.add(new SetCardInfo("Black Vise", 233, Rarity.UNCOMMON, mage.cards.b.BlackVise.class)); cards.add(new SetCardInfo("Black Ward", 189, Rarity.UNCOMMON, mage.cards.b.BlackWard.class)); + cards.add(new SetCardInfo("Blaze of Glory", 190, Rarity.RARE, mage.cards.b.BlazeOfGlory.class)); cards.add(new SetCardInfo("Blessing", 191, Rarity.RARE, mage.cards.b.Blessing.class)); cards.add(new SetCardInfo("Blue Elemental Blast", 50, Rarity.COMMON, mage.cards.b.BlueElementalBlast.class)); cards.add(new SetCardInfo("Blue Ward", 192, Rarity.UNCOMMON, mage.cards.b.BlueWard.class)); diff --git a/Mage.Sets/src/mage/sets/LimitedEditionBeta.java b/Mage.Sets/src/mage/sets/LimitedEditionBeta.java index aed946ed8a..9b642609e4 100644 --- a/Mage.Sets/src/mage/sets/LimitedEditionBeta.java +++ b/Mage.Sets/src/mage/sets/LimitedEditionBeta.java @@ -44,6 +44,7 @@ public class LimitedEditionBeta extends ExpansionSet { cards.add(new SetCardInfo("Black Lotus", 233, Rarity.RARE, mage.cards.b.BlackLotus.class)); cards.add(new SetCardInfo("Black Vise", 234, Rarity.UNCOMMON, mage.cards.b.BlackVise.class)); cards.add(new SetCardInfo("Black Ward", 5, Rarity.UNCOMMON, mage.cards.b.BlackWard.class)); + cards.add(new SetCardInfo("Blaze of Glory", 6, Rarity.RARE, mage.cards.b.BlazeOfGlory.class)); cards.add(new SetCardInfo("Blessing", 7, Rarity.RARE, mage.cards.b.Blessing.class)); cards.add(new SetCardInfo("Blue Elemental Blast", 50, Rarity.COMMON, mage.cards.b.BlueElementalBlast.class)); cards.add(new SetCardInfo("Blue Ward", 8, Rarity.UNCOMMON, mage.cards.b.BlueWard.class)); diff --git a/Mage.Sets/src/mage/sets/Masters25.java b/Mage.Sets/src/mage/sets/Masters25.java index cb35f2c36f..83b55f6041 100644 --- a/Mage.Sets/src/mage/sets/Masters25.java +++ b/Mage.Sets/src/mage/sets/Masters25.java @@ -29,9 +29,10 @@ package mage.sets; /** * - * @author fireshoes + * @author JayDi85 */ import mage.cards.ExpansionSet; +import mage.constants.Rarity; import mage.constants.SetType; public class Masters25 extends ExpansionSet { @@ -43,7 +44,7 @@ public class Masters25 extends ExpansionSet { } private Masters25() { - super("Masters 25", "M25", ExpansionSet.buildDate(2018, 3, 16), SetType.SUPPLEMENTAL); + super("Masters 25", "A25", ExpansionSet.buildDate(2018, 3, 16), SetType.SUPPLEMENTAL); this.blockName = "Reprint"; this.hasBasicLands = false; this.hasBoosters = true; @@ -52,5 +53,255 @@ public class Masters25 extends ExpansionSet { this.numBoosterUncommon = 3; this.numBoosterRare = 1; this.ratioBoosterMythic = 8; + + cards.add(new SetCardInfo("Act of Heroism", 1, Rarity.COMMON, mage.cards.a.ActOfHeroism.class)); + cards.add(new SetCardInfo("Akroma, Angel of Wrath", 2, Rarity.MYTHIC, mage.cards.a.AkromaAngelOfWrath.class)); + cards.add(new SetCardInfo("Akroma's Vengeance", 3, Rarity.RARE, mage.cards.a.AkromasVengeance.class)); + cards.add(new SetCardInfo("Angelic Page", 4, Rarity.UNCOMMON, mage.cards.a.AngelicPage.class)); + cards.add(new SetCardInfo("Armageddon", 5, Rarity.MYTHIC, mage.cards.a.Armageddon.class)); + cards.add(new SetCardInfo("Auramancer", 6, Rarity.COMMON, mage.cards.a.Auramancer.class)); + cards.add(new SetCardInfo("Cloudshift", 7, Rarity.COMMON, mage.cards.c.Cloudshift.class)); + cards.add(new SetCardInfo("Congregate", 8, Rarity.UNCOMMON, mage.cards.c.Congregate.class)); + cards.add(new SetCardInfo("Darien, King of Kjeldor", 9, Rarity.RARE, mage.cards.d.DarienKingOfKjeldor.class)); + cards.add(new SetCardInfo("Dauntless Cathar", 10, Rarity.COMMON, mage.cards.d.DauntlessCathar.class)); + cards.add(new SetCardInfo("Decree of Justice", 11, Rarity.RARE, mage.cards.d.DecreeOfJustice.class)); + cards.add(new SetCardInfo("Disenchant", 12, Rarity.COMMON, mage.cards.d.Disenchant.class)); + cards.add(new SetCardInfo("Fencing Ace", 13, Rarity.COMMON, mage.cards.f.FencingAce.class)); + cards.add(new SetCardInfo("Fiend Hunter", 14, Rarity.UNCOMMON, mage.cards.f.FiendHunter.class)); + cards.add(new SetCardInfo("Geist of the Moors", 15, Rarity.COMMON, mage.cards.g.GeistOfTheMoors.class)); + cards.add(new SetCardInfo("Gods Willing", 16, Rarity.COMMON, mage.cards.g.GodsWilling.class)); + cards.add(new SetCardInfo("Griffin Protector", 17, Rarity.COMMON, mage.cards.g.GriffinProtector.class)); + cards.add(new SetCardInfo("Karona's Zealot", 18, Rarity.UNCOMMON, mage.cards.k.KaronasZealot.class)); + cards.add(new SetCardInfo("Knight of the Skyward Eye", 19, Rarity.COMMON, mage.cards.k.KnightOfTheSkywardEye.class)); + cards.add(new SetCardInfo("Kongming, 'Sleeping Dragon'", 20, Rarity.UNCOMMON, mage.cards.k.KongmingSleepingDragon.class)); + cards.add(new SetCardInfo("Kor Firewalker", 21, Rarity.UNCOMMON, mage.cards.k.KorFirewalker.class)); + cards.add(new SetCardInfo("Loyal Sentry", 22, Rarity.COMMON, mage.cards.l.LoyalSentry.class)); + cards.add(new SetCardInfo("Luminarch Ascension", 23, Rarity.RARE, mage.cards.l.LuminarchAscension.class)); + cards.add(new SetCardInfo("Lunarch Mantle", 24, Rarity.COMMON, mage.cards.l.LunarchMantle.class)); + cards.add(new SetCardInfo("Noble Templar", 25, Rarity.COMMON, mage.cards.n.NobleTemplar.class)); + cards.add(new SetCardInfo("Nyx-Fleece Ram", 26, Rarity.UNCOMMON, mage.cards.n.NyxFleeceRam.class)); + cards.add(new SetCardInfo("Ordeal of Heliod", 27, Rarity.UNCOMMON, mage.cards.o.OrdealOfHeliod.class)); + cards.add(new SetCardInfo("Pacifism", 28, Rarity.COMMON, mage.cards.p.Pacifism.class)); + cards.add(new SetCardInfo("Path of Peace", 29, Rarity.COMMON, mage.cards.p.PathOfPeace.class)); + cards.add(new SetCardInfo("Promise of Bunrei", 30, Rarity.UNCOMMON, mage.cards.p.PromiseOfBunrei.class)); + cards.add(new SetCardInfo("Renewed Faith", 31, Rarity.COMMON, mage.cards.r.RenewedFaith.class)); + cards.add(new SetCardInfo("Rest in Peace", 32, Rarity.RARE, mage.cards.r.RestInPeace.class)); + cards.add(new SetCardInfo("Savannah Lions", 33, Rarity.COMMON, mage.cards.s.SavannahLions.class)); + cards.add(new SetCardInfo("Squadron Hawk", 34, Rarity.COMMON, mage.cards.s.SquadronHawk.class)); + cards.add(new SetCardInfo("Swords to Plowshares", 35, Rarity.UNCOMMON, mage.cards.s.SwordsToPlowshares.class)); + cards.add(new SetCardInfo("Thalia, Guardian of Thraben", 36, Rarity.RARE, mage.cards.t.ThaliaGuardianOfThraben.class)); + cards.add(new SetCardInfo("Urbis Protector", 37, Rarity.UNCOMMON, mage.cards.u.UrbisProtector.class)); + cards.add(new SetCardInfo("Valor in Akros", 38, Rarity.UNCOMMON, mage.cards.v.ValorInAkros.class)); + cards.add(new SetCardInfo("Whitemane Lion", 39, Rarity.COMMON, mage.cards.w.WhitemaneLion.class)); + cards.add(new SetCardInfo("Accumulated Knowledge", 40, Rarity.COMMON, mage.cards.a.AccumulatedKnowledge.class)); + cards.add(new SetCardInfo("Arcane Denial", 41, Rarity.COMMON, mage.cards.a.ArcaneDenial.class)); + cards.add(new SetCardInfo("Bident of Thassa", 42, Rarity.RARE, mage.cards.b.BidentOfThassa.class)); + cards.add(new SetCardInfo("Blue Elemental Blast", 43, Rarity.UNCOMMON, mage.cards.b.BlueElementalBlast.class)); + cards.add(new SetCardInfo("Blue Sun's Zenith", 44, Rarity.RARE, mage.cards.b.BlueSunsZenith.class)); + cards.add(new SetCardInfo("Borrowing 100,000 Arrows", 45, Rarity.COMMON, mage.cards.b.Borrowing100000Arrows.class)); + cards.add(new SetCardInfo("Brainstorm", 46, Rarity.COMMON, mage.cards.b.Brainstorm.class)); + cards.add(new SetCardInfo("Brine Elemental", 47, Rarity.UNCOMMON, mage.cards.b.BrineElemental.class)); + cards.add(new SetCardInfo("Choking Tethers", 48, Rarity.COMMON, mage.cards.c.ChokingTethers.class)); + cards.add(new SetCardInfo("Coralhelm Guide", 49, Rarity.COMMON, mage.cards.c.CoralhelmGuide.class)); + cards.add(new SetCardInfo("Counterspell", 50, Rarity.COMMON, mage.cards.c.Counterspell.class)); + cards.add(new SetCardInfo("Court Hussar", 51, Rarity.COMMON, mage.cards.c.CourtHussar.class)); + cards.add(new SetCardInfo("Curiosity", 52, Rarity.UNCOMMON, mage.cards.c.Curiosity.class)); + cards.add(new SetCardInfo("Cursecatcher", 53, Rarity.UNCOMMON, mage.cards.c.Cursecatcher.class)); + cards.add(new SetCardInfo("Dragon's Eye Savants", 54, Rarity.COMMON, mage.cards.d.DragonsEyeSavants.class)); + cards.add(new SetCardInfo("Exclude", 55, Rarity.UNCOMMON, mage.cards.e.Exclude.class)); + cards.add(new SetCardInfo("Fathom Seer", 56, Rarity.COMMON, mage.cards.f.FathomSeer.class)); + cards.add(new SetCardInfo("Flash", 57, Rarity.RARE, mage.cards.f.Flash.class)); + cards.add(new SetCardInfo("Freed from the Real", 58, Rarity.UNCOMMON, mage.cards.f.FreedFromTheReal.class)); + cards.add(new SetCardInfo("Genju of the Falls", 59, Rarity.UNCOMMON, mage.cards.g.GenjuOfTheFalls.class)); + cards.add(new SetCardInfo("Ghost Ship", 60, Rarity.COMMON, mage.cards.g.GhostShip.class)); + cards.add(new SetCardInfo("Horseshoe Crab", 61, Rarity.COMMON, mage.cards.h.HorseshoeCrab.class)); + cards.add(new SetCardInfo("Jace, the Mind Sculptor", 62, Rarity.MYTHIC, mage.cards.j.JaceTheMindSculptor.class)); + cards.add(new SetCardInfo("Jalira, Master Polymorphist", 63, Rarity.UNCOMMON, mage.cards.j.JaliraMasterPolymorphist.class)); + cards.add(new SetCardInfo("Man-o'-War", 64, Rarity.COMMON, mage.cards.m.ManOWar.class)); + cards.add(new SetCardInfo("Merfolk Looter", 65, Rarity.UNCOMMON, mage.cards.m.MerfolkLooter.class)); + cards.add(new SetCardInfo("Murder of Crows", 66, Rarity.UNCOMMON, mage.cards.m.MurderOfCrows.class)); + cards.add(new SetCardInfo("Mystic of the Hidden Way", 67, Rarity.COMMON, mage.cards.m.MysticOfTheHiddenWay.class)); + cards.add(new SetCardInfo("Pact of Negation", 68, Rarity.RARE, mage.cards.p.PactOfNegation.class)); + cards.add(new SetCardInfo("Phantasmal Bear", 69, Rarity.COMMON, mage.cards.p.PhantasmalBear.class)); + cards.add(new SetCardInfo("Reef Worm", 70, Rarity.RARE, mage.cards.r.ReefWorm.class)); + cards.add(new SetCardInfo("Retraction Helix", 71, Rarity.COMMON, mage.cards.r.RetractionHelix.class)); + cards.add(new SetCardInfo("Shoreline Ranger", 72, Rarity.COMMON, mage.cards.s.ShorelineRanger.class)); + cards.add(new SetCardInfo("Sift", 73, Rarity.COMMON, mage.cards.s.Sift.class)); + cards.add(new SetCardInfo("Totally Lost", 74, Rarity.COMMON, mage.cards.t.TotallyLost.class)); + cards.add(new SetCardInfo("Twisted Image", 75, Rarity.UNCOMMON, mage.cards.t.TwistedImage.class)); + cards.add(new SetCardInfo("Vendilion Clique", 76, Rarity.MYTHIC, mage.cards.v.VendilionClique.class)); + cards.add(new SetCardInfo("Vesuvan Shapeshifter", 77, Rarity.RARE, mage.cards.v.VesuvanShapeshifter.class)); + cards.add(new SetCardInfo("Willbender", 78, Rarity.UNCOMMON, mage.cards.w.Willbender.class)); + cards.add(new SetCardInfo("Ancient Craving", 79, Rarity.UNCOMMON, mage.cards.a.AncientCraving.class)); + cards.add(new SetCardInfo("Bloodhunter Bat", 80, Rarity.COMMON, mage.cards.b.BloodhunterBat.class)); + cards.add(new SetCardInfo("Caustic Tar", 81, Rarity.UNCOMMON, mage.cards.c.CausticTar.class)); + cards.add(new SetCardInfo("Dark Ritual", 82, Rarity.COMMON, mage.cards.d.DarkRitual.class)); + cards.add(new SetCardInfo("Deadly Designs", 83, Rarity.UNCOMMON, mage.cards.d.DeadlyDesigns.class)); + cards.add(new SetCardInfo("Death's-Head Buzzard", 84, Rarity.COMMON, mage.cards.d.DeathsHeadBuzzard.class)); + cards.add(new SetCardInfo("Diabolic Edict", 85, Rarity.COMMON, mage.cards.d.DiabolicEdict.class)); + cards.add(new SetCardInfo("Dirge of Dread", 86, Rarity.COMMON, mage.cards.d.DirgeOfDread.class)); + cards.add(new SetCardInfo("Disfigure", 87, Rarity.COMMON, mage.cards.d.Disfigure.class)); + cards.add(new SetCardInfo("Doomsday", 88, Rarity.MYTHIC, mage.cards.d.Doomsday.class)); + cards.add(new SetCardInfo("Dusk Legion Zealot", 89, Rarity.COMMON, mage.cards.d.DuskLegionZealot.class)); + cards.add(new SetCardInfo("Erg Raiders", 90, Rarity.COMMON, mage.cards.e.ErgRaiders.class)); + cards.add(new SetCardInfo("Fallen Angel", 91, Rarity.UNCOMMON, mage.cards.f.FallenAngel.class)); + cards.add(new SetCardInfo("Hell's Caretaker", 92, Rarity.RARE, mage.cards.h.HellsCaretaker.class)); + cards.add(new SetCardInfo("Horror of the Broken Lands", 93, Rarity.COMMON, mage.cards.h.HorrorOfTheBrokenLands.class)); + cards.add(new SetCardInfo("Ihsan's Shade", 94, Rarity.UNCOMMON, mage.cards.i.IhsansShade.class)); + cards.add(new SetCardInfo("Laquatus's Champion", 95, Rarity.RARE, mage.cards.l.LaquatussChampion.class)); + cards.add(new SetCardInfo("Living Death", 96, Rarity.RARE, mage.cards.l.LivingDeath.class)); + cards.add(new SetCardInfo("Mesmeric Fiend", 97, Rarity.UNCOMMON, mage.cards.m.MesmericFiend.class)); + cards.add(new SetCardInfo("Murder", 98, Rarity.COMMON, mage.cards.m.Murder.class)); + cards.add(new SetCardInfo("Nezumi Cutthroat", 99, Rarity.COMMON, mage.cards.n.NezumiCutthroat.class)); + cards.add(new SetCardInfo("Phyrexian Ghoul", 100, Rarity.COMMON, mage.cards.p.PhyrexianGhoul.class)); + cards.add(new SetCardInfo("Phyrexian Obliterator", 101, Rarity.MYTHIC, mage.cards.p.PhyrexianObliterator.class)); + cards.add(new SetCardInfo("Plague Wind", 102, Rarity.RARE, mage.cards.p.PlagueWind.class)); + cards.add(new SetCardInfo("Ratcatcher", 103, Rarity.RARE, mage.cards.r.Ratcatcher.class)); + cards.add(new SetCardInfo("Ravenous Chupacabra", 104, Rarity.UNCOMMON, mage.cards.r.RavenousChupacabra.class)); + cards.add(new SetCardInfo("Relentless Rats", 105, Rarity.COMMON, mage.cards.r.RelentlessRats.class)); + cards.add(new SetCardInfo("Returned Phalanx", 106, Rarity.COMMON, mage.cards.r.ReturnedPhalanx.class)); + cards.add(new SetCardInfo("Ruthless Ripper", 107, Rarity.COMMON, mage.cards.r.RuthlessRipper.class)); + cards.add(new SetCardInfo("Street Wraith", 108, Rarity.UNCOMMON, mage.cards.s.StreetWraith.class)); + cards.add(new SetCardInfo("Supernatural Stamina", 109, Rarity.COMMON, mage.cards.s.SupernaturalStamina.class)); + cards.add(new SetCardInfo("Triskaidekaphobia", 110, Rarity.RARE, mage.cards.t.Triskaidekaphobia.class)); + cards.add(new SetCardInfo("Twisted Abomination", 111, Rarity.COMMON, mage.cards.t.TwistedAbomination.class)); + cards.add(new SetCardInfo("Undead Gladiator", 112, Rarity.UNCOMMON, mage.cards.u.UndeadGladiator.class)); + cards.add(new SetCardInfo("Unearth", 113, Rarity.COMMON, mage.cards.u.Unearth.class)); + cards.add(new SetCardInfo("Vampire Lacerator", 114, Rarity.COMMON, mage.cards.v.VampireLacerator.class)); + cards.add(new SetCardInfo("Will-o'-the-Wisp", 115, Rarity.UNCOMMON, mage.cards.w.WillOTheWisp.class)); + cards.add(new SetCardInfo("Zombify", 116, Rarity.UNCOMMON, mage.cards.z.Zombify.class)); + cards.add(new SetCardInfo("Zulaport Cutthroat", 117, Rarity.UNCOMMON, mage.cards.z.ZulaportCutthroat.class)); + cards.add(new SetCardInfo("Act of Treason", 118, Rarity.COMMON, mage.cards.a.ActOfTreason.class)); + cards.add(new SetCardInfo("Akroma, Angel of Fury", 119, Rarity.MYTHIC, mage.cards.a.AkromaAngelOfFury.class)); + cards.add(new SetCardInfo("Balduvian Horde", 120, Rarity.COMMON, mage.cards.b.BalduvianHorde.class)); + cards.add(new SetCardInfo("Ball Lightning", 121, Rarity.RARE, mage.cards.b.BallLightning.class)); + cards.add(new SetCardInfo("Blood Moon", 122, Rarity.RARE, mage.cards.b.BloodMoon.class)); + cards.add(new SetCardInfo("Browbeat", 123, Rarity.UNCOMMON, mage.cards.b.Browbeat.class)); + cards.add(new SetCardInfo("Chandra's Outrage", 124, Rarity.COMMON, mage.cards.c.ChandrasOutrage.class)); + cards.add(new SetCardInfo("Chartooth Cougar", 125, Rarity.COMMON, mage.cards.c.ChartoothCougar.class)); + cards.add(new SetCardInfo("Cinder Storm", 126, Rarity.COMMON, mage.cards.c.CinderStorm.class)); + cards.add(new SetCardInfo("Crimson Mage", 127, Rarity.COMMON, mage.cards.c.CrimsonMage.class)); + cards.add(new SetCardInfo("Eidolon of the Great Revel", 128, Rarity.RARE, mage.cards.e.EidolonOfTheGreatRevel.class)); + cards.add(new SetCardInfo("Enthralling Victor", 129, Rarity.UNCOMMON, mage.cards.e.EnthrallingVictor.class)); + cards.add(new SetCardInfo("Fortune Thief", 130, Rarity.RARE, mage.cards.f.FortuneThief.class)); + cards.add(new SetCardInfo("Frenzied Goblin", 131, Rarity.COMMON, mage.cards.f.FrenziedGoblin.class)); + cards.add(new SetCardInfo("Genju of the Spires", 132, Rarity.UNCOMMON, mage.cards.g.GenjuOfTheSpires.class)); + cards.add(new SetCardInfo("Goblin War Drums", 133, Rarity.UNCOMMON, mage.cards.g.GoblinWarDrums.class)); + cards.add(new SetCardInfo("Hordeling Outburst", 134, Rarity.COMMON, mage.cards.h.HordelingOutburst.class)); + cards.add(new SetCardInfo("Humble Defector", 135, Rarity.UNCOMMON, mage.cards.h.HumbleDefector.class)); + cards.add(new SetCardInfo("Imperial Recruiter", 136, Rarity.MYTHIC, mage.cards.i.ImperialRecruiter.class)); + cards.add(new SetCardInfo("Ire Shaman", 137, Rarity.UNCOMMON, mage.cards.i.IreShaman.class)); + cards.add(new SetCardInfo("Izzet Chemister", 138, Rarity.RARE, mage.cards.i.IzzetChemister.class)); + cards.add(new SetCardInfo("Jackal Pup", 139, Rarity.COMMON, mage.cards.j.JackalPup.class)); + cards.add(new SetCardInfo("Kindle", 140, Rarity.COMMON, mage.cards.k.Kindle.class)); + cards.add(new SetCardInfo("Lightning Bolt", 141, Rarity.UNCOMMON, mage.cards.l.LightningBolt.class)); + cards.add(new SetCardInfo("Magus of the Wheel", 142, Rarity.RARE, mage.cards.m.MagusOfTheWheel.class)); + cards.add(new SetCardInfo("Mogg Flunkies", 143, Rarity.COMMON, mage.cards.m.MoggFlunkies.class)); + cards.add(new SetCardInfo("Pillage", 144, Rarity.COMMON, mage.cards.p.Pillage.class)); + cards.add(new SetCardInfo("Pyre Hound", 145, Rarity.COMMON, mage.cards.p.PyreHound.class)); + cards.add(new SetCardInfo("Pyroclasm", 146, Rarity.UNCOMMON, mage.cards.p.Pyroclasm.class)); + cards.add(new SetCardInfo("Red Elemental Blast", 147, Rarity.UNCOMMON, mage.cards.r.RedElementalBlast.class)); + cards.add(new SetCardInfo("Simian Spirit Guide", 148, Rarity.UNCOMMON, mage.cards.s.SimianSpiritGuide.class)); + cards.add(new SetCardInfo("Skeletonize", 149, Rarity.COMMON, mage.cards.s.Skeletonize.class)); + cards.add(new SetCardInfo("Skirk Commando", 150, Rarity.COMMON, mage.cards.s.SkirkCommando.class)); + cards.add(new SetCardInfo("Soulbright Flamekin", 151, Rarity.COMMON, mage.cards.s.SoulbrightFlamekin.class)); + cards.add(new SetCardInfo("Spikeshot Goblin", 152, Rarity.UNCOMMON, mage.cards.s.SpikeshotGoblin.class)); + cards.add(new SetCardInfo("Thresher Lizard", 153, Rarity.COMMON, mage.cards.t.ThresherLizard.class)); + cards.add(new SetCardInfo("Trumpet Blast", 154, Rarity.COMMON, mage.cards.t.TrumpetBlast.class)); + cards.add(new SetCardInfo("Uncaged Fury", 155, Rarity.COMMON, mage.cards.u.UncagedFury.class)); + cards.add(new SetCardInfo("Zada, Hedron Grinder", 156, Rarity.UNCOMMON, mage.cards.z.ZadaHedronGrinder.class)); + cards.add(new SetCardInfo("Ainok Survivalist", 157, Rarity.COMMON, mage.cards.a.AinokSurvivalist.class)); + cards.add(new SetCardInfo("Ambassador Oak", 158, Rarity.COMMON, mage.cards.a.AmbassadorOak.class)); + cards.add(new SetCardInfo("Ancient Stirrings", 159, Rarity.UNCOMMON, mage.cards.a.AncientStirrings.class)); + cards.add(new SetCardInfo("Arbor Elf", 160, Rarity.COMMON, mage.cards.a.ArborElf.class)); + cards.add(new SetCardInfo("Azusa, Lost but Seeking", 161, Rarity.RARE, mage.cards.a.AzusaLostButSeeking.class)); + cards.add(new SetCardInfo("Broodhatch Nantuko", 162, Rarity.UNCOMMON, mage.cards.b.BroodhatchNantuko.class)); + cards.add(new SetCardInfo("Colossal Dreadmaw", 163, Rarity.COMMON, mage.cards.c.ColossalDreadmaw.class)); + cards.add(new SetCardInfo("Courser of Kruphix", 164, Rarity.RARE, mage.cards.c.CourserOfKruphix.class)); + cards.add(new SetCardInfo("Cultivate", 165, Rarity.COMMON, mage.cards.c.Cultivate.class)); + cards.add(new SetCardInfo("Echoing Courage", 166, Rarity.COMMON, mage.cards.e.EchoingCourage.class)); + cards.add(new SetCardInfo("Elvish Aberration", 167, Rarity.COMMON, mage.cards.e.ElvishAberration.class)); + cards.add(new SetCardInfo("Elvish Piper", 168, Rarity.RARE, mage.cards.e.ElvishPiper.class)); + cards.add(new SetCardInfo("Ember Weaver", 169, Rarity.COMMON, mage.cards.e.EmberWeaver.class)); + cards.add(new SetCardInfo("Epic Confrontation", 170, Rarity.COMMON, mage.cards.e.EpicConfrontation.class)); + cards.add(new SetCardInfo("Fierce Empath", 171, Rarity.UNCOMMON, mage.cards.f.FierceEmpath.class)); + cards.add(new SetCardInfo("Giant Growth", 172, Rarity.COMMON, mage.cards.g.GiantGrowth.class)); + cards.add(new SetCardInfo("Invigorate", 173, Rarity.UNCOMMON, mage.cards.i.Invigorate.class)); + cards.add(new SetCardInfo("Iwamori of the Open Fist", 174, Rarity.UNCOMMON, mage.cards.i.IwamoriOfTheOpenFist.class)); + cards.add(new SetCardInfo("Kavu Climber", 175, Rarity.COMMON, mage.cards.k.KavuClimber.class)); + cards.add(new SetCardInfo("Kavu Predator", 176, Rarity.UNCOMMON, mage.cards.k.KavuPredator.class)); + cards.add(new SetCardInfo("Krosan Colossus", 177, Rarity.UNCOMMON, mage.cards.k.KrosanColossus.class)); + cards.add(new SetCardInfo("Krosan Tusker", 178, Rarity.UNCOMMON, mage.cards.k.KrosanTusker.class)); + cards.add(new SetCardInfo("Living Wish", 179, Rarity.RARE, mage.cards.l.LivingWish.class)); + cards.add(new SetCardInfo("Lull", 180, Rarity.COMMON, mage.cards.l.Lull.class)); + cards.add(new SetCardInfo("Master of the Wild Hunt", 181, Rarity.MYTHIC, mage.cards.m.MasterOfTheWildHunt.class)); + cards.add(new SetCardInfo("Nettle Sentinel", 182, Rarity.COMMON, mage.cards.n.NettleSentinel.class)); + cards.add(new SetCardInfo("Plummet", 183, Rarity.COMMON, mage.cards.p.Plummet.class)); + cards.add(new SetCardInfo("Presence of Gond", 184, Rarity.COMMON, mage.cards.p.PresenceOfGond.class)); + cards.add(new SetCardInfo("Protean Hulk", 185, Rarity.RARE, mage.cards.p.ProteanHulk.class)); + cards.add(new SetCardInfo("Rancor", 186, Rarity.UNCOMMON, mage.cards.r.Rancor.class)); + cards.add(new SetCardInfo("Regrowth", 187, Rarity.UNCOMMON, mage.cards.r.Regrowth.class)); + cards.add(new SetCardInfo("Stampede Driver", 188, Rarity.UNCOMMON, mage.cards.s.StampedeDriver.class)); + cards.add(new SetCardInfo("Summoner's Pact", 189, Rarity.RARE, mage.cards.s.SummonersPact.class)); + cards.add(new SetCardInfo("Timberpack Wolf", 190, Rarity.COMMON, mage.cards.t.TimberpackWolf.class)); + cards.add(new SetCardInfo("Tree of Redemption", 191, Rarity.MYTHIC, mage.cards.t.TreeOfRedemption.class)); + cards.add(new SetCardInfo("Utopia Sprawl", 192, Rarity.UNCOMMON, mage.cards.u.UtopiaSprawl.class)); + cards.add(new SetCardInfo("Vessel of Nascency", 193, Rarity.COMMON, mage.cards.v.VesselOfNascency.class)); + cards.add(new SetCardInfo("Wildheart Invoker", 194, Rarity.COMMON, mage.cards.w.WildheartInvoker.class)); + cards.add(new SetCardInfo("Woolly Loxodon", 195, Rarity.COMMON, mage.cards.w.WoollyLoxodon.class)); + cards.add(new SetCardInfo("Animar, Soul of Elements", 196, Rarity.MYTHIC, mage.cards.a.AnimarSoulOfElements.class)); + cards.add(new SetCardInfo("Baloth Null", 197, Rarity.UNCOMMON, mage.cards.b.BalothNull.class)); + cards.add(new SetCardInfo("Blightning", 198, Rarity.UNCOMMON, mage.cards.b.Blightning.class)); + cards.add(new SetCardInfo("Boros Charm", 199, Rarity.UNCOMMON, mage.cards.b.BorosCharm.class)); + cards.add(new SetCardInfo("Brion Stoutarm", 200, Rarity.RARE, mage.cards.b.BrionStoutarm.class)); + cards.add(new SetCardInfo("Cloudblazer", 201, Rarity.UNCOMMON, mage.cards.c.Cloudblazer.class)); + cards.add(new SetCardInfo("Conflux", 202, Rarity.RARE, mage.cards.c.Conflux.class)); + cards.add(new SetCardInfo("Eladamri's Call", 203, Rarity.RARE, mage.cards.e.EladamrisCall.class)); + cards.add(new SetCardInfo("Gisela, Blade of Goldnight", 204, Rarity.MYTHIC, mage.cards.g.GiselaBladeOfGoldnight.class)); + cards.add(new SetCardInfo("Grenzo, Dungeon Warden", 205, Rarity.RARE, mage.cards.g.GrenzoDungeonWarden.class)); + cards.add(new SetCardInfo("Hanna, Ship's Navigator", 206, Rarity.RARE, mage.cards.h.HannaShipsNavigator.class)); + cards.add(new SetCardInfo("Lorescale Coatl", 207, Rarity.UNCOMMON, mage.cards.l.LorescaleCoatl.class)); + cards.add(new SetCardInfo("Mystic Snake", 208, Rarity.RARE, mage.cards.m.MysticSnake.class)); + cards.add(new SetCardInfo("Nicol Bolas", 209, Rarity.RARE, mage.cards.n.NicolBolas.class)); + cards.add(new SetCardInfo("Niv-Mizzet, the Firemind", 210, Rarity.RARE, mage.cards.n.NivMizzetTheFiremind.class)); + cards.add(new SetCardInfo("Notion Thief", 211, Rarity.RARE, mage.cards.n.NotionThief.class)); + cards.add(new SetCardInfo("Pernicious Deed", 212, Rarity.RARE, mage.cards.p.PerniciousDeed.class)); + cards.add(new SetCardInfo("Pillory of the Sleepless", 213, Rarity.UNCOMMON, mage.cards.p.PilloryOfTheSleepless.class)); + cards.add(new SetCardInfo("Prossh, Skyraider of Kher", 214, Rarity.MYTHIC, mage.cards.p.ProsshSkyraiderOfKher.class)); + cards.add(new SetCardInfo("Quicksilver Dagger", 215, Rarity.UNCOMMON, mage.cards.q.QuicksilverDagger.class)); + cards.add(new SetCardInfo("Ruric Thar, the Unbowed", 216, Rarity.RARE, mage.cards.r.RuricTharTheUnbowed.class)); + cards.add(new SetCardInfo("Shadowmage Infiltrator", 217, Rarity.UNCOMMON, mage.cards.s.ShadowmageInfiltrator.class)); + cards.add(new SetCardInfo("Stangg", 218, Rarity.UNCOMMON, mage.cards.s.Stangg.class)); + cards.add(new SetCardInfo("Vindicate", 219, Rarity.RARE, mage.cards.v.Vindicate.class)); + cards.add(new SetCardInfo("Watchwolf", 220, Rarity.UNCOMMON, mage.cards.w.Watchwolf.class)); + cards.add(new SetCardInfo("Assembly-Worker", 221, Rarity.COMMON, mage.cards.a.AssemblyWorker.class)); + cards.add(new SetCardInfo("Chalice of the Void", 222, Rarity.MYTHIC, mage.cards.c.ChaliceOfTheVoid.class)); + cards.add(new SetCardInfo("Coalition Relic", 223, Rarity.RARE, mage.cards.c.CoalitionRelic.class)); + cards.add(new SetCardInfo("Ensnaring Bridge", 224, Rarity.MYTHIC, mage.cards.e.EnsnaringBridge.class)); + cards.add(new SetCardInfo("Heavy Arbalest", 225, Rarity.UNCOMMON, mage.cards.h.HeavyArbalest.class)); + cards.add(new SetCardInfo("Nihil Spellbomb", 226, Rarity.COMMON, mage.cards.n.NihilSpellbomb.class)); + cards.add(new SetCardInfo("Perilous Myr", 227, Rarity.UNCOMMON, mage.cards.p.PerilousMyr.class)); + cards.add(new SetCardInfo("Primal Clay", 228, Rarity.COMMON, mage.cards.p.PrimalClay.class)); + cards.add(new SetCardInfo("Prophetic Prism", 229, Rarity.COMMON, mage.cards.p.PropheticPrism.class)); + cards.add(new SetCardInfo("Sai of the Shinobi", 230, Rarity.UNCOMMON, mage.cards.s.SaiOfTheShinobi.class)); + cards.add(new SetCardInfo("Self-Assembler", 231, Rarity.COMMON, mage.cards.s.SelfAssembler.class)); + cards.add(new SetCardInfo("Strionic Resonator", 232, Rarity.RARE, mage.cards.s.StrionicResonator.class)); + cards.add(new SetCardInfo("Sundering Titan", 233, Rarity.RARE, mage.cards.s.SunderingTitan.class)); + cards.add(new SetCardInfo("Swiftfoot Boots", 234, Rarity.UNCOMMON, mage.cards.s.SwiftfootBoots.class)); + cards.add(new SetCardInfo("Treasure Keeper", 235, Rarity.UNCOMMON, mage.cards.t.TreasureKeeper.class)); + cards.add(new SetCardInfo("Ash Barrens", 236, Rarity.UNCOMMON, mage.cards.a.AshBarrens.class)); + cards.add(new SetCardInfo("Cascade Bluffs", 237, Rarity.RARE, mage.cards.c.CascadeBluffs.class)); + cards.add(new SetCardInfo("Fetid Heath", 238, Rarity.RARE, mage.cards.f.FetidHeath.class)); + cards.add(new SetCardInfo("Flooded Grove", 239, Rarity.RARE, mage.cards.f.FloodedGrove.class)); + cards.add(new SetCardInfo("Haunted Fengraf", 240, Rarity.COMMON, mage.cards.h.HauntedFengraf.class)); + cards.add(new SetCardInfo("Mikokoro, Center of the Sea", 241, Rarity.RARE, mage.cards.m.MikokoroCenterOfTheSea.class)); + cards.add(new SetCardInfo("Mishra's Factory", 242, Rarity.UNCOMMON, mage.cards.m.MishrasFactory.class)); + cards.add(new SetCardInfo("Myriad Landscape", 243, Rarity.UNCOMMON, mage.cards.m.MyriadLandscape.class)); + cards.add(new SetCardInfo("Pendelhaven", 244, Rarity.RARE, mage.cards.p.Pendelhaven.class)); + cards.add(new SetCardInfo("Quicksand", 245, Rarity.UNCOMMON, mage.cards.q.Quicksand.class)); + cards.add(new SetCardInfo("Rishadan Port", 246, Rarity.RARE, mage.cards.r.RishadanPort.class)); + cards.add(new SetCardInfo("Rugged Prairie", 247, Rarity.RARE, mage.cards.r.RuggedPrairie.class)); + cards.add(new SetCardInfo("Twilight Mire", 248, Rarity.RARE, mage.cards.t.TwilightMire.class)); + cards.add(new SetCardInfo("Zoetic Cavern", 249, Rarity.UNCOMMON, mage.cards.z.ZoeticCavern.class)); } } diff --git a/Mage.Sets/src/mage/sets/MastersEditionIII.java b/Mage.Sets/src/mage/sets/MastersEditionIII.java index 6ba6134346..dfc7254072 100644 --- a/Mage.Sets/src/mage/sets/MastersEditionIII.java +++ b/Mage.Sets/src/mage/sets/MastersEditionIII.java @@ -137,6 +137,7 @@ public class MastersEditionIII extends ExpansionSet { cards.add(new SetCardInfo("Hammerheim", 207, Rarity.UNCOMMON, mage.cards.h.Hammerheim.class)); cards.add(new SetCardInfo("Hazezon Tamar", 151, Rarity.RARE, mage.cards.h.HazezonTamar.class)); cards.add(new SetCardInfo("Heal", 14, Rarity.COMMON, mage.cards.h.Heal.class)); + cards.add(new SetCardInfo("Heavy Fog", 122, Rarity.COMMON, mage.cards.h.HeavyFog.class)); cards.add(new SetCardInfo("Hellfire", 70, Rarity.RARE, mage.cards.h.Hellfire.class)); cards.add(new SetCardInfo("Hua Tuo, Honored Physician", 123, Rarity.RARE, mage.cards.h.HuaTuoHonoredPhysician.class)); cards.add(new SetCardInfo("Hunding Gjornersen", 152, Rarity.UNCOMMON, mage.cards.h.HundingGjornersen.class)); diff --git a/Mage.Sets/src/mage/sets/MastersEditionIV.java b/Mage.Sets/src/mage/sets/MastersEditionIV.java index 03ff7d240a..e06cd8e06c 100644 --- a/Mage.Sets/src/mage/sets/MastersEditionIV.java +++ b/Mage.Sets/src/mage/sets/MastersEditionIV.java @@ -91,6 +91,7 @@ public class MastersEditionIV extends ExpansionSet { cards.add(new SetCardInfo("Bee Sting", 144, Rarity.UNCOMMON, mage.cards.b.BeeSting.class)); cards.add(new SetCardInfo("Bird Maiden", 110, Rarity.COMMON, mage.cards.b.BirdMaiden.class)); cards.add(new SetCardInfo("Black Knight", 71, Rarity.UNCOMMON, mage.cards.b.BlackKnight.class)); + cards.add(new SetCardInfo("Blaze of Glory", 7, Rarity.UNCOMMON, mage.cards.b.BlazeOfGlory.class)); cards.add(new SetCardInfo("Blue Elemental Blast", 39, Rarity.UNCOMMON, mage.cards.b.BlueElementalBlast.class)); cards.add(new SetCardInfo("Book of Rass", 183, Rarity.UNCOMMON, mage.cards.b.BookOfRass.class)); cards.add(new SetCardInfo("Bottle of Suleiman", 184, Rarity.RARE, mage.cards.b.BottleOfSuleiman.class)); @@ -169,6 +170,7 @@ public class MastersEditionIV extends ExpansionSet { cards.add(new SetCardInfo("Grapeshot Catapult", 204, Rarity.UNCOMMON, mage.cards.g.GrapeshotCatapult.class)); cards.add(new SetCardInfo("Gravebind", 84, Rarity.COMMON, mage.cards.g.Gravebind.class)); cards.add(new SetCardInfo("Guardian Beast", 85, Rarity.RARE, mage.cards.g.GuardianBeast.class)); + cards.add(new SetCardInfo("Harsh Justice", 13, Rarity.RARE, mage.cards.h.HarshJustice.class)); cards.add(new SetCardInfo("Hasran Ogress", 86, Rarity.COMMON, mage.cards.h.HasranOgress.class)); cards.add(new SetCardInfo("Healing Salve", 14, Rarity.COMMON, mage.cards.h.HealingSalve.class)); cards.add(new SetCardInfo("Horn of Deafening", 205, Rarity.UNCOMMON, mage.cards.h.HornOfDeafening.class)); @@ -181,6 +183,7 @@ public class MastersEditionIV extends ExpansionSet { cards.add(new SetCardInfo("Jade Monolith", 208, Rarity.RARE, mage.cards.j.JadeMonolith.class)); cards.add(new SetCardInfo("Juggernaut", 209, Rarity.UNCOMMON, mage.cards.j.Juggernaut.class)); cards.add(new SetCardInfo("Junún Efreet", 88, Rarity.UNCOMMON, mage.cards.j.JununEfreet.class)); + cards.add(new SetCardInfo("Just Fate", 16, Rarity.COMMON, mage.cards.j.JustFate.class)); cards.add(new SetCardInfo("Kismet", 17, Rarity.RARE, mage.cards.k.Kismet.class)); cards.add(new SetCardInfo("Kormus Bell", 210, Rarity.RARE, mage.cards.k.KormusBell.class)); cards.add(new SetCardInfo("Kudzu", 159, Rarity.UNCOMMON, mage.cards.k.Kudzu.class)); @@ -238,6 +241,7 @@ public class MastersEditionIV extends ExpansionSet { cards.add(new SetCardInfo("Sandstorm", 164, Rarity.COMMON, mage.cards.s.Sandstorm.class)); cards.add(new SetCardInfo("Savannah Lions", 24, Rarity.UNCOMMON, mage.cards.s.SavannahLions.class)); cards.add(new SetCardInfo("Savannah", 250, Rarity.RARE, mage.cards.s.Savannah.class)); + cards.add(new SetCardInfo("Scarecrow", 225, Rarity.UNCOMMON, mage.cards.s.Scarecrow.class)); cards.add(new SetCardInfo("Scarwood Bandits", 165, Rarity.RARE, mage.cards.s.ScarwoodBandits.class)); cards.add(new SetCardInfo("Scavenger Folk", 166, Rarity.COMMON, mage.cards.s.ScavengerFolk.class)); cards.add(new SetCardInfo("Scavenging Ghoul", 95, Rarity.UNCOMMON, mage.cards.s.ScavengingGhoul.class)); @@ -316,6 +320,7 @@ public class MastersEditionIV extends ExpansionSet { cards.add(new SetCardInfo("Wild Aesthir", 34, Rarity.COMMON, mage.cards.w.WildAesthir.class)); cards.add(new SetCardInfo("Wild Griffin", 35, Rarity.COMMON, mage.cards.w.WildGriffin.class)); cards.add(new SetCardInfo("Wild Ox", 174, Rarity.UNCOMMON, mage.cards.w.WildOx.class)); + cards.add(new SetCardInfo("Wood Elemental", 175, Rarity.RARE, mage.cards.w.WoodElemental.class)); cards.add(new SetCardInfo("Xenic Poltergeist", 104, Rarity.UNCOMMON, mage.cards.x.XenicPoltergeist.class)); cards.add(new SetCardInfo("Yotian Soldier", 240, Rarity.COMMON, mage.cards.y.YotianSoldier.class)); cards.add(new SetCardInfo("Zombie Master", 105, Rarity.UNCOMMON, mage.cards.z.ZombieMaster.class)); diff --git a/Mage.Sets/src/mage/sets/MercadianMasques.java b/Mage.Sets/src/mage/sets/MercadianMasques.java index 5ca90702ac..0b52b88858 100644 --- a/Mage.Sets/src/mage/sets/MercadianMasques.java +++ b/Mage.Sets/src/mage/sets/MercadianMasques.java @@ -219,6 +219,7 @@ public class MercadianMasques extends ExpansionSet { cards.add(new SetCardInfo("Maggot Therapy", 145, Rarity.COMMON, mage.cards.m.MaggotTherapy.class)); cards.add(new SetCardInfo("Magistrate's Scepter", 304, Rarity.RARE, mage.cards.m.MagistratesScepter.class)); cards.add(new SetCardInfo("Magistrate's Veto", 204, Rarity.UNCOMMON, mage.cards.m.MagistratesVeto.class)); + cards.add(new SetCardInfo("Mercadia's Downfall", 205, Rarity.UNCOMMON, mage.cards.m.MercadiasDownfall.class)); cards.add(new SetCardInfo("Mercadian Bazaar", 321, Rarity.UNCOMMON, mage.cards.m.MercadianBazaar.class)); cards.add(new SetCardInfo("Midnight Ritual", 146, Rarity.RARE, mage.cards.m.MidnightRitual.class)); cards.add(new SetCardInfo("Misdirection", 87, Rarity.RARE, mage.cards.m.Misdirection.class)); @@ -357,6 +358,7 @@ public class MercadianMasques extends ExpansionSet { cards.add(new SetCardInfo("Two-Headed Dragon", 221, Rarity.RARE, mage.cards.t.TwoHeadedDragon.class)); cards.add(new SetCardInfo("Undertaker", 167, Rarity.COMMON, mage.cards.u.Undertaker.class)); cards.add(new SetCardInfo("Unmask", 168, Rarity.RARE, mage.cards.u.Unmask.class)); + cards.add(new SetCardInfo("Uphill Battle", 222, Rarity.UNCOMMON, mage.cards.u.UphillBattle.class)); cards.add(new SetCardInfo("Vendetta", 170, Rarity.COMMON, mage.cards.v.Vendetta.class)); cards.add(new SetCardInfo("Venomous Dragonfly", 282, Rarity.COMMON, mage.cards.v.VenomousDragonfly.class)); cards.add(new SetCardInfo("Vernal Equinox", 283, Rarity.RARE, mage.cards.v.VernalEquinox.class)); diff --git a/Mage.Sets/src/mage/sets/Mirage.java b/Mage.Sets/src/mage/sets/Mirage.java index 27052f442c..5db3aa9154 100644 --- a/Mage.Sets/src/mage/sets/Mirage.java +++ b/Mage.Sets/src/mage/sets/Mirage.java @@ -79,6 +79,7 @@ public class Mirage extends ExpansionSet { cards.add(new SetCardInfo("Boomerang", 56, Rarity.COMMON, mage.cards.b.Boomerang.class)); cards.add(new SetCardInfo("Breathstealer", 7, Rarity.COMMON, mage.cards.b.Breathstealer.class)); cards.add(new SetCardInfo("Brushwagg", 106, Rarity.RARE, mage.cards.b.Brushwagg.class)); + cards.add(new SetCardInfo("Builder's Bane", 160, Rarity.COMMON, mage.cards.b.BuildersBane.class)); cards.add(new SetCardInfo("Burning Palm Efreet", 161, Rarity.UNCOMMON, mage.cards.b.BurningPalmEfreet.class)); cards.add(new SetCardInfo("Burning Shield Askari", 162, Rarity.COMMON, mage.cards.b.BurningShieldAskari.class)); cards.add(new SetCardInfo("Cadaverous Bloom", 318, Rarity.RARE, mage.cards.c.CadaverousBloom.class)); diff --git a/Mage.Sets/src/mage/sets/Portal.java b/Mage.Sets/src/mage/sets/Portal.java index 8c15c619ed..36adbfaa9b 100644 --- a/Mage.Sets/src/mage/sets/Portal.java +++ b/Mage.Sets/src/mage/sets/Portal.java @@ -71,7 +71,7 @@ public class Portal extends ExpansionSet { cards.add(new SetCardInfo("Armageddon", 167, Rarity.RARE, mage.cards.a.Armageddon.class)); cards.add(new SetCardInfo("Armored Pegasus", 168, Rarity.COMMON, mage.cards.a.ArmoredPegasus.class)); cards.add(new SetCardInfo("Arrogant Vampire", 1, Rarity.UNCOMMON, mage.cards.a.ArrogantVampire.class)); - cards.add(new SetCardInfo("Assassin's Blade", 2, Rarity.UNCOMMON, mage.cards.a.AssassinsBlade.class)); + cards.add(new SetCardInfo("Assassin's Blade", 2, Rarity.UNCOMMON, mage.cards.a.AssassinsBlade.class)); cards.add(new SetCardInfo("Balance of Power", 42, Rarity.RARE, mage.cards.b.BalanceOfPower.class)); cards.add(new SetCardInfo("Baleful Stare", 43, Rarity.UNCOMMON, mage.cards.b.BalefulStare.class)); cards.add(new SetCardInfo("Bee Sting", 83, Rarity.UNCOMMON, mage.cards.b.BeeSting.class)); @@ -95,19 +95,22 @@ public class Portal extends ExpansionSet { cards.add(new SetCardInfo("Cloud Dragon", 46, Rarity.RARE, mage.cards.c.CloudDragon.class)); cards.add(new SetCardInfo("Cloud Pirates", 47, Rarity.COMMON, mage.cards.c.CloudPirates.class)); cards.add(new SetCardInfo("Cloud Spirit", 48, Rarity.UNCOMMON, mage.cards.c.CloudSpirit.class)); - cards.add(new SetCardInfo("Command of Unsummoning", 49, Rarity.UNCOMMON, mage.cards.c.CommandOfUnsummoning.class)); + cards.add(new SetCardInfo("Command of Unsummoning", 49, Rarity.UNCOMMON, mage.cards.c.CommandOfUnsummoning.class)); cards.add(new SetCardInfo("Coral Eel", 50, Rarity.COMMON, mage.cards.c.CoralEel.class)); cards.add(new SetCardInfo("Craven Giant", 126, Rarity.COMMON, mage.cards.c.CravenGiant.class)); cards.add(new SetCardInfo("Craven Knight", 7, Rarity.COMMON, mage.cards.c.CravenKnight.class)); cards.add(new SetCardInfo("Cruel Bargain", 8, Rarity.RARE, mage.cards.c.CruelBargain.class)); + cards.add(new SetCardInfo("Cruel Fate", 51, Rarity.RARE, mage.cards.c.CruelFate.class)); cards.add(new SetCardInfo("Cruel Tutor", 9, Rarity.RARE, mage.cards.c.CruelTutor.class)); cards.add(new SetCardInfo("Deep-Sea Serpent", 52, Rarity.UNCOMMON, mage.cards.d.DeepSeaSerpent.class)); - cards.add(new SetCardInfo("Defiant Stand", 174, Rarity.UNCOMMON, mage.cards.d.DefiantStand.class)); + cards.add(new SetCardInfo("Deep Wood", 86, Rarity.UNCOMMON, mage.cards.d.DeepWood.class)); + cards.add(new SetCardInfo("Defiant Stand", 174, Rarity.UNCOMMON, mage.cards.d.DefiantStand.class)); cards.add(new SetCardInfo("Deja Vu", 53, Rarity.COMMON, mage.cards.d.DejaVu.class)); cards.add(new SetCardInfo("Desert Drake", 127, Rarity.UNCOMMON, mage.cards.d.DesertDrake.class)); cards.add(new SetCardInfo("Devastation", 128, Rarity.RARE, mage.cards.d.Devastation.class)); cards.add(new SetCardInfo("Devoted Hero", 175, Rarity.COMMON, mage.cards.d.DevotedHero.class)); cards.add(new SetCardInfo("Djinn of the Lamp", 54, Rarity.RARE, mage.cards.d.DjinnOfTheLamp.class)); + cards.add(new SetCardInfo("Dread Charge", 10, Rarity.RARE, mage.cards.d.DreadCharge.class)); cards.add(new SetCardInfo("Dread Reaper", 11, Rarity.RARE, mage.cards.d.DreadReaper.class)); cards.add(new SetCardInfo("Dry Spell", 12, Rarity.UNCOMMON, DrySpell.class)); cards.add(new SetCardInfo("Earthquake", 129, Rarity.RARE, mage.cards.e.Earthquake.class)); @@ -143,6 +146,7 @@ public class Portal extends ExpansionSet { cards.add(new SetCardInfo("Grizzly Bears", 94, Rarity.COMMON, mage.cards.g.GrizzlyBears.class)); cards.add(new SetCardInfo("Hand of Death", 18, Rarity.COMMON, mage.cards.h.HandOfDeath.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Hand of Death", 19, Rarity.COMMON, mage.cards.h.HandOfDeath.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Harsh Justice", 180, Rarity.RARE, mage.cards.h.HarshJustice.class)); cards.add(new SetCardInfo("Highland Giant", 137, Rarity.COMMON, mage.cards.h.HighlandGiant.class)); cards.add(new SetCardInfo("Hill Giant", 138, Rarity.COMMON, mage.cards.h.HillGiant.class)); cards.add(new SetCardInfo("Horned Turtle", 58, Rarity.COMMON, mage.cards.h.HornedTurtle.class)); @@ -217,7 +221,7 @@ public class Portal extends ExpansionSet { cards.add(new SetCardInfo("Sacred Knight", 186, Rarity.COMMON, mage.cards.s.SacredKnight.class)); cards.add(new SetCardInfo("Sacred Nectar", 187, Rarity.COMMON, mage.cards.s.SacredNectar.class)); cards.add(new SetCardInfo("Scorching Spear", 154, Rarity.COMMON, mage.cards.s.ScorchingSpear.class)); - cards.add(new SetCardInfo("Scorching Winds", 155, Rarity.UNCOMMON, mage.cards.s.ScorchingWinds.class)); + cards.add(new SetCardInfo("Scorching Winds", 155, Rarity.UNCOMMON, mage.cards.s.ScorchingWinds.class)); cards.add(new SetCardInfo("Seasoned Marshal", 188, Rarity.UNCOMMON, mage.cards.s.SeasonedMarshal.class)); cards.add(new SetCardInfo("Serpent Assassin", 31, Rarity.RARE, mage.cards.s.SerpentAssassin.class)); cards.add(new SetCardInfo("Serpent Warrior", 32, Rarity.COMMON, mage.cards.s.SerpentWarrior.class)); @@ -245,6 +249,7 @@ public class Portal extends ExpansionSet { cards.add(new SetCardInfo("Sylvan Tutor", 114, Rarity.RARE, mage.cards.s.SylvanTutor.class)); cards.add(new SetCardInfo("Symbol of Unsummoning", 71, Rarity.COMMON, mage.cards.s.SymbolOfUnsummoning.class)); cards.add(new SetCardInfo("Taunt", 72, Rarity.RARE, mage.cards.t.Taunt.class)); + cards.add(new SetCardInfo("Temporary Truce", 195, Rarity.RARE, mage.cards.t.TemporaryTruce.class)); cards.add(new SetCardInfo("Theft of Dreams", 73, Rarity.UNCOMMON, mage.cards.t.TheftOfDreams.class)); cards.add(new SetCardInfo("Thing from the Deep", 74, Rarity.RARE, mage.cards.t.ThingFromTheDeep.class)); cards.add(new SetCardInfo("Thundering Wurm", 115, Rarity.RARE, mage.cards.t.ThunderingWurm.class)); @@ -252,7 +257,7 @@ public class Portal extends ExpansionSet { cards.add(new SetCardInfo("Tidal Surge", 75, Rarity.COMMON, mage.cards.t.TidalSurge.class)); cards.add(new SetCardInfo("Time Ebb", 76, Rarity.COMMON, mage.cards.t.TimeEbb.class)); cards.add(new SetCardInfo("Touch of Brilliance", 77, Rarity.COMMON, mage.cards.t.TouchOfBrilliance.class)); - cards.add(new SetCardInfo("Treetop Defense", 116, Rarity.RARE, mage.cards.t.TreetopDefense.class)); + cards.add(new SetCardInfo("Treetop Defense", 116, Rarity.RARE, mage.cards.t.TreetopDefense.class)); cards.add(new SetCardInfo("Undying Beast", 36, Rarity.COMMON, mage.cards.u.UndyingBeast.class)); cards.add(new SetCardInfo("Untamed Wilds", 117, Rarity.UNCOMMON, mage.cards.u.UntamedWilds.class)); cards.add(new SetCardInfo("Valorous Charge", 196, Rarity.UNCOMMON, mage.cards.v.ValorousCharge.class)); diff --git a/Mage.Sets/src/mage/sets/PortalSecondAge.java b/Mage.Sets/src/mage/sets/PortalSecondAge.java index f014ac1968..827a31692c 100644 --- a/Mage.Sets/src/mage/sets/PortalSecondAge.java +++ b/Mage.Sets/src/mage/sets/PortalSecondAge.java @@ -95,6 +95,7 @@ public class PortalSecondAge extends ExpansionSet { cards.add(new SetCardInfo("Dakmor Sorceress", 11, Rarity.RARE, mage.cards.d.DakmorSorceress.class)); cards.add(new SetCardInfo("Dark Offering", 12, Rarity.UNCOMMON, mage.cards.d.DarkOffering.class)); cards.add(new SetCardInfo("Deathcoil Wurm", 65, Rarity.RARE, mage.cards.d.DeathcoilWurm.class)); + cards.add(new SetCardInfo("Deep Wood", 66, Rarity.UNCOMMON, mage.cards.d.DeepWood.class)); cards.add(new SetCardInfo("Deja Vu", 35, Rarity.COMMON, mage.cards.d.DejaVu.class)); cards.add(new SetCardInfo("Denizen of the Deep", 36, Rarity.RARE, mage.cards.d.DenizenOfTheDeep.class)); cards.add(new SetCardInfo("Earthquake", 94, Rarity.RARE, mage.cards.e.Earthquake.class)); @@ -116,6 +117,7 @@ public class PortalSecondAge extends ExpansionSet { cards.add(new SetCardInfo("Goblin Mountaineer", 101, Rarity.COMMON, mage.cards.g.GoblinMountaineer.class)); cards.add(new SetCardInfo("Goblin Piker", 102, Rarity.COMMON, mage.cards.g.GoblinPiker.class)); cards.add(new SetCardInfo("Goblin Raider", 103, Rarity.COMMON, mage.cards.g.GoblinRaider.class)); + cards.add(new SetCardInfo("Goblin War Cry", 104, Rarity.UNCOMMON, mage.cards.g.GoblinWarCry.class)); cards.add(new SetCardInfo("Goblin War Strike", 105, Rarity.COMMON, mage.cards.g.GoblinWarStrike.class)); cards.add(new SetCardInfo("Golden Bear", 67, Rarity.COMMON, mage.cards.g.GoldenBear.class)); cards.add(new SetCardInfo("Hand of Death", 14, Rarity.COMMON, mage.cards.h.HandOfDeath.class)); @@ -127,6 +129,7 @@ public class PortalSecondAge extends ExpansionSet { cards.add(new SetCardInfo("Island", 155, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Island", 156, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Jagged Lightning", 106, Rarity.UNCOMMON, mage.cards.j.JaggedLightning.class)); + cards.add(new SetCardInfo("Just Fate", 137, Rarity.RARE, mage.cards.j.JustFate.class)); cards.add(new SetCardInfo("Kiss of Death", 16, Rarity.UNCOMMON, mage.cards.k.KissOfDeath.class)); cards.add(new SetCardInfo("Lava Axe", 107, Rarity.COMMON, mage.cards.l.LavaAxe.class)); cards.add(new SetCardInfo("Lone Wolf", 71, Rarity.UNCOMMON, mage.cards.l.LoneWolf.class)); @@ -212,6 +215,7 @@ public class PortalSecondAge extends ExpansionSet { cards.add(new SetCardInfo("Vengeance", 147, Rarity.UNCOMMON, mage.cards.v.Vengeance.class)); cards.add(new SetCardInfo("Volcanic Hammer", 119, Rarity.COMMON, mage.cards.v.VolcanicHammer.class)); cards.add(new SetCardInfo("Volunteer Militia", 148, Rarity.COMMON, mage.cards.v.VolunteerMilitia.class)); + cards.add(new SetCardInfo("Warrior's Stand", 149, Rarity.UNCOMMON, mage.cards.w.WarriorsStand.class)); cards.add(new SetCardInfo("Wildfire", 120, Rarity.RARE, mage.cards.w.Wildfire.class)); cards.add(new SetCardInfo("Wild Griffin", 150, Rarity.COMMON, mage.cards.w.WildGriffin.class)); cards.add(new SetCardInfo("Wild Ox", 90, Rarity.UNCOMMON, mage.cards.w.WildOx.class)); diff --git a/Mage.Sets/src/mage/sets/PortalThreeKingdoms.java b/Mage.Sets/src/mage/sets/PortalThreeKingdoms.java index bc64a4afe9..611ca80470 100644 --- a/Mage.Sets/src/mage/sets/PortalThreeKingdoms.java +++ b/Mage.Sets/src/mage/sets/PortalThreeKingdoms.java @@ -83,6 +83,7 @@ public class PortalThreeKingdoms extends ExpansionSet { cards.add(new SetCardInfo("Dong Zhou, the Tyrant", 109, Rarity.RARE, mage.cards.d.DongZhouTheTyrant.class)); cards.add(new SetCardInfo("Eightfold Maze", 2, Rarity.RARE, mage.cards.e.EightfoldMaze.class)); cards.add(new SetCardInfo("Empty City Ruse", 3, Rarity.UNCOMMON, mage.cards.e.EmptyCityRuse.class)); + cards.add(new SetCardInfo("Eunuchs' Intrigues", 110, Rarity.UNCOMMON, mage.cards.e.EunuchsIntrigues.class)); cards.add(new SetCardInfo("Exhaustion", 42, Rarity.RARE, mage.cards.e.Exhaustion.class)); cards.add(new SetCardInfo("Extinguish", 43, Rarity.COMMON, mage.cards.e.Extinguish.class)); cards.add(new SetCardInfo("False Defeat", 4, Rarity.COMMON, mage.cards.f.FalseDefeat.class)); @@ -99,6 +100,7 @@ public class PortalThreeKingdoms extends ExpansionSet { cards.add(new SetCardInfo("Ghostly Visit", 76, Rarity.COMMON, mage.cards.g.GhostlyVisit.class)); cards.add(new SetCardInfo("Guan Yu's 1,000-Li March", 7, Rarity.RARE, mage.cards.g.GuanYus1000LiMarch.class)); cards.add(new SetCardInfo("Guan Yu, Sainted Warrior", 6, Rarity.RARE, mage.cards.g.GuanYuSaintedWarrior.class)); + cards.add(new SetCardInfo("Heavy Fog", 136, Rarity.UNCOMMON, mage.cards.h.HeavyFog.class)); cards.add(new SetCardInfo("Huang Zhong, Shu General", 8, Rarity.RARE, mage.cards.h.HuangZhongShuGeneral.class)); cards.add(new SetCardInfo("Hua Tuo, Honored Physician", 137, Rarity.RARE, mage.cards.h.HuaTuoHonoredPhysician.class)); cards.add(new SetCardInfo("Hunting Cheetah", 138, Rarity.UNCOMMON, mage.cards.h.HuntingCheetah.class)); @@ -110,6 +112,7 @@ public class PortalThreeKingdoms extends ExpansionSet { cards.add(new SetCardInfo("Island", 170, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Island", 171, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Kongming, \"Sleeping Dragon\"", 9, Rarity.RARE, mage.cards.k.KongmingSleepingDragon.class)); + cards.add(new SetCardInfo("Kongming's Contraptions", 10, Rarity.RARE, mage.cards.k.KongmingsContraptions.class)); cards.add(new SetCardInfo("Lady Sun", 45, Rarity.RARE, mage.cards.l.LadySun.class)); cards.add(new SetCardInfo("Lady Zhurong, Warrior Queen", 139, Rarity.RARE, mage.cards.l.LadyZhurongWarriorQueen.class)); cards.add(new SetCardInfo("Liu Bei, Lord of Shu", 11, Rarity.RARE, mage.cards.l.LiuBeiLordOfShu.class)); @@ -185,6 +188,7 @@ public class PortalThreeKingdoms extends ExpansionSet { cards.add(new SetCardInfo("Virtuous Charge", 29, Rarity.COMMON, mage.cards.v.VirtuousCharge.class)); cards.add(new SetCardInfo("Volunteer Militia", 30, Rarity.COMMON, mage.cards.v.VolunteerMilitia.class)); cards.add(new SetCardInfo("Warrior's Oath", 124, Rarity.RARE, mage.cards.w.WarriorsOath.class)); + cards.add(new SetCardInfo("Warrior's Stand", 31, Rarity.UNCOMMON, mage.cards.w.WarriorsStand.class)); cards.add(new SetCardInfo("Wei Ambush Force", 85, Rarity.COMMON, mage.cards.w.WeiAmbushForce.class)); cards.add(new SetCardInfo("Wei Assassins", 86, Rarity.UNCOMMON, mage.cards.w.WeiAssassins.class)); cards.add(new SetCardInfo("Wei Elite Companions", 87, Rarity.UNCOMMON, mage.cards.w.WeiEliteCompanions.class)); diff --git a/Mage.Sets/src/mage/sets/Scourge.java b/Mage.Sets/src/mage/sets/Scourge.java index ad8585d582..3c5bf9920f 100644 --- a/Mage.Sets/src/mage/sets/Scourge.java +++ b/Mage.Sets/src/mage/sets/Scourge.java @@ -126,6 +126,7 @@ public class Scourge extends ExpansionSet { cards.add(new SetCardInfo("Guilty Conscience", 17, Rarity.COMMON, mage.cards.g.GuiltyConscience.class)); cards.add(new SetCardInfo("Hindering Touch", 37, Rarity.COMMON, mage.cards.h.HinderingTouch.class)); cards.add(new SetCardInfo("Hunting Pack", 121, Rarity.UNCOMMON, mage.cards.h.HuntingPack.class)); + cards.add(new SetCardInfo("Karona's Zealot", 18, Rarity.UNCOMMON, mage.cards.k.KaronasZealot.class)); cards.add(new SetCardInfo("Karona, False God", 138, Rarity.RARE, mage.cards.k.KaronaFalseGod.class)); cards.add(new SetCardInfo("Krosan Drover", 122, Rarity.COMMON, mage.cards.k.KrosanDrover.class)); cards.add(new SetCardInfo("Krosan Warchief", 123, Rarity.UNCOMMON, mage.cards.k.KrosanWarchief.class)); @@ -142,8 +143,10 @@ public class Scourge extends ExpansionSet { cards.add(new SetCardInfo("Nefashu", 70, Rarity.RARE, mage.cards.n.Nefashu.class)); cards.add(new SetCardInfo("Noble Templar", 19, Rarity.COMMON, mage.cards.n.NobleTemplar.class)); cards.add(new SetCardInfo("One with Nature", 125, Rarity.UNCOMMON, mage.cards.o.OneWithNature.class)); + cards.add(new SetCardInfo("Parallel Thoughts", 44, Rarity.RARE, mage.cards.p.ParallelThoughts.class)); cards.add(new SetCardInfo("Pemmin's Aura", 45, Rarity.UNCOMMON, mage.cards.p.PemminsAura.class)); cards.add(new SetCardInfo("Primitive Etchings", 126, Rarity.RARE, mage.cards.p.PrimitiveEtchings.class)); + cards.add(new SetCardInfo("Proteus Machine", 141, Rarity.UNCOMMON, mage.cards.p.ProteusMachine.class)); cards.add(new SetCardInfo("Putrid Raptor", 71, Rarity.UNCOMMON, mage.cards.p.PutridRaptor.class)); cards.add(new SetCardInfo("Pyrostatic Pillar", 100, Rarity.UNCOMMON, mage.cards.p.PyrostaticPillar.class)); cards.add(new SetCardInfo("Rain of Blades", 20, Rarity.UNCOMMON, mage.cards.r.RainOfBlades.class)); diff --git a/Mage.Sets/src/mage/sets/Tempest.java b/Mage.Sets/src/mage/sets/Tempest.java index e764804b94..26a956063f 100644 --- a/Mage.Sets/src/mage/sets/Tempest.java +++ b/Mage.Sets/src/mage/sets/Tempest.java @@ -219,6 +219,7 @@ public class Tempest extends ExpansionSet { cards.add(new SetCardInfo("Opportunist", 194, Rarity.UNCOMMON, mage.cards.o.Opportunist.class)); cards.add(new SetCardInfo("Oracle en-Vec", 243, Rarity.RARE, mage.cards.o.OracleEnVec.class)); cards.add(new SetCardInfo("Orim, Samite Healer", 244, Rarity.RARE, mage.cards.o.OrimSamiteHealer.class)); + cards.add(new SetCardInfo("Orim's Prayer", 245, Rarity.UNCOMMON, mage.cards.o.OrimsPrayer.class)); cards.add(new SetCardInfo("Overrun", 137, Rarity.UNCOMMON, mage.cards.o.Overrun.class)); cards.add(new SetCardInfo("Pacifism", 246, Rarity.COMMON, mage.cards.p.Pacifism.class)); cards.add(new SetCardInfo("Pallimud", 195, Rarity.RARE, mage.cards.p.Pallimud.class)); diff --git a/Mage.Sets/src/mage/sets/TimeSpiralTimeshifted.java b/Mage.Sets/src/mage/sets/TimeSpiralTimeshifted.java index 119cb767c9..d124325bcc 100644 --- a/Mage.Sets/src/mage/sets/TimeSpiralTimeshifted.java +++ b/Mage.Sets/src/mage/sets/TimeSpiralTimeshifted.java @@ -96,6 +96,7 @@ public class TimeSpiralTimeshifted extends ExpansionSet { cards.add(new SetCardInfo("Goblin Snowman", 64, Rarity.UNCOMMON, mage.cards.g.GoblinSnowman.class)); cards.add(new SetCardInfo("Grinning Totem", 110, Rarity.SPECIAL, mage.cards.g.GrinningTotem.class)); cards.add(new SetCardInfo("Hail Storm", 79, Rarity.SPECIAL, mage.cards.h.HailStorm.class)); + cards.add(new SetCardInfo("Honorable Passage", 9, Rarity.SPECIAL, mage.cards.h.HonorablePassage.class)); cards.add(new SetCardInfo("Hunting Moa", 80, Rarity.COMMON, mage.cards.h.HuntingMoa.class)); cards.add(new SetCardInfo("Icatian Javelineers", 10, Rarity.SPECIAL, IcatianJavelineers.class)); cards.add(new SetCardInfo("Jasmine Boreal", 93, Rarity.COMMON, mage.cards.j.JasmineBoreal.class)); diff --git a/Mage.Sets/src/mage/sets/Unhinged.java b/Mage.Sets/src/mage/sets/Unhinged.java index 222281febe..b4e4aedb0d 100644 --- a/Mage.Sets/src/mage/sets/Unhinged.java +++ b/Mage.Sets/src/mage/sets/Unhinged.java @@ -20,10 +20,12 @@ public class Unhinged extends ExpansionSet { private Unhinged() { super("Unhinged", "UNH", ExpansionSet.buildDate(2004, 11, 20), SetType.JOKESET); + cards.add(new SetCardInfo("Forest", 140, Rarity.LAND, mage.cards.basiclands.Forest.class, new CardGraphicInfo(FrameStyle.UNH_FULL_ART_BASIC, false))); cards.add(new SetCardInfo("Island", 137, Rarity.LAND, mage.cards.basiclands.Island.class, new CardGraphicInfo(FrameStyle.UNH_FULL_ART_BASIC, false))); cards.add(new SetCardInfo("Johnny, Combo Player", 35, Rarity.RARE, mage.cards.j.JohnnyComboPlayer.class)); cards.add(new SetCardInfo("Mountain", 139, Rarity.LAND, mage.cards.basiclands.Mountain.class, new CardGraphicInfo(FrameStyle.UNH_FULL_ART_BASIC, false))); + cards.add(new SetCardInfo("Mox Lotus", 124, Rarity.RARE, mage.cards.m.MoxLotus.class)); cards.add(new SetCardInfo("Plains", 136, Rarity.LAND, mage.cards.basiclands.Plains.class, new CardGraphicInfo(FrameStyle.UNH_FULL_ART_BASIC, false))); cards.add(new SetCardInfo("Swamp", 138, Rarity.LAND, mage.cards.basiclands.Swamp.class, new CardGraphicInfo(FrameStyle.UNH_FULL_ART_BASIC, false))); } diff --git a/Mage.Sets/src/mage/sets/UnlimitedEdition.java b/Mage.Sets/src/mage/sets/UnlimitedEdition.java index c1213ef331..a27c910c64 100644 --- a/Mage.Sets/src/mage/sets/UnlimitedEdition.java +++ b/Mage.Sets/src/mage/sets/UnlimitedEdition.java @@ -44,6 +44,7 @@ public class UnlimitedEdition extends ExpansionSet { cards.add(new SetCardInfo("Black Lotus", 233, Rarity.RARE, mage.cards.b.BlackLotus.class)); cards.add(new SetCardInfo("Black Vise", 234, Rarity.UNCOMMON, mage.cards.b.BlackVise.class)); cards.add(new SetCardInfo("Black Ward", 189, Rarity.UNCOMMON, mage.cards.b.BlackWard.class)); + cards.add(new SetCardInfo("Blaze of Glory", 190, Rarity.RARE, mage.cards.b.BlazeOfGlory.class)); cards.add(new SetCardInfo("Blessing", 191, Rarity.RARE, mage.cards.b.Blessing.class)); cards.add(new SetCardInfo("Blue Elemental Blast", 50, Rarity.COMMON, mage.cards.b.BlueElementalBlast.class)); cards.add(new SetCardInfo("Blue Ward", 192, Rarity.UNCOMMON, mage.cards.b.BlueWard.class)); diff --git a/Mage.Sets/src/mage/sets/Visions.java b/Mage.Sets/src/mage/sets/Visions.java index b537d3b33d..e1458607a9 100644 --- a/Mage.Sets/src/mage/sets/Visions.java +++ b/Mage.Sets/src/mage/sets/Visions.java @@ -63,7 +63,7 @@ public class Visions extends ExpansionSet { cards.add(new SetCardInfo("Brass-Talon Chimera", 142, Rarity.UNCOMMON, mage.cards.b.BrassTalonChimera.class)); cards.add(new SetCardInfo("Breathstealer's Crypt", 127, Rarity.RARE, mage.cards.b.BreathstealersCrypt.class)); cards.add(new SetCardInfo("Breezekeeper", 27, Rarity.COMMON, mage.cards.b.Breezekeeper.class)); - cards.add(new SetCardInfo("Brood of Cockroaches", 3, Rarity.UNCOMMON, mage.cards.b.BroodOfCockroaches.class)); + cards.add(new SetCardInfo("Brood of Cockroaches", 3, Rarity.UNCOMMON, mage.cards.b.BroodOfCockroaches.class)); cards.add(new SetCardInfo("Bull Elephant", 51, Rarity.COMMON, mage.cards.b.BullElephant.class)); cards.add(new SetCardInfo("Chronatog", 28, Rarity.RARE, mage.cards.c.Chronatog.class)); cards.add(new SetCardInfo("City of Solitude", 52, Rarity.RARE, mage.cards.c.CityOfSolitude.class)); @@ -96,6 +96,7 @@ public class Visions extends ExpansionSet { cards.add(new SetCardInfo("Fireblast", 79, Rarity.COMMON, mage.cards.f.Fireblast.class)); cards.add(new SetCardInfo("Firestorm Hellkite", 130, Rarity.RARE, mage.cards.f.FirestormHellkite.class)); cards.add(new SetCardInfo("Flooded Shoreline", 32, Rarity.RARE, mage.cards.f.FloodedShoreline.class)); + cards.add(new SetCardInfo("Foreshadow", 33, Rarity.UNCOMMON, mage.cards.f.Foreshadow.class)); cards.add(new SetCardInfo("Freewind Falcon", 105, Rarity.COMMON, mage.cards.f.FreewindFalcon.class)); cards.add(new SetCardInfo("Funeral Charm", 11, Rarity.COMMON, mage.cards.f.FuneralCharm.class)); cards.add(new SetCardInfo("Giant Caterpillar", 58, Rarity.COMMON, mage.cards.g.GiantCaterpillar.class)); @@ -105,6 +106,7 @@ public class Visions extends ExpansionSet { cards.add(new SetCardInfo("Griffin Canyon", 163, Rarity.RARE, mage.cards.g.GriffinCanyon.class)); cards.add(new SetCardInfo("Hearth Charm", 82, Rarity.COMMON, mage.cards.h.HearthCharm.class)); cards.add(new SetCardInfo("Helm of Awakening", 145, Rarity.UNCOMMON, mage.cards.h.HelmOfAwakening.class)); + cards.add(new SetCardInfo("Honorable Passage", 107, Rarity.UNCOMMON, mage.cards.h.HonorablePassage.class)); cards.add(new SetCardInfo("Hope Charm", 108, Rarity.COMMON, mage.cards.h.HopeCharm.class)); cards.add(new SetCardInfo("Hulking Cyclops", 84, Rarity.UNCOMMON, mage.cards.h.HulkingCyclops.class)); cards.add(new SetCardInfo("Impulse", 34, Rarity.COMMON, mage.cards.i.Impulse.class)); @@ -199,6 +201,7 @@ public class Visions extends ExpansionSet { cards.add(new SetCardInfo("Warthog", 74, Rarity.COMMON, mage.cards.w.Warthog.class)); cards.add(new SetCardInfo("Waterspout Djinn", 50, Rarity.UNCOMMON, mage.cards.w.WaterspoutDjinn.class)); cards.add(new SetCardInfo("Wicked Reward", 25, Rarity.COMMON, mage.cards.w.WickedReward.class)); + cards.add(new SetCardInfo("Wind Shear", 75, Rarity.UNCOMMON, mage.cards.w.WindShear.class)); cards.add(new SetCardInfo("Zhalfirin Crusader", 125, Rarity.RARE, mage.cards.z.ZhalfirinCrusader.class)); } } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/enters/BloodMoonTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/enters/BloodMoonTest.java index 52b8740aac..d2844086f6 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/enters/BloodMoonTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/enters/BloodMoonTest.java @@ -5,10 +5,13 @@ */ package org.mage.test.cards.abilities.enters; +import mage.constants.CardType; import mage.constants.PhaseStep; +import mage.constants.SubType; import mage.constants.Zone; import mage.game.permanent.Permanent; import org.junit.Assert; +import org.junit.Ignore; import org.junit.Test; import org.mage.test.serverside.base.CardTestPlayerBase; @@ -90,7 +93,7 @@ public class BloodMoonTest extends CardTestPlayerBase { * Spreading Seas was played turn 3 in a Steam Vents, Blood Moon turn 7 or * something * - * The enchanted Steam Vents was producing only U when ir should produce + * The enchanted Steam Vents was producing only U when it should produce * only R because of blood moon's time stamp. * * http://blogs.magicjudges.org/articles/2013/06/18/blood-moon-in-a-modern-environment/ @@ -238,4 +241,167 @@ public class BloodMoonTest extends CardTestPlayerBase { Assert.assertTrue("The mana the land can produce should be [{R}] but it's " + playerA.getManaAvailable(currentGame).toString(), playerA.getManaAvailable(currentGame).toString().equals("[{R}]")); } + + /** + * If Blood Moon enters the battlefield with an animated Mutavault in play, + * the Mutavault stays a 2/2 creature with all creature types and “gains” + * the land type mountain (it can also tap for R). However, once the turn + * ends, the Mutavault will loses both of its abilities and become a non + * basic mountain named Mutavault. + */ + @Test + public void testBloodMoonMutavault() { + + addCard(Zone.BATTLEFIELD, playerA, "Swamp"); + + // {T}: Add {C} to your mana pool. + // {1}: Mutavault becomes a 2/2 creature with all creature types until end of turn. It's still a land. + addCard(Zone.BATTLEFIELD, playerA, "Mutavault", 1); + + // Blood Moon 2R + // Enchantment + // Nonbasic lands are Mountains + addCard(Zone.HAND, playerB, "Blood Moon", 1); + addCard(Zone.BATTLEFIELD, playerB, "Mountain", 3); + + activateAbility(2, PhaseStep.PRECOMBAT_MAIN, playerA, "{1}: "); + + castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerB, "Blood Moon"); + + setStopAt(2, PhaseStep.END_TURN); + + execute(); + + assertPermanentCount(playerB, "Blood Moon", 1); + assertPowerToughness(playerA, "Mutavault", 2, 2); + assertType("Mutavault", CardType.LAND, SubType.MOUNTAIN); + assertType("Swamp", CardType.LAND, SubType.SWAMP); + + Assert.assertTrue("The mana the land can produce should be [{R}] but it's " + playerA.getManaAvailable(currentGame).toString(), playerA.getManaAvailable(currentGame).toString().equals("[{R}]")); + } + + @Test + public void testBloodMoonMutavaultEnd() { + + addCard(Zone.BATTLEFIELD, playerA, "Swamp"); + + // {T}: Add {C} to your mana pool. + // {1}: Mutavault becomes a 2/2 creature with all creature types until end of turn. It's still a land. + addCard(Zone.BATTLEFIELD, playerA, "Mutavault", 1); + + // Blood Moon 2R + // Enchantment + // Nonbasic lands are Mountains + addCard(Zone.HAND, playerB, "Blood Moon", 1); + addCard(Zone.BATTLEFIELD, playerB, "Mountain", 3); + + activateAbility(2, PhaseStep.PRECOMBAT_MAIN, playerA, "{1}: "); + + castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerB, "Blood Moon"); + + setStopAt(3, PhaseStep.PRECOMBAT_MAIN); + + execute(); + + assertPermanentCount(playerB, "Blood Moon", 1); + assertPowerToughness(playerA, "Mutavault", 0, 0); + assertType("Mutavault", CardType.LAND, SubType.MOUNTAIN); + assertType("Swamp", CardType.LAND, SubType.SWAMP); + + Assert.assertTrue("The mana the lands can produce should be [{B}{R}] but it's " + playerA.getManaAvailable(currentGame).toString(), playerA.getManaAvailable(currentGame).toString().equals("[{B}{R}]")); + } + + /** + * If Blood Moon is on the battlefield, Flagstones of Trokair will enter the + * battlefield as a legendary non-basic Mountain. If Flagstones of Trokair + * is put into the graveyard due to “Legends rule” or because it was + * destroyed, its ability doesn’t trigger, because it doesn’t exist: it + * won’t fetch you a Plains. + */ + @Test + public void testBloodMoonFlagstonesOfTrokair() { + // {T}: Add {W} to your mana pool. + // When Flagstones of Trokair is put into a graveyard from the battlefield, you may search + // your library for a Plains card and put it onto the battlefield tapped. If you do, shuffle your library. + addCard(Zone.HAND, playerA, "Flagstones of Trokair", 1); + addCard(Zone.LIBRARY, playerA, "Plains"); + + // Blood Moon 2R + // Enchantment + // Nonbasic lands are Mountains + addCard(Zone.BATTLEFIELD, playerB, "Blood Moon"); + addCard(Zone.BATTLEFIELD, playerB, "Mountain", 3); + addCard(Zone.HAND, playerB, "Stone Rain"); + + playLand(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Flagstones of Trokair"); + castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerB, "Stone Rain", "Flagstones of Trokair"); + + setStopAt(2, PhaseStep.BEGIN_COMBAT); + + execute(); + + assertPermanentCount(playerB, "Blood Moon", 1); + assertGraveyardCount(playerB, "Stone Rain", 1); + + assertPermanentCount(playerA, "Flagstones of Trokair", 0); + assertGraveyardCount(playerA, "Flagstones of Trokair", 1); + + assertPermanentCount(playerA, 0); + } + + /** + * Because Blood Moon’s static ability operates only when it’s on the + * battlefield and begins affecting any nonbasic lands immediately. In fact, + * Blood Moon’s effect is so quick that once a non-basic land hits the + * battlefield it’s going to be affected. Therefore: + * + * If a nonbasic land’s has EtB triggered abilities, these will not trigger + * because the ability isn’t there (it’s gone). Effects that modify the way + * the land enters the battlefield are replacement effects. They are applied + * before the permanent enters the battlefield and taking into account + * continuous effects that already exist and would apply to the permanent. + * (see CR 614.12). + * + * 614.12 Some replacement effects modify how a permanent enters the + * battlefield. (See rules 614.1c-d.) Such effects may come from the + * permanent itself if they affect only that permanent (as opposed to a + * general subset of permanents that includes it). They may also come from + * other sources. To determine which replacement effects apply and how they + * apply, check the characteristics of the permanent as it would exist on + * the battlefield, taking into account replacement effects that have + * already modified how it enters the battlefield (see rule 616.1), + * continuous effects from the permanent's own static abilities that would + * apply to it once it's on the battlefield, and continuous effects that + * ..........................................=========================== + * already exist and would apply to the permanent. + * ================================================ + * + * Madblind Mountain enters the battlefield untapped, as a nonbasic Mountain + * with single mana ability and no other. + */ + @Test + @Ignore + public void testBloodMoonMadblindMountain() { + // {T}: Add {R} to your mana pool. + // Madblind Mountain enters the battlefield tapped. + // {R}, {tap}: Shuffle your library. Activate this ability only if you control two or more red permanents. + addCard(Zone.HAND, playerA, "Madblind Mountain", 1); + + // Blood Moon 2R + // Enchantment + // Nonbasic lands are Mountains + addCard(Zone.BATTLEFIELD, playerB, "Blood Moon"); + + playLand(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Madblind Mountain"); + + setStopAt(1, PhaseStep.BEGIN_COMBAT); + + execute(); + + assertPermanentCount(playerB, "Blood Moon", 1); + assertPermanentCount(playerA, "Madblind Mountain", 1); + + assertTapped("Madblind Mountain", false); // it may not be tapped because the etB effect was removed by Blood Moon + + } } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/asthough/SpendOtherManaTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/asthough/SpendOtherManaTest.java index a71cef7116..76d22a2f12 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/asthough/SpendOtherManaTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/asthough/SpendOtherManaTest.java @@ -134,4 +134,34 @@ public class SpendOtherManaTest extends CardTestPlayerBase { assertHandCount(playerA, "Nissa, Voice of Zendikar", 0); assertPermanentCount(playerA, "Nissa, Voice of Zendikar", 1); } + + @Test + public void testUseSpendManaAsThoughWithManaFromPool() { + addCard(Zone.BATTLEFIELD, playerA, "Swamp", 1); + addCard(Zone.BATTLEFIELD, playerA, "Island", 1); + addCard(Zone.BATTLEFIELD, playerA, "Mountain", 4); + + addCard(Zone.BATTLEFIELD, playerA, "Silvercoat Lion"); // Creature {1}{W} + + // When Hostage Taker enters the battlefield, exile another target artifact or creature until Hostage Taker leaves the battlefield. + // You may cast that card as long as it remains exiled, and you may spend mana as though it were mana of any type to cast that spell. + addCard(Zone.HAND, playerA, "Hostage Taker"); // {2}{U}{B} + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Hostage Taker"); + setChoice(playerA, "Silvercoat Lion"); + + activateManaAbility(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "{T}: Add {R} to your mana pool."); // red mana to pool + activateManaAbility(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "{T}: Add {R} to your mana pool."); // red mana to pool + castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Silvercoat Lion"); // cast it from exile with red mana from pool + + setStopAt(1, PhaseStep.END_TURN); + execute(); + + assertPermanentCount(playerA, "Hostage Taker", 1); + assertTappedCount("Mountain", true, 4); + + assertPermanentCount(playerA, "Silvercoat Lion", 1); + + } + } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/cost/splitcards/CastSplitCardsFromOtherZonesTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/cost/splitcards/CastSplitCardsFromOtherZonesTest.java index fcec6f5e2c..d6430520c3 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/cost/splitcards/CastSplitCardsFromOtherZonesTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/cost/splitcards/CastSplitCardsFromOtherZonesTest.java @@ -124,4 +124,35 @@ public class CastSplitCardsFromOtherZonesTest extends CardTestPlayerBase { assertGraveyardCount(playerB, "Icy Manipulator", 1); } + + /** + * Cast a split card half from exile + */ + @Test + public void testCastSpliHalfFromExile() { + // Fire Instant {1}{R} + // Fire deals 2 damage divided as you choose among one or two target creatures and/or players. + // Ice Instant {1}{U} + // Tap target permanent. + // Draw a card. + addCard(Zone.LIBRARY, playerA, "Fire // Ice", 1); + skipInitShuffling(); + addCard(Zone.BATTLEFIELD, playerA, "Silvercoat Lion"); // Creature 2/2 + + // Whenever Etali, Primal Storm attacks, exile the top card of each player's library, then you may + // cast any number of nonland cards exiled this way without paying their mana costs. + addCard(Zone.BATTLEFIELD, playerB, "Etali, Primal Storm"); // Creature {4}{R} 6/6 + + attack(2, playerB, "Etali, Primal Storm"); + setChoice(playerB, "Yes"); + setChoice(playerB, "Cast Fire"); + addTarget(playerB, "Silvercoat Lion"); + + setStopAt(2, PhaseStep.END_COMBAT); + execute(); + + assertLife(playerA, 14); + assertGraveyardCount(playerA, "Silvercoat Lion", 1); + assertGraveyardCount(playerA, "Fire // Ice", 1); + } } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/replacement/TorporOrbTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/replacement/TorporOrbTest.java index c8694f3540..36b5edb530 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/replacement/TorporOrbTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/replacement/TorporOrbTest.java @@ -41,7 +41,8 @@ public class TorporOrbTest extends CardTestPlayerBase { */ @Test public void testPitTweller() { - addCard(Zone.BATTLEFIELD, playerB, "Torpor Orb"); + // Creatures entering the battlefield don't cause abilities to trigger. + addCard(Zone.BATTLEFIELD, playerB, "Hushwing Gryff"); addCard(Zone.BATTLEFIELD, playerB, "Treacherous Pit-Dweller"); // 4/3 addCard(Zone.HAND, playerA, "Lightning Bolt"); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/lrw/CairnWandererTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/lrw/CairnWandererTest.java index 2f3e6851fe..6f96643b13 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/single/lrw/CairnWandererTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/lrw/CairnWandererTest.java @@ -80,28 +80,28 @@ public class CairnWandererTest extends CardTestPlayerBase { addCard(Zone.GRAVEYARD, playerA, "Typhoid Rats"); // Testing HasteAbility. - addCard(Zone.GRAVEYARD, playerA, "Raging Goblin"); + addCard(Zone.GRAVEYARD, playerB, "Raging Goblin"); // Testing LandwalkAbility. - addCard(Zone.GRAVEYARD, playerA, "Zodiac Rooster"); + addCard(Zone.GRAVEYARD, playerB, "Zodiac Rooster"); // Testing LifelinkAbility. - addCard(Zone.GRAVEYARD, playerA, "Trained Caracal"); + addCard(Zone.GRAVEYARD, playerB, "Trained Caracal"); // Testing ProtectionAbility. - addCard(Zone.GRAVEYARD, playerA, "Progenitus"); + addCard(Zone.GRAVEYARD, playerB, "Progenitus"); // Testing ReachAbility. - addCard(Zone.GRAVEYARD, playerA, "Tree Monkey"); + addCard(Zone.GRAVEYARD, playerB, "Tree Monkey"); // Testing TrampleAbility. - addCard(Zone.GRAVEYARD, playerA, "Defiant Elf"); + addCard(Zone.GRAVEYARD, playerB, "Defiant Elf"); // Testing ShroudAbility. - addCard(Zone.GRAVEYARD, playerA, "Elvish Lookout"); + addCard(Zone.GRAVEYARD, playerB, "Elvish Lookout"); // Testing VigilanceAbility. - addCard(Zone.GRAVEYARD, playerA, "Veteran Cavalier"); + addCard(Zone.GRAVEYARD, playerB, "Veteran Cavalier"); execute(); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/triggers/DefiantVanguardTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/triggers/DefiantVanguardTest.java new file mode 100644 index 0000000000..dc4b99e66f --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/triggers/DefiantVanguardTest.java @@ -0,0 +1,84 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package org.mage.test.cards.triggers; + +import mage.constants.PhaseStep; +import mage.constants.Zone; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * + * @author LevelX2 + */ +public class DefiantVanguardTest extends CardTestPlayerBase { + + @Test + public void testAllDestroyed() { + // When Defiant Vanguard blocks, at end of combat, destroy it and all creatures it blocked this turn. + // {5}, {tap}: Search your library for a Rebel permanent card with converted mana cost 4 or less and put it onto the battlefield. Then shuffle your library. + addCard(Zone.BATTLEFIELD, playerA, "Defiant Vanguard", 1); // Creature {2}{W} 2/2 + + addCard(Zone.BATTLEFIELD, playerB, "Bane Alley Blackguard", 1); // Creature {1}{B} 1/3 + + attack(2, playerB, "Bane Alley Blackguard"); + block(2, playerA, "Defiant Vanguard", "Bane Alley Blackguard"); + + setStopAt(2, PhaseStep.POSTCOMBAT_MAIN); + execute(); + + assertGraveyardCount(playerA, "Defiant Vanguard", 1); + assertGraveyardCount(playerB, "Bane Alley Blackguard", 1); + } + + @Test + public void testSaveCreatureWithCloudshift() { + // When Defiant Vanguard blocks, at end of combat, destroy it and all creatures it blocked this turn. + // {5}, {tap}: Search your library for a Rebel permanent card with converted mana cost 4 or less and put it onto the battlefield. Then shuffle your library. + addCard(Zone.BATTLEFIELD, playerA, "Defiant Vanguard", 1); // Creature {2}{W} 2/2 + + addCard(Zone.BATTLEFIELD, playerB, "Bane Alley Blackguard", 1); // Creature {1}{B} 1/3 + addCard(Zone.BATTLEFIELD, playerB, "Plains", 1); + // Exile target creature you control, then return that card to the battlefield under your control. + addCard(Zone.HAND, playerB, "Cloudshift", 1); // Instant {W} + + attack(2, playerB, "Bane Alley Blackguard"); + block(2, playerA, "Defiant Vanguard", "Bane Alley Blackguard"); + + castSpell(2, PhaseStep.END_COMBAT, playerB, "Cloudshift", "Bane Alley Blackguard", "At end of combat, destroy it and all creatures it blocked this turn."); + + setStopAt(2, PhaseStep.POSTCOMBAT_MAIN); + execute(); + + assertGraveyardCount(playerA, "Defiant Vanguard", 1); + assertGraveyardCount(playerB, "Cloudshift", 1); + assertPermanentCount(playerB, "Bane Alley Blackguard", 1); + + } + +} diff --git a/Mage.Tests/src/test/java/org/mage/test/player/TestPlayer.java b/Mage.Tests/src/test/java/org/mage/test/player/TestPlayer.java index 417fc5a46d..41d0c95c6d 100644 --- a/Mage.Tests/src/test/java/org/mage/test/player/TestPlayer.java +++ b/Mage.Tests/src/test/java/org/mage/test/player/TestPlayer.java @@ -740,7 +740,7 @@ public class TestPlayer implements Player { @Override public boolean choose(Outcome outcome, Choice choice, Game game) { if (!choices.isEmpty()) { - if(choice.setChoiceByAnswers(choices, true)){ + if (choice.setChoiceByAnswers(choices, true)) { return true; } } @@ -2167,6 +2167,24 @@ public class TestPlayer implements Player { @Override public SpellAbility chooseSpellAbilityForCast(SpellAbility ability, Game game, boolean noMana) { + switch (ability.getSpellAbilityType()) { + case SPLIT: + case SPLIT_FUSED: + case SPLIT_AFTERMATH: + if (!choices.isEmpty()) { + MageObject object = game.getObject(ability.getSourceId()); + if (object != null) { + LinkedHashMap useableAbilities = computerPlayer.getSpellAbilities(object, game.getState().getZone(object.getId()), game); + for (String choose : choices) { + for (ActivatedAbility actiavtedAbility : useableAbilities.values()) { + if (actiavtedAbility.getRule().startsWith(choose)) { + return (SpellAbility) actiavtedAbility; + } + } + } + } + } + } return computerPlayer.chooseSpellAbilityForCast(ability, game, noMana); } @@ -2176,13 +2194,17 @@ public class TestPlayer implements Player { } @Override - public boolean choose(Outcome outcome, Target target, UUID sourceId, Game game) { + public boolean choose(Outcome outcome, Target target, + UUID sourceId, Game game + ) { // needed to call here the TestPlayer because it's overwitten return choose(outcome, target, sourceId, game, null); } @Override - public boolean choose(Outcome outcome, Cards cards, TargetCard target, Game game) { + public boolean choose(Outcome outcome, Cards cards, + TargetCard target, Game game + ) { if (!choices.isEmpty()) { for (String choose2 : choices) { // TODO: More targetting to fix @@ -2212,58 +2234,78 @@ public class TestPlayer implements Player { } @Override - public boolean chooseTargetAmount(Outcome outcome, TargetAmount target, Ability source, Game game) { + public boolean chooseTargetAmount(Outcome outcome, TargetAmount target, + Ability source, Game game + ) { return computerPlayer.chooseTargetAmount(outcome, target, source, game); } @Override - public boolean chooseMulligan(Game game) { + public boolean chooseMulligan(Game game + ) { return computerPlayer.chooseMulligan(game); } @Override - public boolean choosePile(Outcome outcome, String message, List pile1, List pile2, Game game) { + public boolean choosePile(Outcome outcome, String message, + List pile1, List pile2, + Game game + ) { return computerPlayer.choosePile(outcome, message, pile1, pile2, game); } @Override - public boolean playMana(Ability ability, ManaCost unpaid, String promptText, Game game) { + public boolean playMana(Ability ability, ManaCost unpaid, + String promptText, Game game + ) { groupsForTargetHandling = null; return computerPlayer.playMana(ability, unpaid, promptText, game); } @Override - public UUID chooseAttackerOrder(List attacker, Game game) { + public UUID chooseAttackerOrder(List attacker, Game game + ) { return computerPlayer.chooseAttackerOrder(attacker, game); } @Override - public UUID chooseBlockerOrder(List blockers, CombatGroup combatGroup, List blockerOrder, Game game) { + public UUID chooseBlockerOrder(List blockers, CombatGroup combatGroup, + List blockerOrder, Game game + ) { return computerPlayer.chooseBlockerOrder(blockers, combatGroup, blockerOrder, game); } @Override - public void assignDamage(int damage, List targets, String singleTargetName, UUID sourceId, Game game) { + public void assignDamage(int damage, List targets, + String singleTargetName, UUID sourceId, + Game game + ) { computerPlayer.assignDamage(damage, targets, singleTargetName, sourceId, game); } @Override - public void sideboard(Match match, Deck deck) { + public void sideboard(Match match, Deck deck + ) { computerPlayer.sideboard(match, deck); } @Override - public void construct(Tournament tournament, Deck deck) { + public void construct(Tournament tournament, Deck deck + ) { computerPlayer.construct(tournament, deck); } @Override - public void pickCard(List cards, Deck deck, Draft draft) { + public void pickCard(List cards, Deck deck, + Draft draft + ) { computerPlayer.pickCard(cards, deck, draft); } @Override - public boolean scry(int value, Ability source, Game game) { + public boolean scry(int value, Ability source, + Game game + ) { // Don't scry at the start of the game. if (game.getTurnNum() == 1 && game.getStep() == null) { return false; @@ -2272,37 +2314,51 @@ public class TestPlayer implements Player { } @Override - public boolean moveCards(Card card, Zone toZone, Ability source, Game game) { + public boolean moveCards(Card card, Zone toZone, + Ability source, Game game + ) { return computerPlayer.moveCards(card, toZone, source, game); } @Override - public boolean moveCards(Card card, Zone toZone, Ability source, Game game, boolean tapped, boolean faceDown, boolean byOwner, List appliedEffects) { + public boolean moveCards(Card card, Zone toZone, + Ability source, Game game, + boolean tapped, boolean faceDown, boolean byOwner, List appliedEffects + ) { return computerPlayer.moveCards(card, toZone, source, game, tapped, faceDown, byOwner, appliedEffects); } @Override - public boolean moveCards(Cards cards, Zone toZone, Ability source, Game game) { + public boolean moveCards(Cards cards, Zone toZone, + Ability source, Game game + ) { return computerPlayer.moveCards(cards, toZone, source, game); } @Override - public boolean moveCards(Set cards, Zone toZone, Ability source, Game game) { + public boolean moveCards(Set cards, Zone toZone, + Ability source, Game game + ) { return computerPlayer.moveCards(cards, toZone, source, game); } @Override - public boolean moveCards(Set cards, Zone toZone, Ability source, Game game, boolean tapped, boolean faceDown, boolean byOwner, List appliedEffects) { + public boolean moveCards(Set cards, Zone toZone, + Ability source, Game game, + boolean tapped, boolean faceDown, boolean byOwner, List appliedEffects + ) { return computerPlayer.moveCards(cards, toZone, source, game, tapped, faceDown, byOwner, appliedEffects); } @Override - public boolean hasDesignation(DesignationType designationName) { + public boolean hasDesignation(DesignationType designationName + ) { return computerPlayer.hasDesignation(designationName); } @Override - public void addDesignation(Designation designation) { + public void addDesignation(Designation designation + ) { computerPlayer.addDesignation(designation); } diff --git a/Mage.Updater/src/main/java/com/magefree/update/Updater.java b/Mage.Updater/src/main/java/com/magefree/update/Updater.java index ed39bc80b9..fdceb24444 100644 --- a/Mage.Updater/src/main/java/com/magefree/update/Updater.java +++ b/Mage.Updater/src/main/java/com/magefree/update/Updater.java @@ -1,6 +1,6 @@ package com.magefree.update; -import com.magefree.update.helpers.ChechsumHelper; +import com.magefree.update.helpers.ChecksumHelper; import com.magefree.update.helpers.FileHelper; import java.io.File; @@ -67,7 +67,7 @@ public class Updater { public HashMap readLocalData() throws Exception { HashMap result = new HashMap<>(); for (File f : findFiles()) { - result.put(f.getPath().replaceAll("\\\\", "/"), ChechsumHelper.getSHA1Checksum(f.getPath())); + result.put(f.getPath().replaceAll("\\\\", "/"), ChecksumHelper.getSHA1Checksum(f.getPath())); } return result; } diff --git a/Mage.Updater/src/main/java/com/magefree/update/helpers/ChechsumHelper.java b/Mage.Updater/src/main/java/com/magefree/update/helpers/ChecksumHelper.java similarity index 97% rename from Mage.Updater/src/main/java/com/magefree/update/helpers/ChechsumHelper.java rename to Mage.Updater/src/main/java/com/magefree/update/helpers/ChecksumHelper.java index c4d035eeed..c815ede0db 100644 --- a/Mage.Updater/src/main/java/com/magefree/update/helpers/ChechsumHelper.java +++ b/Mage.Updater/src/main/java/com/magefree/update/helpers/ChecksumHelper.java @@ -7,7 +7,7 @@ import java.security.MessageDigest; /** * @author Loki */ -public final class ChechsumHelper { +public final class ChecksumHelper { public static byte[] createChecksum(String filename) throws Exception { InputStream fis = null; diff --git a/Mage/src/main/java/mage/MageObjectReference.java b/Mage/src/main/java/mage/MageObjectReference.java index 0c4cde8808..9fd237f7c8 100644 --- a/Mage/src/main/java/mage/MageObjectReference.java +++ b/Mage/src/main/java/mage/MageObjectReference.java @@ -47,7 +47,7 @@ public class MageObjectReference implements Comparable, Ser private static final Logger logger = Logger.getLogger(MageObjectReference.class); private final UUID sourceId; - private int zoneChangeCounter; + private final int zoneChangeCounter; public MageObjectReference(MageObject mageObject, Game game) { this.sourceId = mageObject.getId(); @@ -167,8 +167,4 @@ public class MageObjectReference implements Comparable, Ser } return null; } - - public void setZoneChangeCounter(int zoneChangeCounter) { - this.zoneChangeCounter = zoneChangeCounter; - } } diff --git a/Mage/src/main/java/mage/Mana.java b/Mage/src/main/java/mage/Mana.java index b2461d2b36..32e57e8d45 100644 --- a/Mage/src/main/java/mage/Mana.java +++ b/Mage/src/main/java/mage/Mana.java @@ -131,6 +131,35 @@ public class Mana implements Comparable, Serializable, Copyable { } } + public Mana(final ManaType manaType) { + Objects.requireNonNull(manaType, "The passed in ManaType can not be null"); + switch (manaType) { + case GREEN: + green = 1; + break; + case RED: + red = 1; + break; + case BLACK: + black = 1; + break; + case BLUE: + blue = 1; + break; + case WHITE: + white = 1; + break; + case COLORLESS: + colorless = 1; + break; + case GENERIC: + generic = 1; + break; + default: + throw new IllegalArgumentException("Unknown manaType: " + manaType); + } + } + /** * Creates a {@link Mana} object with the passed in {@code num} of Red mana. * {@code num} can not be a negative value. Negative values will be logged @@ -222,13 +251,12 @@ public class Mana implements Comparable, Serializable, Copyable { } /** - * Creates a {@link Mana} object with the passed in {@code num} of Any - * mana. {@code num} can not be a negative value. Negative values will be - * logged and set to 0. + * Creates a {@link Mana} object with the passed in {@code num} of Any mana. + * {@code num} can not be a negative value. Negative values will be logged + * and set to 0. * * @param num value of Any mana to create. - * @return a {@link Mana} object with the passed in {@code num} of Any - * mana. + * @return a {@link Mana} object with the passed in {@code num} of Any mana. */ public static Mana AnyMana(int num) { return new Mana(0, 0, 0, 0, 0, 0, notNegative(num, "Any"), 0); @@ -490,25 +518,46 @@ public class Mana implements Comparable, Serializable, Copyable { if (generic > 0) { sbMana.append('{').append(Integer.toString(generic)).append('}'); } - for (int i = 0; i < colorless; i++) { + if (colorless >= 20) { + sbMana.append(Integer.toString(colorless)).append("{C}"); + } + if (white >= 20) { + sbMana.append(Integer.toString(white)).append("{W}"); + } + if (blue >= 20) { + sbMana.append(Integer.toString(blue)).append("{U}"); + } + if (black >= 20) { + sbMana.append(Integer.toString(black)).append("{B}"); + } + if (red >= 20) { + sbMana.append(Integer.toString(red)).append("{R}"); + } + if (green >= 20) { + sbMana.append(Integer.toString(green)).append("{G}"); + } + if (any >= 20) { + sbMana.append(Integer.toString(any)).append("{Any}"); + } + for (int i = 0; i < colorless && colorless < 20; i++) { sbMana.append("{C}"); } - for (int i = 0; i < white; i++) { + for (int i = 0; i < white && white < 20; i++) { sbMana.append("{W}"); } - for (int i = 0; i < blue; i++) { + for (int i = 0; i < blue && blue < 20; i++) { sbMana.append("{U}"); } - for (int i = 0; i < black; i++) { + for (int i = 0; i < black && black < 20; i++) { sbMana.append("{B}"); } - for (int i = 0; i < red; i++) { + for (int i = 0; i < red && red < 20; i++) { sbMana.append("{R}"); } - for (int i = 0; i < green; i++) { + for (int i = 0; i < green && green < 20; i++) { sbMana.append("{G}"); } - for (int i = 0; i < any; i++) { + for (int i = 0; i < any && any < 20; i++) { sbMana.append("{Any}"); } return sbMana.toString(); diff --git a/Mage/src/main/java/mage/abilities/Ability.java b/Mage/src/main/java/mage/abilities/Ability.java index d6baff95d4..d0a8f783aa 100644 --- a/Mage/src/main/java/mage/abilities/Ability.java +++ b/Mage/src/main/java/mage/abilities/Ability.java @@ -45,6 +45,7 @@ import mage.constants.Zone; import mage.game.Controllable; import mage.game.Game; import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.Target; import mage.target.Targets; @@ -535,6 +536,17 @@ public interface Ability extends Controllable, Serializable { */ MageObject getSourceObjectIfItStillExists(Game game); + /** + * Returns the permanent that actually existed while the ability triggerd or + * an ability was activated only if it has not changed zone meanwhile. If + * not set yet, the current permanent if one exists will be retrieved from + * the game and returned. + * + * @param game + * @return + */ + Permanent getSourcePermanentIfItStillExists(Game game); + String getTargetDescription(Targets targets, Game game); void setCanFizzle(boolean canFizzle); diff --git a/Mage/src/main/java/mage/abilities/AbilityImpl.java b/Mage/src/main/java/mage/abilities/AbilityImpl.java index 23f8176212..25528d242b 100644 --- a/Mage/src/main/java/mage/abilities/AbilityImpl.java +++ b/Mage/src/main/java/mage/abilities/AbilityImpl.java @@ -1211,6 +1211,19 @@ public abstract class AbilityImpl implements Ability { return null; } + @Override + public Permanent getSourcePermanentIfItStillExists(Game game) { + if (sourceObject == null) { + setSourceObject(game.getObject(getSourceId()), game); + } + if (sourceObject instanceof Permanent) { + if (game.getState().getZoneChangeCounter(getSourceId()) == getSourceObjectZoneChangeCounter()) { + return (Permanent) sourceObject; + } + } + return null; + } + @Override public int getSourceObjectZoneChangeCounter() { return sourceObjectZoneChangeCounter; diff --git a/Mage/src/main/java/mage/abilities/TriggeredAbility.java b/Mage/src/main/java/mage/abilities/TriggeredAbility.java index 638079c1e3..93ca77a32c 100644 --- a/Mage/src/main/java/mage/abilities/TriggeredAbility.java +++ b/Mage/src/main/java/mage/abilities/TriggeredAbility.java @@ -50,6 +50,17 @@ public interface TriggeredAbility extends Ability { */ boolean checkEventType(GameEvent event, Game game); + /** + * This method checks if the event has to trigger the ability. It's + * important to do nothing unique within this method, that can't be done + * multiple times. Because some abilities call this to check if an ability + * is relevant (e.g. Torpor Orb), so the method is calle dmultiple times for + * the same event. + * + * @param event + * @param game + * @return + */ boolean checkTrigger(GameEvent event, Game game); boolean checkInterveningIfClause(Game game); diff --git a/Mage/src/main/java/mage/abilities/costs/common/PutCardFromHandOnTopOfLibraryCost.java b/Mage/src/main/java/mage/abilities/costs/common/PutCardFromHandOnTopOfLibraryCost.java new file mode 100644 index 0000000000..44fa2a8a5e --- /dev/null +++ b/Mage/src/main/java/mage/abilities/costs/common/PutCardFromHandOnTopOfLibraryCost.java @@ -0,0 +1,60 @@ +/* + * 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 mage.abilities.costs.common; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.costs.Cost; +import mage.abilities.costs.CostImpl; +import mage.cards.Card; +import mage.constants.Outcome; +import mage.constants.Zone; +import mage.game.Game; +import mage.players.Player; +import mage.target.common.TargetCardInHand; + +/** + * + * @author jeffwadsworth + */ + +public class PutCardFromHandOnTopOfLibraryCost extends CostImpl { + + public PutCardFromHandOnTopOfLibraryCost() { + this.text = "Put a card from your hand on top of your library"; + } + + public PutCardFromHandOnTopOfLibraryCost(PutCardFromHandOnTopOfLibraryCost cost) { + super(cost); + } + + @Override + public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana, Cost costToPay) { + Player controller = game.getPlayer(controllerId); + TargetCardInHand targetCardInHand = new TargetCardInHand(); + targetCardInHand.setRequired(false); + Card card; + if (targetCardInHand.canChoose(controllerId, game) + && controller.choose(Outcome.PreventDamage, targetCardInHand, sourceId, game)) { + card = game.getCard(targetCardInHand.getFirstTarget()); + paid = controller.moveCardToLibraryWithInfo(card, sourceId, game, Zone.HAND, true, true); + } + return paid; + } + + @Override + public boolean canPay(Ability ability, UUID sourceId, UUID controllerId, Game game) { + Player controller = game.getPlayer(controllerId); + return (controller != null + && !controller.getHand().isEmpty()); + } + + @Override + public PutCardFromHandOnTopOfLibraryCost copy() { + return new PutCardFromHandOnTopOfLibraryCost(this); + } +} + diff --git a/Mage/src/main/java/mage/abilities/costs/common/TapTargetCost.java b/Mage/src/main/java/mage/abilities/costs/common/TapTargetCost.java index ef095d353c..82ed1c371f 100644 --- a/Mage/src/main/java/mage/abilities/costs/common/TapTargetCost.java +++ b/Mage/src/main/java/mage/abilities/costs/common/TapTargetCost.java @@ -78,6 +78,10 @@ public class TapTargetCost extends CostImpl { public boolean canPay(Ability ability, UUID sourceId, UUID controllerId, Game game) { return target.canChoose(sourceId, controllerId, game); } + + public TargetControlledPermanent getTarget() { + return target; + } @Override public TapTargetCost copy() { diff --git a/Mage/src/main/java/mage/abilities/effects/Effect.java b/Mage/src/main/java/mage/abilities/effects/Effect.java index fc98f40a94..cc7d51c7b3 100644 --- a/Mage/src/main/java/mage/abilities/effects/Effect.java +++ b/Mage/src/main/java/mage/abilities/effects/Effect.java @@ -46,12 +46,34 @@ public interface Effect extends Serializable { void newId(); + /** + * Some general behaviours for rule text handling: Rule text of effects get + * automatically a full stop "." at the end, if not another effect e.g. with + * a starting "and" follows. So at least for effects of the framework, that + * are used from multiple cards, it's better to set no full stop at the end + * of the rule text of an effect. Also the starting letter of an effect is + * automatically converted to upper case if the rule text starts with this + * text. So There is no need to let the effect text start with upper case, + * even if extracted from a filter message. Also here it's important to use + * only lower cases for effects located in the framework, so if used for a + * triggered abilitiy, the effect text needs to start with lower case after + * the comma. + * + * @param mode the selected mode of the ability (mostly there is only one) + * @return + */ String getText(Mode mode); Effect setText(String staticText); boolean apply(Game game, Ability source); + /** + * The outcome is used for the AI to decide if an effect does bad or good to + * the targets. + * + * @return + */ Outcome getOutcome(); void setOutcome(Outcome outcome); diff --git a/Mage/src/main/java/mage/abilities/effects/common/CantBeRegeneratedTargetEffect.java b/Mage/src/main/java/mage/abilities/effects/common/CantBeRegeneratedTargetEffect.java index a0219501fb..d844803f73 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/CantBeRegeneratedTargetEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/CantBeRegeneratedTargetEffect.java @@ -81,7 +81,6 @@ public class CantBeRegeneratedTargetEffect extends ContinuousRuleModifyingEffect } sb.append(" can't be regenerated"); if (!duration.toString().isEmpty()) { - sb.append(' '); if (duration == Duration.EndOfTurn) { sb.append(" this turn"); } else { diff --git a/Mage/src/main/java/mage/abilities/effects/common/CreateTokenCopyTargetEffect.java b/Mage/src/main/java/mage/abilities/effects/common/CreateTokenCopyTargetEffect.java index 993422a0d4..6bb2ce18c5 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/CreateTokenCopyTargetEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/CreateTokenCopyTargetEffect.java @@ -286,7 +286,7 @@ public class CreateTokenCopyTargetEffect extends OneShotEffect { sb.append("tokens that are copies of target "); } if (!mode.getTargets().isEmpty()) { - sb.append(mode.getTargets().get(0).getMessage()); + sb.append(mode.getTargets().get(0).getTargetName()); } else { throw new UnsupportedOperationException("Using default rule generation of target effect without having a target object"); } diff --git a/Mage/src/main/java/mage/abilities/effects/common/DetainAllEffect.java b/Mage/src/main/java/mage/abilities/effects/common/DetainAllEffect.java index 56005a8775..774304b6ea 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/DetainAllEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/DetainAllEffect.java @@ -24,19 +24,17 @@ * The views and conclusions contained in the software and documentation are those of the * authors and should not be interpreted as representing official policies, either expressed * or implied, of BetaSteward_at_googlemail.com. -*/ - + */ package mage.abilities.effects.common; import java.util.ArrayList; import java.util.List; import java.util.UUID; - -import mage.constants.Outcome; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.RestrictionEffect; import mage.constants.Duration; +import mage.constants.Outcome; import mage.constants.PhaseStep; import mage.filter.FilterPermanent; import mage.game.Game; @@ -48,7 +46,6 @@ import mage.target.targetpointer.FixedTarget; * * @author LevelX2 */ - public class DetainAllEffect extends OneShotEffect { private FilterPermanent filter = new FilterPermanent(); @@ -56,7 +53,7 @@ public class DetainAllEffect extends OneShotEffect { public DetainAllEffect(FilterPermanent filter) { super(Outcome.Benefit); this.filter = filter; - this.staticText = new StringBuilder("detain ").append(filter.getMessage()).toString(); + this.staticText = "detain " + filter.getMessage(); } public DetainAllEffect(final DetainAllEffect effect) { @@ -73,10 +70,10 @@ public class DetainAllEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { List detainedObjects = new ArrayList<>(); for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game)) { - if (!game.isSimulation()) + if (!game.isSimulation()) { game.informPlayers("Detained permanent: " + permanent.getName()); - FixedTarget fixedTarget = new FixedTarget(permanent.getId()); - fixedTarget.init(game, source); + } + FixedTarget fixedTarget = new FixedTarget(permanent, game); detainedObjects.add(fixedTarget); } @@ -103,23 +100,22 @@ class DetainAllRestrictionEffect extends RestrictionEffect { @Override public void init(Ability source, Game game) { super.init(source, game); - for(FixedTarget fixedTarget :this.detainedObjects) { + for (FixedTarget fixedTarget : this.detainedObjects) { Permanent permanent = game.getPermanent(fixedTarget.getFirst(game, source)); if (permanent != null) { - permanent.addInfo(new StringBuilder("detain").append(getId()).toString(),"[Detained]", game); + permanent.addInfo(new StringBuilder("detain").append(getId()).toString(), "[Detained]", game); } } } @Override public boolean isInactive(Ability source, Game game) { - if (game.getPhase().getStep().getType() == PhaseStep.UNTAP && game.getStep().getStepPart() == Step.StepPart.PRE) - { + if (game.getPhase().getStep().getType() == PhaseStep.UNTAP && game.getStep().getStepPart() == Step.StepPart.PRE) { if (game.getActivePlayerId().equals(source.getControllerId()) || game.getPlayer(source.getControllerId()).hasReachedNextTurnAfterLeaving()) { - for(FixedTarget fixedTarget :this.detainedObjects) { + for (FixedTarget fixedTarget : this.detainedObjects) { Permanent permanent = game.getPermanent(fixedTarget.getFirst(game, source)); if (permanent != null) { - permanent.addInfo(new StringBuilder("detain").append(getId()).toString(),"", game); + permanent.addInfo(new StringBuilder("detain").append(getId()).toString(), "", game); } } return true; @@ -130,7 +126,7 @@ class DetainAllRestrictionEffect extends RestrictionEffect { @Override public boolean applies(Permanent permanent, Ability source, Game game) { - for(FixedTarget fixedTarget :this.detainedObjects) { + for (FixedTarget fixedTarget : this.detainedObjects) { UUID targetId = fixedTarget.getFirst(game, source); if (targetId != null && targetId.equals(permanent.getId())) { return true; @@ -148,7 +144,7 @@ class DetainAllRestrictionEffect extends RestrictionEffect { public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game) { return false; } - + @Override public boolean canUseActivatedAbilities(Permanent permanent, Ability source, Game game) { return false; diff --git a/Mage/src/main/java/mage/abilities/effects/common/DiscardsACardPlayerTriggeredAbility.java b/Mage/src/main/java/mage/abilities/effects/common/DiscardsACardPlayerTriggeredAbility.java new file mode 100644 index 0000000000..5c4ac7641c --- /dev/null +++ b/Mage/src/main/java/mage/abilities/effects/common/DiscardsACardPlayerTriggeredAbility.java @@ -0,0 +1,57 @@ +/* + * 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 mage.abilities.effects.common; + +import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.effects.Effect; +import mage.constants.SetTargetPointer; +import mage.constants.Zone; +import mage.game.Game; +import mage.game.events.GameEvent; + +/** + * + * @author jeffwadsworth + */ + + public class DiscardsACardPlayerTriggeredAbility extends TriggeredAbilityImpl { + + private SetTargetPointer setTargetPointer; + + public DiscardsACardPlayerTriggeredAbility(Effect effect, boolean isOptional) { + this(effect, isOptional, SetTargetPointer.NONE); + } + + public DiscardsACardPlayerTriggeredAbility(Effect effect, boolean isOptional, SetTargetPointer setTargetPointer) { + super(Zone.BATTLEFIELD, effect, isOptional); + this.setTargetPointer = setTargetPointer; + } + + public DiscardsACardPlayerTriggeredAbility(final DiscardsACardPlayerTriggeredAbility ability) { + super(ability); + this.setTargetPointer = ability.setTargetPointer; + } + + @Override + public DiscardsACardPlayerTriggeredAbility copy() { + return new DiscardsACardPlayerTriggeredAbility(this); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.DISCARDED_CARD; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + return true; + } + + @Override + public String getRule() { + return "Whenever player discards a card, " + super.getRule(); + } +} \ No newline at end of file diff --git a/Mage/src/main/java/mage/abilities/effects/common/PreventDamageByTargetEffect.java b/Mage/src/main/java/mage/abilities/effects/common/PreventDamageByTargetEffect.java index e26affa441..081cd81b8c 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/PreventDamageByTargetEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/PreventDamageByTargetEffect.java @@ -96,7 +96,7 @@ public class PreventDamageByTargetEffect extends PreventionEffectImpl { StringBuilder sb = new StringBuilder(); sb.append("Prevent all"); if (onlyCombat) { - sb.append(" combat "); + sb.append(" combat"); } sb.append(" damage target "); sb.append(mode.getTargets().get(0).getTargetName()).append(" would deal ").append(duration.toString()); diff --git a/Mage/src/main/java/mage/abilities/effects/common/PreventNextDamageFromChosenSourceToYouEffect.java b/Mage/src/main/java/mage/abilities/effects/common/PreventNextDamageFromChosenSourceToYouEffect.java index 6164d9c2de..86f10acf76 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/PreventNextDamageFromChosenSourceToYouEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/PreventNextDamageFromChosenSourceToYouEffect.java @@ -71,7 +71,7 @@ public class PreventNextDamageFromChosenSourceToYouEffect extends PreventionEffe StringBuilder sb = new StringBuilder("The next time a ").append(targetSource.getFilter().getMessage()); sb.append(" of your choice would deal damage to you"); if (duration == Duration.EndOfTurn) { - sb.append(" this turn"); + sb.append(" this turn"); } sb.append(", prevent that damage"); return sb.toString(); diff --git a/Mage/src/main/java/mage/abilities/effects/common/PutTopCardOfLibraryIntoGraveEachPlayerEffect.java b/Mage/src/main/java/mage/abilities/effects/common/PutTopCardOfLibraryIntoGraveEachPlayerEffect.java index 77ebb1377d..0a378703ab 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/PutTopCardOfLibraryIntoGraveEachPlayerEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/PutTopCardOfLibraryIntoGraveEachPlayerEffect.java @@ -123,9 +123,12 @@ public class PutTopCardOfLibraryIntoGraveEachPlayerEffect extends OneShotEffect throw new UnsupportedOperationException("TargetController type not supported."); } sb.append("puts the top "); - sb.append(CardUtil.numberToText(numberCards.toString(), "a")); - sb.append(" card"); - sb.append(numberCards.toString().equals("1") ? "" : "s"); + if(numberCards.toString().equals("1")) { + sb.append("card"); + } else { + sb.append(CardUtil.numberToText(numberCards.toString())); + sb.append(" cards"); + } sb.append(" of his or her library into his or her graveyard"); return sb.toString(); } diff --git a/Mage/src/main/java/mage/abilities/effects/common/RegenerateAllEffect.java b/Mage/src/main/java/mage/abilities/effects/common/RegenerateAllEffect.java index f224789f66..2482ff947f 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/RegenerateAllEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/RegenerateAllEffect.java @@ -63,7 +63,7 @@ public class RegenerateAllEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game)) { RegenerateTargetEffect regenEffect = new RegenerateTargetEffect(); - regenEffect.setTargetPointer(new FixedTarget(permanent.getId())); + regenEffect.setTargetPointer(new FixedTarget(permanent, game)); game.addEffect(regenEffect, source); } return true; diff --git a/Mage/src/main/java/mage/abilities/effects/common/TapAllTargetPlayerControlsEffect.java b/Mage/src/main/java/mage/abilities/effects/common/TapAllTargetPlayerControlsEffect.java index 08ca0c506f..ac2bee4e1d 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/TapAllTargetPlayerControlsEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/TapAllTargetPlayerControlsEffect.java @@ -80,6 +80,6 @@ public class TapAllTargetPlayerControlsEffect extends OneShotEffect { if (staticText != null && !staticText.isEmpty()) { return staticText; } - return "tap all " + filter.toString() + " target " + mode.getTargets().get(0).getMessage() + " controls"; + return "tap all " + filter.toString() + " target " + mode.getTargets().get(0).getTargetName() + " controls"; } } diff --git a/Mage/src/main/java/mage/abilities/effects/common/combat/CantBeBlockedByCreaturesAllEffect.java b/Mage/src/main/java/mage/abilities/effects/common/combat/CantBeBlockedByCreaturesAllEffect.java index fa528cfcdf..11dfb626a5 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/combat/CantBeBlockedByCreaturesAllEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/combat/CantBeBlockedByCreaturesAllEffect.java @@ -45,7 +45,7 @@ public class CantBeBlockedByCreaturesAllEffect extends RestrictionEffect { private final FilterCreaturePermanent filterCreatures; public CantBeBlockedByCreaturesAllEffect(FilterCreaturePermanent filterCreatures, FilterCreaturePermanent filterBlockedBy, Duration duration) { - super(Duration.WhileOnBattlefield); + super(duration); this.filterCreatures = filterCreatures; this.filterBlockedBy = filterBlockedBy; staticText = new StringBuilder(filterCreatures.getMessage()).append(" can't be blocked ") diff --git a/Mage/src/main/java/mage/abilities/effects/common/continuous/BecomesChosenCreatureTypeSourceEffect.java b/Mage/src/main/java/mage/abilities/effects/common/continuous/BecomesChosenCreatureTypeSourceEffect.java index 56d90e8f21..4ee8f6462e 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/continuous/BecomesChosenCreatureTypeSourceEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/continuous/BecomesChosenCreatureTypeSourceEffect.java @@ -3,6 +3,7 @@ package mage.abilities.effects.common.continuous; import mage.abilities.Ability; import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; +import mage.constants.Duration; import mage.constants.Outcome; import mage.game.Game; import mage.game.permanent.Permanent; @@ -10,17 +11,28 @@ import mage.target.targetpointer.FixedTarget; public class BecomesChosenCreatureTypeSourceEffect extends OneShotEffect { + private final boolean nonWall; + private final Duration duration; + public BecomesChosenCreatureTypeSourceEffect() { - this(false); + this(false, Duration.EndOfTurn); } public BecomesChosenCreatureTypeSourceEffect(boolean nonWall) { + this(nonWall, Duration.EndOfTurn); + } + + public BecomesChosenCreatureTypeSourceEffect(boolean nonWall, Duration duration) { super(Outcome.BoostCreature); - staticText = "{this} becomes the creature type of your choice until end of turn."; + this.nonWall = nonWall; + this.duration = duration; + staticText = "{this} becomes the creature type of your choice" + (duration == Duration.EndOfTurn ? " until end of turn." : ""); } public BecomesChosenCreatureTypeSourceEffect(final BecomesChosenCreatureTypeSourceEffect effect) { super(effect); + this.nonWall = effect.nonWall; + this.duration = effect.duration; } @Override @@ -29,7 +41,7 @@ public class BecomesChosenCreatureTypeSourceEffect extends OneShotEffect { if (sourcePerm == null) { return false; } - Effect effect = new BecomesChosenCreatureTypeTargetEffect(); + Effect effect = new BecomesChosenCreatureTypeTargetEffect(nonWall, duration); effect.setTargetPointer(new FixedTarget(sourcePerm, game)); return effect.apply(game, source); } diff --git a/Mage/src/main/java/mage/abilities/effects/common/continuous/BecomesChosenCreatureTypeTargetEffect.java b/Mage/src/main/java/mage/abilities/effects/common/continuous/BecomesChosenCreatureTypeTargetEffect.java index 982f160fb6..ef3759eaa9 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/continuous/BecomesChosenCreatureTypeTargetEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/continuous/BecomesChosenCreatureTypeTargetEffect.java @@ -17,17 +17,24 @@ import mage.target.targetpointer.FixedTarget; public class BecomesChosenCreatureTypeTargetEffect extends OneShotEffect { private final boolean nonWall; + private final Duration duration; public BecomesChosenCreatureTypeTargetEffect() { - this(false); + this(false, Duration.EndOfTurn); } public BecomesChosenCreatureTypeTargetEffect(boolean nonWall) { + this(nonWall, Duration.EndOfTurn); + } + + public BecomesChosenCreatureTypeTargetEffect(boolean nonWall, Duration duration) { super(Outcome.BoostCreature); this.nonWall = nonWall; - if (nonWall) { + this.duration = duration; + if(nonWall) { staticText = "choose a creature type other than Wall. Target creature becomes that type until end of turn"; - } else { + } + else { staticText = "target creature becomes the creature type of your choice until end of turn"; } @@ -36,6 +43,7 @@ public class BecomesChosenCreatureTypeTargetEffect extends OneShotEffect { public BecomesChosenCreatureTypeTargetEffect(final BecomesChosenCreatureTypeTargetEffect effect) { super(effect); this.nonWall = effect.nonWall; + this.duration = effect.duration; } @Override @@ -46,21 +54,23 @@ public class BecomesChosenCreatureTypeTargetEffect extends OneShotEffect { if (player != null && card != null) { Choice typeChoice = new ChoiceCreatureType(); String msg = "Choose a creature type"; - if (nonWall) { + if(nonWall) { msg += " other than Wall"; } typeChoice.setMessage(msg); - if (nonWall) { + if(nonWall) { typeChoice.getChoices().remove(SubType.WALL.getDescription()); } - if (!player.choose(Outcome.BoostCreature, typeChoice, game)) { - return false; + while (!player.choose(Outcome.BoostCreature, typeChoice, game)) { + if (!player.canRespond()) { + return false; + } } game.informPlayers(card.getName() + ": " + player.getLogName() + " has chosen " + typeChoice.getChoice()); chosenType = typeChoice.getChoice(); if (chosenType != null && !chosenType.isEmpty()) { // ADD TYPE TO TARGET - ContinuousEffect effect = new BecomesCreatureTypeTargetEffect(Duration.EndOfTurn, SubType.byDescription(chosenType)); + ContinuousEffect effect = new BecomesCreatureTypeTargetEffect(duration, SubType.byDescription(chosenType)); effect.setTargetPointer(new FixedTarget(getTargetPointer().getFirst(game, source))); game.addEffect(effect, source); return true; diff --git a/Mage/src/main/java/mage/abilities/effects/common/cost/SpellsCostIncreasementAllEffect.java b/Mage/src/main/java/mage/abilities/effects/common/cost/SpellsCostIncreasementAllEffect.java index 95d6d6e524..6b371b0dc4 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/cost/SpellsCostIncreasementAllEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/cost/SpellsCostIncreasementAllEffect.java @@ -48,7 +48,7 @@ public class SpellsCostIncreasementAllEffect extends CostModificationEffectImpl private int amount; public SpellsCostIncreasementAllEffect(int amount) { - this(new FilterCard("All Spells "), amount); + this(new FilterCard("Spells"), amount); } public SpellsCostIncreasementAllEffect(FilterCard filter, int amount) { diff --git a/Mage/src/main/java/mage/abilities/keyword/DefenderAbility.java b/Mage/src/main/java/mage/abilities/keyword/DefenderAbility.java index 293ad9adb2..a6cf1ce515 100644 --- a/Mage/src/main/java/mage/abilities/keyword/DefenderAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/DefenderAbility.java @@ -56,7 +56,7 @@ public class DefenderAbility extends StaticAbility implements MageSingleton { @Override public String getRule() { - return "Defender"; + return "defender"; } @Override diff --git a/Mage/src/main/java/mage/abilities/keyword/LifelinkAbility.java b/Mage/src/main/java/mage/abilities/keyword/LifelinkAbility.java index c22dde451a..7a12b66426 100644 --- a/Mage/src/main/java/mage/abilities/keyword/LifelinkAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/LifelinkAbility.java @@ -56,7 +56,7 @@ public class LifelinkAbility extends StaticAbility implements MageSingleton { @Override public String getRule() { - return "Lifelink (Damage dealt by this creature also causes you to gain that much life.)"; + return "lifelink (Damage dealt by this creature also causes you to gain that much life.)"; } @Override diff --git a/Mage/src/main/java/mage/abilities/keyword/PersistAbility.java b/Mage/src/main/java/mage/abilities/keyword/PersistAbility.java index 085d893a49..bf4ca8188f 100644 --- a/Mage/src/main/java/mage/abilities/keyword/PersistAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/PersistAbility.java @@ -38,7 +38,6 @@ import mage.game.Game; import mage.game.events.GameEvent; import mage.game.events.ZoneChangeEvent; import mage.game.permanent.Permanent; -import mage.target.targetpointer.FixedTarget; public class PersistAbility extends DiesTriggeredAbility { @@ -66,8 +65,6 @@ public class PersistAbility extends DiesTriggeredAbility { if (super.checkTrigger(event, game)) { Permanent permanent = ((ZoneChangeEvent) event).getTarget(); if (permanent.getCounters(game).getCount(CounterType.M1M1) == 0) { - FixedTarget fixedTarget = new FixedTarget(permanent.getId()); - fixedTarget.init(game, this); return true; } } diff --git a/Mage/src/main/java/mage/abilities/keyword/ProtectionAbility.java b/Mage/src/main/java/mage/abilities/keyword/ProtectionAbility.java index 5f1b480406..46471af292 100644 --- a/Mage/src/main/java/mage/abilities/keyword/ProtectionAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/ProtectionAbility.java @@ -89,7 +89,7 @@ public class ProtectionAbility extends StaticAbility { @Override public String getRule() { - return "Protection from " + filter.getMessage() + (removeAuras ? "" : ". This effect doesn't remove auras."); + return "protection from " + filter.getMessage() + (removeAuras ? "" : ". This effect doesn't remove auras."); } public boolean canTarget(MageObject source, Game game) { diff --git a/Mage/src/main/java/mage/abilities/keyword/TotemArmorAbility.java b/Mage/src/main/java/mage/abilities/keyword/TotemArmorAbility.java index 604f164504..f31280d1bf 100644 --- a/Mage/src/main/java/mage/abilities/keyword/TotemArmorAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/TotemArmorAbility.java @@ -65,7 +65,7 @@ public class TotemArmorAbility extends SimpleStaticAbility { @Override public String getRule() { - return "Totem Armor (If enchanted creature would be destroyed, instead remove all damage from it and destroy this Aura.)"; + return "Totem armor (If enchanted creature would be destroyed, instead remove all damage from it and destroy this Aura.)"; } } diff --git a/Mage/src/main/java/mage/abilities/mana/SimpleManaAbility.java b/Mage/src/main/java/mage/abilities/mana/SimpleManaAbility.java index 093dedb048..0163abd7a6 100644 --- a/Mage/src/main/java/mage/abilities/mana/SimpleManaAbility.java +++ b/Mage/src/main/java/mage/abilities/mana/SimpleManaAbility.java @@ -53,7 +53,7 @@ public class SimpleManaAbility extends ActivatedManaAbilityImpl { * @param zone * @param effect * @param cost - * @param predictable set to false if definig the mana type or amount needs + * @param predictable set to false if defining the mana type or amount needs * to reveal information and can't be predicted */ public SimpleManaAbility(Zone zone, ManaEffect effect, Cost cost, boolean predictable) { diff --git a/Mage/src/main/java/mage/cards/repository/CardRepository.java b/Mage/src/main/java/mage/cards/repository/CardRepository.java index 02b9c5abf5..9538db973e 100644 --- a/Mage/src/main/java/mage/cards/repository/CardRepository.java +++ b/Mage/src/main/java/mage/cards/repository/CardRepository.java @@ -58,7 +58,7 @@ public enum CardRepository { // raise this if db structure was changed private static final long CARD_DB_VERSION = 51; // raise this if new cards were added to the server - private static final long CARD_CONTENT_VERSION = 104; + private static final long CARD_CONTENT_VERSION = 105; private Dao cardDao; private Set classNames; diff --git a/Mage/src/main/java/mage/filter/StaticFilters.java b/Mage/src/main/java/mage/filter/StaticFilters.java index c724734fa8..e6ccc99657 100644 --- a/Mage/src/main/java/mage/filter/StaticFilters.java +++ b/Mage/src/main/java/mage/filter/StaticFilters.java @@ -179,7 +179,13 @@ public final class StaticFilters { static { FILTER_CONTROLLED_CREATURE.setLockedFilter(true); + } + public static final FilterControlledCreaturePermanent FILTER_CONTROLLED_CREATURES = new FilterControlledCreaturePermanent("creatures you control"); + + static { + FILTER_CONTROLLED_CREATURES.setLockedFilter(true); } + public static final FilterControlledCreaturePermanent FILTER_CONTROLLED_A_CREATURE = new FilterControlledCreaturePermanent("a creature you control"); static { diff --git a/Mage/src/main/java/mage/filter/predicate/ability/ArtifactSourcePredicate.java b/Mage/src/main/java/mage/filter/predicate/ability/ArtifactSourcePredicate.java new file mode 100644 index 0000000000..36ff6b0032 --- /dev/null +++ b/Mage/src/main/java/mage/filter/predicate/ability/ArtifactSourcePredicate.java @@ -0,0 +1,51 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.filter.predicate.ability; + +import mage.MageObject; +import mage.abilities.Ability; +import mage.filter.predicate.Predicate; +import mage.game.Game; + +/** + * + * @author LevelX2 + */ +public class ArtifactSourcePredicate implements Predicate { + + @Override + public boolean apply(Ability input, Game game) { + MageObject sourceObject = input.getSourceObject(game); + return sourceObject != null && sourceObject.isArtifact(); + } + + @Override + public String toString() { + return "Source(Artifact)"; + } +} diff --git a/Mage/src/main/java/mage/filter/predicate/other/CardTextPredicate.java b/Mage/src/main/java/mage/filter/predicate/other/CardTextPredicate.java index 36cf356ce4..503d290e05 100644 --- a/Mage/src/main/java/mage/filter/predicate/other/CardTextPredicate.java +++ b/Mage/src/main/java/mage/filter/predicate/other/CardTextPredicate.java @@ -27,6 +27,7 @@ */ package mage.filter.predicate.other; +import java.util.HashMap; import mage.cards.Card; import mage.cards.SplitCard; import mage.constants.SubType; @@ -44,21 +45,38 @@ public class CardTextPredicate implements Predicate { private final boolean inNames; private final boolean inTypes; private final boolean inRules; + private final boolean isUnique; + private HashMap seenCards = null; - public CardTextPredicate(String text, boolean inNames, boolean inTypes, boolean inRules) { + public CardTextPredicate(String text, boolean inNames, boolean inTypes, boolean inRules, boolean isUnique) { this.text = text; this.inNames = inNames; this.inTypes = inTypes; this.inRules = inRules; + this.isUnique = isUnique; + seenCards = new HashMap<>(); } @Override public boolean apply(Card input, Game game) { - if (text.isEmpty()) { + if (text.isEmpty() && !isUnique) { return true; } + + if (text.isEmpty() && isUnique) { + boolean found = !seenCards.keySet().contains(input.getName()); + seenCards.put(input.getName(), true); + return found; + } + // first check in card name if (inNames && input.getName().toLowerCase().contains(text.toLowerCase())) { + if (isUnique && seenCards.keySet().contains(input.getName())) { + return false; + } + if (isUnique) { + seenCards.put(input.getName(), true); + } return true; } @@ -105,11 +123,18 @@ public class CardTextPredicate implements Predicate { } } } + + if (found && isUnique && seenCards.keySet().contains(input.getName())) { + found = false; + } if (!found) { return false; } } + if (isUnique) { + seenCards.put(input.getName(), true); + } return true; } diff --git a/Mage/src/main/java/mage/game/GameImpl.java b/Mage/src/main/java/mage/game/GameImpl.java index efb8984d58..572a2a4307 100644 --- a/Mage/src/main/java/mage/game/GameImpl.java +++ b/Mage/src/main/java/mage/game/GameImpl.java @@ -156,9 +156,12 @@ public abstract class GameImpl implements Game, Serializable { private final int startLife; protected PlayerList playerList; + // infinite loop check (no copy of this attributes neccessary) private int infiniteLoopCounter; // used to check if the game is in an infinite loop private int lastNumberOfAbilitiesOnTheStack; // used to check how long no new ability was put to stack + private List lastPlayersLifes = null; // if life is going down, it's no infinite loop private final LinkedList stackObjectsCheck = new LinkedList<>(); // used to check if different sources used the stack + // used to set the counters a permanent adds the battlefield (if no replacement effect is used e.g. Persist) protected Map enterWithCounters = new HashMap<>(); // used to proceed player conceding requests @@ -1418,6 +1421,24 @@ public abstract class GameImpl implements Game, Serializable { protected void checkInfiniteLoop(UUID removedStackObjectSourceId) { if (stackObjectsCheck.contains(removedStackObjectSourceId) && getStack().size() >= lastNumberOfAbilitiesOnTheStack) { + // Create a list of players life + List newLastPlayersLifes = new ArrayList<>(); + for (Player player : this.getPlayers().values()) { + newLastPlayersLifes.add(player.getLife()); + } + // Check if a player is loosing life + if (lastPlayersLifes != null && lastPlayersLifes.size() == newLastPlayersLifes.size()) { + for (int i = 0; i < newLastPlayersLifes.size(); i++) { + if (newLastPlayersLifes.get(i) < lastPlayersLifes.get(i)) { + // player is loosing life + lastPlayersLifes = null; + infiniteLoopCounter = 0; // reset the infinite counter + break; + } + } + } else { + lastPlayersLifes = newLastPlayersLifes; + } infiniteLoopCounter++; if (infiniteLoopCounter > 15) { Player controller = getPlayer(getControllerId(removedStackObjectSourceId)); diff --git a/Mage/src/main/java/mage/game/combat/Combat.java b/Mage/src/main/java/mage/game/combat/Combat.java index 9746308866..52b77917cc 100644 --- a/Mage/src/main/java/mage/game/combat/Combat.java +++ b/Mage/src/main/java/mage/game/combat/Combat.java @@ -750,6 +750,78 @@ public class Combat implements Serializable, Copyable { potentialBlockers.add(creature.getId()); } } + // check the mustBlockAllAttackers requirement for creatures already blocking (Blaze of Glory) ------------------------------- + if (effect.mustBlockAllAttackers(game)) { + // find all the attackers that the creature can block (and no restictions prevent this) + Set attackersToBlock = new HashSet<>(); + boolean mayBlock = false; + for (UUID attackingCreatureId : getAttackers()) { + if (creature.canBlock(attackingCreatureId, game)) { + Permanent attackingCreature = game.getPermanent(attackingCreatureId); + if (attackingCreature != null) { + // check if the attacker is already blocked by a max of blockers, so blocker can't block it also + if (attackingCreature.getMaxBlockedBy() != 0) { // 0 = no restriction about the number of possible blockers + int alreadyBlockingCreatures = 0; + for (CombatGroup group : getGroups()) { + if (group.getAttackers().contains(attackingCreatureId)) { + alreadyBlockingCreatures = group.getBlockers().size(); + break; + } + } + if (attackingCreature.getMaxBlockedBy() <= alreadyBlockingCreatures) { + continue; // Attacker can't be blocked by more blockers so check next attacker + } + } + // check restrictions of the creature to block that prevent it can be blocked (note L_J: not sure what this refers to...) + + // check if enough possible blockers are available, if true, mayBlock can be set to true + if (attackingCreature.getMinBlockedBy() > 1) { + int alreadyBlockingCreatures = 0; + for (CombatGroup group : getGroups()) { + if (group.getAttackers().contains(attackingCreatureId)) { + alreadyBlockingCreatures = group.getBlockers().size(); + break; + } + } + if (attackingCreature.getMinBlockedBy() >= alreadyBlockingCreatures) { + continue; // Attacker can't be blocked by the current blocker amount so check next attacker + } + } else { + attackersToBlock.add(attackingCreatureId); + } + } + } + } + if (!attackersToBlock.isEmpty()) { + for (UUID attackerId : attackersToBlock) { + if (!findGroup(attackerId).getBlockers().contains(creature.getId())) { + mayBlock = true; + break; + } + } + } + // if creature can block more attackers, inform human player or set blocks for AI player + if (mayBlock) { + if (controller.isHuman()) { + if (!game.isSimulation()) { + game.informPlayer(controller, "Creature should block all attackers it's able to this turn: " + creature.getIdName()); + } + } else { + Player defender = game.getPlayer(creature.getControllerId()); + if (defender != null) { + for (UUID attackingCreatureId : getAttackers()) { + if (creature.canBlock(attackingCreatureId, game) + && !findGroup(attackingCreatureId).getBlockers().contains(creature.getId()) + && attackersToBlock.contains(attackingCreatureId)) { + // TODO: might need to revisit this (calls some pickBlockerOrder instances even for a single blocker - damage distribution appears to be working correctly however) + defender.declareBlocker(defender.getId(), creature.getId(), attackingCreatureId, game); + } + } + } + } + return false; + } + } } } @@ -773,10 +845,9 @@ public class Combat implements Serializable, Copyable { } } - // check the mustBlockAny requirement ---------------------------------------- - if (effect.mustBlockAny(game)) { - // check that it can block at least one of the attackers - // and no restictions prevent this + // check the mustBlockAny requirement (and mustBlockAllAttackers for not blocking creatures) ---------------------------------------- + if (effect.mustBlockAny(game) || effect.mustBlockAllAttackers(game)) { + // check that it can block at least one of the attackers and no restictions prevent this boolean mayBlock = false; for (UUID attackingCreatureId : getAttackers()) { if (creature.canBlock(attackingCreatureId, game)) { @@ -792,15 +863,23 @@ public class Combat implements Serializable, Copyable { } } if (attackingCreature.getMaxBlockedBy() <= alreadyBlockingCreatures) { - // Attacker can't be blocked by more blockers so check next attacker - continue; + continue; // Attacker can't be blocked by more blockers so check next attacker } } - // check restrictions of the creature to block that prevent it can be blocked + // check restrictions of the creature to block that prevent it can be blocked (note L_J: not sure what this refers to...) + // check if enough possible blockers are available, if true, mayBlock can be set to true if (attackingCreature.getMinBlockedBy() > 1) { - // TODO: check if enough possible blockers are available, if true, mayBlock can be set to true - + int alreadyBlockingCreatures = 0; + for (CombatGroup group : getGroups()) { + if (group.getAttackers().contains(attackingCreatureId)) { + alreadyBlockingCreatures = group.getBlockers().size(); + break; + } + } + if (attackingCreature.getMinBlockedBy() >= alreadyBlockingCreatures) { + continue; // Attacker can't be blocked by the current blocker amount so check next attacker + } } else { mayBlock = true; break; @@ -808,7 +887,7 @@ public class Combat implements Serializable, Copyable { } } } - // if so inform human player or set block for AI player + // if creature can block, inform human player or set block for AI player if (mayBlock) { if (controller.isHuman()) { if (!game.isSimulation()) { @@ -818,7 +897,8 @@ public class Combat implements Serializable, Copyable { Player defender = game.getPlayer(creature.getControllerId()); if (defender != null) { for (UUID attackingCreatureId : getAttackers()) { - if (creature.canBlock(attackingCreatureId, game)) { + if (creature.canBlock(attackingCreatureId, game) + && !findGroup(attackingCreatureId).getBlockers().contains(creature.getId())) { defender.declareBlocker(defender.getId(), creature.getId(), attackingCreatureId, game); break; } diff --git a/Mage/src/main/java/mage/game/match/MatchOptions.java b/Mage/src/main/java/mage/game/match/MatchOptions.java index 5b1f4a6df9..e0dbb153fa 100644 --- a/Mage/src/main/java/mage/game/match/MatchOptions.java +++ b/Mage/src/main/java/mage/game/match/MatchOptions.java @@ -25,7 +25,6 @@ * authors and should not be interpreted as representing official policies, either expressed * or implied, of BetaSteward_at_googlemail.com. */ - package mage.game.match; import mage.constants.MatchTimeLimit; @@ -61,6 +60,7 @@ public class MatchOptions implements Serializable { protected String password; protected SkillLevel skillLevel; protected boolean rollbackTurnsAllowed; + protected boolean spectatorsAllowed; protected int quitRatio; protected int edhPowerLevel; protected boolean rated; @@ -79,8 +79,7 @@ public class MatchOptions implements Serializable { this.multiPlayer = false; this.numSeats = 2; }*/ - - public MatchOptions(String name, String gameType, boolean multiPlayer, int numSeats ) { + public MatchOptions(String name, String gameType, boolean multiPlayer, int numSeats) { this.name = name; this.gameType = gameType; this.password = ""; @@ -178,7 +177,7 @@ public class MatchOptions implements Serializable { public MatchTimeLimit getMatchTimeLimit() { return this.matchTimeLimit; } - + public void setMatchTimeLimit(MatchTimeLimit matchTimeLimit) { this.matchTimeLimit = matchTimeLimit; } @@ -207,6 +206,14 @@ public class MatchOptions implements Serializable { this.rollbackTurnsAllowed = rollbackTurnsAllowed; } + public boolean isSpectatorsAllowed() { + return spectatorsAllowed; + } + + public void setSpectatorsAllowed(boolean spectatorsAllowed) { + this.spectatorsAllowed = spectatorsAllowed; + } + public int getQuitRatio() { return quitRatio; } @@ -214,7 +221,7 @@ public class MatchOptions implements Serializable { public void setQuitRatio(int quitRatio) { this.quitRatio = quitRatio; } - + public int getEdhPowerLevel() { return edhPowerLevel; } diff --git a/Mage/src/main/java/mage/game/permanent/Permanent.java b/Mage/src/main/java/mage/game/permanent/Permanent.java index 8700e560df..8b9273e824 100644 --- a/Mage/src/main/java/mage/game/permanent/Permanent.java +++ b/Mage/src/main/java/mage/game/permanent/Permanent.java @@ -59,7 +59,6 @@ public interface Permanent extends Card, Controllable { * @param tapped * @deprecated */ - @Deprecated void setTapped(boolean tapped); boolean canTap(); diff --git a/Mage/src/main/java/mage/game/stack/StackAbility.java b/Mage/src/main/java/mage/game/stack/StackAbility.java index 07509f5786..00eabb629a 100644 --- a/Mage/src/main/java/mage/game/stack/StackAbility.java +++ b/Mage/src/main/java/mage/game/stack/StackAbility.java @@ -50,6 +50,7 @@ import mage.constants.*; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.events.ZoneChangeEvent; +import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.Target; import mage.target.Targets; @@ -529,12 +530,17 @@ public class StackAbility extends StackObjImpl implements Ability { @Override public MageObject getSourceObject(Game game) { - return game.getBaseObject(getSourceId()); + return this.ability.getSourceObject(game); } @Override public MageObject getSourceObjectIfItStillExists(Game game) { - throw new UnsupportedOperationException("Not supported."); + return this.ability.getSourceObjectIfItStillExists(game); + } + + @Override + public Permanent getSourcePermanentIfItStillExists(Game game) { + return this.ability.getSourcePermanentIfItStillExists(game); } @Override diff --git a/Mage/src/main/java/mage/players/ManaPool.java b/Mage/src/main/java/mage/players/ManaPool.java index 62ddedf6d6..565e96cac2 100644 --- a/Mage/src/main/java/mage/players/ManaPool.java +++ b/Mage/src/main/java/mage/players/ManaPool.java @@ -118,10 +118,19 @@ public class ManaPool implements Serializable { // if manual payment and the needed mana type was not unlocked, nothing will be paid return false; } + ManaType possibleAsThoughtPoolManaType = null; if (autoPayment && autoPaymentRestricted && !wasManaAddedBeyondStock() && manaType != unlockedManaType) { // if automatic restricted payment and there is already mana in the pool // and the needed mana type was not unlocked, nothing will be paid - return false; + if (unlockedManaType != null) { + ManaPoolItem checkItem = new ManaPoolItem(); + checkItem.add(unlockedManaType, 1); + possibleAsThoughtPoolManaType = game.getContinuousEffects().asThoughMana(manaType, checkItem, ability.getSourceId(), ability, ability.getControllerId(), game); + } + // Check if it's possible to use mana as thought for the unlocked manatype in the mana pool for this ability + if (possibleAsThoughtPoolManaType == null || possibleAsThoughtPoolManaType != unlockedManaType) { + return false; // if it's not possible return + } } if (getConditional(manaType, ability, filter, game, costToPay) > 0) { @@ -138,7 +147,7 @@ public class ManaPool implements Serializable { } } } - if (manaType != unlockedManaType && autoPayment && autoPaymentRestricted && mana.count() == mana.getStock()) { + if (possibleAsThoughtPoolManaType == null && manaType != unlockedManaType && autoPayment && autoPaymentRestricted && mana.count() == mana.getStock()) { // no mana added beyond the stock so don't auto pay this continue; } diff --git a/Mage/src/main/java/mage/players/PlayerImpl.java b/Mage/src/main/java/mage/players/PlayerImpl.java index a61e8023f3..da939fea99 100644 --- a/Mage/src/main/java/mage/players/PlayerImpl.java +++ b/Mage/src/main/java/mage/players/PlayerImpl.java @@ -1097,6 +1097,8 @@ public abstract class PlayerImpl implements Player, Serializable { if (!ignoreTiming && !playLandAbility.canActivate(this.playerId, game)) { return false; } + + game.fireEvent(GameEvent.getEvent(GameEvent.EventType.PLAY_LAND, card.getId(), card.getId(), playerId)); //20091005 - 305.1 if (!game.replaceEvent(GameEvent.getEvent(GameEvent.EventType.PLAY_LAND, card.getId(), card.getId(), playerId))) { // int bookmark = game.bookmarkState(); @@ -1113,7 +1115,7 @@ public abstract class PlayerImpl implements Player, Serializable { // what makes no real sense. So it makes no sense to generally do a restorState here. // restoreState(bookmark, card.getName(), game); } - // if the to play the land is replaced (e.g. Kjeldoran Outpos and don't sacrificing a Plains) it's a valid satte so returning true here + // if the to play the land is replaced (e.g. Kjeldoran Outpos and don't sacrificing a Plains) it's a valid state so returning true here return true; } @@ -1274,7 +1276,7 @@ public abstract class PlayerImpl implements Player, Serializable { return false; } - protected LinkedHashMap getSpellAbilities(MageObject object, Zone zone, Game game) { + public LinkedHashMap getSpellAbilities(MageObject object, Zone zone, Game game) { LinkedHashMap useable = new LinkedHashMap<>(); for (Ability ability : object.getAbilities()) { if (ability instanceof SpellAbility) { diff --git a/Mage/src/main/java/mage/target/common/TargetActivatedAbility.java b/Mage/src/main/java/mage/target/common/TargetActivatedAbility.java index 00e65d3b11..b107528f6e 100644 --- a/Mage/src/main/java/mage/target/common/TargetActivatedAbility.java +++ b/Mage/src/main/java/mage/target/common/TargetActivatedAbility.java @@ -57,7 +57,7 @@ public class TargetActivatedAbility extends TargetObject { this.minNumberOfTargets = 1; this.maxNumberOfTargets = 1; this.zone = Zone.STACK; - this.targetName = "activated ability"; + this.targetName = filter.getMessage(); this.filter = filter; } diff --git a/Mage/src/main/java/mage/target/common/TargetActivatedOrTriggeredAbility.java b/Mage/src/main/java/mage/target/common/TargetActivatedOrTriggeredAbility.java index 8c9df2be20..3e3eeff5c2 100644 --- a/Mage/src/main/java/mage/target/common/TargetActivatedOrTriggeredAbility.java +++ b/Mage/src/main/java/mage/target/common/TargetActivatedOrTriggeredAbility.java @@ -44,7 +44,7 @@ public class TargetActivatedOrTriggeredAbility extends TargetObject { protected final FilterStackObject filter; public TargetActivatedOrTriggeredAbility() { - this(new FilterStackObject()); + this(new FilterStackObject("activated or triggered ability")); } public TargetActivatedOrTriggeredAbility(FilterStackObject filter) { diff --git a/Mage/src/main/java/mage/target/targetpointer/FirstTargetPointer.java b/Mage/src/main/java/mage/target/targetpointer/FirstTargetPointer.java index 01d2b3c7db..82241949eb 100644 --- a/Mage/src/main/java/mage/target/targetpointer/FirstTargetPointer.java +++ b/Mage/src/main/java/mage/target/targetpointer/FirstTargetPointer.java @@ -35,7 +35,7 @@ public class FirstTargetPointer implements TargetPointer { Card card = game.getCard(target); if (card != null) { this.zoneChangeCounter.put(target, card.getZoneChangeCounter(game)); - } + } } } } @@ -66,9 +66,9 @@ public class FirstTargetPointer implements TargetPointer { if (zoneChangeCounter.containsKey(targetId)) { Card card = game.getCard(targetId); if (card != null && zoneChangeCounter.containsKey(targetId) - && card.getZoneChangeCounter(game) != zoneChangeCounter.get(targetId)) { - // because if dies trigger has to trigger as permanent has already moved zone, we have to check if target was on the battlefield immed. before - // but no longer if new permanent is already on the battlefield + && card.getZoneChangeCounter(game) != zoneChangeCounter.get(targetId)) { + // because if dies trigger has to trigger as permanent has already moved zone, we have to check if target was on the battlefield immed. before + // but no longer if new permanent is already on the battlefield Permanent permanent = game.getPermanentOrLKIBattlefield(targetId); if (permanent == null || permanent.getZoneChangeCounter(game) != zoneChangeCounter.get(targetId)) { return null; @@ -82,4 +82,16 @@ public class FirstTargetPointer implements TargetPointer { public TargetPointer copy() { return new FirstTargetPointer(this); } + + @Override + public FixedTarget getFixedTarget(Game game, Ability source) { + this.init(game, source); + UUID firstId = getFirst(game, source); + if (firstId != null) { + return new FixedTarget(firstId, game.getState().getZoneChangeCounter(firstId)); + } + return null; + + } + } diff --git a/Mage/src/main/java/mage/target/targetpointer/FixedTarget.java b/Mage/src/main/java/mage/target/targetpointer/FixedTarget.java index 397e4e7de3..c931962322 100644 --- a/Mage/src/main/java/mage/target/targetpointer/FixedTarget.java +++ b/Mage/src/main/java/mage/target/targetpointer/FixedTarget.java @@ -1,15 +1,14 @@ package mage.target.targetpointer; -import mage.abilities.Ability; -import mage.cards.Card; -import mage.constants.Zone; -import mage.game.Game; -import mage.game.permanent.Permanent; - import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.UUID; +import mage.abilities.Ability; +import mage.cards.Card; +import mage.constants.Zone; +import mage.game.Game; +import mage.game.permanent.Permanent; public class FixedTarget implements TargetPointer { @@ -65,10 +64,7 @@ public class FixedTarget implements TargetPointer { public void init(Game game, Ability source) { if (!initialized) { initialized = true; - Card card = game.getCard(targetId); - if (card != null) { - this.zoneChangeCounter = card.getZoneChangeCounter(game); - } + this.zoneChangeCounter = game.getState().getZoneChangeCounter(targetId); } } @@ -121,4 +117,10 @@ public class FixedTarget implements TargetPointer { return permanent; } + @Override + public FixedTarget getFixedTarget(Game game, Ability source) { + init(game, source); + return this; + } + } diff --git a/Mage/src/main/java/mage/target/targetpointer/FixedTargets.java b/Mage/src/main/java/mage/target/targetpointer/FixedTargets.java index bb231a51c7..e220491074 100644 --- a/Mage/src/main/java/mage/target/targetpointer/FixedTargets.java +++ b/Mage/src/main/java/mage/target/targetpointer/FixedTargets.java @@ -21,10 +21,12 @@ import mage.game.permanent.Permanent; public class FixedTargets implements TargetPointer { final ArrayList targets = new ArrayList<>(); + final ArrayList targetsNotInitialized = new ArrayList<>(); + private boolean initialized; public FixedTargets(UUID targetId) { - targets.add(new MageObjectReference(targetId)); + targetsNotInitialized.add(targetId); this.initialized = false; } @@ -46,6 +48,7 @@ public class FixedTargets implements TargetPointer { private FixedTargets(final FixedTargets fixedTargets) { this.targets.addAll(fixedTargets.targets); + this.targetsNotInitialized.addAll(fixedTargets.targetsNotInitialized); this.initialized = fixedTargets.initialized; } @@ -53,8 +56,8 @@ public class FixedTargets implements TargetPointer { public void init(Game game, Ability source) { if (!initialized) { initialized = true; - for (MageObjectReference mor : targets) { - mor.setZoneChangeCounter(game.getState().getZoneChangeCounter(mor.getSourceId())); + for (UUID targetId : targetsNotInitialized) { + targets.add(new MageObjectReference(targetId, game.getState().getZoneChangeCounter(targetId), game)); } } } @@ -87,4 +90,20 @@ public class FixedTargets implements TargetPointer { return new FixedTargets(this); } + /** + * Returns a fixed target for (and only) the first taget + * + * @param game + * @param source + * @return + */ + @Override + public FixedTarget getFixedTarget(Game game, Ability source) { + this.init(game, source); + UUID firstId = getFirst(game, source); + if (firstId != null) { + return new FixedTarget(firstId, game.getState().getZoneChangeCounter(firstId)); + } + return null; + } } diff --git a/Mage/src/main/java/mage/target/targetpointer/SecondTargetPointer.java b/Mage/src/main/java/mage/target/targetpointer/SecondTargetPointer.java index db301a7055..9d2779b4ef 100644 --- a/Mage/src/main/java/mage/target/targetpointer/SecondTargetPointer.java +++ b/Mage/src/main/java/mage/target/targetpointer/SecondTargetPointer.java @@ -1,11 +1,10 @@ package mage.target.targetpointer; +import java.util.*; import mage.abilities.Ability; import mage.cards.Card; import mage.game.Game; -import java.util.*; - public class SecondTargetPointer implements TargetPointer { private Map zoneChangeCounter = new HashMap<>(); @@ -59,7 +58,7 @@ public class SecondTargetPointer implements TargetPointer { if (zoneChangeCounter.containsKey(targetId)) { Card card = game.getCard(targetId); if (card != null && zoneChangeCounter.containsKey(targetId) - && card.getZoneChangeCounter(game) != zoneChangeCounter.get(targetId)) { + && card.getZoneChangeCounter(game) != zoneChangeCounter.get(targetId)) { return null; } } @@ -72,4 +71,14 @@ public class SecondTargetPointer implements TargetPointer { public TargetPointer copy() { return new SecondTargetPointer(this); } + + @Override + public FixedTarget getFixedTarget(Game game, Ability source) { + this.init(game, source); + UUID firstId = getFirst(game, source); + if (firstId != null) { + return new FixedTarget(firstId, game.getState().getZoneChangeCounter(firstId)); + } + return null; + } } diff --git a/Mage/src/main/java/mage/target/targetpointer/TargetPointer.java b/Mage/src/main/java/mage/target/targetpointer/TargetPointer.java index 0b77cd2bf6..6dd021c9ac 100644 --- a/Mage/src/main/java/mage/target/targetpointer/TargetPointer.java +++ b/Mage/src/main/java/mage/target/targetpointer/TargetPointer.java @@ -7,8 +7,14 @@ import mage.abilities.Ability; import mage.game.Game; public interface TargetPointer extends Serializable { + void init(Game game, Ability source); + List getTargets(Game game, Ability source); + UUID getFirst(Game game, Ability source); + TargetPointer copy(); + + FixedTarget getFixedTarget(Game game, Ability source); } diff --git a/Mage/src/main/java/mage/target/targetpointer/ThirdTargetPointer.java b/Mage/src/main/java/mage/target/targetpointer/ThirdTargetPointer.java index 2fdbf05037..206bfe2eb9 100644 --- a/Mage/src/main/java/mage/target/targetpointer/ThirdTargetPointer.java +++ b/Mage/src/main/java/mage/target/targetpointer/ThirdTargetPointer.java @@ -84,4 +84,15 @@ public class ThirdTargetPointer implements TargetPointer { public TargetPointer copy() { return new ThirdTargetPointer(this); } + + @Override + public FixedTarget getFixedTarget(Game game, Ability source) { + this.init(game, source); + UUID firstId = getFirst(game, source); + if (firstId != null) { + return new FixedTarget(firstId, game.getState().getZoneChangeCounter(firstId)); + } + return null; + + } } diff --git a/Mage/src/main/java/mage/watchers/common/PlayerAttackedStepWatcher.java b/Mage/src/main/java/mage/watchers/common/PlayerAttackedStepWatcher.java index 03f56c9beb..0fb1362cd2 100644 --- a/Mage/src/main/java/mage/watchers/common/PlayerAttackedStepWatcher.java +++ b/Mage/src/main/java/mage/watchers/common/PlayerAttackedStepWatcher.java @@ -44,7 +44,7 @@ public class PlayerAttackedStepWatcher extends Watcher { private final Map playerAttacked = new HashMap<>(); public PlayerAttackedStepWatcher() { - super(PlayerAttackedWatcher.class.getSimpleName(), WatcherScope.GAME); + super(PlayerAttackedStepWatcher.class.getSimpleName(), WatcherScope.GAME); } public PlayerAttackedStepWatcher(final PlayerAttackedStepWatcher watcher) { diff --git a/Utils/mtg-cards-data.txt b/Utils/mtg-cards-data.txt index 5ffce6bc34..f17930b11c 100644 --- a/Utils/mtg-cards-data.txt +++ b/Utils/mtg-cards-data.txt @@ -33077,3 +33077,4 @@ Urza's Science Fair Project|Unglued|83|U|{6}|Artifact Creature - Construct|4|4| Snow Mercy|Happy Holidays|10|R|{2}{W}{W}|Snow Enchantment|||Whenever a creature deals damage to you, put a globe counter on it.${t},{untap},{t},{untap},{t}: Tap all creatures with globe counters on them.| Fruitcake Elemental|Happy Holidays|6|R|{1}{G}{G}|Creature - Elemental|7|7|Fruitcake Elemental is indestructible.$At the end of your turn, Fruitcake Elemental deals 7 damage to you.${3}: Target player gains control of Fruitcake Elemental.| Season's Beatings|Happy Holidays|9|R|{R}{R}{R}{R}|Sorcery|||Family gathering - Each creature target player controls deals damage equal to its power to another random creature that player controls.| +Mox Lotus|Unhinged|124|R|{15}|Artifact|||{t}: Add infinity to your mana pool.${100}: Add one mana of any color to your mana pool.&You don't lose life due to mana burn.| diff --git a/Utils/mtg-sets-data.txt b/Utils/mtg-sets-data.txt index 9a6faa767d..ea542b580f 100644 --- a/Utils/mtg-sets-data.txt +++ b/Utils/mtg-sets-data.txt @@ -117,7 +117,7 @@ Magic 2013|M13| Magic 2014|M14| Magic 2015|M15| Core 2019|M19| -Masters 25|M25| +Masters 25|A25| Magic: The Gathering-Commander|CMD| Magic: The Gathering-Conspiracy|CNS| Media Inserts|MBP|