diff --git a/.gitignore b/.gitignore index ae4cade4b6..34ddf1abfb 100644 --- a/.gitignore +++ b/.gitignore @@ -152,3 +152,6 @@ mage-bundle # build-tools config and log files when building client/server with Atom .build-tools.cson build-output.log + +# Visual Studio Code +.history diff --git a/Mage.Client/pom.xml b/Mage.Client/pom.xml index fe209e15e5..78fb0b9f4c 100644 --- a/Mage.Client/pom.xml +++ b/Mage.Client/pom.xml @@ -6,7 +6,7 @@ org.mage mage-root - 1.4.37 + 1.4.39 mage-client diff --git a/Mage.Client/src/main/java/mage/client/deckeditor/collection/viewer/MageBook.java b/Mage.Client/src/main/java/mage/client/deckeditor/collection/viewer/MageBook.java index ae4d2db50c..7ef72f3440 100644 --- a/Mage.Client/src/main/java/mage/client/deckeditor/collection/viewer/MageBook.java +++ b/Mage.Client/src/main/java/mage/client/deckeditor/collection/viewer/MageBook.java @@ -695,13 +695,13 @@ public class MageBook extends JComponent { int totalTokensEmblems = totalTokens + getTotalNumEmblems(set); int start = 0; if (!(page * conf.CARDS_PER_PAGE <= totalTokensEmblems && (page + 1) * conf.CARDS_PER_PAGE >= totalTokensEmblems)) { - start = page * conf.CARDS_PER_PAGE - totalTokensEmblems; + start = Math.max(0, page * conf.CARDS_PER_PAGE - totalTokensEmblems); pageRight.setVisible(true); } int end = planes.size(); if ((page + 1) * conf.CARDS_PER_PAGE < totalTokensEmblems + planes.size()) { - end = (page + 1) * conf.CARDS_PER_PAGE - totalTokensEmblems; + end = Math.max(0, (page + 1) * conf.CARDS_PER_PAGE - totalTokensEmblems); pageRight.setVisible(true); } else { pageRight.setVisible(false); diff --git a/Mage.Client/src/main/java/mage/client/dialog/ConnectDialog.form b/Mage.Client/src/main/java/mage/client/dialog/ConnectDialog.form index 4028425331..4b0dae2a96 100644 --- a/Mage.Client/src/main/java/mage/client/dialog/ConnectDialog.form +++ b/Mage.Client/src/main/java/mage/client/dialog/ConnectDialog.form @@ -422,11 +422,10 @@ - - + + - diff --git a/Mage.Client/src/main/java/mage/client/dialog/ConnectDialog.java b/Mage.Client/src/main/java/mage/client/dialog/ConnectDialog.java index 9846764b5a..33d1b75b29 100644 --- a/Mage.Client/src/main/java/mage/client/dialog/ConnectDialog.java +++ b/Mage.Client/src/main/java/mage/client/dialog/ConnectDialog.java @@ -283,11 +283,10 @@ public class ConnectDialog extends MageDialog { }); btnFindUs.setIcon(new javax.swing.ImageIcon(getClass().getResource("/flags/us.png"))); // NOI18N - btnFindUs.setText("P"); - btnFindUs.setToolTipText("Connect to mtg.powersofwar.com (USA, use any username without registration)"); + btnFindUs.setText("US"); + btnFindUs.setToolTipText("Connect to us.xmage.today (USA, use any username without registration)"); btnFindUs.setActionCommand("connectXmageus"); btnFindUs.setAlignmentY(0.0F); - btnFindUs.setEnabled(false); btnFindUs.setMargin(new java.awt.Insets(2, 2, 2, 2)); btnFindUs.setName("connectXmageusBtn"); // NOI18N btnFindUs.setPreferredSize(new java.awt.Dimension(23, 23)); @@ -310,36 +309,34 @@ public class ConnectDialog extends MageDialog { javax.swing.GroupLayout panelFastLayout = new javax.swing.GroupLayout(panelFast); panelFast.setLayout(panelFastLayout); panelFastLayout.setHorizontalGroup( - panelFastLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(panelFastLayout.createSequentialGroup() - .addGap(0, 0, 0) - .addComponent(btnFindMain, javax.swing.GroupLayout.PREFERRED_SIZE, 90, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(btnFindUs, javax.swing.GroupLayout.PREFERRED_SIZE, 90, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(btnFindBeta, javax.swing.GroupLayout.PREFERRED_SIZE, 90, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(btnFindLocal, javax.swing.GroupLayout.PREFERRED_SIZE, 90, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(btnFindOther, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addGap(0, 0, 0)) + panelFastLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(panelFastLayout.createSequentialGroup() + .addGap(0, 0, 0) + .addComponent(btnFindMain, javax.swing.GroupLayout.PREFERRED_SIZE, 90, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(btnFindUs, javax.swing.GroupLayout.PREFERRED_SIZE, 90, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(btnFindBeta, javax.swing.GroupLayout.PREFERRED_SIZE, 90, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(btnFindLocal, javax.swing.GroupLayout.PREFERRED_SIZE, 90, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(btnFindOther, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addGap(0, 0, 0)) ); panelFastLayout.setVerticalGroup( - panelFastLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(panelFastLayout.createSequentialGroup() - .addGap(0, 0, 0) - .addGroup(panelFastLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(btnFindMain, javax.swing.GroupLayout.PREFERRED_SIZE, 30, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(btnFindLocal, javax.swing.GroupLayout.PREFERRED_SIZE, 30, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(btnFindUs, javax.swing.GroupLayout.PREFERRED_SIZE, 30, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(btnFindBeta, javax.swing.GroupLayout.PREFERRED_SIZE, 30, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(btnFindOther, javax.swing.GroupLayout.PREFERRED_SIZE, 30, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addGap(0, 0, 0)) + panelFastLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(panelFastLayout.createSequentialGroup() + .addGap(0, 0, 0) + .addGroup(panelFastLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(btnFindMain, javax.swing.GroupLayout.PREFERRED_SIZE, 30, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(btnFindLocal, javax.swing.GroupLayout.PREFERRED_SIZE, 30, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(btnFindUs, javax.swing.GroupLayout.PREFERRED_SIZE, 30, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(btnFindBeta, javax.swing.GroupLayout.PREFERRED_SIZE, 30, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(btnFindOther, javax.swing.GroupLayout.PREFERRED_SIZE, 30, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGap(0, 0, 0)) ); txtPort.addKeyListener(new java.awt.event.KeyAdapter() { - - @Override public void keyTyped(java.awt.event.KeyEvent evt) { ConnectDialog.this.keyTyped(evt); } @@ -363,26 +360,26 @@ public class ConnectDialog extends MageDialog { javax.swing.GroupLayout panelServerLayout = new javax.swing.GroupLayout(panelServer); panelServer.setLayout(panelServerLayout); panelServerLayout.setHorizontalGroup( - panelServerLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(panelServerLayout.createSequentialGroup() - .addComponent(txtServer, javax.swing.GroupLayout.PREFERRED_SIZE, 212, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(lblPort) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(txtPort, javax.swing.GroupLayout.PREFERRED_SIZE, 75, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(btnCheckStatus, javax.swing.GroupLayout.DEFAULT_SIZE, 205, Short.MAX_VALUE) - .addGap(0, 0, 0)) + panelServerLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(panelServerLayout.createSequentialGroup() + .addComponent(txtServer, javax.swing.GroupLayout.PREFERRED_SIZE, 212, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(lblPort) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(txtPort, javax.swing.GroupLayout.PREFERRED_SIZE, 75, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(btnCheckStatus, javax.swing.GroupLayout.DEFAULT_SIZE, 205, Short.MAX_VALUE) + .addGap(0, 0, 0)) ); panelServerLayout.setVerticalGroup( - panelServerLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(panelServerLayout.createSequentialGroup() - .addGap(0, 0, 0) - .addGroup(panelServerLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(txtServer, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(txtPort, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(lblPort) - .addComponent(btnCheckStatus, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))) + panelServerLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(panelServerLayout.createSequentialGroup() + .addGap(0, 0, 0) + .addGroup(panelServerLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(txtServer, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(txtPort, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(lblPort) + .addComponent(btnCheckStatus, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))) ); btnWhatsNew.setText("Show what's new"); @@ -397,92 +394,92 @@ public class ConnectDialog extends MageDialog { javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane()); getContentPane().setLayout(layout); layout.setHorizontalGroup( - layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(layout.createSequentialGroup() - .addContainerGap() - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) - .addComponent(lblUserName, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(lblServer, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(lblFastConnect, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(lblPassword, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(lblFlag, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) - .addGap(18, 18, 18) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(lblStatus, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(chkForceUpdateDB, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(chkAutoConnect, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(txtUserName) - .addComponent(panelFlag, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addGroup(layout.createSequentialGroup() - .addComponent(btnConnect, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) - .addComponent(btnRegister, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(btnForgotPassword, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(btnCancel, javax.swing.GroupLayout.PREFERRED_SIZE, 77, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addComponent(panelFast, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(panelServer, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addGroup(layout.createSequentialGroup() - .addComponent(jProxySettingsButton) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(btnWhatsNew) - .addGap(0, 0, Short.MAX_VALUE)) - .addGroup(layout.createSequentialGroup() - .addComponent(txtPassword) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(jLabel1))) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(filler2, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addContainerGap()) + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addContainerGap() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) + .addComponent(lblUserName, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(lblServer, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(lblFastConnect, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(lblPassword, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(lblFlag, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addGap(18, 18, 18) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(lblStatus, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(chkForceUpdateDB, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(chkAutoConnect, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(txtUserName) + .addComponent(panelFlag, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addGroup(layout.createSequentialGroup() + .addComponent(btnConnect, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) + .addComponent(btnRegister, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(btnForgotPassword, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(btnCancel, javax.swing.GroupLayout.PREFERRED_SIZE, 77, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addComponent(panelFast, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(panelServer, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addGroup(layout.createSequentialGroup() + .addComponent(jProxySettingsButton) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(btnWhatsNew) + .addGap(0, 0, Short.MAX_VALUE)) + .addGroup(layout.createSequentialGroup() + .addComponent(txtPassword) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(jLabel1))) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(filler2, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addContainerGap()) ); layout.setVerticalGroup( - layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() - .addContainerGap() - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(panelFast, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(lblFastConnect, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(panelServer, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(lblServer, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(layout.createSequentialGroup() - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(txtUserName, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(lblUserName, javax.swing.GroupLayout.PREFERRED_SIZE, 20, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(txtPassword) - .addComponent(jLabel1)) - .addComponent(lblPassword, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))) - .addComponent(filler2, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(panelFlag, javax.swing.GroupLayout.PREFERRED_SIZE, 20, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(lblFlag, javax.swing.GroupLayout.PREFERRED_SIZE, 18, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addComponent(chkAutoConnect) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(chkForceUpdateDB) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(jProxySettingsButton, javax.swing.GroupLayout.PREFERRED_SIZE, 30, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(btnWhatsNew, javax.swing.GroupLayout.PREFERRED_SIZE, 30, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addComponent(lblStatus, javax.swing.GroupLayout.PREFERRED_SIZE, 24, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false) - .addGroup(layout.createSequentialGroup() - .addComponent(btnRegister, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(btnForgotPassword, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) - .addComponent(btnConnect, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(btnCancel, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) - .addGap(23, 23, 23)) + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() + .addContainerGap() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(panelFast, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(lblFastConnect, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(panelServer, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(lblServer, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(txtUserName, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(lblUserName, javax.swing.GroupLayout.PREFERRED_SIZE, 20, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(txtPassword) + .addComponent(jLabel1)) + .addComponent(lblPassword, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))) + .addComponent(filler2, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(panelFlag, javax.swing.GroupLayout.PREFERRED_SIZE, 20, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(lblFlag, javax.swing.GroupLayout.PREFERRED_SIZE, 18, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(chkAutoConnect) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(chkForceUpdateDB) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(jProxySettingsButton, javax.swing.GroupLayout.PREFERRED_SIZE, 30, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(btnWhatsNew, javax.swing.GroupLayout.PREFERRED_SIZE, 30, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(lblStatus, javax.swing.GroupLayout.PREFERRED_SIZE, 24, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false) + .addGroup(layout.createSequentialGroup() + .addComponent(btnRegister, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(btnForgotPassword, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addComponent(btnConnect, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(btnCancel, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addGap(23, 23, 23)) ); lblFastConnect.getAccessibleContext().setAccessibleName("Fast connect to:"); @@ -768,7 +765,7 @@ public class ConnectDialog extends MageDialog { }//GEN-LAST:event_btnFind2findPublicServerActionPerformed private void connectXmageus(java.awt.event.ActionEvent evt) { - String serverAddress = "mtg.powersofwar.com"; + String serverAddress = "us.xmage.today"; this.txtServer.setText(serverAddress); this.txtPort.setText("17171"); // Update userName and password according to the chosen server. @@ -777,7 +774,7 @@ public class ConnectDialog extends MageDialog { } private void connectBeta(java.awt.event.ActionEvent evt) { - String serverAddress = "xmage.today"; + String serverAddress = "beta.xmage.today"; this.txtServer.setText(serverAddress); this.txtPort.setText("17171"); // Update userName and password according to the chosen server. 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 503f59e6b6..a99ef8bec2 100644 --- a/Mage.Client/src/main/java/mage/client/dialog/NewTableDialog.java +++ b/Mage.Client/src/main/java/mage/client/dialog/NewTableDialog.java @@ -637,6 +637,7 @@ public class NewTableDialog extends MageDialog { case "Variant Magic - Commander": case "Variant Magic - Duel Commander": case "Variant Magic - MTGO 1v1 Commander": + case "Variant Magic - Centurion Commander": case "Variant Magic - Penny Dreadful Commander": if (!options.getGameType().startsWith("Commander")) { JOptionPane.showMessageDialog(MageFrame.getDesktop(), "Deck type Commander needs also a Commander game type", "Error", JOptionPane.ERROR_MESSAGE); @@ -683,6 +684,7 @@ public class NewTableDialog extends MageDialog { if (!options.getDeckType().equals("Variant Magic - Commander") && !options.getDeckType().equals("Variant Magic - Duel Commander") && !options.getDeckType().equals("Variant Magic - MTGO 1v1 Commander") + && !options.getDeckType().equals("Variant Magic - Centurion Commander") && !options.getDeckType().equals("Variant Magic - Freeform Commander") && !options.getDeckType().equals("Variant Magic - Penny Dreadful Commander")) { JOptionPane.showMessageDialog(MageFrame.getDesktop(), "Deck type Commander needs also a Commander game type", "Error", JOptionPane.ERROR_MESSAGE); diff --git a/Mage.Client/src/main/java/mage/client/table/TablesPanel.form b/Mage.Client/src/main/java/mage/client/table/TablesPanel.form index 41e7b06a4c..14518523fd 100644 --- a/Mage.Client/src/main/java/mage/client/table/TablesPanel.form +++ b/Mage.Client/src/main/java/mage/client/table/TablesPanel.form @@ -366,6 +366,20 @@ + + + + + + + + + + + + + + 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 5d01790591..62326c77a8 100644 --- a/Mage.Client/src/main/java/mage/client/table/TablesPanel.java +++ b/Mage.Client/src/main/java/mage/client/table/TablesPanel.java @@ -333,7 +333,7 @@ public class TablesPanel extends javax.swing.JPanel { filterButtons = new JToggleButton[]{btnStateWaiting, btnStateActive, btnStateFinished, btnTypeMatch, btnTypeTourneyConstructed, btnTypeTourneyLimited, btnFormatBlock, btnFormatStandard, btnFormatModern, btnFormatLegacy, btnFormatVintage, btnFormatPremodern, btnFormatCommander, btnFormatTinyLeader, btnFormatLimited, btnFormatOther, - btnSkillBeginner, btnSkillCasual, btnSkillSerious, btnRated, btnUnrated, btnOpen, btnPassword, btnFormatOathbreaker}; + btnSkillBeginner, btnSkillCasual, btnSkillSerious, btnRated, btnUnrated, btnOpen, btnPassword, btnFormatOathbreaker, btnFormatPioneer}; JComponent[] components = new JComponent[]{chatPanelMain, jSplitPane1, jScrollPaneTablesActive, jScrollPaneTablesFinished, jPanelTop, jPanelTables}; for (JComponent component : components) { @@ -802,6 +802,9 @@ public class TablesPanel extends javax.swing.JPanel { if (btnFormatModern.isSelected()) { formatFilterList.add(RowFilter.regexFilter("^Constructed - Modern", TablesTableModel.COLUMN_DECK_TYPE)); } + if (btnFormatPioneer.isSelected()) { + formatFilterList.add(RowFilter.regexFilter("^Constructed - Pioneer", TablesTableModel.COLUMN_DECK_TYPE)); + } if (btnFormatLegacy.isSelected()) { formatFilterList.add(RowFilter.regexFilter("^Constructed - Legacy", TablesTableModel.COLUMN_DECK_TYPE)); } @@ -812,7 +815,7 @@ public class TablesPanel extends javax.swing.JPanel { formatFilterList.add(RowFilter.regexFilter("^Constructed - Premodern", TablesTableModel.COLUMN_DECK_TYPE)); } if (btnFormatCommander.isSelected()) { - formatFilterList.add(RowFilter.regexFilter("^Commander|^Duel Commander|^Penny Dreadful Commander|^Freeform Commander|^MTGO 1v1 Commander|^Duel Brawl|^Brawl", TablesTableModel.COLUMN_DECK_TYPE)); + formatFilterList.add(RowFilter.regexFilter("^Commander|^Duel Commander|^Centurion Commander|^Penny Dreadful Commander|^Freeform Commander|^MTGO 1v1 Commander|^Duel Brawl|^Brawl", TablesTableModel.COLUMN_DECK_TYPE)); } if (btnFormatTinyLeader.isSelected()) { formatFilterList.add(RowFilter.regexFilter("^Tiny", TablesTableModel.COLUMN_DECK_TYPE)); @@ -965,6 +968,7 @@ public class TablesPanel extends javax.swing.JPanel { btnFormatBlock = new javax.swing.JToggleButton(); btnFormatStandard = new javax.swing.JToggleButton(); btnFormatModern = new javax.swing.JToggleButton(); + btnFormatPioneer = new javax.swing.JToggleButton(); btnFormatLegacy = new javax.swing.JToggleButton(); btnFormatVintage = new javax.swing.JToggleButton(); btnFormatPremodern = new javax.swing.JToggleButton(); @@ -1256,6 +1260,20 @@ public class TablesPanel extends javax.swing.JPanel { }); filterBar2.add(btnFormatModern); + btnFormatPioneer.setSelected(true); + btnFormatPioneer.setText("Pioneer"); + btnFormatPioneer.setToolTipText("Pioneer format."); + btnFormatPioneer.setFocusPainted(false); + btnFormatPioneer.setFocusable(false); + btnFormatPioneer.setRequestFocusEnabled(false); + btnFormatPioneer.setVerifyInputWhenFocusTarget(false); + btnFormatPioneer.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + btnFilterActionPerformed(evt); + } + }); + filterBar2.add(btnFormatPioneer); + btnFormatLegacy.setSelected(true); btnFormatLegacy.setText("Legacy"); btnFormatLegacy.setToolTipText("Legacy format."); @@ -1670,6 +1688,7 @@ public class TablesPanel extends javax.swing.JPanel { private javax.swing.JToggleButton btnFormatLegacy; private javax.swing.JToggleButton btnFormatLimited; private javax.swing.JToggleButton btnFormatModern; + private javax.swing.JToggleButton btnFormatPioneer; private javax.swing.JToggleButton btnFormatOathbreaker; private javax.swing.JToggleButton btnFormatOther; private javax.swing.JToggleButton btnFormatPremodern; diff --git a/Mage.Client/src/main/java/mage/client/util/sets/ConstructedFormats.java b/Mage.Client/src/main/java/mage/client/util/sets/ConstructedFormats.java index 37d050fc46..854f6d5195 100644 --- a/Mage.Client/src/main/java/mage/client/util/sets/ConstructedFormats.java +++ b/Mage.Client/src/main/java/mage/client/util/sets/ConstructedFormats.java @@ -20,6 +20,7 @@ public final class ConstructedFormats { public static final String STANDARD = "- Standard"; public static final String EXTENDED = "- Extended"; public static final String FRONTIER = "- Frontier"; + public static final String PIONEER = "- Pioneer"; public static final String MODERN = "- Modern"; public static final String VINTAGE_LEGACY = "- Vintage / Legacy"; public static final String JOKE = "- Joke Sets"; @@ -29,6 +30,7 @@ public final class ConstructedFormats { // Attention -Month is 0 Based so Feb = 1 for example. // private static final Date extendedDate = new GregorianCalendar(2009, 7, 20).getTime(); private static final Date frontierDate = new GregorianCalendar(2014, 6, 17).getTime(); + private static final Date pioneerDate = new GregorianCalendar(2012, 10, 5).getTime(); private static final Date modernDate = new GregorianCalendar(2003, 6, 20).getTime(); // for all sets just return empty list @@ -82,6 +84,7 @@ public final class ConstructedFormats { underlyingSetCodesPerFormat.put(STANDARD, new ArrayList<>()); underlyingSetCodesPerFormat.put(EXTENDED, new ArrayList<>()); underlyingSetCodesPerFormat.put(FRONTIER, new ArrayList<>()); + underlyingSetCodesPerFormat.put(PIONEER, new ArrayList<>()); underlyingSetCodesPerFormat.put(MODERN, new ArrayList<>()); underlyingSetCodesPerFormat.put(VINTAGE_LEGACY, new ArrayList<>()); underlyingSetCodesPerFormat.put(JOKE, new ArrayList<>()); @@ -134,6 +137,11 @@ public final class ConstructedFormats { underlyingSetCodesPerFormat.get(FRONTIER).add(set.getCode()); } + // frontier + if (set.getType().isStandardLegal() && set.getReleaseDate().after(pioneerDate)) { + underlyingSetCodesPerFormat.get(PIONEER).add(set.getCode()); + } + // modern if (set.getType().isModernLegal() && set.getReleaseDate().after(modernDate)) { underlyingSetCodesPerFormat.get(MODERN).add(set.getCode()); @@ -251,6 +259,7 @@ public final class ConstructedFormats { formats.add(0, JOKE); formats.add(0, VINTAGE_LEGACY); formats.add(0, MODERN); + formats.add(0, PIONEER); formats.add(0, FRONTIER); formats.add(0, EXTENDED); formats.add(0, STANDARD); diff --git a/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/ScryfallImageSupportCards.java b/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/ScryfallImageSupportCards.java index 213b653630..31e5cd0eb2 100644 --- a/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/ScryfallImageSupportCards.java +++ b/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/ScryfallImageSupportCards.java @@ -23,7 +23,9 @@ public class ScryfallImageSupportCards { put("EURO", "pelp"). put("GPX", "pgpx"). put("MED", "me1"). - put("MEDM", "med").build(); + put("MEDM", "med"). + put("CELD", "eld"). // scryfall moved ELD and CELD cards in one set, but card numbers are different + build(); private static final Set supportedSets = new ArraySet() { { @@ -240,6 +242,7 @@ public class ScryfallImageSupportCards { add("M20"); add("C19"); add("ELD"); + add("CELD"); // add("EURO"); add("GPX"); diff --git a/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/ScryfallImageSupportTokens.java b/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/ScryfallImageSupportTokens.java index b201eed797..6632fab3ca 100644 --- a/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/ScryfallImageSupportTokens.java +++ b/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/ScryfallImageSupportTokens.java @@ -228,8 +228,8 @@ public class ScryfallImageSupportTokens { put("MH1/Squirrel", "https://api.scryfall.com/cards/tmh1/15/en?format=image"); put("MH1/Emblem Wrenn and Six", "https://api.scryfall.com/cards/tmh1/21/en?format=image"); put("MH1/Zombie", "https://api.scryfall.com/cards/tmh1/7/en?format=image"); - - //M19 + + // M19 put("M19/Emblem Ajani, Adversary of Tyrants", "https://api.scryfall.com/cards/tm19/15/en?format=image"); put("M19/Angel", "https://api.scryfall.com/cards/tm19/1/en?format=image"); put("M19/Avatar", "https://api.scryfall.com/cards/tm19/2/en?format=image"); @@ -247,7 +247,7 @@ public class ScryfallImageSupportTokens { put("M19/Thopter", "https://api.scryfall.com/cards/tm19/14/en?format=image"); put("M19/Emblem Vivien Reid", "https://api.scryfall.com/cards/tm19/17/en?format=image"); put("M19/Zombie", "https://api.scryfall.com/cards/tm19/8/en?format=image"); - + // M20 put("M20/Ajani's Pridemate", "https://api.scryfall.com/cards/tm20/1/en?format=image"); put("M20/Emblem Chandra, Awakened Inferno", "https://api.scryfall.com/cards/tm20/11/en?format=image"); @@ -261,8 +261,8 @@ public class ScryfallImageSupportTokens { put("M20/Treasure", "https://api.scryfall.com/cards/tm20/10/en?format=image"); put("M20/Wolf", "https://api.scryfall.com/cards/tm20/8/en?format=image"); put("M20/Zombie", "https://api.scryfall.com/cards/tm20/6/en?format=image"); - - //C18 + + // C18 put("C18/Angel", "https://api.scryfall.com/cards/tc18/3/en?format=image"); put("C18/Cat Warrior", "https://api.scryfall.com/cards/tc18/15/en?format=image"); put("C18/Cat", "https://api.scryfall.com/cards/tc18/5/en?format=image"); @@ -312,6 +312,26 @@ public class ScryfallImageSupportTokens { put("C19/Zombie/1", "https://api.scryfall.com/cards/tc19/11/en?format=image"); put("C19/Zombie/2", "https://api.scryfall.com/cards/tc19/10/en?format=image"); + // ELD + put("ELD/Bear", "https://api.scryfall.com/cards/teld/8/en?format=image"); + put("ELD/Boar", "https://api.scryfall.com/cards/teld/9/en?format=image"); + put("ELD/Dwarf", "https://api.scryfall.com/cards/teld/7/en?format=image"); + put("ELD/Faerie", "https://api.scryfall.com/cards/teld/5/en?format=image"); + put("ELD/Food/1", "https://api.scryfall.com/cards/teld/15/en?format=image"); + put("ELD/Food/2", "https://api.scryfall.com/cards/teld/16/en?format=image"); + put("ELD/Food/3", "https://api.scryfall.com/cards/teld/17/en?format=image"); + put("ELD/Food/4", "https://api.scryfall.com/cards/teld/18/en?format=image"); + put("ELD/Emblem Garruk, Cursed Huntsman", "https://api.scryfall.com/cards/teld/19/en?format=image"); + put("ELD/Giant", "https://api.scryfall.com/cards/teld/10/en?format=image"); + put("ELD/Goat", "https://api.scryfall.com/cards/teld/1/en?format=image"); + put("ELD/Human Cleric", "https://api.scryfall.com/cards/teld/11/en?format=image"); + put("ELD/Human Rogue", "https://api.scryfall.com/cards/teld/12/en?format=image"); + put("ELD/Human Warrior", "https://api.scryfall.com/cards/teld/13/en?format=image"); + put("ELD/Human", "https://api.scryfall.com/cards/teld/2/en?format=image"); + put("ELD/Knight", "https://api.scryfall.com/cards/teld/3/en?format=image"); + put("ELD/Mouse", "https://api.scryfall.com/cards/teld/4/en?format=image"); + put("ELD/Rat", "https://api.scryfall.com/cards/teld/6/en?format=image"); + put("ELD/Wolf", "https://api.scryfall.com/cards/teld/14/en?format=image"); // generate supported sets supportedSets.clear(); diff --git a/Mage.Client/src/main/resources/card-pictures-tok.txt b/Mage.Client/src/main/resources/card-pictures-tok.txt index 106c5083ed..01c97d879e 100644 --- a/Mage.Client/src/main/resources/card-pictures-tok.txt +++ b/Mage.Client/src/main/resources/card-pictures-tok.txt @@ -100,6 +100,7 @@ |Generate|EMBLEM:DOM|Jaya Ballard||Emblem Jaya Ballard|JayaBallardEmblem| |Generate|EMBLEM:DOM|Teferi, Hero of Dominaria||Emblem Teferi|TeferiHeroOfDominariaEmblem| |Generate|EMBLEM:AER|Tezzeret the Schemer||Emblem Tezzeret|TezzeretTheSchemerEmblem| +|Generate|EMBLEM:ELD|Garruk, Cursed Huntsman||Emblem Garruk|GarrukCursedHuntsmanEmblem| |Generate|PLANE:PCA|Plane - Academy At Tolaria West|||AcademyAtTolariaWestPlane| |Generate|PLANE:PCA|Plane - Agyrem|||AgyremPlane| |Generate|PLANE:PCA|Plane - Akoum|||AkoumPlane| @@ -1319,3 +1320,21 @@ |Generate|TOK:M20|Treasure|||TreasureToken| |Generate|TOK:M20|Wolf|||WolfToken| |Generate|TOK:M20|Zombie|||ZombieToken| +|Generate|TOK:ELD|Bear|||BearToken| +|Generate|TOK:ELD|Boar|||WolfsQuarryToken| +|Generate|TOK:ELD|Dwarf|||DwarfToken| +|Generate|TOK:ELD|Faerie|||FaerieToken| +|Generate|TOK:ELD|Food|1||FoodToken| +|Generate|TOK:ELD|Food|2||FoodToken| +|Generate|TOK:ELD|Food|3||FoodToken| +|Generate|TOK:ELD|Food|4||FoodToken| +|Generate|TOK:ELD|Giant|||GiantOpportunityToken| +|Generate|TOK:ELD|Goat|||GoatToken| +|Generate|TOK:ELD|Human|||HumanToken| +|Generate|TOK:ELD|Human Cleric|||OutlawsMerrimentClericToken| +|Generate|TOK:ELD|Human Rogue|||OutlawsMerrimentRogueToken| +|Generate|TOK:ELD|Human Warrior|||OutlawsMerrimentWarriorToken| +|Generate|TOK:ELD|Knight|||KnightToken| +|Generate|TOK:ELD|Mouse|||MouseToken| +|Generate|TOK:ELD|Rat|||RatToken| +|Generate|TOK:ELD|Wolf|||GarrukCursedHuntsmanToken| \ No newline at end of file diff --git a/Mage.Common/pom.xml b/Mage.Common/pom.xml index 2791a46b63..2aa92f8cbe 100644 --- a/Mage.Common/pom.xml +++ b/Mage.Common/pom.xml @@ -7,7 +7,7 @@ org.mage mage-root - 1.4.37 + 1.4.39 mage-common diff --git a/Mage.Common/src/main/java/mage/utils/MageVersion.java b/Mage.Common/src/main/java/mage/utils/MageVersion.java index 330229ae5f..1a2ed5a8a8 100644 --- a/Mage.Common/src/main/java/mage/utils/MageVersion.java +++ b/Mage.Common/src/main/java/mage/utils/MageVersion.java @@ -11,11 +11,11 @@ public class MageVersion implements Serializable, Comparable { public static final int MAGE_VERSION_MAJOR = 1; public static final int MAGE_VERSION_MINOR = 4; - public static final int MAGE_VERSION_PATCH = 37; + public static final int MAGE_VERSION_PATCH = 39; public static final String MAGE_EDITION_INFO = ""; // set "-beta" for 1.4.32-betaV0 - public static final String MAGE_VERSION_MINOR_PATCH = "V4"; // default + public static final String MAGE_VERSION_MINOR_PATCH = "V0"; // default // strict mode - private static final boolean MAGE_VERSION_MINOR_PATCH_MUST_BE_SAME = true; // set true on uncompatible github changes, set false after new major release (after MAGE_VERSION_PATCH changes) + private static final boolean MAGE_VERSION_MINOR_PATCH_MUST_BE_SAME = false; // set true on uncompatible github changes, set false after new major release (after MAGE_VERSION_PATCH changes) public static final boolean MAGE_VERSION_SHOW_BUILD_TIME = true; private final int major; diff --git a/Mage.Plugins/Mage.Counter.Plugin/pom.xml b/Mage.Plugins/Mage.Counter.Plugin/pom.xml index 451e8c6767..eb0d6042d5 100644 --- a/Mage.Plugins/Mage.Counter.Plugin/pom.xml +++ b/Mage.Plugins/Mage.Counter.Plugin/pom.xml @@ -7,7 +7,7 @@ org.mage mage-plugins - 1.4.37 + 1.4.39 mage-counter-plugin diff --git a/Mage.Plugins/pom.xml b/Mage.Plugins/pom.xml index 130037cdfc..f670b9ff44 100644 --- a/Mage.Plugins/pom.xml +++ b/Mage.Plugins/pom.xml @@ -7,7 +7,7 @@ org.mage mage-root - 1.4.37 + 1.4.39 mage-plugins diff --git a/Mage.Server.Console/pom.xml b/Mage.Server.Console/pom.xml index 13a2ee42eb..95edc3ef3e 100644 --- a/Mage.Server.Console/pom.xml +++ b/Mage.Server.Console/pom.xml @@ -6,7 +6,7 @@ org.mage mage-root - 1.4.37 + 1.4.39 mage.server.console diff --git a/Mage.Server.Plugins/Mage.Deck.Constructed/pom.xml b/Mage.Server.Plugins/Mage.Deck.Constructed/pom.xml index 584bfe3d3f..76ddbeb0c6 100644 --- a/Mage.Server.Plugins/Mage.Deck.Constructed/pom.xml +++ b/Mage.Server.Plugins/Mage.Deck.Constructed/pom.xml @@ -7,7 +7,7 @@ org.mage mage-server-plugins - 1.4.37 + 1.4.39 mage-deck-constructed diff --git a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/AusHighlander.java b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/AusHighlander.java index 574bfec565..a66fdab991 100644 --- a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/AusHighlander.java +++ b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/AusHighlander.java @@ -29,7 +29,6 @@ public class AusHighlander extends Constructed { pointMap.put("Sol Ring", 3); pointMap.put("Time Walk", 3); pointMap.put("Vampiric Tutor", 3); - pointMap.put("Yawgmoth's Will", 3); pointMap.put("Channel", 2); pointMap.put("Dig Through Time", 2); pointMap.put("Library of Alexandria", 2); @@ -37,13 +36,16 @@ public class AusHighlander extends Constructed { pointMap.put("Mind Twist", 2); pointMap.put("Mystical Tutor", 2); pointMap.put("Protean Hulk", 2); + pointMap.put("Strip Mine", 2); pointMap.put("Tinker", 2); pointMap.put("Tolarian Academy", 2); pointMap.put("Treasure Cruise", 2); + pointMap.put("True-Name Nemesis", 2); pointMap.put("Balance", 1); pointMap.put("Birthing Pod", 1); pointMap.put("Crop Rotation", 1); pointMap.put("Dark Petition", 1); + pointMap.put("Doomsday", 1); pointMap.put("Enlightened Tutor", 1); pointMap.put("Fastbond", 1); pointMap.put("Flash", 1); @@ -57,25 +59,25 @@ public class AusHighlander extends Constructed { pointMap.put("Lim-Dul's Vault", 1); pointMap.put("Mana Drain", 1); pointMap.put("Mana Vault", 1); - pointMap.put("Memory Jar", 1); pointMap.put("Merchant Scroll", 1); pointMap.put("Mishra's Workshop", 1); pointMap.put("Natural Order", 1); pointMap.put("Oath of Druids", 1); pointMap.put("Personal Tutor", 1); + pointMap.put("Scheming Symmetry", 1); pointMap.put("Sensei's Divining Top", 1); pointMap.put("Skullclamp", 1); pointMap.put("Snapcaster Mage", 1); pointMap.put("Stoneforge Mystic", 1); - pointMap.put("Strip Mine", 1); pointMap.put("Survival of the Fittest", 1); pointMap.put("Tainted Pact", 1); + pointMap.put("Tendrils of Agony", 1); pointMap.put("Time Spiral", 1); pointMap.put("Timetwister", 1); - pointMap.put("True-Name Nemesis", 1); pointMap.put("Umezawa's Jitte", 1); pointMap.put("Wasteland", 1); pointMap.put("Yawgmoth's Bargain", 1); + pointMap.put("Yawgmoth's Will", 1); } public AusHighlander() { @@ -133,14 +135,7 @@ public class AusHighlander extends Constructed { Map counts = new HashMap<>(); countCards(counts, deck.getCards()); countCards(counts, deck.getSideboard()); - for (Map.Entry entry : counts.entrySet()) { - if (entry.getValue() > 1) { - if (!basicLandNames.contains(entry.getKey()) && !anyNumberCardsAllowed.contains(entry.getKey())) { - invalid.put(entry.getKey(), "Too many: " + entry.getValue()); - valid = false; - } - } - } + valid = checkCounts(1, counts) && valid; int totalPoints = 0; for (Map.Entry entry : counts.entrySet()) { diff --git a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Brawl.java b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Brawl.java index 8b1feca862..2a3c502b68 100644 --- a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Brawl.java +++ b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Brawl.java @@ -22,8 +22,6 @@ public class Brawl extends Constructed { // Copy of standard sets setCodes.addAll(Standard.makeLegalSets()); - banned.add("Baral, Chief of Compliance"); - banned.add("Smuggler's Copter"); banned.add("Sorcerous Spyglass"); } @@ -49,14 +47,7 @@ public class Brawl extends Constructed { Map counts = new HashMap<>(); countCards(counts, deck.getCards()); countCards(counts, deck.getSideboard()); - for (Map.Entry entry : counts.entrySet()) { - if (entry.getValue() > 1) { - if (!basicLandNames.contains(entry.getKey()) && !anyNumberCardsAllowed.contains(entry.getKey())) { - invalid.put(entry.getKey(), "Too many: " + entry.getValue()); - valid = false; - } - } - } + valid = checkCounts(1, counts) && valid; for (String bannedCard : banned) { if (counts.containsKey(bannedCard)) { diff --git a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/CanadianHighlander.java b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/CanadianHighlander.java index 527cbbead6..89f03d1acb 100644 --- a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/CanadianHighlander.java +++ b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/CanadianHighlander.java @@ -20,7 +20,8 @@ public class CanadianHighlander extends Constructed { pointMap.put("Balance", 1); pointMap.put("Birthing Pod", 2); pointMap.put("Black Lotus", 7); - pointMap.put("Demonic Tutor", 3); + pointMap.put("Crop Rotation", 1); + pointMap.put("Demonic Tutor", 4); pointMap.put("Dig Through Time", 1); pointMap.put("Enlightened Tutor", 1); pointMap.put("Flash", 6); @@ -28,7 +29,7 @@ public class CanadianHighlander extends Constructed { pointMap.put("Imperial Seal", 1); pointMap.put("Intuition", 1); pointMap.put("Library of Alexandria", 1); - pointMap.put("Mana Crypt", 3); + pointMap.put("Mana Crypt", 4); pointMap.put("Mana Drain", 1); pointMap.put("Mana Vault", 1); pointMap.put("Merchant Scroll", 1); @@ -41,7 +42,7 @@ public class CanadianHighlander extends Constructed { pointMap.put("Mystical Tutor", 2); pointMap.put("Natural Order", 4); pointMap.put("Protean Hulk", 3); - pointMap.put("Sol Ring", 3); + pointMap.put("Sol Ring", 4); pointMap.put("Spellseeker", 1); pointMap.put("Stoneforge Mystic", 1); pointMap.put("Strip Mine", 2); @@ -88,14 +89,7 @@ public class CanadianHighlander extends Constructed { Map counts = new HashMap<>(); countCards(counts, deck.getCards()); countCards(counts, deck.getSideboard()); - for (Map.Entry entry : counts.entrySet()) { - if (entry.getValue() > 1) { - if (!basicLandNames.contains(entry.getKey()) && !anyNumberCardsAllowed.contains(entry.getKey())) { - invalid.put(entry.getKey(), "Too many: " + entry.getValue()); - valid = false; - } - } - } + valid = checkCounts(1, counts) && valid; int allowedPoints = 10; int totalPoints = 0; diff --git a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/CenturionCommander.java b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/CenturionCommander.java new file mode 100644 index 0000000000..e66990b5af --- /dev/null +++ b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/CenturionCommander.java @@ -0,0 +1,86 @@ + +package mage.deck; + +/** + * + * @author andreacosta + */ +public class CenturionCommander extends Commander { + + public CenturionCommander() { + super("Centurion Commander"); + banned.add("Ancestral Recall"); + banned.add("Ancient Tomb"); + banned.add("Back to Basic"); + banned.add("Balance"); + banned.add("Bazaar of Baghdad"); + banned.add("Black Lotus"); + banned.add("Cataclysm"); + banned.add("Channel"); + banned.add("Chaos Orb"); + banned.add("Chrome Mox"); + banned.add("Demonic Tutor"); + banned.add("Dig Through Time"); + banned.add("Emrakul, the Aeons Torn"); + banned.add("Emrakul, the Promised End"); + banned.add("Entomb"); + banned.add("Erayo, Soratami Ascendant"); + banned.add("Falling Star"); + banned.add("Fastbond"); + banned.add("Food Chain"); + banned.add("Gaea’s Cradle"); + banned.add("Gifts Ungiven"); + banned.add("Grim Monolith"); + banned.add("Grindstone"); + banned.add("Hermit Druid"); + banned.add("High Tide"); + banned.add("Humility"); + banned.add("Imperial Seal"); + banned.add("Karakas"); + banned.add("Library of Alexandria"); + banned.add("Mana Crypt"); + banned.add("Mana Drain"); + banned.add("Mana Vault"); + banned.add("Mishra’s Workshop"); + banned.add("Mind Twist"); + banned.add("Mox Diamond"); + banned.add("Mox Emerald"); + banned.add("Mox Jet"); + banned.add("Mox Pearl"); + banned.add("Mox Ruby"); + banned.add("Mox Sapphire"); + banned.add("Mystical Tutor"); + banned.add("Natural Order"); + banned.add("Necropotence"); + banned.add("Oath of Druids"); + banned.add("Protean Hulk"); + banned.add("Sensei’s Diving Top"); + banned.add("Serra Ascendant"); + banned.add("Sharazad"); + banned.add("Survival of the Fittest"); + banned.add("Sol Ring"); + banned.add("Strip Mine"); + banned.add("The Tabernacle at Pendrell Vale"); + banned.add("Time Vault"); + banned.add("Time Walk"); + banned.add("Tinker"); + banned.add("Tolarian Academy"); + banned.add("Treasure Cruise"); + banned.add("Vampiric Tutor"); + banned.add("Vanishing"); + banned.add("Winter Orb"); + banned.add("Yawgmoth’s Bargain"); + + bannedCommander.add("Baral, Chief of Compliance"); + bannedCommander.add("Derevi, Empyrial Tactician"); + bannedCommander.add("Edgar Markov"); + bannedCommander.add("Kess, Dissident Mage"); + bannedCommander.add("Rofellos, Llanowar Emissary"); + + bannedPartner.add("Rowan Kenrith"); + bannedPartner.add("Tymna the Weaver"); + bannedPartner.add("Will Kenrith"); + bannedPartner.add("Vial Smasher The Fierce"); + } + +} diff --git a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Commander.java b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Commander.java index d9fcf98cd2..8930973535 100644 --- a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Commander.java +++ b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Commander.java @@ -21,7 +21,8 @@ import java.util.*; */ public class Commander extends Constructed { - protected List bannedCommander = new ArrayList<>(); + protected final List bannedCommander = new ArrayList<>(); + protected final List bannedPartner = new ArrayList<>(); protected boolean partnerAllowed = true; public Commander() { @@ -99,14 +100,7 @@ public class Commander extends Constructed { Map counts = new HashMap<>(); countCards(counts, deck.getCards()); countCards(counts, deck.getSideboard()); - for (Map.Entry entry : counts.entrySet()) { - if (entry.getValue() > 1) { - if (!basicLandNames.contains(entry.getKey()) && !anyNumberCardsAllowed.contains(entry.getKey())) { - invalid.put(entry.getKey(), "Too many: " + entry.getValue()); - valid = false; - } - } - } + valid = checkCounts(1, counts) && valid; for (String bannedCard : banned) { if (counts.containsKey(bannedCard)) { @@ -136,18 +130,23 @@ public class Commander extends Constructed { invalid.put("Commander", "Commander invalid (" + commander.getName() + ')'); valid = false; } - if (deck.getSideboard().size() == 2 && !commander.getAbilities().contains(PartnerAbility.getInstance())) { - boolean partnersWith = false; - for (Ability ability : commander.getAbilities()) { - if (ability instanceof PartnerWithAbility - && commanderNames.contains(((PartnerWithAbility) ability).getPartnerName())) { - partnersWith = true; - break; + if (deck.getSideboard().size() == 2) { + if (commander.getAbilities().contains(PartnerAbility.getInstance())) { + if (bannedPartner.contains(commander.getName())) { + invalid.put("Commander", "Partner banned (" + commander.getName() + ')'); + valid = false; + } + } else { + boolean partnersWith = commander.getAbilities() + .stream() + .filter(PartnerWithAbility.class::isInstance) + .map(PartnerWithAbility.class::cast) + .map(PartnerWithAbility::getPartnerName) + .anyMatch(commanderNames::contains); + if (!partnersWith) { + invalid.put("Commander", "Commander without Partner (" + commander.getName() + ')'); + valid = false; } - } - if (!partnersWith) { - invalid.put("Commander", "Commander without Partner (" + commander.getName() + ')'); - valid = false; } } ManaUtil.collectColorIdentity(colorIdentity, commander.getColorIdentity()); diff --git a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/FreeformCommander.java b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/FreeformCommander.java index fc6da30d75..8a1a41c631 100644 --- a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/FreeformCommander.java +++ b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/FreeformCommander.java @@ -59,14 +59,7 @@ public class FreeformCommander extends Constructed { countCards(counts, deck.getCards()); countCards(counts, deck.getSideboard()); - for (Map.Entry entry : counts.entrySet()) { - if (entry.getValue() > 1) { - if (!basicLandNames.contains(entry.getKey()) && !anyNumberCardsAllowed.contains(entry.getKey())) { - invalid.put(entry.getKey(), "Too many: " + entry.getValue()); - valid = false; - } - } - } + valid = checkCounts(1, counts) && valid; if (deck.getSideboard().isEmpty() || deck.getSideboard().size() > 2) { invalid.put("Commander", "Sideboard must contain only the commander(s)"); diff --git a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Oathbreaker.java b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Oathbreaker.java index 28231f41e7..b299afbaf6 100644 --- a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Oathbreaker.java +++ b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Oathbreaker.java @@ -52,7 +52,6 @@ public class Oathbreaker extends Vintage { banned.add("Painter's Servant"); banned.add("Panoptic Mirror"); banned.add("Primal Surge"); - banned.add("Recurring Nightmare"); banned.add("Saheeli, the Gifted"); banned.add("Sol Ring"); banned.add("Sundering Titan"); @@ -99,14 +98,7 @@ public class Oathbreaker extends Vintage { } } - for (Map.Entry entry : counts.entrySet()) { - if (entry.getValue() > 1) { - if (!basicLandNames.contains(entry.getKey()) && !anyNumberCardsAllowed.contains(entry.getKey())) { - invalid.put(entry.getKey(), "Too many: " + entry.getValue()); - valid = false; - } - } - } + valid = checkCounts(1, counts) && valid; Set commanderNames = new HashSet<>(); Set signatureSpells = new HashSet<>(); diff --git a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Pauper.java b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Pauper.java index beee09be79..f22eba8467 100644 --- a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Pauper.java +++ b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Pauper.java @@ -21,6 +21,7 @@ public class Pauper extends Constructed { rarities.add(Rarity.COMMON); rarities.add(Rarity.LAND); + banned.add("Arcum's Astrolabe"); banned.add("Cloud of Faeries"); banned.add("Cloudpost"); banned.add("Cranial Plating"); diff --git a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Pioneer.java b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Pioneer.java new file mode 100644 index 0000000000..fe7f1ebd42 --- /dev/null +++ b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Pioneer.java @@ -0,0 +1,34 @@ +package mage.deck; + +import mage.cards.ExpansionSet; +import mage.cards.Sets; +import mage.cards.decks.Constructed; + +import java.util.Date; +import java.util.GregorianCalendar; + +/** + * @author TheElk801 + */ +public class Pioneer extends Constructed { + + public Pioneer() { + super("Constructed - Pioneer"); + + Date cutoff = new GregorianCalendar(2012, 10, 5).getTime(); // M15 release date + for (ExpansionSet set : Sets.getInstance().values()) { + if (set.getSetType().isStandardLegal() && (set.getReleaseDate().after(cutoff) || set.getReleaseDate().equals(cutoff))) { + setCodes.add(set.getCode()); + } + } + + banned.add("Bloodstained Mire"); + banned.add("Flooded Strand"); + banned.add("Polluted Delta"); + banned.add("Windswept Heath"); + banned.add("Wooded Foothills"); + banned.add("Felidar Guardian"); + banned.add("Leyline of Abundance"); + banned.add("Oath of Nissa"); + } +} diff --git a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Premodern.java b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Premodern.java index 138a97fe9e..a73be72a95 100644 --- a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Premodern.java +++ b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Premodern.java @@ -54,7 +54,6 @@ public class Premodern extends Constructed { banned.add("Entomb"); banned.add("Flash"); banned.add("Force of Will"); - banned.add("Frantic Search"); banned.add("Goblin Recruiter"); banned.add("Grim Monolith"); banned.add("Jeweled Bird"); @@ -76,5 +75,6 @@ public class Premodern extends Constructed { banned.add("Windfall"); banned.add("Worldgorger Dragon"); banned.add("Yawgmoth's Will"); + banned.add("Yawgmoth's Bargain"); } } diff --git a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Standard.java b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Standard.java index 6abe881da1..3c95dc7616 100644 --- a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Standard.java +++ b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Standard.java @@ -16,6 +16,8 @@ public class Standard extends Constructed { super("Constructed - Standard"); setCodes.addAll(makeLegalSets()); + + banned.add("Field of the Dead"); // since 2019-10-21 } private static boolean isFallSet(ExpansionSet set) { @@ -25,7 +27,7 @@ public class Standard extends Constructed { return set.getSetType() == SetType.EXPANSION && (cal.get(Calendar.MONTH) > 7); } - public static List makeLegalSets() { + static List makeLegalSets() { List codes = new ArrayList<>(); GregorianCalendar current = new GregorianCalendar(); List sets = new ArrayList(Sets.getInstance().values()); diff --git a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/TinyLeaders.java b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/TinyLeaders.java index a93db2a326..e136d33205 100644 --- a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/TinyLeaders.java +++ b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/TinyLeaders.java @@ -113,14 +113,7 @@ public class TinyLeaders extends Constructed { counts.put(deck.getName(), 1); // add the commander to the counts, so it can't be in the deck or sideboard again countCards(counts, deck.getCards()); countCards(counts, deck.getSideboard()); - for (Map.Entry entry : counts.entrySet()) { - if (entry.getValue() > 1) { - if (!basicLandNames.contains(entry.getKey()) && !anyNumberCardsAllowed.contains(entry.getKey())) { - invalid.put(entry.getKey(), "Too many: " + entry.getValue()); - valid = false; - } - } - } + valid = checkCounts(1, counts) && valid; for (String bannedCard : banned) { if (counts.containsKey(bannedCard)) { diff --git a/Mage.Server.Plugins/Mage.Deck.Limited/pom.xml b/Mage.Server.Plugins/Mage.Deck.Limited/pom.xml index 3bc05c16a5..012723d4e4 100644 --- a/Mage.Server.Plugins/Mage.Deck.Limited/pom.xml +++ b/Mage.Server.Plugins/Mage.Deck.Limited/pom.xml @@ -7,7 +7,7 @@ org.mage mage-server-plugins - 1.4.37 + 1.4.39 mage-deck-limited diff --git a/Mage.Server.Plugins/Mage.Deck.Limited/src/mage/deck/Limited.java b/Mage.Server.Plugins/Mage.Deck.Limited/src/mage/deck/Limited.java index 30d32964e0..542f045045 100644 --- a/Mage.Server.Plugins/Mage.Deck.Limited/src/mage/deck/Limited.java +++ b/Mage.Server.Plugins/Mage.Deck.Limited/src/mage/deck/Limited.java @@ -3,6 +3,9 @@ package mage.deck; import mage.cards.decks.Deck; import mage.cards.decks.DeckValidator; +import java.util.HashMap; +import java.util.Map; + /** * @author BetaSteward_at_googlemail.com */ @@ -29,9 +32,15 @@ public class Limited extends DeckValidator { if (deck.getCards().size() < getDeckMinSize()) { invalid.put("Deck", "Must contain at least " + getDeckMinSize() + " cards: has only " + deck.getCards().size() + " cards"); valid = false; - + } + Map counts = new HashMap<>(); + countCards(counts, deck.getCards()); + for (Map.Entry entry : counts.entrySet()) { + if (entry.getValue() > 7 && entry.getKey().equals("Seven Dwarves")) { + invalid.put(entry.getKey(), "Too many: " + entry.getValue()); + valid = false; + } } return valid; } - } diff --git a/Mage.Server.Plugins/Mage.Game.BrawlDuel/pom.xml b/Mage.Server.Plugins/Mage.Game.BrawlDuel/pom.xml index ccd689bdb9..c439d1bfb7 100644 --- a/Mage.Server.Plugins/Mage.Game.BrawlDuel/pom.xml +++ b/Mage.Server.Plugins/Mage.Game.BrawlDuel/pom.xml @@ -7,7 +7,7 @@ org.mage mage-server-plugins - 1.4.37 + 1.4.39 mage-game-brawlduel diff --git a/Mage.Server.Plugins/Mage.Game.BrawlFreeForAll/pom.xml b/Mage.Server.Plugins/Mage.Game.BrawlFreeForAll/pom.xml index 361659397c..d1890b2c63 100644 --- a/Mage.Server.Plugins/Mage.Game.BrawlFreeForAll/pom.xml +++ b/Mage.Server.Plugins/Mage.Game.BrawlFreeForAll/pom.xml @@ -6,7 +6,7 @@ org.mage mage-server-plugins - 1.4.37 + 1.4.39 mage-game-brawlfreeforall diff --git a/Mage.Server.Plugins/Mage.Game.CanadianHighlanderDuel/pom.xml b/Mage.Server.Plugins/Mage.Game.CanadianHighlanderDuel/pom.xml index b45bc7a4c4..91de1f20e5 100644 --- a/Mage.Server.Plugins/Mage.Game.CanadianHighlanderDuel/pom.xml +++ b/Mage.Server.Plugins/Mage.Game.CanadianHighlanderDuel/pom.xml @@ -7,7 +7,7 @@ org.mage mage-server-plugins - 1.4.37 + 1.4.39 mage-game-canadianhighlanderduel diff --git a/Mage.Server.Plugins/Mage.Game.CommanderDuel/pom.xml b/Mage.Server.Plugins/Mage.Game.CommanderDuel/pom.xml index 00ff1eefa5..efca633d52 100644 --- a/Mage.Server.Plugins/Mage.Game.CommanderDuel/pom.xml +++ b/Mage.Server.Plugins/Mage.Game.CommanderDuel/pom.xml @@ -7,7 +7,7 @@ org.mage mage-server-plugins - 1.4.37 + 1.4.39 mage-game-commanderduel diff --git a/Mage.Server.Plugins/Mage.Game.CommanderDuel/src/mage/game/CommanderDuelMatch.java b/Mage.Server.Plugins/Mage.Game.CommanderDuel/src/mage/game/CommanderDuelMatch.java index f03473c6e2..a6008061ec 100644 --- a/Mage.Server.Plugins/Mage.Game.CommanderDuel/src/mage/game/CommanderDuelMatch.java +++ b/Mage.Server.Plugins/Mage.Game.CommanderDuel/src/mage/game/CommanderDuelMatch.java @@ -22,7 +22,7 @@ public class CommanderDuelMatch extends MatchImpl { startLife = 20; // Starting with the Commander 2016 update (on November 11th, 2016), Duel Commander will be played with 20 life points instead of 30. checkCommanderDamage = false; // since nov 16 duel commander uses no longer commander damage rule } - if (options.getDeckType().equals("Variant Magic - MTGO 1v1 Commander")) { + if (options.getDeckType().equals("Variant Magic - MTGO 1v1 Commander") || options.getDeckType().equals("Variant Magic - Centurion Commander")) { startLife = 30; } Mulligan mulligan = options.getMulliganType().getMulligan(options.getFreeMulligans()); diff --git a/Mage.Server.Plugins/Mage.Game.CommanderFreeForAll/pom.xml b/Mage.Server.Plugins/Mage.Game.CommanderFreeForAll/pom.xml index 0b56915db6..c346e6d407 100644 --- a/Mage.Server.Plugins/Mage.Game.CommanderFreeForAll/pom.xml +++ b/Mage.Server.Plugins/Mage.Game.CommanderFreeForAll/pom.xml @@ -6,7 +6,7 @@ org.mage mage-server-plugins - 1.4.37 + 1.4.39 mage-game-commanderfreeforall diff --git a/Mage.Server.Plugins/Mage.Game.FreeForAll/pom.xml b/Mage.Server.Plugins/Mage.Game.FreeForAll/pom.xml index 8570bbca78..35beea22a9 100644 --- a/Mage.Server.Plugins/Mage.Game.FreeForAll/pom.xml +++ b/Mage.Server.Plugins/Mage.Game.FreeForAll/pom.xml @@ -7,7 +7,7 @@ org.mage mage-server-plugins - 1.4.37 + 1.4.39 mage-game-freeforall diff --git a/Mage.Server.Plugins/Mage.Game.FreeformCommanderDuel/pom.xml b/Mage.Server.Plugins/Mage.Game.FreeformCommanderDuel/pom.xml index 07ef467487..aa5f263b55 100644 --- a/Mage.Server.Plugins/Mage.Game.FreeformCommanderDuel/pom.xml +++ b/Mage.Server.Plugins/Mage.Game.FreeformCommanderDuel/pom.xml @@ -7,7 +7,7 @@ org.mage mage-server-plugins - 1.4.37 + 1.4.39 mage-game-freeformcommanderduel diff --git a/Mage.Server.Plugins/Mage.Game.FreeformCommanderDuel/src/mage/game/FreeformCommanderDuelMatch.java b/Mage.Server.Plugins/Mage.Game.FreeformCommanderDuel/src/mage/game/FreeformCommanderDuelMatch.java index 57422d41be..f1d1ea7427 100644 --- a/Mage.Server.Plugins/Mage.Game.FreeformCommanderDuel/src/mage/game/FreeformCommanderDuelMatch.java +++ b/Mage.Server.Plugins/Mage.Game.FreeformCommanderDuel/src/mage/game/FreeformCommanderDuelMatch.java @@ -15,7 +15,7 @@ public class FreeformCommanderDuelMatch extends MatchImpl { @Override public void startGame() throws GameException { - int startLife = 20; + int startLife = 40; Mulligan mulligan = options.getMulliganType().getMulligan(options.getFreeMulligans()); FreeformCommanderDuel game = new FreeformCommanderDuel(options.getAttackOption(), options.getRange(), mulligan, startLife); diff --git a/Mage.Server.Plugins/Mage.Game.FreeformCommanderFreeForAll/pom.xml b/Mage.Server.Plugins/Mage.Game.FreeformCommanderFreeForAll/pom.xml index 656ea15123..ca94da6302 100644 --- a/Mage.Server.Plugins/Mage.Game.FreeformCommanderFreeForAll/pom.xml +++ b/Mage.Server.Plugins/Mage.Game.FreeformCommanderFreeForAll/pom.xml @@ -6,7 +6,7 @@ org.mage mage-server-plugins - 1.4.37 + 1.4.39 mage-game-freeformcommanderfreeforall diff --git a/Mage.Server.Plugins/Mage.Game.MomirDuel/pom.xml b/Mage.Server.Plugins/Mage.Game.MomirDuel/pom.xml index 3cb630bf94..722608ea31 100644 --- a/Mage.Server.Plugins/Mage.Game.MomirDuel/pom.xml +++ b/Mage.Server.Plugins/Mage.Game.MomirDuel/pom.xml @@ -7,7 +7,7 @@ org.mage mage-server-plugins - 1.4.37 + 1.4.39 mage-game-momirduel diff --git a/Mage.Server.Plugins/Mage.Game.MomirGame/pom.xml b/Mage.Server.Plugins/Mage.Game.MomirGame/pom.xml index 1d671df0b8..be6053a9f6 100644 --- a/Mage.Server.Plugins/Mage.Game.MomirGame/pom.xml +++ b/Mage.Server.Plugins/Mage.Game.MomirGame/pom.xml @@ -7,7 +7,7 @@ org.mage mage-server-plugins - 1.4.37 + 1.4.39 mage-game-momirfreeforall diff --git a/Mage.Server.Plugins/Mage.Game.OathbreakerDuel/pom.xml b/Mage.Server.Plugins/Mage.Game.OathbreakerDuel/pom.xml index ce0e6aec0c..aecfbc697e 100644 --- a/Mage.Server.Plugins/Mage.Game.OathbreakerDuel/pom.xml +++ b/Mage.Server.Plugins/Mage.Game.OathbreakerDuel/pom.xml @@ -6,7 +6,7 @@ org.mage mage-server-plugins - 1.4.37 + 1.4.39 mage-game-oathbreakerduel @@ -22,7 +22,7 @@ org.mage mage-game-oathbreakerfreeforall - 1.4.37 + 1.4.39 compile diff --git a/Mage.Server.Plugins/Mage.Game.OathbreakerFreeForAll/pom.xml b/Mage.Server.Plugins/Mage.Game.OathbreakerFreeForAll/pom.xml index 902049f967..4df90b35dd 100644 --- a/Mage.Server.Plugins/Mage.Game.OathbreakerFreeForAll/pom.xml +++ b/Mage.Server.Plugins/Mage.Game.OathbreakerFreeForAll/pom.xml @@ -7,7 +7,7 @@ org.mage mage-server-plugins - 1.4.37 + 1.4.39 mage-game-oathbreakerfreeforall diff --git a/Mage.Server.Plugins/Mage.Game.PennyDreadfulCommanderFreeForAll/pom.xml b/Mage.Server.Plugins/Mage.Game.PennyDreadfulCommanderFreeForAll/pom.xml index 942b63e711..2128a509e3 100644 --- a/Mage.Server.Plugins/Mage.Game.PennyDreadfulCommanderFreeForAll/pom.xml +++ b/Mage.Server.Plugins/Mage.Game.PennyDreadfulCommanderFreeForAll/pom.xml @@ -6,7 +6,7 @@ org.mage mage-server-plugins - 1.4.37 + 1.4.39 mage-game-pennydreadfulcommanderfreeforall diff --git a/Mage.Server.Plugins/Mage.Game.TinyLeadersDuel/pom.xml b/Mage.Server.Plugins/Mage.Game.TinyLeadersDuel/pom.xml index c38ad44ed2..890ce33b47 100644 --- a/Mage.Server.Plugins/Mage.Game.TinyLeadersDuel/pom.xml +++ b/Mage.Server.Plugins/Mage.Game.TinyLeadersDuel/pom.xml @@ -7,7 +7,7 @@ org.mage mage-server-plugins - 1.4.37 + 1.4.39 mage-game-tinyleadersduel diff --git a/Mage.Server.Plugins/Mage.Game.TwoPlayerDuel/pom.xml b/Mage.Server.Plugins/Mage.Game.TwoPlayerDuel/pom.xml index 8c99266e0e..2d2a71777d 100644 --- a/Mage.Server.Plugins/Mage.Game.TwoPlayerDuel/pom.xml +++ b/Mage.Server.Plugins/Mage.Game.TwoPlayerDuel/pom.xml @@ -7,7 +7,7 @@ org.mage mage-server-plugins - 1.4.37 + 1.4.39 mage-game-twoplayerduel diff --git a/Mage.Server.Plugins/Mage.Player.AI.DraftBot/pom.xml b/Mage.Server.Plugins/Mage.Player.AI.DraftBot/pom.xml index 92b12f18e1..4a3cb786af 100644 --- a/Mage.Server.Plugins/Mage.Player.AI.DraftBot/pom.xml +++ b/Mage.Server.Plugins/Mage.Player.AI.DraftBot/pom.xml @@ -7,7 +7,7 @@ org.mage mage-server-plugins - 1.4.37 + 1.4.39 mage-player-ai-draftbot diff --git a/Mage.Server.Plugins/Mage.Player.AI.MA/pom.xml b/Mage.Server.Plugins/Mage.Player.AI.MA/pom.xml index 4cd66cab77..28e3a25276 100644 --- a/Mage.Server.Plugins/Mage.Player.AI.MA/pom.xml +++ b/Mage.Server.Plugins/Mage.Player.AI.MA/pom.xml @@ -7,7 +7,7 @@ org.mage mage-server-plugins - 1.4.37 + 1.4.39 mage-player-ai-ma diff --git a/Mage.Server.Plugins/Mage.Player.AI/pom.xml b/Mage.Server.Plugins/Mage.Player.AI/pom.xml index 1faa9b3f92..cb99882986 100644 --- a/Mage.Server.Plugins/Mage.Player.AI/pom.xml +++ b/Mage.Server.Plugins/Mage.Player.AI/pom.xml @@ -7,7 +7,7 @@ org.mage mage-server-plugins - 1.4.37 + 1.4.39 mage-player-ai diff --git a/Mage.Server.Plugins/Mage.Player.AIMCTS/pom.xml b/Mage.Server.Plugins/Mage.Player.AIMCTS/pom.xml index b3a9a5435c..b34b687f76 100644 --- a/Mage.Server.Plugins/Mage.Player.AIMCTS/pom.xml +++ b/Mage.Server.Plugins/Mage.Player.AIMCTS/pom.xml @@ -7,7 +7,7 @@ org.mage mage-server-plugins - 1.4.37 + 1.4.39 mage-player-ai-mcts diff --git a/Mage.Server.Plugins/Mage.Player.AIMinimax/pom.xml b/Mage.Server.Plugins/Mage.Player.AIMinimax/pom.xml index 9ad8a71e08..5373478dc2 100644 --- a/Mage.Server.Plugins/Mage.Player.AIMinimax/pom.xml +++ b/Mage.Server.Plugins/Mage.Player.AIMinimax/pom.xml @@ -7,7 +7,7 @@ org.mage mage-server-plugins - 1.4.37 + 1.4.39 mage-player-aiminimax diff --git a/Mage.Server.Plugins/Mage.Player.Human/pom.xml b/Mage.Server.Plugins/Mage.Player.Human/pom.xml index 95e743bba2..e19fa52fda 100644 --- a/Mage.Server.Plugins/Mage.Player.Human/pom.xml +++ b/Mage.Server.Plugins/Mage.Player.Human/pom.xml @@ -7,7 +7,7 @@ org.mage mage-server-plugins - 1.4.37 + 1.4.39 mage-player-human diff --git a/Mage.Server.Plugins/Mage.Player.Human/src/mage/player/human/HumanPlayer.java b/Mage.Server.Plugins/Mage.Player.Human/src/mage/player/human/HumanPlayer.java index ff0a8289b5..d2c615b80b 100644 --- a/Mage.Server.Plugins/Mage.Player.Human/src/mage/player/human/HumanPlayer.java +++ b/Mage.Server.Plugins/Mage.Player.Human/src/mage/player/human/HumanPlayer.java @@ -708,7 +708,11 @@ public class HumanPlayer extends PlayerImpl { while (!abort) { prepareForResponse(game); if (!isExecutingMacro()) { - game.fireSelectTargetEvent(playerId, new MessageToClient(target.getMessage() + "\n Amount remaining:" + target.getAmountRemaining(), getRelatedObjectName(source, game)), + String selectedNames = target.getTargetedName(game); + game.fireSelectTargetEvent(playerId, new MessageToClient(target.getMessage() + + "
Amount remaining: " + target.getAmountRemaining() + + (selectedNames.isEmpty() ? "" : ", selected: " + selectedNames), + getRelatedObjectName(source, game)), target.possibleTargets(source == null ? null : source.getSourceId(), playerId, game), target.isRequired(source), getOptions(target, null)); @@ -717,8 +721,19 @@ public class HumanPlayer extends PlayerImpl { if (response.getUUID() != null) { if (target.canTarget(response.getUUID(), source, game)) { UUID targetId = response.getUUID(); - int amountSelected = getAmount(1, target.getAmountRemaining(), "Select amount", game); - target.addTarget(targetId, amountSelected, source, game); + MageObject targetObject = game.getObject(targetId); + + boolean removeMode = target.getTargets().contains(targetId) + && chooseUse(outcome, "What do you want to do with " + (targetObject != null ? targetObject.getLogName() : "target") + "?", "", + "Remove from selected", "Add extra amount", source, game); + + if (removeMode) { + target.remove(targetId); + } else { + int amountSelected = getAmount(1, target.getAmountRemaining(), "Select amount", game); + target.addTarget(targetId, amountSelected, source, game); + } + return true; } } else if (!target.isRequired(source)) { diff --git a/Mage.Server.Plugins/Mage.Tournament.BoosterDraft/pom.xml b/Mage.Server.Plugins/Mage.Tournament.BoosterDraft/pom.xml index 4cc129d679..ddc1ef1fea 100644 --- a/Mage.Server.Plugins/Mage.Tournament.BoosterDraft/pom.xml +++ b/Mage.Server.Plugins/Mage.Tournament.BoosterDraft/pom.xml @@ -7,7 +7,7 @@ org.mage mage-server-plugins - 1.4.37 + 1.4.39 mage-tournament-boosterdraft diff --git a/Mage.Server.Plugins/Mage.Tournament.Constructed/pom.xml b/Mage.Server.Plugins/Mage.Tournament.Constructed/pom.xml index 50eefc4743..df95dc6a2d 100644 --- a/Mage.Server.Plugins/Mage.Tournament.Constructed/pom.xml +++ b/Mage.Server.Plugins/Mage.Tournament.Constructed/pom.xml @@ -7,7 +7,7 @@ org.mage mage-server-plugins - 1.4.37 + 1.4.39 mage-tournament-constructed diff --git a/Mage.Server.Plugins/Mage.Tournament.Sealed/pom.xml b/Mage.Server.Plugins/Mage.Tournament.Sealed/pom.xml index 43727030e5..39ea1f9fe3 100644 --- a/Mage.Server.Plugins/Mage.Tournament.Sealed/pom.xml +++ b/Mage.Server.Plugins/Mage.Tournament.Sealed/pom.xml @@ -7,7 +7,7 @@ org.mage mage-server-plugins - 1.4.37 + 1.4.39 mage-tournament-sealed diff --git a/Mage.Server.Plugins/pom.xml b/Mage.Server.Plugins/pom.xml index 12c74d9094..e20f356938 100644 --- a/Mage.Server.Plugins/pom.xml +++ b/Mage.Server.Plugins/pom.xml @@ -7,7 +7,7 @@ org.mage mage-root - 1.4.37 + 1.4.39 mage-server-plugins diff --git a/Mage.Server/config/config.xml b/Mage.Server/config/config.xml index 625a01d39d..8f182580c1 100644 --- a/Mage.Server/config/config.xml +++ b/Mage.Server/config/config.xml @@ -149,6 +149,7 @@ + @@ -169,6 +170,7 @@ + diff --git a/Mage.Server/pom.xml b/Mage.Server/pom.xml index 47e27da1f6..3c4b3ea16f 100644 --- a/Mage.Server/pom.xml +++ b/Mage.Server/pom.xml @@ -6,7 +6,7 @@ org.mage mage-root - 1.4.37 + 1.4.39 mage-server @@ -91,7 +91,7 @@ org.apache.commons commons-compress - 1.18 + [1.19,) diff --git a/Mage.Server/release/config/config.xml b/Mage.Server/release/config/config.xml index 2584861224..75c5d943a0 100644 --- a/Mage.Server/release/config/config.xml +++ b/Mage.Server/release/config/config.xml @@ -143,6 +143,7 @@ + @@ -163,6 +164,7 @@ + diff --git a/Mage.Sets/pom.xml b/Mage.Sets/pom.xml index 185cde6f19..a91e4de445 100644 --- a/Mage.Sets/pom.xml +++ b/Mage.Sets/pom.xml @@ -7,7 +7,7 @@ org.mage mage-root - 1.4.37 + 1.4.39 mage-sets diff --git a/Mage.Sets/src/mage/cards/a/AboshanCephalidEmperor.java b/Mage.Sets/src/mage/cards/a/AboshanCephalidEmperor.java index c7e2fb8075..f24172edee 100644 --- a/Mage.Sets/src/mage/cards/a/AboshanCephalidEmperor.java +++ b/Mage.Sets/src/mage/cards/a/AboshanCephalidEmperor.java @@ -1,7 +1,5 @@ - package mage.cards.a; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; @@ -24,24 +22,25 @@ import mage.filter.predicate.mageobject.SubtypePredicate; import mage.target.TargetPermanent; import mage.target.common.TargetControlledCreaturePermanent; +import java.util.UUID; + /** - * * @author cbt33 */ public final class AboshanCephalidEmperor extends CardImpl { - -static final FilterControlledCreaturePermanent filter1 = new FilterControlledCreaturePermanent("untapped Cephalid you control"); -static final FilterCreaturePermanent filter2 = new FilterCreaturePermanent("creatures without flying"); -static { - filter1.add(new SubtypePredicate(SubType.CEPHALID)); - filter2.add(Predicates.not(new AbilityPredicate(FlyingAbility.class))); -} + static final FilterControlledCreaturePermanent filter1 = new FilterControlledCreaturePermanent("untapped Cephalid you control"); + static final FilterCreaturePermanent filter2 = new FilterCreaturePermanent("creatures without flying"); + + static { + filter1.add(new SubtypePredicate(SubType.CEPHALID)); + filter2.add(Predicates.not(new AbilityPredicate(FlyingAbility.class))); + } public AboshanCephalidEmperor(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{4}{U}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{U}{U}"); addSuperType(SuperType.LEGENDARY); - this.subtype.add(SubType.CEPHALID); + this.subtype.add(SubType.CEPHALID, SubType.NOBLE); this.power = new MageInt(3); this.toughness = new MageInt(3); @@ -50,7 +49,7 @@ static { Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new TapTargetEffect(), new TapTargetCost(new TargetControlledCreaturePermanent(1, 1, filter1, true))); ability.addTarget(new TargetPermanent()); this.addAbility(ability); - + // {U}{U}{U}: Tap all creatures without flying. this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new TapAllEffect(filter2), new ManaCostsImpl("{U}{U}{U}"))); } diff --git a/Mage.Sets/src/mage/cards/a/AcclaimedContender.java b/Mage.Sets/src/mage/cards/a/AcclaimedContender.java new file mode 100644 index 0000000000..7dfaf13e36 --- /dev/null +++ b/Mage.Sets/src/mage/cards/a/AcclaimedContender.java @@ -0,0 +1,79 @@ +package mage.cards.a; + +import mage.MageInt; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.condition.Condition; +import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; +import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; +import mage.abilities.dynamicvalue.common.StaticValue; +import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.constants.Zone; +import mage.filter.FilterCard; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledPermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.CardTypePredicate; +import mage.filter.predicate.mageobject.SubtypePredicate; +import mage.filter.predicate.mageobject.SupertypePredicate; +import mage.filter.predicate.permanent.AnotherPredicate; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class AcclaimedContender extends CardImpl { + + private static final FilterPermanent filter = new FilterControlledPermanent(SubType.KNIGHT); + private static final FilterCard filter2 + = new FilterCard("a Knight, Aura, Equipment, or legendary artifact card"); + + static { + filter.add(AnotherPredicate.instance); + filter2.add(Predicates.or( + new SubtypePredicate(SubType.KNIGHT), + new SubtypePredicate(SubType.AURA), + new SubtypePredicate(SubType.EQUIPMENT), + Predicates.and( + new SupertypePredicate(SuperType.LEGENDARY), + new CardTypePredicate(CardType.ARTIFACT) + ) + )); + } + + private static final Condition condition = new PermanentsOnTheBattlefieldCondition(filter); + + public AcclaimedContender(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{W}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.KNIGHT); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // When Acclaimed Contender enters the battlefield, if you control another Knight, look at the top five cards of your library. You may reveal a Knight, Aura, Equipment, or legendary artifact card from among them and put it into your hand. Put the rest on the bottom of your library in a random order. + this.addAbility(new ConditionalInterveningIfTriggeredAbility( + new EntersBattlefieldTriggeredAbility(new LookLibraryAndPickControllerEffect( + new StaticValue(5), false, new StaticValue(1), filter2, Zone.LIBRARY, false, + true, false, Zone.HAND, true, false, false + ).setBackInRandomOrder(true)), condition, "When {this} enters the battlefield, " + + "if you control another Knight, look at the top five cards of your library. " + + "You may reveal a Knight, Aura, Equipment, or legendary artifact card from among them " + + "and put it into your hand. Put the rest on the bottom of your library in a random order." + )); + } + + private AcclaimedContender(final AcclaimedContender card) { + super(card); + } + + @Override + public AcclaimedContender copy() { + return new AcclaimedContender(this); + } +} diff --git a/Mage.Sets/src/mage/cards/a/AkoumHellkite.java b/Mage.Sets/src/mage/cards/a/AkoumHellkite.java index 24a13cc142..9a512bb57c 100644 --- a/Mage.Sets/src/mage/cards/a/AkoumHellkite.java +++ b/Mage.Sets/src/mage/cards/a/AkoumHellkite.java @@ -23,7 +23,6 @@ import mage.target.targetpointer.FixedTarget; import java.util.UUID; /** - * * @author fireshoes */ public final class AkoumHellkite extends CardImpl { @@ -56,9 +55,6 @@ public final class AkoumHellkite extends CardImpl { class AkoumHellkiteTriggeredAbility extends TriggeredAbilityImpl { - private static final String text = "Landfall — Whenever a land enters the battlefield under your control, {this} deals 1 damage to any target. " - + "If that land is a Mountain, Akoum Hellkite deals 2 damage to that permanent or player instead."; - public AkoumHellkiteTriggeredAbility() { super(Zone.BATTLEFIELD, new AkoumHellkiteDamageEffect()); } @@ -98,7 +94,8 @@ class AkoumHellkiteTriggeredAbility extends TriggeredAbilityImpl { @Override public String getRule() { - return text; + return "Landfall — Whenever a land enters the battlefield under your control, " + + "{this} deals 1 damage to any target. If that land is a Mountain, {this} deals 2 damage instead."; } } diff --git a/Mage.Sets/src/mage/cards/a/AminatouTheFateShifter.java b/Mage.Sets/src/mage/cards/a/AminatouTheFateshifter.java similarity index 96% rename from Mage.Sets/src/mage/cards/a/AminatouTheFateShifter.java rename to Mage.Sets/src/mage/cards/a/AminatouTheFateshifter.java index bdd8b1e1ed..b9a89f87e3 100644 --- a/Mage.Sets/src/mage/cards/a/AminatouTheFateShifter.java +++ b/Mage.Sets/src/mage/cards/a/AminatouTheFateshifter.java @@ -34,7 +34,7 @@ import java.util.UUID; * * @author Colin Redman */ -public class AminatouTheFateShifter extends CardImpl { +public class AminatouTheFateshifter extends CardImpl { private static final FilterPermanent filter = new FilterPermanent("permanent you own"); @@ -43,7 +43,7 @@ public class AminatouTheFateShifter extends CardImpl { filter.add(AnotherPredicate.instance); } - public AminatouTheFateShifter(UUID ownerId, CardSetInfo setInfo) { + public AminatouTheFateshifter(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.PLANESWALKER}, "{W}{U}{B}"); this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.AMINATOU); @@ -69,13 +69,13 @@ public class AminatouTheFateShifter extends CardImpl { this.addAbility(CanBeYourCommanderAbility.getInstance()); } - public AminatouTheFateShifter(final AminatouTheFateShifter card) { + public AminatouTheFateshifter(final AminatouTheFateshifter card) { super(card); } @Override - public AminatouTheFateShifter copy() { - return new AminatouTheFateShifter(this); + public AminatouTheFateshifter copy() { + return new AminatouTheFateshifter(this); } } diff --git a/Mage.Sets/src/mage/cards/a/Apathy.java b/Mage.Sets/src/mage/cards/a/Apathy.java new file mode 100644 index 0000000000..5469844970 --- /dev/null +++ b/Mage.Sets/src/mage/cards/a/Apathy.java @@ -0,0 +1,93 @@ +package mage.cards.a; + +import mage.abilities.Ability; +import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.AttachEffect; +import mage.abilities.effects.common.DontUntapInControllersUntapStepEnchantedEffect; +import mage.abilities.keyword.EnchantAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.constants.TargetController; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.TargetPermanent; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class Apathy extends CardImpl { + + public Apathy(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{U}"); + + this.subtype.add(SubType.AURA); + + // Enchant creature + TargetPermanent auraTarget = new TargetCreaturePermanent(); + this.getSpellAbility().addTarget(auraTarget); + this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); + Ability ability = new EnchantAbility(auraTarget.getTargetName()); + this.addAbility(ability); + + // Enchanted creature doesn't untap during its controller's untap step. + this.addAbility(new SimpleStaticAbility(new DontUntapInControllersUntapStepEnchantedEffect())); + + // At the beginning of the upkeep of enchanted creature’s controller, that player may discard a card at random. If the player does, untap that creature. + this.addAbility(new BeginningOfUpkeepTriggeredAbility( + new ApathyEffect(), TargetController.CONTROLLER_ATTACHED_TO, false + )); + } + + private Apathy(final Apathy card) { + super(card); + } + + @Override + public Apathy copy() { + return new Apathy(this); + } +} + +class ApathyEffect extends OneShotEffect { + + ApathyEffect() { + super(Outcome.Benefit); + staticText = "that player may discard a card at random. If the player does, untap that creature"; + } + + private ApathyEffect(final ApathyEffect effect) { + super(effect); + } + + @Override + public ApathyEffect copy() { + return new ApathyEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(game.getActivePlayerId()); + if (player == null) { + return false; + } + if (!player.chooseUse(outcome, "Discard a card at random to untap enchanted creature?", source, game) + || player.discardOne(true, source, game) == null) { + return false; + } + Permanent permanent = game.getPermanent(source.getSourceId()); + if (permanent == null) { + return false; + } + permanent = game.getPermanent(permanent.getAttachedTo()); + return permanent != null && permanent.untap(game); + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/a/ArcanistsOwl.java b/Mage.Sets/src/mage/cards/a/ArcanistsOwl.java index 47e465d620..eb42874e68 100644 --- a/Mage.Sets/src/mage/cards/a/ArcanistsOwl.java +++ b/Mage.Sets/src/mage/cards/a/ArcanistsOwl.java @@ -1,6 +1,7 @@ package mage.cards.a; import mage.MageInt; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; import mage.abilities.keyword.FlyingAbility; @@ -32,7 +33,7 @@ public final class ArcanistsOwl extends CardImpl { this.addAbility(FlyingAbility.getInstance()); // When Arcanist's Owl enters the battlefield, look at the top four cards of your library. You may reveal an artifact or enchantment card from among them and put it into your hand. Put the rest on the bottom of your library in a random order. - this.getSpellAbility().addEffect( + this.addAbility(new EntersBattlefieldTriggeredAbility( new LookLibraryAndPickControllerEffect( new StaticValue(4), false, new StaticValue(1), filter, Zone.LIBRARY, false, true, false, Zone.HAND, @@ -40,7 +41,7 @@ public final class ArcanistsOwl extends CardImpl { ).setBackInRandomOrder(true).setText("Look at the top four cards of your library. " + "You may reveal an artifact or enchantment from among them and put it into your hand. " + "Put the rest on the bottom of your library in a random order.") - ); + )); } private ArcanistsOwl(final ArcanistsOwl card) { diff --git a/Mage.Sets/src/mage/cards/a/ArchfiendOfSpite.java b/Mage.Sets/src/mage/cards/a/ArchfiendOfSpite.java index be75084658..fc186f0ba0 100644 --- a/Mage.Sets/src/mage/cards/a/ArchfiendOfSpite.java +++ b/Mage.Sets/src/mage/cards/a/ArchfiendOfSpite.java @@ -73,7 +73,7 @@ class ArchfiendOfSpiteAbility extends TriggeredAbilityImpl { @Override public boolean checkEventType(GameEvent event, Game game) { - return event.getType() == GameEvent.EventType.DAMAGED_PLAYER; + return event.getType() == GameEvent.EventType.DAMAGED_CREATURE; } @Override diff --git a/Mage.Sets/src/mage/cards/a/ArchonOfAbsolution.java b/Mage.Sets/src/mage/cards/a/ArchonOfAbsolution.java new file mode 100644 index 0000000000..f1aec8f3df --- /dev/null +++ b/Mage.Sets/src/mage/cards/a/ArchonOfAbsolution.java @@ -0,0 +1,49 @@ +package mage.cards.a; + +import mage.MageInt; +import mage.ObjectColor; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.combat.CantAttackYouUnlessPayManaAllEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.abilities.keyword.ProtectionAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ArchonOfAbsolution extends CardImpl { + + public ArchonOfAbsolution(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{W}"); + + this.subtype.add(SubType.ARCHON); + this.power = new MageInt(3); + this.toughness = new MageInt(2); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // Protection from white + this.addAbility(ProtectionAbility.from(ObjectColor.WHITE)); + + // Creatures can't attack you or a planeswalker you control unless their controller pays {1} for each of those creatures. + this.addAbility(new SimpleStaticAbility( + new CantAttackYouUnlessPayManaAllEffect(new ManaCostsImpl("{1}"), true) + )); + } + + private ArchonOfAbsolution(final ArchonOfAbsolution card) { + super(card); + } + + @Override + public ArchonOfAbsolution copy() { + return new ArchonOfAbsolution(this); + } +} diff --git a/Mage.Sets/src/mage/cards/a/ArcticFoxes.java b/Mage.Sets/src/mage/cards/a/ArcticFoxes.java new file mode 100644 index 0000000000..a7a503331c --- /dev/null +++ b/Mage.Sets/src/mage/cards/a/ArcticFoxes.java @@ -0,0 +1,74 @@ +package mage.cards.a; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.Condition; +import mage.abilities.decorator.ConditionalRestrictionEffect; +import mage.abilities.effects.common.combat.CantBeBlockedByCreaturesSourceEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.common.FilterLandPermanent; +import mage.filter.predicate.mageobject.PowerPredicate; +import mage.filter.predicate.mageobject.SupertypePredicate; +import mage.game.Game; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ArcticFoxes extends CardImpl { + + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent(); + + static { + filter.add(new PowerPredicate(ComparisonType.MORE_THAN, 1)); + } + + public ArcticFoxes(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W}"); + + this.subtype.add(SubType.FOX); + this.power = new MageInt(1); + this.toughness = new MageInt(1); + + // Creatures with power 2 or greater can't block Arctic Foxes as long as defending player controls a snow land. + this.addAbility(new SimpleStaticAbility(new ConditionalRestrictionEffect( + new CantBeBlockedByCreaturesSourceEffect(filter, Duration.WhileOnBattlefield), + ArcticFoxesCondition.instance, "creatures with power 2 or greater can't block {this}" + + " as long as defending player controls a snow land" + ))); + } + + private ArcticFoxes(final ArcticFoxes card) { + super(card); + } + + @Override + public ArcticFoxes copy() { + return new ArcticFoxes(this); + } +} + +enum ArcticFoxesCondition implements Condition { + instance; + + private static final FilterPermanent filter = new FilterLandPermanent(); + + static { + filter.add(new SupertypePredicate(SuperType.SNOW)); + } + + @Override + public boolean apply(Game game, Ability source) { + UUID defenderId = game.getCombat().getDefendingPlayerId(source.getSourceId(), game); + if (defenderId == null) { + return false; + } + return game.getBattlefield().contains(filter, defenderId, 1, game); + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/a/ArdenvalePaladin.java b/Mage.Sets/src/mage/cards/a/ArdenvalePaladin.java new file mode 100644 index 0000000000..4c93d78958 --- /dev/null +++ b/Mage.Sets/src/mage/cards/a/ArdenvalePaladin.java @@ -0,0 +1,46 @@ +package mage.cards.a; + +import mage.MageInt; +import mage.abilities.common.EntersBattlefieldAbility; +import mage.abilities.condition.common.AdamantCondition; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.counters.CounterType; +import mage.watchers.common.ManaSpentToCastWatcher; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ArdenvalePaladin extends CardImpl { + + public ArdenvalePaladin(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{W}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.KNIGHT); + this.power = new MageInt(2); + this.toughness = new MageInt(5); + + // Adamant — If at least three white mana was spent to cast this spell, Ardenvale Paladin enters the battlefield with a +1/+1 counter on it. + this.addAbility(new EntersBattlefieldAbility( + new AddCountersSourceEffect(CounterType.P1P1.createInstance()), + AdamantCondition.WHITE, "
Adamant — " + + "If at least three white mana was spent to cast this spell, " + + "{this} enters the battlefield with a +1/+1 counter on it.", "" + ), new ManaSpentToCastWatcher()); + } + + private ArdenvalePaladin(final ArdenvalePaladin card) { + super(card); + } + + @Override + public ArdenvalePaladin copy() { + return new ArdenvalePaladin(this); + } +} diff --git a/Mage.Sets/src/mage/cards/a/ArdenvaleTactician.java b/Mage.Sets/src/mage/cards/a/ArdenvaleTactician.java new file mode 100644 index 0000000000..cfafc8aac4 --- /dev/null +++ b/Mage.Sets/src/mage/cards/a/ArdenvaleTactician.java @@ -0,0 +1,44 @@ +package mage.cards.a; + +import mage.MageInt; +import mage.abilities.effects.common.TapTargetEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.AdventureCard; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ArdenvaleTactician extends AdventureCard { + + public ArdenvaleTactician(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, new CardType[]{CardType.INSTANT}, "{1}{W}{W}", "Dizzying Swoop", "{1}{W}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.KNIGHT); + this.power = new MageInt(2); + this.toughness = new MageInt(3); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // Dizzying Swoop + // Tap up to two target creatures. + this.getAdventureSpellAbility().addEffect(new TapTargetEffect()); + this.getAdventureSpellAbility().addTarget(new TargetCreaturePermanent(0, 2)); + } + + private ArdenvaleTactician(final ArdenvaleTactician card) { + super(card); + } + + @Override + public ArdenvaleTactician copy() { + return new ArdenvaleTactician(this); + } +} diff --git a/Mage.Sets/src/mage/cards/a/AyaraFirstOfLocthwain.java b/Mage.Sets/src/mage/cards/a/AyaraFirstOfLocthwain.java new file mode 100644 index 0000000000..15d2e1a9f4 --- /dev/null +++ b/Mage.Sets/src/mage/cards/a/AyaraFirstOfLocthwain.java @@ -0,0 +1,70 @@ +package mage.cards.a; + +import mage.MageInt; +import mage.ObjectColor; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldControlledTriggeredAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.SacrificeTargetCost; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.GainLifeEffect; +import mage.abilities.effects.common.LoseLifeOpponentsEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.common.FilterControlledPermanent; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.mageobject.ColorPredicate; +import mage.target.common.TargetControlledPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class AyaraFirstOfLocthwain extends CardImpl { + + private static final FilterPermanent filter + = new FilterCreaturePermanent("{this} or another black creature"); + private static final FilterControlledPermanent filter2 + = new FilterControlledCreaturePermanent("another black creature"); + + static { + filter.add(new ColorPredicate(ObjectColor.BLACK)); + filter2.add(new ColorPredicate(ObjectColor.BLACK)); + } + + public AyaraFirstOfLocthwain(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{B}{B}{B}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.ELF); + this.subtype.add(SubType.NOBLE); + this.power = new MageInt(2); + this.toughness = new MageInt(3); + + // Whenever Ayara, First of Locthwain or another black creature enters the battlefield under your control, each opponent loses 1 life and you gain 1 life. + Ability ability = new EntersBattlefieldControlledTriggeredAbility(new LoseLifeOpponentsEffect(1), filter); + ability.addEffect(new GainLifeEffect(1).concatBy("and")); + this.addAbility(ability); + + // {T}, Sacrifice another black creature: Draw a card. + ability = new SimpleActivatedAbility(new DrawCardSourceControllerEffect(1), new TapSourceCost()); + ability.addCost(new SacrificeTargetCost(new TargetControlledPermanent(filter2))); + this.addAbility(ability); + } + + private AyaraFirstOfLocthwain(final AyaraFirstOfLocthwain card) { + super(card); + } + + @Override + public AyaraFirstOfLocthwain copy() { + return new AyaraFirstOfLocthwain(this); + } +} diff --git a/Mage.Sets/src/mage/cards/a/AzoriusAEthermage.java b/Mage.Sets/src/mage/cards/a/AzoriusAethermage.java similarity index 92% rename from Mage.Sets/src/mage/cards/a/AzoriusAEthermage.java rename to Mage.Sets/src/mage/cards/a/AzoriusAethermage.java index 851c91793a..16aed74a47 100644 --- a/Mage.Sets/src/mage/cards/a/AzoriusAEthermage.java +++ b/Mage.Sets/src/mage/cards/a/AzoriusAethermage.java @@ -23,11 +23,11 @@ import mage.game.permanent.Permanent; * * @author jeffwadsworth */ -public final class AzoriusAEthermage extends CardImpl { +public final class AzoriusAethermage extends CardImpl { private static final String rule = "Whenever a permanent is returned to your hand, "; - public AzoriusAEthermage(UUID ownerId, CardSetInfo setInfo) { + public AzoriusAethermage(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W}{U}"); this.subtype.add(SubType.HUMAN); @@ -40,13 +40,13 @@ public final class AzoriusAEthermage extends CardImpl { this.addAbility(new AzoriusAEthermageAbility(Zone.BATTLEFIELD, Zone.BATTLEFIELD, Zone.HAND, effect, new FilterPermanent(), rule, true)); } - public AzoriusAEthermage(final AzoriusAEthermage card) { + public AzoriusAethermage(final AzoriusAethermage card) { super(card); } @Override - public AzoriusAEthermage copy() { - return new AzoriusAEthermage(this); + public AzoriusAethermage copy() { + return new AzoriusAethermage(this); } } diff --git a/Mage.Sets/src/mage/cards/b/BargeIn.java b/Mage.Sets/src/mage/cards/b/BargeIn.java new file mode 100644 index 0000000000..6f3e297b92 --- /dev/null +++ b/Mage.Sets/src/mage/cards/b/BargeIn.java @@ -0,0 +1,52 @@ +package mage.cards.b; + +import mage.abilities.effects.common.continuous.BoostTargetEffect; +import mage.abilities.effects.common.continuous.GainAbilityAllEffect; +import mage.abilities.keyword.TrampleAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.SubtypePredicate; +import mage.filter.predicate.permanent.AttackingPredicate; +import mage.target.common.TargetAttackingCreature; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class BargeIn extends CardImpl { + + private static final FilterPermanent filter + = new FilterCreaturePermanent("Each attacking non-Human creature"); + + static { + filter.add(AttackingPredicate.instance); + filter.add(Predicates.not(new SubtypePredicate(SubType.HUMAN))); + } + + public BargeIn(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{R}"); + + // Target attacking creature gets +2/+2 until end of turn. Each attacking non-Human creature gains trample until end of turn. + this.getSpellAbility().addEffect(new BoostTargetEffect(2, 2, Duration.EndOfTurn)); + this.getSpellAbility().addEffect(new GainAbilityAllEffect( + TrampleAbility.getInstance(), Duration.EndOfTurn, filter + )); + this.getSpellAbility().addTarget(new TargetAttackingCreature()); + } + + private BargeIn(final BargeIn card) { + super(card); + } + + @Override + public BargeIn copy() { + return new BargeIn(this); + } +} diff --git a/Mage.Sets/src/mage/cards/b/BaronSengir.java b/Mage.Sets/src/mage/cards/b/BaronSengir.java index 41375fb1ce..f97a75dbd9 100644 --- a/Mage.Sets/src/mage/cards/b/BaronSengir.java +++ b/Mage.Sets/src/mage/cards/b/BaronSengir.java @@ -1,7 +1,5 @@ - package mage.cards.b; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.DealtDamageAndDiedTriggeredAbility; @@ -22,12 +20,13 @@ import mage.filter.predicate.mageobject.SubtypePredicate; import mage.filter.predicate.permanent.AnotherPredicate; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author fireshoes */ public final class BaronSengir extends CardImpl { - + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("another target Vampire"); static { @@ -36,18 +35,18 @@ public final class BaronSengir extends CardImpl { } public BaronSengir(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{5}{B}{B}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{5}{B}{B}{B}"); addSuperType(SuperType.LEGENDARY); - this.subtype.add(SubType.VAMPIRE); + this.subtype.add(SubType.VAMPIRE, SubType.NOBLE); this.power = new MageInt(5); this.toughness = new MageInt(5); // Flying this.addAbility(FlyingAbility.getInstance()); - + // Whenever a creature dealt damage by Baron Sengir this turn dies, put a +2/+2 counter on Baron Sengir. this.addAbility(new DealtDamageAndDiedTriggeredAbility(new AddCountersSourceEffect(CounterType.P2P2.createInstance()), false)); - + // {tap}: Regenerate another target Vampire. Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new RegenerateTargetEffect(), new TapSourceCost()); ability.addTarget(new TargetCreaturePermanent(filter)); diff --git a/Mage.Sets/src/mage/cards/b/BarrowWitches.java b/Mage.Sets/src/mage/cards/b/BarrowWitches.java new file mode 100644 index 0000000000..f442b28e5c --- /dev/null +++ b/Mage.Sets/src/mage/cards/b/BarrowWitches.java @@ -0,0 +1,50 @@ +package mage.cards.b; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.common.ReturnFromGraveyardToHandTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.filter.FilterCard; +import mage.filter.predicate.mageobject.SubtypePredicate; +import mage.target.common.TargetCardInYourGraveyard; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class BarrowWitches extends CardImpl { + + private static final FilterCard filter = new FilterCard("Knight card from your graveyard"); + + static { + filter.add(new SubtypePredicate(SubType.KNIGHT)); + } + + public BarrowWitches(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{B}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.WARLOCK); + this.power = new MageInt(3); + this.toughness = new MageInt(4); + + // When Barrow Witches enters the battlefield, return target Knight card from your graveyard to your hand. + Ability ability = new EntersBattlefieldTriggeredAbility(new ReturnFromGraveyardToHandTargetEffect()); + ability.addTarget(new TargetCardInYourGraveyard(filter)); + this.addAbility(ability); + } + + private BarrowWitches(final BarrowWitches card) { + super(card); + } + + @Override + public BarrowWitches copy() { + return new BarrowWitches(this); + } +} diff --git a/Mage.Sets/src/mage/cards/b/BarteredCow.java b/Mage.Sets/src/mage/cards/b/BarteredCow.java new file mode 100644 index 0000000000..07fb03f4e6 --- /dev/null +++ b/Mage.Sets/src/mage/cards/b/BarteredCow.java @@ -0,0 +1,66 @@ +package mage.cards.b; + +import mage.MageInt; +import mage.MageObject; +import mage.abilities.common.DiesTriggeredAbility; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.DiscardCardControllerTriggeredAbility; +import mage.abilities.meta.OrTriggeredAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.Zone; +import mage.filter.FilterCard; +import mage.filter.predicate.ObjectSourcePlayer; +import mage.filter.predicate.ObjectSourcePlayerPredicate; +import mage.game.Game; +import mage.game.permanent.token.FoodToken; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class BarteredCow extends CardImpl { + + private static final FilterCard filter = new FilterCard(); + + static { + filter.add(BarteredCowPredicate.instance); + } + + public BarteredCow(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{W}"); + + this.subtype.add(SubType.OX); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // When Bartered Cow dies or when you discard it, create a Food token. + this.addAbility(new OrTriggeredAbility( + Zone.ALL, new CreateTokenEffect(new FoodToken()), false, + "When {this} dies or when you discard it, ", new DiesTriggeredAbility((Effect) null), + new DiscardCardControllerTriggeredAbility(null, false, filter) + )); + } + + private BarteredCow(final BarteredCow card) { + super(card); + } + + @Override + public BarteredCow copy() { + return new BarteredCow(this); + } +} + +enum BarteredCowPredicate implements ObjectSourcePlayerPredicate> { + instance; + + @Override + public boolean apply(ObjectSourcePlayer input, Game game) { + return input.getObject().getId().equals(input.getSourceId()); + } +} diff --git a/Mage.Sets/src/mage/cards/b/BatwingBrume.java b/Mage.Sets/src/mage/cards/b/BatwingBrume.java index bfd0ffc933..5f09e9bd34 100644 --- a/Mage.Sets/src/mage/cards/b/BatwingBrume.java +++ b/Mage.Sets/src/mage/cards/b/BatwingBrume.java @@ -36,11 +36,11 @@ public final class BatwingBrume extends CardImpl { // Prevent all combat damage that would be dealt this turn if {W} was spent to cast Batwing Brume. Each player loses 1 life for each attacking creature he or she controls if {B} was spent to cast Batwing Brume. Effect effect = new ConditionalReplacementEffect(new PreventAllDamageByAllPermanentsEffect(Duration.EndOfTurn, true), new LockedInCondition(new ManaWasSpentCondition(ColoredManaSymbol.W))); - effect.setText("Prevent all combat damage that would be dealt this turn if {W} was spent to cast {this}"); + effect.setText("Prevent all combat damage that would be dealt this turn if {W} was spent to cast this spell"); this.getSpellAbility().addEffect(effect); this.getSpellAbility().addEffect(new ConditionalOneShotEffect( new BatwingBrumeEffect(), - new ManaWasSpentCondition(ColoredManaSymbol.B), "Each player loses 1 life for each attacking creature he or she controls if {B} was spent to cast {this}")); + new ManaWasSpentCondition(ColoredManaSymbol.B), "Each player loses 1 life for each attacking creature he or she controls if {B} was spent to cast this spell")); this.getSpellAbility().addEffect(new InfoEffect("(Do both if {W}{B} was spent.)")); this.getSpellAbility().addWatcher(new ManaSpentToCastWatcher()); diff --git a/Mage.Sets/src/mage/cards/b/BedlamReveler.java b/Mage.Sets/src/mage/cards/b/BedlamReveler.java index 6bd1228508..5eff9cbdb0 100644 --- a/Mage.Sets/src/mage/cards/b/BedlamReveler.java +++ b/Mage.Sets/src/mage/cards/b/BedlamReveler.java @@ -14,6 +14,7 @@ import mage.abilities.keyword.ProwessAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.*; +import mage.filter.StaticFilters; import mage.filter.common.FilterInstantOrSorceryCard; /** @@ -29,7 +30,7 @@ public final class BedlamReveler extends CardImpl { this.toughness = new MageInt(4); // Bedlam Reveler costs {1} less to cast for each instant or sorcery card in your graveyard. - Ability ability = new SimpleStaticAbility(Zone.ALL, new SourceCostReductionForEachCardInGraveyardEffect(new FilterInstantOrSorceryCard())); + Ability ability = new SimpleStaticAbility(Zone.ALL, new SourceCostReductionForEachCardInGraveyardEffect(StaticFilters.FILTER_CARD_INSTANT_AND_SORCERY)); ability.setRuleAtTheTop(true); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/b/BelovedPrincess.java b/Mage.Sets/src/mage/cards/b/BelovedPrincess.java new file mode 100644 index 0000000000..ecba10b8ae --- /dev/null +++ b/Mage.Sets/src/mage/cards/b/BelovedPrincess.java @@ -0,0 +1,55 @@ +package mage.cards.b; + +import mage.MageInt; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.combat.CantBeBlockedByCreaturesSourceEffect; +import mage.abilities.keyword.LifelinkAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.ComparisonType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.mageobject.PowerPredicate; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class BelovedPrincess extends CardImpl { + + private static final FilterCreaturePermanent filter + = new FilterCreaturePermanent("creatures with power 3 or greater"); + + static { + filter.add(new PowerPredicate(ComparisonType.MORE_THAN, 2)); + } + + public BelovedPrincess(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{W}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.NOBLE); + this.power = new MageInt(1); + this.toughness = new MageInt(1); + + // Lifelink + this.addAbility(LifelinkAbility.getInstance()); + + // Beloved Princess can't be blocked by creatures with power 3 or greater. + this.addAbility(new SimpleStaticAbility( + new CantBeBlockedByCreaturesSourceEffect(filter, Duration.WhileOnBattlefield) + )); + } + + private BelovedPrincess(final BelovedPrincess card) { + super(card); + } + + @Override + public BelovedPrincess copy() { + return new BelovedPrincess(this); + } +} diff --git a/Mage.Sets/src/mage/cards/b/BiomancersFamiliar.java b/Mage.Sets/src/mage/cards/b/BiomancersFamiliar.java index 99f4667c1a..ced7a58d5f 100644 --- a/Mage.Sets/src/mage/cards/b/BiomancersFamiliar.java +++ b/Mage.Sets/src/mage/cards/b/BiomancersFamiliar.java @@ -37,12 +37,10 @@ public final class BiomancersFamiliar extends CardImpl { this.toughness = new MageInt(2); // Activated abilities of creatures you control cost {2} less to activate. This effect can't reduce the amount of mana an ability costs to activate to less than one mana. - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BiomancersFamiliarCostReductionEffect())); + this.addAbility(new SimpleStaticAbility(new BiomancersFamiliarCostReductionEffect())); // {T}: The next time target creature adapts this turn, it adapts as though it had no +1/+1 counters on it. - Ability ability = new SimpleActivatedAbility( - new BiomancersFamiliarReplacementEffect(), new TapSourceCost() - ); + Ability ability = new SimpleActivatedAbility(new BiomancersFamiliarReplacementEffect(), new TapSourceCost()); ability.addTarget(new TargetCreaturePermanent()); this.addAbility(ability); } @@ -74,47 +72,48 @@ class BiomancersFamiliarCostReductionEffect extends CostModificationEffectImpl { @Override public boolean apply(Game game, Ability source, Ability abilityToModify) { Player controller = game.getPlayer(abilityToModify.getControllerId()); - if (controller != null) { - Mana mana = abilityToModify.getManaCostsToPay().getMana(); - int reduceMax = mana.getGeneric(); - if (reduceMax > 0 && mana.count() == mana.getGeneric()) { - reduceMax--; - } - if (reduceMax > 2) { - reduceMax = 2; - } - if (reduceMax > 0) { - ChoiceImpl choice = new ChoiceImpl(true); - Set set = new LinkedHashSet<>(); - - for (int i = 0; i <= reduceMax; i++) { - set.add(String.valueOf(i)); - } - choice.setChoices(set); - choice.setMessage("Reduce ability cost"); - if (!controller.choose(Outcome.Benefit, choice, game)) { - return false; - } - int reduce = Integer.parseInt(choice.getChoice()); - CardUtil.reduceCost(abilityToModify, reduce); - } + if (controller == null) { + return false; + } + Mana mana = abilityToModify.getManaCostsToPay().getMana(); + int reduceMax = mana.getGeneric(); + if (reduceMax > 0 && mana.count() == mana.getGeneric()) { + reduceMax--; + } + if (reduceMax > 2) { + reduceMax = 2; + } + if (reduceMax <= 0) { return true; } + ChoiceImpl choice = new ChoiceImpl(true); + Set set = new LinkedHashSet<>(); + + for (int i = 0; i <= reduceMax; i++) { + set.add(String.valueOf(i)); + } + choice.setChoices(set); + choice.setMessage("Reduce ability cost"); + if (!controller.choose(Outcome.Benefit, choice, game)) { + return false; + } + int reduce = Integer.parseInt(choice.getChoice()); + CardUtil.reduceCost(abilityToModify, reduce); + return true; - return false; } @Override public boolean applies(Ability abilityToModify, Ability source, Game game) { - if (abilityToModify.getAbilityType() == AbilityType.ACTIVATED - || (abilityToModify.getAbilityType() == AbilityType.MANA && abilityToModify instanceof ActivatedAbility)) { - //Activated abilities of creatures you control - Permanent permanent = game.getPermanent(abilityToModify.getSourceId()); - if (permanent != null && permanent.isCreature() && permanent.isControlledBy(source.getControllerId())) { - return true; - } + if (abilityToModify.getAbilityType() != AbilityType.ACTIVATED + && (abilityToModify.getAbilityType() != AbilityType.MANA + || !(abilityToModify instanceof ActivatedAbility))) { + return false; } - return false; + //Activated abilities of creatures you control + Permanent permanent = game.getPermanent(abilityToModify.getSourceId()); + return permanent != null && permanent.isCreature() + && permanent.isControlledBy(source.getControllerId()); } @Override diff --git a/Mage.Sets/src/mage/cards/b/BlacklanceParagon.java b/Mage.Sets/src/mage/cards/b/BlacklanceParagon.java new file mode 100644 index 0000000000..f7b066a634 --- /dev/null +++ b/Mage.Sets/src/mage/cards/b/BlacklanceParagon.java @@ -0,0 +1,61 @@ + +package mage.cards.b; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; +import mage.abilities.effects.Effect; +import mage.abilities.keyword.DeathtouchAbility; +import mage.abilities.keyword.LifelinkAbility; +import mage.abilities.keyword.FlashAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.filter.common.FilterCreaturePermanent; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author Tsirides + */ +public final class BlacklanceParagon extends CardImpl { + + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent(SubType.KNIGHT, "Knight"); + + public BlacklanceParagon(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{B}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.KNIGHT); + this.power = new MageInt(3); + this.toughness = new MageInt(1); + + // Flash + this.addAbility(FlashAbility.getInstance()); + + + // When Blacklance Paragon enters the battlefield, target Knight gains deathtouch and lifelink until end of turn. + Effect effect = new GainAbilityTargetEffect(DeathtouchAbility.getInstance(), Duration.EndOfTurn); + effect.setText("target Knight gains deathtouch"); + Ability ability = new EntersBattlefieldTriggeredAbility(effect); + effect = new GainAbilityTargetEffect(LifelinkAbility.getInstance(), Duration.EndOfTurn); + effect.setText("and lifelink until end of turn"); + ability.addEffect(effect); + ability.addTarget(new TargetCreaturePermanent(filter)); + this.addAbility(ability); + + } + + public BlacklanceParagon(final BlacklanceParagon card) { + super(card); + } + + @Override + public BlacklanceParagon copy() { + return new BlacklanceParagon(this); + } +} diff --git a/Mage.Sets/src/mage/cards/b/BlindFury.java b/Mage.Sets/src/mage/cards/b/BlindFury.java new file mode 100644 index 0000000000..cd7a9bb007 --- /dev/null +++ b/Mage.Sets/src/mage/cards/b/BlindFury.java @@ -0,0 +1,83 @@ +package mage.cards.b; + +import mage.abilities.Ability; +import mage.abilities.effects.ReplacementEffectImpl; +import mage.abilities.effects.common.continuous.LoseAbilityAllEffect; +import mage.abilities.keyword.TrampleAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.game.events.DamageCreatureEvent; +import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; +import mage.util.CardUtil; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class BlindFury extends CardImpl { + + public BlindFury(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{R}{R}"); + + // All creatures lose trample until end of turn. If a creature would deal combat damage to a creature this turn, it deals double that damage to that creature instead. + this.getSpellAbility().addEffect(new LoseAbilityAllEffect( + TrampleAbility.getInstance(), Duration.EndOfTurn, + StaticFilters.FILTER_PERMANENT_CREATURES + ).setText("All creatures lose trample until end of turn.")); + this.getSpellAbility().addEffect(new FurnaceOfRathEffect()); + } + + private BlindFury(final BlindFury card) { + super(card); + } + + @Override + public BlindFury copy() { + return new BlindFury(this); + } +} + +class FurnaceOfRathEffect extends ReplacementEffectImpl { + + FurnaceOfRathEffect() { + super(Duration.EndOfTurn, Outcome.Damage); + staticText = "If a creature would deal combat damage to a creature this turn, " + + "it deals double that damage to that creature instead"; + } + + private FurnaceOfRathEffect(final FurnaceOfRathEffect effect) { + super(effect); + } + + @Override + public FurnaceOfRathEffect copy() { + return new FurnaceOfRathEffect(this); + } + + @Override + public boolean checksEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.DAMAGE_CREATURE; + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + Permanent permanent = game.getPermanent(event.getSourceId()); + return permanent != null + && permanent.isCreature() + && ((DamageCreatureEvent) event).isCombatDamage(); + + } + + @Override + public boolean replaceEvent(GameEvent event, Ability source, Game game) { + event.setAmount(CardUtil.addWithOverflowCheck(event.getAmount(), event.getAmount())); + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/b/BlindZealot.java b/Mage.Sets/src/mage/cards/b/BlindZealot.java index c1de1d9731..4fb163cab2 100644 --- a/Mage.Sets/src/mage/cards/b/BlindZealot.java +++ b/Mage.Sets/src/mage/cards/b/BlindZealot.java @@ -1,6 +1,5 @@ package mage.cards.b; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.TriggeredAbilityImpl; @@ -16,13 +15,15 @@ import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.permanent.ControllerIdPredicate; import mage.game.Game; +import mage.game.events.DamagedEvent; import mage.game.events.GameEvent; import mage.game.events.GameEvent.EventType; import mage.players.Player; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author North */ public final class BlindZealot extends CardImpl { @@ -42,7 +43,7 @@ public final class BlindZealot extends CardImpl { this.addAbility(ability); } - public BlindZealot(final BlindZealot card) { + private BlindZealot(final BlindZealot card) { super(card); } @@ -54,11 +55,11 @@ public final class BlindZealot extends CardImpl { class BlindZealotTriggeredAbility extends TriggeredAbilityImpl { - public BlindZealotTriggeredAbility() { + BlindZealotTriggeredAbility() { super(Zone.BATTLEFIELD, new DoIfCostPaid(new DestroyTargetEffect(), new SacrificeSourceCost()), true); } - public BlindZealotTriggeredAbility(final BlindZealotTriggeredAbility ability) { + private BlindZealotTriggeredAbility(final BlindZealotTriggeredAbility ability) { super(ability); } @@ -75,14 +76,16 @@ class BlindZealotTriggeredAbility extends TriggeredAbilityImpl { @Override public boolean checkTrigger(GameEvent event, Game game) { Player opponent = game.getPlayer(event.getPlayerId()); - if (opponent != null && event.getSourceId().equals(this.sourceId)) { - FilterCreaturePermanent filter = new FilterCreaturePermanent("creature " + opponent.getLogName() + " controls"); - filter.add(new ControllerIdPredicate(opponent.getId())); - this.getTargets().clear(); - this.addTarget(new TargetCreaturePermanent(filter)); - return true; + if (opponent == null + || !event.getSourceId().equals(this.sourceId) + || !((DamagedEvent) event).isCombatDamage()) { + return false; } - return false; + FilterCreaturePermanent filter = new FilterCreaturePermanent("creature " + opponent.getLogName() + " controls"); + filter.add(new ControllerIdPredicate(opponent.getId())); + this.getTargets().clear(); + this.addTarget(new TargetCreaturePermanent(filter)); + return true; } @Override diff --git a/Mage.Sets/src/mage/cards/b/BloodForBones.java b/Mage.Sets/src/mage/cards/b/BloodForBones.java index e04e4a2717..c0c4ea3716 100644 --- a/Mage.Sets/src/mage/cards/b/BloodForBones.java +++ b/Mage.Sets/src/mage/cards/b/BloodForBones.java @@ -56,7 +56,7 @@ class BloodForBonesEffect extends OneShotEffect { = new FilterCreatureCard("creature card in your graveyard (to put into your hand"); BloodForBonesEffect() { - super(Outcome.Benefit); + super(Outcome.PutCardInPlay); staticText = "Return a creature card from your graveyard to the battlefield, " + "then return another creature card from your graveyard to your hand."; } diff --git a/Mage.Sets/src/mage/cards/b/BloodhazeWolverine.java b/Mage.Sets/src/mage/cards/b/BloodhazeWolverine.java new file mode 100644 index 0000000000..38b7b6e513 --- /dev/null +++ b/Mage.Sets/src/mage/cards/b/BloodhazeWolverine.java @@ -0,0 +1,47 @@ +package mage.cards.b; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.DrawSecondCardTriggeredAbility; +import mage.abilities.effects.common.continuous.BoostSourceEffect; +import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; +import mage.abilities.keyword.FirstStrikeAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class BloodhazeWolverine extends CardImpl { + + public BloodhazeWolverine(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{R}"); + + this.subtype.add(SubType.WOLVERINE); + this.power = new MageInt(2); + this.toughness = new MageInt(1); + + // Whenever you draw your second card each turn, Bloodhaze Wolverine gets +1/+1 and gains first strike until end of turn. + Ability ability = new DrawSecondCardTriggeredAbility(new BoostSourceEffect( + 1, 1, Duration.EndOfTurn + ).setText("{this} gets +1/+1"), false); + ability.addEffect(new GainAbilitySourceEffect( + FirstStrikeAbility.getInstance(), Duration.EndOfTurn + ).setText("and gains first strike until end of turn")); + this.addAbility(ability); + } + + private BloodhazeWolverine(final BloodhazeWolverine card) { + super(card); + } + + @Override + public BloodhazeWolverine copy() { + return new BloodhazeWolverine(this); + } +} diff --git a/Mage.Sets/src/mage/cards/b/BlowYourHouseDown.java b/Mage.Sets/src/mage/cards/b/BlowYourHouseDown.java new file mode 100644 index 0000000000..4c8bc31c28 --- /dev/null +++ b/Mage.Sets/src/mage/cards/b/BlowYourHouseDown.java @@ -0,0 +1,70 @@ +package mage.cards.b; + +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.combat.CantBlockTargetEffect; +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.game.Game; +import mage.target.Target; +import mage.target.common.TargetCreaturePermanent; + +import java.util.Collection; +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class BlowYourHouseDown extends CardImpl { + + public BlowYourHouseDown(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{R}"); + + // Up to three target creatures can't block this turn. Destroy any of them that are Walls. + this.getSpellAbility().addEffect(new CantBlockTargetEffect(Duration.EndOfTurn)); + this.getSpellAbility().addEffect(new BlowYourHouseDownEffect()); + this.getSpellAbility().addTarget(new TargetCreaturePermanent(0, 3)); + } + + private BlowYourHouseDown(final BlowYourHouseDown card) { + super(card); + } + + @Override + public BlowYourHouseDown copy() { + return new BlowYourHouseDown(this); + } +} + +class BlowYourHouseDownEffect extends OneShotEffect { + + BlowYourHouseDownEffect() { + super(Outcome.Benefit); + staticText = "Destroy any of them that are Walls"; + } + + private BlowYourHouseDownEffect(final BlowYourHouseDownEffect effect) { + super(effect); + } + + @Override + public BlowYourHouseDownEffect copy() { + return new BlowYourHouseDownEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + source.getTargets() + .stream() + .map(Target::getTargets) + .flatMap(Collection::stream) + .map(game::getPermanent) + .filter(permanent -> permanent != null && permanent.hasSubtype(SubType.WALL, game)) + .forEach(permanent -> permanent.destroy(source.getSourceId(), game, false)); + return true; + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/b/BogNaughty.java b/Mage.Sets/src/mage/cards/b/BogNaughty.java new file mode 100644 index 0000000000..39aa74ef30 --- /dev/null +++ b/Mage.Sets/src/mage/cards/b/BogNaughty.java @@ -0,0 +1,55 @@ +package mage.cards.b; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.SacrificeTargetCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.continuous.BoostTargetEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.filter.common.FilterControlledPermanent; +import mage.target.common.TargetControlledPermanent; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class BogNaughty extends CardImpl { + + private static final FilterControlledPermanent filter = new FilterControlledPermanent(SubType.FOOD, "a Food"); + + public BogNaughty(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{B}{B}"); + + this.subtype.add(SubType.FAERIE); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // {2}{B}, Sacrifice a Food: Target creature gets -3/-3 until end of turn. + Ability ability = new SimpleActivatedAbility( + new BoostTargetEffect(-3, -3, Duration.EndOfTurn), new ManaCostsImpl("{2}{B}") + ); + ability.addCost(new SacrificeTargetCost(new TargetControlledPermanent(filter))); + ability.addTarget(new TargetCreaturePermanent()); + this.addAbility(ability); + } + + private BogNaughty(final BogNaughty card) { + super(card); + } + + @Override + public BogNaughty copy() { + return new BogNaughty(this); + } +} diff --git a/Mage.Sets/src/mage/cards/b/BonecrusherGiant.java b/Mage.Sets/src/mage/cards/b/BonecrusherGiant.java new file mode 100644 index 0000000000..5d33e4e228 --- /dev/null +++ b/Mage.Sets/src/mage/cards/b/BonecrusherGiant.java @@ -0,0 +1,82 @@ +package mage.cards.b; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.BecomesTargetTriggeredAbility; +import mage.abilities.effects.ReplacementEffectImpl; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.cards.AdventureCard; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.target.common.TargetAnyTarget; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class BonecrusherGiant extends AdventureCard { + + public BonecrusherGiant(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, new CardType[]{CardType.INSTANT}, "{2}{R}", "Stomp", "{1}{R}"); + + this.subtype.add(SubType.GIANT); + this.power = new MageInt(4); + this.toughness = new MageInt(3); + + // Whenever Bonecrusher Giant becomes the target of a spell, Bonecrusher Giant deals 2 damage to that spell's controller. + this.addAbility(new BecomesTargetTriggeredAbility(new DamageTargetEffect( + 2, true, "that's spell's controller", "{this}" + ), StaticFilters.FILTER_SPELL_A, SetTargetPointer.PLAYER)); + + // Stomp + // Damage can’t be prevented this turn. Stomp deals 2 damage to any target. + this.getAdventureSpellAbility().addEffect(new StompEffect()); + this.getAdventureSpellAbility().addEffect(new DamageTargetEffect(2)); + this.getAdventureSpellAbility().addTarget(new TargetAnyTarget()); + } + + private BonecrusherGiant(final BonecrusherGiant card) { + super(card); + } + + @Override + public BonecrusherGiant copy() { + return new BonecrusherGiant(this); + } +} + +class StompEffect extends ReplacementEffectImpl { + + StompEffect() { + super(Duration.EndOfTurn, Outcome.Benefit); + staticText = "Damage can't be prevented this turn."; + } + + private StompEffect(final StompEffect effect) { + super(effect); + } + + @Override + public StompEffect copy() { + return new StompEffect(this); + } + + @Override + public boolean replaceEvent(GameEvent event, Ability source, Game game) { + return true; + } + + @Override + public boolean checksEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.PREVENT_DAMAGE; + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/b/BorealElemental.java b/Mage.Sets/src/mage/cards/b/BorealElemental.java index e496ba4261..bd0f8fcada 100644 --- a/Mage.Sets/src/mage/cards/b/BorealElemental.java +++ b/Mage.Sets/src/mage/cards/b/BorealElemental.java @@ -2,6 +2,7 @@ package mage.cards.b; import mage.MageInt; import mage.abilities.Ability; +import mage.abilities.Mode; import mage.abilities.SpellAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.common.cost.CostModificationEffectImpl; @@ -10,8 +11,10 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.*; import mage.game.Game; +import mage.target.Target; import mage.util.CardUtil; +import java.util.Collection; import java.util.UUID; /** @@ -72,15 +75,11 @@ class BorealElementalCostIncreaseEffect extends CostModificationEffectImpl { .getSelectedModes() .stream() .map(uuid -> abilityToModify.getModes().get(uuid)) - .anyMatch(mode -> mode - .getTargets() - .stream() - .anyMatch(target -> target - .getTargets() - .stream() - .anyMatch(uuid -> uuid.equals(source.getSourceId())) - ) - ); + .map(Mode::getTargets) + .flatMap(Collection::stream) + .map(Target::getTargets) + .flatMap(Collection::stream) + .anyMatch(uuid -> uuid.equals(source.getSourceId())); } @Override diff --git a/Mage.Sets/src/mage/cards/b/BorosFuryShield.java b/Mage.Sets/src/mage/cards/b/BorosFuryShield.java index 509e6fd4e6..4b744fbe53 100644 --- a/Mage.Sets/src/mage/cards/b/BorosFuryShield.java +++ b/Mage.Sets/src/mage/cards/b/BorosFuryShield.java @@ -37,7 +37,7 @@ public final class BorosFuryShield extends CardImpl { // If {R} was spent to cast Boros Fury-Shield, it deals damage to that creature's controller equal to the creature's power. this.getSpellAbility().addEffect(new ConditionalOneShotEffect( new BorosFuryShieldDamageEffect(), - new ManaWasSpentCondition(ColoredManaSymbol.R), "If {R} was spent to cast {this}, it deals damage to that creature's controller equal to the creature's power")); + new ManaWasSpentCondition(ColoredManaSymbol.R), "If {R} was spent to cast this spell, it deals damage to that creature's controller equal to the creature's power")); } public BorosFuryShield(final BorosFuryShield card) { diff --git a/Mage.Sets/src/mage/cards/b/BragoKingEternal.java b/Mage.Sets/src/mage/cards/b/BragoKingEternal.java index f1445fd1ee..ce1353d4d0 100644 --- a/Mage.Sets/src/mage/cards/b/BragoKingEternal.java +++ b/Mage.Sets/src/mage/cards/b/BragoKingEternal.java @@ -1,7 +1,5 @@ - package mage.cards.b; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; @@ -20,8 +18,9 @@ import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.CardTypePredicate; import mage.target.common.TargetControlledPermanent; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class BragoKingEternal extends CardImpl { @@ -29,7 +28,7 @@ public final class BragoKingEternal extends CardImpl { public BragoKingEternal(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{W}{U}"); addSuperType(SuperType.LEGENDARY); - this.subtype.add(SubType.SPIRIT); + this.subtype.add(SubType.SPIRIT, SubType.NOBLE); this.power = new MageInt(2); this.toughness = new MageInt(4); diff --git a/Mage.Sets/src/mage/cards/b/BramblefortFink.java b/Mage.Sets/src/mage/cards/b/BramblefortFink.java new file mode 100644 index 0000000000..8356669ee0 --- /dev/null +++ b/Mage.Sets/src/mage/cards/b/BramblefortFink.java @@ -0,0 +1,47 @@ +package mage.cards.b; + +import mage.MageInt; +import mage.abilities.common.ActivateIfConditionActivatedAbility; +import mage.abilities.condition.Condition; +import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.effects.common.continuous.SetPowerToughnessSourceEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledPlaneswalkerPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class BramblefortFink extends CardImpl { + + private static final FilterPermanent filter + = new FilterControlledPlaneswalkerPermanent(SubType.OKO, "you control an Oko planeswalker"); + private static final Condition condition = new PermanentsOnTheBattlefieldCondition(filter); + + public BramblefortFink(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{G}"); + + this.subtype.add(SubType.OUPHE); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // {8}: Bramblefort Fink has base power and toughness 10/10 until end of turn. Activate this ability only if you control an Oko planeswalker. + this.addAbility(new ActivateIfConditionActivatedAbility(Zone.BATTLEFIELD, new SetPowerToughnessSourceEffect( + 10, 10, Duration.EndOfTurn, SubLayer.SetPT_7b + ).setText("{this} has base power and toughness 10/10 until end of turn"), new GenericManaCost(8), condition)); + } + + private BramblefortFink(final BramblefortFink card) { + super(card); + } + + @Override + public BramblefortFink copy() { + return new BramblefortFink(this); + } +} diff --git a/Mage.Sets/src/mage/cards/b/BrazenBorrower.java b/Mage.Sets/src/mage/cards/b/BrazenBorrower.java new file mode 100644 index 0000000000..14bc967401 --- /dev/null +++ b/Mage.Sets/src/mage/cards/b/BrazenBorrower.java @@ -0,0 +1,63 @@ +package mage.cards.b; + +import mage.MageInt; +import mage.abilities.common.CanBlockOnlyFlyingAbility; +import mage.abilities.effects.common.ReturnToHandTargetEffect; +import mage.abilities.keyword.FlashAbility; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.AdventureCard; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.TargetController; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterNonlandPermanent; +import mage.filter.predicate.permanent.ControllerPredicate; +import mage.target.TargetPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class BrazenBorrower extends AdventureCard { + + private static final FilterPermanent filter + = new FilterNonlandPermanent("nonland permanent an opponent controls"); + + static { + filter.add(new ControllerPredicate(TargetController.OPPONENT)); + } + + public BrazenBorrower(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, new CardType[]{CardType.INSTANT}, "{1}{U}{U}", "Petty Theft", "{1}{U}"); + + this.subtype.add(SubType.FAERIE); + this.subtype.add(SubType.ROGUE); + this.power = new MageInt(3); + this.toughness = new MageInt(1); + + // Flash + this.addAbility(FlashAbility.getInstance()); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // Bazen Borrower can block only creatures with flying. + this.addAbility(new CanBlockOnlyFlyingAbility()); + + // Petty Theft + // Return target nonland permanent an opponent controls to its owner's hand. + this.getAdventureSpellAbility().addEffect(new ReturnToHandTargetEffect()); + this.getAdventureSpellAbility().addTarget(new TargetPermanent(filter)); + } + + private BrazenBorrower(final BrazenBorrower card) { + super(card); + } + + @Override + public BrazenBorrower copy() { + return new BrazenBorrower(this); + } +} diff --git a/Mage.Sets/src/mage/cards/b/BrimstoneTrebuchet.java b/Mage.Sets/src/mage/cards/b/BrimstoneTrebuchet.java new file mode 100644 index 0000000000..e36f61c957 --- /dev/null +++ b/Mage.Sets/src/mage/cards/b/BrimstoneTrebuchet.java @@ -0,0 +1,57 @@ +package mage.cards.b; + +import mage.MageInt; +import mage.abilities.common.EntersBattlefieldControlledTriggeredAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.effects.common.DamagePlayersEffect; +import mage.abilities.effects.common.UntapSourceEffect; +import mage.abilities.keyword.DefenderAbility; +import mage.abilities.keyword.ReachAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.TargetController; +import mage.filter.FilterPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class BrimstoneTrebuchet extends CardImpl { + + private static final FilterPermanent filter = new FilterPermanent(SubType.KNIGHT, "a Knight"); + + public BrimstoneTrebuchet(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{2}{R}"); + + this.subtype.add(SubType.WALL); + this.power = new MageInt(1); + this.toughness = new MageInt(3); + + // Defender + this.addAbility(DefenderAbility.getInstance()); + + // Reach + this.addAbility(ReachAbility.getInstance()); + + // {T}: Brimstone Trebuchet deals 1 damage to each opponent. + this.addAbility(new SimpleActivatedAbility( + new DamagePlayersEffect(1, TargetController.OPPONENT), new TapSourceCost() + )); + + // Whenever a Knight enters the battlefield under your control, untap Brimstone Trebuchet. + this.addAbility(new EntersBattlefieldControlledTriggeredAbility(new UntapSourceEffect(), filter)); + } + + private BrimstoneTrebuchet(final BrimstoneTrebuchet card) { + super(card); + } + + @Override + public BrimstoneTrebuchet copy() { + return new BrimstoneTrebuchet(this); + } +} diff --git a/Mage.Sets/src/mage/cards/b/BrimstoneVolley.java b/Mage.Sets/src/mage/cards/b/BrimstoneVolley.java index d0fca03525..d58a4b1021 100644 --- a/Mage.Sets/src/mage/cards/b/BrimstoneVolley.java +++ b/Mage.Sets/src/mage/cards/b/BrimstoneVolley.java @@ -1,20 +1,17 @@ package mage.cards.b; -import java.util.UUID; -import mage.abilities.Ability; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.condition.common.HellbentCondition; +import mage.abilities.decorator.ConditionalOneShotEffect; +import mage.abilities.effects.common.DamageTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Outcome; -import mage.game.Game; -import mage.game.permanent.Permanent; -import mage.players.Player; import mage.target.common.TargetAnyTarget; -import mage.watchers.Watcher; import mage.watchers.common.MorbidWatcher; +import java.util.UUID; + /** * @author nantuko */ @@ -25,8 +22,13 @@ public final class BrimstoneVolley extends CardImpl { // Brimstone Volley deals 3 damage to any target. // Morbid — Brimstone Volley deals 5 damage to that creature or player instead if a creature died this turn. - this.getSpellAbility().addEffect(new BrimstoneVolleyEffect()); + this.getSpellAbility().addEffect(new ConditionalOneShotEffect( + new DamageTargetEffect(3), new DamageTargetEffect(5), HellbentCondition.instance, + "{this} deals 3 damage to any target." + + "
Morbid — {this} deals 5 damage instead if a creature died this turn." + )); this.getSpellAbility().addTarget(new TargetAnyTarget()); + this.getSpellAbility().addWatcher(new MorbidWatcher()); } public BrimstoneVolley(final BrimstoneVolley card) { @@ -38,41 +40,3 @@ public final class BrimstoneVolley extends CardImpl { return new BrimstoneVolley(this); } } - -class BrimstoneVolleyEffect extends OneShotEffect { - - public BrimstoneVolleyEffect() { - super(Outcome.Damage); - staticText = "{this} deals 3 damage to any target.\n Morbid — {this} deals 5 damage to that permanent or player instead if a creature died this turn"; - } - - public BrimstoneVolleyEffect(final BrimstoneVolleyEffect effect) { - super(effect); - } - - @Override - public boolean apply(Game game, Ability source) { - int damage = 3; - MorbidWatcher watcher = game.getState().getWatcher(MorbidWatcher.class); - if (watcher != null && watcher.conditionMet()) { - damage = 5; - } - Permanent permanent = game.getPermanent(targetPointer.getFirst(game, source)); - if (permanent != null) { - permanent.damage(damage, source.getSourceId(), game, false, true); - return true; - } - Player player = game.getPlayer(targetPointer.getFirst(game, source)); - if (player != null) { - player.damage(damage, source.getSourceId(), game, false, true); - return true; - } - return false; - } - - @Override - public BrimstoneVolleyEffect copy() { - return new BrimstoneVolleyEffect(this); - } - -} diff --git a/Mage.Sets/src/mage/cards/b/BurningYardTrainer.java b/Mage.Sets/src/mage/cards/b/BurningYardTrainer.java new file mode 100644 index 0000000000..3d37d2b461 --- /dev/null +++ b/Mage.Sets/src/mage/cards/b/BurningYardTrainer.java @@ -0,0 +1,70 @@ +package mage.cards.b; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.common.continuous.BoostTargetEffect; +import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; +import mage.abilities.keyword.HasteAbility; +import mage.abilities.keyword.TrampleAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledPermanent; +import mage.filter.predicate.permanent.AnotherPredicate; +import mage.target.TargetPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class BurningYardTrainer extends CardImpl { + + private static final FilterPermanent filter = new FilterControlledPermanent(SubType.KNIGHT); + + static { + filter.add(AnotherPredicate.instance); + } + + public BurningYardTrainer(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{R}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.KNIGHT); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // Trample + this.addAbility(TrampleAbility.getInstance()); + + // Haste + this.addAbility(HasteAbility.getInstance()); + + // When Burning-Yard Trainer enters the battlefield, another target Knight you control gets +2/+2 and gains trample and haste until end of turn. + Ability ability = new EntersBattlefieldTriggeredAbility( + new BoostTargetEffect(2, 2, Duration.EndOfTurn) + .setText("another target Knight you control gets +2/+2") + ); + ability.addEffect(new GainAbilityTargetEffect( + TrampleAbility.getInstance(), Duration.EndOfTurn + ).setText("and gains trample")); + ability.addEffect(new GainAbilityTargetEffect( + HasteAbility.getInstance(), Duration.EndOfTurn + ).setText("and haste until end of turn")); + ability.addTarget(new TargetPermanent(filter)); + this.addAbility(ability); + } + + private BurningYardTrainer(final BurningYardTrainer card) { + super(card); + } + + @Override + public BurningYardTrainer copy() { + return new BurningYardTrainer(this); + } +} diff --git a/Mage.Sets/src/mage/cards/c/CacklingFlames.java b/Mage.Sets/src/mage/cards/c/CacklingFlames.java index 5c7ba05fa3..194036356c 100644 --- a/Mage.Sets/src/mage/cards/c/CacklingFlames.java +++ b/Mage.Sets/src/mage/cards/c/CacklingFlames.java @@ -1,8 +1,5 @@ - package mage.cards.c; -import java.util.UUID; -import mage.abilities.condition.InvertCondition; import mage.abilities.condition.common.HellbentCondition; import mage.abilities.decorator.ConditionalOneShotEffect; import mage.abilities.effects.common.DamageTargetEffect; @@ -11,8 +8,9 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.target.common.TargetAnyTarget; +import java.util.UUID; + /** - * * @author JotaPeRL */ public final class CacklingFlames extends CardImpl { @@ -21,16 +19,12 @@ public final class CacklingFlames extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{3}{R}"); // Cackling Flames deals 3 damage to any target. - this.getSpellAbility().addEffect(new ConditionalOneShotEffect( - new DamageTargetEffect(3), - new InvertCondition(HellbentCondition.instance), - "{this} deals 3 damage to any target")); // Hellbent - Cackling Flames deals 5 damage to that creature or player instead if you have no cards in hand. this.getSpellAbility().addEffect(new ConditionalOneShotEffect( - new DamageTargetEffect(5), - HellbentCondition.instance, - "

Hellbent — {this} deals 5 damage to that permanent or player instead if you have no cards in hand.")); - + new DamageTargetEffect(3), new DamageTargetEffect(5), HellbentCondition.instance, + "{this} deals 3 damage to any target
Hellbent " + + "— {this} deals 5 damage instead if you have no cards in hand." + )); this.getSpellAbility().addTarget(new TargetAnyTarget()); } diff --git a/Mage.Sets/src/mage/cards/c/CalculatingLich.java b/Mage.Sets/src/mage/cards/c/CalculatingLich.java new file mode 100644 index 0000000000..d003b57b95 --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/CalculatingLich.java @@ -0,0 +1,85 @@ +package mage.cards.c; + +import mage.MageInt; +import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.effects.common.LoseLifeTargetEffect; +import mage.abilities.keyword.MenaceAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.Zone; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.players.Player; +import mage.target.targetpointer.FixedTarget; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class CalculatingLich extends CardImpl { + + public CalculatingLich(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{B}{B}"); + + this.subtype.add(SubType.ZOMBIE); + this.subtype.add(SubType.WIZARD); + this.power = new MageInt(5); + this.toughness = new MageInt(5); + + // Menace + this.addAbility(new MenaceAbility()); + + // Whenever a creature attacks one of your opponents, that player loses 1 life. + this.addAbility(new CalculatingLichTriggeredAbility()); + } + + private CalculatingLich(final CalculatingLich card) { + super(card); + } + + @Override + public CalculatingLich copy() { + return new CalculatingLich(this); + } +} + +class CalculatingLichTriggeredAbility extends TriggeredAbilityImpl { + + CalculatingLichTriggeredAbility() { + super(Zone.BATTLEFIELD, null, false); + } + + private CalculatingLichTriggeredAbility(final CalculatingLichTriggeredAbility ability) { + super(ability); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.DECLARED_ATTACKERS; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + Player player = game.getPlayer(getControllerId()); + UUID defenderId = game.getCombat().getDefenderId(event.getSourceId()); + if (player == null || !player.hasOpponent(defenderId, game)) { + return false; + } + getEffects().clear(); + addEffect(new LoseLifeTargetEffect(1).setTargetPointer(new FixedTarget(defenderId, game))); + return true; + } + + @Override + public String getRule() { + return "Whenever a creature attacks one of your opponents, that player loses 1 life."; + } + + @Override + public CalculatingLichTriggeredAbility copy() { + return new CalculatingLichTriggeredAbility(this); + } +} diff --git a/Mage.Sets/src/mage/cards/c/CankerousThirst.java b/Mage.Sets/src/mage/cards/c/CankerousThirst.java index 724a37456d..0531514051 100644 --- a/Mage.Sets/src/mage/cards/c/CankerousThirst.java +++ b/Mage.Sets/src/mage/cards/c/CankerousThirst.java @@ -54,7 +54,7 @@ class CankerousThirstEffect extends OneShotEffect { public CankerousThirstEffect() { super(Outcome.Benefit); - this.staticText = "If {B} was spent to cast {this}, you may have target creature get -3/-3 until end of turn. If {G} was spent to cast {this}, you may have target creature get +3/+3 until end of turn"; + this.staticText = "If {B} was spent to cast {this}, you may have target creature get -3/-3 until end of turn. If {G} was spent to cast this spell, you may have target creature get +3/+3 until end of turn"; } public CankerousThirstEffect(final CankerousThirstEffect effect) { diff --git a/Mage.Sets/src/mage/cards/c/CastleArdenvale.java b/Mage.Sets/src/mage/cards/c/CastleArdenvale.java new file mode 100644 index 0000000000..6e15956b76 --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/CastleArdenvale.java @@ -0,0 +1,61 @@ +package mage.cards.c; + +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.condition.Condition; +import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.decorator.ConditionalOneShotEffect; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.TapSourceEffect; +import mage.abilities.mana.WhiteManaAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.ComparisonType; +import mage.constants.SubType; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledPermanent; +import mage.game.permanent.token.HumanToken; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class CastleArdenvale extends CardImpl { + + private static final FilterPermanent filter = new FilterControlledPermanent(SubType.PLAINS); + private static final Condition condition + = new PermanentsOnTheBattlefieldCondition(filter, ComparisonType.EQUAL_TO, 0); + + public CastleArdenvale(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); + + // Castle Ardenvale enters the battlefield tapped unless you control a Plains. + this.addAbility(new EntersBattlefieldAbility(new ConditionalOneShotEffect( + new TapSourceEffect(), condition + ), "tapped unless you control a Plains")); + + // {T}: Add {W}. + this.addAbility(new WhiteManaAbility()); + + // {2}{W}{W}, {T}: Create a 1/1 white Human creature token. + Ability ability = new SimpleActivatedAbility( + new CreateTokenEffect(new HumanToken()), new ManaCostsImpl("{2}{W}{W}") + ); + ability.addCost(new TapSourceCost()); + this.addAbility(ability); + } + + private CastleArdenvale(final CastleArdenvale card) { + super(card); + } + + @Override + public CastleArdenvale copy() { + return new CastleArdenvale(this); + } +} diff --git a/Mage.Sets/src/mage/cards/c/CastleEmbereth.java b/Mage.Sets/src/mage/cards/c/CastleEmbereth.java new file mode 100644 index 0000000000..2b4f10aea8 --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/CastleEmbereth.java @@ -0,0 +1,61 @@ +package mage.cards.c; + +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.condition.Condition; +import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.decorator.ConditionalOneShotEffect; +import mage.abilities.effects.common.TapSourceEffect; +import mage.abilities.effects.common.continuous.BoostControlledEffect; +import mage.abilities.mana.RedManaAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.ComparisonType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class CastleEmbereth extends CardImpl { + + private static final FilterPermanent filter = new FilterControlledPermanent(SubType.MOUNTAIN); + private static final Condition condition + = new PermanentsOnTheBattlefieldCondition(filter, ComparisonType.EQUAL_TO, 0); + + public CastleEmbereth(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); + + // Castle Embereth enters the battlefield tapped unless you control a Mountain. + this.addAbility(new EntersBattlefieldAbility(new ConditionalOneShotEffect( + new TapSourceEffect(), condition + ), "tapped unless you control a Mountain")); + + // {T}: Add {R}. + this.addAbility(new RedManaAbility()); + + // {1}{R}{R}, {T}: Creatures you control get +1/+0 until end of turn. + Ability ability = new SimpleActivatedAbility( + new BoostControlledEffect(1, 0, Duration.EndOfTurn), new ManaCostsImpl("{1}{R}{R}") + ); + ability.addCost(new TapSourceCost()); + this.addAbility(ability); + } + + private CastleEmbereth(final CastleEmbereth card) { + super(card); + } + + @Override + public CastleEmbereth copy() { + return new CastleEmbereth(this); + } +} diff --git a/Mage.Sets/src/mage/cards/c/CastleGarenbrig.java b/Mage.Sets/src/mage/cards/c/CastleGarenbrig.java new file mode 100644 index 0000000000..4e79fc9239 --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/CastleGarenbrig.java @@ -0,0 +1,99 @@ +package mage.cards.c; + +import mage.ConditionalMana; +import mage.MageObject; +import mage.Mana; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldAbility; +import mage.abilities.condition.Condition; +import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.decorator.ConditionalOneShotEffect; +import mage.abilities.effects.common.TapSourceEffect; +import mage.abilities.mana.ConditionalColoredManaAbility; +import mage.abilities.mana.GreenManaAbility; +import mage.abilities.mana.builder.ConditionalManaBuilder; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.ComparisonType; +import mage.constants.SubType; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledPermanent; +import mage.game.Game; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class CastleGarenbrig extends CardImpl { + + private static final FilterPermanent filter = new FilterControlledPermanent(SubType.FOREST); + private static final Condition condition + = new PermanentsOnTheBattlefieldCondition(filter, ComparisonType.EQUAL_TO, 0); + + public CastleGarenbrig(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); + + // Castle Garenbrig enters the battlefield tapped unless you control a Forest. + this.addAbility(new EntersBattlefieldAbility(new ConditionalOneShotEffect( + new TapSourceEffect(), condition + ), "tapped unless you control a Forest")); + + // {T}: Add {G}. + this.addAbility(new GreenManaAbility()); + + // {2}{G}{G}, {T}: Add six {G}. Spend this mana only to cast creature spells or activate abilities of creatures. + Ability ability = new ConditionalColoredManaAbility( + new ManaCostsImpl("{2}{G}{G}"), Mana.GreenMana(6), new CastleGarenbrigManaBuilder() + ); + ability.addCost(new TapSourceCost()); + this.addAbility(ability); + } + + private CastleGarenbrig(final CastleGarenbrig card) { + super(card); + } + + @Override + public CastleGarenbrig copy() { + return new CastleGarenbrig(this); + } +} + +class CastleGarenbrigManaBuilder extends ConditionalManaBuilder { + + @Override + public ConditionalMana build(Object... options) { + return new CastleGarenbrigConditionalMana(this.mana); + } + + @Override + public String getRule() { + return "Spend this mana only to cast creature spells or activate abilities of creatures"; + } +} + +class CastleGarenbrigConditionalMana extends ConditionalMana { + + CastleGarenbrigConditionalMana(Mana mana) { + super(mana); + this.staticText = "Spend this mana only to cast creature spells or activate abilities of creatures"; + addCondition(CastleGarenbrigManaCondition.instance); + } +} + +enum CastleGarenbrigManaCondition implements Condition { + instance; + + @Override + public boolean apply(Game game, Ability source) { + MageObject object = game.getObject(source.getSourceId()); + if (object != null && object.isCreature()) { + return true; + } + return false; + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/c/CastleLocthwain.java b/Mage.Sets/src/mage/cards/c/CastleLocthwain.java new file mode 100644 index 0000000000..06aa17106c --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/CastleLocthwain.java @@ -0,0 +1,64 @@ +package mage.cards.c; + +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.condition.Condition; +import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.decorator.ConditionalOneShotEffect; +import mage.abilities.dynamicvalue.common.CardsInControllerHandCount; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.LoseLifeSourceControllerEffect; +import mage.abilities.effects.common.TapSourceEffect; +import mage.abilities.mana.BlackManaAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.ComparisonType; +import mage.constants.SubType; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class CastleLocthwain extends CardImpl { + + private static final FilterPermanent filter = new FilterControlledPermanent(SubType.SWAMP); + private static final Condition condition + = new PermanentsOnTheBattlefieldCondition(filter, ComparisonType.EQUAL_TO, 0); + + public CastleLocthwain(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); + + // Castle Locthwain enters the battlefield tapped unless you control a Swamp. + this.addAbility(new EntersBattlefieldAbility(new ConditionalOneShotEffect( + new TapSourceEffect(), condition + ), "tapped unless you control a Swamp")); + + // {T}: Add {B}. + this.addAbility(new BlackManaAbility()); + + // {1}{B}{B}, {T}: Draw a card, then you lose life equal to the number of cards in your hand. + Ability ability = new SimpleActivatedAbility( + new DrawCardSourceControllerEffect(1).setText("draw a card,"), new ManaCostsImpl("{1}{B}{B}") + ); + ability.addEffect(new LoseLifeSourceControllerEffect(CardsInControllerHandCount.instance) + .setText("then you lose life equal to the number of cards in your hand")); + ability.addCost(new TapSourceCost()); + this.addAbility(ability); + } + + private CastleLocthwain(final CastleLocthwain card) { + super(card); + } + + @Override + public CastleLocthwain copy() { + return new CastleLocthwain(this); + } +} diff --git a/Mage.Sets/src/mage/cards/c/CastleVantress.java b/Mage.Sets/src/mage/cards/c/CastleVantress.java new file mode 100644 index 0000000000..9e73d7a217 --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/CastleVantress.java @@ -0,0 +1,58 @@ +package mage.cards.c; + +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.condition.Condition; +import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.decorator.ConditionalOneShotEffect; +import mage.abilities.effects.common.TapSourceEffect; +import mage.abilities.effects.keyword.ScryEffect; +import mage.abilities.mana.BlueManaAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.ComparisonType; +import mage.constants.SubType; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class CastleVantress extends CardImpl { + + private static final FilterPermanent filter = new FilterControlledPermanent(SubType.ISLAND); + private static final Condition condition + = new PermanentsOnTheBattlefieldCondition(filter, ComparisonType.EQUAL_TO, 0); + + public CastleVantress(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); + + // Castle Vantress enters the battlefield tapped unless you control an Island. + this.addAbility(new EntersBattlefieldAbility(new ConditionalOneShotEffect( + new TapSourceEffect(), condition + ), "tapped unless you control an Island")); + + // {T}: Add {U}. + this.addAbility(new BlueManaAbility()); + + // {2}{U}{U}, {T}: Scry 2. + Ability ability = new SimpleActivatedAbility(new ScryEffect(2), new ManaCostsImpl("{2}{U}{U}")); + ability.addCost(new TapSourceCost()); + this.addAbility(ability); + } + + private CastleVantress(final CastleVantress card) { + super(card); + } + + @Override + public CastleVantress copy() { + return new CastleVantress(this); + } +} diff --git a/Mage.Sets/src/mage/cards/c/CauldronFamiliar.java b/Mage.Sets/src/mage/cards/c/CauldronFamiliar.java new file mode 100644 index 0000000000..f9ba1ce582 --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/CauldronFamiliar.java @@ -0,0 +1,55 @@ +package mage.cards.c; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.SacrificeTargetCost; +import mage.abilities.effects.common.GainLifeEffect; +import mage.abilities.effects.common.LoseLifeOpponentsEffect; +import mage.abilities.effects.common.ReturnSourceFromGraveyardToBattlefieldEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.Zone; +import mage.filter.common.FilterControlledPermanent; +import mage.target.common.TargetControlledPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class CauldronFamiliar extends CardImpl { + + private static final FilterControlledPermanent filter = new FilterControlledPermanent(SubType.FOOD, "a Food"); + + public CauldronFamiliar(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{B}"); + + this.subtype.add(SubType.CAT); + this.power = new MageInt(1); + this.toughness = new MageInt(1); + + // When Cauldron Familiar enters the battlefield, each opponent loses 1 life and you gain 1 life. + Ability ability = new EntersBattlefieldTriggeredAbility(new LoseLifeOpponentsEffect(1)); + ability.addEffect(new GainLifeEffect(1).concatBy("and")); + this.addAbility(ability); + + // Sacrifice a Food: Return Cauldron Familiar from your graveyard to the battlefield. + this.addAbility(new SimpleActivatedAbility( + Zone.GRAVEYARD, new ReturnSourceFromGraveyardToBattlefieldEffect(), + new SacrificeTargetCost(new TargetControlledPermanent(filter)) + )); + } + + private CauldronFamiliar(final CauldronFamiliar card) { + super(card); + } + + @Override + public CauldronFamiliar copy() { + return new CauldronFamiliar(this); + } +} diff --git a/Mage.Sets/src/mage/cards/c/CauldronsGift.java b/Mage.Sets/src/mage/cards/c/CauldronsGift.java new file mode 100644 index 0000000000..923e9568a8 --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/CauldronsGift.java @@ -0,0 +1,92 @@ +package mage.cards.c; + +import mage.abilities.Ability; +import mage.abilities.condition.common.AdamantCondition; +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.constants.Zone; +import mage.counters.CounterType; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.TargetCard; +import mage.target.common.TargetCardInYourGraveyard; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class CauldronsGift extends CardImpl { + + public CauldronsGift(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{4}{B}"); + + // Adamant — If at least three black mana was spent to cast this spell, put the top four cards of your library into your graveyard. + // You may choose a creature card in your graveyard. If you do, return it to the battlefield with an additional +1/+1 counter on it. + this.getSpellAbility().addEffect(new CauldronsGiftEffect()); + } + + private CauldronsGift(final CauldronsGift card) { + super(card); + } + + @Override + public CauldronsGift copy() { + return new CauldronsGift(this); + } +} + +class CauldronsGiftEffect extends OneShotEffect { + + CauldronsGiftEffect() { + super(Outcome.Benefit); + staticText = "Adamant — If at least three black mana was spent to cast this spell, " + + "put the top four cards of your library into your graveyard." + + "
You may choose a creature card in your graveyard. " + + "If you do, return it to the battlefield with an additional +1/+1 counter on it."; + } + + private CauldronsGiftEffect(final CauldronsGiftEffect effect) { + super(effect); + } + + @Override + public CauldronsGiftEffect copy() { + return new CauldronsGiftEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; + } + if (AdamantCondition.BLACK.apply(game, source)) { + player.moveCards(player.getLibrary().getTopCards(game, 4), Zone.GRAVEYARD, source, game); + } + if (player.getGraveyard().count(StaticFilters.FILTER_CARD_CREATURE, game) == 0 + || !player.chooseUse(outcome, "Choose a creature card in your graveyard to return to the battlefield?", source, game)) { + return true; + } + TargetCard target = new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD); + target.setNotTarget(true); + if (!player.choose(outcome, player.getGraveyard(), target, game)) { + return false; + } + Card card = game.getCard(target.getFirstTarget()); + if (card == null || !player.moveCards(card, Zone.BATTLEFIELD, source, game)) { + return false; + } + Permanent permanent = game.getPermanent(card.getId()); + if (permanent != null) { + permanent.addCounters(CounterType.P1P1.createInstance(), source, game); + } + return true; + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/c/CavalierOfFlame.java b/Mage.Sets/src/mage/cards/c/CavalierOfFlame.java index d39443a884..6021ff0504 100644 --- a/Mage.Sets/src/mage/cards/c/CavalierOfFlame.java +++ b/Mage.Sets/src/mage/cards/c/CavalierOfFlame.java @@ -103,7 +103,7 @@ class CavalierOfFlameEffect extends OneShotEffect { return false; } TargetCardInHand target = new TargetCardInHand(0, player.getHand().size(), StaticFilters.FILTER_CARD); - if (player.choose(outcome, player.getHand(), target, game)) { + if (player.choose(Outcome.Discard, player.getHand(), target, game)) { int counter = target .getTargets() .stream() diff --git a/Mage.Sets/src/mage/cards/c/CephalidAristocrat.java b/Mage.Sets/src/mage/cards/c/CephalidAristocrat.java index 7cdf081dfc..18f3ea581e 100644 --- a/Mage.Sets/src/mage/cards/c/CephalidAristocrat.java +++ b/Mage.Sets/src/mage/cards/c/CephalidAristocrat.java @@ -1,7 +1,5 @@ - package mage.cards.c; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.BecomesTargetTriggeredAbility; import mage.abilities.effects.common.PutTopCardOfLibraryIntoGraveControllerEffect; @@ -10,15 +8,16 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; +import java.util.UUID; + /** - * * @author fireshoes */ public final class CephalidAristocrat extends CardImpl { public CephalidAristocrat(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{4}{U}"); - this.subtype.add(SubType.CEPHALID); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{U}"); + this.subtype.add(SubType.CEPHALID, SubType.NOBLE); this.power = new MageInt(3); this.toughness = new MageInt(3); diff --git a/Mage.Sets/src/mage/cards/c/ChainedThroatseeker.java b/Mage.Sets/src/mage/cards/c/ChainedThroatseeker.java index f9ac5ba327..ded5fb991e 100644 --- a/Mage.Sets/src/mage/cards/c/ChainedThroatseeker.java +++ b/Mage.Sets/src/mage/cards/c/ChainedThroatseeker.java @@ -10,7 +10,6 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.SubType; -import mage.constants.Zone; import mage.counters.CounterType; import mage.game.Game; import mage.game.permanent.Permanent; @@ -34,10 +33,10 @@ public final class ChainedThroatseeker extends CardImpl { this.addAbility(InfectAbility.getInstance()); // Chained Throatseeker can't attack unless defending player is poisoned. - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new ChainedThroatseekerCantAttackEffect())); + this.addAbility(new SimpleStaticAbility(new ChainedThroatseekerCantAttackEffect())); } - public ChainedThroatseeker(final ChainedThroatseeker card) { + private ChainedThroatseeker(final ChainedThroatseeker card) { super(card); } @@ -49,12 +48,12 @@ public final class ChainedThroatseeker extends CardImpl { class ChainedThroatseekerCantAttackEffect extends RestrictionEffect { - public ChainedThroatseekerCantAttackEffect() { + ChainedThroatseekerCantAttackEffect() { super(Duration.WhileOnBattlefield); staticText = "{this} can't attack unless defending player is poisoned"; } - public ChainedThroatseekerCantAttackEffect(final ChainedThroatseekerCantAttackEffect effect) { + private ChainedThroatseekerCantAttackEffect(final ChainedThroatseekerCantAttackEffect effect) { super(effect); } @@ -65,16 +64,12 @@ class ChainedThroatseekerCantAttackEffect extends RestrictionEffect { @Override public boolean canAttack(Permanent attacker, UUID defenderId, Ability source, Game game, boolean canUseChooseDialogs) { - Player targetPlayer = game.getPlayer(defenderId); - if (targetPlayer != null) { - return targetPlayer.getCounters().containsKey(CounterType.POISON); - } - return false; + Player targetPlayer = game.getPlayerOrPlaneswalkerController(defenderId); + return targetPlayer != null && targetPlayer.getCounters().containsKey(CounterType.POISON); } @Override public ChainedThroatseekerCantAttackEffect copy() { return new ChainedThroatseekerCantAttackEffect(this); } - -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/cards/c/CharmedSleep.java b/Mage.Sets/src/mage/cards/c/CharmedSleep.java new file mode 100644 index 0000000000..41daf61253 --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/CharmedSleep.java @@ -0,0 +1,52 @@ +package mage.cards.c; + +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.AttachEffect; +import mage.abilities.effects.common.DontUntapInControllersUntapStepEnchantedEffect; +import mage.abilities.effects.common.TapEnchantedEffect; +import mage.abilities.keyword.EnchantAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.target.TargetPermanent; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class CharmedSleep extends CardImpl { + + public CharmedSleep(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{U}{U}"); + + this.subtype.add(SubType.AURA); + + // Enchant creature + TargetPermanent auraTarget = new TargetCreaturePermanent(); + this.getSpellAbility().addTarget(auraTarget); + this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); + Ability ability = new EnchantAbility(auraTarget.getTargetName()); + this.addAbility(ability); + + // When Charmed Sleep enters the battlefield, tap enchanted creature. + this.addAbility(new EntersBattlefieldTriggeredAbility(new TapEnchantedEffect())); + + // Enchanted creature doesn't untap during its controller's untap step. + this.addAbility(new SimpleStaticAbility(new DontUntapInControllersUntapStepEnchantedEffect())); + } + + private CharmedSleep(final CharmedSleep card) { + super(card); + } + + @Override + public CharmedSleep copy() { + return new CharmedSleep(this); + } +} diff --git a/Mage.Sets/src/mage/cards/c/CharmingPrince.java b/Mage.Sets/src/mage/cards/c/CharmingPrince.java new file mode 100644 index 0000000000..a1b2419257 --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/CharmingPrince.java @@ -0,0 +1,113 @@ +package mage.cards.c; + +import mage.MageInt; +import mage.MageObject; +import mage.abilities.Ability; +import mage.abilities.Mode; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbility; +import mage.abilities.effects.Effect; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.GainLifeEffect; +import mage.abilities.effects.common.ReturnToBattlefieldUnderYourControlTargetEffect; +import mage.abilities.effects.keyword.ScryEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.other.OwnerPredicate; +import mage.filter.predicate.permanent.AnotherPredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.TargetPermanent; +import mage.target.targetpointer.FixedTarget; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class CharmingPrince extends CardImpl { + + + private static final FilterPermanent filter = new FilterCreaturePermanent("another creature you own"); + + static { + filter.add(new OwnerPredicate(TargetController.YOU)); + filter.add(AnotherPredicate.instance); + } + + public CharmingPrince(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.NOBLE); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // When Charming Prince enters the battlefield, choose one — + // • Scry 2. + Ability ability = new EntersBattlefieldTriggeredAbility(new ScryEffect(2)); + + // • You gain 3 life. + ability.addMode(new Mode(new GainLifeEffect(3))); + + // • Exile another target creature you own. Return it to the battlefield under your control at the beginning of the next end step. + Mode mode = new Mode(new CharmingPrinceEffect()); + mode.addTarget(new TargetPermanent(filter)); + ability.addMode(mode); + this.addAbility(ability); + } + + private CharmingPrince(final CharmingPrince card) { + super(card); + } + + @Override + public CharmingPrince copy() { + return new CharmingPrince(this); + } +} + +class CharmingPrinceEffect extends OneShotEffect { + + CharmingPrinceEffect() { + super(Outcome.Benefit); + staticText = "Exile another target creature you own. " + + "Return it to the battlefield under your control at the beginning of the next end step."; + } + + private CharmingPrinceEffect(final CharmingPrinceEffect effect) { + super(effect); + } + + @Override + public CharmingPrinceEffect copy() { + return new CharmingPrinceEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + MageObject sourceObject = game.getObject(source.getSourceId()); + if (controller == null || sourceObject == null) { + return false; + } + Permanent permanent = game.getPermanent(source.getFirstTarget()); + if (permanent == null) { + return false; + } + if (!controller.moveCardToExileWithInfo(permanent, source.getSourceId(), sourceObject.getIdName(), source.getSourceId(), game, Zone.BATTLEFIELD, true)) { + return false; + } + //create delayed triggered ability + Effect effect = new ReturnToBattlefieldUnderYourControlTargetEffect(); + effect.setText("Return it to the battlefield under your control at the beginning of the next end step"); + effect.setTargetPointer(new FixedTarget(permanent.getId(), game)); + game.addDelayedTriggeredAbility(new AtTheBeginOfNextEndStepDelayedTriggeredAbility(effect), source); + return true; + + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/c/ClackbridgeTroll.java b/Mage.Sets/src/mage/cards/c/ClackbridgeTroll.java new file mode 100644 index 0000000000..b8be5017bc --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/ClackbridgeTroll.java @@ -0,0 +1,123 @@ +package mage.cards.c; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.BeginningOfCombatTriggeredAbility; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.CreateTokenTargetEffect; +import mage.abilities.keyword.HasteAbility; +import mage.abilities.keyword.TrampleAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.constants.TargetController; +import mage.filter.common.FilterControlledPermanent; +import mage.filter.predicate.mageobject.CardTypePredicate; +import mage.filter.predicate.permanent.ControllerPredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.game.permanent.token.GoatToken; +import mage.players.Player; +import mage.target.common.TargetControlledPermanent; +import mage.target.common.TargetOpponent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ClackbridgeTroll extends CardImpl { + + public ClackbridgeTroll(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{B}{B}"); + + this.subtype.add(SubType.TROLL); + this.power = new MageInt(8); + this.toughness = new MageInt(8); + + // Trample + this.addAbility(TrampleAbility.getInstance()); + + // Haste + this.addAbility(HasteAbility.getInstance()); + + // When Clackbridge Troll enters the battlefield, target opponent creates three 0/1 white Goat creature tokens. + Ability ability = new EntersBattlefieldTriggeredAbility(new CreateTokenTargetEffect(new GoatToken(), 3)); + ability.addTarget(new TargetOpponent()); + this.addAbility(ability); + + // At the beginning of combat on your turn, any opponent may sacrifice a creature. If a player does, tap Clackbridge Troll, you gain 3 life, and you draw a card. + this.addAbility(new BeginningOfCombatTriggeredAbility( + new ClackbridgeTrollEffect(), TargetController.YOU, false) + ); + } + + private ClackbridgeTroll(final ClackbridgeTroll card) { + super(card); + } + + @Override + public ClackbridgeTroll copy() { + return new ClackbridgeTroll(this); + } +} + +class ClackbridgeTrollEffect extends OneShotEffect { + + ClackbridgeTrollEffect() { + super(Outcome.Benefit); + staticText = "any opponent may sacrifice a creature. If a player does, " + + "tap {this}, you gain 3 life, and you draw a card."; + } + + private ClackbridgeTrollEffect(final ClackbridgeTrollEffect effect) { + super(effect); + } + + @Override + public ClackbridgeTrollEffect copy() { + return new ClackbridgeTrollEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + Permanent sourcePerm = game.getPermanent(source.getSourceId()); + if (controller == null) { + return false; + } + boolean flag = false; + for (UUID opponentId : game.getOpponents(controller.getId())) { + Player opponent = game.getPlayer(opponentId); + if (opponent == null) { + continue; + } + FilterControlledPermanent filter = new FilterControlledPermanent("creature to sacrifice"); + filter.add(new CardTypePredicate(CardType.CREATURE)); + filter.add(new ControllerPredicate(TargetController.YOU)); + TargetControlledPermanent target = new TargetControlledPermanent(filter); + target.setNotTarget(true); + if (!target.canChoose(opponent.getId(), game) + || !opponent.chooseUse(Outcome.AIDontUseIt, "Sacrifice a creature?", source, game) + || !opponent.choose(Outcome.Sacrifice, target, source.getSourceId(), game)) { + continue; + } + Permanent permanent = game.getPermanent(target.getFirstTarget()); + if (permanent == null || !permanent.sacrifice(source.getSourceId(), game)) { + continue; + } + flag = true; + } + if (flag) { + if (sourcePerm != null) { + sourcePerm.tap(game); + } + controller.gainLife(3, game, source); + controller.drawCards(1, game); + } + return true; + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/c/ClaimTheFirstborn.java b/Mage.Sets/src/mage/cards/c/ClaimTheFirstborn.java new file mode 100644 index 0000000000..8d328a6427 --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/ClaimTheFirstborn.java @@ -0,0 +1,51 @@ +package mage.cards.c; + +import mage.abilities.effects.common.UntapTargetEffect; +import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; +import mage.abilities.effects.common.continuous.GainControlTargetEffect; +import mage.abilities.keyword.HasteAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.ComparisonType; +import mage.constants.Duration; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.mageobject.ConvertedManaCostPredicate; +import mage.target.TargetPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ClaimTheFirstborn extends CardImpl { + + private static final FilterPermanent filter + = new FilterCreaturePermanent("creature with converted mana cost 3 or less"); + + static { + filter.add(new ConvertedManaCostPredicate(ComparisonType.FEWER_THAN, 4)); + } + + public ClaimTheFirstborn(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{R}"); + + // Gain control of target creature with converted mana cost 3 or less until end of turn. Untap that creature. It gains haste until end of turn. + this.getSpellAbility().addEffect(new GainControlTargetEffect(Duration.EndOfTurn)); + this.getSpellAbility().addEffect(new UntapTargetEffect() + .setText("Untap that creature")); + this.getSpellAbility().addEffect(new GainAbilityTargetEffect(HasteAbility.getInstance(), Duration.EndOfTurn) + .setText("It gains haste until end of turn.")); + this.getSpellAbility().addTarget(new TargetPermanent(filter)); + } + + private ClaimTheFirstborn(final ClaimTheFirstborn card) { + super(card); + } + + @Override + public ClaimTheFirstborn copy() { + return new ClaimTheFirstborn(this); + } +} diff --git a/Mage.Sets/src/mage/cards/c/ClockworkServant.java b/Mage.Sets/src/mage/cards/c/ClockworkServant.java new file mode 100644 index 0000000000..0e38967ad9 --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/ClockworkServant.java @@ -0,0 +1,44 @@ +package mage.cards.c; + +import mage.MageInt; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.condition.common.AdamantCondition; +import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.watchers.common.ManaSpentToCastWatcher; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ClockworkServant extends CardImpl { + + public ClockworkServant(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{3}"); + + this.subtype.add(SubType.GNOME); + this.power = new MageInt(2); + this.toughness = new MageInt(3); + + // Adamant - When Clockwork Servant enters the battlefield, if at least three mana of the same color was spent to cast it, draw a card. + this.addAbility(new ConditionalInterveningIfTriggeredAbility( + new EntersBattlefieldTriggeredAbility(new DrawCardSourceControllerEffect(1)), + AdamantCondition.ANY, "
Adamant — When {this} enters the battlefield, " + + "if at least three mana of the same color was spent to cast it, draw a card." + ), new ManaSpentToCastWatcher()); + } + + private ClockworkServant(final ClockworkServant card) { + super(card); + } + + @Override + public ClockworkServant copy() { + return new ClockworkServant(this); + } +} diff --git a/Mage.Sets/src/mage/cards/c/CouncilGuardian.java b/Mage.Sets/src/mage/cards/c/CouncilGuardian.java index 0931fdd466..631f174e09 100644 --- a/Mage.Sets/src/mage/cards/c/CouncilGuardian.java +++ b/Mage.Sets/src/mage/cards/c/CouncilGuardian.java @@ -1,9 +1,5 @@ - package mage.cards.c; -import java.util.HashMap; -import java.util.Map; -import java.util.UUID; import mage.MageInt; import mage.ObjectColor; import mage.abilities.Ability; @@ -15,14 +11,17 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.choices.ChoiceColor; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Duration; import mage.constants.Outcome; +import mage.constants.SubType; import mage.game.Game; import mage.players.Player; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + /** - * * @author Styxo */ public final class CouncilGuardian extends CardImpl { @@ -53,7 +52,7 @@ public final class CouncilGuardian extends CardImpl { class CouncilsGuardianEffect extends OneShotEffect { public CouncilsGuardianEffect() { - super(Outcome.Exile); + super(Outcome.Benefit); this.staticText = "starting with you, each player votes for blue, black, red, or green. {this} gains protection from each color with the most votes or tied for most votes"; } @@ -78,7 +77,7 @@ class CouncilsGuardianEffect extends OneShotEffect { Player player = game.getPlayer(playerId); if (player != null) { choice.clearChoice(); - if (player.choose(outcome, choice, game)) { + if (player.choose(Outcome.Detriment, choice, game)) { ObjectColor color = choice.getColor(); if (color != null) { if (chosenColors.containsKey(color)) { diff --git a/Mage.Sets/src/mage/cards/c/CovetousUrge.java b/Mage.Sets/src/mage/cards/c/CovetousUrge.java new file mode 100644 index 0000000000..45b570c261 --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/CovetousUrge.java @@ -0,0 +1,170 @@ +package mage.cards.c; + +import mage.MageObjectReference; +import mage.abilities.Ability; +import mage.abilities.effects.AsThoughEffectImpl; +import mage.abilities.effects.AsThoughManaEffect; +import mage.abilities.effects.OneShotEffect; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.players.ManaPoolItem; +import mage.players.Player; +import mage.target.TargetCard; +import mage.target.common.TargetCardInGraveyard; +import mage.target.common.TargetCardInHand; +import mage.target.common.TargetOpponent; +import mage.target.targetpointer.FixedTarget; + +import java.util.Objects; +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class CovetousUrge extends CardImpl { + + public CovetousUrge(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{U/B}{U/B}{U/B}{U/B}"); + + // Target opponent reveals their hand. You choose a nonland card from that player's graveyard or hand and exile it. You may cast that card for as long as it remains exiled, and you may spend mana as though it were mana of any color to cast that spell. + this.getSpellAbility().addEffect(new CovetousUrgeEffect()); + this.getSpellAbility().addTarget(new TargetOpponent()); + } + + private CovetousUrge(final CovetousUrge card) { + super(card); + } + + @Override + public CovetousUrge copy() { + return new CovetousUrge(this); + } +} + +class CovetousUrgeEffect extends OneShotEffect { + + CovetousUrgeEffect() { + super(Outcome.Benefit); + staticText = "Target opponent reveals their hand. You choose a nonland card from that player's graveyard " + + "or hand and exile it. You may cast that card for as long as it remains exiled," + + " and you may spend mana as though it were mana of any color to cast that spell."; + } + + private CovetousUrgeEffect(final CovetousUrgeEffect effect) { + super(effect); + } + + @Override + public CovetousUrgeEffect copy() { + return new CovetousUrgeEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + Player player = game.getPlayer(source.getFirstTarget()); + if (controller == null || player == null) { + return false; + } + player.revealCards(source, player.getHand(), game); + if (!controller.chooseUse(outcome, "Choose a nonland card to exile?", source, game)) { + return false; + } + TargetCard target; + if (player.getGraveyard().isEmpty() || controller.chooseUse(outcome, + "Exile a nonland card from " + player.getName() + "'s hand or graveyard", + "", "Hand", "Graveyard", source, game)) { + if (player.getHand().isEmpty()) { + return true; + } + target = new TargetCardInHand(StaticFilters.FILTER_CARD_A_NON_LAND); + controller.choose(outcome, player.getHand(), target, game); + } else { + target = new TargetCardInGraveyard(StaticFilters.FILTER_CARD_A_NON_LAND); + controller.choose(outcome, player.getGraveyard(), target, game); + } + Card card = game.getCard(target.getFirstTarget()); + if (card == null || !controller.moveCards(card, Zone.EXILED, source, game)) { + return false; + } + if (card.getSpellAbility() == null) { + return true; + } + game.addEffect(new CovetousUrgeCastFromExileEffect(new MageObjectReference(card, game)), source); + game.addEffect(new CovetousUrgeSpendAnyManaEffect().setTargetPointer(new FixedTarget(card, game)), source); + return true; + } +} + +class CovetousUrgeCastFromExileEffect extends AsThoughEffectImpl { + + private final MageObjectReference mor; + + CovetousUrgeCastFromExileEffect(MageObjectReference mor) { + super(AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, Duration.Custom, Outcome.Benefit); + this.mor = mor; + } + + private CovetousUrgeCastFromExileEffect(final CovetousUrgeCastFromExileEffect effect) { + super(effect); + this.mor = effect.mor; + } + + @Override + public boolean apply(Game game, Ability source) { + return true; + } + + @Override + public CovetousUrgeCastFromExileEffect copy() { + return new CovetousUrgeCastFromExileEffect(this); + } + + @Override + public boolean applies(UUID sourceId, Ability source, UUID affectedControllerId, Game game) { + if (mor.getCard(game) == null) { + discard(); + return false; + } + return mor.refersTo(sourceId, game) && source.isControlledBy(affectedControllerId); + } +} + +class CovetousUrgeSpendAnyManaEffect extends AsThoughEffectImpl implements AsThoughManaEffect { + + CovetousUrgeSpendAnyManaEffect() { + super(AsThoughEffectType.SPEND_OTHER_MANA, Duration.Custom, Outcome.Benefit); + } + + private CovetousUrgeSpendAnyManaEffect(final CovetousUrgeSpendAnyManaEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source) { + return true; + } + + @Override + public CovetousUrgeSpendAnyManaEffect copy() { + return new CovetousUrgeSpendAnyManaEffect(this); + } + + @Override + public boolean applies(UUID objectId, Ability source, UUID affectedControllerId, Game game) { + FixedTarget fixedTarget = ((FixedTarget) getTargetPointer()); + return source.isControlledBy(affectedControllerId) + && Objects.equals(objectId, fixedTarget.getTarget()) + && fixedTarget.getZoneChangeCounter() + 1 == game.getState().getZoneChangeCounter(objectId) + && game.getState().getZone(objectId) == Zone.STACK; + } + + @Override + public ManaType getAsThoughManaType(ManaType manaType, ManaPoolItem mana, UUID affectedControllerId, Ability source, Game game) { + return mana.getFirstAvailable(); + } +} diff --git a/Mage.Sets/src/mage/cards/c/CrashingDrawbridge.java b/Mage.Sets/src/mage/cards/c/CrashingDrawbridge.java new file mode 100644 index 0000000000..fedc767115 --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/CrashingDrawbridge.java @@ -0,0 +1,47 @@ +package mage.cards.c; + +import mage.MageInt; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; +import mage.abilities.keyword.DefenderAbility; +import mage.abilities.keyword.HasteAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.filter.StaticFilters; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class CrashingDrawbridge extends CardImpl { + + public CrashingDrawbridge(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{2}"); + + this.subtype.add(SubType.WALL); + this.power = new MageInt(0); + this.toughness = new MageInt(4); + + // Defender + this.addAbility(DefenderAbility.getInstance()); + + // {T}: Creatures you control gain haste until end of turn. + this.addAbility(new SimpleActivatedAbility(new GainAbilityControlledEffect( + HasteAbility.getInstance(), Duration.EndOfTurn, StaticFilters.FILTER_PERMANENT_CREATURES + ), new TapSourceCost())); + } + + private CrashingDrawbridge(final CrashingDrawbridge card) { + super(card); + } + + @Override + public CrashingDrawbridge copy() { + return new CrashingDrawbridge(this); + } +} diff --git a/Mage.Sets/src/mage/cards/c/CratersClaws.java b/Mage.Sets/src/mage/cards/c/CratersClaws.java index a4b2b4dbfb..a0b6a3d12d 100644 --- a/Mage.Sets/src/mage/cards/c/CratersClaws.java +++ b/Mage.Sets/src/mage/cards/c/CratersClaws.java @@ -28,7 +28,7 @@ public final class CratersClaws extends CardImpl { new DamageTargetEffect(ManacostVariableValue.instance), FerociousCondition.instance, "{this} deals X damage to any target." - + "
Ferocious — {this} deals X plus 2 damage to that permanent or player instead if you control a creature with power 4 or greater")); + + "
Ferocious — {this} deals X plus 2 damage instead if you control a creature with power 4 or greater")); this.getSpellAbility().addTarget(new TargetAnyTarget()); this.getSpellAbility().addHint(FerociousHint.instance); } diff --git a/Mage.Sets/src/mage/cards/c/CrimsonRoc.java b/Mage.Sets/src/mage/cards/c/CrimsonRoc.java new file mode 100644 index 0000000000..6b7d68697c --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/CrimsonRoc.java @@ -0,0 +1,87 @@ +package mage.cards.c; + +import mage.MageInt; +import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.effects.common.continuous.BoostSourceEffect; +import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; +import mage.abilities.keyword.FirstStrikeAbility; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.constants.Zone; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class CrimsonRoc extends CardImpl { + + public CrimsonRoc(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{R}"); + + this.subtype.add(SubType.BIRD); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // Whenever Crimson Roc blocks a creature without flying, Crimson Roc gets +1/+0 and gains first strike until end of turn. + this.addAbility(new CrimsonRocTriggeredAbility()); + } + + private CrimsonRoc(final CrimsonRoc card) { + super(card); + } + + @Override + public CrimsonRoc copy() { + return new CrimsonRoc(this); + } +} + +class CrimsonRocTriggeredAbility extends TriggeredAbilityImpl { + + CrimsonRocTriggeredAbility() { + super(Zone.BATTLEFIELD, new BoostSourceEffect(1, 0, Duration.EndOfTurn), false); + this.addEffect(new GainAbilitySourceEffect(FirstStrikeAbility.getInstance(), Duration.EndOfTurn)); + } + + private CrimsonRocTriggeredAbility(final CrimsonRocTriggeredAbility ability) { + super(ability); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.BLOCKER_DECLARED; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + if (!event.getSourceId().equals(this.getSourceId())) { + return false; + } + Permanent permanent = game.getPermanent(event.getTargetId()); + return permanent != null + && permanent.isCreature() + && !permanent.getAbilities(game).contains(FlyingAbility.getInstance()); + } + + @Override + public String getRule() { + return "Whenever {this} blocks a creature without flying, " + + "{this} gets +1/+0 and gains first strike until end of turn."; + } + + @Override + public CrimsonRocTriggeredAbility copy() { + return new CrimsonRocTriggeredAbility(this); + } +} diff --git a/Mage.Sets/src/mage/cards/c/CuriousPair.java b/Mage.Sets/src/mage/cards/c/CuriousPair.java new file mode 100644 index 0000000000..f63363f9f3 --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/CuriousPair.java @@ -0,0 +1,39 @@ +package mage.cards.c; + +import mage.MageInt; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.cards.AdventureCard; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.game.permanent.token.FoodToken; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class CuriousPair extends AdventureCard { + + public CuriousPair(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, new CardType[]{CardType.SORCERY}, "{1}{G}", "Treats to Share", "{G}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.PEASANT); + this.power = new MageInt(1); + this.toughness = new MageInt(3); + + // Treats to Share + // Create a Food token. + this.getAdventureSpellAbility().addEffect(new CreateTokenEffect(new FoodToken())); + } + + private CuriousPair(final CuriousPair card) { + super(card); + } + + @Override + public CuriousPair copy() { + return new CuriousPair(this); + } +} diff --git a/Mage.Sets/src/mage/cards/d/DanceOfTheManse.java b/Mage.Sets/src/mage/cards/d/DanceOfTheManse.java new file mode 100644 index 0000000000..b46a38d00c --- /dev/null +++ b/Mage.Sets/src/mage/cards/d/DanceOfTheManse.java @@ -0,0 +1,122 @@ +package mage.cards.d; + +import mage.abilities.Ability; +import mage.abilities.effects.ContinuousEffect; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.continuous.AddCardTypeTargetEffect; +import mage.abilities.effects.common.continuous.SetPowerToughnessTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.cards.Cards; +import mage.cards.CardsImpl; +import mage.constants.*; +import mage.filter.FilterCard; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.CardTypePredicate; +import mage.filter.predicate.mageobject.ConvertedManaCostPredicate; +import mage.filter.predicate.mageobject.SubtypePredicate; +import mage.game.Game; +import mage.players.Player; +import mage.target.Target; +import mage.target.common.TargetCardInYourGraveyard; +import mage.target.targetadjustment.TargetAdjuster; +import mage.target.targetpointer.FixedTarget; + +import java.util.Collection; +import java.util.Objects; +import java.util.UUID; +import java.util.stream.Collectors; + +/** + * @author TheElk801 + */ +public final class DanceOfTheManse extends CardImpl { + + public DanceOfTheManse(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{X}{W}{U}"); + + // Return up to X target artifact and/or non-Aura enchantment cards each with converted mana cost X or less from your graveyard to the battlefield. If X is 6 or more, those permanents are 4/4 creatures in addition to their other types. + this.getSpellAbility().addEffect(new DanceOfTheManseEffect()); + this.getSpellAbility().setTargetAdjuster(DanceOfTheManseAdjuster.instance); + } + + private DanceOfTheManse(final DanceOfTheManse card) { + super(card); + } + + @Override + public DanceOfTheManse copy() { + return new DanceOfTheManse(this); + } +} + +enum DanceOfTheManseAdjuster implements TargetAdjuster { + instance; + + @Override + public void adjustTargets(Ability ability, Game game) { + int xValue = ability.getManaCostsToPay().getX(); + FilterCard filter = new FilterCard("artifact and/or non-Aura enchantment cards " + + "each with converted mana cost " + xValue + " or less from your graveyard"); + filter.add(Predicates.or( + new CardTypePredicate(CardType.ARTIFACT), + Predicates.and( + new CardTypePredicate(CardType.ENCHANTMENT), + Predicates.not(new SubtypePredicate(SubType.AURA)) + ) + )); + filter.add(new ConvertedManaCostPredicate(ComparisonType.FEWER_THAN, xValue + 1)); + ability.getTargets().clear(); + ability.addTarget(new TargetCardInYourGraveyard(0, xValue, filter)); + } +} + +class DanceOfTheManseEffect extends OneShotEffect { + + DanceOfTheManseEffect() { + super(Outcome.Benefit); + staticText = "Return up to X target artifact and/or non-Aura enchantment cards " + + "each with converted mana cost X or less from your graveyard to the battlefield. " + + "If X is 6 or more, those permanents are 4/4 creatures in addition to their other types."; + } + + private DanceOfTheManseEffect(final DanceOfTheManseEffect effect) { + super(effect); + } + + @Override + public DanceOfTheManseEffect copy() { + return new DanceOfTheManseEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; + } + Cards cards = new CardsImpl(source + .getTargets() + .stream() + .map(Target::getTargets) + .flatMap(Collection::stream) + .map(game::getCard) + .collect(Collectors.toSet())); + player.moveCards(cards, Zone.BATTLEFIELD, source, game); + if (source.getManaCostsToPay().getX() < 6) { + return true; + } + cards.stream() + .map(game::getPermanent) + .filter(Objects::nonNull) + .forEach(permanent -> { + ContinuousEffect effect = new AddCardTypeTargetEffect(Duration.EndOfGame, CardType.CREATURE); + effect.setTargetPointer(new FixedTarget(permanent, game)); + game.addEffect(effect, source); + effect = new SetPowerToughnessTargetEffect(4, 4, Duration.EndOfGame); + effect.setTargetPointer(new FixedTarget(permanent, game)); + game.addEffect(effect, source); + }); + return true; + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/d/DawnglowInfusion.java b/Mage.Sets/src/mage/cards/d/DawnglowInfusion.java index 7faec30b05..bf930dca29 100644 --- a/Mage.Sets/src/mage/cards/d/DawnglowInfusion.java +++ b/Mage.Sets/src/mage/cards/d/DawnglowInfusion.java @@ -28,7 +28,7 @@ public final class DawnglowInfusion extends CardImpl { DynamicValue xValue = ManacostVariableValue.instance; this.getSpellAbility().addEffect(new ConditionalOneShotEffect( new GainLifeEffect(xValue), - new ManaWasSpentCondition(ColoredManaSymbol.G), "You gain X life if {G} was spent to cast {this}")); + new ManaWasSpentCondition(ColoredManaSymbol.G), "You gain X life if {G} was spent to cast this spell")); this.getSpellAbility().addEffect(new ConditionalOneShotEffect( new GainLifeEffect(xValue), new ManaWasSpentCondition(ColoredManaSymbol.W), " And X life if {W} was spent to cast it")); diff --git a/Mage.Sets/src/mage/cards/d/DeafeningSilence.java b/Mage.Sets/src/mage/cards/d/DeafeningSilence.java new file mode 100644 index 0000000000..5663fd2f53 --- /dev/null +++ b/Mage.Sets/src/mage/cards/d/DeafeningSilence.java @@ -0,0 +1,115 @@ +package mage.cards.d; + +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.ContinuousRuleModifyingEffectImpl; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.WatcherScope; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.stack.Spell; +import mage.watchers.Watcher; + +import java.util.HashSet; +import java.util.Set; +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class DeafeningSilence extends CardImpl { + + public DeafeningSilence(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{W}"); + + // Each player can't cast more than one noncreature spell each turn. + this.addAbility(new SimpleStaticAbility(new DeafeningSilenceEffect()), new DeafeningSilenceWatcher()); + } + + private DeafeningSilence(final DeafeningSilence card) { + super(card); + } + + @Override + public DeafeningSilence copy() { + return new DeafeningSilence(this); + } +} + +class DeafeningSilenceEffect extends ContinuousRuleModifyingEffectImpl { + + DeafeningSilenceEffect() { + super(Duration.WhileOnBattlefield, Outcome.Detriment); + staticText = "each player can't cast more than one noncreature spell each turn"; + } + + private DeafeningSilenceEffect(final DeafeningSilenceEffect effect) { + super(effect); + } + + @Override + public DeafeningSilenceEffect copy() { + return new DeafeningSilenceEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + return true; + } + + @Override + public boolean checksEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.CAST_SPELL; + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + Card card = game.getCard(event.getTargetId()); + if (card == null || card.isCreature()) { + return false; + } + DeafeningSilenceWatcher watcher = game.getState().getWatcher(DeafeningSilenceWatcher.class); + return watcher != null && watcher.castSpell(event.getPlayerId()); + } +} + +class DeafeningSilenceWatcher extends Watcher { + + private final Set castSpell = new HashSet<>(); + + DeafeningSilenceWatcher() { + super(WatcherScope.GAME); + } + + private DeafeningSilenceWatcher(final DeafeningSilenceWatcher watcher) { + super(watcher); + this.castSpell.addAll(watcher.castSpell); + } + + @Override + public void watch(GameEvent event, Game game) { + if (event.getType() != GameEvent.EventType.SPELL_CAST) { + return; + } + Spell spell = game.getSpell(event.getTargetId()); + if (spell == null || spell.isCreature()) { + return; + } + castSpell.add(event.getPlayerId()); + } + + @Override + public void reset() { + super.reset(); + castSpell.clear(); + } + + boolean castSpell(UUID playerId) { + return castSpell.contains(playerId); + } +} diff --git a/Mage.Sets/src/mage/cards/d/DeathlessKnight.java b/Mage.Sets/src/mage/cards/d/DeathlessKnight.java new file mode 100644 index 0000000000..8b536dbf10 --- /dev/null +++ b/Mage.Sets/src/mage/cards/d/DeathlessKnight.java @@ -0,0 +1,93 @@ +package mage.cards.d; + +import mage.MageInt; +import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.effects.common.ReturnSourceFromGraveyardToHandEffect; +import mage.abilities.keyword.HasteAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.Zone; +import mage.game.Game; +import mage.game.events.GameEvent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class DeathlessKnight extends CardImpl { + + public DeathlessKnight(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{B/G}{B/G}{B/G}{B/G}"); + + this.subtype.add(SubType.SKELETON); + this.subtype.add(SubType.KNIGHT); + this.power = new MageInt(4); + this.toughness = new MageInt(2); + + // Haste + this.addAbility(HasteAbility.getInstance()); + + // When you gain life for the first time each turn, return Deathless Knight from your graveyard to your hand. + this.addAbility(new DeathlessKnightTriggeredAbility()); + } + + private DeathlessKnight(final DeathlessKnight card) { + super(card); + } + + @Override + public DeathlessKnight copy() { + return new DeathlessKnight(this); + } +} + +class DeathlessKnightTriggeredAbility extends TriggeredAbilityImpl { + + private boolean triggeredOnce = false; + + DeathlessKnightTriggeredAbility() { + super(Zone.ALL, new ReturnSourceFromGraveyardToHandEffect(), false); + } + + private DeathlessKnightTriggeredAbility(final DeathlessKnightTriggeredAbility ability) { + super(ability); + this.triggeredOnce = ability.triggeredOnce; + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.GAINED_LIFE + || event.getType() == GameEvent.EventType.END_PHASE_POST; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + if (event.getType() == GameEvent.EventType.END_PHASE_POST) { + triggeredOnce = false; + return false; + } + if (event.getType() != GameEvent.EventType.GAINED_LIFE + || !event.getPlayerId().equals(controllerId) + || game.getState().getZone(this.getSourceId()) == Zone.GRAVEYARD) { + return false; + } + if (triggeredOnce) { + return false; + } + triggeredOnce = true; + return true; + } + + @Override + public String getRule() { + return "When you gain life for the first time each turn, return {this} from your graveyard to your hand."; + } + + @Override + public DeathlessKnightTriggeredAbility copy() { + return new DeathlessKnightTriggeredAbility(this); + } +} diff --git a/Mage.Sets/src/mage/cards/d/DefensiveManeuvers.java b/Mage.Sets/src/mage/cards/d/DefensiveManeuvers.java index afdce81b29..755fe98290 100644 --- a/Mage.Sets/src/mage/cards/d/DefensiveManeuvers.java +++ b/Mage.Sets/src/mage/cards/d/DefensiveManeuvers.java @@ -1,7 +1,5 @@ - package mage.cards.d; -import java.util.UUID; import mage.MageObject; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; @@ -19,8 +17,9 @@ import mage.filter.predicate.mageobject.SubtypePredicate; import mage.game.Game; import mage.players.Player; +import java.util.UUID; + /** - * * @author TheElk801 */ public final class DefensiveManeuvers extends CardImpl { @@ -45,7 +44,7 @@ public final class DefensiveManeuvers extends CardImpl { class DefensiveManeuversEffect extends OneShotEffect { DefensiveManeuversEffect() { - super(Outcome.Benefit); + super(Outcome.BoostCreature); this.staticText = "Creatures of the creature type of your choice get +0/+4 until end of turn."; } diff --git a/Mage.Sets/src/mage/cards/d/DidntSayPlease.java b/Mage.Sets/src/mage/cards/d/DidntSayPlease.java new file mode 100644 index 0000000000..f4e6a186b5 --- /dev/null +++ b/Mage.Sets/src/mage/cards/d/DidntSayPlease.java @@ -0,0 +1,69 @@ +package mage.cards.d; + +import mage.abilities.Ability; +import mage.abilities.effects.Effect; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.CounterTargetEffect; +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.TargetSpell; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class DidntSayPlease extends CardImpl { + + public DidntSayPlease(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{U}{U}"); + + // Counter target spell. Its controller puts the top three cards of their library into their graveyard. + this.getSpellAbility().addEffect(new DidntSayPleaseEffect()); + this.getSpellAbility().addTarget(new TargetSpell()); + } + + private DidntSayPlease(final DidntSayPlease card) { + super(card); + } + + @Override + public DidntSayPlease copy() { + return new DidntSayPlease(this); + } +} + +class DidntSayPleaseEffect extends OneShotEffect { + + private static final Effect effect = new CounterTargetEffect(); + + DidntSayPleaseEffect() { + super(Outcome.Benefit); + staticText = "Counter target spell. Its controller puts " + + "the top three cards of their library into their graveyard."; + } + + private DidntSayPleaseEffect(final DidntSayPleaseEffect effect) { + super(effect); + } + + @Override + public DidntSayPleaseEffect copy() { + return new DidntSayPleaseEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(game.getControllerId(source.getFirstTarget())); + if (player == null) { + return false; + } + player.moveCards(player.getLibrary().getTopCards(game, 3), Zone.GRAVEYARD, source, game); + return effect.apply(game, source); + } +} diff --git a/Mage.Sets/src/mage/cards/d/DoomForetold.java b/Mage.Sets/src/mage/cards/d/DoomForetold.java new file mode 100644 index 0000000000..2a997df0c6 --- /dev/null +++ b/Mage.Sets/src/mage/cards/d/DoomForetold.java @@ -0,0 +1,105 @@ +package mage.cards.d; + +import mage.abilities.Ability; +import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; +import mage.abilities.effects.Effect; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.SacrificeSourceEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.TargetController; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterNonlandPermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.permanent.ControllerIdPredicate; +import mage.filter.predicate.permanent.TokenPredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.game.permanent.token.KnightToken; +import mage.players.Player; +import mage.target.TargetPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class DoomForetold extends CardImpl { + + public DoomForetold(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{W}{B}"); + + // At the beginning of each player's upkeep, that player sacrifices a nonland, nontoken permanent. If that player can't, they discard a card, they lose 2 life, you draw a card, you gain 2 life, you create a 2/2 white Knight creature token with vigilance, then you sacrifice Doom Foretold. + this.addAbility(new BeginningOfUpkeepTriggeredAbility( + new DoomForetoldEffect(), TargetController.ACTIVE, false + )); + } + + private DoomForetold(final DoomForetold card) { + super(card); + } + + @Override + public DoomForetold copy() { + return new DoomForetold(this); + } +} + +class DoomForetoldEffect extends OneShotEffect { + + private static final FilterPermanent filter = new FilterNonlandPermanent("nonland, nontoken permanent"); + + static { + filter.add(Predicates.not(TokenPredicate.instance)); + } + + private static final Effect effect1 = new CreateTokenEffect(new KnightToken()); + private static final Effect effect2 = new SacrificeSourceEffect(); + + DoomForetoldEffect() { + super(Outcome.Benefit); + staticText = "that player sacrifices a nonland, nontoken permanent. " + + "If that player can't, they discard a card, they lose 2 life, you draw a card, you gain 2 life, " + + "you create a 2/2 white Knight creature token with vigilance, then you sacrifice {this}"; + } + + private DoomForetoldEffect(final DoomForetoldEffect effect) { + super(effect); + } + + @Override + public DoomForetoldEffect copy() { + return new DoomForetoldEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + Player player = game.getPlayer(game.getActivePlayerId()); + if (controller == null || player == null) { + return false; + } + FilterPermanent filter2 = filter.copy(); + filter2.add(new ControllerIdPredicate(player.getId())); + if (game.getBattlefield().contains(filter2, 1, game)) { + TargetPermanent target = new TargetPermanent(filter2); + target.setNotTarget(true); + if (player.choose(Outcome.Sacrifice, target, source.getSourceId(), game)) { + Permanent permanent = game.getPermanent(target.getFirstTarget()); + if (permanent != null && permanent.sacrifice(source.getSourceId(), game)) { + return true; + } + } + } + player.discard(1, false, source, game); + player.loseLife(2, game, false); + controller.drawCards(1, game); + controller.gainLife(2, game, source); + effect1.apply(game, source); + effect2.apply(game, source); + return true; + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/d/DreadWarlock.java b/Mage.Sets/src/mage/cards/d/DreadWarlock.java index 7652b982f5..48c352c4f1 100644 --- a/Mage.Sets/src/mage/cards/d/DreadWarlock.java +++ b/Mage.Sets/src/mage/cards/d/DreadWarlock.java @@ -31,6 +31,7 @@ public final class DreadWarlock extends CardImpl { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{B}{B}"); this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.WIZARD); + this.subtype.add(SubType.WARLOCK); this.power = new MageInt(2); this.toughness = new MageInt(2); diff --git a/Mage.Sets/src/mage/cards/d/DrownInTheLoch.java b/Mage.Sets/src/mage/cards/d/DrownInTheLoch.java new file mode 100644 index 0000000000..0fcbf673e2 --- /dev/null +++ b/Mage.Sets/src/mage/cards/d/DrownInTheLoch.java @@ -0,0 +1,70 @@ +package mage.cards.d; + +import mage.MageObject; +import mage.abilities.Mode; +import mage.abilities.effects.common.CounterTargetEffect; +import mage.abilities.effects.common.DestroyTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.filter.FilterPermanent; +import mage.filter.FilterSpell; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.Predicate; +import mage.game.Game; +import mage.players.Player; +import mage.target.TargetPermanent; +import mage.target.TargetSpell; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class DrownInTheLoch extends CardImpl { + + private static final FilterSpell filter + = new FilterSpell("spell with converted mana cost less than or equal to " + + "the number of cards in its controller's graveyard"); + private static final FilterPermanent filter2 + = new FilterCreaturePermanent("creature with converted mana cost less than or equal to " + + "the number of cards in its controller's graveyard"); + + static { + filter.add(DrownInTheLochPredicate.instance); + filter2.add(DrownInTheLochPredicate.instance); + } + + public DrownInTheLoch(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{U}{B}"); + + // Choose one — + // • Counter target spell with converted mana cost less than or equal to the number of cards in its controller's graveyard. + this.getSpellAbility().addEffect(new CounterTargetEffect()); + this.getSpellAbility().addTarget(new TargetSpell(filter)); + + // • Destroy target creature with converted mana cost less than or equal to the number of cards in its controller's graveyard. + Mode mode = new Mode(new DestroyTargetEffect()); + mode.addTarget(new TargetPermanent(filter2)); + this.getSpellAbility().addMode(mode); + } + + private DrownInTheLoch(final DrownInTheLoch card) { + super(card); + } + + @Override + public DrownInTheLoch copy() { + return new DrownInTheLoch(this); + } +} + +enum DrownInTheLochPredicate implements Predicate { + instance; + + @Override + public boolean apply(MageObject input, Game game) { + Player player = game.getPlayer(game.getControllerId(input.getId())); + return player != null && input.getConvertedManaCost() <= player.getGraveyard().size(); + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/d/DryadsCaress.java b/Mage.Sets/src/mage/cards/d/DryadsCaress.java index 6c0fa37837..4450f3abf2 100644 --- a/Mage.Sets/src/mage/cards/d/DryadsCaress.java +++ b/Mage.Sets/src/mage/cards/d/DryadsCaress.java @@ -33,7 +33,7 @@ public final class DryadsCaress extends CardImpl { //If {W} was spent to cast Dryad's Caress, untap all creatures you control. this.getSpellAbility().addEffect(new ConditionalOneShotEffect( new UntapAllControllerEffect(new FilterControlledCreaturePermanent(), rule), - new ManaWasSpentCondition(ColoredManaSymbol.W), "If {W} was spent to cast {this}, untap all creatures you control")); + new ManaWasSpentCondition(ColoredManaSymbol.W), "If {W} was spent to cast this spell, untap all creatures you control")); } public DryadsCaress(final DryadsCaress card) { diff --git a/Mage.Sets/src/mage/cards/d/DwarvenMine.java b/Mage.Sets/src/mage/cards/d/DwarvenMine.java new file mode 100644 index 0000000000..bf26b0e4b4 --- /dev/null +++ b/Mage.Sets/src/mage/cards/d/DwarvenMine.java @@ -0,0 +1,64 @@ +package mage.cards.d; + +import mage.abilities.common.EntersBattlefieldAbility; +import mage.abilities.common.EntersBattlefieldUntappedTriggeredAbility; +import mage.abilities.condition.Condition; +import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; +import mage.abilities.decorator.ConditionalOneShotEffect; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.TapSourceEffect; +import mage.abilities.mana.RedManaAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.ComparisonType; +import mage.constants.SubType; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledPermanent; +import mage.filter.predicate.permanent.AnotherPredicate; +import mage.game.permanent.token.DwarfToken; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class DwarvenMine extends CardImpl { + + private static final FilterPermanent filter + = new FilterControlledPermanent(SubType.MOUNTAIN); + + static { + filter.add(AnotherPredicate.instance); + } + + private static final Condition condition + = new PermanentsOnTheBattlefieldCondition(filter, ComparisonType.FEWER_THAN, 3); + + public DwarvenMine(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); + + this.subtype.add(SubType.MOUNTAIN); + + // ({T}: Add {R}.) + this.addAbility(new RedManaAbility()); + + // Dwarven Mine enters the battlefield tapped unless you control three or more other Mountains. + this.addAbility(new EntersBattlefieldAbility( + new ConditionalOneShotEffect(new TapSourceEffect(), condition), + "tapped unless you control three or more other Mountains" + )); + + // When Dwarven Mine enters the battlefield untapped, create a 1/1 red Dwarf creature token. + this.addAbility(new EntersBattlefieldUntappedTriggeredAbility(new CreateTokenEffect(new DwarfToken()), false)); + } + + private DwarvenMine(final DwarvenMine card) { + super(card); + } + + @Override + public DwarvenMine copy() { + return new DwarvenMine(this); + } +} diff --git a/Mage.Sets/src/mage/cards/d/DwarvenSong.java b/Mage.Sets/src/mage/cards/d/DwarvenSong.java index 6cae2173d9..ac6962d25f 100644 --- a/Mage.Sets/src/mage/cards/d/DwarvenSong.java +++ b/Mage.Sets/src/mage/cards/d/DwarvenSong.java @@ -1,7 +1,5 @@ - package mage.cards.d; -import java.util.UUID; import mage.ObjectColor; import mage.abilities.effects.Effect; import mage.abilities.effects.common.continuous.BecomesColorTargetEffect; @@ -9,11 +7,11 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; -import mage.filter.StaticFilters; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author maxlebedev */ public final class DwarvenSong extends CardImpl { @@ -23,13 +21,12 @@ public final class DwarvenSong extends CardImpl { // Any number of target creatures become red until end of turn. Effect effect = new BecomesColorTargetEffect(ObjectColor.RED, Duration.EndOfTurn); - effect.setText("Any number of target creatures become red until end of turn"); + effect.setText("One or more target creatures become red until end of turn"); this.getSpellAbility().addEffect(effect); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(0, Integer.MAX_VALUE, StaticFilters.FILTER_PERMANENT_CREATURE, false)); - + this.getSpellAbility().addTarget(new TargetCreaturePermanent(1, Integer.MAX_VALUE)); } - public DwarvenSong(final DwarvenSong card) { + private DwarvenSong(final DwarvenSong card) { super(card); } diff --git a/Mage.Sets/src/mage/cards/e/EarthshakerGiant.java b/Mage.Sets/src/mage/cards/e/EarthshakerGiant.java new file mode 100644 index 0000000000..8c6c2c7521 --- /dev/null +++ b/Mage.Sets/src/mage/cards/e/EarthshakerGiant.java @@ -0,0 +1,53 @@ +package mage.cards.e; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.common.continuous.BoostControlledEffect; +import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; +import mage.abilities.keyword.TrampleAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.filter.StaticFilters; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class EarthshakerGiant extends CardImpl { + + public EarthshakerGiant(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{G}{G}"); + + this.subtype.add(SubType.GIANT); + this.subtype.add(SubType.DRUID); + this.power = new MageInt(6); + this.toughness = new MageInt(6); + + // Trample + this.addAbility(TrampleAbility.getInstance()); + + // When Earthshaker Giant enters the battlefield, other creatures you control get +3/+3 and gain trample until end of turn. + Ability ability = new EntersBattlefieldTriggeredAbility(new BoostControlledEffect( + 3, 3, Duration.EndOfTurn, true + ).setText("other creatures you control get +3/+3")); + ability.addEffect(new GainAbilityControlledEffect( + TrampleAbility.getInstance(), Duration.EndOfTurn, + StaticFilters.FILTER_PERMANENT_CREATURE, true + ).setText("and gain trample until end of turn")); + this.addAbility(ability); + } + + private EarthshakerGiant(final EarthshakerGiant card) { + super(card); + } + + @Override + public EarthshakerGiant copy() { + return new EarthshakerGiant(this); + } +} diff --git a/Mage.Sets/src/mage/cards/e/EdgewallInnkeeper.java b/Mage.Sets/src/mage/cards/e/EdgewallInnkeeper.java new file mode 100644 index 0000000000..95ef140f1f --- /dev/null +++ b/Mage.Sets/src/mage/cards/e/EdgewallInnkeeper.java @@ -0,0 +1,50 @@ +package mage.cards.e; + +import mage.MageInt; +import mage.abilities.common.SpellCastControllerTriggeredAbility; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.filter.FilterSpell; +import mage.filter.common.FilterCreatureSpell; +import mage.filter.predicate.mageobject.AdventurePredicate; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class EdgewallInnkeeper extends CardImpl { + + private static final FilterSpell filter + = new FilterCreatureSpell("a creature spell that has an Adventure"); + + static { + filter.add(AdventurePredicate.instance); + } + + public EdgewallInnkeeper(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{G}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.PEASANT); + this.power = new MageInt(1); + this.toughness = new MageInt(1); + + // Whenever you cast a creature spell that has an Adventure, draw a card. + this.addAbility(new SpellCastControllerTriggeredAbility( + new DrawCardSourceControllerEffect(1), filter, false + )); + } + + private EdgewallInnkeeper(final EdgewallInnkeeper card) { + super(card); + } + + @Override + public EdgewallInnkeeper copy() { + return new EdgewallInnkeeper(this); + } +} diff --git a/Mage.Sets/src/mage/cards/e/ElfhameSanctuary.java b/Mage.Sets/src/mage/cards/e/ElfhameSanctuary.java index 15beccd114..7007ce985b 100644 --- a/Mage.Sets/src/mage/cards/e/ElfhameSanctuary.java +++ b/Mage.Sets/src/mage/cards/e/ElfhameSanctuary.java @@ -19,22 +19,23 @@ import mage.target.common.TargetCardInLibrary; import java.util.UUID; /** - * * @author Markedagain */ public final class ElfhameSanctuary extends CardImpl { public ElfhameSanctuary(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{1}{G}"); + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{G}"); // At the beginning of your upkeep, you may search your library for a basic land card, reveal that card, and put it into your hand. If you do, you skip your draw step this turn and shuffle your library. - Ability ability = new BeginningOfUpkeepTriggeredAbility(new SearchLibraryPutInHandEffect(new TargetCardInLibrary(StaticFilters.FILTER_CARD_BASIC_LAND)), TargetController.YOU, true); + Ability ability = new BeginningOfUpkeepTriggeredAbility(new SearchLibraryPutInHandEffect( + new TargetCardInLibrary(StaticFilters.FILTER_CARD_BASIC_LAND), true + ), TargetController.YOU, true); ability.addEffect(new SkipDrawStepThisTurn()); - + this.addAbility(ability); } - public ElfhameSanctuary(final ElfhameSanctuary card) { + private ElfhameSanctuary(final ElfhameSanctuary card) { super(card); } @@ -46,12 +47,12 @@ public final class ElfhameSanctuary extends CardImpl { class SkipDrawStepThisTurn extends ReplacementEffectImpl { - public SkipDrawStepThisTurn() { + SkipDrawStepThisTurn() { super(Duration.UntilYourNextTurn, Outcome.Neutral); staticText = "Skip your draw step this turn"; } - public SkipDrawStepThisTurn(final SkipDrawStepThisTurn effect) { + private SkipDrawStepThisTurn(final SkipDrawStepThisTurn effect) { super(effect); } diff --git a/Mage.Sets/src/mage/cards/e/EliteHeadhunter.java b/Mage.Sets/src/mage/cards/e/EliteHeadhunter.java new file mode 100644 index 0000000000..b5e86c7537 --- /dev/null +++ b/Mage.Sets/src/mage/cards/e/EliteHeadhunter.java @@ -0,0 +1,77 @@ +package mage.cards.e; + +import mage.MageInt; +import mage.MageObject; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.SacrificeTargetCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.keyword.MenaceAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.filter.common.FilterControlledPermanent; +import mage.filter.predicate.ObjectSourcePlayer; +import mage.filter.predicate.ObjectSourcePlayerPredicate; +import mage.game.Game; +import mage.target.common.TargetControlledPermanent; +import mage.target.common.TargetCreatureOrPlaneswalker; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class EliteHeadhunter extends CardImpl { + + private static final FilterControlledPermanent filter + = new FilterControlledPermanent("another creature or an artifact"); + + static { + filter.add(EliteHeadhunterPredicate.instance); + } + + public EliteHeadhunter(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{B/R}{B/R}{B/R}{B/R}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.KNIGHT); + this.power = new MageInt(2); + this.toughness = new MageInt(3); + + // Menace + this.addAbility(new MenaceAbility()); + + // {B/R}{B/R}{B/R}, Sacrifice another creature or an artifact: Elite Headhunter deals 2 damage to target creature or planeswalker. + Ability ability = new SimpleActivatedAbility( + new DamageTargetEffect(2), new ManaCostsImpl("{B/R}{B/R}{B/R}") + ); + ability.addCost(new SacrificeTargetCost(new TargetControlledPermanent(filter))); + ability.addTarget(new TargetCreatureOrPlaneswalker()); + this.addAbility(ability); + } + + private EliteHeadhunter(final EliteHeadhunter card) { + super(card); + } + + @Override + public EliteHeadhunter copy() { + return new EliteHeadhunter(this); + } +} + +enum EliteHeadhunterPredicate implements ObjectSourcePlayerPredicate> { + instance; + + @Override + public boolean apply(ObjectSourcePlayer input, Game game) { + MageObject obj = input.getObject(); + if (obj.getId().equals(input.getSourceId())) { + return obj.isArtifact(); + } + return obj.isCreature() || obj.isArtifact(); + } +} diff --git a/Mage.Sets/src/mage/cards/e/ElvishHealer.java b/Mage.Sets/src/mage/cards/e/ElvishHealer.java new file mode 100644 index 0000000000..2719974459 --- /dev/null +++ b/Mage.Sets/src/mage/cards/e/ElvishHealer.java @@ -0,0 +1,79 @@ +package mage.cards.e; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.PreventDamageToTargetEffect; +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.game.Game; +import mage.game.permanent.Permanent; +import mage.target.common.TargetAnyTarget; +import mage.target.targetpointer.FixedTarget; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ElvishHealer extends CardImpl { + + public ElvishHealer(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{W}"); + + this.subtype.add(SubType.ELF); + this.subtype.add(SubType.CLERIC); + this.power = new MageInt(1); + this.toughness = new MageInt(2); + + // {T}: Prevent the next 1 damage that would be dealt to any target this turn. If it’s a green creature, prevent the next 2 damage instead. + Ability ability = new SimpleActivatedAbility(new ElvishHealerEffect(), new TapSourceCost()); + ability.addTarget(new TargetAnyTarget()); + this.addAbility(ability); + } + + private ElvishHealer(final ElvishHealer card) { + super(card); + } + + @Override + public ElvishHealer copy() { + return new ElvishHealer(this); + } +} + +class ElvishHealerEffect extends OneShotEffect { + + ElvishHealerEffect() { + super(Outcome.Benefit); + staticText = "Prevent the next 1 damage that would be dealt to any target this turn. " + + "If it’s a green creature, prevent the next 2 damage instead."; + } + + private ElvishHealerEffect(final ElvishHealerEffect effect) { + super(effect); + } + + @Override + public ElvishHealerEffect copy() { + return new ElvishHealerEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + int toPrevent = 1; + Permanent permanent = game.getPermanent(source.getFirstTarget()); + if (permanent != null && permanent.isCreature() && permanent.getColor(game).isGreen()) { + toPrevent = 2; + } + game.addEffect(new PreventDamageToTargetEffect(Duration.EndOfTurn, toPrevent) + .setTargetPointer(new FixedTarget(source.getFirstTarget(), game)), source); + return true; + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/e/Embercleave.java b/Mage.Sets/src/mage/cards/e/Embercleave.java new file mode 100644 index 0000000000..2c0d2baa7d --- /dev/null +++ b/Mage.Sets/src/mage/cards/e/Embercleave.java @@ -0,0 +1,111 @@ +package mage.cards.e; + +import mage.abilities.Ability; +import mage.abilities.SpellAbility; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.AttachEffect; +import mage.abilities.effects.common.continuous.BoostEquippedEffect; +import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect; +import mage.abilities.effects.common.cost.CostModificationEffectImpl; +import mage.abilities.keyword.DoubleStrikeAbility; +import mage.abilities.keyword.EquipAbility; +import mage.abilities.keyword.FlashAbility; +import mage.abilities.keyword.TrampleAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.predicate.permanent.AttackingPredicate; +import mage.game.Game; +import mage.target.common.TargetControlledCreaturePermanent; +import mage.util.CardUtil; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class Embercleave extends CardImpl { + + public Embercleave(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{4}{R}{R}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.EQUIPMENT); + + // Flash + this.addAbility(FlashAbility.getInstance()); + + // This spell costs {1} less to cast for each attacking creature you control. + this.addAbility(new SimpleStaticAbility(Zone.ALL, new EmbercleaveCostReductionEffect())); + + // When Embercleave enters the battlefield, attach it to target creature you control. + Ability ability = new EntersBattlefieldTriggeredAbility(new AttachEffect( + Outcome.BoostCreature, "attach it to target creature you control" + ), false); + ability.addTarget(new TargetControlledCreaturePermanent()); + this.addAbility(ability); + + // Equipped creature gets +1/+1 and has double strike and trample. + ability = new SimpleStaticAbility(new BoostEquippedEffect(1, 1)); + ability.addEffect(new GainAbilityAttachedEffect( + DoubleStrikeAbility.getInstance(), AttachmentType.EQUIPMENT + ).setText("and has double strike")); + ability.addEffect(new GainAbilityAttachedEffect( + TrampleAbility.getInstance(), AttachmentType.EQUIPMENT + ).setText("and trample")); + this.addAbility(ability); + + // Equip {3} + this.addAbility(new EquipAbility(3)); + } + + private Embercleave(final Embercleave card) { + super(card); + } + + @Override + public Embercleave copy() { + return new Embercleave(this); + } +} + +class EmbercleaveCostReductionEffect extends CostModificationEffectImpl { + + private static final FilterPermanent filter = new FilterControlledCreaturePermanent(); + + static { + filter.add(AttackingPredicate.instance); + } + + EmbercleaveCostReductionEffect() { + super(Duration.WhileOnStack, Outcome.Benefit, CostModificationType.REDUCE_COST); + staticText = "This spell costs {1} less to cast for each attacking creature you control"; + } + + private EmbercleaveCostReductionEffect(EmbercleaveCostReductionEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source, Ability abilityToModify) { + int reductionAmount = game.getBattlefield().count(filter, source.getSourceId(), source.getControllerId(), game); + CardUtil.reduceCost(abilityToModify, reductionAmount); + return true; + } + + @Override + public boolean applies(Ability abilityToModify, Ability source, Game game) { + if ((abilityToModify instanceof SpellAbility) && abilityToModify.getSourceId().equals(source.getSourceId())) { + return game.getCard(abilityToModify.getSourceId()) != null; + } + return false; + } + + @Override + public EmbercleaveCostReductionEffect copy() { + return new EmbercleaveCostReductionEffect(this); + } +} diff --git a/Mage.Sets/src/mage/cards/e/EmpressGalina.java b/Mage.Sets/src/mage/cards/e/EmpressGalina.java index cf5419eed4..f07c72a432 100644 --- a/Mage.Sets/src/mage/cards/e/EmpressGalina.java +++ b/Mage.Sets/src/mage/cards/e/EmpressGalina.java @@ -1,7 +1,5 @@ - package mage.cards.e; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; @@ -10,21 +8,18 @@ import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.common.continuous.GainControlTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; -import mage.constants.Duration; -import mage.constants.SuperType; -import mage.constants.Zone; +import mage.constants.*; import mage.filter.FilterPermanent; import mage.filter.predicate.mageobject.SupertypePredicate; import mage.target.TargetPermanent; +import java.util.UUID; + /** - * * @author fireshoes */ public final class EmpressGalina extends CardImpl { - + private static final FilterPermanent filter = new FilterPermanent("legendary permanent"); static { @@ -32,9 +27,9 @@ public final class EmpressGalina extends CardImpl { } public EmpressGalina(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{U}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{U}{U}"); addSuperType(SuperType.LEGENDARY); - this.subtype.add(SubType.MERFOLK); + this.subtype.add(SubType.MERFOLK, SubType.NOBLE); this.power = new MageInt(1); this.toughness = new MageInt(3); diff --git a/Mage.Sets/src/mage/cards/e/EmryLurkerOfTheLoch.java b/Mage.Sets/src/mage/cards/e/EmryLurkerOfTheLoch.java new file mode 100644 index 0000000000..428efcfb49 --- /dev/null +++ b/Mage.Sets/src/mage/cards/e/EmryLurkerOfTheLoch.java @@ -0,0 +1,129 @@ +package mage.cards.e; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.SpellAbility; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.effects.AsThoughEffectImpl; +import mage.abilities.effects.common.PutTopCardOfLibraryIntoGraveControllerEffect; +import mage.abilities.effects.common.cost.CostModificationEffectImpl; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.target.common.TargetCardInYourGraveyard; +import mage.util.CardUtil; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class EmryLurkerOfTheLoch extends CardImpl { + + public EmryLurkerOfTheLoch(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{U}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.MERFOLK); + this.subtype.add(SubType.WIZARD); + this.power = new MageInt(1); + this.toughness = new MageInt(2); + + // This spell costs {1} less to cast for each artifact you control. + this.addAbility(new SimpleStaticAbility(Zone.STACK, new EmryLurkerOfTheLochCostReductionEffect())); + + // When Emry, Lurker of the Loch enters the battlefield, put the top four cards of your library into your graveyard. + this.addAbility(new EntersBattlefieldTriggeredAbility( + new PutTopCardOfLibraryIntoGraveControllerEffect(4) + )); + + // {T}: Choose target artifact card in your graveyard. You may cast that card this turn. + Ability ability = new SimpleActivatedAbility(new EmryLurkerOfTheLochPlayEffect(), new TapSourceCost()); + ability.addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_ARTIFACT)); + this.addAbility(ability); + } + + private EmryLurkerOfTheLoch(final EmryLurkerOfTheLoch card) { + super(card); + } + + @Override + public EmryLurkerOfTheLoch copy() { + return new EmryLurkerOfTheLoch(this); + } +} + +class EmryLurkerOfTheLochCostReductionEffect extends CostModificationEffectImpl { + + EmryLurkerOfTheLochCostReductionEffect() { + super(Duration.WhileOnStack, Outcome.Benefit, CostModificationType.REDUCE_COST); + staticText = "This spell costs {1} less to cast for each artifact you control"; + } + + private EmryLurkerOfTheLochCostReductionEffect(final EmryLurkerOfTheLochCostReductionEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source, Ability abilityToModify) { + int reductionAmount = game.getBattlefield().count( + StaticFilters.FILTER_CONTROLLED_PERMANENT_ARTIFACT, + source.getSourceId(), source.getControllerId(), game + ); + CardUtil.reduceCost(abilityToModify, reductionAmount); + return true; + } + + @Override + public boolean applies(Ability abilityToModify, Ability source, Game game) { + return abilityToModify instanceof SpellAbility + && abilityToModify.getSourceId().equals(source.getSourceId()) + && game.getCard(abilityToModify.getSourceId()) != null; + } + + @Override + public EmryLurkerOfTheLochCostReductionEffect copy() { + return new EmryLurkerOfTheLochCostReductionEffect(this); + } +} + +class EmryLurkerOfTheLochPlayEffect extends AsThoughEffectImpl { + + EmryLurkerOfTheLochPlayEffect() { + super(AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, Duration.EndOfTurn, Outcome.Benefit); + staticText = "Choose target artifact card in your graveyard. You may cast that card this turn."; + } + + private EmryLurkerOfTheLochPlayEffect(final EmryLurkerOfTheLochPlayEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source) { + return true; + } + + @Override + public EmryLurkerOfTheLochPlayEffect copy() { + return new EmryLurkerOfTheLochPlayEffect(this); + } + + @Override + public boolean applies(UUID objectId, Ability source, UUID affectedControllerId, Game game) { + UUID targetId = getTargetPointer().getFirst(game, source); + if (targetId != null) { + return targetId.equals(objectId) + && source.isControlledBy(affectedControllerId) + && Zone.GRAVEYARD == game.getState().getZone(objectId); + } else { + // the target card has changed zone meanwhile, so the effect is no longer needed + discard(); + return false; + } + } +} diff --git a/Mage.Sets/src/mage/cards/e/EnchantedCarriage.java b/Mage.Sets/src/mage/cards/e/EnchantedCarriage.java new file mode 100644 index 0000000000..5a4b3011fc --- /dev/null +++ b/Mage.Sets/src/mage/cards/e/EnchantedCarriage.java @@ -0,0 +1,42 @@ +package mage.cards.e; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.constants.SubType; +import mage.abilities.keyword.CrewAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.game.permanent.token.MouseToken; + +/** + * + * @author TheElk801 + */ +public final class EnchantedCarriage extends CardImpl { + + public EnchantedCarriage(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{5}"); + + this.subtype.add(SubType.VEHICLE); + this.power = new MageInt(4); + this.toughness = new MageInt(4); + + // When Enchanted Carriage enters the battlefield, create two 1/1 white Mouse creature tokens. + this.addAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new MouseToken(),2))); + + // Crew 2 + this.addAbility(new CrewAbility(2)); + } + + private EnchantedCarriage(final EnchantedCarriage card) { + super(card); + } + + @Override + public EnchantedCarriage copy() { + return new EnchantedCarriage(this); + } +} diff --git a/Mage.Sets/src/mage/cards/e/EpicDownfall.java b/Mage.Sets/src/mage/cards/e/EpicDownfall.java new file mode 100644 index 0000000000..79e307b008 --- /dev/null +++ b/Mage.Sets/src/mage/cards/e/EpicDownfall.java @@ -0,0 +1,43 @@ +package mage.cards.e; + +import mage.abilities.effects.common.ExileTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.ComparisonType; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.mageobject.ConvertedManaCostPredicate; +import mage.target.TargetPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class EpicDownfall extends CardImpl { + + private static final FilterPermanent filter + = new FilterCreaturePermanent("creature with converted mana cost 3 or greater"); + + static { + filter.add(new ConvertedManaCostPredicate(ComparisonType.MORE_THAN, 2)); + } + + public EpicDownfall(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{1}{B}"); + + // Exile target creature with converted mana cost 3 or greater. + this.getSpellAbility().addEffect(new ExileTargetEffect()); + this.getSpellAbility().addTarget(new TargetPermanent(filter)); + } + + private EpicDownfall(final EpicDownfall card) { + super(card); + } + + @Override + public EpicDownfall copy() { + return new EpicDownfall(this); + } +} diff --git a/Mage.Sets/src/mage/cards/e/EscapeToTheWilds.java b/Mage.Sets/src/mage/cards/e/EscapeToTheWilds.java new file mode 100644 index 0000000000..0c36bdd097 --- /dev/null +++ b/Mage.Sets/src/mage/cards/e/EscapeToTheWilds.java @@ -0,0 +1,119 @@ +package mage.cards.e; + +import mage.abilities.Ability; +import mage.abilities.effects.AsThoughEffectImpl; +import mage.abilities.effects.ContinuousEffect; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.continuous.PlayAdditionalLandsControllerEffect; +import mage.cards.*; +import mage.constants.*; +import mage.game.Game; +import mage.players.Player; +import mage.target.targetpointer.FixedTarget; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class EscapeToTheWilds extends CardImpl { + + public EscapeToTheWilds(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{3}{R}{G}"); + + // Exile the top five cards of your library. You may play cards exiled this way until the end of your next turn. + // You may play an additional land this turn. + this.getSpellAbility().addEffect(new EscapeToTheWildsEffect()); + } + + private EscapeToTheWilds(final EscapeToTheWilds card) { + super(card); + } + + @Override + public EscapeToTheWilds copy() { + return new EscapeToTheWilds(this); + } +} + +class EscapeToTheWildsEffect extends OneShotEffect { + + EscapeToTheWildsEffect() { + super(Outcome.PlayForFree); + this.staticText = "Exile the top five cards of your library. " + + "You may play cards exiled this way until the end of your next turn.
" + + "You may play an additional land this turn."; + } + + private EscapeToTheWildsEffect(final EscapeToTheWildsEffect effect) { + super(effect); + } + + @Override + public EscapeToTheWildsEffect copy() { + return new EscapeToTheWildsEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller == null) { + return false; + } + Cards cards = new CardsImpl(controller.getLibrary().getTopCards(game, 5)); + Card sourceCard = game.getCard(source.getSourceId()); + controller.moveCards(cards, Zone.EXILED, source, game); + + cards.getCards(game).stream().forEach(card -> { + ContinuousEffect effect = new EscapeToTheWildsMayPlayEffect(); + effect.setTargetPointer(new FixedTarget(card.getId())); + game.addEffect(effect, source); + }); + game.addEffect(new PlayAdditionalLandsControllerEffect(1, Duration.EndOfTurn), source); + return true; + } +} + +class EscapeToTheWildsMayPlayEffect extends AsThoughEffectImpl { + + private int castOnTurn = 0; + + EscapeToTheWildsMayPlayEffect() { + super(AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, Duration.Custom, Outcome.Benefit); + this.staticText = "Until the end of your next turn, you may play that card."; + } + + private EscapeToTheWildsMayPlayEffect(final EscapeToTheWildsMayPlayEffect effect) { + super(effect); + castOnTurn = effect.castOnTurn; + } + + @Override + public EscapeToTheWildsMayPlayEffect copy() { + return new EscapeToTheWildsMayPlayEffect(this); + } + + @Override + public void init(Ability source, Game game) { + super.init(source, game); + castOnTurn = game.getTurnNum(); + } + + @Override + public boolean isInactive(Ability source, Game game) { + return castOnTurn != game.getTurnNum() + && game.getPhase().getStep().getType() == PhaseStep.END_TURN + && game.isActivePlayer(source.getControllerId()); + } + + @Override + public boolean apply(Game game, Ability source) { + return true; + } + + @Override + public boolean applies(UUID sourceId, Ability source, UUID affectedControllerId, Game game) { + return source.isControlledBy(affectedControllerId) + && getTargetPointer().getTargets(game, source).contains(sourceId); + } +} diff --git a/Mage.Sets/src/mage/cards/e/EscapedShapeshifter.java b/Mage.Sets/src/mage/cards/e/EscapedShapeshifter.java new file mode 100644 index 0000000000..93457726f3 --- /dev/null +++ b/Mage.Sets/src/mage/cards/e/EscapedShapeshifter.java @@ -0,0 +1,100 @@ +package mage.cards.e; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.ContinuousEffectImpl; +import mage.abilities.keyword.FirstStrikeAbility; +import mage.abilities.keyword.FlyingAbility; +import mage.abilities.keyword.ProtectionAbility; +import mage.abilities.keyword.TrampleAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.filter.StaticFilters; +import mage.filter.predicate.mageobject.ColorPredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; + +import java.util.Collection; +import java.util.Objects; +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class EscapedShapeshifter extends CardImpl { + + public EscapedShapeshifter(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{U}{U}"); + + this.subtype.add(SubType.SHAPESHIFTER); + this.power = new MageInt(3); + this.toughness = new MageInt(4); + + // As long as an opponent controls a creature with flying not named Escaped Shapeshifter, Escaped Shapeshifter has flying. The same is true for first strike, trample, and protection from any color. + this.addAbility(new SimpleStaticAbility(new EscapedShapeshifterEffect())); + } + + private EscapedShapeshifter(final EscapedShapeshifter card) { + super(card); + } + + @Override + public EscapedShapeshifter copy() { + return new EscapedShapeshifter(this); + } +} + +class EscapedShapeshifterEffect extends ContinuousEffectImpl { + + EscapedShapeshifterEffect() { + super(Duration.WhileOnBattlefield, Layer.AbilityAddingRemovingEffects_6, SubLayer.NA, Outcome.AddAbility); + this.addDependedToType(DependencyType.AddingAbility); + staticText = "As long as an opponent controls a creature with flying not named Escaped Shapeshifter, " + + "{this} has flying. The same is true for first strike, trample, and protection from any color."; + } + + private EscapedShapeshifterEffect(final EscapedShapeshifterEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent sourcePermanent = game.getPermanent(source.getSourceId()); + if (sourcePermanent == null) { + return false; + } + + game.getBattlefield() + .getActivePermanents( + StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE, + source.getControllerId(), source.getSourceId(), game + ).stream() + .filter(Objects::nonNull) + .filter(permanent -> permanent.getName() != "Escaped Shapeshifter") + .map(Permanent::getAbilities) + .flatMap(Collection::stream).filter(EscapedShapeshifterEffect::checkAbility) + .forEach(ability -> sourcePermanent.addAbility(ability, source.getSourceId(), game)); + return true; + } + + private static boolean checkAbility(Ability ability) { + if (ability instanceof FlyingAbility + || ability instanceof FirstStrikeAbility + || ability instanceof TrampleAbility) { + return true; + } + return ability instanceof ProtectionAbility + && ((ProtectionAbility) ability) + .getFilter() + .getPredicates() + .stream() + .anyMatch(ColorPredicate.class::isInstance); + } + + @Override + public EscapedShapeshifterEffect copy() { + return new EscapedShapeshifterEffect(this); + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/e/EssenceVortex.java b/Mage.Sets/src/mage/cards/e/EssenceVortex.java new file mode 100644 index 0000000000..72256d7394 --- /dev/null +++ b/Mage.Sets/src/mage/cards/e/EssenceVortex.java @@ -0,0 +1,69 @@ +package mage.cards.e; + +import mage.abilities.Ability; +import mage.abilities.costs.Cost; +import mage.abilities.costs.common.PayLifeCost; +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.game.permanent.Permanent; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class EssenceVortex extends CardImpl { + + public EssenceVortex(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{U}{B}"); + + // Destroy target creature unless its controller pays life equal to its toughness. A creature destroyed this way can't be regenerated. + this.getSpellAbility().addEffect(new EssenceVortexEffect()); + this.getSpellAbility().addTarget(new TargetCreaturePermanent()); + } + + private EssenceVortex(final EssenceVortex card) { + super(card); + } + + @Override + public EssenceVortex copy() { + return new EssenceVortex(this); + } +} + +class EssenceVortexEffect extends OneShotEffect { + + EssenceVortexEffect() { + super(Outcome.Benefit); + staticText = "Destroy target creature unless its controller pays life equal to its toughness. " + + "A creature destroyed this way can't be regenerated."; + } + + private EssenceVortexEffect(final EssenceVortexEffect effect) { + super(effect); + } + + @Override + public EssenceVortexEffect copy() { + return new EssenceVortexEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent permanent = game.getPermanent(source.getFirstTarget()); + if (permanent == null) { + return false; + } + Cost cost = new PayLifeCost(permanent.getToughness().getValue()); + if (cost.pay(source, game, source.getSourceId(), permanent.getControllerId(), true)) { + return true; + } + return permanent.destroy(source.getSourceId(), game, true); + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/e/Extinction.java b/Mage.Sets/src/mage/cards/e/Extinction.java index e77c192cb2..27e3bc3be3 100644 --- a/Mage.Sets/src/mage/cards/e/Extinction.java +++ b/Mage.Sets/src/mage/cards/e/Extinction.java @@ -1,7 +1,5 @@ - package mage.cards.e; -import java.util.UUID; import mage.MageObject; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; @@ -18,8 +16,9 @@ import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; +import java.util.UUID; + /** - * * @author fireshoes */ public final class Extinction extends CardImpl { @@ -44,7 +43,7 @@ public final class Extinction extends CardImpl { class ExtinctionEffect extends OneShotEffect { public ExtinctionEffect() { - super(Outcome.UnboostCreature); + super(Outcome.DestroyPermanent); staticText = "Destroy all creatures of the creature type of your choice"; } diff --git a/Mage.Sets/src/mage/cards/f/FabledPassage.java b/Mage.Sets/src/mage/cards/f/FabledPassage.java new file mode 100644 index 0000000000..7897263e3a --- /dev/null +++ b/Mage.Sets/src/mage/cards/f/FabledPassage.java @@ -0,0 +1,90 @@ +package mage.cards.f; + +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.SacrificeSourceCost; +import mage.abilities.costs.common.TapSourceCost; +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.constants.Zone; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.common.TargetCardInLibrary; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class FabledPassage extends CardImpl { + + public FabledPassage(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); + + // {T}, Sacrifice Fabled Passage: Search your library for a basic land card, put it onto the battlefield tapped, then shuffle your library. Then if you control four or more lands, untap that land. + Ability ability = new SimpleActivatedAbility(new FabledPassageEffect(), new TapSourceCost()); + ability.addCost(new SacrificeSourceCost()); + this.addAbility(ability); + } + + private FabledPassage(final FabledPassage card) { + super(card); + } + + @Override + public FabledPassage copy() { + return new FabledPassage(this); + } +} + +class FabledPassageEffect extends OneShotEffect { + + FabledPassageEffect() { + super(Outcome.Benefit); + staticText = "Search your library for a basic land card, put it onto the battlefield tapped, " + + "then shuffle your library. Then if you control four or more lands, untap that land."; + } + + private FabledPassageEffect(final FabledPassageEffect effect) { + super(effect); + } + + @Override + public FabledPassageEffect copy() { + return new FabledPassageEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; + } + TargetCardInLibrary target = new TargetCardInLibrary(StaticFilters.FILTER_CARD_BASIC_LAND_A); + if (!player.searchLibrary(target, source, game)) { + return false; + } + player.shuffleLibrary(source, game); + Card card = game.getCard(target.getFirstTarget()); + if (card == null) { + return false; + } + if (!player.moveCards(card, Zone.BATTLEFIELD, source, game, true, false, false, null)) { + return false; + } + if (game.getBattlefield().countAll(StaticFilters.FILTER_LAND, source.getControllerId(), game) < 4) { + return true; + } + Permanent permanent = game.getPermanent(card.getId()); + if (permanent == null) { + return false; + } + return permanent.untap(game); + } +} diff --git a/Mage.Sets/src/mage/cards/f/FaeOfWishes.java b/Mage.Sets/src/mage/cards/f/FaeOfWishes.java new file mode 100644 index 0000000000..d6aa24c094 --- /dev/null +++ b/Mage.Sets/src/mage/cards/f/FaeOfWishes.java @@ -0,0 +1,56 @@ +package mage.cards.f; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.DiscardTargetCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.ReturnToHandSourceEffect; +import mage.abilities.effects.common.WishEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.AdventureCard; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.filter.StaticFilters; +import mage.target.common.TargetCardInHand; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class FaeOfWishes extends AdventureCard { + + public FaeOfWishes(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, new CardType[]{CardType.SORCERY}, "{1}{U}", "Granted", "{3}{U}"); + + this.subtype.add(SubType.FAERIE); + this.subtype.add(SubType.WIZARD); + this.power = new MageInt(1); + this.toughness = new MageInt(4); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // {1}{U}, Discard two cards: Return Fae of Wishes to its owner's hand. + Ability ability = new SimpleActivatedAbility( + new ReturnToHandSourceEffect(true), new ManaCostsImpl("{1}{U}") + ); + ability.addCost(new DiscardTargetCost(new TargetCardInHand(2, StaticFilters.FILTER_CARD))); + this.addAbility(ability); + + // Granted + // You may choose a noncreature card you own from outside the game, reveal it, and put it into your hand. + this.getAdventureSpellAbility().addEffect(new WishEffect(StaticFilters.FILTER_CARD_A_NON_LAND)); + } + + private FaeOfWishes(final FaeOfWishes card) { + super(card); + } + + @Override + public FaeOfWishes copy() { + return new FaeOfWishes(this); + } +} diff --git a/Mage.Sets/src/mage/cards/f/FaeburrowElder.java b/Mage.Sets/src/mage/cards/f/FaeburrowElder.java new file mode 100644 index 0000000000..6cfbe65430 --- /dev/null +++ b/Mage.Sets/src/mage/cards/f/FaeburrowElder.java @@ -0,0 +1,142 @@ +package mage.cards.f; + +import mage.MageInt; +import mage.Mana; +import mage.ObjectColor; +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.ManaEffect; +import mage.abilities.effects.common.continuous.BoostSourceEffect; +import mage.abilities.keyword.VigilanceAbility; +import mage.abilities.mana.SimpleManaAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.constants.Zone; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class FaeburrowElder extends CardImpl { + + public FaeburrowElder(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{G}{W}"); + + this.subtype.add(SubType.TREEFOLK); + this.subtype.add(SubType.DRUID); + this.power = new MageInt(0); + this.toughness = new MageInt(0); + + // Vigilance + this.addAbility(VigilanceAbility.getInstance()); + + // Faeburrow Elder gets +1/+1 for each color among permanents you control. + this.addAbility(new SimpleStaticAbility(new BoostSourceEffect( + FaeburrowElderValue.instance, FaeburrowElderValue.instance, Duration.WhileOnBattlefield, false + ))); + + // {T}: For each color among permanents you control, add one mana of that color. + this.addAbility(new SimpleManaAbility(Zone.BATTLEFIELD, new FaeburrowElderManaEffect(), new TapSourceCost())); + } + + private FaeburrowElder(final FaeburrowElder card) { + super(card); + } + + @Override + public FaeburrowElder copy() { + return new FaeburrowElder(this); + } +} + +enum FaeburrowElderValue implements DynamicValue { + instance; + + @Override + public int calculate(Game game, Ability sourceAbility, Effect effect) { + ObjectColor color = new ObjectColor(""); + game.getBattlefield() + .getAllActivePermanents(sourceAbility.getControllerId()) + .stream() + .map(permanent -> permanent.getColor(game)) + .forEach(color::addColor); + return color.getColorCount(); + } + + @Override + public FaeburrowElderValue copy() { + return instance; + } + + @Override + public String toString() { + return "1"; + } + + @Override + public String getMessage() { + return "for each color among permanents you control"; + } +} + +class FaeburrowElderManaEffect extends ManaEffect { + + FaeburrowElderManaEffect() { + super(); + staticText = "For each color among permanents you control, add one mana of that color"; + } + + private FaeburrowElderManaEffect(final FaeburrowElderManaEffect effect) { + super(effect); + } + + @Override + public FaeburrowElderManaEffect copy() { + return new FaeburrowElderManaEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller == null) { + return false; + } + Mana mana = getMana(game, source); + checkToFirePossibleEvents(mana, game, source); + controller.getManaPool().addMana(mana, game, source); + return true; + } + + @Override + public Mana produceMana(boolean netMana, Game game, Ability source) { + Mana mana = new Mana(); + for (Permanent permanent : game.getBattlefield().getAllActivePermanents(source.getControllerId())) { + if (mana.getBlack() == 0 && permanent.getColor(game).isBlack()) { + mana.increaseBlack(); + } + if (mana.getBlue() == 0 && permanent.getColor(game).isBlue()) { + mana.increaseBlue(); + } + if (mana.getRed() == 0 && permanent.getColor(game).isRed()) { + mana.increaseRed(); + } + if (mana.getGreen() == 0 && permanent.getColor(game).isGreen()) { + mana.increaseGreen(); + } + if (mana.getWhite() == 0 && permanent.getColor(game).isWhite()) { + mana.increaseWhite(); + } + } + return mana; + } +} diff --git a/Mage.Sets/src/mage/cards/f/FaerieGuidemother.java b/Mage.Sets/src/mage/cards/f/FaerieGuidemother.java new file mode 100644 index 0000000000..03d51364ce --- /dev/null +++ b/Mage.Sets/src/mage/cards/f/FaerieGuidemother.java @@ -0,0 +1,50 @@ +package mage.cards.f; + +import mage.MageInt; +import mage.abilities.effects.common.continuous.BoostTargetEffect; +import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.AdventureCard; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class FaerieGuidemother extends AdventureCard { + + public FaerieGuidemother(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, new CardType[]{CardType.SORCERY}, "{W}", "Gift of the Fae", "{1}{W}"); + + this.subtype.add(SubType.FAERIE); + this.power = new MageInt(1); + this.toughness = new MageInt(1); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // Gift of the Fae + // Target creature gets +2/+1 and gains flying until end of turn. + this.getAdventureSpellAbility().addEffect(new BoostTargetEffect( + 2, 1, Duration.EndOfTurn + ).setText("Target creature gets +2/+1")); + this.getAdventureSpellAbility().addEffect(new GainAbilityTargetEffect( + FlyingAbility.getInstance(), Duration.EndOfTurn + ).setText("and gains flying until end of turn")); + this.getAdventureSpellAbility().addTarget(new TargetCreaturePermanent()); + } + + private FaerieGuidemother(final FaerieGuidemother card) { + super(card); + } + + @Override + public FaerieGuidemother copy() { + return new FaerieGuidemother(this); + } +} diff --git a/Mage.Sets/src/mage/cards/f/FaerieNoble.java b/Mage.Sets/src/mage/cards/f/FaerieNoble.java index 6962d48718..e9d6f52b52 100644 --- a/Mage.Sets/src/mage/cards/f/FaerieNoble.java +++ b/Mage.Sets/src/mage/cards/f/FaerieNoble.java @@ -1,7 +1,5 @@ - package mage.cards.f; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; @@ -19,12 +17,13 @@ import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.SubtypePredicate; +import java.util.UUID; + /** - * * @author ilcartographer */ public final class FaerieNoble extends CardImpl { - + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("Faerie creatures"); static { @@ -32,8 +31,8 @@ public final class FaerieNoble extends CardImpl { } public FaerieNoble(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{G}"); - this.subtype.add(SubType.FAERIE); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{G}"); + this.subtype.add(SubType.FAERIE, SubType.NOBLE); this.power = new MageInt(1); this.toughness = new MageInt(2); diff --git a/Mage.Sets/src/mage/cards/f/FaerieVandal.java b/Mage.Sets/src/mage/cards/f/FaerieVandal.java new file mode 100644 index 0000000000..dff975f655 --- /dev/null +++ b/Mage.Sets/src/mage/cards/f/FaerieVandal.java @@ -0,0 +1,49 @@ +package mage.cards.f; + +import mage.MageInt; +import mage.abilities.common.DrawSecondCardTriggeredAbility; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.abilities.keyword.FlashAbility; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.counters.CounterType; + +import java.util.UUID; + +/** + * @author jmharmon + */ +public final class FaerieVandal extends CardImpl { + + public FaerieVandal(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{U}"); + this.subtype.add(SubType.FAERIE); + this.subtype.add(SubType.ROGUE); + + this.power = new MageInt(1); + this.toughness = new MageInt(2); + + // Flash + this.addAbility(FlashAbility.getInstance()); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // Whenever you draw your second card each turn, put a +1/+1 counter on Faerie Vandal. + this.addAbility(new DrawSecondCardTriggeredAbility( + new AddCountersSourceEffect(CounterType.P1P1.createInstance()), false + )); + } + + private FaerieVandal(final FaerieVandal card) { + super(card); + } + + @Override + public FaerieVandal copy() { + return new FaerieVandal(this); + } +} diff --git a/Mage.Sets/src/mage/cards/f/FalkenrathAristocrat.java b/Mage.Sets/src/mage/cards/f/FalkenrathAristocrat.java index 7dbd0922e2..70ee0b725c 100644 --- a/Mage.Sets/src/mage/cards/f/FalkenrathAristocrat.java +++ b/Mage.Sets/src/mage/cards/f/FalkenrathAristocrat.java @@ -1,7 +1,5 @@ - package mage.cards.f; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; @@ -16,20 +14,22 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.*; import mage.counters.CounterType; -import static mage.filter.StaticFilters.FILTER_CONTROLLED_CREATURE_SHORT_TEXT; import mage.game.Game; import mage.game.permanent.Permanent; import mage.target.common.TargetControlledCreaturePermanent; +import java.util.UUID; + +import static mage.filter.StaticFilters.FILTER_CONTROLLED_CREATURE_SHORT_TEXT; + /** - * * @author North */ public final class FalkenrathAristocrat extends CardImpl { public FalkenrathAristocrat(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}{R}"); - this.subtype.add(SubType.VAMPIRE); + this.subtype.add(SubType.VAMPIRE, SubType.NOBLE); this.power = new MageInt(4); this.toughness = new MageInt(1); diff --git a/Mage.Sets/src/mage/cards/f/FalkenrathNoble.java b/Mage.Sets/src/mage/cards/f/FalkenrathNoble.java index 3491dc5262..35cc7bbde1 100644 --- a/Mage.Sets/src/mage/cards/f/FalkenrathNoble.java +++ b/Mage.Sets/src/mage/cards/f/FalkenrathNoble.java @@ -1,7 +1,5 @@ - package mage.cards.f; -import java.util.UUID; import mage.MageInt; import mage.abilities.TriggeredAbilityImpl; import mage.abilities.effects.common.GainLifeEffect; @@ -19,15 +17,16 @@ import mage.game.events.ZoneChangeEvent; import mage.game.permanent.Permanent; import mage.target.TargetPlayer; +import java.util.UUID; + /** - * * @author North */ public final class FalkenrathNoble extends CardImpl { public FalkenrathNoble(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{B}"); - this.subtype.add(SubType.VAMPIRE); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{B}"); + this.subtype.add(SubType.VAMPIRE, SubType.NOBLE); this.power = new MageInt(2); this.toughness = new MageInt(2); @@ -72,19 +71,17 @@ class FalkenrathNobleTriggeredAbility extends TriggeredAbilityImpl { @Override public boolean checkTrigger(GameEvent event, Game game) { ZoneChangeEvent zEvent = (ZoneChangeEvent) event; - if (zEvent.isDiesEvent()) { - Permanent permanent = (Permanent) game.getLastKnownInformation(event.getTargetId(), Zone.BATTLEFIELD); - if (permanent != null) { - if (permanent.getId().equals(this.getSourceId())) { - return true; - } else { - if (permanent.isCreature()) { - return true; - } - } - } + if (!zEvent.isDiesEvent()) { + return false; } - return false; + Permanent permanent = (Permanent) game.getLastKnownInformation(event.getTargetId(), Zone.BATTLEFIELD); + if (permanent == null) { + return false; + } + if (permanent.getId().equals(this.getSourceId())) { + return true; + } + return permanent.isCreature(); } @Override diff --git a/Mage.Sets/src/mage/cards/f/FeastingTrollKing.java b/Mage.Sets/src/mage/cards/f/FeastingTrollKing.java new file mode 100644 index 0000000000..8a8955c7da --- /dev/null +++ b/Mage.Sets/src/mage/cards/f/FeastingTrollKing.java @@ -0,0 +1,71 @@ +package mage.cards.f; + +import mage.MageInt; +import mage.abilities.common.ActivateIfConditionActivatedAbility; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.condition.common.CastFromHandSourceCondition; +import mage.abilities.condition.common.MyTurnCondition; +import mage.abilities.costs.common.SacrificeTargetCost; +import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.ReturnSourceFromGraveyardToBattlefieldEffect; +import mage.abilities.keyword.TrampleAbility; +import mage.abilities.keyword.VigilanceAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.Zone; +import mage.filter.common.FilterControlledPermanent; +import mage.game.permanent.token.FoodToken; +import mage.target.common.TargetControlledPermanent; +import mage.watchers.common.CastFromHandWatcher; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class FeastingTrollKing extends CardImpl { + + private static final FilterControlledPermanent filter = new FilterControlledPermanent(SubType.FOOD, "Foods"); + + public FeastingTrollKing(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{G}{G}{G}{G}"); + + this.subtype.add(SubType.TROLL); + this.subtype.add(SubType.NOBLE); + this.power = new MageInt(7); + this.toughness = new MageInt(6); + + // Vigilance + this.addAbility(VigilanceAbility.getInstance()); + + // Trample + this.addAbility(TrampleAbility.getInstance()); + + // When Feasting Troll King enters the battlefield, if you cast it from your hand, create three Food tokens. + this.addAbility(new ConditionalInterveningIfTriggeredAbility( + new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new FoodToken(), 3)), + CastFromHandSourceCondition.instance, "When {this} enters the battlefield, " + + "if you cast it from your hand, create three Food tokens." + ), new CastFromHandWatcher()); + + // Sacrifice three Foods: Return Feasting Troll King from your graveyard to the battlefield. Activate this ability only during your turn. + this.addAbility(new ActivateIfConditionActivatedAbility( + Zone.GRAVEYARD, + new ReturnSourceFromGraveyardToBattlefieldEffect(), + new SacrificeTargetCost(new TargetControlledPermanent(3, filter)), + MyTurnCondition.instance + )); + } + + private FeastingTrollKing(final FeastingTrollKing card) { + super(card); + } + + @Override + public FeastingTrollKing copy() { + return new FeastingTrollKing(this); + } +} diff --git a/Mage.Sets/src/mage/cards/f/FellThePheasant.java b/Mage.Sets/src/mage/cards/f/FellThePheasant.java new file mode 100644 index 0000000000..14c4c01826 --- /dev/null +++ b/Mage.Sets/src/mage/cards/f/FellThePheasant.java @@ -0,0 +1,46 @@ +package mage.cards.f; + +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.mageobject.AbilityPredicate; +import mage.game.permanent.token.FoodToken; +import mage.target.TargetPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class FellThePheasant extends CardImpl { + + + private static final FilterPermanent filter = new FilterCreaturePermanent("creature with flying."); + + static { + filter.add(new AbilityPredicate(FlyingAbility.class)); + } + + public FellThePheasant(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{G}"); + + // Fell the Pheasant deals 5 damage to target creature with flying. Create a Food token. + this.getSpellAbility().addEffect(new DamageTargetEffect(5)); + this.getSpellAbility().addEffect(new CreateTokenEffect(new FoodToken())); + this.getSpellAbility().addTarget(new TargetPermanent(filter)); + } + + private FellThePheasant(final FellThePheasant card) { + super(card); + } + + @Override + public FellThePheasant copy() { + return new FellThePheasant(this); + } +} diff --git a/Mage.Sets/src/mage/cards/f/FerocityOfTheWilds.java b/Mage.Sets/src/mage/cards/f/FerocityOfTheWilds.java new file mode 100644 index 0000000000..43da88093b --- /dev/null +++ b/Mage.Sets/src/mage/cards/f/FerocityOfTheWilds.java @@ -0,0 +1,57 @@ +package mage.cards.f; + +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.continuous.BoostControlledEffect; +import mage.abilities.effects.common.continuous.GainAbilityAllEffect; +import mage.abilities.keyword.TrampleAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.constants.TargetController; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.SubtypePredicate; +import mage.filter.predicate.permanent.AttackingPredicate; +import mage.filter.predicate.permanent.ControllerPredicate; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class FerocityOfTheWilds extends CardImpl { + + private static final FilterCreaturePermanent filter + = new FilterCreaturePermanent("attacking non-Human creatures"); + + static { + filter.add(AttackingPredicate.instance); + filter.add(new ControllerPredicate(TargetController.YOU)); + filter.add(Predicates.not(new SubtypePredicate(SubType.HUMAN))); + } + + public FerocityOfTheWilds(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{R}"); + + // Attacking non-Human creatures you control get +1/+0 and have trample. + Ability ability = new SimpleStaticAbility( + new BoostControlledEffect(1, 0, Duration.WhileOnBattlefield, filter) + ); + ability.addEffect(new GainAbilityAllEffect( + TrampleAbility.getInstance(), Duration.WhileOnBattlefield, filter, "and have trample" + )); + this.addAbility(ability); + } + + private FerocityOfTheWilds(final FerocityOfTheWilds card) { + super(card); + } + + @Override + public FerocityOfTheWilds copy() { + return new FerocityOfTheWilds(this); + } +} diff --git a/Mage.Sets/src/mage/cards/f/FerventChampion.java b/Mage.Sets/src/mage/cards/f/FerventChampion.java new file mode 100644 index 0000000000..e6122045a4 --- /dev/null +++ b/Mage.Sets/src/mage/cards/f/FerventChampion.java @@ -0,0 +1,107 @@ +package mage.cards.f; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.AttacksTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.continuous.BoostTargetEffect; +import mage.abilities.effects.common.cost.CostModificationEffectImpl; +import mage.abilities.keyword.EquipAbility; +import mage.abilities.keyword.FirstStrikeAbility; +import mage.abilities.keyword.HasteAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.filter.FilterPermanent; +import mage.filter.predicate.permanent.AnotherPredicate; +import mage.filter.predicate.permanent.AttackingPredicate; +import mage.game.Game; +import mage.target.Target; +import mage.target.TargetPermanent; +import mage.util.CardUtil; + +import java.util.Collection; +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class FerventChampion extends CardImpl { + + private static final FilterPermanent filter + = new FilterPermanent(SubType.KNIGHT, "another target attacking Knight"); + + static { + filter.add(AttackingPredicate.instance); + filter.add(AnotherPredicate.instance); + } + + public FerventChampion(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{R}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.KNIGHT); + this.power = new MageInt(1); + this.toughness = new MageInt(1); + + // First strike + this.addAbility(FirstStrikeAbility.getInstance()); + + // Haste + this.addAbility(HasteAbility.getInstance()); + + // Whenever Fervent Champion attacks, another target attacking Knight you control gets +1/+0 until end of turn. + Ability ability = new AttacksTriggeredAbility( + new BoostTargetEffect(1, 0, Duration.EndOfTurn), false + ); + ability.addTarget(new TargetPermanent(filter)); + this.addAbility(ability); + + // Equip abilities you activate that target Fervent Champion cost {3} less to activate. + this.addAbility(new SimpleStaticAbility(new FerventChampionEffect())); + } + + private FerventChampion(final FerventChampion card) { + super(card); + } + + @Override + public FerventChampion copy() { + return new FerventChampion(this); + } +} + +class FerventChampionEffect extends CostModificationEffectImpl { + + FerventChampionEffect() { + super(Duration.Custom, Outcome.Benefit, CostModificationType.REDUCE_COST); + staticText = "equip abilities you activate that target {this} cost {3} less to activate"; + } + + private FerventChampionEffect(final FerventChampionEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source, Ability abilityToModify) { + CardUtil.reduceCost(abilityToModify, 3); + return true; + } + + @Override + public boolean applies(Ability abilityToModify, Ability source, Game game) { + return abilityToModify instanceof EquipAbility + && abilityToModify.isControlledBy(source.getControllerId()) + && abilityToModify + .getTargets() + .stream() + .map(Target::getTargets) + .flatMap(Collection::stream) + .anyMatch(source.getSourceId()::equals); + } + + @Override + public FerventChampionEffect copy() { + return new FerventChampionEffect(this); + } +} diff --git a/Mage.Sets/src/mage/cards/f/FestiveFuneral.java b/Mage.Sets/src/mage/cards/f/FestiveFuneral.java new file mode 100644 index 0000000000..087e7d73d4 --- /dev/null +++ b/Mage.Sets/src/mage/cards/f/FestiveFuneral.java @@ -0,0 +1,40 @@ +package mage.cards.f; + +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.dynamicvalue.common.CardsInControllerGraveyardCount; +import mage.abilities.effects.common.continuous.BoostTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.filter.StaticFilters; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class FestiveFuneral extends CardImpl { + + private static final DynamicValue xValue = new CardsInControllerGraveyardCount(StaticFilters.FILTER_CARD, -1); + + public FestiveFuneral(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{4}{B}"); + + // Target creature gets -X/-X until end of turn, where X is the number of cards in your graveyard. + this.getSpellAbility().addEffect(new BoostTargetEffect( + xValue, xValue, Duration.EndOfTurn, true + ).setText("target creature gets -X/-X until end of turn, where X is the number of cards in your graveyard")); + this.getSpellAbility().addTarget(new TargetCreaturePermanent()); + } + + private FestiveFuneral(final FestiveFuneral card) { + super(card); + } + + @Override + public FestiveFuneral copy() { + return new FestiveFuneral(this); + } +} diff --git a/Mage.Sets/src/mage/cards/f/FiendishDuo.java b/Mage.Sets/src/mage/cards/f/FiendishDuo.java new file mode 100644 index 0000000000..e8ae73d92e --- /dev/null +++ b/Mage.Sets/src/mage/cards/f/FiendishDuo.java @@ -0,0 +1,88 @@ +package mage.cards.f; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.ReplacementEffectImpl; +import mage.abilities.keyword.FirstStrikeAbility; +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.game.Game; +import mage.game.events.GameEvent; +import mage.players.Player; +import mage.util.CardUtil; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class FiendishDuo extends CardImpl { + + public FiendishDuo(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{R}{R}"); + + this.subtype.add(SubType.DEVIL); + this.power = new MageInt(5); + this.toughness = new MageInt(5); + + // First strike + this.addAbility(FirstStrikeAbility.getInstance()); + + // If a source would deal damage to an opponent, it deals double that damage to that player instead. + this.addAbility(new SimpleStaticAbility(new FiendishDuoEffect())); + } + + private FiendishDuo(final FiendishDuo card) { + super(card); + } + + @Override + public FiendishDuo copy() { + return new FiendishDuo(this); + } +} + +class FiendishDuoEffect extends ReplacementEffectImpl { + + FiendishDuoEffect() { + super(Duration.WhileOnBattlefield, Outcome.Damage); + staticText = "If a source would deal damage to an opponent, " + + "it deals double that damage to that player instead"; + } + + private FiendishDuoEffect(final FiendishDuoEffect effect) { + super(effect); + } + + @Override + public FiendishDuoEffect copy() { + return new FiendishDuoEffect(this); + } + + @Override + public boolean checksEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.DAMAGE_PLAYER; + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + Player player = game.getPlayer(source.getControllerId()); + return player != null && player.hasOpponent(event.getTargetId(), game); + } + + @Override + public boolean apply(Game game, Ability source) { + return true; + } + + @Override + public boolean replaceEvent(GameEvent event, Ability source, Game game) { + event.setAmount(CardUtil.addWithOverflowCheck(event.getAmount(), event.getAmount())); + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/f/FierceWitchstalker.java b/Mage.Sets/src/mage/cards/f/FierceWitchstalker.java new file mode 100644 index 0000000000..a4defd85a5 --- /dev/null +++ b/Mage.Sets/src/mage/cards/f/FierceWitchstalker.java @@ -0,0 +1,42 @@ +package mage.cards.f; + +import mage.MageInt; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.keyword.TrampleAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.game.permanent.token.FoodToken; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class FierceWitchstalker extends CardImpl { + + public FierceWitchstalker(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{G}{G}"); + + this.subtype.add(SubType.WOLF); + this.power = new MageInt(4); + this.toughness = new MageInt(4); + + // Trample + this.addAbility(TrampleAbility.getInstance()); + + // When Fierce Witchstalker enters the battlefield, create a Food token. + this.addAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new FoodToken()))); + } + + private FierceWitchstalker(final FierceWitchstalker card) { + super(card); + } + + @Override + public FierceWitchstalker copy() { + return new FierceWitchstalker(this); + } +} diff --git a/Mage.Sets/src/mage/cards/f/FieryImpulse.java b/Mage.Sets/src/mage/cards/f/FieryImpulse.java index b8e2e52d5f..8a1738dc11 100644 --- a/Mage.Sets/src/mage/cards/f/FieryImpulse.java +++ b/Mage.Sets/src/mage/cards/f/FieryImpulse.java @@ -1,7 +1,6 @@ package mage.cards.f; -import java.util.UUID; import mage.abilities.condition.common.SpellMasteryCondition; import mage.abilities.decorator.ConditionalOneShotEffect; import mage.abilities.effects.common.DamageTargetEffect; @@ -10,20 +9,21 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author fireshoes */ public final class FieryImpulse extends CardImpl { public FieryImpulse(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{R}"); + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{R}"); // Fiery Impulse deals 2 damage to target creature. // Spell mastery — If there are two or more instant and/or sorcery cards in your graveyard, Fiery Impulse deals 3 damage to that creature instead. - this.getSpellAbility().addEffect(new ConditionalOneShotEffect(new DamageTargetEffect(3), - new DamageTargetEffect(2), SpellMasteryCondition.instance, - "{this} deals 2 damage to target creature. Spell mastery — If there are two or more instant and/or sorcery cards in your graveyard, {this} deals 3 damage to that creature instead")); + this.getSpellAbility().addEffect(new ConditionalOneShotEffect( + new DamageTargetEffect(3), new DamageTargetEffect(2), SpellMasteryCondition.instance, + "{this} deals 2 damage to target creature.
Spell mastery — If there are two or more instant and/or sorcery cards in your graveyard, {this} deals 3 damage instead")); this.getSpellAbility().addTarget(new TargetCreaturePermanent()); } diff --git a/Mage.Sets/src/mage/cards/f/FirecannonBlast.java b/Mage.Sets/src/mage/cards/f/FirecannonBlast.java index abebb600f0..5f387877be 100644 --- a/Mage.Sets/src/mage/cards/f/FirecannonBlast.java +++ b/Mage.Sets/src/mage/cards/f/FirecannonBlast.java @@ -1,7 +1,6 @@ package mage.cards.f; -import java.util.UUID; import mage.abilities.condition.InvertCondition; import mage.abilities.condition.common.RaidCondition; import mage.abilities.decorator.ConditionalOneShotEffect; @@ -12,8 +11,9 @@ import mage.constants.CardType; import mage.target.common.TargetCreaturePermanent; import mage.watchers.common.PlayerAttackedWatcher; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class FirecannonBlast extends CardImpl { @@ -22,16 +22,13 @@ public final class FirecannonBlast extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{1}{R}{R}"); // Firecannon Blast deals 3 damage to target creature. - this.getSpellAbility().addEffect(new ConditionalOneShotEffect( - new DamageTargetEffect(3), - new InvertCondition(RaidCondition.instance), - "{this} deals 3 damage to target creature")); - this.getSpellAbility().addTarget(new TargetCreaturePermanent()); // Raid - Firecannon Blast deals 6 damage to that creature instead if you attacked with a creature this turn. this.getSpellAbility().addEffect(new ConditionalOneShotEffect( - new DamageTargetEffect(6, false), - RaidCondition.instance, - "

Raid — {this} deals 6 damage to that creature instead if you attacked with a creature this turn")); + new DamageTargetEffect(3), + new DamageTargetEffect(6), + new InvertCondition(RaidCondition.instance), + "{this} deals 3 damage to target creature.
Raid — {this} deals 6 damage instead if you attacked with a creature this turn")); + this.getSpellAbility().addTarget(new TargetCreaturePermanent()); this.getSpellAbility().addWatcher(new PlayerAttackedWatcher()); } diff --git a/Mage.Sets/src/mage/cards/f/FiresOfInvention.java b/Mage.Sets/src/mage/cards/f/FiresOfInvention.java new file mode 100644 index 0000000000..b87e4c6185 --- /dev/null +++ b/Mage.Sets/src/mage/cards/f/FiresOfInvention.java @@ -0,0 +1,99 @@ +package mage.cards.f; + +import mage.MageObject; +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.ContinuousRuleModifyingEffectImpl; +import mage.abilities.effects.common.continuous.CastFromHandWithoutPayingManaCostEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.filter.FilterCard; +import mage.filter.StaticFilters; +import mage.filter.predicate.ObjectSourcePlayer; +import mage.filter.predicate.ObjectSourcePlayerPredicate; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.watchers.common.CastSpellLastTurnWatcher; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class FiresOfInvention extends CardImpl { + + private static final FilterCard filter + = new FilterCard("spells with converted mana cost less than or equal to the number of lands you control"); + + static { + filter.add(FiresOfInventionPredicate.instance); + } + + public FiresOfInvention(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{3}{R}"); + + // You can cast spells only during your turn and you can cast no more than two spells each turn. + this.addAbility(new SimpleStaticAbility(new FiresOfInventionCastEffect())); + + // You may cast spells with converted mana cost less than or equal to the number of lands you control without paying their mana costs. + this.addAbility(new SimpleStaticAbility(new CastFromHandWithoutPayingManaCostEffect(filter, false))); + } + + private FiresOfInvention(final FiresOfInvention card) { + super(card); + } + + @Override + public FiresOfInvention copy() { + return new FiresOfInvention(this); + } +} + +enum FiresOfInventionPredicate implements ObjectSourcePlayerPredicate> { + instance; + + @Override + public boolean apply(ObjectSourcePlayer input, Game game) { + return input.getObject().getConvertedManaCost() <= + game.getBattlefield().countAll(StaticFilters.FILTER_LAND, game.getControllerId(input.getSourceId()), game); + } +} + +class FiresOfInventionCastEffect extends ContinuousRuleModifyingEffectImpl { + + FiresOfInventionCastEffect() { + super(Duration.WhileOnBattlefield, Outcome.Detriment); + staticText = "you can cast spells only during your turn and you can cast no more than two spells each turn"; + } + + private FiresOfInventionCastEffect(final FiresOfInventionCastEffect effect) { + super(effect); + } + + @Override + public FiresOfInventionCastEffect copy() { + return new FiresOfInventionCastEffect(this); + } + + @Override + public boolean checksEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.CAST_SPELL; + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + if (!event.getPlayerId().equals(source.getControllerId())) { + return false; + } + CastSpellLastTurnWatcher watcher = game.getState().getWatcher(CastSpellLastTurnWatcher.class); + if (watcher == null) { + return false; + } + return watcher.getAmountOfSpellsPlayerCastOnCurrentTurn(source.getControllerId()) > 1 + || !game.getActivePlayerId().equals(source.getControllerId()); + } + +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/f/Firespout.java b/Mage.Sets/src/mage/cards/f/Firespout.java index 42d3b97e50..5a2f51e589 100644 --- a/Mage.Sets/src/mage/cards/f/Firespout.java +++ b/Mage.Sets/src/mage/cards/f/Firespout.java @@ -1,11 +1,9 @@ package mage.cards.f; -import java.util.UUID; import mage.abilities.condition.common.ManaWasSpentCondition; import mage.abilities.decorator.ConditionalOneShotEffect; import mage.abilities.effects.common.DamageAllEffect; -import mage.abilities.effects.common.InfoEffect; import mage.abilities.keyword.FlyingAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -16,35 +14,33 @@ import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.AbilityPredicate; import mage.watchers.common.ManaSpentToCastWatcher; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class Firespout extends CardImpl { private static final FilterCreaturePermanent filter1 = new FilterCreaturePermanent("creature without flying"); private static final FilterCreaturePermanent filter2 = new FilterCreaturePermanent("creature with flying"); + static { filter1.add(Predicates.not(new AbilityPredicate(FlyingAbility.class))); filter2.add(new AbilityPredicate(FlyingAbility.class)); } public Firespout(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{2}{R/G}"); + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{R/G}"); // Firespout deals 3 damage to each creature without flying if {R} was spent to cast Firespout and 3 damage to each creature with flying if {G} was spent to cast it. this.getSpellAbility().addEffect(new ConditionalOneShotEffect( new DamageAllEffect(3, filter1), - new ManaWasSpentCondition(ColoredManaSymbol.R), "{this} deals 3 damage to each creature without flying if {R} was spent to cast {this}")); + new ManaWasSpentCondition(ColoredManaSymbol.R), "{this} deals 3 damage to each creature without flying if {R} was spent to cast this spell")); this.getSpellAbility().addEffect(new ConditionalOneShotEffect( new DamageAllEffect(3, filter2), - new ManaWasSpentCondition(ColoredManaSymbol.G), " And 3 damage to each creature with flying if {G} was spent to cast it")); - this.getSpellAbility().addEffect(new InfoEffect("(Do both if {R}{G} was spent.)")); + new ManaWasSpentCondition(ColoredManaSymbol.G), "and 3 damage to each creature with flying if {G} was spent to cast it. (Do both if {R}{G} was spent.)")); this.getSpellAbility().addWatcher(new ManaSpentToCastWatcher()); - - - } public Firespout(final Firespout card) { diff --git a/Mage.Sets/src/mage/cards/f/FlashConscription.java b/Mage.Sets/src/mage/cards/f/FlashConscription.java index 4e2ac4a41a..ec60a4b850 100644 --- a/Mage.Sets/src/mage/cards/f/FlashConscription.java +++ b/Mage.Sets/src/mage/cards/f/FlashConscription.java @@ -38,7 +38,7 @@ public final class FlashConscription extends CardImpl { this.getSpellAbility().addEffect(new ConditionalContinuousEffect( new GainAbilityTargetEffect(new FlashConscriptionTriggeredAbility(), Duration.EndOfTurn), new ManaWasSpentCondition(ColoredManaSymbol.W), - "If {W} was spent to cast {this}, the creature gains " + "If {W} was spent to cast this spell, the creature gains " + "\"Whenever this creature deals combat damage, you gain that much life\" until end of turn" )); diff --git a/Mage.Sets/src/mage/cards/f/Flutterfox.java b/Mage.Sets/src/mage/cards/f/Flutterfox.java new file mode 100644 index 0000000000..aaf6b55a8f --- /dev/null +++ b/Mage.Sets/src/mage/cards/f/Flutterfox.java @@ -0,0 +1,57 @@ +package mage.cards.f; + +import mage.MageInt; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.Condition; +import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; +import mage.abilities.decorator.ConditionalContinuousEffect; +import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.constants.TargetController; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterArtifactOrEnchantmentPermanent; +import mage.filter.predicate.permanent.ControllerPredicate; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class Flutterfox extends CardImpl { + + private static final FilterPermanent filter = new FilterArtifactOrEnchantmentPermanent(); + + static { + filter.add(new ControllerPredicate(TargetController.YOU)); + } + + private static final Condition condition = new PermanentsOnTheBattlefieldCondition(filter); + + public Flutterfox(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W}"); + + this.subtype.add(SubType.FOX); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // As long as you control an artifact or enchantment, Flutterfox has flying. + this.addAbility(new SimpleStaticAbility(new ConditionalContinuousEffect( + new GainAbilitySourceEffect(FlyingAbility.getInstance(), Duration.WhileOnBattlefield), + condition, "As long as you control an artifact or enchantment, {this} has flying." + ))); + } + + private Flutterfox(final Flutterfox card) { + super(card); + } + + @Override + public Flutterfox copy() { + return new Flutterfox(this); + } +} diff --git a/Mage.Sets/src/mage/cards/f/FolioOfFancies.java b/Mage.Sets/src/mage/cards/f/FolioOfFancies.java new file mode 100644 index 0000000000..191fe2c06d --- /dev/null +++ b/Mage.Sets/src/mage/cards/f/FolioOfFancies.java @@ -0,0 +1,95 @@ +package mage.cards.f; + +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.dynamicvalue.common.ManacostVariableValue; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.DrawCardAllEffect; +import mage.abilities.effects.common.continuous.MaximumHandSizeControllerEffect; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.game.Game; +import mage.players.Player; + +import java.util.Collection; +import java.util.Objects; +import java.util.Set; +import java.util.UUID; +import java.util.stream.Collectors; + +/** + * @author TheElk801 + */ +public final class FolioOfFancies extends CardImpl { + + public FolioOfFancies(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{1}{U}"); + + // Players have no maximum hand size. + this.addAbility(new SimpleStaticAbility(new MaximumHandSizeControllerEffect( + Integer.MAX_VALUE, Duration.WhileOnBattlefield, + MaximumHandSizeControllerEffect.HandSizeModification.SET, TargetController.ANY + ))); + + // {X}{X}, {T}: Each player draws X cards. + Ability ability = new SimpleActivatedAbility( + new DrawCardAllEffect(ManacostVariableValue.instance), new ManaCostsImpl("{X}{X}") + ); + ability.addCost(new TapSourceCost()); + this.addAbility(ability); + + // {2}{U}, {T}: Each opponent puts a number of cards equal to the number of cards in their hand from the top of their library into their graveyard. + ability = new SimpleActivatedAbility(new FolioOfFanciesEffect(), new ManaCostsImpl("{2}{U}")); + ability.addCost(new TapSourceCost()); + this.addAbility(ability); + } + + private FolioOfFancies(final FolioOfFancies card) { + super(card); + } + + @Override + public FolioOfFancies copy() { + return new FolioOfFancies(this); + } +} + +class FolioOfFanciesEffect extends OneShotEffect { + + FolioOfFanciesEffect() { + super(Outcome.Benefit); + staticText = "Each opponent puts a number of cards equal to the number of cards in their hand " + + "from the top of their library into their graveyard."; + } + + private FolioOfFanciesEffect(final FolioOfFanciesEffect effect) { + super(effect); + } + + @Override + public FolioOfFanciesEffect copy() { + return new FolioOfFanciesEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller == null) { + return false; + } + Set cards = game.getOpponents(source.getControllerId()) + .stream() + .map(game::getPlayer) + .filter(Objects::nonNull) + .filter(player -> !player.getHand().isEmpty()) + .map(player -> player.getLibrary().getTopCards(game, player.getHand().size())) + .flatMap(Collection::stream) + .collect(Collectors.toSet()); + return controller.moveCards(cards, Zone.GRAVEYARD, source, game); + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/f/ForebodingFruit.java b/Mage.Sets/src/mage/cards/f/ForebodingFruit.java new file mode 100644 index 0000000000..14cf2f4416 --- /dev/null +++ b/Mage.Sets/src/mage/cards/f/ForebodingFruit.java @@ -0,0 +1,46 @@ +package mage.cards.f; + +import mage.abilities.condition.common.AdamantCondition; +import mage.abilities.decorator.ConditionalOneShotEffect; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.DrawCardTargetEffect; +import mage.abilities.effects.common.LoseLifeTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.game.permanent.token.FoodToken; +import mage.target.TargetPlayer; +import mage.watchers.common.ManaSpentToCastWatcher; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ForebodingFruit extends CardImpl { + + public ForebodingFruit(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{B}"); + + // Target player draws two cards and loses 2 life. + this.getSpellAbility().addEffect(new DrawCardTargetEffect(2)); + this.getSpellAbility().addEffect(new LoseLifeTargetEffect(2).setText("and loses 2 life")); + this.getSpellAbility().addTarget(new TargetPlayer()); + + // Adamant — If at least three black mana was spent to cast this spell, create a Food token. + this.getSpellAbility().addEffect(new ConditionalOneShotEffect( + new CreateTokenEffect(new FoodToken()), AdamantCondition.BLACK, "
Adamant — " + + "If at least three black mana was spent to cast this spell, create a Food token." + )); + this.getSpellAbility().addWatcher(new ManaSpentToCastWatcher()); + } + + private ForebodingFruit(final ForebodingFruit card) { + super(card); + } + + @Override + public ForebodingFruit copy() { + return new ForebodingFruit(this); + } +} diff --git a/Mage.Sets/src/mage/cards/f/ForeverYoung.java b/Mage.Sets/src/mage/cards/f/ForeverYoung.java new file mode 100644 index 0000000000..abfe7a967f --- /dev/null +++ b/Mage.Sets/src/mage/cards/f/ForeverYoung.java @@ -0,0 +1,80 @@ +package mage.cards.f; + +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.cards.CardsImpl; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.players.Player; +import mage.target.Target; +import mage.target.common.TargetCardInYourGraveyard; + +import java.util.Collection; +import java.util.UUID; +import java.util.stream.Collectors; + +/** + * @author TheElk801 + */ +public final class ForeverYoung extends CardImpl { + + public ForeverYoung(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{1}{B}"); + + // Put any number of target creature cards from your graveyard on top of your library. + this.getSpellAbility().addEffect(new ForeverYoungEffect()); + this.getSpellAbility().addTarget(new TargetCardInYourGraveyard( + 0, Integer.MAX_VALUE, StaticFilters.FILTER_CARD_CREATURES_YOUR_GRAVEYARD + )); + + // Draw a card. + this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(1)); + } + + private ForeverYoung(final ForeverYoung card) { + super(card); + } + + @Override + public ForeverYoung copy() { + return new ForeverYoung(this); + } +} + +class ForeverYoungEffect extends OneShotEffect { + + ForeverYoungEffect() { + super(Outcome.Benefit); + staticText = "Put any number of target creature cards from your graveyard on top of your library."; + } + + private ForeverYoungEffect(final ForeverYoungEffect effect) { + super(effect); + } + + @Override + public ForeverYoungEffect copy() { + return new ForeverYoungEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; + } + return player.putCardsOnTopOfLibrary(new CardsImpl( + source.getTargets() + .stream() + .map(Target::getTargets) + .flatMap(Collection::stream) + .map(game::getCard) + .collect(Collectors.toSet()) + ), game, source, true); + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/f/ForkedLightning.java b/Mage.Sets/src/mage/cards/f/ForkedLightning.java new file mode 100644 index 0000000000..0d14651ab6 --- /dev/null +++ b/Mage.Sets/src/mage/cards/f/ForkedLightning.java @@ -0,0 +1,35 @@ +package mage.cards.f; + +import java.util.UUID; + +import mage.abilities.effects.common.DamageMultiEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.target.Target; +import mage.target.common.TargetCreaturePermanentAmount; + +/** + * + * @author TheElk801 + */ +public final class ForkedLightning extends CardImpl { + + public ForkedLightning(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{3}{R}"); + + // Forked Lightning deals 4 damage divided as you choose among one, two, or three target creatures. + this.getSpellAbility().addEffect(new DamageMultiEffect(4) + .setText("{this} deals 4 damage divided as you choose among one, two, or three target creatures")); + Target target=new TargetCreaturePermanentAmount(4);target.setMaxNumberOfTargets(3);this.getSpellAbility().addTarget(target); + } + + private ForkedLightning(final ForkedLightning card) { + super(card); + } + + @Override + public ForkedLightning copy() { + return new ForkedLightning(this); + } +} diff --git a/Mage.Sets/src/mage/cards/f/FortifyingProvisions.java b/Mage.Sets/src/mage/cards/f/FortifyingProvisions.java new file mode 100644 index 0000000000..61f6c41034 --- /dev/null +++ b/Mage.Sets/src/mage/cards/f/FortifyingProvisions.java @@ -0,0 +1,38 @@ +package mage.cards.f; + +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.CreateTokenEffect; +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.game.permanent.token.FoodToken; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class FortifyingProvisions extends CardImpl { + + public FortifyingProvisions(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{W}"); + + // Creatures you control get +0/+1. + this.addAbility(new SimpleStaticAbility(new BoostControlledEffect(0, 1, Duration.WhileOnBattlefield))); + + // When Fortifying Provisions enters the battlefield, create a Food token. + this.addAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new FoodToken()))); + } + + private FortifyingProvisions(final FortifyingProvisions card) { + super(card); + } + + @Override + public FortifyingProvisions copy() { + return new FortifyingProvisions(this); + } +} diff --git a/Mage.Sets/src/mage/cards/g/GadwickTheWizened.java b/Mage.Sets/src/mage/cards/g/GadwickTheWizened.java new file mode 100644 index 0000000000..cfdece046c --- /dev/null +++ b/Mage.Sets/src/mage/cards/g/GadwickTheWizened.java @@ -0,0 +1,145 @@ +package mage.cards.g; + +import mage.MageInt; +import mage.MageObjectReference; +import mage.ObjectColor; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.SpellCastControllerTriggeredAbility; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.TapTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.filter.FilterPermanent; +import mage.filter.FilterSpell; +import mage.filter.common.FilterNonlandPermanent; +import mage.filter.predicate.mageobject.ColorPredicate; +import mage.filter.predicate.permanent.ControllerPredicate; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.stack.Spell; +import mage.target.TargetPermanent; +import mage.watchers.Watcher; + +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class GadwickTheWizened extends CardImpl { + + private static final FilterSpell filter + = new FilterSpell("a blue spell"); + private static final FilterPermanent filter2 + = new FilterNonlandPermanent("nonland permanent an opponent controls"); + + static { + filter.add(new ColorPredicate(ObjectColor.BLUE)); + filter2.add(new ControllerPredicate(TargetController.OPPONENT)); + } + + public GadwickTheWizened(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{X}{U}{U}{U}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.WIZARD); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // When Gadwick, the Wizened enters the battlefield, draw X cards. + this.addAbility(new EntersBattlefieldTriggeredAbility( + new DrawCardSourceControllerEffect(GadwickTheWizenedValue.instance) + ), new GadwickTheWizenedWatcher()); + + // Whenever you cast a blue spell, tap target nonland permanent an opponent controls. + Ability ability = new SpellCastControllerTriggeredAbility(new TapTargetEffect(), filter, false); + ability.addTarget(new TargetPermanent(filter2)); + this.addAbility(ability); + } + + private GadwickTheWizened(final GadwickTheWizened card) { + super(card); + } + + @Override + public GadwickTheWizened copy() { + return new GadwickTheWizened(this); + } +} + +enum GadwickTheWizenedValue implements DynamicValue { + instance; + + @Override + public int calculate(Game game, Ability sourceAbility, Effect effect) { + GadwickTheWizenedWatcher watcher = game.getState().getWatcher(GadwickTheWizenedWatcher.class); + if (watcher == null) { + return 0; + } + return watcher.getX(new MageObjectReference(sourceAbility.getSourceId(), game)); + } + + @Override + public DynamicValue copy() { + return instance; + } + + @Override + public String toString() { + return "X"; + } + + @Override + public String getMessage() { + return ""; + } +} + +class GadwickTheWizenedWatcher extends Watcher { + + private final Map xMap = new HashMap(); + + GadwickTheWizenedWatcher() { + super(WatcherScope.GAME); + } + + private GadwickTheWizenedWatcher(final GadwickTheWizenedWatcher watcher) { + super(watcher); + this.xMap.putAll(watcher.xMap); + } + + @Override + public void watch(GameEvent event, Game game) { + if (event.getType() != GameEvent.EventType.SPELL_CAST) { + return; + } + Spell spell = game.getSpellOrLKIStack(event.getTargetId()); + if (spell == null) { + return; + } + xMap.put(new MageObjectReference( + spell.getSourceId(), spell.getZoneChangeCounter(game) + 1, game + ), spell.getSpellAbility().getManaCostsToPay().getX()); + } + + @Override + public GadwickTheWizenedWatcher copy() { + return new GadwickTheWizenedWatcher(this); + } + + @Override + public void reset() { + super.reset(); + xMap.clear(); + } + + public int getX(MageObjectReference mageObjectReference) { + return xMap.getOrDefault(mageObjectReference, 0); + } +} diff --git a/Mage.Sets/src/mage/cards/g/GaeasBalance.java b/Mage.Sets/src/mage/cards/g/GaeasBalance.java new file mode 100644 index 0000000000..178cdcee8f --- /dev/null +++ b/Mage.Sets/src/mage/cards/g/GaeasBalance.java @@ -0,0 +1,104 @@ +package mage.cards.g; + +import mage.abilities.Ability; +import mage.abilities.costs.common.SacrificeTargetCost; +import mage.abilities.effects.OneShotEffect; +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.SubType; +import mage.constants.Zone; +import mage.filter.FilterCard; +import mage.filter.StaticFilters; +import mage.filter.common.FilterLandCard; +import mage.filter.predicate.mageobject.SubtypePredicate; +import mage.game.Game; +import mage.players.Player; +import mage.target.common.TargetCardInLibrary; +import mage.target.common.TargetControlledPermanent; + +import java.util.Arrays; +import java.util.List; +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class GaeasBalance extends CardImpl { + + public GaeasBalance(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{3}{G}"); + + // As an additional cost to cast Gaea's Balance, sacrifice five lands. + this.getSpellAbility().addCost(new SacrificeTargetCost( + new TargetControlledPermanent(5, StaticFilters.FILTER_CONTROLLED_LAND_SHORT_TEXT) + )); + + // Search your library for a land card of each basic land type and put them onto the battlefield. Then shuffle your library. + this.getSpellAbility().addEffect(new GaeasBalanceEffect()); + } + + private GaeasBalance(final GaeasBalance card) { + super(card); + } + + @Override + public GaeasBalance copy() { + return new GaeasBalance(this); + } +} + +class GaeasBalanceEffect extends OneShotEffect { + + private static final FilterCard plainsFilter = new FilterLandCard("a Plains land card"); + private static final FilterCard islandFilter = new FilterLandCard("an Island land card"); + private static final FilterCard swampFilter = new FilterLandCard("a Swamp land card"); + private static final FilterCard mountainFilter = new FilterLandCard("a Mountain land card"); + private static final FilterCard forestFilter = new FilterLandCard("a Forest land card"); + + static { + plainsFilter.add(new SubtypePredicate(SubType.PLAINS)); + islandFilter.add(new SubtypePredicate(SubType.ISLAND)); + swampFilter.add(new SubtypePredicate(SubType.SWAMP)); + mountainFilter.add(new SubtypePredicate(SubType.MOUNTAIN)); + forestFilter.add(new SubtypePredicate(SubType.FOREST)); + } + + private static final List filterList = Arrays.asList( + plainsFilter, islandFilter, swampFilter, mountainFilter, forestFilter + ); + + GaeasBalanceEffect() { + super(Outcome.Benefit); + staticText = "Search your library for a land card of each basic land type " + + "and put them onto the battlefield. Then shuffle your library."; + } + + private GaeasBalanceEffect(final GaeasBalanceEffect effect) { + super(effect); + } + + @Override + public GaeasBalanceEffect copy() { + return new GaeasBalanceEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; + } + Cards cards = new CardsImpl(); + filterList.stream().map(TargetCardInLibrary::new).forEachOrdered(target -> { + player.searchLibrary(target, source, game, target.getFilter().getMessage().contains("Forest")); + cards.add(target.getFirstTarget()); + }); + player.moveCards(cards, Zone.BATTLEFIELD, source, game); + player.shuffleLibrary(source, game); + return true; + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/g/GalvanicBlast.java b/Mage.Sets/src/mage/cards/g/GalvanicBlast.java index 6c696f13df..5c49d14547 100644 --- a/Mage.Sets/src/mage/cards/g/GalvanicBlast.java +++ b/Mage.Sets/src/mage/cards/g/GalvanicBlast.java @@ -1,7 +1,5 @@ - package mage.cards.g; -import java.util.UUID; import mage.abilities.condition.common.MetalcraftCondition; import mage.abilities.decorator.ConditionalOneShotEffect; import mage.abilities.effects.common.DamageTargetEffect; @@ -10,13 +8,15 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.target.common.TargetAnyTarget; +import java.util.UUID; + /** - * * @author North */ public final class GalvanicBlast extends CardImpl { - private static final String effectText = "{this} deals 2 damage to anytarget.
Metalcraft — {this} deals 4 damage to that permanent or player instead if you control three or more artifacts"; + private static final String effectText = "{this} deals 2 damage to any target." + + "
Metalcraft — {this} deals 4 damage instead if you control three or more artifacts"; public GalvanicBlast(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{R}"); @@ -24,7 +24,10 @@ public final class GalvanicBlast extends CardImpl { // Galvanic Blast deals 2 damage to any target. // Metalcraft — Galvanic Blast deals 4 damage to that creature or player instead if you control three or more artifacts. - this.getSpellAbility().addEffect(new ConditionalOneShotEffect(new DamageTargetEffect(4), new DamageTargetEffect(2), MetalcraftCondition.instance, effectText)); + this.getSpellAbility().addEffect(new ConditionalOneShotEffect( + new DamageTargetEffect(4), new DamageTargetEffect(2), + MetalcraftCondition.instance, effectText + )); this.getSpellAbility().addTarget(new TargetAnyTarget()); } diff --git a/Mage.Sets/src/mage/cards/g/GarenbrigCarver.java b/Mage.Sets/src/mage/cards/g/GarenbrigCarver.java new file mode 100644 index 0000000000..311deb9a14 --- /dev/null +++ b/Mage.Sets/src/mage/cards/g/GarenbrigCarver.java @@ -0,0 +1,41 @@ +package mage.cards.g; + +import mage.MageInt; +import mage.abilities.effects.common.continuous.BoostTargetEffect; +import mage.cards.AdventureCard; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class GarenbrigCarver extends AdventureCard { + + public GarenbrigCarver(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, new CardType[]{CardType.INSTANT}, "{3}{G}", "Shield's Might", "{1}{G}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.WARRIOR); + this.power = new MageInt(3); + this.toughness = new MageInt(2); + + // Shield's Might + // Target creature gets +2/+2 until end of turn. + this.getAdventureSpellAbility().addEffect(new BoostTargetEffect(2, 2, Duration.EndOfTurn)); + this.getAdventureSpellAbility().addTarget(new TargetCreaturePermanent()); + } + + private GarenbrigCarver(final GarenbrigCarver card) { + super(card); + } + + @Override + public GarenbrigCarver copy() { + return new GarenbrigCarver(this); + } +} diff --git a/Mage.Sets/src/mage/cards/g/GarenbrigPaladin.java b/Mage.Sets/src/mage/cards/g/GarenbrigPaladin.java new file mode 100644 index 0000000000..59db660707 --- /dev/null +++ b/Mage.Sets/src/mage/cards/g/GarenbrigPaladin.java @@ -0,0 +1,63 @@ +package mage.cards.g; + +import mage.MageInt; +import mage.abilities.common.EntersBattlefieldAbility; +import mage.abilities.common.SimpleEvasionAbility; +import mage.abilities.condition.common.AdamantCondition; +import mage.abilities.effects.common.combat.CantBeBlockedByCreaturesSourceEffect; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.ComparisonType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.counters.CounterType; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.mageobject.PowerPredicate; +import mage.watchers.common.ManaSpentToCastWatcher; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class GarenbrigPaladin extends CardImpl { + + private static final FilterCreaturePermanent filter + = new FilterCreaturePermanent("creatures with power 2 or less"); + + static { + filter.add(new PowerPredicate(ComparisonType.FEWER_THAN, 3)); + } + + public GarenbrigPaladin(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{G}"); + + this.subtype.add(SubType.GIANT); + this.subtype.add(SubType.KNIGHT); + this.power = new MageInt(4); + this.toughness = new MageInt(4); + + // Adamant — If at least three green mana was spent to cast this spell, Garenbrig Paladin enters the battlefield with a +1/+1 counter on it. + this.addAbility(new EntersBattlefieldAbility(new AddCountersSourceEffect( + CounterType.P1P1.createInstance()), AdamantCondition.GREEN, + "
Adamant — If at least three green mana was spent to cast this spell, " + + "{this} enters the battlefield with a +1/+1 counter on it.", "" + ), new ManaSpentToCastWatcher()); + + // Garenbrig Paladin can't be blocked by creatures with power 2 or less. + this.addAbility(new SimpleEvasionAbility( + new CantBeBlockedByCreaturesSourceEffect(filter, Duration.WhileOnBattlefield) + )); + } + + private GarenbrigPaladin(final GarenbrigPaladin card) { + super(card); + } + + @Override + public GarenbrigPaladin copy() { + return new GarenbrigPaladin(this); + } +} diff --git a/Mage.Sets/src/mage/cards/g/GarenbrigSquire.java b/Mage.Sets/src/mage/cards/g/GarenbrigSquire.java new file mode 100644 index 0000000000..29c9d887f3 --- /dev/null +++ b/Mage.Sets/src/mage/cards/g/GarenbrigSquire.java @@ -0,0 +1,51 @@ +package mage.cards.g; + +import mage.MageInt; +import mage.abilities.common.SpellCastControllerTriggeredAbility; +import mage.abilities.effects.common.continuous.BoostSourceEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.filter.FilterSpell; +import mage.filter.common.FilterCreatureSpell; +import mage.filter.predicate.mageobject.AdventurePredicate; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class GarenbrigSquire extends CardImpl { + + private static final FilterSpell filter + = new FilterCreatureSpell("a creature spell that has an Adventure"); + + static { + filter.add(AdventurePredicate.instance); + } + + public GarenbrigSquire(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{G}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.SOLDIER); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // Whenever you cast a creature spell that has an Adventure, Garenbrig Squire gets +1/+1 until end of turn. + this.addAbility(new SpellCastControllerTriggeredAbility( + new BoostSourceEffect(1, 1, Duration.EndOfTurn), filter, false + )); + } + + private GarenbrigSquire(final GarenbrigSquire card) { + super(card); + } + + @Override + public GarenbrigSquire copy() { + return new GarenbrigSquire(this); + } +} diff --git a/Mage.Sets/src/mage/cards/g/GarrisonGriffin.java b/Mage.Sets/src/mage/cards/g/GarrisonGriffin.java new file mode 100644 index 0000000000..5a1849faf3 --- /dev/null +++ b/Mage.Sets/src/mage/cards/g/GarrisonGriffin.java @@ -0,0 +1,52 @@ +package mage.cards.g; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.AttacksTriggeredAbility; +import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledPermanent; +import mage.target.TargetPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class GarrisonGriffin extends CardImpl { + + private static final FilterPermanent filter = new FilterControlledPermanent(SubType.KNIGHT); + + public GarrisonGriffin(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{W}"); + + this.subtype.add(SubType.GRIFFIN); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // Whenever Garrison Griffin attacks, target Knight you control gains flying until end of turn. + Ability ability = new AttacksTriggeredAbility(new GainAbilityTargetEffect( + FlyingAbility.getInstance(), Duration.EndOfTurn + ), false); + ability.addTarget(new TargetPermanent(filter)); + this.addAbility(ability); + } + + private GarrisonGriffin(final GarrisonGriffin card) { + super(card); + } + + @Override + public GarrisonGriffin copy() { + return new GarrisonGriffin(this); + } +} diff --git a/Mage.Sets/src/mage/cards/g/GarzaZolPlagueQueen.java b/Mage.Sets/src/mage/cards/g/GarzaZolPlagueQueen.java index 250468050c..7e6971f640 100644 --- a/Mage.Sets/src/mage/cards/g/GarzaZolPlagueQueen.java +++ b/Mage.Sets/src/mage/cards/g/GarzaZolPlagueQueen.java @@ -1,7 +1,5 @@ - package mage.cards.g; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; import mage.abilities.common.DealtDamageAndDiedTriggeredAbility; @@ -16,25 +14,26 @@ import mage.constants.SubType; import mage.constants.SuperType; import mage.counters.CounterType; +import java.util.UUID; + /** - * * @author fireshoes */ public final class GarzaZolPlagueQueen extends CardImpl { public GarzaZolPlagueQueen(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{4}{U}{B}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{U}{B}{R}"); addSuperType(SuperType.LEGENDARY); - this.subtype.add(SubType.VAMPIRE); + this.subtype.add(SubType.VAMPIRE, SubType.NOBLE); this.power = new MageInt(5); this.toughness = new MageInt(5); // Flying this.addAbility(FlyingAbility.getInstance()); - + // Haste this.addAbility(HasteAbility.getInstance()); - + // Whenever a creature dealt damage by Garza Zol, Plague Queen this turn dies, put a +1/+1 counter on Garza Zol. this.addAbility(new DealtDamageAndDiedTriggeredAbility(new AddCountersSourceEffect(CounterType.P1P1.createInstance()))); diff --git a/Mage.Sets/src/mage/cards/g/GiantKiller.java b/Mage.Sets/src/mage/cards/g/GiantKiller.java new file mode 100644 index 0000000000..27ea004156 --- /dev/null +++ b/Mage.Sets/src/mage/cards/g/GiantKiller.java @@ -0,0 +1,62 @@ +package mage.cards.g; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.DestroyTargetEffect; +import mage.abilities.effects.common.TapTargetEffect; +import mage.cards.AdventureCard; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.ComparisonType; +import mage.constants.SubType; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.mageobject.PowerPredicate; +import mage.target.TargetPermanent; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class GiantKiller extends AdventureCard { + + private static final FilterPermanent filter = new FilterCreaturePermanent("creature with power 4 or greater"); + + static { + filter.add(new PowerPredicate(ComparisonType.MORE_THAN, 3)); + } + + public GiantKiller(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, new CardType[]{CardType.INSTANT}, "{W}", "Chop Down", "{2}{W}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.PEASANT); + this.power = new MageInt(1); + this.toughness = new MageInt(2); + + // {1}{W}, {T}: Tap target creature. + Ability ability = new SimpleActivatedAbility(new TapTargetEffect(), new ManaCostsImpl("{1}{W}")); + ability.addCost(new TapSourceCost()); + ability.addTarget(new TargetCreaturePermanent()); + this.addAbility(ability); + + // Chop Down + // Destroy target creature with power 4 or greater. + this.getAdventureSpellAbility().addEffect(new DestroyTargetEffect()); + this.getAdventureSpellAbility().addTarget(new TargetPermanent(filter)); + } + + private GiantKiller(final GiantKiller card) { + super(card); + } + + @Override + public GiantKiller copy() { + return new GiantKiller(this); + } +} diff --git a/Mage.Sets/src/mage/cards/g/GiantOpportunity.java b/Mage.Sets/src/mage/cards/g/GiantOpportunity.java new file mode 100644 index 0000000000..0baf6ebb8b --- /dev/null +++ b/Mage.Sets/src/mage/cards/g/GiantOpportunity.java @@ -0,0 +1,44 @@ +package mage.cards.g; + +import mage.abilities.costs.common.SacrificeTargetCost; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.DoIfCostPaid; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.filter.common.FilterControlledPermanent; +import mage.game.permanent.token.FoodToken; +import mage.game.permanent.token.GiantOpportunityToken; +import mage.target.common.TargetControlledPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class GiantOpportunity extends CardImpl { + + private static final FilterControlledPermanent filter = new FilterControlledPermanent(SubType.FOOD, "Foods"); + + public GiantOpportunity(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{G}"); + + // You may sacrifice two Foods. If you do, create a 7/7 green Giant creature token. Otherwise, create three Food tokens. + this.getSpellAbility().addEffect(new DoIfCostPaid( + new CreateTokenEffect(new GiantOpportunityToken()), + new CreateTokenEffect(new FoodToken(), 3), + new SacrificeTargetCost(new TargetControlledPermanent(2, filter)) + ).setText("You may sacrifice two Foods. If you do, create a 7/7 green Giant creature token. " + + "Otherwise, create three Food tokens.")); + } + + private GiantOpportunity(final GiantOpportunity card) { + super(card); + } + + @Override + public GiantOpportunity copy() { + return new GiantOpportunity(this); + } +} diff --git a/Mage.Sets/src/mage/cards/g/GiantsSkewer.java b/Mage.Sets/src/mage/cards/g/GiantsSkewer.java new file mode 100644 index 0000000000..1baf34e5fa --- /dev/null +++ b/Mage.Sets/src/mage/cards/g/GiantsSkewer.java @@ -0,0 +1,84 @@ +package mage.cards.g; + +import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.continuous.BoostEquippedEffect; +import mage.abilities.keyword.EquipAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.Zone; +import mage.game.Game; +import mage.game.events.DamagedCreatureEvent; +import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; +import mage.game.permanent.token.FoodToken; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class GiantsSkewer extends CardImpl { + + public GiantsSkewer(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{1}{B}"); + + this.subtype.add(SubType.EQUIPMENT); + + // Equipped creature gets +2/+1. + this.addAbility(new SimpleStaticAbility(new BoostEquippedEffect(2, 1))); + + // Whenever equipped creature deals combat damage to a creature, create a Food token. + this.addAbility(new GiantsSkewerTriggeredAbility()); + + // Equip {3} + this.addAbility(new EquipAbility(3)); + } + + private GiantsSkewer(final GiantsSkewer card) { + super(card); + } + + @Override + public GiantsSkewer copy() { + return new GiantsSkewer(this); + } +} + +class GiantsSkewerTriggeredAbility extends TriggeredAbilityImpl { + + GiantsSkewerTriggeredAbility() { + super(Zone.BATTLEFIELD, new CreateTokenEffect(new FoodToken())); + } + + private GiantsSkewerTriggeredAbility(final GiantsSkewerTriggeredAbility ability) { + super(ability); + } + + @Override + public GiantsSkewerTriggeredAbility copy() { + return new GiantsSkewerTriggeredAbility(this); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.DAMAGED_CREATURE; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + if (!((DamagedCreatureEvent) event).isCombatDamage()) { + return false; + } + Permanent permanent = game.getPermanent(event.getSourceId()); + return permanent != null && permanent.getAttachments().contains(this.getSourceId()); + } + + @Override + public String getRule() { + return "Whenever equipped creature deals combat damage to a creature, create a Food token."; + } +} diff --git a/Mage.Sets/src/mage/cards/g/GingerbreadCabin.java b/Mage.Sets/src/mage/cards/g/GingerbreadCabin.java new file mode 100644 index 0000000000..a6d6295fbb --- /dev/null +++ b/Mage.Sets/src/mage/cards/g/GingerbreadCabin.java @@ -0,0 +1,64 @@ +package mage.cards.g; + +import mage.abilities.common.EntersBattlefieldAbility; +import mage.abilities.common.EntersBattlefieldUntappedTriggeredAbility; +import mage.abilities.condition.Condition; +import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; +import mage.abilities.decorator.ConditionalOneShotEffect; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.TapSourceEffect; +import mage.abilities.mana.GreenManaAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.ComparisonType; +import mage.constants.SubType; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledPermanent; +import mage.filter.predicate.permanent.AnotherPredicate; +import mage.game.permanent.token.FoodToken; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class GingerbreadCabin extends CardImpl { + + private static final FilterPermanent filter + = new FilterControlledPermanent(SubType.FOREST); + + static { + filter.add(AnotherPredicate.instance); + } + + private static final Condition condition + = new PermanentsOnTheBattlefieldCondition(filter, ComparisonType.FEWER_THAN, 3); + + public GingerbreadCabin(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); + + this.subtype.add(SubType.FOREST); + + // ({T}: Add {G}.) + this.addAbility(new GreenManaAbility()); + + // Gingerbread Cabin enters the battlefield tapped unless you control three or more other Forests. + this.addAbility(new EntersBattlefieldAbility( + new ConditionalOneShotEffect(new TapSourceEffect(), condition), + "tapped unless you control three or more other Forests" + )); + + // When Gingerbread Cabin enters the battlefield untapped, create a Food token. + this.addAbility(new EntersBattlefieldUntappedTriggeredAbility(new CreateTokenEffect(new FoodToken()), false)); + } + + private GingerbreadCabin(final GingerbreadCabin card) { + super(card); + } + + @Override + public GingerbreadCabin copy() { + return new GingerbreadCabin(this); + } +} diff --git a/Mage.Sets/src/mage/cards/g/Gingerbrute.java b/Mage.Sets/src/mage/cards/g/Gingerbrute.java new file mode 100644 index 0000000000..2d65b3cad6 --- /dev/null +++ b/Mage.Sets/src/mage/cards/g/Gingerbrute.java @@ -0,0 +1,66 @@ +package mage.cards.g; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.SacrificeSourceCost; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.effects.common.GainLifeEffect; +import mage.abilities.effects.common.combat.CantBeBlockedByCreaturesSourceEffect; +import mage.abilities.keyword.HasteAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.AbilityPredicate; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class Gingerbrute extends CardImpl { + + private static final FilterCreaturePermanent filter + = new FilterCreaturePermanent("except by creatures with haste"); + + static { + filter.add(Predicates.not(new AbilityPredicate(HasteAbility.class))); + } + + public Gingerbrute(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{1}"); + + this.subtype.add(SubType.FOOD); + this.subtype.add(SubType.GOLEM); + this.power = new MageInt(1); + this.toughness = new MageInt(1); + + // Haste + this.addAbility(HasteAbility.getInstance()); + + // {1}: Gingerbrute can't be blocked this turn except by creatures with haste. + this.addAbility(new SimpleActivatedAbility( + new CantBeBlockedByCreaturesSourceEffect(filter, Duration.EndOfTurn), new GenericManaCost(1) + )); + + // {2}, {T}, Sacrifice Gingerbrute: You gain 3 life. + Ability ability = new SimpleActivatedAbility(new GainLifeEffect(3), new GenericManaCost(2)); + ability.addCost(new TapSourceCost()); + ability.addCost(new SacrificeSourceCost()); + this.addAbility(ability); + } + + private Gingerbrute(final Gingerbrute card) { + super(card); + } + + @Override + public Gingerbrute copy() { + return new Gingerbrute(this); + } +} diff --git a/Mage.Sets/src/mage/cards/g/GlassCasket.java b/Mage.Sets/src/mage/cards/g/GlassCasket.java new file mode 100644 index 0000000000..a2267dcbb0 --- /dev/null +++ b/Mage.Sets/src/mage/cards/g/GlassCasket.java @@ -0,0 +1,53 @@ +package mage.cards.g; + +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.delayed.OnLeaveReturnExiledToBattlefieldAbility; +import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect; +import mage.abilities.effects.common.ExileUntilSourceLeavesEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.ComparisonType; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterOpponentsCreaturePermanent; +import mage.filter.predicate.mageobject.ConvertedManaCostPredicate; +import mage.target.TargetPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class GlassCasket extends CardImpl { + + private static final FilterPermanent filter + = new FilterOpponentsCreaturePermanent("creature an opponent controls with converted mana cost 3 or less"); + + static { + filter.add(new ConvertedManaCostPredicate(ComparisonType.FEWER_THAN, 4)); + } + + public GlassCasket(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{1}{W}"); + + // When Glass Casket enters the battlefield, exile target creature an opponent controls with converted mana cost 3 or less until Glass Casket leaves the battlefield. + Ability ability = new EntersBattlefieldTriggeredAbility( + new ExileUntilSourceLeavesEffect("") + .setText("exile target creature an opponent controls with converted mana cost 3 " + + "or less until {this} leaves the battlefield") + ); + ability.addTarget(new TargetPermanent(filter)); + ability.addEffect(new CreateDelayedTriggeredAbilityEffect(new OnLeaveReturnExiledToBattlefieldAbility())); + this.addAbility(ability); + } + + private GlassCasket(final GlassCasket card) { + super(card); + } + + @Override + public GlassCasket copy() { + return new GlassCasket(this); + } +} diff --git a/Mage.Sets/src/mage/cards/g/GoryosVengeance.java b/Mage.Sets/src/mage/cards/g/GoryosVengeance.java index d05257c919..45b8fb8753 100644 --- a/Mage.Sets/src/mage/cards/g/GoryosVengeance.java +++ b/Mage.Sets/src/mage/cards/g/GoryosVengeance.java @@ -1,4 +1,3 @@ - package mage.cards.g; import mage.abilities.Ability; @@ -16,6 +15,7 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.*; import mage.filter.FilterCard; +import mage.filter.common.FilterCreatureCard; import mage.filter.predicate.mageobject.SupertypePredicate; import mage.game.Game; import mage.game.permanent.Permanent; @@ -26,19 +26,18 @@ import mage.target.targetpointer.FixedTarget; import java.util.UUID; /** - * * @author LevelX2 */ public final class GoryosVengeance extends CardImpl { - private static final FilterCard filter = new FilterCard("legendary creature card"); + private static final FilterCard filter = new FilterCreatureCard("legendary creature card"); static { filter.add(new SupertypePredicate(SuperType.LEGENDARY)); } public GoryosVengeance(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{1}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{B}"); this.subtype.add(SubType.ARCANE); // Return target legendary creature card from your graveyard to the battlefield. That creature gains haste. Exile it at the beginning of the next end step. @@ -49,7 +48,7 @@ public final class GoryosVengeance extends CardImpl { this.addAbility(new SpliceOntoArcaneAbility("{2}{B}")); } - public GoryosVengeance(final GoryosVengeance card) { + private GoryosVengeance(final GoryosVengeance card) { super(card); } @@ -61,12 +60,12 @@ public final class GoryosVengeance extends CardImpl { class GoryosVengeanceEffect extends OneShotEffect { - public GoryosVengeanceEffect() { + GoryosVengeanceEffect() { super(Outcome.PutCardInPlay); this.staticText = "Return target legendary creature card from your graveyard to the battlefield. That creature gains haste. Exile it at the beginning of the next end step"; } - public GoryosVengeanceEffect(final GoryosVengeanceEffect effect) { + private GoryosVengeanceEffect(final GoryosVengeanceEffect effect) { super(effect); } @@ -78,27 +77,27 @@ class GoryosVengeanceEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - if (controller != null) { - Card card = game.getCard(targetPointer.getFirst(game, source)); - if (card != null) { - if (controller.moveCards(card, Zone.BATTLEFIELD, source, game)) { - Permanent permanent = game.getPermanent(card.getId()); - if (permanent != null) { - // Haste - ContinuousEffect effect = new GainAbilityTargetEffect(HasteAbility.getInstance(), Duration.Custom); - effect.setTargetPointer(new FixedTarget(permanent, game)); - game.addEffect(effect, source); - // Exile it at end of turn - Effect exileEffect = new ExileTargetEffect("Exile " + permanent.getName() + " at the beginning of the next end step"); - exileEffect.setTargetPointer(new FixedTarget(permanent, game)); - DelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(exileEffect); - game.addDelayedTriggeredAbility(delayedAbility, source); - return true; - - } - } - } + if (controller == null) { + return false; } - return false; + Card card = game.getCard(targetPointer.getFirst(game, source)); + if (card == null || !controller.moveCards(card, Zone.BATTLEFIELD, source, game)) { + return false; + } + Permanent permanent = game.getPermanent(card.getId()); + if (permanent == null) { + return false; + } + // Haste + ContinuousEffect effect = new GainAbilityTargetEffect(HasteAbility.getInstance(), Duration.Custom); + effect.setTargetPointer(new FixedTarget(permanent, game)); + game.addEffect(effect, source); + // Exile it at end of turn + Effect exileEffect = new ExileTargetEffect("Exile " + permanent.getName() + " at the beginning of the next end step"); + exileEffect.setTargetPointer(new FixedTarget(permanent, game)); + DelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(exileEffect); + game.addDelayedTriggeredAbility(delayedAbility, source); + return true; + } } diff --git a/Mage.Sets/src/mage/cards/g/GrizzledWolverine.java b/Mage.Sets/src/mage/cards/g/GrizzledWolverine.java new file mode 100644 index 0000000000..18712cb7da --- /dev/null +++ b/Mage.Sets/src/mage/cards/g/GrizzledWolverine.java @@ -0,0 +1,65 @@ +package mage.cards.g; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.LimitedTimesPerTurnActivatedAbility; +import mage.abilities.condition.Condition; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.continuous.BoostSourceEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.game.Game; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class GrizzledWolverine extends CardImpl { + + public GrizzledWolverine(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{R}{R}"); + + this.subtype.add(SubType.WOLVERINE); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // {R}: Grizzled Wolverine gets +2/+0 until end of turn. Activate this ability only during the declare blockers step, only if at least one creature is blocking Grizzled Wolverine, and only once each turn. + this.addAbility(new LimitedTimesPerTurnActivatedAbility( + Zone.BATTLEFIELD, new BoostSourceEffect(2, 0, Duration.EndOfTurn), + new ManaCostsImpl("{R}"), 1, GrizzledWolverineCondition.instance + )); + } + + private GrizzledWolverine(final GrizzledWolverine card) { + super(card); + } + + @Override + public GrizzledWolverine copy() { + return new GrizzledWolverine(this); + } +} + +enum GrizzledWolverineCondition implements Condition { + instance; + + @Override + public boolean apply(Game game, Ability source) { + if (game.getPhase().getStep().getType() != PhaseStep.DECLARE_BLOCKERS) { + return false; + } + return game + .getCombat() + .getGroups() + .stream() + .anyMatch(combatGroup -> combatGroup.getAttackers().contains(source.getSourceId()) + && !combatGroup.getBlockers().isEmpty()); + } + + @Override + public String toString() { + return "during the declare blockers step, only if at least one creature is blocking {this},"; + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/g/GrumgullyTheGenerous.java b/Mage.Sets/src/mage/cards/g/GrumgullyTheGenerous.java new file mode 100644 index 0000000000..cd77305d73 --- /dev/null +++ b/Mage.Sets/src/mage/cards/g/GrumgullyTheGenerous.java @@ -0,0 +1,86 @@ +package mage.cards.g; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.ReplacementEffectImpl; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.counters.CounterType; +import mage.game.Game; +import mage.game.events.EntersTheBattlefieldEvent; +import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class GrumgullyTheGenerous extends CardImpl { + + public GrumgullyTheGenerous(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{R}{G}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.GOBLIN); + this.subtype.add(SubType.SHAMAN); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // Each other non-Human creature you controls enters the battlefield with an additional +1/+1 counter on it. + this.addAbility(new SimpleStaticAbility(new GrumgullyTheGenerousReplacementEffect())); + } + + private GrumgullyTheGenerous(final GrumgullyTheGenerous card) { + super(card); + } + + @Override + public GrumgullyTheGenerous copy() { + return new GrumgullyTheGenerous(this); + } +} + +class GrumgullyTheGenerousReplacementEffect extends ReplacementEffectImpl { + + GrumgullyTheGenerousReplacementEffect() { + super(Duration.WhileOnBattlefield, Outcome.BoostCreature); + staticText = "Each other non-Human creature you controls " + + "enters the battlefield with an additional +1/+1 counter on it."; + } + + private GrumgullyTheGenerousReplacementEffect(final GrumgullyTheGenerousReplacementEffect effect) { + super(effect); + } + + @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) { + Permanent creature = ((EntersTheBattlefieldEvent) event).getTarget(); + return creature != null + && creature.isCreature() + && !source.getSourceId().equals(creature.getId()) + && creature.isControlledBy(source.getControllerId()) + && !creature.hasSubtype(SubType.HUMAN, game); + } + + @Override + public boolean replaceEvent(GameEvent event, Ability source, Game game) { + Permanent creature = ((EntersTheBattlefieldEvent) event).getTarget(); + if (creature != null) { + creature.addCounters(CounterType.P1P1.createInstance(), source, game, event.getAppliedEffects()); + } + return false; + } + + @Override + public GrumgullyTheGenerousReplacementEffect copy() { + return new GrumgullyTheGenerousReplacementEffect(this); + } +} diff --git a/Mage.Sets/src/mage/cards/g/GruulScrapper.java b/Mage.Sets/src/mage/cards/g/GruulScrapper.java index e90188edbf..591ab3071e 100644 --- a/Mage.Sets/src/mage/cards/g/GruulScrapper.java +++ b/Mage.Sets/src/mage/cards/g/GruulScrapper.java @@ -31,7 +31,7 @@ public final class GruulScrapper extends CardImpl { this.toughness = new MageInt(2); //When Gruul Scrapper enters the battlefield, if Red was spent to cast Gruul Scrapper, it gains haste until end of turn. - this.addAbility(new EntersBattlefieldTriggeredAbility(new ConditionalContinuousEffect(new GainAbilitySourceEffect(HasteAbility.getInstance(), Duration.EndOfTurn), new ManaWasSpentCondition(ColoredManaSymbol.R), " if {R} was spent to cast {this}, it gains haste until end of turn")), new ManaSpentToCastWatcher()); + this.addAbility(new EntersBattlefieldTriggeredAbility(new ConditionalContinuousEffect(new GainAbilitySourceEffect(HasteAbility.getInstance(), Duration.EndOfTurn), new ManaWasSpentCondition(ColoredManaSymbol.R), " if {R} was spent to cast this spell, it gains haste until end of turn")), new ManaSpentToCastWatcher()); } diff --git a/Mage.Sets/src/mage/cards/h/HappilyEverAfter.java b/Mage.Sets/src/mage/cards/h/HappilyEverAfter.java new file mode 100644 index 0000000000..c1f1b476a1 --- /dev/null +++ b/Mage.Sets/src/mage/cards/h/HappilyEverAfter.java @@ -0,0 +1,125 @@ +package mage.cards.h; + +import mage.ObjectColor; +import mage.abilities.Ability; +import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.condition.Condition; +import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.WinGameSourceControllerEffect; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.TargetController; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; + +import java.util.Collection; +import java.util.EnumSet; +import java.util.Objects; +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class HappilyEverAfter extends CardImpl { + + public HappilyEverAfter(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{W}"); + + // When Happily Ever After enters the battlefield, each player gains 5 life and draws a card. + this.addAbility(new EntersBattlefieldTriggeredAbility(new HappilyEverAfterEffect())); + + // At the beginning of your upkeep, if there are five colors among permanents you control, there are six or more card types among permanents you control and/or cards in your graveyard, and your life total is greater than or equal to your starting life total, you win the game. + this.addAbility(new ConditionalInterveningIfTriggeredAbility( + new BeginningOfUpkeepTriggeredAbility( + new WinGameSourceControllerEffect(), TargetController.YOU, false + ), HappilyEverAfterCondition.instance, "At the beginning of your upkeep, " + + "if there are five colors among permanents you control, there are six or more card types " + + "among permanents you control and/or cards in your graveyard, and your life total is " + + "greater than or equal to your starting life total, you win the game." + )); + } + + private HappilyEverAfter(final HappilyEverAfter card) { + super(card); + } + + @Override + public HappilyEverAfter copy() { + return new HappilyEverAfter(this); + } +} + +class HappilyEverAfterEffect extends OneShotEffect { + + HappilyEverAfterEffect() { + super(Outcome.GainLife); + staticText = "each player gains 5 life and draws a card"; + } + + private HappilyEverAfterEffect(final HappilyEverAfterEffect effect) { + super(effect); + } + + @Override + public HappilyEverAfterEffect copy() { + return new HappilyEverAfterEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + game.getState() + .getPlayersInRange(source.getControllerId(), game) + .stream() + .map(game::getPlayer) + .filter(Objects::nonNull) + .forEachOrdered(player -> { + player.gainLife(5, game, source); + player.drawCards(1, game); + }); + return true; + } +} + +enum HappilyEverAfterCondition implements Condition { + instance; + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null || player.getLife() < game.getLife()) { + return false; + } + ObjectColor color = new ObjectColor(""); + game.getBattlefield() + .getAllActivePermanents(source.getControllerId()) + .stream() + .map(permanent -> permanent.getColor(game)) + .forEach(color::addColor); + if (color.getColorCount() < 5) { + return false; + } + EnumSet cardTypeEnumSet = EnumSet.noneOf(CardType.class); + game.getBattlefield() + .getAllActivePermanents(source.getControllerId()) + .stream() + .map(Permanent::getCardType) + .flatMap(Collection::stream) + .forEach(cardTypeEnumSet::add); + if (cardTypeEnumSet.size() >= 6) { + return true; + } + player.getGraveyard() + .getCards(game) + .stream() + .map(Card::getCardType) + .flatMap(Collection::stream) + .forEach(cardTypeEnumSet::add); + return cardTypeEnumSet.size() >= 6; + } +} diff --git a/Mage.Sets/src/mage/cards/h/HarmoniousArchon.java b/Mage.Sets/src/mage/cards/h/HarmoniousArchon.java new file mode 100644 index 0000000000..71150b769b --- /dev/null +++ b/Mage.Sets/src/mage/cards/h/HarmoniousArchon.java @@ -0,0 +1,59 @@ +package mage.cards.h; + +import mage.MageInt; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.continuous.SetPowerToughnessAllEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.SubtypePredicate; +import mage.game.permanent.token.HumanToken; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class HarmoniousArchon extends CardImpl { + + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("non-Archon creatures"); + + static { + filter.add(Predicates.not(new SubtypePredicate(SubType.ARCHON))); + } + + public HarmoniousArchon(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{W}{W}"); + + this.subtype.add(SubType.ARCHON); + this.power = new MageInt(4); + this.toughness = new MageInt(5); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // Non-Archon creatures have base power and toughness 3/3. + this.addAbility(new SimpleStaticAbility(new SetPowerToughnessAllEffect( + 3, 3, Duration.WhileOnBattlefield, filter, true + ))); + + // When Harmonious Archon enters the battlefield, create two 1/1 white Human creature tokens. + this.addAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new HumanToken(), 2))); + } + + private HarmoniousArchon(final HarmoniousArchon card) { + super(card); + } + + @Override + public HarmoniousArchon copy() { + return new HarmoniousArchon(this); + } +} diff --git a/Mage.Sets/src/mage/cards/h/HengeWalker.java b/Mage.Sets/src/mage/cards/h/HengeWalker.java new file mode 100644 index 0000000000..1550201d9c --- /dev/null +++ b/Mage.Sets/src/mage/cards/h/HengeWalker.java @@ -0,0 +1,45 @@ +package mage.cards.h; + +import mage.MageInt; +import mage.abilities.common.EntersBattlefieldAbility; +import mage.abilities.condition.common.AdamantCondition; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.counters.CounterType; +import mage.watchers.common.ManaSpentToCastWatcher; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class HengeWalker extends CardImpl { + + public HengeWalker(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{3}"); + + this.subtype.add(SubType.GOLEM); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // Adamant — If at least three mana of the same color was spent to cast this spell, Henge Walker enters the battlefield with a +1/+1 counter on it. + this.addAbility(new EntersBattlefieldAbility( + new AddCountersSourceEffect(CounterType.P1P1.createInstance()), + AdamantCondition.ANY, "
Adamant — " + + "If at least three mana of the same color was spent to cast this spell, " + + "{this} enters the battlefield with a +1/+1 counter on it.", "" + ), new ManaSpentToCastWatcher()); + } + + private HengeWalker(final HengeWalker card) { + super(card); + } + + @Override + public HengeWalker copy() { + return new HengeWalker(this); + } +} diff --git a/Mage.Sets/src/mage/cards/h/HeraldicBanner.java b/Mage.Sets/src/mage/cards/h/HeraldicBanner.java index 6e40a48304..4171169e3f 100644 --- a/Mage.Sets/src/mage/cards/h/HeraldicBanner.java +++ b/Mage.Sets/src/mage/cards/h/HeraldicBanner.java @@ -12,7 +12,7 @@ import mage.abilities.mana.SimpleManaAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.*; -import mage.filter.common.FilterCreaturePermanent; +import mage.filter.StaticFilters; import mage.game.Game; import mage.game.permanent.Permanent; @@ -31,13 +31,13 @@ public final class HeraldicBanner extends CardImpl { this.addAbility(new AsEntersBattlefieldAbility(new ChooseColorEffect(Outcome.Benefit))); // Creatures you control of the chosen color get +1/+0. - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new HeraldicBannerEffect())); + this.addAbility(new SimpleStaticAbility(new HeraldicBannerEffect())); // {T}: Add one mana of the chosen color. this.addAbility(new SimpleManaAbility(Zone.BATTLEFIELD, new AddManaChosenColorEffect(), new TapSourceCost())); } - public HeraldicBanner(final HeraldicBanner card) { + private HeraldicBanner(final HeraldicBanner card) { super(card); } @@ -49,14 +49,12 @@ public final class HeraldicBanner extends CardImpl { class HeraldicBannerEffect extends ContinuousEffectImpl { - private static final FilterCreaturePermanent filter = new FilterCreaturePermanent(); - - public HeraldicBannerEffect() { + HeraldicBannerEffect() { super(Duration.WhileOnBattlefield, Layer.PTChangingEffects_7, SubLayer.ModifyPT_7c, Outcome.BoostCreature); staticText = "Creatures you control of the chosen color get +1/+0"; } - public HeraldicBannerEffect(final HeraldicBannerEffect effect) { + private HeraldicBannerEffect(final HeraldicBannerEffect effect) { super(effect); } @@ -68,14 +66,18 @@ class HeraldicBannerEffect extends ContinuousEffectImpl { @Override public boolean apply(Game game, Ability source) { Permanent permanent = game.getPermanent(source.getSourceId()); - if (permanent != null) { - ObjectColor color = (ObjectColor) game.getState().getValue(permanent.getId() + "_color"); - if (color != null) { - for (Permanent perm : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), game)) { - if (perm.getColor(game).contains(color)) { - perm.addPower(1); - } - } + if (permanent == null) { + return false; + } + ObjectColor color = (ObjectColor) game.getState().getValue(permanent.getId() + "_color"); + if (color == null) { + return false; + } + for (Permanent perm : game.getBattlefield().getActivePermanents( + StaticFilters.FILTER_CONTROLLED_CREATURE, source.getControllerId(), source.getSourceId(), game + )) { + if (perm.getColor(game).contains(color)) { + perm.addPower(1); } } return true; diff --git a/Mage.Sets/src/mage/cards/h/HexplateGolem.java b/Mage.Sets/src/mage/cards/h/HexplateGolem.java index 34b9e6a5c8..ff6ec9671b 100644 --- a/Mage.Sets/src/mage/cards/h/HexplateGolem.java +++ b/Mage.Sets/src/mage/cards/h/HexplateGolem.java @@ -1,28 +1,27 @@ - - package mage.cards.h; -import java.util.UUID; import mage.MageInt; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; +import java.util.UUID; + /** - * * @author Loki */ public final class HexplateGolem extends CardImpl { - public HexplateGolem (UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT,CardType.CREATURE},"{7}"); + public HexplateGolem(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{7}"); + this.subtype.add(SubType.GOLEM); this.power = new MageInt(5); this.toughness = new MageInt(7); } - public HexplateGolem (final HexplateGolem card) { + private HexplateGolem(final HexplateGolem card) { super(card); } @@ -30,5 +29,4 @@ public final class HexplateGolem extends CardImpl { public HexplateGolem copy() { return new HexplateGolem(this); } - } diff --git a/Mage.Sets/src/mage/cards/h/HighcliffFelidar.java b/Mage.Sets/src/mage/cards/h/HighcliffFelidar.java new file mode 100644 index 0000000000..38a85db364 --- /dev/null +++ b/Mage.Sets/src/mage/cards/h/HighcliffFelidar.java @@ -0,0 +1,162 @@ +package mage.cards.h; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.keyword.VigilanceAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.ComparisonType; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.filter.FilterPermanent; +import mage.filter.StaticFilters; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.mageobject.PowerPredicate; +import mage.filter.predicate.permanent.ControllerIdPredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.TargetPermanent; + +import java.util.HashSet; +import java.util.Objects; +import java.util.Set; +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class HighcliffFelidar extends CardImpl { + + public HighcliffFelidar(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{5}{W}{W}"); + + this.subtype.add(SubType.CAT); + this.subtype.add(SubType.BEAST); + this.power = new MageInt(5); + this.toughness = new MageInt(5); + + // Vigilance + this.addAbility(VigilanceAbility.getInstance()); + + // When Highcliff Felidar enters the battlefield, for each opponent, choose a creature with the greatest power among creatures that player controls. Destroy those creatures. + this.addAbility(new EntersBattlefieldTriggeredAbility(new HighcliffFelidarEffect())); + } + + private HighcliffFelidar(final HighcliffFelidar card) { + super(card); + } + + @Override + public HighcliffFelidar copy() { + return new HighcliffFelidar(this); + } +} + +class HighcliffFelidarEffect extends OneShotEffect { + + HighcliffFelidarEffect() { + super(Outcome.Benefit); + staticText = "for each opponent, choose a creature with the greatest power " + + "among creatures that player controls. Destroy those creatures."; + } + + private HighcliffFelidarEffect(final HighcliffFelidarEffect effect) { + super(effect); + } + + @Override + public HighcliffFelidarEffect copy() { + return new HighcliffFelidarEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; + } + Set toDestroy = new HashSet(); + game.getOpponents(source.getControllerId()) + .stream() + .map(game::getPlayer) + .filter(Objects::nonNull) + .forEachOrdered(opponent -> { + int maxPower = game + .getBattlefield() + .getAllActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, opponent.getId(), game) + .stream() + .map(Permanent::getPower) + .mapToInt(MageInt::getValue) + .max() + .orElse(Integer.MIN_VALUE); + if (maxPower == Integer.MIN_VALUE) { + return; + } + FilterPermanent filter = new FilterCreaturePermanent( + "creature with the greatest power controlled by " + opponent.getName() + ); + filter.add(new ControllerIdPredicate(opponent.getId())); + filter.add(new PowerPredicate(ComparisonType.EQUAL_TO, maxPower)); + TargetPermanent target = new TargetPermanent(filter); + target.setNotTarget(true); + if (player.choose(outcome, target, source.getSourceId(), game)) { + toDestroy.add(target.getFirstTarget()); + } + }); + toDestroy.stream() + .map(game::getPermanent) + .filter(Objects::nonNull) + .forEachOrdered(permanent -> permanent.destroy(source.getSourceId(), game, false)); + return true; + } +} + +// I realized after writing all this that the ability doesn't target but I like this code too much to erase it + +//enum HighcliffFelidarAdjuster implements TargetAdjuster { +// instance; +// +// private static class HighcliffFelidarPredicate implements Predicate { +// private final UUID controllerId; +// +// private HighcliffFelidarPredicate(UUID controllerId) { +// this.controllerId = controllerId; +// } +// +// @Override +// public boolean apply(Permanent input, Game game) { +// if (input == null || !input.isControlledBy(controllerId) || !input.isCreature()) { +// return false; +// } +// int maxPower = game.getBattlefield() +// .getAllActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, controllerId, game) +// .stream() +// .map(Permanent::getPower) +// .mapToInt(MageInt::getValue) +// .max() +// .orElse(Integer.MIN_VALUE); +// return input.getPower().getValue() >= maxPower; +// } +// +// private static TargetPermanent getTarget(Player player) { +// FilterPermanent filter = new FilterPermanent("creature with the greatest power controlled by " + player.getName()); +// filter.add(new HighcliffFelidarPredicate(player.getId())); +// return new TargetPermanent(filter); +// } +// } +// +// @Override +// public void adjustTargets(Ability ability, Game game) { +// ability.getTargets().clear(); +// game.getOpponents(ability.getControllerId()) +// .stream() +// .map(game::getPlayer) +// .filter(Objects::nonNull) +// .map(HighcliffFelidarPredicate::getTarget) +// .forEachOrdered(ability::addTarget); +// } +//} diff --git a/Mage.Sets/src/mage/cards/h/HostageTaker.java b/Mage.Sets/src/mage/cards/h/HostageTaker.java index fd60803464..816ff40e09 100644 --- a/Mage.Sets/src/mage/cards/h/HostageTaker.java +++ b/Mage.Sets/src/mage/cards/h/HostageTaker.java @@ -1,6 +1,5 @@ package mage.cards.h; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; @@ -12,17 +11,12 @@ import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.AsThoughEffectType; -import mage.constants.CardType; -import mage.constants.Duration; -import mage.constants.ManaType; -import mage.constants.Outcome; -import mage.constants.SubType; -import mage.constants.Zone; +import mage.constants.*; import mage.filter.FilterPermanent; import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.CardTypePredicate; import mage.filter.predicate.permanent.AnotherPredicate; +import mage.game.ExileZone; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.ManaPoolItem; @@ -31,8 +25,10 @@ import mage.target.TargetPermanent; import mage.target.targetpointer.FixedTarget; import mage.util.CardUtil; +import java.util.Objects; +import java.util.UUID; + /** - * * @author TheElk801 */ public final class HostageTaker extends CardImpl { @@ -43,7 +39,8 @@ public final class HostageTaker extends CardImpl { filter.add(AnotherPredicate.instance); filter.add(Predicates.or( new CardTypePredicate(CardType.ARTIFACT), - new CardTypePredicate(CardType.CREATURE))); + new CardTypePredicate(CardType.CREATURE) + )); } public HostageTaker(UUID ownerId, CardSetInfo setInfo) { @@ -55,13 +52,13 @@ public final class HostageTaker extends CardImpl { this.toughness = new MageInt(3); // 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. - Ability ability = new EntersBattlefieldTriggeredAbility(new HostageTakerExileEffect(filter.getMessage())); + Ability ability = new EntersBattlefieldTriggeredAbility(new HostageTakerExileEffect()); ability.addTarget(new TargetPermanent(filter)); ability.addEffect(new CreateDelayedTriggeredAbilityEffect(new OnLeaveReturnExiledToBattlefieldAbility())); this.addAbility(ability); } - public HostageTaker(final HostageTaker card) { + private HostageTaker(final HostageTaker card) { super(card); } @@ -73,14 +70,14 @@ public final class HostageTaker extends CardImpl { class HostageTakerExileEffect extends OneShotEffect { - public HostageTakerExileEffect(String targetName) { + HostageTakerExileEffect() { super(Outcome.Benefit); this.staticText = "exile another target artifact or creature until {this} 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"; } - public HostageTakerExileEffect(final HostageTakerExileEffect effect) { + private HostageTakerExileEffect(final HostageTakerExileEffect effect) { super(effect); } @@ -93,35 +90,41 @@ class HostageTakerExileEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Permanent card = game.getPermanent(getTargetPointer().getFirst(game, source)); Permanent permanent = game.getPermanent(source.getSourceId()); - if (permanent != null && card != null) { - Player controller = game.getPlayer(card.getControllerId()); - if (controller != null) { - // move card to exile - UUID exileId = CardUtil.getCardExileZoneId(game, source); - controller.moveCardToExileWithInfo(card, exileId, permanent.getIdName(), source.getSourceId(), game, Zone.BATTLEFIELD, true); - // allow to cast the card - ContinuousEffect effect = new HostageTakerCastFromExileEffect(); - effect.setTargetPointer(new FixedTarget(card.getId())); - game.addEffect(effect, source); - // and you may spend mana as though it were mana of any color to cast it - effect = new HostageTakerSpendAnyManaEffect(); - effect.setTargetPointer(new FixedTarget(card.getId())); - game.addEffect(effect, source); - } + if (permanent == null || card == null) { + return false; } + Player controller = game.getPlayer(card.getControllerId()); + if (controller == null) { + return false; + } + // move card to exile + UUID exileId = CardUtil.getCardExileZoneId(game, source); + controller.moveCardToExileWithInfo(card, exileId, permanent.getIdName(), source.getSourceId(), game, Zone.BATTLEFIELD, true); + // allow to cast the card + game.addEffect(new HostageTakerCastFromExileEffect(card.getId(), exileId), source); + // and you may spend mana as though it were mana of any color to cast it + ContinuousEffect effect = new HostageTakerSpendAnyManaEffect(); + effect.setTargetPointer(new FixedTarget(card.getId(), game)); + game.addEffect(effect, source); return false; } } class HostageTakerCastFromExileEffect extends AsThoughEffectImpl { - public HostageTakerCastFromExileEffect() { + private UUID cardId; + private UUID exileId; + + HostageTakerCastFromExileEffect(UUID cardId, UUID exileId) { super(AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, Duration.Custom, Outcome.Benefit); - staticText = "You may cast that card for as long as it remains exiled, and you may spend mana as though it were mana of any color to cast that spell"; + this.cardId = cardId; + this.exileId = exileId; } - public HostageTakerCastFromExileEffect(final HostageTakerCastFromExileEffect effect) { + private HostageTakerCastFromExileEffect(final HostageTakerCastFromExileEffect effect) { super(effect); + this.cardId = effect.cardId; + this.exileId = effect.exileId; } @Override @@ -135,29 +138,26 @@ class HostageTakerCastFromExileEffect extends AsThoughEffectImpl { } @Override - public boolean applies(UUID objectId, Ability source, UUID affectedControllerId, Game game) { - if (objectId.equals(getTargetPointer().getFirst(game, source))) { - if (affectedControllerId.equals(source.getControllerId())) { - return true; - } - } else { - if (((FixedTarget) getTargetPointer()).getTarget().equals(objectId)) { - // object has moved zone so effect can be discarted - this.discard(); - } + public boolean applies(UUID sourceId, Ability source, UUID affectedControllerId, Game game) { + if (!sourceId.equals(cardId) || !source.isControlledBy(affectedControllerId)) { + return false; } + ExileZone exileZone = game.getState().getExile().getExileZone(exileId); + if (exileZone != null && exileZone.contains(cardId)) { + return true; + } + discard(); return false; } } class HostageTakerSpendAnyManaEffect extends AsThoughEffectImpl implements AsThoughManaEffect { - public HostageTakerSpendAnyManaEffect() { + HostageTakerSpendAnyManaEffect() { super(AsThoughEffectType.SPEND_OTHER_MANA, Duration.Custom, Outcome.Benefit); - staticText = "you may spend mana as though it were mana of any color to cast it"; } - public HostageTakerSpendAnyManaEffect(final HostageTakerSpendAnyManaEffect effect) { + private HostageTakerSpendAnyManaEffect(final HostageTakerSpendAnyManaEffect effect) { super(effect); } @@ -173,22 +173,11 @@ class HostageTakerSpendAnyManaEffect extends AsThoughEffectImpl implements AsTho @Override public boolean applies(UUID objectId, Ability source, UUID affectedControllerId, Game game) { - objectId = game.getCard(objectId).getMainCard().getId(); // for split cards - if (objectId.equals(((FixedTarget) getTargetPointer()).getTarget()) - && game.getState().getZoneChangeCounter(objectId) <= ((FixedTarget) getTargetPointer()).getZoneChangeCounter() + 1) { - if (affectedControllerId.equals(source.getControllerId())) { - // if the card moved from exile to spell the zone change counter is increased by 1 - if (game.getState().getZoneChangeCounter(objectId) == ((FixedTarget) getTargetPointer()).getZoneChangeCounter() + 1) { - return true; - } - } - } else { - if (((FixedTarget) getTargetPointer()).getTarget().equals(objectId)) { - // object has moved zone so effect can be discarted - this.discard(); - } - } - return false; + FixedTarget fixedTarget = ((FixedTarget) getTargetPointer()); + return source.isControlledBy(affectedControllerId) + && Objects.equals(objectId, fixedTarget.getTarget()) + && fixedTarget.getZoneChangeCounter() + 1 == game.getState().getZoneChangeCounter(objectId) + && game.getState().getZone(objectId) == Zone.STACK; } @Override diff --git a/Mage.Sets/src/mage/cards/h/Hushbringer.java b/Mage.Sets/src/mage/cards/h/Hushbringer.java new file mode 100644 index 0000000000..76e83933fb --- /dev/null +++ b/Mage.Sets/src/mage/cards/h/Hushbringer.java @@ -0,0 +1,119 @@ +package mage.cards.h; + +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.FlyingAbility; +import mage.abilities.keyword.LifelinkAbility; +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.events.ZoneChangeEvent; +import mage.game.permanent.Permanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class Hushbringer extends CardImpl { + + public Hushbringer(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W}"); + + this.subtype.add(SubType.FAERIE); + this.power = new MageInt(1); + this.toughness = new MageInt(2); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // Lifelink + this.addAbility(LifelinkAbility.getInstance()); + + // Creatures entering the battlefield or dying don't cause abilities to trigger. + this.addAbility(new SimpleStaticAbility(new HushbringerEffect())); + } + + private Hushbringer(final Hushbringer card) { + super(card); + } + + @Override + public Hushbringer copy() { + return new Hushbringer(this); + } +} + +class HushbringerEffect extends ContinuousRuleModifyingEffectImpl { + + HushbringerEffect() { + super(Duration.WhileOnBattlefield, Outcome.Detriment, false, false); + staticText = "Creatures entering the battlefield or dying don't cause abilities to trigger"; + } + + private HushbringerEffect(final HushbringerEffect effect) { + super(effect); + } + + @Override + public boolean checksEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.ENTERS_THE_BATTLEFIELD + || event.getType() == GameEvent.EventType.ZONE_CHANGE; + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + Ability ability = (Ability) getValue("targetAbility"); + if (ability == null || ability.getAbilityType() != AbilityType.TRIGGERED) { + return false; + } + Permanent permanent; + switch (event.getType()) { + case ENTERS_THE_BATTLEFIELD: + permanent = ((EntersTheBattlefieldEvent) event).getTarget(); + break; + case ZONE_CHANGE: + ZoneChangeEvent zEvent = ((ZoneChangeEvent) event); + if (!zEvent.isDiesEvent()) { + return false; + } + permanent = zEvent.getTarget(); + break; + default: + return false; + } + + if (permanent == null || !permanent.isCreature()) { + return false; + } + return (((TriggeredAbility) ability).checkTrigger(event, game)); + } + + @Override + public String getInfoMessage(Ability source, GameEvent event, Game game) { + MageObject enteringObject = game.getObject(event.getSourceId()); + MageObject sourceObject = game.getObject(source.getSourceId()); + Ability ability = (Ability) getValue("targetAbility"); + if (enteringObject == null || sourceObject == null || ability == null) { + return null; + } + MageObject abilitObject = game.getObject(ability.getSourceId()); + if (abilitObject == null) { + return null; + } + return sourceObject.getLogName() + " prevented ability of " + + abilitObject.getLogName() + " from triggering."; + } + + @Override + public HushbringerEffect copy() { + return new HushbringerEffect(this); + } +} diff --git a/Mage.Sets/src/mage/cards/h/HypnoticSprite.java b/Mage.Sets/src/mage/cards/h/HypnoticSprite.java new file mode 100644 index 0000000000..40868c5afb --- /dev/null +++ b/Mage.Sets/src/mage/cards/h/HypnoticSprite.java @@ -0,0 +1,52 @@ +package mage.cards.h; + +import mage.MageInt; +import mage.abilities.effects.common.CounterTargetEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.AdventureCard; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.ComparisonType; +import mage.constants.SubType; +import mage.filter.FilterSpell; +import mage.filter.predicate.mageobject.ConvertedManaCostPredicate; +import mage.target.TargetSpell; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class HypnoticSprite extends AdventureCard { + + private static final FilterSpell filter = new FilterSpell("spell with converted mana cost 3 or less"); + + static { + filter.add(new ConvertedManaCostPredicate(ComparisonType.FEWER_THAN, 4)); + } + + public HypnoticSprite(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, new CardType[]{CardType.INSTANT}, "{U}{U}", "Mesmeric Glare", "{2}{U}"); + + this.subtype.add(SubType.FAERIE); + this.power = new MageInt(2); + this.toughness = new MageInt(1); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // Mesmeric Glare + // Counter target spell with converted mana cost 3 or less. + this.getAdventureSpellAbility().addEffect(new CounterTargetEffect()); + this.getAdventureSpellAbility().addTarget(new TargetSpell(filter)); + } + + private HypnoticSprite(final HypnoticSprite card) { + super(card); + } + + @Override + public HypnoticSprite copy() { + return new HypnoticSprite(this); + } +} diff --git a/Mage.Sets/src/mage/cards/i/IdyllicGrange.java b/Mage.Sets/src/mage/cards/i/IdyllicGrange.java new file mode 100644 index 0000000000..50b1d4bfc6 --- /dev/null +++ b/Mage.Sets/src/mage/cards/i/IdyllicGrange.java @@ -0,0 +1,69 @@ +package mage.cards.i; + +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldAbility; +import mage.abilities.common.EntersBattlefieldUntappedTriggeredAbility; +import mage.abilities.condition.Condition; +import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; +import mage.abilities.decorator.ConditionalOneShotEffect; +import mage.abilities.effects.common.TapSourceEffect; +import mage.abilities.effects.common.counter.AddCountersTargetEffect; +import mage.abilities.mana.WhiteManaAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.ComparisonType; +import mage.constants.SubType; +import mage.counters.CounterType; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledPermanent; +import mage.filter.predicate.permanent.AnotherPredicate; +import mage.target.common.TargetControlledCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class IdyllicGrange extends CardImpl { + + private static final FilterPermanent filter + = new FilterControlledPermanent(SubType.PLAINS); + + static { + filter.add(AnotherPredicate.instance); + } + private static final Condition condition + = new PermanentsOnTheBattlefieldCondition(filter, ComparisonType.FEWER_THAN, 3); + + public IdyllicGrange(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); + + this.subtype.add(SubType.PLAINS); + + // ({T}: Add {W}.) + this.addAbility(new WhiteManaAbility()); + + // Idyllic Grange enters the battlefield tapped unless you control three or more other Plains. + this.addAbility(new EntersBattlefieldAbility( + new ConditionalOneShotEffect(new TapSourceEffect(), condition), + "tapped unless you control three or more other Plains" + )); + + // When Idyllic Grange enters the battlefield untapped, put a +1/+1 counter on target creature you control. + Ability ability = new EntersBattlefieldUntappedTriggeredAbility( + new AddCountersTargetEffect(CounterType.P1P1.createInstance()), false + ); + ability.addTarget(new TargetControlledCreaturePermanent()); + this.addAbility(ability); + } + + private IdyllicGrange(final IdyllicGrange card) { + super(card); + } + + @Override + public IdyllicGrange copy() { + return new IdyllicGrange(this); + } +} diff --git a/Mage.Sets/src/mage/cards/i/ImposingSovereign.java b/Mage.Sets/src/mage/cards/i/ImposingSovereign.java index e46be3e1bc..9a38f66703 100644 --- a/Mage.Sets/src/mage/cards/i/ImposingSovereign.java +++ b/Mage.Sets/src/mage/cards/i/ImposingSovereign.java @@ -1,32 +1,27 @@ - package mage.cards.i; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.ReplacementEffectImpl; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; -import mage.constants.Duration; -import mage.constants.Outcome; -import mage.constants.Zone; +import mage.constants.*; import mage.game.Game; import mage.game.events.EntersTheBattlefieldEvent; import mage.game.events.GameEvent; import mage.game.permanent.Permanent; +import java.util.UUID; + /** - * * @author jeffwadsworth */ public final class ImposingSovereign extends CardImpl { public ImposingSovereign(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{W}"); - this.subtype.add(SubType.HUMAN); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W}"); + this.subtype.add(SubType.HUMAN, SubType.NOBLE); this.power = new MageInt(2); this.toughness = new MageInt(1); @@ -36,7 +31,7 @@ public final class ImposingSovereign extends CardImpl { } - public ImposingSovereign(final ImposingSovereign card) { + private ImposingSovereign(final ImposingSovereign card) { super(card); } @@ -53,7 +48,7 @@ class ImposingSovereignEffect extends ReplacementEffectImpl { staticText = "Creatures your opponents control enter the battlefield tapped"; } - ImposingSovereignEffect(final ImposingSovereignEffect effect) { + private ImposingSovereignEffect(final ImposingSovereignEffect effect) { super(effect); } @@ -73,13 +68,11 @@ class ImposingSovereignEffect extends ReplacementEffectImpl { @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; - } + if (!game.getOpponents(source.getControllerId()).contains(event.getPlayerId())) { + return false; } - return false; + Permanent permanent = ((EntersTheBattlefieldEvent) event).getTarget(); + return permanent != null && permanent.isCreature(); } @Override diff --git a/Mage.Sets/src/mage/cards/i/ImprobableAlliance.java b/Mage.Sets/src/mage/cards/i/ImprobableAlliance.java new file mode 100644 index 0000000000..85c917a197 --- /dev/null +++ b/Mage.Sets/src/mage/cards/i/ImprobableAlliance.java @@ -0,0 +1,40 @@ +package mage.cards.i; + +import mage.abilities.common.DrawSecondCardTriggeredAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.DrawDiscardControllerEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.game.permanent.token.FaerieToken; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ImprobableAlliance extends CardImpl { + + public ImprobableAlliance(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{U}{R}"); + + // Whenever you draw your second card each turn, create a 1/1 blue Faerie creature token with flying. + this.addAbility(new DrawSecondCardTriggeredAbility(new CreateTokenEffect(new FaerieToken()), false)); + + // {4}{U}{R}: Draw a card, then discard a card. + this.addAbility(new SimpleActivatedAbility( + new DrawDiscardControllerEffect(1, 1), new ManaCostsImpl("{4}{U}{R}") + )); + } + + private ImprobableAlliance(final ImprobableAlliance card) { + super(card); + } + + @Override + public ImprobableAlliance copy() { + return new ImprobableAlliance(this); + } +} diff --git a/Mage.Sets/src/mage/cards/i/InduceParanoia.java b/Mage.Sets/src/mage/cards/i/InduceParanoia.java index d4b4a8d37c..d8862fa168 100644 --- a/Mage.Sets/src/mage/cards/i/InduceParanoia.java +++ b/Mage.Sets/src/mage/cards/i/InduceParanoia.java @@ -31,7 +31,7 @@ public final class InduceParanoia extends CardImpl { this.getSpellAbility().addEffect(new ConditionalOneShotEffect( new InduceParanoiaEffect(), new CounterTargetEffect(), - new ManaWasSpentCondition(ColoredManaSymbol.B), "Counter target spell. If {B} was spent to cast {this}, that spell's controller puts the top X cards of their library into their graveyard, where X is the spell's converted mana cost.")); + new ManaWasSpentCondition(ColoredManaSymbol.B), "Counter target spell. If {B} was spent to cast this spell, that spell's controller puts the top X cards of their library into their graveyard, where X is the spell's converted mana cost.")); // Counter target spell. this.getSpellAbility().addTarget(new TargetSpell()); @@ -51,7 +51,7 @@ class InduceParanoiaEffect extends OneShotEffect { InduceParanoiaEffect() { super(Outcome.Detriment); - this.staticText = "Counter target spell. If {B} was spent to cast {this}, that spell's controller puts the top X cards of their library into their graveyard, where X is the spell's converted mana cost."; + this.staticText = "Counter target spell. If {B} was spent to cast this spell, that spell's controller puts the top X cards of their library into their graveyard, where X is the spell's converted mana cost."; } InduceParanoiaEffect(final InduceParanoiaEffect effect) { diff --git a/Mage.Sets/src/mage/cards/i/IndulgentAristocrat.java b/Mage.Sets/src/mage/cards/i/IndulgentAristocrat.java index 3379c1dc35..ec6c93cdd6 100644 --- a/Mage.Sets/src/mage/cards/i/IndulgentAristocrat.java +++ b/Mage.Sets/src/mage/cards/i/IndulgentAristocrat.java @@ -1,7 +1,5 @@ - package mage.cards.i; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; @@ -15,13 +13,15 @@ import mage.constants.CardType; import mage.constants.SubType; import mage.constants.Zone; import mage.counters.CounterType; -import static mage.filter.StaticFilters.FILTER_CONTROLLED_CREATURE_SHORT_TEXT; import mage.filter.common.FilterControlledPermanent; import mage.filter.predicate.mageobject.SubtypePredicate; import mage.target.common.TargetControlledCreaturePermanent; +import java.util.UUID; + +import static mage.filter.StaticFilters.FILTER_CONTROLLED_CREATURE_SHORT_TEXT; + /** - * * @author fireshoes */ public final class IndulgentAristocrat extends CardImpl { @@ -34,7 +34,7 @@ public final class IndulgentAristocrat extends CardImpl { public IndulgentAristocrat(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{B}"); - this.subtype.add(SubType.VAMPIRE); + this.subtype.add(SubType.VAMPIRE, SubType.NOBLE); this.power = new MageInt(1); this.toughness = new MageInt(1); @@ -47,7 +47,7 @@ public final class IndulgentAristocrat extends CardImpl { this.addAbility(ability); } - public IndulgentAristocrat(final IndulgentAristocrat card) { + private IndulgentAristocrat(final IndulgentAristocrat card) { super(card); } diff --git a/Mage.Sets/src/mage/cards/i/InfernalHarvest.java b/Mage.Sets/src/mage/cards/i/InfernalHarvest.java new file mode 100644 index 0000000000..74f128ab3e --- /dev/null +++ b/Mage.Sets/src/mage/cards/i/InfernalHarvest.java @@ -0,0 +1,127 @@ +package mage.cards.i; + +import mage.abilities.Ability; +import mage.abilities.costs.Cost; +import mage.abilities.costs.CostImpl; +import mage.abilities.costs.VariableCostImpl; +import mage.abilities.dynamicvalue.common.GetXValue; +import mage.abilities.effects.common.DamageMultiEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.constants.Zone; +import mage.filter.common.FilterControlledPermanent; +import mage.game.Game; +import mage.players.Player; +import mage.target.Target; +import mage.target.common.TargetControlledPermanent; +import mage.target.common.TargetCreaturePermanentAmount; + +import java.util.Collection; +import java.util.Objects; +import java.util.UUID; +import java.util.stream.Collectors; + +/** + * @author TheElk801 + */ +public final class InfernalHarvest extends CardImpl { + + public InfernalHarvest(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{1}{B}"); + + // As an additional cost to cast Infernal Harvest, return X Swamps you control to their owner's hand. + this.getSpellAbility().addCost(new InfernalHarvestVariableCost()); + + // Infernal Harvest deals X damage divided as you choose among any number of target creatures. + this.getSpellAbility().addEffect(new DamageMultiEffect(GetXValue.instance)); + this.getSpellAbility().addTarget(new TargetCreaturePermanentAmount(GetXValue.instance)); + } + + private InfernalHarvest(final InfernalHarvest card) { + super(card); + } + + @Override + public InfernalHarvest copy() { + return new InfernalHarvest(this); + } +} + +class InfernalHarvestVariableCost extends VariableCostImpl { + + private static final FilterControlledPermanent filter = new FilterControlledPermanent(SubType.SWAMP); + + InfernalHarvestVariableCost() { + super("Swamps to return"); + this.text = "return " + xText + " Swamps you control to their owner's hand"; + } + + private InfernalHarvestVariableCost(final InfernalHarvestVariableCost cost) { + super(cost); + } + + @Override + public InfernalHarvestVariableCost copy() { + return new InfernalHarvestVariableCost(this); + } + + @Override + public int getMaxValue(Ability source, Game game) { + return game.getBattlefield().countAll(filter, source.getControllerId(), game); + } + + @Override + public Cost getFixedCostsFromAnnouncedValue(int xValue) { + return new InfernalHarvestCost(xValue); + } + + private static final class InfernalHarvestCost extends CostImpl { + + private final int xValue; + + private InfernalHarvestCost(int xValue) { + super(); + this.xValue = xValue; + this.text = "return " + xValue + " Swamps you control to their owner's hand"; + this.addTarget(new TargetControlledPermanent(xValue, xValue, filter, true)); + } + + private InfernalHarvestCost(final InfernalHarvestCost cost) { + super(cost); + this.xValue = cost.xValue; + } + + @Override + public boolean canPay(Ability ability, UUID sourceId, UUID controllerId, Game game) { + return game.getBattlefield().countAll(filter, controllerId, game) >= xValue; + } + + @Override + public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana, Cost costToPay) { + if (!this.canPay(ability, sourceId, controllerId, game)) { + return false; + } + Player player = game.getPlayer(controllerId); + if (player == null || !targets.choose(Outcome.ReturnToHand, controllerId, sourceId, game)) { + return false; + } + return paid = player.moveCards( + targets.stream() + .map(Target::getTargets) + .flatMap(Collection::stream) + .map(game::getCard) + .filter(Objects::nonNull) + .collect(Collectors.toSet()), + Zone.HAND, ability, game + ); + } + + @Override + public Cost copy() { + return new InfernalHarvestCost(this); + } + } +} diff --git a/Mage.Sets/src/mage/cards/i/InquisitivePuppet.java b/Mage.Sets/src/mage/cards/i/InquisitivePuppet.java new file mode 100644 index 0000000000..9de9edf129 --- /dev/null +++ b/Mage.Sets/src/mage/cards/i/InquisitivePuppet.java @@ -0,0 +1,44 @@ +package mage.cards.i; + +import mage.MageInt; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.ExileSourceCost; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.keyword.ScryEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.game.permanent.token.HumanToken; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class InquisitivePuppet extends CardImpl { + + public InquisitivePuppet(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{1}"); + + this.subtype.add(SubType.CONSTRUCT); + this.power = new MageInt(0); + this.toughness = new MageInt(2); + + // When Inquisitive Puppet enters the battlefield, scry 1. + this.addAbility(new EntersBattlefieldTriggeredAbility(new ScryEffect(1))); + + // Exile Inquisitive Puppet: Create a 1/1 white Human creature token. + this.addAbility(new SimpleActivatedAbility(new CreateTokenEffect(new HumanToken()), new ExileSourceCost())); + } + + private InquisitivePuppet(final InquisitivePuppet card) { + super(card); + } + + @Override + public InquisitivePuppet copy() { + return new InquisitivePuppet(this); + } +} diff --git a/Mage.Sets/src/mage/cards/i/InsatiableAppetite.java b/Mage.Sets/src/mage/cards/i/InsatiableAppetite.java new file mode 100644 index 0000000000..60bc2bfaad --- /dev/null +++ b/Mage.Sets/src/mage/cards/i/InsatiableAppetite.java @@ -0,0 +1,45 @@ +package mage.cards.i; + +import mage.abilities.costs.common.SacrificeTargetCost; +import mage.abilities.effects.common.DoIfCostPaid; +import mage.abilities.effects.common.continuous.BoostTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.filter.common.FilterControlledPermanent; +import mage.target.common.TargetControlledPermanent; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class InsatiableAppetite extends CardImpl { + + private static final FilterControlledPermanent filter = new FilterControlledPermanent(SubType.FOOD, "a Food"); + + public InsatiableAppetite(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{G}"); + + // You may sacrifice a Food. If you do, target creature gets +5/+5 until end of turn. Otherwise, that creature gets +3/+3 until end of turn. + this.getSpellAbility().addEffect(new DoIfCostPaid( + new BoostTargetEffect(5, 5, Duration.EndOfTurn), + new BoostTargetEffect(3, 3, Duration.EndOfTurn), + new SacrificeTargetCost(new TargetControlledPermanent(filter)) + ).setText("You may sacrifice a Food. If you do, target creature gets +5/+5 until end of turn. " + + "Otherwise, that creature gets +3/+3 until end of turn.")); + this.getSpellAbility().addTarget(new TargetCreaturePermanent()); + } + + private InsatiableAppetite(final InsatiableAppetite card) { + super(card); + } + + @Override + public InsatiableAppetite copy() { + return new InsatiableAppetite(this); + } +} diff --git a/Mage.Sets/src/mage/cards/i/InspiringVeteran.java b/Mage.Sets/src/mage/cards/i/InspiringVeteran.java index caa57a7a20..6bd8f7e88a 100644 --- a/Mage.Sets/src/mage/cards/i/InspiringVeteran.java +++ b/Mage.Sets/src/mage/cards/i/InspiringVeteran.java @@ -30,7 +30,7 @@ public final class InspiringVeteran extends CardImpl { // Other Knights you control get +1/+1. this.addAbility(new SimpleStaticAbility( - new BoostControlledEffect(1, 1, Duration.WhileOnBattlefield, filter) + new BoostControlledEffect(1, 1, Duration.WhileOnBattlefield, filter, true) )); } @@ -42,4 +42,4 @@ public final class InspiringVeteran extends CardImpl { public InspiringVeteran copy() { return new InspiringVeteran(this); } -} +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/i/IntoTheStory.java b/Mage.Sets/src/mage/cards/i/IntoTheStory.java new file mode 100644 index 0000000000..e48ef7bf07 --- /dev/null +++ b/Mage.Sets/src/mage/cards/i/IntoTheStory.java @@ -0,0 +1,63 @@ +package mage.cards.i; + +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.Condition; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.cost.SpellCostReductionSourceEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Zone; +import mage.game.Game; +import mage.game.Graveyard; +import mage.players.Player; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class IntoTheStory extends CardImpl { + + public IntoTheStory(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{5}{U}{U}"); + + // This spell costs {3} less to cast if an opponent has seven or more cards in their graveyard. + this.addAbility(new SimpleStaticAbility( + Zone.STACK, new SpellCostReductionSourceEffect(3, IntoTheStoryCondition.instance) + ).setRuleAtTheTop(true)); + + // Draw four cards. + this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(4)); + } + + private IntoTheStory(final IntoTheStory card) { + super(card); + } + + @Override + public IntoTheStory copy() { + return new IntoTheStory(this); + } +} + +enum IntoTheStoryCondition implements Condition { + instance; + + @Override + public boolean apply(Game game, Ability source) { + return game + .getOpponents(source.getControllerId()) + .stream() + .map(game::getPlayer) + .map(Player::getGraveyard) + .mapToInt(Graveyard::size) + .anyMatch(i -> i >= 7); + } + + @Override + public String toString() { + return "an opponent has seven or more cards in their graveyard"; + } +} diff --git a/Mage.Sets/src/mage/cards/i/InvertTheSkies.java b/Mage.Sets/src/mage/cards/i/InvertTheSkies.java index 6d7daa3836..23ef03b4eb 100644 --- a/Mage.Sets/src/mage/cards/i/InvertTheSkies.java +++ b/Mage.Sets/src/mage/cards/i/InvertTheSkies.java @@ -43,7 +43,7 @@ public final class InvertTheSkies extends CardImpl { this.getSpellAbility().addEffect(new ConditionalContinuousEffect( new LoseAbilityAllEffect(FlyingAbility.getInstance(), Duration.EndOfTurn, filter), new LockedInCondition(new ManaWasSpentCondition(ColoredManaSymbol.G)), - "Creatures your opponents control lose flying until end of turn if {G} was spent to cast {this},")); + "Creatures your opponents control lose flying until end of turn if {G} was spent to cast this spell,")); this.getSpellAbility().addEffect(new ConditionalContinuousEffect( new GainAbilityControlledEffect(FlyingAbility.getInstance(), Duration.EndOfTurn), diff --git a/Mage.Sets/src/mage/cards/i/IrencragFeat.java b/Mage.Sets/src/mage/cards/i/IrencragFeat.java new file mode 100644 index 0000000000..022811c4af --- /dev/null +++ b/Mage.Sets/src/mage/cards/i/IrencragFeat.java @@ -0,0 +1,102 @@ +package mage.cards.i; + +import mage.Mana; +import mage.abilities.Ability; +import mage.abilities.effects.ContinuousRuleModifyingEffectImpl; +import mage.abilities.effects.Effect; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.mana.BasicManaEffect; +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.watchers.common.CastSpellLastTurnWatcher; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class IrencragFeat extends CardImpl { + + public IrencragFeat(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{1}{R}{R}{R}"); + + // Add seven {R}. You can cast only one more spell this turn. + this.getSpellAbility().addEffect(new IrencragFeatEffect()); + } + + private IrencragFeat(final IrencragFeat card) { + super(card); + } + + @Override + public IrencragFeat copy() { + return new IrencragFeat(this); + } +} + +class IrencragFeatEffect extends OneShotEffect { + + private static final Effect effect = new BasicManaEffect(Mana.RedMana(7)); + + IrencragFeatEffect() { + super(Outcome.Benefit); + staticText = "Add seven {R}. You can cast only one more spell this turn."; + } + + private IrencragFeatEffect(final IrencragFeatEffect effect) { + super(effect); + } + + @Override + public IrencragFeatEffect copy() { + return new IrencragFeatEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + CastSpellLastTurnWatcher watcher = game.getState().getWatcher(CastSpellLastTurnWatcher.class); + if (watcher == null) { + return false; + } + int spellsCast = watcher.getAmountOfSpellsPlayerCastOnCurrentTurn(source.getControllerId()); + game.addEffect(new IrencragFeatCantCastEffect(spellsCast), source); + return effect.apply(game, source); + } +} + +class IrencragFeatCantCastEffect extends ContinuousRuleModifyingEffectImpl { + + private final int spellsCast; + + IrencragFeatCantCastEffect(int spellsCast) { + super(Duration.WhileOnBattlefield, Outcome.Detriment); + this.spellsCast = spellsCast; + } + + private IrencragFeatCantCastEffect(final IrencragFeatCantCastEffect effect) { + super(effect); + this.spellsCast = effect.spellsCast; + } + + @Override + public IrencragFeatCantCastEffect copy() { + return new IrencragFeatCantCastEffect(this); + } + + @Override + public boolean checksEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.CAST_SPELL; + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + CastSpellLastTurnWatcher watcher = game.getState().getWatcher(CastSpellLastTurnWatcher.class); + return event.getPlayerId().equals(source.getControllerId()) + && watcher.getAmountOfSpellsPlayerCastOnCurrentTurn(event.getPlayerId()) > spellsCast + 1; + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/i/IrencragPyromancer.java b/Mage.Sets/src/mage/cards/i/IrencragPyromancer.java new file mode 100644 index 0000000000..15265ab317 --- /dev/null +++ b/Mage.Sets/src/mage/cards/i/IrencragPyromancer.java @@ -0,0 +1,42 @@ +package mage.cards.i; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.DrawSecondCardTriggeredAbility; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.target.common.TargetAnyTarget; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class IrencragPyromancer extends CardImpl { + + public IrencragPyromancer(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{R}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.WIZARD); + this.power = new MageInt(0); + this.toughness = new MageInt(4); + + // Whenever you draw your second card each turn, Irencrag Pyromancer deals 3 damage to any target. + Ability ability = new DrawSecondCardTriggeredAbility(new DamageTargetEffect(3), false); + ability.addTarget(new TargetAnyTarget()); + this.addAbility(ability); + } + + private IrencragPyromancer(final IrencragPyromancer card) { + super(card); + } + + @Override + public IrencragPyromancer copy() { + return new IrencragPyromancer(this); + } +} diff --git a/Mage.Sets/src/mage/cards/j/JaceArcaneStrategist.java b/Mage.Sets/src/mage/cards/j/JaceArcaneStrategist.java index bbaeeef62d..cec4fe502c 100644 --- a/Mage.Sets/src/mage/cards/j/JaceArcaneStrategist.java +++ b/Mage.Sets/src/mage/cards/j/JaceArcaneStrategist.java @@ -1,18 +1,20 @@ package mage.cards.j; +import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.common.DrawSecondCardTriggeredAbility; import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.combat.CantBeBlockedAllEffect; import mage.abilities.effects.common.counter.AddCountersTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.*; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.constants.SuperType; import mage.counters.CounterType; import mage.filter.StaticFilters; -import mage.game.Game; -import mage.game.events.GameEvent; import mage.target.common.TargetControlledCreaturePermanent; import java.util.UUID; @@ -30,7 +32,11 @@ public final class JaceArcaneStrategist extends CardImpl { this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(4)); // Whenever you draw your second card each turn, put a +1/+1 counter on target creature you control. - this.addAbility(new JaceArcaneStrategistTriggeredAbility()); + Ability ability = new DrawSecondCardTriggeredAbility( + new AddCountersTargetEffect(CounterType.P1P1.createInstance()), false + ); + ability.addTarget(new TargetControlledCreaturePermanent()); + this.addAbility(ability); // +1: Draw a card. this.addAbility(new LoyaltyAbility(new DrawCardSourceControllerEffect(1), 1)); @@ -50,59 +56,3 @@ public final class JaceArcaneStrategist extends CardImpl { return new JaceArcaneStrategist(this); } } - -class JaceArcaneStrategistTriggeredAbility extends TriggeredAbilityImpl { - - private boolean triggeredOnce = false; - private boolean triggeredTwice = false; - - JaceArcaneStrategistTriggeredAbility() { - super(Zone.BATTLEFIELD, new AddCountersTargetEffect(CounterType.P1P1.createInstance()), false); - this.addTarget(new TargetControlledCreaturePermanent()); - } - - private JaceArcaneStrategistTriggeredAbility(final JaceArcaneStrategistTriggeredAbility ability) { - super(ability); - this.triggeredOnce = ability.triggeredOnce; - this.triggeredTwice = ability.triggeredTwice; - } - - @Override - public boolean checkEventType(GameEvent event, Game game) { - return event.getType() == GameEvent.EventType.DREW_CARD - || event.getType() == GameEvent.EventType.END_PHASE_POST; - } - - @Override - public boolean checkTrigger(GameEvent event, Game game) { - if (event.getType() == GameEvent.EventType.END_PHASE_POST) { - triggeredOnce = triggeredTwice = false; - return false; - } - if (event.getType() == GameEvent.EventType.DREW_CARD - && event.getPlayerId().equals(controllerId)) { - if (triggeredOnce) { - if (triggeredTwice) { - return false; - } else { - triggeredTwice = true; - return true; - } - } else { - triggeredOnce = true; - return false; - } - } - return false; - } - - @Override - public String getRule() { - return "Whenever you draw your second card each turn, put a +1/+1 counter on target creature you control."; - } - - @Override - public JaceArcaneStrategistTriggeredAbility copy() { - return new JaceArcaneStrategistTriggeredAbility(this); - } -} diff --git a/Mage.Sets/src/mage/cards/j/JaceCunningCastaway.java b/Mage.Sets/src/mage/cards/j/JaceCunningCastaway.java index f4bd134f43..38841f6747 100644 --- a/Mage.Sets/src/mage/cards/j/JaceCunningCastaway.java +++ b/Mage.Sets/src/mage/cards/j/JaceCunningCastaway.java @@ -1,24 +1,17 @@ package mage.cards.j; -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.DelayedTriggeredAbility; import mage.abilities.LoyaltyAbility; import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.CreateTokenCopyTargetEffect; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.DrawDiscardControllerEffect; -import mage.abilities.effects.common.CreateTokenCopyTargetEffect; 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.SuperType; +import mage.constants.*; import mage.game.Game; import mage.game.events.DamagedPlayerEvent; import mage.game.events.GameEvent; @@ -26,8 +19,11 @@ import mage.game.permanent.Permanent; import mage.game.permanent.token.JaceCunningCastawayIllusionToken; import mage.target.targetpointer.FixedTarget; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + /** - * * @author TheElk801 */ public final class JaceCunningCastaway extends CardImpl { @@ -50,7 +46,7 @@ public final class JaceCunningCastaway extends CardImpl { this.addAbility(new LoyaltyAbility(new JaceCunningCastawayCopyEffect(), -5)); } - public JaceCunningCastaway(final JaceCunningCastaway card) { + private JaceCunningCastaway(final JaceCunningCastaway card) { super(card); } @@ -62,12 +58,12 @@ public final class JaceCunningCastaway extends CardImpl { class JaceCunningCastawayEffect1 extends OneShotEffect { - public JaceCunningCastawayEffect1() { + JaceCunningCastawayEffect1() { super(Outcome.DrawCard); this.staticText = "Whenever one or more creatures you control deal combat damage to a player this turn, draw a card, then discard a card"; } - public JaceCunningCastawayEffect1(final JaceCunningCastawayEffect1 effect) { + private JaceCunningCastawayEffect1(final JaceCunningCastawayEffect1 effect) { super(effect); } @@ -86,13 +82,13 @@ class JaceCunningCastawayEffect1 extends OneShotEffect { class JaceCunningCastawayDamageTriggeredAbility extends DelayedTriggeredAbility { - List damagedPlayerIds = new ArrayList<>(); + private final List damagedPlayerIds = new ArrayList<>(); - public JaceCunningCastawayDamageTriggeredAbility() { + JaceCunningCastawayDamageTriggeredAbility() { super(new DrawDiscardControllerEffect(1, 1), Duration.EndOfTurn, false); } - public JaceCunningCastawayDamageTriggeredAbility(final JaceCunningCastawayDamageTriggeredAbility ability) { + private JaceCunningCastawayDamageTriggeredAbility(final JaceCunningCastawayDamageTriggeredAbility ability) { super(ability); } @@ -104,7 +100,7 @@ class JaceCunningCastawayDamageTriggeredAbility extends DelayedTriggeredAbility @Override public boolean checkEventType(GameEvent event, Game game) { return event.getType() == GameEvent.EventType.DAMAGED_PLAYER - || event.getType() == GameEvent.EventType.END_COMBAT_STEP_POST; + || event.getType() == GameEvent.EventType.COMBAT_DAMAGE_STEP_POST; } @Override @@ -119,7 +115,7 @@ class JaceCunningCastawayDamageTriggeredAbility extends DelayedTriggeredAbility } } } - if (event.getType() == GameEvent.EventType.END_COMBAT_STEP_POST) { + if (event.getType() == GameEvent.EventType.COMBAT_DAMAGE_STEP_POST) { damagedPlayerIds.clear(); } return false; @@ -138,7 +134,7 @@ class JaceCunningCastawayCopyEffect extends OneShotEffect { this.staticText = "Create two tokens that are copies of {this}, except they're not legendary"; } - JaceCunningCastawayCopyEffect(final JaceCunningCastawayCopyEffect effect) { + private JaceCunningCastawayCopyEffect(final JaceCunningCastawayCopyEffect effect) { super(effect); } @@ -150,12 +146,12 @@ class JaceCunningCastawayCopyEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Permanent permanent = game.getPermanentOrLKIBattlefield(source.getSourceId()); - if (permanent != null) { - CreateTokenCopyTargetEffect effect = new CreateTokenCopyTargetEffect(source.getControllerId(), null, false, 2); - effect.setTargetPointer(new FixedTarget(source.getSourceId(), game)); - effect.setIsntLegendary(true); - return effect.apply(game, source); + if (permanent == null) { + return false; } - return false; + CreateTokenCopyTargetEffect effect = new CreateTokenCopyTargetEffect(source.getControllerId(), null, false, 2); + effect.setTargetPointer(new FixedTarget(source.getSourceId(), game)); + effect.setIsntLegendary(true); + return effect.apply(game, source); } } diff --git a/Mage.Sets/src/mage/cards/j/Joust.java b/Mage.Sets/src/mage/cards/j/Joust.java new file mode 100644 index 0000000000..c6ccef240f --- /dev/null +++ b/Mage.Sets/src/mage/cards/j/Joust.java @@ -0,0 +1,88 @@ +package mage.cards.j; + +import mage.abilities.Ability; +import mage.abilities.effects.ContinuousEffect; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.continuous.BoostTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.permanent.ControllerPredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.target.TargetPermanent; +import mage.target.common.TargetControlledCreaturePermanent; +import mage.target.targetpointer.FixedTarget; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class Joust extends CardImpl { + + private static final FilterPermanent filter + = new FilterCreaturePermanent("creature you don't control"); + + static { + filter.add(new ControllerPredicate(TargetController.NOT_YOU)); + } + + public Joust(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{1}{R}"); + + // Choose target creature you control and target creature you don't control. The creature you control gets +2/+1 until end of turn if it's a Knight. Then those creatures fight each other. + this.getSpellAbility().addEffect(new JoustEffect()); + this.getSpellAbility().addTarget(new TargetControlledCreaturePermanent()); + this.getSpellAbility().addTarget(new TargetPermanent(filter)); + } + + private Joust(final Joust card) { + super(card); + } + + @Override + public Joust copy() { + return new Joust(this); + } +} + +class JoustEffect extends OneShotEffect { + + JoustEffect() { + super(Outcome.Benefit); + staticText = "Choose target creature you control and target creature you don't control. " + + "The creature you control gets +2/+1 until end of turn if it's a Knight. " + + "Then those creatures fight each other."; + } + + private JoustEffect(final JoustEffect effect) { + super(effect); + } + + @Override + public JoustEffect copy() { + return new JoustEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent creature1 = game.getPermanent(source.getTargets().get(0).getFirstTarget()); + Permanent creature2 = game.getPermanent(source.getTargets().get(1).getFirstTarget()); + if (creature1 == null) { + return false; + } + if (creature1.hasSubtype(SubType.KNIGHT, game)) { + ContinuousEffect effect = new BoostTargetEffect(2, 1, Duration.EndOfTurn); + effect.setTargetPointer(new FixedTarget(creature1.getId(), game)); + game.addEffect(effect, source); + } + if (creature2 == null) { + return true; + } + game.applyEffects(); + return creature1.fight(creature2, source, game); + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/j/JoustingDummy.java b/Mage.Sets/src/mage/cards/j/JoustingDummy.java new file mode 100644 index 0000000000..a6a4d73cdc --- /dev/null +++ b/Mage.Sets/src/mage/cards/j/JoustingDummy.java @@ -0,0 +1,42 @@ +package mage.cards.j; + +import mage.MageInt; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.effects.common.continuous.BoostSourceEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class JoustingDummy extends CardImpl { + + public JoustingDummy(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{2}"); + + this.subtype.add(SubType.SCARECROW); + this.subtype.add(SubType.KNIGHT); + this.power = new MageInt(2); + this.toughness = new MageInt(1); + + // {3}: Jousting Dummy gets +1/+0 until end of turn. + this.addAbility(new SimpleActivatedAbility( + new BoostSourceEffect(1, 0, Duration.EndOfTurn), new GenericManaCost(3) + )); + } + + private JoustingDummy(final JoustingDummy card) { + super(card); + } + + @Override + public JoustingDummy copy() { + return new JoustingDummy(this); + } +} diff --git a/Mage.Sets/src/mage/cards/k/KazuulTyrantOfTheCliffs.java b/Mage.Sets/src/mage/cards/k/KazuulTyrantOfTheCliffs.java index 370f5d4eb7..c5061f7826 100644 --- a/Mage.Sets/src/mage/cards/k/KazuulTyrantOfTheCliffs.java +++ b/Mage.Sets/src/mage/cards/k/KazuulTyrantOfTheCliffs.java @@ -1,8 +1,5 @@ - package mage.cards.k; -import java.util.Objects; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.TriggeredAbilityImpl; @@ -11,21 +8,17 @@ import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.effects.OneShotEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; -import mage.constants.Outcome; -import mage.constants.SuperType; -import mage.constants.Zone; +import mage.constants.*; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.events.GameEvent.EventType; -import mage.game.permanent.Permanent; import mage.game.permanent.token.OgreToken; import mage.players.Player; import mage.target.targetpointer.FixedTarget; +import java.util.UUID; + /** - * * @author jeffwadsworth */ public final class KazuulTyrantOfTheCliffs extends CardImpl { @@ -55,11 +48,11 @@ public final class KazuulTyrantOfTheCliffs extends CardImpl { class KazuulTyrantOfTheCliffsTriggeredAbility extends TriggeredAbilityImpl { - public KazuulTyrantOfTheCliffsTriggeredAbility() { + KazuulTyrantOfTheCliffsTriggeredAbility() { super(Zone.BATTLEFIELD, new KazuulTyrantOfTheCliffsEffect(new GenericManaCost(3))); } - public KazuulTyrantOfTheCliffsTriggeredAbility(final KazuulTyrantOfTheCliffsTriggeredAbility ability) { + private KazuulTyrantOfTheCliffsTriggeredAbility(final KazuulTyrantOfTheCliffsTriggeredAbility ability) { super(ability); } @@ -75,19 +68,17 @@ class KazuulTyrantOfTheCliffsTriggeredAbility extends TriggeredAbilityImpl { @Override public boolean checkTrigger(GameEvent event, Game game) { - Permanent attacker = game.getPermanent(event.getSourceId()); - Player defender = game.getPlayer(event.getTargetId()); - Player you = game.getPlayer(controllerId); - if (!Objects.equals(attacker.getControllerId(), you.getId()) && Objects.equals(defender, you)) { - this.getEffects().get(0).setTargetPointer(new FixedTarget(attacker.getControllerId())); - return true; + if (!getControllerId().equals(game.getCombat().getDefendingPlayerId(event.getSourceId(), game))) { + return false; } - return false; + this.getEffects().get(0).setTargetPointer(new FixedTarget(game.getControllerId(event.getSourceId()))); + return true; } @Override public String getRule() { - return "Whenever a creature an opponent controls attacks, if you're the defending player, create a 3/3 red Ogre creature token unless that creature's controller pays {3}"; + return "Whenever a creature an opponent controls attacks, if you're the defending player, " + + "create a 3/3 red Ogre creature token unless that creature's controller pays {3}"; } } @@ -96,12 +87,12 @@ class KazuulTyrantOfTheCliffsEffect extends OneShotEffect { protected Cost cost; private static OgreToken token = new OgreToken(); - public KazuulTyrantOfTheCliffsEffect(Cost cost) { + KazuulTyrantOfTheCliffsEffect(Cost cost) { super(Outcome.PutCreatureInPlay); this.cost = cost; } - public KazuulTyrantOfTheCliffsEffect(KazuulTyrantOfTheCliffsEffect effect) { + private KazuulTyrantOfTheCliffsEffect(KazuulTyrantOfTheCliffsEffect effect) { super(effect); this.cost = effect.cost.copy(); } @@ -109,13 +100,14 @@ class KazuulTyrantOfTheCliffsEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player payee = game.getPlayer(targetPointer.getFirst(game, source)); - if (payee != null) { - cost.clearPaid(); - if (!cost.pay(source, game, source.getSourceId(), payee.getId(), false, null)) { - return token.putOntoBattlefield(1, game, source.getSourceId(), source.getControllerId()); - } + if (payee == null) { + return false; } - return false; + cost.clearPaid(); + if (cost.pay(source, game, source.getSourceId(), payee.getId(), false, null)) { + return false; + } + return token.putOntoBattlefield(1, game, source.getSourceId(), source.getControllerId()); } @Override diff --git a/Mage.Sets/src/mage/cards/k/KeeperOfFables.java b/Mage.Sets/src/mage/cards/k/KeeperOfFables.java index ff9db9fd6e..e5e07bdb11 100644 --- a/Mage.Sets/src/mage/cards/k/KeeperOfFables.java +++ b/Mage.Sets/src/mage/cards/k/KeeperOfFables.java @@ -63,7 +63,7 @@ class KeeperOfFablesTriggeredAbility extends TriggeredAbilityImpl { @Override public boolean checkEventType(GameEvent event, Game game) { return event.getType() == GameEvent.EventType.DAMAGED_PLAYER - || event.getType() == GameEvent.EventType.END_COMBAT_STEP_POST; + || event.getType() == GameEvent.EventType.COMBAT_DAMAGE_STEP_POST; } @Override @@ -80,7 +80,7 @@ class KeeperOfFablesTriggeredAbility extends TriggeredAbilityImpl { } } } - if (event.getType() == GameEvent.EventType.END_COMBAT_STEP_POST) { + if (event.getType() == GameEvent.EventType.COMBAT_DAMAGE_STEP_POST) { damagedPlayerIds.clear(); } return false; diff --git a/Mage.Sets/src/mage/cards/k/KenrithTheReturnedKing.java b/Mage.Sets/src/mage/cards/k/KenrithTheReturnedKing.java new file mode 100644 index 0000000000..c1b780cf35 --- /dev/null +++ b/Mage.Sets/src/mage/cards/k/KenrithTheReturnedKing.java @@ -0,0 +1,114 @@ +package mage.cards.k; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.DrawCardTargetEffect; +import mage.abilities.effects.common.GainLifeTargetEffect; +import mage.abilities.effects.common.continuous.GainAbilityAllEffect; +import mage.abilities.effects.common.counter.AddCountersTargetEffect; +import mage.abilities.keyword.HasteAbility; +import mage.abilities.keyword.TrampleAbility; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.counters.CounterType; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.players.Player; +import mage.target.TargetPlayer; +import mage.target.common.TargetCardInGraveyard; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class KenrithTheReturnedKing extends CardImpl { + + public KenrithTheReturnedKing(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{W}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.NOBLE); + this.power = new MageInt(5); + this.toughness = new MageInt(5); + + // {R}: All creatures gain trample and haste until end of turn. + Ability ability = new SimpleActivatedAbility(new GainAbilityAllEffect( + TrampleAbility.getInstance(), Duration.EndOfTurn, + StaticFilters.FILTER_PERMANENT_CREATURE + ).setText("all creatures gain trample"), new ManaCostsImpl("{R}")); + ability.addEffect(new GainAbilityAllEffect( + HasteAbility.getInstance(), Duration.EndOfTurn, + StaticFilters.FILTER_PERMANENT_CREATURE + ).setText("and haste until end of turn")); + this.addAbility(ability); + + // {1}{G}: Put a +1/+1 counter on target creature. + ability = new SimpleActivatedAbility( + new AddCountersTargetEffect(CounterType.P1P1.createInstance()), new ManaCostsImpl("{1}{G}") + ); + ability.addTarget(new TargetCreaturePermanent()); + this.addAbility(ability); + + // {2}{W}: Target player gains 5 life. + ability = new SimpleActivatedAbility(new GainLifeTargetEffect(5), new ManaCostsImpl("{2}{W}")); + ability.addTarget(new TargetPlayer()); + this.addAbility(ability); + + // {3}{U}: Target player draws a card. + ability = new SimpleActivatedAbility(new DrawCardTargetEffect(1), new ManaCostsImpl("{3}{U}")); + ability.addTarget(new TargetPlayer()); + this.addAbility(ability); + + // {4}{B}: Put target creature card from a graveyard onto the battlefield under its owner's control. + ability = new SimpleActivatedAbility(new KenrithTheReturnedKingEffect(), new ManaCostsImpl("{4}{B}")); + ability.addTarget(new TargetCardInGraveyard(StaticFilters.FILTER_CARD_CREATURE)); + this.addAbility(ability); + } + + private KenrithTheReturnedKing(final KenrithTheReturnedKing card) { + super(card); + } + + @Override + public KenrithTheReturnedKing copy() { + return new KenrithTheReturnedKing(this); + } +} + +class KenrithTheReturnedKingEffect extends OneShotEffect { + + KenrithTheReturnedKingEffect() { + super(Outcome.Benefit); + staticText = "put target creature card from a graveyard onto the battlefield under its owner's control"; + } + + private KenrithTheReturnedKingEffect(final KenrithTheReturnedKingEffect effect) { + super(effect); + } + + @Override + public KenrithTheReturnedKingEffect copy() { + return new KenrithTheReturnedKingEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Card card = game.getCard(source.getFirstTarget()); + if (card == null) { + return false; + } + Player player = game.getPlayer(card.getOwnerId()); + if (player == null) { + return false; + } + return player.moveCards(card, Zone.BATTLEFIELD, source, game); + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/k/KenrithsTransformation.java b/Mage.Sets/src/mage/cards/k/KenrithsTransformation.java new file mode 100644 index 0000000000..800bc419d5 --- /dev/null +++ b/Mage.Sets/src/mage/cards/k/KenrithsTransformation.java @@ -0,0 +1,58 @@ +package mage.cards.k; + +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.AttachEffect; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.continuous.BecomesCreatureAttachedEffect; +import mage.abilities.keyword.EnchantAbility; +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.game.permanent.token.custom.CreatureToken; +import mage.target.TargetPermanent; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class KenrithsTransformation extends CardImpl { + + public KenrithsTransformation(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{G}"); + + this.subtype.add(SubType.AURA); + + // Enchant creature + TargetPermanent auraTarget = new TargetCreaturePermanent(); + this.getSpellAbility().addTarget(auraTarget); + this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); + Ability ability = new EnchantAbility(auraTarget.getTargetName()); + this.addAbility(ability); + + // When Kenrith's Transformation enters the battlefield, draw a card. + this.addAbility(new EntersBattlefieldTriggeredAbility(new DrawCardSourceControllerEffect(1))); + + // Enchanted creature loses all abilities and is a green Elk creature with base power and toughness 3/3. + this.addAbility(new SimpleStaticAbility(new BecomesCreatureAttachedEffect( + new CreatureToken(3, 3, "", SubType.ELK).withColor("G"), + "Enchanted creature loses all abilities and is a green Elk creature with base power and toughness 3/3", + Duration.WhileOnBattlefield, BecomesCreatureAttachedEffect.LoseType.ALL + ))); + } + + private KenrithsTransformation(final KenrithsTransformation card) { + super(card); + } + + @Override + public KenrithsTransformation copy() { + return new KenrithsTransformation(this); + } +} diff --git a/Mage.Sets/src/mage/cards/k/KingMacarTheGoldCursed.java b/Mage.Sets/src/mage/cards/k/KingMacarTheGoldCursed.java index f943bf421d..c9ce38abf2 100644 --- a/Mage.Sets/src/mage/cards/k/KingMacarTheGoldCursed.java +++ b/Mage.Sets/src/mage/cards/k/KingMacarTheGoldCursed.java @@ -1,7 +1,6 @@ package mage.cards.k; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.effects.Effect; @@ -16,8 +15,9 @@ import mage.constants.SuperType; import mage.game.permanent.token.GoldToken; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class KingMacarTheGoldCursed extends CardImpl { @@ -25,7 +25,7 @@ public final class KingMacarTheGoldCursed extends CardImpl { public KingMacarTheGoldCursed(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}{B}"); addSuperType(SuperType.LEGENDARY); - this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.HUMAN, SubType.NOBLE); this.power = new MageInt(2); this.toughness = new MageInt(3); diff --git a/Mage.Sets/src/mage/cards/k/KingSuleiman.java b/Mage.Sets/src/mage/cards/k/KingSuleiman.java index 3af926e5db..b3ea6d5648 100644 --- a/Mage.Sets/src/mage/cards/k/KingSuleiman.java +++ b/Mage.Sets/src/mage/cards/k/KingSuleiman.java @@ -1,7 +1,5 @@ - package mage.cards.k; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; @@ -17,8 +15,9 @@ import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.SubtypePredicate; import mage.target.TargetPermanent; +import java.util.UUID; + /** - * * @author KholdFuzion */ public final class KingSuleiman extends CardImpl { @@ -26,14 +25,15 @@ public final class KingSuleiman extends CardImpl { private static final FilterPermanent filter = new FilterPermanent("Djinn or Efreet"); static { - filter.add( Predicates.or( + filter.add(Predicates.or( new SubtypePredicate(SubType.DJINN), - new SubtypePredicate(SubType.EFREET))); + new SubtypePredicate(SubType.EFREET) + )); } public KingSuleiman(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{W}"); - this.subtype.add(SubType.HUMAN); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W}"); + this.subtype.add(SubType.HUMAN, SubType.NOBLE); this.power = new MageInt(1); this.toughness = new MageInt(1); diff --git a/Mage.Sets/src/mage/cards/k/KnightOfTheKeep.java b/Mage.Sets/src/mage/cards/k/KnightOfTheKeep.java new file mode 100644 index 0000000000..4a44649a46 --- /dev/null +++ b/Mage.Sets/src/mage/cards/k/KnightOfTheKeep.java @@ -0,0 +1,33 @@ +package mage.cards.k; + +import mage.MageInt; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class KnightOfTheKeep extends CardImpl { + + public KnightOfTheKeep(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{W}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.KNIGHT); + this.power = new MageInt(3); + this.toughness = new MageInt(2); + } + + private KnightOfTheKeep(final KnightOfTheKeep card) { + super(card); + } + + @Override + public KnightOfTheKeep copy() { + return new KnightOfTheKeep(this); + } +} diff --git a/Mage.Sets/src/mage/cards/k/KumenasSpeaker.java b/Mage.Sets/src/mage/cards/k/KumenasSpeaker.java index 58cc2dd777..9626941ed4 100644 --- a/Mage.Sets/src/mage/cards/k/KumenasSpeaker.java +++ b/Mage.Sets/src/mage/cards/k/KumenasSpeaker.java @@ -1,22 +1,21 @@ - package mage.cards.k; -import java.util.UUID; import mage.MageInt; +import mage.MageObject; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.common.continuous.BoostSourceWhileControlsEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Zone; import mage.filter.FilterPermanent; -import mage.filter.predicate.Predicates; -import mage.filter.predicate.mageobject.SubtypePredicate; -import mage.filter.predicate.permanent.AnotherPredicate; +import mage.filter.predicate.ObjectSourcePlayer; +import mage.filter.predicate.ObjectSourcePlayerPredicate; +import mage.game.Game; + +import java.util.UUID; /** - * * @author TheElk801 */ public final class KumenasSpeaker extends CardImpl { @@ -24,10 +23,7 @@ public final class KumenasSpeaker extends CardImpl { private static final FilterPermanent filter = new FilterPermanent("another Merfolk or an Island"); static { - filter.add(AnotherPredicate.instance); - filter.add(Predicates.or( - new SubtypePredicate(SubType.ISLAND), - new SubtypePredicate(SubType.MERFOLK))); + filter.add(KumenasSpeakerPredicate.instance); } public KumenasSpeaker(UUID ownerId, CardSetInfo setInfo) { @@ -39,10 +35,10 @@ public final class KumenasSpeaker extends CardImpl { this.toughness = new MageInt(1); // Kumena's Omenspeaker gets +1/+1 as long as you control another Merfolk or Island. - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostSourceWhileControlsEffect(filter, 1, 1))); + this.addAbility(new SimpleStaticAbility(new BoostSourceWhileControlsEffect(filter, 1, 1))); } - public KumenasSpeaker(final KumenasSpeaker card) { + private KumenasSpeaker(final KumenasSpeaker card) { super(card); } @@ -51,3 +47,17 @@ public final class KumenasSpeaker extends CardImpl { return new KumenasSpeaker(this); } } + +enum KumenasSpeakerPredicate implements ObjectSourcePlayerPredicate> { + instance; + + @Override + public boolean apply(ObjectSourcePlayer input, Game game) { + MageObject obj = input.getObject(); + if (obj.getId().equals(input.getSourceId())) { + return obj.hasSubtype(SubType.ISLAND, game); + } + return obj.hasSubtype(SubType.ISLAND, game) + || obj.hasSubtype(SubType.MERFOLK, game); + } +} diff --git a/Mage.Sets/src/mage/cards/l/LashOfThorns.java b/Mage.Sets/src/mage/cards/l/LashOfThorns.java new file mode 100644 index 0000000000..ecf2961622 --- /dev/null +++ b/Mage.Sets/src/mage/cards/l/LashOfThorns.java @@ -0,0 +1,40 @@ +package mage.cards.l; + +import mage.abilities.effects.common.continuous.BoostTargetEffect; +import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; +import mage.abilities.keyword.DeathtouchAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class LashOfThorns extends CardImpl { + + public LashOfThorns(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{B}"); + + // Target creature gets +2/+1 and gains deathtouch until end of turn. + this.getSpellAbility().addEffect(new BoostTargetEffect( + 2, 1, Duration.EndOfTurn + ).setText("target creature gets +2/+1")); + this.getSpellAbility().addEffect(new GainAbilityTargetEffect( + DeathtouchAbility.getInstance(), Duration.EndOfTurn + ).setText("and gains deathtouch until end of turn")); + this.getSpellAbility().addTarget(new TargetCreaturePermanent()); + } + + private LashOfThorns(final LashOfThorns card) { + super(card); + } + + @Override + public LashOfThorns copy() { + return new LashOfThorns(this); + } +} diff --git a/Mage.Sets/src/mage/cards/l/LindenTheSteadfastQueen.java b/Mage.Sets/src/mage/cards/l/LindenTheSteadfastQueen.java new file mode 100644 index 0000000000..f016f227fa --- /dev/null +++ b/Mage.Sets/src/mage/cards/l/LindenTheSteadfastQueen.java @@ -0,0 +1,54 @@ +package mage.cards.l; + +import mage.MageInt; +import mage.ObjectColor; +import mage.abilities.common.AttacksCreatureYouControlTriggeredAbility; +import mage.abilities.effects.common.GainLifeEffect; +import mage.abilities.keyword.VigilanceAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.predicate.mageobject.ColorPredicate; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class LindenTheSteadfastQueen extends CardImpl { + + private static final FilterControlledCreaturePermanent filter + = new FilterControlledCreaturePermanent("white creature you control"); + + static { + filter.add(new ColorPredicate(ObjectColor.WHITE)); + } + + public LindenTheSteadfastQueen(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{W}{W}{W}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.NOBLE); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // Vigilance + this.addAbility(VigilanceAbility.getInstance()); + + // Whenever a white creature you control attacks, you gain 1 life. + this.addAbility(new AttacksCreatureYouControlTriggeredAbility(new GainLifeEffect(1), false, filter)); + } + + private LindenTheSteadfastQueen(final LindenTheSteadfastQueen card) { + super(card); + } + + @Override + public LindenTheSteadfastQueen copy() { + return new LindenTheSteadfastQueen(this); + } +} diff --git a/Mage.Sets/src/mage/cards/l/LlawanCephalidEmpress.java b/Mage.Sets/src/mage/cards/l/LlawanCephalidEmpress.java index ed0cb60905..9821dd9e9c 100644 --- a/Mage.Sets/src/mage/cards/l/LlawanCephalidEmpress.java +++ b/Mage.Sets/src/mage/cards/l/LlawanCephalidEmpress.java @@ -1,7 +1,6 @@ package mage.cards.l; -import java.util.UUID; import mage.MageInt; import mage.MageObject; import mage.ObjectColor; @@ -23,8 +22,9 @@ import mage.game.Game; import mage.game.events.GameEvent; import mage.players.Player; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class LlawanCephalidEmpress extends CardImpl { @@ -38,9 +38,9 @@ public final class LlawanCephalidEmpress extends CardImpl { } public LlawanCephalidEmpress(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{U}"); addSuperType(SuperType.LEGENDARY); - this.subtype.add(SubType.CEPHALID); + this.subtype.add(SubType.CEPHALID, SubType.NOBLE); this.power = new MageInt(2); this.toughness = new MageInt(3); @@ -90,7 +90,7 @@ class LlawanCephalidRuleModifyingEffect extends ContinuousRuleModifyingEffectImp public boolean apply(Game game, Ability source) { return true; } - + @Override public String getInfoMessage(Ability source, GameEvent event, Game game) { MageObject mageObject = game.getObject(source.getSourceId()); @@ -99,12 +99,12 @@ class LlawanCephalidRuleModifyingEffect extends ContinuousRuleModifyingEffectImp } return null; } - + @Override public boolean checksEventType(GameEvent event, Game game) { return event.getType() == GameEvent.EventType.CAST_SPELL; } - + @Override public boolean applies(GameEvent event, Ability source, Game game) { Player controller = game.getPlayer(source.getControllerId()); diff --git a/Mage.Sets/src/mage/cards/l/LochDragon.java b/Mage.Sets/src/mage/cards/l/LochDragon.java new file mode 100644 index 0000000000..aedf384cff --- /dev/null +++ b/Mage.Sets/src/mage/cards/l/LochDragon.java @@ -0,0 +1,45 @@ +package mage.cards.l; + +import mage.MageInt; +import mage.abilities.common.EntersBattlefieldOrAttacksSourceTriggeredAbility; +import mage.abilities.costs.common.DiscardCardCost; +import mage.abilities.effects.common.DoIfCostPaid; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class LochDragon extends CardImpl { + + public LochDragon(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{U/R}{U/R}{U/R}{U/R}"); + + this.subtype.add(SubType.DRAGON); + this.power = new MageInt(3); + this.toughness = new MageInt(2); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // Whenever Loch Dragon enters the battlefield or attacks, you may discard a card. If you do, draw a card. + this.addAbility(new EntersBattlefieldOrAttacksSourceTriggeredAbility( + new DoIfCostPaid(new DrawCardSourceControllerEffect(1), new DiscardCardCost()) + )); + } + + private LochDragon(final LochDragon card) { + super(card); + } + + @Override + public LochDragon copy() { + return new LochDragon(this); + } +} diff --git a/Mage.Sets/src/mage/cards/l/LochmereSerpent.java b/Mage.Sets/src/mage/cards/l/LochmereSerpent.java new file mode 100644 index 0000000000..80d89e826f --- /dev/null +++ b/Mage.Sets/src/mage/cards/l/LochmereSerpent.java @@ -0,0 +1,82 @@ +package mage.cards.l; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.ActivateAsSorceryActivatedAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.SacrificeTargetCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.ExileTargetEffect; +import mage.abilities.effects.common.GainLifeEffect; +import mage.abilities.effects.common.ReturnSourceFromGraveyardToHandEffect; +import mage.abilities.effects.common.combat.CantBeBlockedSourceEffect; +import mage.abilities.keyword.FlashAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.constants.Zone; +import mage.filter.StaticFilters; +import mage.filter.common.FilterControlledPermanent; +import mage.target.common.TargetCardInOpponentsGraveyard; +import mage.target.common.TargetControlledPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class LochmereSerpent extends CardImpl { + + private static final FilterControlledPermanent filter1 + = new FilterControlledPermanent(SubType.ISLAND, "an Island"); + private static final FilterControlledPermanent filter2 + = new FilterControlledPermanent(SubType.SWAMP, "a Swamp"); + + public LochmereSerpent(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{U}{B}"); + + this.subtype.add(SubType.SERPENT); + this.power = new MageInt(7); + this.toughness = new MageInt(7); + + // Flash + this.addAbility(FlashAbility.getInstance()); + + // {U}, Sacrifice an Island: Lochmere Serpent can't be blocked this turn. + Ability ability = new SimpleActivatedAbility( + new CantBeBlockedSourceEffect(Duration.EndOfTurn), new ManaCostsImpl("{U}") + ); + ability.addCost(new SacrificeTargetCost(new TargetControlledPermanent(filter1))); + this.addAbility(ability); + + // {B}, Sacrifice a Swamp: You gain 1 life and draw a card. + ability = new SimpleActivatedAbility(new GainLifeEffect(1), new ManaCostsImpl("{B}")); + ability.addEffect(new DrawCardSourceControllerEffect(1).concatBy("and")); + ability.addCost(new SacrificeTargetCost(new TargetControlledPermanent(filter2))); + this.addAbility(ability); + + // {U}{B}: Exile five target cards from an opponent's graveyard. Return Lochmere Serpent from your graveyard to your hand. Activate this ability only any time you could cast a sorcery. + ability = new ActivateAsSorceryActivatedAbility( + Zone.GRAVEYARD, + new ExileTargetEffect().setText("Exile five target cards from an opponent's graveyard."), + new ManaCostsImpl("{U}{B}") + ); + ability.addEffect(new ReturnSourceFromGraveyardToHandEffect()); + ability.addTarget(new TargetCardInOpponentsGraveyard( + 5, 5, StaticFilters.FILTER_CARD, true + )); + this.addAbility(ability); + } + + private LochmereSerpent(final LochmereSerpent card) { + super(card); + } + + @Override + public LochmereSerpent copy() { + return new LochmereSerpent(this); + } +} diff --git a/Mage.Sets/src/mage/cards/l/LocthwainGargoyle.java b/Mage.Sets/src/mage/cards/l/LocthwainGargoyle.java new file mode 100644 index 0000000000..3337259447 --- /dev/null +++ b/Mage.Sets/src/mage/cards/l/LocthwainGargoyle.java @@ -0,0 +1,48 @@ +package mage.cards.l; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.effects.common.continuous.BoostSourceEffect; +import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class LocthwainGargoyle extends CardImpl { + + public LocthwainGargoyle(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{1}"); + + this.subtype.add(SubType.GARGOYLE); + this.power = new MageInt(0); + this.toughness = new MageInt(3); + + // {4}: Locthwain Gargoyle gets +2/+0 and gains flying until end of turn. + Ability ability = new SimpleActivatedAbility(new BoostSourceEffect( + 2, 0, Duration.EndOfTurn).setText("{this} gets +2/+0" + ), new GenericManaCost(4)); + ability.addEffect(new GainAbilitySourceEffect( + FlyingAbility.getInstance(), Duration.EndOfTurn + ).setText("and gains flying until end of turn")); + this.addAbility(ability); + } + + private LocthwainGargoyle(final LocthwainGargoyle card) { + super(card); + } + + @Override + public LocthwainGargoyle copy() { + return new LocthwainGargoyle(this); + } +} diff --git a/Mage.Sets/src/mage/cards/l/LocthwainPaladin.java b/Mage.Sets/src/mage/cards/l/LocthwainPaladin.java new file mode 100644 index 0000000000..ab4ffa5d21 --- /dev/null +++ b/Mage.Sets/src/mage/cards/l/LocthwainPaladin.java @@ -0,0 +1,50 @@ +package mage.cards.l; + +import mage.MageInt; +import mage.abilities.common.EntersBattlefieldAbility; +import mage.abilities.condition.common.AdamantCondition; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.abilities.keyword.MenaceAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.counters.CounterType; +import mage.watchers.common.ManaSpentToCastWatcher; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class LocthwainPaladin extends CardImpl { + + public LocthwainPaladin(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{B}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.KNIGHT); + this.power = new MageInt(3); + this.toughness = new MageInt(2); + + // Menace + this.addAbility(new MenaceAbility()); + + // Adamant — If at least three black mana was spent to cast this spell, Locthwain Paladin enters the battlefield with a +1/+1 counter on it. + this.addAbility(new EntersBattlefieldAbility( + new AddCountersSourceEffect(CounterType.P1P1.createInstance()), + AdamantCondition.BLACK, "
Adamant — " + + "If at least three black mana was spent to cast this spell, " + + "{this} enters the battlefield with a +1/+1 counter on it.", "" + ), new ManaSpentToCastWatcher()); + } + + private LocthwainPaladin(final LocthwainPaladin card) { + super(card); + } + + @Override + public LocthwainPaladin copy() { + return new LocthwainPaladin(this); + } +} diff --git a/Mage.Sets/src/mage/cards/l/LonesomeUnicorn.java b/Mage.Sets/src/mage/cards/l/LonesomeUnicorn.java new file mode 100644 index 0000000000..ead17bfb3e --- /dev/null +++ b/Mage.Sets/src/mage/cards/l/LonesomeUnicorn.java @@ -0,0 +1,42 @@ +package mage.cards.l; + +import mage.MageInt; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.keyword.VigilanceAbility; +import mage.cards.AdventureCard; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.game.permanent.token.KnightToken; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class LonesomeUnicorn extends AdventureCard { + + public LonesomeUnicorn(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, new CardType[]{CardType.SORCERY}, "{4}{W}", "Rider in Need", "{2}{W}"); + + this.subtype.add(SubType.UNICORN); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // Vigilance + this.addAbility(VigilanceAbility.getInstance()); + + // Rider in Need + // Create a 2/2 white Knight creature token with vigilance. + this.getAdventureSpellAbility().addEffect(new CreateTokenEffect(new KnightToken())); + } + + private LonesomeUnicorn(final LonesomeUnicorn card) { + super(card); + } + + @Override + public LonesomeUnicorn copy() { + return new LonesomeUnicorn(this); + } +} diff --git a/Mage.Sets/src/mage/cards/l/LostLegion.java b/Mage.Sets/src/mage/cards/l/LostLegion.java new file mode 100644 index 0000000000..9c6ec9dacc --- /dev/null +++ b/Mage.Sets/src/mage/cards/l/LostLegion.java @@ -0,0 +1,38 @@ +package mage.cards.l; + +import mage.MageInt; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.keyword.ScryEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class LostLegion extends CardImpl { + + public LostLegion(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{B}{B}"); + + this.subtype.add(SubType.SPIRIT); + this.subtype.add(SubType.KNIGHT); + this.power = new MageInt(2); + this.toughness = new MageInt(3); + + // When Lost Legion enters the battlefield, scry 2. + this.addAbility(new EntersBattlefieldTriggeredAbility(new ScryEffect(2))); + } + + private LostLegion(final LostLegion card) { + super(card); + } + + @Override + public LostLegion copy() { + return new LostLegion(this); + } +} diff --git a/Mage.Sets/src/mage/cards/l/LuckyClover.java b/Mage.Sets/src/mage/cards/l/LuckyClover.java new file mode 100644 index 0000000000..08ef868750 --- /dev/null +++ b/Mage.Sets/src/mage/cards/l/LuckyClover.java @@ -0,0 +1,45 @@ +package mage.cards.l; + +import mage.abilities.common.SpellCastControllerTriggeredAbility; +import mage.abilities.effects.common.CopyTargetSpellEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.filter.FilterSpell; +import mage.filter.common.FilterInstantOrSorcerySpell; +import mage.filter.predicate.mageobject.SubtypePredicate; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class LuckyClover extends CardImpl { + + private static final FilterSpell filter + = new FilterInstantOrSorcerySpell("an Adventure instant or sorcery spell"); + + static { + filter.add(new SubtypePredicate(SubType.ADVENTURE)); + } + + public LuckyClover(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{2}"); + + // Whenever you cast an Adventure instant or sorcery spell, copy it. You may choose new targets for the copy. + this.addAbility(new SpellCastControllerTriggeredAbility( + new CopyTargetSpellEffect(true).withSpellName("it"), + filter, false, true + )); + } + + private LuckyClover(final LuckyClover card) { + super(card); + } + + @Override + public LuckyClover copy() { + return new LuckyClover(this); + } +} diff --git a/Mage.Sets/src/mage/cards/m/MadRatter.java b/Mage.Sets/src/mage/cards/m/MadRatter.java new file mode 100644 index 0000000000..aa38a13633 --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/MadRatter.java @@ -0,0 +1,38 @@ +package mage.cards.m; + +import mage.MageInt; +import mage.abilities.common.DrawSecondCardTriggeredAbility; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.game.permanent.token.RatToken; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class MadRatter extends CardImpl { + + public MadRatter(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{R}"); + + this.subtype.add(SubType.GOBLIN); + this.power = new MageInt(1); + this.toughness = new MageInt(2); + + // Whenever you draw your second card each turn, create two 1/1 black Rat creature tokens. + this.addAbility(new DrawSecondCardTriggeredAbility(new CreateTokenEffect(new RatToken(), 2), false)); + } + + private MadRatter(final MadRatter card) { + super(card); + } + + @Override + public MadRatter copy() { + return new MadRatter(this); + } +} diff --git a/Mage.Sets/src/mage/cards/m/MalevolentNoble.java b/Mage.Sets/src/mage/cards/m/MalevolentNoble.java new file mode 100644 index 0000000000..4c7f6ff3bf --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/MalevolentNoble.java @@ -0,0 +1,73 @@ +package mage.cards.m; + +import mage.MageInt; +import mage.MageObject; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.SacrificeTargetCost; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.counters.CounterType; +import mage.filter.common.FilterControlledPermanent; +import mage.filter.predicate.ObjectSourcePlayer; +import mage.filter.predicate.ObjectSourcePlayerPredicate; +import mage.game.Game; +import mage.target.common.TargetControlledPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class MalevolentNoble extends CardImpl { + + private static final FilterControlledPermanent filter + = new FilterControlledPermanent("an artifact or another creature"); + + static { + filter.add(MalevolentNoblePredicate.instance); + } + + public MalevolentNoble(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{B}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.NOBLE); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // {2}, Sacrifice an artifact or another creature: Put a +1/+1 counter on Malevolent Noble. + Ability ability = new SimpleActivatedAbility( + new AddCountersSourceEffect(CounterType.P1P1.createInstance()), new GenericManaCost(2) + ); + ability.addCost(new SacrificeTargetCost(new TargetControlledPermanent(filter))); + this.addAbility(ability); + } + + private MalevolentNoble(final MalevolentNoble card) { + super(card); + } + + @Override + public MalevolentNoble copy() { + return new MalevolentNoble(this); + } +} + +enum MalevolentNoblePredicate implements ObjectSourcePlayerPredicate> { + instance; + + @Override + public boolean apply(ObjectSourcePlayer input, Game game) { + MageObject obj = input.getObject(); + if (obj.getId().equals(input.getSourceId())) { + return obj.isArtifact(); + } + return obj.isArtifact() + || obj.isCreature(); + } +} diff --git a/Mage.Sets/src/mage/cards/m/MantleOfTides.java b/Mage.Sets/src/mage/cards/m/MantleOfTides.java new file mode 100644 index 0000000000..efde9dae20 --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/MantleOfTides.java @@ -0,0 +1,50 @@ +package mage.cards.m; + +import mage.abilities.Ability; +import mage.abilities.common.DrawSecondCardTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.AttachEffect; +import mage.abilities.effects.common.continuous.BoostEquippedEffect; +import mage.abilities.keyword.EquipAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.target.common.TargetControlledCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class MantleOfTides extends CardImpl { + + public MantleOfTides(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{U}"); + + this.subtype.add(SubType.EQUIPMENT); + + // Equipped creature gets +1/+2. + this.addAbility(new SimpleStaticAbility(new BoostEquippedEffect(1, 2))); + + // Whenever you draw your second card each turn, attach Mantle of Tides to target creature you control. + Ability ability = new DrawSecondCardTriggeredAbility(new AttachEffect( + Outcome.Benefit, "attach {this} to target creature you control" + ), false); + ability.addTarget(new TargetControlledCreaturePermanent()); + this.addAbility(ability); + + // Equip {3} + this.addAbility(new EquipAbility(3)); + } + + private MantleOfTides(final MantleOfTides card) { + super(card); + } + + @Override + public MantleOfTides copy() { + return new MantleOfTides(this); + } +} diff --git a/Mage.Sets/src/mage/cards/m/MaraleafRider.java b/Mage.Sets/src/mage/cards/m/MaraleafRider.java new file mode 100644 index 0000000000..25f1baba2b --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/MaraleafRider.java @@ -0,0 +1,49 @@ +package mage.cards.m; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.SacrificeTargetCost; +import mage.abilities.effects.common.combat.MustBeBlockedByTargetSourceEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.filter.common.FilterControlledPermanent; +import mage.target.common.TargetControlledPermanent; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class MaraleafRider extends CardImpl { + + private static final FilterControlledPermanent filter = new FilterControlledPermanent(SubType.FOOD, "a Food"); + + public MaraleafRider(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{G}"); + + this.subtype.add(SubType.ELF); + this.subtype.add(SubType.KNIGHT); + this.power = new MageInt(3); + this.toughness = new MageInt(1); + + // Sacrifice a Food: Target creature blocks Maraleaf Rider this turn if able. + Ability ability = new SimpleActivatedAbility( + new MustBeBlockedByTargetSourceEffect(), new SacrificeTargetCost(new TargetControlledPermanent(filter)) + ); + ability.addTarget(new TargetCreaturePermanent()); + this.addAbility(ability); + } + + private MaraleafRider(final MaraleafRider card) { + super(card); + } + + @Override + public MaraleafRider copy() { + return new MaraleafRider(this); + } +} diff --git a/Mage.Sets/src/mage/cards/m/MemoryTheft.java b/Mage.Sets/src/mage/cards/m/MemoryTheft.java new file mode 100644 index 0000000000..e302ecfeef --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/MemoryTheft.java @@ -0,0 +1,87 @@ +package mage.cards.m; + +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.discard.DiscardCardYouChooseTargetEffect; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.TargetController; +import mage.constants.Zone; +import mage.filter.FilterCard; +import mage.filter.StaticFilters; +import mage.filter.predicate.mageobject.AdventurePredicate; +import mage.filter.predicate.other.OwnerIdPredicate; +import mage.game.Game; +import mage.players.Player; +import mage.target.TargetCard; +import mage.target.common.TargetCardInExile; +import mage.target.common.TargetOpponent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class MemoryTheft extends CardImpl { + + public MemoryTheft(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{B}"); + + // Target opponent reveals their hand. You choose a nonland card from it. That player discards that card. You may put a card that has an Adventure that player owns from exile into that player's graveyard. + this.getSpellAbility().addEffect( + new DiscardCardYouChooseTargetEffect(StaticFilters.FILTER_CARD_NON_LAND, TargetController.ANY) + ); + this.getSpellAbility().addEffect(new MemoryTheftEffect()); + this.getSpellAbility().addTarget(new TargetOpponent()); + } + + private MemoryTheft(final MemoryTheft card) { + super(card); + } + + @Override + public MemoryTheft copy() { + return new MemoryTheft(this); + } +} + +class MemoryTheftEffect extends OneShotEffect { + + MemoryTheftEffect() { + super(Outcome.Benefit); + staticText = "Target opponent reveals their hand. You choose a nonland card from it. " + + "That player discards that card. You may put a card that has an Adventure " + + "that player owns from exile into that player's graveyard."; + } + + private MemoryTheftEffect(final MemoryTheftEffect effect) { + super(effect); + } + + @Override + public MemoryTheftEffect copy() { + return new MemoryTheftEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + Player player = game.getPlayer(source.getFirstTarget()); + if (controller == null || player == null) { + return false; + } + FilterCard filter = new FilterCard("card owned by " + player.getName() + " that has an Adventure"); + filter.add(AdventurePredicate.instance); + filter.add(new OwnerIdPredicate(player.getId())); + TargetCard target = new TargetCardInExile(0, 1, filter, null, true); + if (!target.canChoose(source.getSourceId(), source.getControllerId(), game) + || !controller.choose(outcome, target, source.getSourceId(), game)) { + return false; + } + Card card = game.getCard(target.getFirstTarget()); + return controller.moveCards(card, Zone.GRAVEYARD, source, game); + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/m/MerchantOfTheVale.java b/Mage.Sets/src/mage/cards/m/MerchantOfTheVale.java new file mode 100644 index 0000000000..f89f695ad7 --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/MerchantOfTheVale.java @@ -0,0 +1,52 @@ +package mage.cards.m; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.DiscardCardCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.DoIfCostPaid; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.cards.AdventureCard; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class MerchantOfTheVale extends AdventureCard { + + public MerchantOfTheVale(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, new CardType[]{CardType.INSTANT}, "{2}{R}", "Haggle", "{R}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.PEASANT); + this.power = new MageInt(2); + this.toughness = new MageInt(3); + + // {2}{R}, Discard a card: Draw a card. + Ability ability = new SimpleActivatedAbility( + new DrawCardSourceControllerEffect(1), new ManaCostsImpl("{2}{R}") + ); + ability.addCost(new DiscardCardCost()); + this.addAbility(ability); + + // Haggle + // You may discard a card. If you do, draw a card. + this.getAdventureSpellAbility().addEffect(new DoIfCostPaid( + new DrawCardSourceControllerEffect(1), new DiscardCardCost() + )); + } + + private MerchantOfTheVale(final MerchantOfTheVale card) { + super(card); + } + + @Override + public MerchantOfTheVale copy() { + return new MerchantOfTheVale(this); + } +} diff --git a/Mage.Sets/src/mage/cards/m/MerfolkSecretkeeper.java b/Mage.Sets/src/mage/cards/m/MerfolkSecretkeeper.java new file mode 100644 index 0000000000..fcc7b742a1 --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/MerfolkSecretkeeper.java @@ -0,0 +1,40 @@ +package mage.cards.m; + +import mage.MageInt; +import mage.abilities.effects.common.PutLibraryIntoGraveTargetEffect; +import mage.cards.AdventureCard; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.target.TargetPlayer; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class MerfolkSecretkeeper extends AdventureCard { + + public MerfolkSecretkeeper(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, new CardType[]{CardType.SORCERY}, "{U}", "Venture Deeper", "{U}"); + + this.subtype.add(SubType.MERFOLK); + this.subtype.add(SubType.WIZARD); + this.power = new MageInt(0); + this.toughness = new MageInt(4); + + // Venture Deeper + // Target player puts the top four cards of their library into their graveyard. + this.getAdventureSpellAbility().addEffect(new PutLibraryIntoGraveTargetEffect(4)); + this.getAdventureSpellAbility().addTarget(new TargetPlayer()); + } + + private MerfolkSecretkeeper(final MerfolkSecretkeeper card) { + super(card); + } + + @Override + public MerfolkSecretkeeper copy() { + return new MerfolkSecretkeeper(this); + } +} diff --git a/Mage.Sets/src/mage/cards/m/MerfolkSovereign.java b/Mage.Sets/src/mage/cards/m/MerfolkSovereign.java index f2637dd00d..c39b6fbaaf 100644 --- a/Mage.Sets/src/mage/cards/m/MerfolkSovereign.java +++ b/Mage.Sets/src/mage/cards/m/MerfolkSovereign.java @@ -1,8 +1,5 @@ - - package mage.cards.m; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; @@ -20,8 +17,9 @@ import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.SubtypePredicate; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author BetaSteward_at_googlemail.com */ public final class MerfolkSovereign extends CardImpl { @@ -35,8 +33,8 @@ public final class MerfolkSovereign extends CardImpl { } public MerfolkSovereign(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{U}{U}"); - this.subtype.add(SubType.MERFOLK); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{U}{U}"); + this.subtype.add(SubType.MERFOLK, SubType.NOBLE); this.power = new MageInt(2); this.toughness = new MageInt(2); diff --git a/Mage.Sets/src/mage/cards/m/Mirrormade.java b/Mage.Sets/src/mage/cards/m/Mirrormade.java new file mode 100644 index 0000000000..4a82c19e0d --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/Mirrormade.java @@ -0,0 +1,34 @@ +package mage.cards.m; + +import mage.abilities.common.EntersBattlefieldAbility; +import mage.abilities.effects.common.CopyPermanentEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.filter.StaticFilters; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class Mirrormade extends CardImpl { + + public Mirrormade(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{U}{U}"); + + // You may have Mirrormade enter the battlefield as a copy of any artifact or enchantment on the battlefield. + this.addAbility(new EntersBattlefieldAbility( + new CopyPermanentEffect(StaticFilters.FILTER_PERMANENT_ARTIFACT_OR_ENCHANTMENT), true + )); + } + + private Mirrormade(final Mirrormade card) { + super(card); + } + + @Override + public Mirrormade copy() { + return new Mirrormade(this); + } +} diff --git a/Mage.Sets/src/mage/cards/m/MistfordRiverTurtle.java b/Mage.Sets/src/mage/cards/m/MistfordRiverTurtle.java new file mode 100644 index 0000000000..3bfb928789 --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/MistfordRiverTurtle.java @@ -0,0 +1,58 @@ +package mage.cards.m; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.AttacksTriggeredAbility; +import mage.abilities.effects.common.combat.CantBeBlockedTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.SubtypePredicate; +import mage.filter.predicate.permanent.AnotherPredicate; +import mage.filter.predicate.permanent.AttackingPredicate; +import mage.target.TargetPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class MistfordRiverTurtle extends CardImpl { + + private static final FilterPermanent filter + = new FilterCreaturePermanent("another target attacking non-Human creature"); + + static { + filter.add(AnotherPredicate.instance); + filter.add(AttackingPredicate.instance); + filter.add(Predicates.not(new SubtypePredicate(SubType.HUMAN))); + } + + public MistfordRiverTurtle(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{U}"); + + this.subtype.add(SubType.TURTLE); + this.power = new MageInt(1); + this.toughness = new MageInt(5); + + // Whenever Mistford River Turtle attacks, another target attacking non-Human creature can't be blocked this turn. + Ability ability = new AttacksTriggeredAbility(new CantBeBlockedTargetEffect(Duration.EndOfTurn) + .setText("another target attacking non-Human creature can't be blocked this turn"), false); + ability.addTarget(new TargetPermanent(filter)); + this.addAbility(ability); + } + + private MistfordRiverTurtle(final MistfordRiverTurtle card) { + super(card); + } + + @Override + public MistfordRiverTurtle copy() { + return new MistfordRiverTurtle(this); + } +} diff --git a/Mage.Sets/src/mage/cards/m/Moonhold.java b/Mage.Sets/src/mage/cards/m/Moonhold.java index 97926e3e4c..df0c7252f2 100644 --- a/Mage.Sets/src/mage/cards/m/Moonhold.java +++ b/Mage.Sets/src/mage/cards/m/Moonhold.java @@ -34,7 +34,7 @@ public final class Moonhold extends CardImpl { // Target player can't play land cards this turn if {R} was spent to cast Moonhold and can't play creature cards this turn if {W} was spent to cast it. ContinuousRuleModifyingEffect effect = new MoonholdEffect(); ContinuousRuleModifyingEffect effect2 = new MoonholdEffect2(); - effect.setText("Target player can't play lands this turn if {R} was spent to cast {this}"); + effect.setText("Target player can't play lands this turn if {R} was spent to cast this spell"); effect2.setText("and can't cast creature spells this turn if {W} was spent to cast it."); this.getSpellAbility().addEffect(new ConditionalContinuousRuleModifyingEffect( effect, diff --git a/Mage.Sets/src/mage/cards/m/MoonlitScavengers.java b/Mage.Sets/src/mage/cards/m/MoonlitScavengers.java new file mode 100644 index 0000000000..e3a3872292 --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/MoonlitScavengers.java @@ -0,0 +1,61 @@ +package mage.cards.m; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.condition.Condition; +import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; +import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; +import mage.abilities.effects.common.ReturnToHandTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.TargetController; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterArtifactOrEnchantmentPermanent; +import mage.filter.predicate.permanent.ControllerPredicate; +import mage.target.common.TargetOpponentsCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class MoonlitScavengers extends CardImpl { + + private static final FilterPermanent filter = new FilterArtifactOrEnchantmentPermanent(); + + static { + filter.add(new ControllerPredicate(TargetController.YOU)); + } + + private static final Condition condition = new PermanentsOnTheBattlefieldCondition(filter); + + public MoonlitScavengers(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{5}{U}"); + + this.subtype.add(SubType.MERFOLK); + this.subtype.add(SubType.ROGUE); + this.power = new MageInt(4); + this.toughness = new MageInt(5); + + // When Moonlit Scavengers enters the battlefield, if you control an artifact or enchantment, return target creature an opponent controls to its owner's hand. + Ability ability = new ConditionalInterveningIfTriggeredAbility( + new EntersBattlefieldTriggeredAbility(new ReturnToHandTargetEffect()), condition, + "When {this} enters the battlefield, if you control an artifact or enchantment, " + + "return target creature an opponent controls to its owner's hand." + ); + ability.addTarget(new TargetOpponentsCreaturePermanent()); + this.addAbility(ability); + } + + private MoonlitScavengers(final MoonlitScavengers card) { + super(card); + } + + @Override + public MoonlitScavengers copy() { + return new MoonlitScavengers(this); + } +} diff --git a/Mage.Sets/src/mage/cards/m/MtendaLion.java b/Mage.Sets/src/mage/cards/m/MtendaLion.java new file mode 100644 index 0000000000..cdda060084 --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/MtendaLion.java @@ -0,0 +1,78 @@ +package mage.cards.m; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.AttacksTriggeredAbility; +import mage.abilities.costs.Cost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.PreventCombatDamageBySourceEffect; +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.game.Game; +import mage.players.Player; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class MtendaLion extends CardImpl { + + public MtendaLion(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{G}"); + + this.subtype.add(SubType.CAT); + this.power = new MageInt(2); + this.toughness = new MageInt(1); + + // Whenever Mtenda Lion attacks, defending player may pay {U}. If that player does, prevent all combat damage that would be dealt by Mtenda Lion this turn. + this.addAbility(new AttacksTriggeredAbility(new MtendaLionEffect(), false)); + } + + private MtendaLion(final MtendaLion card) { + super(card); + } + + @Override + public MtendaLion copy() { + return new MtendaLion(this); + } +} + +class MtendaLionEffect extends OneShotEffect { + + MtendaLionEffect() { + super(Outcome.Benefit); + staticText = "defending player may pay {U}. If that player does, " + + "prevent all combat damage that would be dealt by {this} this turn."; + } + + private MtendaLionEffect(final MtendaLionEffect effect) { + super(effect); + } + + @Override + public MtendaLionEffect copy() { + return new MtendaLionEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(game.getCombat().getDefendingPlayerId(source.getSourceId(), game)); + if (player == null) { + return false; + } + Cost cost = new ManaCostsImpl("{U}"); + if (!player.chooseUse(outcome, "Pay {U} to prevent damage?", source, game) + || !cost.pay(source, game, source.getSourceId(), player.getId(), false)) { + return false; + } + game.addEffect(new PreventCombatDamageBySourceEffect(Duration.EndOfTurn), source); + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/m/MurderousRider.java b/Mage.Sets/src/mage/cards/m/MurderousRider.java new file mode 100644 index 0000000000..24cf1b16f9 --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/MurderousRider.java @@ -0,0 +1,55 @@ +package mage.cards.m; + +import mage.MageInt; +import mage.abilities.common.DiesTriggeredAbility; +import mage.abilities.effects.common.DestroyTargetEffect; +import mage.abilities.effects.common.LoseLifeSourceControllerEffect; +import mage.abilities.effects.common.PutOnLibraryTargetEffect; +import mage.abilities.keyword.LifelinkAbility; +import mage.cards.AdventureCard; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.target.common.TargetCreatureOrPlaneswalker; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class MurderousRider extends AdventureCard { + + public MurderousRider(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, new CardType[]{CardType.INSTANT}, "{1}{B}{B}", "Swift End", "{1}{B}{B}"); + + this.subtype.add(SubType.ZOMBIE); + this.subtype.add(SubType.KNIGHT); + this.power = new MageInt(2); + this.toughness = new MageInt(3); + + // Lifelink + this.addAbility(LifelinkAbility.getInstance()); + + // When Murderous Rider dies, put it on the bottom of its owner's library. + this.addAbility(new DiesTriggeredAbility(new PutOnLibraryTargetEffect( + false, "put it on the bottom of its owner's library" + ), false)); + + // Swift End + // Destroy target creature or planeswalker. You lose 2 life. + this.getAdventureSpellAbility().addEffect(new DestroyTargetEffect()); + this.getAdventureSpellAbility().addEffect( + new LoseLifeSourceControllerEffect(2).setText("You lose 2 life.") + ); + this.getAdventureSpellAbility().addTarget(new TargetCreatureOrPlaneswalker()); + } + + private MurderousRider(final MurderousRider card) { + super(card); + } + + @Override + public MurderousRider copy() { + return new MurderousRider(this); + } +} diff --git a/Mage.Sets/src/mage/cards/m/MysteriousPathlighter.java b/Mage.Sets/src/mage/cards/m/MysteriousPathlighter.java new file mode 100644 index 0000000000..49cfff12c0 --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/MysteriousPathlighter.java @@ -0,0 +1,95 @@ +package mage.cards.m; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.ReplacementEffectImpl; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.AdventureCard; +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.counters.CounterType; +import mage.game.Game; +import mage.game.events.EntersTheBattlefieldEvent; +import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class MysteriousPathlighter extends CardImpl { + + public MysteriousPathlighter(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{W}"); + + this.subtype.add(SubType.FAERIE); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // Each creature you control that has an Adventure enters the battlefield with an additional +1/+1 counter on it. + this.addAbility(new SimpleStaticAbility(new MysteriousPathlighterEffect())); + } + + private MysteriousPathlighter(final MysteriousPathlighter card) { + super(card); + } + + @Override + public MysteriousPathlighter copy() { + return new MysteriousPathlighter(this); + } +} + +class MysteriousPathlighterEffect extends ReplacementEffectImpl { + + MysteriousPathlighterEffect() { + super(Duration.WhileOnBattlefield, Outcome.BoostCreature); + this.staticText = "Each creature you control that has an Adventure " + + "enters the battlefield with an additional +1/+1 counter on it"; + } + + private MysteriousPathlighterEffect(MysteriousPathlighterEffect effect) { + super(effect); + } + + @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) { + Permanent permanent = ((EntersTheBattlefieldEvent) event).getTarget(); + return permanent instanceof AdventureCard + && permanent.isControlledBy(source.getControllerId()) + && permanent.isCreature(); + } + + @Override + public boolean apply(Game game, Ability source) { + return false; + } + + @Override + public boolean replaceEvent(GameEvent event, Ability source, Game game) { + Permanent target = ((EntersTheBattlefieldEvent) event).getTarget(); + if (target != null) { + target.addCounters(CounterType.P1P1.createInstance(), source, game, event.getAppliedEffects()); + } + return false; + } + + @Override + public MysteriousPathlighterEffect copy() { + return new MysteriousPathlighterEffect(this); + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/m/MysticSanctuary.java b/Mage.Sets/src/mage/cards/m/MysticSanctuary.java new file mode 100644 index 0000000000..b01e015bd5 --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/MysticSanctuary.java @@ -0,0 +1,75 @@ +package mage.cards.m; + +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldAbility; +import mage.abilities.common.EntersBattlefieldUntappedTriggeredAbility; +import mage.abilities.condition.Condition; +import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; +import mage.abilities.decorator.ConditionalOneShotEffect; +import mage.abilities.effects.common.PutOnLibraryTargetEffect; +import mage.abilities.effects.common.TapSourceEffect; +import mage.abilities.mana.BlueManaAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.ComparisonType; +import mage.constants.SubType; +import mage.filter.FilterCard; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledPermanent; +import mage.filter.common.FilterInstantOrSorceryCard; +import mage.filter.predicate.permanent.AnotherPredicate; +import mage.target.common.TargetCardInYourGraveyard; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class MysticSanctuary extends CardImpl { + + private static final FilterPermanent filter + = new FilterControlledPermanent(SubType.ISLAND); + private static final FilterCard filter2 + = new FilterInstantOrSorceryCard("instant or sorcery card from your graveyard"); + + static { + filter.add(AnotherPredicate.instance); + } + + private static final Condition condition + = new PermanentsOnTheBattlefieldCondition(filter, ComparisonType.FEWER_THAN, 3); + + public MysticSanctuary(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); + + this.subtype.add(SubType.ISLAND); + + // ({T}: Add {U}.) + this.addAbility(new BlueManaAbility()); + + // Mystic Sanctuary enters the battlefield tapped unless you control three or more other Islands. + this.addAbility(new EntersBattlefieldAbility( + new ConditionalOneShotEffect(new TapSourceEffect(), condition), + "tapped unless you control three or more other Islands" + )); + + // When Mystic Sanctuary enters the battlefield untapped, you may put target instant or sorcery card from your graveyard on top of your library. + Ability ability = new EntersBattlefieldUntappedTriggeredAbility( + new PutOnLibraryTargetEffect(true) + .setText("put target instant or sorcery card from your graveyard on top of your library"), + true + ); + ability.addTarget(new TargetCardInYourGraveyard(filter2)); + this.addAbility(ability); + } + + private MysticSanctuary(final MysticSanctuary card) { + super(card); + } + + @Override + public MysticSanctuary copy() { + return new MysticSanctuary(this); + } +} diff --git a/Mage.Sets/src/mage/cards/m/MysticalDispute.java b/Mage.Sets/src/mage/cards/m/MysticalDispute.java new file mode 100644 index 0000000000..f2c290d95e --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/MysticalDispute.java @@ -0,0 +1,73 @@ +package mage.cards.m; + +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.Condition; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.effects.common.CounterUnlessPaysEffect; +import mage.abilities.effects.common.cost.SpellCostReductionSourceEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Zone; +import mage.game.Game; +import mage.game.stack.StackObject; +import mage.target.Target; +import mage.target.TargetSpell; + +import java.util.Collection; +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class MysticalDispute extends CardImpl { + + public MysticalDispute(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{U}"); + + // This spell costs {2} less to cast if it targets a blue spell. + this.addAbility(new SimpleStaticAbility( + Zone.STACK, new SpellCostReductionSourceEffect(2, MysticalDisputeCondition.instance) + ).setRuleAtTheTop(true)); + + // Counter target spell unless its controller pays {3}. + this.getSpellAbility().addEffect(new CounterUnlessPaysEffect(new GenericManaCost(3))); + this.getSpellAbility().addTarget(new TargetSpell()); + } + + private MysticalDispute(final MysticalDispute card) { + super(card); + } + + @Override + public MysticalDispute copy() { + return new MysticalDispute(this); + } +} + +enum MysticalDisputeCondition implements Condition { + instance; + + @Override + public boolean apply(Game game, Ability source) { + StackObject sourceSpell = game.getStack().getStackObject(source.getSourceId()); + if (sourceSpell == null) { + return false; + } + return sourceSpell + .getStackAbility() + .getTargets() + .stream() + .map(Target::getTargets) + .flatMap(Collection::stream) + .map(game::getSpell) + .anyMatch(spell -> spell != null && spell.getColor(game).isBlue()); + } + + @Override + public String toString() { + return "it targets a blue spell"; + } + +} diff --git a/Mage.Sets/src/mage/cards/o/OakhameAdversary.java b/Mage.Sets/src/mage/cards/o/OakhameAdversary.java new file mode 100644 index 0000000000..e33931ff44 --- /dev/null +++ b/Mage.Sets/src/mage/cards/o/OakhameAdversary.java @@ -0,0 +1,69 @@ +package mage.cards.o; + +import mage.MageInt; +import mage.ObjectColor; +import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.Condition; +import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.cost.SpellCostReductionSourceEffect; +import mage.abilities.keyword.DeathtouchAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.TargetController; +import mage.constants.Zone; +import mage.filter.FilterPermanent; +import mage.filter.predicate.mageobject.ColorPredicate; +import mage.filter.predicate.permanent.ControllerPredicate; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class OakhameAdversary extends CardImpl { + + private static final FilterPermanent filter + = new FilterPermanent("your opponent controls a green permanent"); + + static { + filter.add(new ControllerPredicate(TargetController.OPPONENT)); + filter.add(new ColorPredicate(ObjectColor.GREEN)); + } + + private static final Condition condition = new PermanentsOnTheBattlefieldCondition(filter); + + public OakhameAdversary(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{G}"); + + this.subtype.add(SubType.ELF); + this.subtype.add(SubType.WARRIOR); + this.power = new MageInt(2); + this.toughness = new MageInt(3); + + // This spell costs {2} less to cast if your opponent controls a green permanent. + this.addAbility(new SimpleStaticAbility( + Zone.STACK, new SpellCostReductionSourceEffect(2, condition) + ).setRuleAtTheTop(true)); + + // Deathtouch + this.addAbility(DeathtouchAbility.getInstance()); + + // Whenever Oakhame Adversary deals combat damage to a player, draw a card. + this.addAbility(new DealsCombatDamageToAPlayerTriggeredAbility( + new DrawCardSourceControllerEffect(1), false + )); + } + + private OakhameAdversary(final OakhameAdversary card) { + super(card); + } + + @Override + public OakhameAdversary copy() { + return new OakhameAdversary(this); + } +} diff --git a/Mage.Sets/src/mage/cards/o/OakhameRanger.java b/Mage.Sets/src/mage/cards/o/OakhameRanger.java new file mode 100644 index 0000000000..ce7ff7ddd5 --- /dev/null +++ b/Mage.Sets/src/mage/cards/o/OakhameRanger.java @@ -0,0 +1,48 @@ +package mage.cards.o; + +import mage.MageInt; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.continuous.BoostControlledEffect; +import mage.cards.AdventureCard; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.game.permanent.token.HumanToken; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class OakhameRanger extends AdventureCard { + + public OakhameRanger(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, new CardType[]{CardType.SORCERY}, "{G/W}{G/W}{G/W}{G/W}", "Bring Back", "{G/W}{G/W}{G/W}{G/W}"); + + this.subtype.add(SubType.ELF); + this.subtype.add(SubType.KNIGHT); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // {T}: Creatures you control get +1/+1 until end of turn. + this.addAbility(new SimpleActivatedAbility( + new BoostControlledEffect(1, 1, Duration.EndOfTurn), new TapSourceCost() + )); + + // Bring Back + // Create two 1/1 white Human creature tokens. + this.getAdventureSpellAbility().addEffect(new CreateTokenEffect(new HumanToken(), 2)); + } + + private OakhameRanger(final OakhameRanger card) { + super(card); + } + + @Override + public OakhameRanger copy() { + return new OakhameRanger(this); + } +} diff --git a/Mage.Sets/src/mage/cards/o/OathswornKnight.java b/Mage.Sets/src/mage/cards/o/OathswornKnight.java new file mode 100644 index 0000000000..70e3164371 --- /dev/null +++ b/Mage.Sets/src/mage/cards/o/OathswornKnight.java @@ -0,0 +1,50 @@ +package mage.cards.o; + +import mage.MageInt; +import mage.abilities.common.AttacksEachCombatStaticAbility; +import mage.abilities.common.EntersBattlefieldAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.PreventDamageAndRemoveCountersEffect; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.counters.CounterType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class OathswornKnight extends CardImpl { + + public OathswornKnight(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{B}{B}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.KNIGHT); + this.power = new MageInt(0); + this.toughness = new MageInt(0); + + // Oathsworn Knight enters the battlefield with four +1/+1 counters on it. + this.addAbility(new EntersBattlefieldAbility(new AddCountersSourceEffect( + CounterType.P1P1.createInstance(4) + ), "with four +1/+1 counters on it")); + + // Oathsworn Knight attacks each combat if able. + this.addAbility(new AttacksEachCombatStaticAbility()); + + // If damage would be dealt to Oathsworn Knight while it has a +1/+1 counter on it, prevent that damage and remove a +1/+1 counter from it. + this.addAbility(new SimpleStaticAbility(new PreventDamageAndRemoveCountersEffect(false))); + } + + private OathswornKnight(final OathswornKnight card) { + super(card); + } + + @Override + public OathswornKnight copy() { + return new OathswornKnight(this); + } +} diff --git a/Mage.Sets/src/mage/cards/o/ObzedatGhostCouncil.java b/Mage.Sets/src/mage/cards/o/ObzedatGhostCouncil.java index b0ea8280e2..c936c96074 100644 --- a/Mage.Sets/src/mage/cards/o/ObzedatGhostCouncil.java +++ b/Mage.Sets/src/mage/cards/o/ObzedatGhostCouncil.java @@ -1,14 +1,12 @@ package mage.cards.o; -import java.util.UUID; import mage.MageInt; +import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.DelayedTriggeredAbility; import mage.abilities.common.BeginningOfYourEndStepTriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; -import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; -import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect; import mage.abilities.effects.common.GainLifeEffect; import mage.abilities.effects.common.LoseLifeTargetEffect; import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; @@ -24,8 +22,9 @@ import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.common.TargetOpponent; +import java.util.UUID; + /** - * * @author Plopman */ public final class ObzedatGhostCouncil extends CardImpl { @@ -41,16 +40,15 @@ public final class ObzedatGhostCouncil extends CardImpl { //When Obzedat, Ghost Council enters the battlefield, target opponent loses 2 life and you gain 2 life. Ability ability = new EntersBattlefieldTriggeredAbility(new LoseLifeTargetEffect(2)); - ability.addEffect(new GainLifeEffect(2).setText("and you gain 2 life")); + ability.addEffect(new GainLifeEffect(2).concatBy("and")); ability.addTarget(new TargetOpponent()); this.addAbility(ability); //At the beginning of your end step you may exile Obzedat. If you do, return it to the battlefield under its owner's control at the beginning of your next upkeep. It gains haste. Ability ability2 = new BeginningOfYourEndStepTriggeredAbility(new ObzedatGhostCouncilExileSourceEffect(), true); - ability2.addEffect(new CreateDelayedTriggeredAbilityEffect(new BeginningOfYourUpkeepdelayTriggeredAbility())); this.addAbility(ability2); } - public ObzedatGhostCouncil(final ObzedatGhostCouncil card) { + private ObzedatGhostCouncil(final ObzedatGhostCouncil card) { super(card); } @@ -62,12 +60,13 @@ public final class ObzedatGhostCouncil extends CardImpl { class ObzedatGhostCouncilExileSourceEffect extends OneShotEffect { - public ObzedatGhostCouncilExileSourceEffect() { + ObzedatGhostCouncilExileSourceEffect() { super(Outcome.Exile); - staticText = "exile {this}"; + staticText = "exile {this}. If you do, return it to the battlefield under its owner's control " + + "at the beginning of your next upkeep. It gains haste."; } - public ObzedatGhostCouncilExileSourceEffect(final ObzedatGhostCouncilExileSourceEffect effect) { + private ObzedatGhostCouncilExileSourceEffect(final ObzedatGhostCouncilExileSourceEffect effect) { super(effect); } @@ -78,27 +77,25 @@ class ObzedatGhostCouncilExileSourceEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); Permanent permanent = game.getPermanent(source.getSourceId()); - if (permanent != null) { - return permanent.moveToExile(source.getSourceId(), permanent.getName(), source.getSourceId(), game); + if (permanent == null || player == null + || !player.moveCards(permanent, Zone.EXILED, source, game)) { + return false; } - return false; + game.addDelayedTriggeredAbility(new ObzedatGhostCouncilDelayedTriggeredAbility(new MageObjectReference(permanent, game)), source); + return true; } } -class BeginningOfYourUpkeepdelayTriggeredAbility extends DelayedTriggeredAbility { +class ObzedatGhostCouncilDelayedTriggeredAbility extends DelayedTriggeredAbility { - public BeginningOfYourUpkeepdelayTriggeredAbility() { - this(new ObzedatGhostCouncilReturnEffect(), TargetController.YOU); - this.addEffect(new GainAbilitySourceEffect(HasteAbility.getInstance(), Duration.Custom)); + ObzedatGhostCouncilDelayedTriggeredAbility(MageObjectReference mor) { + super(new ObzedatGhostCouncilReturnEffect(mor)); } - public BeginningOfYourUpkeepdelayTriggeredAbility(Effect effect, TargetController targetController) { - super(effect); - } - - public BeginningOfYourUpkeepdelayTriggeredAbility(BeginningOfYourUpkeepdelayTriggeredAbility ability) { + private ObzedatGhostCouncilDelayedTriggeredAbility(ObzedatGhostCouncilDelayedTriggeredAbility ability) { super(ability); } @@ -113,24 +110,28 @@ class BeginningOfYourUpkeepdelayTriggeredAbility extends DelayedTriggeredAbility } @Override - public BeginningOfYourUpkeepdelayTriggeredAbility copy() { - return new BeginningOfYourUpkeepdelayTriggeredAbility(this); + public ObzedatGhostCouncilDelayedTriggeredAbility copy() { + return new ObzedatGhostCouncilDelayedTriggeredAbility(this); } @Override public String getRule() { - return "If you do, return it to the battlefield under its owner's control at the beginning of your next upkeep. It gains haste"; + return "Return {this} to the battlefield under its owner's control at the beginning of your next upkeep. It gains haste"; } } class ObzedatGhostCouncilReturnEffect extends OneShotEffect { - public ObzedatGhostCouncilReturnEffect() { + private final MageObjectReference mor; + + ObzedatGhostCouncilReturnEffect(MageObjectReference mor) { super(Outcome.Benefit); + this.mor = mor; } - public ObzedatGhostCouncilReturnEffect(final ObzedatGhostCouncilReturnEffect effect) { + private ObzedatGhostCouncilReturnEffect(final ObzedatGhostCouncilReturnEffect effect) { super(effect); + this.mor = effect.mor; } @Override @@ -140,19 +141,20 @@ class ObzedatGhostCouncilReturnEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Card card = game.getCard(source.getSourceId()); - if (card != null) { - Zone zone = game.getState().getZone(source.getSourceId()); - // return it from every public zone - http://www.mtgsalvation.com/forums/magic-fundamentals/magic-rulings/magic-rulings-archives/513186-obzedat-gc-as-edh-commander - if (zone != Zone.BATTLEFIELD && zone != Zone.LIBRARY && zone != Zone.HAND) { - Player owner = game.getPlayer(card.getOwnerId()); - if (owner != null) { - owner.moveCards(card, Zone.BATTLEFIELD, source, game); - } - } - return true; + Card card = mor.getCard(game); + if (card == null) { + return false; } - return false; + Zone zone = game.getState().getZone(source.getSourceId()); + // return it from every public zone - http://www.mtgsalvation.com/forums/magic-fundamentals/magic-rulings/magic-rulings-archives/513186-obzedat-gc-as-edh-commander + if (zone == Zone.BATTLEFIELD || zone == Zone.LIBRARY || zone == Zone.HAND) { + return false; + } + Player owner = game.getPlayer(card.getOwnerId()); + if (owner == null || !owner.moveCards(card, Zone.BATTLEFIELD, source, game)) { + return false; + } + game.addEffect(new GainAbilitySourceEffect(HasteAbility.getInstance(), Duration.WhileOnBattlefield), source); + return true; } - } diff --git a/Mage.Sets/src/mage/cards/o/OgreErrant.java b/Mage.Sets/src/mage/cards/o/OgreErrant.java new file mode 100644 index 0000000000..683342b6b4 --- /dev/null +++ b/Mage.Sets/src/mage/cards/o/OgreErrant.java @@ -0,0 +1,57 @@ +package mage.cards.o; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.AttacksTriggeredAbility; +import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; +import mage.abilities.keyword.MenaceAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.filter.FilterPermanent; +import mage.filter.predicate.permanent.AnotherPredicate; +import mage.filter.predicate.permanent.AttackingPredicate; +import mage.target.TargetPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class OgreErrant extends CardImpl { + + private static final FilterPermanent filter + = new FilterPermanent(SubType.KNIGHT, "another attacking Knight"); + + static { + filter.add(AttackingPredicate.instance); + filter.add(AnotherPredicate.instance); + } + + public OgreErrant(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{R}"); + + this.subtype.add(SubType.OGRE); + this.subtype.add(SubType.KNIGHT); + this.power = new MageInt(3); + this.toughness = new MageInt(4); + + // Whenever Ogre Errant attacks, another target attacking Knight gains menace until end of turn. + Ability ability = new AttacksTriggeredAbility(new GainAbilityTargetEffect( + new MenaceAbility(), Duration.EndOfTurn + ).setText("another target attacking Knight gains menace until end of turn"), false); + ability.addTarget(new TargetPermanent(filter)); + this.addAbility(ability); + } + + private OgreErrant(final OgreErrant card) { + super(card); + } + + @Override + public OgreErrant copy() { + return new OgreErrant(this); + } +} diff --git a/Mage.Sets/src/mage/cards/o/OgreSavant.java b/Mage.Sets/src/mage/cards/o/OgreSavant.java index 3b7cafa2ac..e230ccfccc 100644 --- a/Mage.Sets/src/mage/cards/o/OgreSavant.java +++ b/Mage.Sets/src/mage/cards/o/OgreSavant.java @@ -33,7 +33,7 @@ public final class OgreSavant extends CardImpl { TriggeredAbility ability = new EntersBattlefieldTriggeredAbility(new ReturnToHandTargetEffect(),false); ability.addTarget(new TargetCreaturePermanent()); this.addAbility(new ConditionalInterveningIfTriggeredAbility(ability, new ManaWasSpentCondition(ColoredManaSymbol.U), - "if {U} was spent to cast {this}, return target creature to its owner's hand."), + "if {U} was spent to cast this spell, return target creature to its owner's hand."), new ManaSpentToCastWatcher()); } diff --git a/Mage.Sets/src/mage/cards/o/OkoTheTrickster.java b/Mage.Sets/src/mage/cards/o/OkoTheTrickster.java new file mode 100644 index 0000000000..fba45954e1 --- /dev/null +++ b/Mage.Sets/src/mage/cards/o/OkoTheTrickster.java @@ -0,0 +1,97 @@ +package mage.cards.o; + +import mage.abilities.Ability; +import mage.abilities.LoyaltyAbility; +import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.PreventAllDamageToSourceEffect; +import mage.abilities.effects.common.continuous.GainAbilityAllEffect; +import mage.abilities.effects.common.continuous.SetPowerToughnessAllEffect; +import mage.abilities.effects.common.counter.AddCountersTargetEffect; +import mage.abilities.keyword.TrampleAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.counters.CounterType; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.target.common.TargetControlledCreaturePermanent; +import mage.util.functions.EmptyApplyToPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class OkoTheTrickster extends CardImpl { + + public OkoTheTrickster(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.PLANESWALKER}, "{4}{G}{U}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.OKO); + this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(4)); + + // +1: Put two +1/+1 counters on up to one target creature you control. + Ability ability = new LoyaltyAbility( + new AddCountersTargetEffect(CounterType.P1P1.createInstance(2)), 1 + ); + ability.addTarget(new TargetControlledCreaturePermanent(0, 1)); + this.addAbility(ability); + + // 0: Until end of turn, Oko, the Trickster becomes a copy of target creature you control. Prevent all damage that would be dealt to him this turn. + ability = new LoyaltyAbility(new OkoTheTricksterCopyEffect(), 0); + ability.addEffect(new PreventAllDamageToSourceEffect(Duration.EndOfTurn) + .setText("Prevent all damage that would be dealt to him this turn.")); + ability.addTarget(new TargetControlledCreaturePermanent()); + this.addAbility(ability); + + // −7: Until end of turn, each creature you control has base power and toughness 10/10 and gains trample. + ability = new LoyaltyAbility(new SetPowerToughnessAllEffect( + 10, 10, Duration.EndOfTurn, StaticFilters.FILTER_CONTROLLED_CREATURE, true + ).setText("Until end of turn, each creature you control has base power and toughness 10/10"), -7); + ability.addEffect(new GainAbilityAllEffect( + TrampleAbility.getInstance(), Duration.EndOfTurn, + StaticFilters.FILTER_CONTROLLED_CREATURE + ).setText("and gains trample")); + this.addAbility(ability); + } + + private OkoTheTrickster(final OkoTheTrickster card) { + super(card); + } + + @Override + public OkoTheTrickster copy() { + return new OkoTheTrickster(this); + } +} + +class OkoTheTricksterCopyEffect extends OneShotEffect { + + OkoTheTricksterCopyEffect() { + super(Outcome.Copy); + this.staticText = "Until end of turn, {this} becomes a copy of target creature you control."; + } + + private OkoTheTricksterCopyEffect(final OkoTheTricksterCopyEffect effect) { + super(effect); + } + + @Override + public OkoTheTricksterCopyEffect copy() { + return new OkoTheTricksterCopyEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent sourcePermanent = game.getPermanent(source.getSourceId()); + Permanent copyFromPermanent = game.getPermanent(getTargetPointer().getFirst(game, source)); + if (sourcePermanent == null || copyFromPermanent == null) { + return false; + } + game.copyPermanent(Duration.EndOfTurn, copyFromPermanent, sourcePermanent.getId(), source, new EmptyApplyToPermanent()); + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/o/OkoThiefOfCrowns.java b/Mage.Sets/src/mage/cards/o/OkoThiefOfCrowns.java index a87c2fd372..79e5881224 100644 --- a/Mage.Sets/src/mage/cards/o/OkoThiefOfCrowns.java +++ b/Mage.Sets/src/mage/cards/o/OkoThiefOfCrowns.java @@ -39,7 +39,7 @@ public final class OkoThiefOfCrowns extends CardImpl { this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(4)); // +2: Create a Food token. - this.addAbility(new LoyaltyAbility(new CreateTokenEffect(new FoodToken(), 2))); + this.addAbility(new LoyaltyAbility(new CreateTokenEffect(new FoodToken()), 2)); // +1: Target artifact or creature loses all abilities and becomes a green Elk creature with base power and toughness 3/3. Ability ability = new LoyaltyAbility(new BecomesCreatureTargetEffect( diff --git a/Mage.Sets/src/mage/cards/o/OkosAccomplices.java b/Mage.Sets/src/mage/cards/o/OkosAccomplices.java new file mode 100644 index 0000000000..65134616d9 --- /dev/null +++ b/Mage.Sets/src/mage/cards/o/OkosAccomplices.java @@ -0,0 +1,36 @@ +package mage.cards.o; + +import mage.MageInt; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class OkosAccomplices extends CardImpl { + + public OkosAccomplices(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{U}"); + + this.subtype.add(SubType.FAERIE); + this.power = new MageInt(2); + this.toughness = new MageInt(3); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + } + + private OkosAccomplices(final OkosAccomplices card) { + super(card); + } + + @Override + public OkosAccomplices copy() { + return new OkosAccomplices(this); + } +} diff --git a/Mage.Sets/src/mage/cards/o/OkosHospitality.java b/Mage.Sets/src/mage/cards/o/OkosHospitality.java new file mode 100644 index 0000000000..02cb47d377 --- /dev/null +++ b/Mage.Sets/src/mage/cards/o/OkosHospitality.java @@ -0,0 +1,46 @@ +package mage.cards.o; + +import mage.abilities.effects.common.continuous.SetPowerToughnessAllEffect; +import mage.abilities.effects.common.search.SearchLibraryGraveyardPutInHandEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.filter.FilterCard; +import mage.filter.StaticFilters; +import mage.filter.predicate.mageobject.NamePredicate; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class OkosHospitality extends CardImpl { + + private static final FilterCard filter = new FilterCard("Oko, the Trickster"); + + static { + filter.add(new NamePredicate("Oko, the Trickster")); + } + + public OkosHospitality(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{3}{G}{U}"); + + // Creatures you control have base power and toughness 3/3 until end of turn. You may search your library and/or graveyard for a card named Oko, the Trickster, reveal it, and put it into your hand. If you search your library this way, shuffle it. + this.getSpellAbility().addEffect(new SetPowerToughnessAllEffect( + 3, 3, Duration.EndOfTurn, StaticFilters.FILTER_CONTROLLED_CREATURES, true + )); + this.getSpellAbility().addEffect( + new SearchLibraryGraveyardPutInHandEffect(filter, false, true) + ); + } + + private OkosHospitality(final OkosHospitality card) { + super(card); + } + + @Override + public OkosHospitality copy() { + return new OkosHospitality(this); + } +} diff --git a/Mage.Sets/src/mage/cards/o/OnceAndFuture.java b/Mage.Sets/src/mage/cards/o/OnceAndFuture.java new file mode 100644 index 0000000000..f1fd695ac4 --- /dev/null +++ b/Mage.Sets/src/mage/cards/o/OnceAndFuture.java @@ -0,0 +1,101 @@ +package mage.cards.o; + +import mage.abilities.Ability; +import mage.abilities.condition.common.AdamantCondition; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.ExileSpellEffect; +import mage.cards.*; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Zone; +import mage.game.Game; +import mage.players.Player; +import mage.target.Target; +import mage.target.common.TargetCardInYourGraveyard; +import mage.watchers.common.ManaSpentToCastWatcher; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class OnceAndFuture extends CardImpl { + + public OnceAndFuture(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{3}{G}"); + + // Return target card from your graveyard to your hand. Put up to one other target card from your graveyard on top of your library. Exile Once and Future. + // Adamant — If at least three green mana was spent to cast this spell, instead return those cards to your hand and exile Once and Future. + this.getSpellAbility().addEffect(new OnceAndFutureEffect()); + + Target target = new TargetCardInYourGraveyard().withChooseHint("To put in your hand"); + target.setTargetTag(1); + this.getSpellAbility().addTarget(target); + + target = new TargetCardInYourGraveyard(0, 1).withChooseHint("To put on top of your library"); + target.setTargetTag(2); + this.getSpellAbility().addTarget(target); + + this.getSpellAbility().addWatcher(new ManaSpentToCastWatcher()); + } + + private OnceAndFuture(final OnceAndFuture card) { + super(card); + } + + @Override + public OnceAndFuture copy() { + return new OnceAndFuture(this); + } +} + +class OnceAndFutureEffect extends OneShotEffect { + + OnceAndFutureEffect() { + super(Outcome.Benefit); + staticText = "Return target card from your graveyard to your hand. " + + "Put up to one other target card from your graveyard on top of your library. Exile {this}." + + "
Adamant — If at least three green mana was spent to cast this spell, " + + "instead return those cards to your hand and exile {this}."; + } + + private OnceAndFutureEffect(final OnceAndFutureEffect effect) { + super(effect); + } + + @Override + public OnceAndFutureEffect copy() { + return new OnceAndFutureEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; + } + Card card1 = game.getCard(source.getFirstTarget()); + Card card2 = game.getCard(source.getTargets().get(1).getFirstTarget()); + if (card1 == null) { + card1 = card2; + card2 = null; + } + if (card1 == null) { + return false; + } + if (card2 == null) { + player.putInHand(card1, game); + return ExileSpellEffect.getInstance().apply(game, source); + } + if (AdamantCondition.GREEN.apply(game, source)) { + Cards cards = new CardsImpl(); + cards.add(card1); + cards.add(card2); + player.moveCards(cards, Zone.HAND, source, game); + return ExileSpellEffect.getInstance().apply(game, source); + } + player.putInHand(card1, game); + player.putCardsOnTopOfLibrary(new CardsImpl(card2), game, source, false); + return ExileSpellEffect.getInstance().apply(game, source); + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/o/OnceUponATime.java b/Mage.Sets/src/mage/cards/o/OnceUponATime.java new file mode 100644 index 0000000000..3a3559d9fa --- /dev/null +++ b/Mage.Sets/src/mage/cards/o/OnceUponATime.java @@ -0,0 +1,106 @@ +package mage.cards.o; + +import mage.abilities.Ability; +import mage.abilities.condition.Condition; +import mage.abilities.costs.AlternativeCostSourceAbility; +import mage.abilities.dynamicvalue.common.StaticValue; +import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.WatcherScope; +import mage.constants.Zone; +import mage.filter.FilterCard; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.CardTypePredicate; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.watchers.Watcher; + +import java.util.HashSet; +import java.util.Set; +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class OnceUponATime extends CardImpl { + + private static final FilterCard filter = new FilterCard("a creature or land card"); + + static { + filter.add(Predicates.or( + new CardTypePredicate(CardType.CREATURE), + new CardTypePredicate(CardType.LAND) + )); + } + + public OnceUponATime(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{G}"); + + // If this spell is the first spell you've cast this game, you may cast it without paying its mana cost. + this.addAbility(new AlternativeCostSourceAbility( + null, OnceUponATimeCondition.instance, "If this spell is the first spell " + + "you've cast this game, you may cast it without paying its mana cost." + ), new OnceUponATimeWatcher()); + + // Look at the top five cards of your library. You may reveal a creature or land card from among them and put it into your hand. Put the rest on the bottom of your library in a random order. + this.getSpellAbility().addEffect(new LookLibraryAndPickControllerEffect( + new StaticValue(5), false, new StaticValue(1), filter, + Zone.LIBRARY, false, true, false, Zone.HAND, + true, false, false + ).setBackInRandomOrder(true).setText("Look at the top five cards of your library. " + + "You may reveal a creature or land card from among them and put it into your hand. " + + "Put the rest on the bottom of your library in a random order." + )); + } + + private OnceUponATime(final OnceUponATime card) { + super(card); + } + + @Override + public OnceUponATime copy() { + return new OnceUponATime(this); + } +} + +enum OnceUponATimeCondition implements Condition { + instance; + + @Override + public boolean apply(Game game, Ability source) { + OnceUponATimeWatcher watcher = game.getState().getWatcher(OnceUponATimeWatcher.class); + return watcher != null && watcher.getSpellsCastThisTurn(source.getControllerId()); + } +} + +class OnceUponATimeWatcher extends Watcher { + + private final Set castSpells = new HashSet(); + + OnceUponATimeWatcher() { + super(WatcherScope.GAME); + } + + private OnceUponATimeWatcher(final OnceUponATimeWatcher watcher) { + super(watcher); + this.castSpells.addAll(watcher.castSpells); + } + + @Override + public OnceUponATimeWatcher copy() { + return new OnceUponATimeWatcher(this); + } + + @Override + public void watch(GameEvent event, Game game) { + if (GameEvent.EventType.SPELL_CAST == event.getType()) { + castSpells.add(event.getPlayerId()); + } + } + + public boolean getSpellsCastThisTurn(UUID playerId) { + return !castSpells.contains(playerId); + } +} diff --git a/Mage.Sets/src/mage/cards/o/OpportunisticDragon.java b/Mage.Sets/src/mage/cards/o/OpportunisticDragon.java new file mode 100644 index 0000000000..d4e9aa9746 --- /dev/null +++ b/Mage.Sets/src/mage/cards/o/OpportunisticDragon.java @@ -0,0 +1,146 @@ +package mage.cards.o; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.common.combat.CantAttackBlockTargetEffect; +import mage.abilities.effects.common.continuous.GainControlTargetEffect; +import mage.abilities.effects.common.continuous.LoseAllAbilitiesTargetEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.constants.TargetController; +import mage.filter.FilterPermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.CardTypePredicate; +import mage.filter.predicate.mageobject.SubtypePredicate; +import mage.filter.predicate.permanent.ControllerPredicate; +import mage.game.Game; +import mage.target.TargetPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class OpportunisticDragon extends CardImpl { + + private static final FilterPermanent filter = new FilterPermanent("Human or artifact an opponent controls"); + + static { + filter.add(Predicates.or( + new CardTypePredicate(CardType.ARTIFACT), + new SubtypePredicate(SubType.HUMAN) + )); + filter.add(new ControllerPredicate(TargetController.OPPONENT)); + } + + public OpportunisticDragon(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{R}{R}"); + + this.subtype.add(SubType.DRAGON); + this.power = new MageInt(4); + this.toughness = new MageInt(3); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // When Opportunistic Dragon enters the battlefield, choose target Human or artifact an opponent controls. For as long as Opportunistic Dragon remains on the battlefield, gain control of that permanent, it loses all abilities, and it can't attack or block. + Ability ability = new EntersBattlefieldTriggeredAbility(new OpportunisticDragonControlEffect()); + ability.addEffect(new OpportunisticDragonLoseAbilitiesEffect()); + ability.addEffect(new OpportunisticDragonAttackBlockEffect()); + ability.addTarget(new TargetPermanent(filter)); + this.addAbility(ability); + } + + private OpportunisticDragon(final OpportunisticDragon card) { + super(card); + } + + @Override + public OpportunisticDragon copy() { + return new OpportunisticDragon(this); + } +} + +class OpportunisticDragonControlEffect extends GainControlTargetEffect { + + OpportunisticDragonControlEffect() { + super(Duration.Custom); + staticText = "choose target Human or artifact an opponent controls. " + + "For as long as {this} remains on the battlefield, gain control of that permanent,"; + } + + private OpportunisticDragonControlEffect(final OpportunisticDragonControlEffect effect) { + super(effect); + } + + @Override + public OpportunisticDragonControlEffect copy() { + return new OpportunisticDragonControlEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + if (source.getSourcePermanentIfItStillExists(game) == null) { + discard(); + return false; + } + return super.apply(game, source); + } +} + +class OpportunisticDragonLoseAbilitiesEffect extends LoseAllAbilitiesTargetEffect { + + OpportunisticDragonLoseAbilitiesEffect() { + super(Duration.Custom); + staticText = "it loses all abilities,"; + } + + private OpportunisticDragonLoseAbilitiesEffect(final OpportunisticDragonLoseAbilitiesEffect effect) { + super(effect); + } + + @Override + public OpportunisticDragonLoseAbilitiesEffect copy() { + return new OpportunisticDragonLoseAbilitiesEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + if (source.getSourcePermanentIfItStillExists(game) == null) { + discard(); + return false; + } + return super.apply(game, source); + } +} + +class OpportunisticDragonAttackBlockEffect extends CantAttackBlockTargetEffect { + + OpportunisticDragonAttackBlockEffect() { + super(Duration.Custom); + staticText = "and it can't attack or block"; + } + + private OpportunisticDragonAttackBlockEffect(final OpportunisticDragonAttackBlockEffect effect) { + super(effect); + } + + @Override + public OpportunisticDragonAttackBlockEffect copy() { + return new OpportunisticDragonAttackBlockEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + if (source.getSourcePermanentIfItStillExists(game) == null) { + discard(); + return false; + } + return super.apply(game, source); + } +} diff --git a/Mage.Sets/src/mage/cards/o/Outflank.java b/Mage.Sets/src/mage/cards/o/Outflank.java new file mode 100644 index 0000000000..3818073819 --- /dev/null +++ b/Mage.Sets/src/mage/cards/o/Outflank.java @@ -0,0 +1,40 @@ +package mage.cards.o; + +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.filter.StaticFilters; +import mage.target.common.TargetAttackingOrBlockingCreature; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class Outflank extends CardImpl { + + private static final DynamicValue xValue + = new PermanentsOnBattlefieldCount(StaticFilters.FILTER_CONTROLLED_CREATURE); + + public Outflank(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{W}"); + + // Outflank deals damage to target attacking or blocking creature equal to the number of creatures you control. + this.getSpellAbility().addEffect(new DamageTargetEffect(xValue) + .setText("{this} deals damage to target attacking or blocking creature " + + "equal to the number of creatures you control")); + this.getSpellAbility().addTarget(new TargetAttackingOrBlockingCreature()); + } + + private Outflank(final Outflank card) { + super(card); + } + + @Override + public Outflank copy() { + return new Outflank(this); + } +} diff --git a/Mage.Sets/src/mage/cards/o/OutlawsMerriment.java b/Mage.Sets/src/mage/cards/o/OutlawsMerriment.java new file mode 100644 index 0000000000..653fa86cf9 --- /dev/null +++ b/Mage.Sets/src/mage/cards/o/OutlawsMerriment.java @@ -0,0 +1,55 @@ +package mage.cards.o; + +import mage.abilities.Ability; +import mage.abilities.Mode; +import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.TargetController; +import mage.game.permanent.token.OutlawsMerrimentClericToken; +import mage.game.permanent.token.OutlawsMerrimentRogueToken; +import mage.game.permanent.token.OutlawsMerrimentWarriorToken; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class OutlawsMerriment extends CardImpl { + + public OutlawsMerriment(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{R}{W}{W}"); + + // At the beginning of your upkeep, choose one at random. Create a red and white creature token with those characteristics. + // • 3/1 Human Warrior with trample and haste. + Ability ability = new BeginningOfUpkeepTriggeredAbility( + new CreateTokenEffect(new OutlawsMerrimentWarriorToken()) + .setText("3/1 Human Warrior with trample and haste"), + TargetController.YOU, false + ); + + // • 2/1 Human Cleric with lifelink and haste. + ability.addMode(new Mode(new CreateTokenEffect(new OutlawsMerrimentClericToken()) + .setText("2/1 Human Cleric with lifelink and haste"))); + + // • 1/2 Human Rogue with haste and "When this creature enters the battlefield, it deals 1 damage to any target." + ability.addMode(new Mode(new CreateTokenEffect(new OutlawsMerrimentRogueToken()) + .setText("1/2 Human Rogue with haste and \"When this creature enters the battlefield, it deals 1 damage to any target.\""))); + + ability.getModes().setChooseText("choose one at random. Create a red and white creature token with those characteristics."); + ability.getModes().setRandom(true); + + this.addAbility(ability); + } + + private OutlawsMerriment(final OutlawsMerriment card) { + super(card); + } + + @Override + public OutlawsMerriment copy() { + return new OutlawsMerriment(this); + } +} diff --git a/Mage.Sets/src/mage/cards/o/Outmuscle.java b/Mage.Sets/src/mage/cards/o/Outmuscle.java new file mode 100644 index 0000000000..02fc9bbbbf --- /dev/null +++ b/Mage.Sets/src/mage/cards/o/Outmuscle.java @@ -0,0 +1,98 @@ +package mage.cards.o; + +import mage.abilities.Ability; +import mage.abilities.condition.common.AdamantCondition; +import mage.abilities.effects.ContinuousEffect; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; +import mage.abilities.keyword.IndestructibleAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.TargetController; +import mage.counters.CounterType; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.permanent.ControllerPredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.target.TargetPermanent; +import mage.target.common.TargetControlledCreaturePermanent; +import mage.target.targetpointer.FixedTarget; +import mage.watchers.common.ManaSpentToCastWatcher; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class Outmuscle extends CardImpl { + + private static final FilterCreaturePermanent filter + = new FilterCreaturePermanent("creature you don't control"); + + static { + filter.add(new ControllerPredicate(TargetController.NOT_YOU)); + } + + public Outmuscle(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{3}{G}"); + + // Put a +1/+1 counter on target creature you control, then it fights target creature you don't control. + // Adamant — If at least three green mana was spent to cast this spell, the creature you control gains indestructible until end of turn. + this.getSpellAbility().addEffect(new OutmuscleEffect()); + this.getSpellAbility().addTarget(new TargetControlledCreaturePermanent()); + this.getSpellAbility().addTarget(new TargetPermanent(filter)); + this.getSpellAbility().addWatcher(new ManaSpentToCastWatcher()); + } + + private Outmuscle(final Outmuscle card) { + super(card); + } + + @Override + public Outmuscle copy() { + return new Outmuscle(this); + } +} + +class OutmuscleEffect extends OneShotEffect { + + OutmuscleEffect() { + super(Outcome.Benefit); + staticText = "Put a +1/+1 counter on target creature you control, " + + "then it fights target creature you don't control." + + "
Adamant — If at least three green mana was spent to cast this spell, " + + "the creature you control gains indestructible until end of turn."; + } + + private OutmuscleEffect(final OutmuscleEffect effect) { + super(effect); + } + + @Override + public OutmuscleEffect copy() { + return new OutmuscleEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent permanent = game.getPermanent(source.getFirstTarget()); + if (permanent == null) { + return false; + } + if (AdamantCondition.GREEN.apply(game, source)) { + ContinuousEffect effect = new GainAbilityTargetEffect(IndestructibleAbility.getInstance(), Duration.EndOfTurn); + effect.setTargetPointer(new FixedTarget(permanent, game)); + game.addEffect(effect, source); + } + permanent.addCounters(CounterType.P1P1.createInstance(), source, game); + Permanent creature = game.getPermanent(source.getTargets().get(1).getFirstTarget()); + if (creature == null) { + return true; + } + game.applyEffects(); + return creature.fight(permanent, source, game); + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/o/OverwhelmedApprentice.java b/Mage.Sets/src/mage/cards/o/OverwhelmedApprentice.java new file mode 100644 index 0000000000..c62134e566 --- /dev/null +++ b/Mage.Sets/src/mage/cards/o/OverwhelmedApprentice.java @@ -0,0 +1,45 @@ +package mage.cards.o; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.common.PutTopCardOfLibraryIntoGraveEachPlayerEffect; +import mage.abilities.effects.keyword.ScryEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.TargetController; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class OverwhelmedApprentice extends CardImpl { + + public OverwhelmedApprentice(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{U}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.WIZARD); + this.power = new MageInt(1); + this.toughness = new MageInt(2); + + // When Overwhelmed Apprentice enters the battlefield, each opponent puts the top two cards of their library into their graveyard. Then you scry 2. + Ability ability = new EntersBattlefieldTriggeredAbility( + new PutTopCardOfLibraryIntoGraveEachPlayerEffect(2, TargetController.OPPONENT) + ); + ability.addEffect(new ScryEffect(2).setText("Then you scry 2.")); + this.addAbility(ability); + } + + private OverwhelmedApprentice(final OverwhelmedApprentice card) { + super(card); + } + + @Override + public OverwhelmedApprentice copy() { + return new OverwhelmedApprentice(this); + } +} diff --git a/Mage.Sets/src/mage/cards/p/PatternMatcher.java b/Mage.Sets/src/mage/cards/p/PatternMatcher.java index 61844ffa6d..c53382c25e 100644 --- a/Mage.Sets/src/mage/cards/p/PatternMatcher.java +++ b/Mage.Sets/src/mage/cards/p/PatternMatcher.java @@ -19,9 +19,9 @@ import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.common.TargetCardInLibrary; -import java.util.ArrayList; import java.util.List; import java.util.UUID; +import java.util.stream.Collectors; /** * @author TheElk801 @@ -72,14 +72,16 @@ class RegularExpression extends OneShotEffect { if (player == null) { return false; } - List predicates = new ArrayList(); - game.getBattlefield() - .getAllActivePermanents( - StaticFilters.FILTER_CONTROLLED_ANOTHER_CREATURE, source.getControllerId(), game + List predicates = game + .getBattlefield() + .getActivePermanents( + StaticFilters.FILTER_CONTROLLED_ANOTHER_CREATURE, + source.getControllerId(), source.getSourceId(), game ).stream() .map(Permanent::getName) .filter(s -> !"".equals(s)) - .forEach(s -> predicates.add(new NamePredicate(s))); + .map(NamePredicate::new) + .collect(Collectors.toList()); FilterCard filter = new FilterCard("a creature card with the same name as another creature you control"); filter.add(Predicates.or(predicates)); diff --git a/Mage.Sets/src/mage/cards/p/PiperOfTheSwarm.java b/Mage.Sets/src/mage/cards/p/PiperOfTheSwarm.java index ceac31b061..028bd0c5c1 100644 --- a/Mage.Sets/src/mage/cards/p/PiperOfTheSwarm.java +++ b/Mage.Sets/src/mage/cards/p/PiperOfTheSwarm.java @@ -8,13 +8,15 @@ import mage.abilities.costs.common.SacrificeTargetCost; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.common.CreateTokenEffect; -import mage.abilities.effects.common.continuous.BoostControlledEffect; +import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; import mage.abilities.effects.common.continuous.GainControlTargetEffect; +import mage.abilities.keyword.MenaceAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.SubType; +import mage.filter.FilterPermanent; import mage.filter.common.FilterControlledPermanent; import mage.filter.common.FilterCreaturePermanent; import mage.game.permanent.token.RatToken; @@ -28,7 +30,7 @@ import java.util.UUID; */ public final class PiperOfTheSwarm extends CardImpl { - private static final FilterCreaturePermanent filter = new FilterCreaturePermanent(SubType.RAT, "Rats"); + private static final FilterPermanent filter = new FilterCreaturePermanent(SubType.RAT, "Rats"); private static final FilterControlledPermanent filter2 = new FilterControlledPermanent(SubType.RAT, "Rats"); public PiperOfTheSwarm(UUID ownerId, CardSetInfo setInfo) { @@ -41,7 +43,7 @@ public final class PiperOfTheSwarm extends CardImpl { // Rats you control have menace. this.addAbility(new SimpleStaticAbility( - new BoostControlledEffect(1, 1, Duration.WhileOnBattlefield, filter) + new GainAbilityControlledEffect(new MenaceAbility(), Duration.WhileOnBattlefield, filter) )); // {1}{B}, {T}: Create a 1/1 black Rat creature token. diff --git a/Mage.Sets/src/mage/cards/p/PrizedGriffin.java b/Mage.Sets/src/mage/cards/p/PrizedGriffin.java new file mode 100644 index 0000000000..5487a3b732 --- /dev/null +++ b/Mage.Sets/src/mage/cards/p/PrizedGriffin.java @@ -0,0 +1,36 @@ +package mage.cards.p; + +import mage.MageInt; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class PrizedGriffin extends CardImpl { + + public PrizedGriffin(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{W}"); + + this.subtype.add(SubType.GRIFFIN); + this.power = new MageInt(3); + this.toughness = new MageInt(4); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + } + + private PrizedGriffin(final PrizedGriffin card) { + super(card); + } + + @Override + public PrizedGriffin copy() { + return new PrizedGriffin(this); + } +} diff --git a/Mage.Sets/src/mage/cards/p/ProphetOfThePeak.java b/Mage.Sets/src/mage/cards/p/ProphetOfThePeak.java new file mode 100644 index 0000000000..3f55e1e3f2 --- /dev/null +++ b/Mage.Sets/src/mage/cards/p/ProphetOfThePeak.java @@ -0,0 +1,37 @@ +package mage.cards.p; + +import mage.MageInt; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.keyword.ScryEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ProphetOfThePeak extends CardImpl { + + public ProphetOfThePeak(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{6}"); + + this.subtype.add(SubType.CAT); + this.power = new MageInt(5); + this.toughness = new MageInt(5); + + // When Prophet of the Peak enters the battlefield, scry 2. + this.addAbility(new EntersBattlefieldTriggeredAbility(new ScryEffect(2))); + } + + private ProphetOfThePeak(final ProphetOfThePeak card) { + super(card); + } + + @Override + public ProphetOfThePeak copy() { + return new ProphetOfThePeak(this); + } +} diff --git a/Mage.Sets/src/mage/cards/p/ProteanHydra.java b/Mage.Sets/src/mage/cards/p/ProteanHydra.java index ca3820ba66..ad50c03001 100644 --- a/Mage.Sets/src/mage/cards/p/ProteanHydra.java +++ b/Mage.Sets/src/mage/cards/p/ProteanHydra.java @@ -38,7 +38,7 @@ public final class ProteanHydra extends CardImpl { this.addAbility(new EntersBattlefieldAbility(new EntersBattlefieldWithXCountersEffect(CounterType.P1P1.createInstance()))); // If damage would be dealt to Protean Hydra, prevent that damage and remove that many +1/+1 counters from it. - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new PreventDamageAndRemoveCountersEffect())); + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new PreventDamageAndRemoveCountersEffect(true))); // Whenever a +1/+1 counter is removed from Protean Hydra, put two +1/+1 counters on it at the beginning of the next end step. this.addAbility(new ProteanHydraAbility()); diff --git a/Mage.Sets/src/mage/cards/p/PufferExtract.java b/Mage.Sets/src/mage/cards/p/PufferExtract.java new file mode 100644 index 0000000000..8005874a67 --- /dev/null +++ b/Mage.Sets/src/mage/cards/p/PufferExtract.java @@ -0,0 +1,73 @@ +package mage.cards.p; + +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbility; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.DestroyTargetEffect; +import mage.abilities.effects.common.continuous.BoostTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.game.Game; +import mage.target.common.TargetControlledCreaturePermanent; +import mage.target.targetpointer.FixedTarget; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class PufferExtract extends CardImpl { + + public PufferExtract(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{5}"); + + // {X}, {T}: Target creature you control gets +X/+X until end of turn. Destroy it at the beginning of the next end step. + Ability ability = new SimpleActivatedAbility(new PufferExtractEffect(), new ManaCostsImpl("{X}")); + ability.addCost(new TapSourceCost()); + ability.addTarget(new TargetControlledCreaturePermanent()); + this.addAbility(ability); + } + + private PufferExtract(final PufferExtract card) { + super(card); + } + + @Override + public PufferExtract copy() { + return new PufferExtract(this); + } +} + +class PufferExtractEffect extends OneShotEffect { + + PufferExtractEffect() { + super(Outcome.Benefit); + staticText = "Target creature you control gets +X/+X until end of turn. " + + "Destroy it at the beginning of the next end step."; + } + + private PufferExtractEffect(final PufferExtractEffect effect) { + super(effect); + } + + @Override + public PufferExtractEffect copy() { + return new PufferExtractEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + int xValue = source.getManaCostsToPay().getX(); + game.addEffect(new BoostTargetEffect(xValue, xValue, Duration.EndOfTurn), source); + game.addDelayedTriggeredAbility(new AtTheBeginOfNextEndStepDelayedTriggeredAbility( + new DestroyTargetEffect().setTargetPointer(new FixedTarget(source.getFirstTarget(), game)) + ), source); + return true; + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/q/QueenOfIce.java b/Mage.Sets/src/mage/cards/q/QueenOfIce.java new file mode 100644 index 0000000000..0bbbf185f4 --- /dev/null +++ b/Mage.Sets/src/mage/cards/q/QueenOfIce.java @@ -0,0 +1,57 @@ +package mage.cards.q; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.DealsDamageToACreatureTriggeredAbility; +import mage.abilities.effects.common.DontUntapInControllersNextUntapStepTargetEffect; +import mage.abilities.effects.common.TapTargetEffect; +import mage.cards.AdventureCard; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class QueenOfIce extends AdventureCard { + + public QueenOfIce(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, new CardType[]{CardType.SORCERY}, "{2}{U}", "Rage of Winter", "{1}{U}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.NOBLE); + this.subtype.add(SubType.WIZARD); + this.power = new MageInt(2); + this.toughness = new MageInt(3); + + // Whenever Queen of Ice deals combat damage to a creature, tap that creature. It doesn't untap during its controller's next untap step. + Ability ability = new DealsDamageToACreatureTriggeredAbility( + new TapTargetEffect().setText("tap that creature."), + true, false, true + ); + ability.addEffect(new DontUntapInControllersNextUntapStepTargetEffect() + .setText("It doesn't untap during its controller's next untap step") + ); + this.addAbility(ability); + + // Rage of Winter + // Tap target creature. It doesn’t untap during its controller’s next untap step. + this.getAdventureSpellAbility().addEffect(new TapTargetEffect()); + this.getAdventureSpellAbility().addEffect(new DontUntapInControllersNextUntapStepTargetEffect() + .setText("It doesn't untap during its controller's next untap step")); + this.getAdventureSpellAbility().addTarget(new TargetCreaturePermanent()); + } + + private QueenOfIce(final QueenOfIce card) { + super(card); + } + + @Override + public QueenOfIce copy() { + return new QueenOfIce(this); + } +} +// let it go diff --git a/Mage.Sets/src/mage/cards/q/QuestingBeast.java b/Mage.Sets/src/mage/cards/q/QuestingBeast.java new file mode 100644 index 0000000000..0a4193b7ef --- /dev/null +++ b/Mage.Sets/src/mage/cards/q/QuestingBeast.java @@ -0,0 +1,157 @@ +package mage.cards.q; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.common.SimpleEvasionAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.ContinuousRuleModifyingEffectImpl; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.effects.common.combat.CantBeBlockedByCreaturesSourceEffect; +import mage.abilities.keyword.DeathtouchAbility; +import mage.abilities.keyword.HasteAbility; +import mage.abilities.keyword.VigilanceAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.common.FilterPlaneswalkerPermanent; +import mage.filter.predicate.mageobject.PowerPredicate; +import mage.filter.predicate.permanent.ControllerIdPredicate; +import mage.game.Game; +import mage.game.events.DamageEvent; +import mage.game.events.DamagedEvent; +import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.TargetPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class QuestingBeast extends CardImpl { + + private static final FilterCreaturePermanent filter + = new FilterCreaturePermanent("creatures with power 2 or less"); + + static { + filter.add(new PowerPredicate(ComparisonType.FEWER_THAN, 3)); + } + + public QuestingBeast(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{G}{G}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.BEAST); + this.power = new MageInt(4); + this.toughness = new MageInt(4); + + // Vigilance + this.addAbility(VigilanceAbility.getInstance()); + + // Deathtouch + this.addAbility(DeathtouchAbility.getInstance()); + + // Haste + this.addAbility(HasteAbility.getInstance()); + + // Questing Beast can't be blocked by creatures with power 2 or less. + this.addAbility(new SimpleEvasionAbility(new CantBeBlockedByCreaturesSourceEffect(filter, Duration.WhileOnBattlefield))); + + // Combat damage that would be dealt by creatures you control can't be prevented. + this.addAbility(new SimpleStaticAbility(new QuestingBeastPreventionEffect())); + + // Whenever Questing Beast deals combat damage to an opponent, it deals that much damage to target planeswalker that player controls. + this.addAbility(new QuestingBeastTriggeredAbility()); + } + + private QuestingBeast(final QuestingBeast card) { + super(card); + } + + @Override + public QuestingBeast copy() { + return new QuestingBeast(this); + } +} + +class QuestingBeastPreventionEffect extends ContinuousRuleModifyingEffectImpl { + + QuestingBeastPreventionEffect() { + super(Duration.WhileOnBattlefield, Outcome.Benefit); + staticText = "Combat damage that would be dealt by creatures you control can't be prevented."; + } + + private QuestingBeastPreventionEffect(final QuestingBeastPreventionEffect effect) { + super(effect); + } + + @Override + public QuestingBeastPreventionEffect copy() { + return new QuestingBeastPreventionEffect(this); + } + + @Override + public boolean checksEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.PREVENT_DAMAGE; + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + if (!((DamageEvent) event).isCombatDamage()) { + return false; + } + Permanent permanent = game.getPermanent(event.getSourceId()); + return permanent != null + && permanent.isCreature() + && permanent.isControlledBy(source.getControllerId()); + } +} + +class QuestingBeastTriggeredAbility extends TriggeredAbilityImpl { + + QuestingBeastTriggeredAbility() { + super(Zone.BATTLEFIELD, null, true); + } + + private QuestingBeastTriggeredAbility(final QuestingBeastTriggeredAbility ability) { + super(ability); + } + + @Override + public QuestingBeastTriggeredAbility copy() { + return new QuestingBeastTriggeredAbility(this); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.DAMAGED_PLAYER; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + Player opponent = game.getPlayer(event.getPlayerId()); + if (opponent == null + || !event.getSourceId().equals(this.getSourceId()) + || !opponent.hasOpponent(this.getControllerId(), game) + || !((DamagedEvent) event).isCombatDamage()) { + return false; + } + this.getEffects().clear(); + this.addEffect(new DamageTargetEffect(event.getAmount())); + FilterPermanent filter = new FilterPlaneswalkerPermanent("planeswalker " + opponent.getLogName() + " controls"); + filter.add(new ControllerIdPredicate(opponent.getId())); + this.getTargets().clear(); + this.addTarget(new TargetPermanent(filter)); + return true; + } + + @Override + public String getRule() { + return "Whenever {this} deals combat damage to an opponent, " + + "it deals that much damage to target planeswalker that player controls"; + } +} diff --git a/Mage.Sets/src/mage/cards/r/RagingRedcap.java b/Mage.Sets/src/mage/cards/r/RagingRedcap.java new file mode 100644 index 0000000000..4681a9673a --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/RagingRedcap.java @@ -0,0 +1,37 @@ +package mage.cards.r; + +import mage.MageInt; +import mage.abilities.keyword.DoubleStrikeAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class RagingRedcap extends CardImpl { + + public RagingRedcap(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{R}"); + + this.subtype.add(SubType.GOBLIN); + this.subtype.add(SubType.KNIGHT); + this.power = new MageInt(1); + this.toughness = new MageInt(2); + + // Double strike + this.addAbility(DoubleStrikeAbility.getInstance()); + } + + private RagingRedcap(final RagingRedcap card) { + super(card); + } + + @Override + public RagingRedcap copy() { + return new RagingRedcap(this); + } +} diff --git a/Mage.Sets/src/mage/cards/r/RallyForTheThrone.java b/Mage.Sets/src/mage/cards/r/RallyForTheThrone.java new file mode 100644 index 0000000000..86e39e86e9 --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/RallyForTheThrone.java @@ -0,0 +1,49 @@ +package mage.cards.r; + +import mage.abilities.condition.common.AdamantCondition; +import mage.abilities.decorator.ConditionalOneShotEffect; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.GainLifeEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.filter.StaticFilters; +import mage.game.permanent.token.HumanToken; +import mage.watchers.common.ManaSpentToCastWatcher; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class RallyForTheThrone extends CardImpl { + + private static final DynamicValue xValue + = new PermanentsOnBattlefieldCount(StaticFilters.FILTER_CONTROLLED_CREATURE); + + public RallyForTheThrone(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{W}"); + + // Create two 1/1 white Human creature tokens. + this.getSpellAbility().addEffect(new CreateTokenEffect(new HumanToken(), 2)); + + // Adamant — If at least three white mana was spent to cast this spell, you gain 1 life for each creature you control. + this.getSpellAbility().addEffect(new ConditionalOneShotEffect( + new GainLifeEffect(xValue), AdamantCondition.WHITE, "
Adamant — " + + "If at least three white mana was spent to cast this spell, " + + "you gain 1 life for each creature you control." + )); + this.getSpellAbility().addWatcher(new ManaSpentToCastWatcher()); + } + + private RallyForTheThrone(final RallyForTheThrone card) { + super(card); + } + + @Override + public RallyForTheThrone copy() { + return new RallyForTheThrone(this); + } +} diff --git a/Mage.Sets/src/mage/cards/r/RampartSmasher.java b/Mage.Sets/src/mage/cards/r/RampartSmasher.java new file mode 100644 index 0000000000..381abf43da --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/RampartSmasher.java @@ -0,0 +1,52 @@ +package mage.cards.r; + +import mage.MageInt; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.combat.CantBeBlockedByCreaturesSourceEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.SubtypePredicate; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class RampartSmasher extends CardImpl { + + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("Knights or Walls"); + + static { + filter.add(Predicates.or( + new SubtypePredicate(SubType.KNIGHT), + new SubtypePredicate(SubType.WALL) + )); + } + + public RampartSmasher(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{R/G}{R/G}{R/G}{R/G}"); + + this.subtype.add(SubType.GIANT); + this.power = new MageInt(5); + this.toughness = new MageInt(5); + + // Rampart Smasher can't be blocked by Knights or Walls. + this.addAbility(new SimpleStaticAbility( + new CantBeBlockedByCreaturesSourceEffect(filter, Duration.WhileOnBattlefield) + )); + } + + private RampartSmasher(final RampartSmasher card) { + super(card); + } + + @Override + public RampartSmasher copy() { + return new RampartSmasher(this); + } +} diff --git a/Mage.Sets/src/mage/cards/r/RankleMasterOfPranks.java b/Mage.Sets/src/mage/cards/r/RankleMasterOfPranks.java index 182ff06ed1..9686f52d2c 100644 --- a/Mage.Sets/src/mage/cards/r/RankleMasterOfPranks.java +++ b/Mage.Sets/src/mage/cards/r/RankleMasterOfPranks.java @@ -51,8 +51,9 @@ public final class RankleMasterOfPranks extends CardImpl { // • Each player sacrifices a creature. ability.addMode(new Mode(new SacrificeAllEffect(StaticFilters.FILTER_CONTROLLED_CREATURE_SHORT_TEXT))); - ability.getModes().setMinModes(0); + ability.getModes().setMinModes(1); ability.getModes().setMaxModes(3); + ability.getModes().setChooseText("choose any number —"); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/r/RayamiFirstOfTheFallen.java b/Mage.Sets/src/mage/cards/r/RayamiFirstOfTheFallen.java index 1aa9e4d039..dcdac69a32 100644 --- a/Mage.Sets/src/mage/cards/r/RayamiFirstOfTheFallen.java +++ b/Mage.Sets/src/mage/cards/r/RayamiFirstOfTheFallen.java @@ -18,6 +18,7 @@ import mage.game.permanent.Permanent; import mage.game.permanent.PermanentToken; import mage.players.Player; +import java.util.Collection; import java.util.UUID; /** @@ -76,25 +77,24 @@ class RayamiFirstOfTheFallenEffect extends ContinuousEffectImpl { .stream() .filter(Card::isCreature) .filter(card -> card.getCounters(game).getCount(CounterType.BLOOD) > 0) - .forEach(card -> { - card.getAbilities(game).stream().forEach(ability -> { - if (ability instanceof FlyingAbility - || ability instanceof FirstStrikeAbility - || ability instanceof DoubleStrikeAbility - || ability instanceof DeathtouchAbility - || ability instanceof HasteAbility - || ability instanceof HexproofAbility - || ability instanceof IndestructibleAbility - || ability instanceof LifelinkAbility - || ability instanceof MenaceAbility - || ability instanceof ReachAbility - || ability instanceof TrampleAbility - || ability instanceof VigilanceAbility) { - sourcePermanent.addAbility(ability, source.getSourceId(), game); - } else if (ability instanceof ProtectionAbility) { - sourcePermanent.addAbility(ability, source.getSourceId(), game); - } - }); + .map(card -> card.getAbilities(game)) + .flatMap(Collection::stream) + .forEach(ability -> { + if (ability instanceof FlyingAbility + || ability instanceof FirstStrikeAbility + || ability instanceof DoubleStrikeAbility + || ability instanceof DeathtouchAbility + || ability instanceof HasteAbility + || ability instanceof HexproofAbility + || ability instanceof IndestructibleAbility + || ability instanceof LifelinkAbility + || ability instanceof MenaceAbility + || ability instanceof ReachAbility + || ability instanceof TrampleAbility + || ability instanceof VigilanceAbility + || ability instanceof ProtectionAbility) { + sourcePermanent.addAbility(ability, source.getSourceId(), game); + } }); return true; } @@ -108,7 +108,7 @@ class RayamiFirstOfTheFallenEffect extends ContinuousEffectImpl { class RayamiFirstOfTheFallenReplacementEffect extends ReplacementEffectImpl { RayamiFirstOfTheFallenReplacementEffect() { - super(Duration.EndOfTurn, Outcome.Exile); + super(Duration.WhileOnBattlefield, Outcome.Exile); staticText = "If a nontoken creature would die, exile that card with a blood counter on it instead"; } diff --git a/Mage.Sets/src/mage/cards/r/RealmCloakedGiant.java b/Mage.Sets/src/mage/cards/r/RealmCloakedGiant.java new file mode 100644 index 0000000000..ea2c8bdd57 --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/RealmCloakedGiant.java @@ -0,0 +1,52 @@ +package mage.cards.r; + +import mage.MageInt; +import mage.abilities.effects.common.DestroyAllEffect; +import mage.abilities.keyword.VigilanceAbility; +import mage.cards.AdventureCard; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.SubtypePredicate; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class RealmCloakedGiant extends AdventureCard { + + private static final FilterCreaturePermanent filter + = new FilterCreaturePermanent("non-Giant creatures"); + + static { + filter.add(Predicates.not(new SubtypePredicate(SubType.GIANT))); + } + + public RealmCloakedGiant(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, new CardType[]{CardType.SORCERY}, "{5}{W}{W}", "{5}{W}{W}", "{3}{W}{W}"); + + this.subtype.add(SubType.GIANT); + this.power = new MageInt(7); + this.toughness = new MageInt(7); + + // Vigilance + this.addAbility(VigilanceAbility.getInstance()); + + // Cast Off + // Destroy all non-Giant creatures. + this.getAdventureSpellAbility().addEffect(new DestroyAllEffect(filter)); + } + + private RealmCloakedGiant(final RealmCloakedGiant card) { + super(card); + } + + @Override + public RealmCloakedGiant copy() { + return new RealmCloakedGiant(this); + } +} +// clock up diff --git a/Mage.Sets/src/mage/cards/r/ReaperOfNight.java b/Mage.Sets/src/mage/cards/r/ReaperOfNight.java new file mode 100644 index 0000000000..6bdd66b0da --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/ReaperOfNight.java @@ -0,0 +1,66 @@ +package mage.cards.r; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.AttacksTriggeredAbility; +import mage.abilities.condition.Condition; +import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; +import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; +import mage.abilities.effects.common.discard.DiscardTargetEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.AdventureCard; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.game.Game; +import mage.players.Player; +import mage.target.common.TargetOpponent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ReaperOfNight extends AdventureCard { + + public ReaperOfNight(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, new CardType[]{CardType.SORCERY}, "{5}{B}{B}", "Harvest Fear", "{3}{B}"); + + this.subtype.add(SubType.SPECTER); + this.power = new MageInt(4); + this.toughness = new MageInt(5); + + // Whenever Reaper of Night attacks, if defending player has two or fewer cards in hand, it gains flying until end of turn. + this.addAbility(new ConditionalInterveningIfTriggeredAbility( + new AttacksTriggeredAbility(new GainAbilitySourceEffect( + FlyingAbility.getInstance(), Duration.EndOfTurn + ), false), ReaperOfNightCondition.instance, "Whenever {this} attacks, " + + "if defending player has two or fewer cards in hand, it gains flying until end of turn." + )); + + // Harvest Fear + // Target opponent discards two cards. + this.getAdventureSpellAbility().addEffect(new DiscardTargetEffect(2)); + this.getAdventureSpellAbility().addTarget(new TargetOpponent()); + } + + private ReaperOfNight(final ReaperOfNight card) { + super(card); + } + + @Override + public ReaperOfNight copy() { + return new ReaperOfNight(this); + } +} + +enum ReaperOfNightCondition implements Condition { + instance; + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(game.getCombat().getDefendingPlayerId(source.getSourceId(), game)); + return player != null && player.getHand().size() <= 2; + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/r/RedcapMelee.java b/Mage.Sets/src/mage/cards/r/RedcapMelee.java new file mode 100644 index 0000000000..e0673a7be6 --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/RedcapMelee.java @@ -0,0 +1,72 @@ +package mage.cards.r; + +import mage.abilities.Ability; +import mage.abilities.effects.Effect; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.SacrificeControllerEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.target.common.TargetCreatureOrPlaneswalker; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class RedcapMelee extends CardImpl { + + public RedcapMelee(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{R}"); + + // Redcap Melee deals 4 damage to target creature or planeswalker. If a nonred permanent is dealt damage this way, you sacrifice a land. + this.getSpellAbility().addEffect(new RedcapMeleeEffect()); + this.getSpellAbility().addTarget(new TargetCreatureOrPlaneswalker()); + } + + private RedcapMelee(final RedcapMelee card) { + super(card); + } + + @Override + public RedcapMelee copy() { + return new RedcapMelee(this); + } +} + +class RedcapMeleeEffect extends OneShotEffect { + + private static final Effect effect = new SacrificeControllerEffect(StaticFilters.FILTER_LAND, 1, ""); + + RedcapMeleeEffect() { + super(Outcome.Benefit); + staticText = "{this} deals 4 damage to target creature or planeswalker. " + + "If a nonred permanent is dealt damage this way, you sacrifice a land."; + } + + private RedcapMeleeEffect(final RedcapMeleeEffect effect) { + super(effect); + } + + @Override + public RedcapMeleeEffect copy() { + return new RedcapMeleeEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent permanent = game.getPermanent(source.getFirstTarget()); + if (permanent == null) { + return false; + } + boolean isRed = permanent.getColor(game).isRed(); + if (permanent.damage(4, source.getSourceId(), game) > 0 && !isRed) { + return effect.apply(game, source); + } + return true; + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/r/RedcapRaiders.java b/Mage.Sets/src/mage/cards/r/RedcapRaiders.java new file mode 100644 index 0000000000..876af13159 --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/RedcapRaiders.java @@ -0,0 +1,62 @@ +package mage.cards.r; + +import mage.MageInt; +import mage.abilities.common.AttacksTriggeredAbility; +import mage.abilities.costs.common.TapTargetCost; +import mage.abilities.effects.common.DoIfCostPaid; +import mage.abilities.effects.common.continuous.BoostSourceEffect; +import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; +import mage.abilities.keyword.TrampleAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.common.FilterControlledPermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.SubtypePredicate; +import mage.filter.predicate.permanent.TappedPredicate; +import mage.target.common.TargetControlledPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class RedcapRaiders extends CardImpl { + + private static final FilterControlledPermanent filter + = new FilterControlledCreaturePermanent("an untapped non-Human creature you control"); + + static { + filter.add(Predicates.not(TappedPredicate.instance)); + filter.add(Predicates.not(new SubtypePredicate(SubType.HUMAN))); + } + + public RedcapRaiders(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{R}"); + + this.subtype.add(SubType.GOBLIN); + this.subtype.add(SubType.WARRIOR); + this.power = new MageInt(3); + this.toughness = new MageInt(2); + + // Whenever Redcap Raiders attacks, you may tap an untapped non-Human creature you control. If you do, Redcap Raiders gets +1/+1 and gains trample until end of turn. + this.addAbility(new AttacksTriggeredAbility(new DoIfCostPaid( + new BoostSourceEffect(1, 1, Duration.EndOfTurn).setText("{this} gets +1/+1"), + new TapTargetCost(new TargetControlledPermanent(filter)) + ).addEffect(new GainAbilitySourceEffect( + TrampleAbility.getInstance(), Duration.EndOfTurn + ).setText("and gains trample until end of turn")), false)); + } + + private RedcapRaiders(final RedcapRaiders card) { + super(card); + } + + @Override + public RedcapRaiders copy() { + return new RedcapRaiders(this); + } +} diff --git a/Mage.Sets/src/mage/cards/r/ReignOfTerror.java b/Mage.Sets/src/mage/cards/r/ReignOfTerror.java new file mode 100644 index 0000000000..c19cb0cd46 --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/ReignOfTerror.java @@ -0,0 +1,82 @@ +package mage.cards.r; + +import mage.ObjectColor; +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.filter.FilterPermanent; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.mageobject.ColorPredicate; +import mage.game.Game; +import mage.players.Player; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ReignOfTerror extends CardImpl { + + public ReignOfTerror(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{3}{B}{B}"); + + // Destroy all green creatures or all white creatures. They can't be regenerated. You lose 2 life for each creature that died this way. + this.getSpellAbility().addEffect(new ReignOfTerrorEffect()); + } + + private ReignOfTerror(final ReignOfTerror card) { + super(card); + } + + @Override + public ReignOfTerror copy() { + return new ReignOfTerror(this); + } +} + +class ReignOfTerrorEffect extends OneShotEffect { + + private static final FilterPermanent greenFilter = new FilterCreaturePermanent(); + private static final FilterPermanent whiteFilter = new FilterCreaturePermanent(); + + static { + greenFilter.add(new ColorPredicate(ObjectColor.GREEN)); + whiteFilter.add(new ColorPredicate(ObjectColor.WHITE)); + } + + ReignOfTerrorEffect() { + super(Outcome.Benefit); + staticText = "Destroy all green creatures or all white creatures. They can't be regenerated. " + + "You lose 2 life for each creature that died this way."; + } + + private ReignOfTerrorEffect(final ReignOfTerrorEffect effect) { + super(effect); + } + + @Override + public ReignOfTerrorEffect copy() { + return new ReignOfTerrorEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; + } + FilterPermanent filter = player.chooseUse( + outcome, "Destroy all green creatures or all white creatures?", + "", "Green", "White", source, game + ) ? greenFilter : whiteFilter; + int died = game.getBattlefield() + .getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game) + .stream() + .mapToInt(permanent -> permanent.destroy(source.getSourceId(), game, true) ? 1 : 0) + .sum(); + return player.loseLife(2 * died, game, false) > 0; + } +} diff --git a/Mage.Sets/src/mage/cards/r/RepelIntruders.java b/Mage.Sets/src/mage/cards/r/RepelIntruders.java index 93f8d7eabe..2e939e6783 100644 --- a/Mage.Sets/src/mage/cards/r/RepelIntruders.java +++ b/Mage.Sets/src/mage/cards/r/RepelIntruders.java @@ -31,10 +31,10 @@ public final class RepelIntruders extends CardImpl { target.setRequired(false); this.getSpellAbility().addEffect(new ConditionalOneShotEffect( new CreateTokenEffect(new KithkinToken(), 2), - new ManaWasSpentCondition(ColoredManaSymbol.W), "Create two 1/1 white Kithkin Soldier creature tokens if {W} was spent to cast {this}")); + new ManaWasSpentCondition(ColoredManaSymbol.W), "Create two 1/1 white Kithkin Soldier creature tokens if {W} was spent to cast this spell")); this.getSpellAbility().addEffect(new ConditionalOneShotEffect( new CounterTargetEffect(), - new ManaWasSpentCondition(ColoredManaSymbol.U), " Counter up to one target creature spell if {U} was spent to cast {this}")); + new ManaWasSpentCondition(ColoredManaSymbol.U), " Counter up to one target creature spell if {U} was spent to cast this spell")); this.getSpellAbility().addTarget(target); this.getSpellAbility().addEffect(new InfoEffect("(Do both if {W}{U} was spent.)")); this.getSpellAbility().addWatcher(new ManaSpentToCastWatcher()); diff --git a/Mage.Sets/src/mage/cards/r/ResoluteRider.java b/Mage.Sets/src/mage/cards/r/ResoluteRider.java new file mode 100644 index 0000000000..ed3b33441e --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/ResoluteRider.java @@ -0,0 +1,49 @@ +package mage.cards.r; + +import mage.MageInt; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; +import mage.abilities.keyword.IndestructibleAbility; +import mage.abilities.keyword.LifelinkAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ResoluteRider extends CardImpl { + + public ResoluteRider(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{W/B}{W/B}{W/B}{W/B}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.KNIGHT); + this.power = new MageInt(4); + this.toughness = new MageInt(2); + + // {W/B}{W/B}: Resolute Rider gains lifelink until end of turn. + this.addAbility(new SimpleActivatedAbility(new GainAbilitySourceEffect( + LifelinkAbility.getInstance(), Duration.EndOfTurn + ), new ManaCostsImpl("{W/B}{W/B}"))); + + // {W/B}{W/B}{W/B}: Resolute Rider gains indestructible until end of turn. + this.addAbility(new SimpleActivatedAbility(new GainAbilitySourceEffect( + IndestructibleAbility.getInstance(), Duration.EndOfTurn + ), new ManaCostsImpl("{W/B}{W/B}{W/B}"))); + } + + private ResoluteRider(final ResoluteRider card) { + super(card); + } + + @Override + public ResoluteRider copy() { + return new ResoluteRider(this); + } +} diff --git a/Mage.Sets/src/mage/cards/r/ReturnOfTheWildspeaker.java b/Mage.Sets/src/mage/cards/r/ReturnOfTheWildspeaker.java new file mode 100644 index 0000000000..ea0ae6927e --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/ReturnOfTheWildspeaker.java @@ -0,0 +1,84 @@ +package mage.cards.r; + +import mage.MageInt; +import mage.MageObject; +import mage.abilities.Ability; +import mage.abilities.Mode; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +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.SubType; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.SubtypePredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ReturnOfTheWildspeaker extends CardImpl { + + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("non-Human creatures"); + + static { + filter.add(Predicates.not(new SubtypePredicate(SubType.HUMAN))); + } + + public ReturnOfTheWildspeaker(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{4}{G}"); + + // Choose one — + // • Draw cards equal to the greatest power among non-Human creatures you control. + this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(ReturnOfTheWildspeakerValue.instance) + .setText("draw cards equal to the greatest power among non-Human creatures you control")); + + // • Non-Human creatures you control get +3/+3 until end of turn. + this.getSpellAbility().addMode(new Mode( + new BoostControlledEffect(3, 3, Duration.EndOfTurn, filter) + )); + } + + private ReturnOfTheWildspeaker(final ReturnOfTheWildspeaker card) { + super(card); + } + + @Override + public ReturnOfTheWildspeaker copy() { + return new ReturnOfTheWildspeaker(this); + } +} + +enum ReturnOfTheWildspeakerValue implements DynamicValue { + instance; + + @Override + public int calculate(Game game, Ability sourceAbility, Effect effect) { + return game.getBattlefield() + .getAllActivePermanents(sourceAbility.getControllerId()) + .stream() + .filter(Permanent::isCreature) + .filter(permanent -> !permanent.hasSubtype(SubType.HUMAN, game)) + .map(MageObject::getPower) + .mapToInt(MageInt::getValue) + .max() + .orElse(0); + } + + @Override + public DynamicValue copy() { + return instance; + } + + @Override + public String getMessage() { + return ""; + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/r/RevengeOfRavens.java b/Mage.Sets/src/mage/cards/r/RevengeOfRavens.java new file mode 100644 index 0000000000..e37f9a5ed6 --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/RevengeOfRavens.java @@ -0,0 +1,41 @@ +package mage.cards.r; + +import mage.abilities.Ability; +import mage.abilities.common.AttacksAllTriggeredAbility; +import mage.abilities.effects.common.GainLifeEffect; +import mage.abilities.effects.common.LoseLifeTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SetTargetPointer; +import mage.filter.StaticFilters; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class RevengeOfRavens extends CardImpl { + + public RevengeOfRavens(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{3}{B}"); + + // Whenever a creature attacks you or a planeswalker you control, that creature's controller loses 1 life and you gain 1 life. + Ability ability = new AttacksAllTriggeredAbility( + new LoseLifeTargetEffect(1).setText("that creature's controller loses 1 life"), + false, StaticFilters.FILTER_PERMANENT_CREATURE, + SetTargetPointer.PLAYER, true, true + ); + ability.addEffect(new GainLifeEffect(1).concatBy("and")); + this.addAbility(ability); + } + + private RevengeOfRavens(final RevengeOfRavens card) { + super(card); + } + + @Override + public RevengeOfRavens copy() { + return new RevengeOfRavens(this); + } +} diff --git a/Mage.Sets/src/mage/cards/r/RibbonsOfNight.java b/Mage.Sets/src/mage/cards/r/RibbonsOfNight.java index f503fc24bc..6294cfedec 100644 --- a/Mage.Sets/src/mage/cards/r/RibbonsOfNight.java +++ b/Mage.Sets/src/mage/cards/r/RibbonsOfNight.java @@ -36,7 +36,7 @@ public final class RibbonsOfNight extends CardImpl { //If {U} was spent to cast Ribbons of Night, draw a card. this.getSpellAbility().addEffect(new ConditionalOneShotEffect( new DrawCardSourceControllerEffect(1), - new ManaWasSpentCondition(ColoredManaSymbol.U), "If {U} was spent to cast {this}, draw a card")); + new ManaWasSpentCondition(ColoredManaSymbol.U), "If {U} was spent to cast this spell, draw a card")); } public RibbonsOfNight(final RibbonsOfNight card) { diff --git a/Mage.Sets/src/mage/cards/r/RimrockKnight.java b/Mage.Sets/src/mage/cards/r/RimrockKnight.java new file mode 100644 index 0000000000..929b181a06 --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/RimrockKnight.java @@ -0,0 +1,45 @@ +package mage.cards.r; + +import mage.MageInt; +import mage.abilities.common.CantBlockAbility; +import mage.abilities.effects.common.continuous.BoostTargetEffect; +import mage.cards.AdventureCard; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class RimrockKnight extends AdventureCard { + + public RimrockKnight(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, new CardType[]{CardType.INSTANT}, "{1}{R}", "Boulder Rush", "{R}"); + + this.subtype.add(SubType.DWARF); + this.subtype.add(SubType.KNIGHT); + this.power = new MageInt(3); + this.toughness = new MageInt(1); + + // Rimrock Knight can't block + this.addAbility(new CantBlockAbility()); + + // Boulder Rush + // Target creature gets +2/+0 until end of turn. + this.getAdventureSpellAbility().addEffect(new BoostTargetEffect(2, 0, Duration.EndOfTurn)); + this.getAdventureSpellAbility().addTarget(new TargetCreaturePermanent()); + } + + private RimrockKnight(final RimrockKnight card) { + super(card); + } + + @Override + public RimrockKnight copy() { + return new RimrockKnight(this); + } +} diff --git a/Mage.Sets/src/mage/cards/r/RiversGrasp.java b/Mage.Sets/src/mage/cards/r/RiversGrasp.java index e337929ba6..f050c73502 100644 --- a/Mage.Sets/src/mage/cards/r/RiversGrasp.java +++ b/Mage.Sets/src/mage/cards/r/RiversGrasp.java @@ -38,10 +38,10 @@ public final class RiversGrasp extends CardImpl { Target targetPlayer = new TargetPlayer(); this.getSpellAbility().addEffect(new ConditionalOneShotEffect( new ReturnToHandTargetEffect(), - new ManaWasSpentCondition(ColoredManaSymbol.U), "If {U} was spent to cast {this}, return up to one target creature to its owner's hand")); + new ManaWasSpentCondition(ColoredManaSymbol.U), "If {U} was spent to cast this spell, return up to one target creature to its owner's hand")); this.getSpellAbility().addEffect(new ConditionalOneShotEffect( new RiversGraspEffect(), - new ManaWasSpentCondition(ColoredManaSymbol.B), " If {B} was spent to cast {this}, target player reveals their hand, you choose a nonland card from it, then that player discards that card")); + new ManaWasSpentCondition(ColoredManaSymbol.B), " If {B} was spent to cast this spell, target player reveals their hand, you choose a nonland card from it, then that player discards that card")); this.getSpellAbility().addTarget(targetCreature); this.getSpellAbility().addTarget(targetPlayer); diff --git a/Mage.Sets/src/mage/cards/r/RobberOfTheRich.java b/Mage.Sets/src/mage/cards/r/RobberOfTheRich.java new file mode 100644 index 0000000000..923b51ecb1 --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/RobberOfTheRich.java @@ -0,0 +1,250 @@ +package mage.cards.r; + +import mage.MageInt; +import mage.MageObject; +import mage.abilities.Ability; +import mage.abilities.common.AttacksTriggeredAbility; +import mage.abilities.condition.Condition; +import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; +import mage.abilities.effects.AsThoughEffectImpl; +import mage.abilities.effects.AsThoughManaEffect; +import mage.abilities.effects.ContinuousEffect; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.keyword.HasteAbility; +import mage.abilities.keyword.ReachAbility; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.game.ExileZone; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; +import mage.players.ManaPoolItem; +import mage.players.Player; +import mage.target.targetpointer.FixedTarget; +import mage.util.CardUtil; +import mage.watchers.Watcher; + +import java.util.HashSet; +import java.util.Objects; +import java.util.Set; +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class RobberOfTheRich extends CardImpl { + + public RobberOfTheRich(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{R}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.ARCHER); + this.subtype.add(SubType.ROGUE); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // Reach + this.addAbility(ReachAbility.getInstance()); + + // Haste + this.addAbility(HasteAbility.getInstance()); + + // Whenever Robber of the Rich attacks, if defending player has more cards in hand than you, exile the top card of their library. During any turn you attacked with a Rogue, you may cast that card and you may spend mana as though it were mana of any color to cast that spell. + this.addAbility(new ConditionalInterveningIfTriggeredAbility( + new AttacksTriggeredAbility( + new RobberOfTheRichEffect(), false, "", SetTargetPointer.PLAYER + ), RobberOfTheRichCondition.instance, "Whenever {this} attacks, " + + "if defending player has more cards in hand than you, exile the top card of their library. " + + "During any turn you attacked with a Rogue, you may cast that card and " + + "you may spend mana as though it were mana of any color to cast that spell." + ), new RobberOfTheRichWatcher()); + } + + private RobberOfTheRich(final RobberOfTheRich card) { + super(card); + } + + @Override + public RobberOfTheRich copy() { + return new RobberOfTheRich(this); + } +} + +enum RobberOfTheRichCondition implements Condition { + instance; + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + Player player = game.getPlayer(game.getCombat().getDefendingPlayerId(source.getSourceId(), game)); + return controller != null && player != null && controller.getHand().size() < player.getHand().size(); + } +} + +class RobberOfTheRichEffect extends OneShotEffect { + + RobberOfTheRichEffect() { + super(Outcome.PutCreatureInPlay); + } + + private RobberOfTheRichEffect(final RobberOfTheRichEffect effect) { + super(effect); + } + + @Override + public RobberOfTheRichEffect copy() { + return new RobberOfTheRichEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + Player damagedPlayer = game.getPlayer(this.getTargetPointer().getFirst(game, source)); + if (controller == null || damagedPlayer == null) { + return false; + } + MageObject sourceObject = game.getObject(source.getSourceId()); + UUID exileId = CardUtil.getCardExileZoneId(game, source); + Card card = damagedPlayer.getLibrary().getFromTop(game); + if (card == null || sourceObject == null) { + return true; + } + // move card to exile + controller.moveCardToExileWithInfo(card, exileId, sourceObject.getIdName(), source.getSourceId(), game, Zone.LIBRARY, true); + // Add effects only if the card has a spellAbility (e.g. not for lands). + if (card.getSpellAbility() == null) { + return true; + } + // allow to cast the card + game.addEffect(new RobberOfTheRichCastFromExileEffect(card.getId(), exileId), source); + // and you may spend mana as though it were mana of any color to cast it + ContinuousEffect effect = new RobberOfTheRichSpendAnyManaEffect(); + effect.setTargetPointer(new FixedTarget(card.getId())); + game.addEffect(effect, source); + return true; + } +} + +class RobberOfTheRichCastFromExileEffect extends AsThoughEffectImpl { + + private UUID cardId; + private UUID exileId; + + RobberOfTheRichCastFromExileEffect(UUID cardId, UUID exileId) { + super(AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, Duration.Custom, Outcome.Benefit); + this.cardId = cardId; + this.exileId = exileId; + } + + private RobberOfTheRichCastFromExileEffect(final RobberOfTheRichCastFromExileEffect effect) { + super(effect); + this.cardId = effect.cardId; + this.exileId = effect.exileId; + } + + @Override + public boolean apply(Game game, Ability source) { + return true; + } + + @Override + public RobberOfTheRichCastFromExileEffect copy() { + return new RobberOfTheRichCastFromExileEffect(this); + } + + @Override + public boolean applies(UUID sourceId, Ability source, UUID affectedControllerId, Game game) { + RobberOfTheRichWatcher watcher = game.getState().getWatcher(RobberOfTheRichWatcher.class); + if (watcher == null || !watcher.getAttackedWithRogue(source.getControllerId())) { + return false; + } + if (!sourceId.equals(cardId) || !source.isControlledBy(affectedControllerId)) { + return false; + } + ExileZone exileZone = game.getState().getExile().getExileZone(exileId); + if (exileZone != null && exileZone.contains(cardId)) { + return true; + } + discard(); + return false; + } +} + +class RobberOfTheRichSpendAnyManaEffect extends AsThoughEffectImpl implements AsThoughManaEffect { + + RobberOfTheRichSpendAnyManaEffect() { + super(AsThoughEffectType.SPEND_OTHER_MANA, Duration.Custom, Outcome.Benefit); + } + + private RobberOfTheRichSpendAnyManaEffect(final RobberOfTheRichSpendAnyManaEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source) { + return true; + } + + @Override + public RobberOfTheRichSpendAnyManaEffect copy() { + return new RobberOfTheRichSpendAnyManaEffect(this); + } + + @Override + public boolean applies(UUID objectId, Ability source, UUID affectedControllerId, Game game) { + FixedTarget fixedTarget = ((FixedTarget) getTargetPointer()); + return source.isControlledBy(affectedControllerId) + && Objects.equals(objectId, fixedTarget.getTarget()) + && fixedTarget.getZoneChangeCounter() + 1 == game.getState().getZoneChangeCounter(objectId) + && game.getState().getZone(objectId) == Zone.STACK; + } + + @Override + public ManaType getAsThoughManaType(ManaType manaType, ManaPoolItem mana, UUID affectedControllerId, Ability source, Game game) { + return mana.getFirstAvailable(); + } +} + +class RobberOfTheRichWatcher extends Watcher { + + private Set rogueAttackers = new HashSet(); + + RobberOfTheRichWatcher() { + super(WatcherScope.GAME); + } + + private RobberOfTheRichWatcher(final RobberOfTheRichWatcher watcher) { + super(watcher); + this.rogueAttackers.addAll(watcher.rogueAttackers); + } + + @Override + public RobberOfTheRichWatcher copy() { + return new RobberOfTheRichWatcher(this); + } + + @Override + public void watch(GameEvent event, Game game) { + if (event.getType() != GameEvent.EventType.ATTACKER_DECLARED) { + return; + } + Permanent permanent = game.getPermanent(event.getSourceId()); + if (permanent == null || !permanent.hasSubtype(SubType.ROGUE, game)) { + return; + } + rogueAttackers.add(event.getPlayerId()); + } + + @Override + public void reset() { + super.reset(); + rogueAttackers.clear(); + } + + boolean getAttackedWithRogue(UUID playerId) { + return rogueAttackers.contains(playerId); + } +} + diff --git a/Mage.Sets/src/mage/cards/r/RollingSpoil.java b/Mage.Sets/src/mage/cards/r/RollingSpoil.java index ec99f76457..ef6341122e 100644 --- a/Mage.Sets/src/mage/cards/r/RollingSpoil.java +++ b/Mage.Sets/src/mage/cards/r/RollingSpoil.java @@ -30,7 +30,7 @@ public final class RollingSpoil extends CardImpl { // If {B} was spent to cast Rolling Spoil, all creatures get -1/-1 until end of turn. this.getSpellAbility().addEffect(new ConditionalContinuousEffect( new BoostAllEffect(-1, -1, Duration.EndOfTurn), - new ManaWasSpentCondition(ColoredManaSymbol.B), "If {B} was spent to cast {this}, all creatures get -1/-1 until end of turn")); + new ManaWasSpentCondition(ColoredManaSymbol.B), "If {B} was spent to cast this spell, all creatures get -1/-1 until end of turn")); } public RollingSpoil(final RollingSpoil card) { diff --git a/Mage.Sets/src/mage/cards/r/RosethornHalberd.java b/Mage.Sets/src/mage/cards/r/RosethornHalberd.java new file mode 100644 index 0000000000..ca2c55f834 --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/RosethornHalberd.java @@ -0,0 +1,61 @@ +package mage.cards.r; + +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.AttachEffect; +import mage.abilities.effects.common.continuous.BoostEquippedEffect; +import mage.abilities.keyword.EquipAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.SubtypePredicate; +import mage.target.TargetPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class RosethornHalberd extends CardImpl { + + private static final FilterPermanent filter + = new FilterControlledCreaturePermanent("non-Human creature you control"); + + static { + filter.add(Predicates.not(new SubtypePredicate(SubType.HUMAN))); + } + + public RosethornHalberd(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{G}"); + + this.subtype.add(SubType.EQUIPMENT); + + // When Rosethorn Halberd enters the battlefield, attach it to target non-Human creature you control. + Ability ability = new EntersBattlefieldTriggeredAbility( + new AttachEffect(Outcome.Benefit, "attach it to target non-Human creature you control") + ); + ability.addTarget(new TargetPermanent(filter)); + this.addAbility(ability); + + // Equipped creature gets +2/+1. + this.addAbility(new SimpleStaticAbility(new BoostEquippedEffect(2, 1))); + + // Equip {5} + this.addAbility(new EquipAbility(5)); + } + + private RosethornHalberd(final RosethornHalberd card) { + super(card); + } + + @Override + public RosethornHalberd copy() { + return new RosethornHalberd(this); + } +} diff --git a/Mage.Sets/src/mage/cards/r/RovingKeep.java b/Mage.Sets/src/mage/cards/r/RovingKeep.java new file mode 100644 index 0000000000..05f9af99ad --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/RovingKeep.java @@ -0,0 +1,57 @@ +package mage.cards.r; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.effects.common.combat.CanAttackAsThoughItDidntHaveDefenderSourceEffect; +import mage.abilities.effects.common.continuous.BoostSourceEffect; +import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; +import mage.abilities.keyword.DefenderAbility; +import mage.abilities.keyword.TrampleAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class RovingKeep extends CardImpl { + + public RovingKeep(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{7}"); + + this.subtype.add(SubType.WALL); + this.power = new MageInt(5); + this.toughness = new MageInt(7); + + // Defender + this.addAbility(DefenderAbility.getInstance()); + + // {7}: Roving Keep gets +2/+0 and gains trample until end of turn. It can attack this turn as though it didn't have defender. + Ability ability = new SimpleActivatedAbility( + new BoostSourceEffect(2, 0, Duration.EndOfTurn) + .setText("{this} gets +2/+0"), new GenericManaCost(7) + ); + ability.addEffect(new GainAbilitySourceEffect( + TrampleAbility.getInstance(), Duration.EndOfTurn + ).setText("and gains trample until end of turn.")); + ability.addEffect(new CanAttackAsThoughItDidntHaveDefenderSourceEffect(Duration.EndOfTurn) + .setText("It can attack this turn as though it didn't have defender")); + this.addAbility(ability); + } + + private RovingKeep(final RovingKeep card) { + super(card); + } + + @Override + public RovingKeep copy() { + return new RovingKeep(this); + } +} +// sexy hexy is back, baby! diff --git a/Mage.Sets/src/mage/cards/r/RowanFearlessSparkmage.java b/Mage.Sets/src/mage/cards/r/RowanFearlessSparkmage.java new file mode 100644 index 0000000000..ade68c0c67 --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/RowanFearlessSparkmage.java @@ -0,0 +1,76 @@ +package mage.cards.r; + +import mage.abilities.Ability; +import mage.abilities.LoyaltyAbility; +import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.effects.common.UntapAllEffect; +import mage.abilities.effects.common.combat.CantBlockTargetEffect; +import mage.abilities.effects.common.continuous.BoostTargetEffect; +import mage.abilities.effects.common.continuous.GainAbilityAllEffect; +import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; +import mage.abilities.effects.common.continuous.GainControlAllEffect; +import mage.abilities.keyword.FirstStrikeAbility; +import mage.abilities.keyword.HasteAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterCreaturePermanent; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class RowanFearlessSparkmage extends CardImpl { + + private static final FilterPermanent filter = new FilterCreaturePermanent("all creatures"); + + public RowanFearlessSparkmage(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.PLANESWALKER}, "{3}{R}{R}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.ROWAN); + this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(5)); + + // +1: Up to one target creature gets +3/+0 and gains first strike until end of turn. + Ability ability = new LoyaltyAbility(new BoostTargetEffect( + 3, 0, Duration.EndOfTurn + ).setText("Up to one target creature gets +3/+0"), 1); + ability.addEffect(new GainAbilityTargetEffect( + FirstStrikeAbility.getInstance(), Duration.EndOfTurn + ).setText("and gains first strike until end of turn")); + ability.addTarget(new TargetCreaturePermanent(0, 1)); + this.addAbility(ability); + + // −2: Rowan, Fearless Sparkmage deals 1 damage to each of up to two target creatures. Those creatures can't block this turn. + ability = new LoyaltyAbility(new DamageTargetEffect(1) + .setText("deals 1 damage to each of up to two target creatures."), -2); + ability.addEffect(new CantBlockTargetEffect(Duration.EndOfTurn) + .setText("Those creatures can't block this turn.")); + ability.addTarget(new TargetCreaturePermanent(0, 2)); + this.addAbility(ability); + + // −9: Gain control of all creatures until end of turn. Untap them. They gain haste until end of turn. + ability = new LoyaltyAbility(new GainControlAllEffect(Duration.EndOfTurn, filter), -9); + ability.addEffect(new UntapAllEffect(filter).setText("until end of turn. Untap them.")); + ability.addEffect(new GainAbilityAllEffect( + HasteAbility.getInstance(), Duration.EndOfTurn, filter + ).setText("They gain haste until end of turn")); + this.addAbility(ability); + } + + private RowanFearlessSparkmage(final RowanFearlessSparkmage card) { + super(card); + } + + @Override + public RowanFearlessSparkmage copy() { + return new RowanFearlessSparkmage(this); + } +} diff --git a/Mage.Sets/src/mage/cards/r/RowansBattleguard.java b/Mage.Sets/src/mage/cards/r/RowansBattleguard.java new file mode 100644 index 0000000000..5b2c730cf8 --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/RowansBattleguard.java @@ -0,0 +1,56 @@ +package mage.cards.r; + +import mage.MageInt; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.Condition; +import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; +import mage.abilities.decorator.ConditionalContinuousEffect; +import mage.abilities.effects.common.continuous.BoostSourceEffect; +import mage.abilities.keyword.FirstStrikeAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledPlaneswalkerPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class RowansBattleguard extends CardImpl { + + private static final FilterPermanent filter + = new FilterControlledPlaneswalkerPermanent(SubType.ROWAN); + private static final Condition condition + = new PermanentsOnTheBattlefieldCondition(filter); + + public RowansBattleguard(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{R}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.KNIGHT); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // First strike + this.addAbility(FirstStrikeAbility.getInstance()); + + // As long as you control a Rowan planeswalker, Rowan's Battleguard gets +3/+0. + this.addAbility(new SimpleStaticAbility(new ConditionalContinuousEffect( + new BoostSourceEffect(3, 0, Duration.WhileOnBattlefield), condition, + "As long as you control a Rowan planeswalker, {this} gets +3/+0" + ))); + } + + private RowansBattleguard(final RowansBattleguard card) { + super(card); + } + + @Override + public RowansBattleguard copy() { + return new RowansBattleguard(this); + } +} diff --git a/Mage.Sets/src/mage/cards/r/RowansStalwarts.java b/Mage.Sets/src/mage/cards/r/RowansStalwarts.java new file mode 100644 index 0000000000..1dbb4762f2 --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/RowansStalwarts.java @@ -0,0 +1,48 @@ +package mage.cards.r; + +import mage.MageInt; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.common.search.SearchLibraryGraveyardPutInHandEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.filter.FilterCard; +import mage.filter.predicate.mageobject.NamePredicate; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class RowansStalwarts extends CardImpl { + + private static final FilterCard filter = new FilterCard("Rowan, Fearless Sparkmage"); + + static { + filter.add(new NamePredicate("Rowan, Fearless Sparkmage")); + } + + public RowansStalwarts(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{R}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.KNIGHT); + this.power = new MageInt(5); + this.toughness = new MageInt(2); + + // When Rowan's Stalwarts enters the battlefield, you may search your library and/or graveyard for a card named Rowan, Fearless Sparkmage, reveal it, and put it into your hand. If you search your library this way, shuffle it. + this.addAbility(new EntersBattlefieldTriggeredAbility( + new SearchLibraryGraveyardPutInHandEffect(filter, false, true) + )); + } + + private RowansStalwarts(final RowansStalwarts card) { + super(card); + } + + @Override + public RowansStalwarts copy() { + return new RowansStalwarts(this); + } +} diff --git a/Mage.Sets/src/mage/cards/r/RunAwayTogether.java b/Mage.Sets/src/mage/cards/r/RunAwayTogether.java index 2b6f0628d4..03a7ecd3b3 100644 --- a/Mage.Sets/src/mage/cards/r/RunAwayTogether.java +++ b/Mage.Sets/src/mage/cards/r/RunAwayTogether.java @@ -5,11 +5,12 @@ import mage.abilities.effects.common.ReturnToHandTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.filter.StaticFilters; +import mage.filter.common.FilterCreaturePermanent; import mage.game.Game; import mage.game.permanent.Permanent; import mage.target.common.TargetCreaturePermanent; +import java.util.Objects; import java.util.UUID; /** @@ -21,7 +22,10 @@ public final class RunAwayTogether extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{U}"); // Choose two target creatures controlled by different players. Return those creatures to their owners' hands. - this.getSpellAbility().addEffect(new ReturnToHandTargetEffect(true)); + this.getSpellAbility().addEffect(new ReturnToHandTargetEffect(true) + .setText("Choose two target creatures controlled by different players. " + + "Return those creatures to their owners' hands.") + ); this.getSpellAbility().addTarget(new RunAwayTogetherTarget()); } @@ -37,8 +41,11 @@ public final class RunAwayTogether extends CardImpl { class RunAwayTogetherTarget extends TargetCreaturePermanent { + private static final FilterCreaturePermanent filter + = new FilterCreaturePermanent("creatures controlled by different players"); + RunAwayTogetherTarget() { - super(2, 2, StaticFilters.FILTER_PERMANENT_CREATURE, false); + super(2, 2, filter, false); } private RunAwayTogetherTarget(final RunAwayTogetherTarget target) { @@ -59,12 +66,12 @@ class RunAwayTogetherTarget extends TargetCreaturePermanent { if (creature == null) { return false; } - return !this.getTargets() + return this.getTargets() .stream() .map(game::getPermanent) - .anyMatch(permanent -> permanent != null - && !creature.getId().equals(permanent.getId()) - && !creature.isControlledBy(permanent.getControllerId()) + .filter(Objects::nonNull) + .noneMatch(permanent -> !creature.getId().equals(permanent.getId()) + && creature.isControlledBy(permanent.getControllerId()) ); } } diff --git a/Mage.Sets/src/mage/cards/s/SageOfTheFalls.java b/Mage.Sets/src/mage/cards/s/SageOfTheFalls.java new file mode 100644 index 0000000000..d8acc2ca0a --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SageOfTheFalls.java @@ -0,0 +1,51 @@ +package mage.cards.s; + +import mage.MageInt; +import mage.abilities.common.EntersBattlefieldControlledTriggeredAbility; +import mage.abilities.effects.common.DrawDiscardControllerEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.SubtypePredicate; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SageOfTheFalls extends CardImpl { + + private static final FilterPermanent filter + = new FilterCreaturePermanent("{this} or another non-Human creature"); + + static { + filter.add(Predicates.not(new SubtypePredicate(SubType.HUMAN))); + } + + public SageOfTheFalls(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{U}"); + + this.subtype.add(SubType.MERFOLK); + this.subtype.add(SubType.WIZARD); + this.power = new MageInt(2); + this.toughness = new MageInt(5); + + // Whenever Sage of the Falls or another non-Human creature enters the battlefield under you control, you may draw a card. If you do, discard a card. + this.addAbility(new EntersBattlefieldControlledTriggeredAbility( + new DrawDiscardControllerEffect(1, 1, true), filter + )); + } + + private SageOfTheFalls(final SageOfTheFalls card) { + super(card); + } + + @Override + public SageOfTheFalls copy() { + return new SageOfTheFalls(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SarpadianEmpiresVolVii.java b/Mage.Sets/src/mage/cards/s/SarpadianEmpiresVolVII.java similarity index 93% rename from Mage.Sets/src/mage/cards/s/SarpadianEmpiresVolVii.java rename to Mage.Sets/src/mage/cards/s/SarpadianEmpiresVolVII.java index a31d1760e2..8f54f958b3 100644 --- a/Mage.Sets/src/mage/cards/s/SarpadianEmpiresVolVii.java +++ b/Mage.Sets/src/mage/cards/s/SarpadianEmpiresVolVII.java @@ -21,7 +21,6 @@ import mage.game.permanent.token.CitizenToken; import mage.game.permanent.token.GoblinToken; import mage.game.permanent.token.SaprolingToken; import mage.game.permanent.token.ThrullToken; -import mage.game.permanent.token.TokenImpl; import mage.game.permanent.token.Token; import mage.players.Player; @@ -29,9 +28,9 @@ import mage.players.Player; * * @author LoneFox */ -public final class SarpadianEmpiresVolVii extends CardImpl { +public final class SarpadianEmpiresVolVII extends CardImpl { - public SarpadianEmpiresVolVii(UUID ownerId, CardSetInfo setInfo) { + public SarpadianEmpiresVolVII(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{3}"); // As Sarpadian Empires, Vol. VII enters the battlefield, choose white Citizen, blue Camarid, black Thrull, red Goblin, or green Saproling. @@ -42,13 +41,13 @@ public final class SarpadianEmpiresVolVii extends CardImpl { this.addAbility(ability); } - public SarpadianEmpiresVolVii(final SarpadianEmpiresVolVii card) { + public SarpadianEmpiresVolVII(final SarpadianEmpiresVolVII card) { super(card); } @Override - public SarpadianEmpiresVolVii copy() { - return new SarpadianEmpiresVolVii(this); + public SarpadianEmpiresVolVII copy() { + return new SarpadianEmpiresVolVII(this); } } diff --git a/Mage.Sets/src/mage/cards/s/ScaldingCauldron.java b/Mage.Sets/src/mage/cards/s/ScaldingCauldron.java new file mode 100644 index 0000000000..39d1685f3c --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/ScaldingCauldron.java @@ -0,0 +1,42 @@ +package mage.cards.s; + +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.SacrificeSourceCost; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ScaldingCauldron extends CardImpl { + + public ScaldingCauldron(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{1}"); + + // {3}, {T}, Sacrifice Scalding Cauldron: It deals 3 damage to target creature. + Ability ability = new SimpleActivatedAbility( + new DamageTargetEffect(3, "it"), new GenericManaCost(3) + ); + ability.addCost(new TapSourceCost()); + ability.addCost(new SacrificeSourceCost()); + ability.addTarget(new TargetCreaturePermanent()); + this.addAbility(ability); + } + + private ScaldingCauldron(final ScaldingCauldron card) { + super(card); + } + + @Override + public ScaldingCauldron copy() { + return new ScaldingCauldron(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/ScorchingDragonfire.java b/Mage.Sets/src/mage/cards/s/ScorchingDragonfire.java new file mode 100644 index 0000000000..c0ca25806e --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/ScorchingDragonfire.java @@ -0,0 +1,35 @@ +package mage.cards.s; + +import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.effects.common.ExileTargetIfDiesEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.target.common.TargetCreatureOrPlaneswalker; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ScorchingDragonfire extends CardImpl { + + public ScorchingDragonfire(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{R}"); + + // Scorching Dragonfire deals 3 damage to target creature or planeswalker. If that creature or planeswalker would die this turn, exile it instead. + this.getSpellAbility().addEffect(new DamageTargetEffect(3)); + this.getSpellAbility().addEffect(new ExileTargetIfDiesEffect() + .setText("If that creature or planeswalker would die this turn, exile it instead.")); + this.getSpellAbility().addTarget(new TargetCreatureOrPlaneswalker()); + } + + private ScorchingDragonfire(final ScorchingDragonfire card) { + super(card); + } + + @Override + public ScorchingDragonfire copy() { + return new ScorchingDragonfire(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SearingBarrage.java b/Mage.Sets/src/mage/cards/s/SearingBarrage.java new file mode 100644 index 0000000000..3032de92a3 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SearingBarrage.java @@ -0,0 +1,44 @@ +package mage.cards.s; + +import mage.abilities.condition.common.AdamantCondition; +import mage.abilities.decorator.ConditionalOneShotEffect; +import mage.abilities.effects.common.DamageTargetControllerEffect; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.target.common.TargetCreaturePermanent; +import mage.watchers.common.ManaSpentToCastWatcher; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SearingBarrage extends CardImpl { + + public SearingBarrage(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{4}{R}"); + + // Searing Barrage deals 5 damage to target creature. + this.getSpellAbility().addEffect(new DamageTargetEffect(5)); + this.getSpellAbility().addTarget(new TargetCreaturePermanent()); + + // Adamant — If at least three red mana was spent to cast this spell, Searing Barrage deals 3 damage to that creature's controller. + this.getSpellAbility().addEffect(new ConditionalOneShotEffect( + new DamageTargetControllerEffect(3), AdamantCondition.RED, + "
Adamant — If at least three red mana was spent to cast this spell, " + + "{this} deals 3 damage to that creature's controller." + )); + this.getSpellAbility().addWatcher(new ManaSpentToCastWatcher()); + } + + private SearingBarrage(final SearingBarrage card) { + super(card); + } + + @Override + public SearingBarrage copy() { + return new SearingBarrage(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SeasonedPyromancer.java b/Mage.Sets/src/mage/cards/s/SeasonedPyromancer.java index 64859e6951..f30bcf4b83 100644 --- a/Mage.Sets/src/mage/cards/s/SeasonedPyromancer.java +++ b/Mage.Sets/src/mage/cards/s/SeasonedPyromancer.java @@ -86,7 +86,7 @@ class SeasonedPyromancerEffect extends OneShotEffect { int toDiscard = Math.min(player.getHand().size(), 2); if (toDiscard > 0) { TargetCard target = new TargetCardInHand(toDiscard, StaticFilters.FILTER_CARD); - if (player.choose(outcome, player.getHand(), target, game)) { + if (player.choose(Outcome.Discard, player.getHand(), target, game)) { Cards cards = new CardsImpl(target.getTargets()); for (Card card : cards.getCards(game)) { if (player.discard(card, source, game) && !card.isLand()) { diff --git a/Mage.Sets/src/mage/cards/s/SeedSpark.java b/Mage.Sets/src/mage/cards/s/SeedSpark.java index 2d1a454dc2..291e2dec9b 100644 --- a/Mage.Sets/src/mage/cards/s/SeedSpark.java +++ b/Mage.Sets/src/mage/cards/s/SeedSpark.java @@ -31,7 +31,7 @@ public final class SeedSpark extends CardImpl { //If {G} was spent to cast Seed Spark, create two 1/1 green Saproling creature tokens. this.getSpellAbility().addEffect(new ConditionalOneShotEffect( new CreateTokenEffect(new SaprolingToken(), 2), - new ManaWasSpentCondition(ColoredManaSymbol.G), "If {G} was spent to cast {this}, create two 1/1 green Saproling creature tokens")); + new ManaWasSpentCondition(ColoredManaSymbol.G), "If {G} was spent to cast this spell, create two 1/1 green Saproling creature tokens")); } public SeedSpark(final SeedSpark card) { diff --git a/Mage.Sets/src/mage/cards/s/SevenDwarves.java b/Mage.Sets/src/mage/cards/s/SevenDwarves.java new file mode 100644 index 0000000000..03a6b1caa1 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SevenDwarves.java @@ -0,0 +1,64 @@ +package mage.cards.s; + +import mage.MageInt; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; +import mage.abilities.effects.common.InfoEffect; +import mage.abilities.effects.common.continuous.BoostSourceEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.constants.Zone; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.predicate.mageobject.NamePredicate; +import mage.filter.predicate.permanent.AnotherPredicate; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SevenDwarves extends CardImpl { + + private static final FilterPermanent filter = new FilterControlledCreaturePermanent(); + + static { + filter.add(AnotherPredicate.instance); + filter.add(new NamePredicate("Seven Dwarves")); + } + + private static final DynamicValue xValue = new PermanentsOnBattlefieldCount(filter); + + public SevenDwarves(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{R}"); + + this.subtype.add(SubType.DWARF); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // Seven Dwarves gets +1/+1 for each other creature named Seven Dwarves you control. + this.addAbility(new SimpleStaticAbility( + new BoostSourceEffect(xValue, xValue, Duration.WhileOnBattlefield).setText( + "{this} gets +1/+1 for each other creature named Seven Dwarves you control" + ) + )); + + // A deck can have up to seven cards named Seven Dwarves. + this.addAbility(new SimpleStaticAbility( + Zone.ALL, new InfoEffect("A deck can have up to seven cards named Seven Dwarves.") + )); + } + + private SevenDwarves(final SevenDwarves card) { + super(card); + } + + @Override + public SevenDwarves copy() { + return new SevenDwarves(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SevinneTheChronoclasm.java b/Mage.Sets/src/mage/cards/s/SevinneTheChronoclasm.java index 0c4600499d..79b6f7f918 100644 --- a/Mage.Sets/src/mage/cards/s/SevinneTheChronoclasm.java +++ b/Mage.Sets/src/mage/cards/s/SevinneTheChronoclasm.java @@ -54,7 +54,7 @@ public final class SevinneTheChronoclasm extends CardImpl { class SevinneTheChronoclasmTriggeredAbility extends SpellCastControllerTriggeredAbility { SevinneTheChronoclasmTriggeredAbility() { - super(Zone.BATTLEFIELD, null, StaticFilters.FILTER_SPELL_INSTANT_OR_SORCERY, false, true); + super(Zone.BATTLEFIELD, null, StaticFilters.FILTER_SPELL_INSTANT_OR_SORCERY, false, false); } private SevinneTheChronoclasmTriggeredAbility(final SevinneTheChronoclasmTriggeredAbility ability) { diff --git a/Mage.Sets/src/mage/cards/s/ShamblingSuit.java b/Mage.Sets/src/mage/cards/s/ShamblingSuit.java new file mode 100644 index 0000000000..43efe5a380 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/ShamblingSuit.java @@ -0,0 +1,50 @@ +package mage.cards.s; + +import mage.MageInt; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; +import mage.abilities.effects.common.continuous.SetPowerSourceEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterArtifactOrEnchantmentPermanent; +import mage.filter.predicate.permanent.ControllerPredicate; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ShamblingSuit extends CardImpl { + + private static final FilterPermanent filter + = new FilterArtifactOrEnchantmentPermanent("artifacts and/or enchantments you control"); + + static { + filter.add(new ControllerPredicate(TargetController.YOU)); + } + + private static final DynamicValue xValue = new PermanentsOnBattlefieldCount(filter); + + public ShamblingSuit(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{3}"); + + this.subtype.add(SubType.CONSTRUCT); + this.power = new MageInt(0); + this.toughness = new MageInt(3); + + // Shambling Suit's power is equal to the number of artifacts and/or enchantments you control. + this.addAbility(new SimpleStaticAbility(Zone.ALL, new SetPowerSourceEffect(xValue, Duration.EndOfGame))); + } + + private ShamblingSuit(final ShamblingSuit card) { + super(card); + } + + @Override + public ShamblingSuit copy() { + return new ShamblingSuit(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/ShepherdOfTheFlock.java b/Mage.Sets/src/mage/cards/s/ShepherdOfTheFlock.java new file mode 100644 index 0000000000..37c657ff45 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/ShepherdOfTheFlock.java @@ -0,0 +1,40 @@ +package mage.cards.s; + +import mage.MageInt; +import mage.abilities.effects.common.ReturnToHandTargetEffect; +import mage.cards.AdventureCard; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.target.common.TargetControlledPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ShepherdOfTheFlock extends AdventureCard { + + public ShepherdOfTheFlock(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, new CardType[]{CardType.INSTANT}, "{1}{W}", "Usher to Safety", "{W}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.PEASANT); + this.power = new MageInt(3); + this.toughness = new MageInt(1); + + // Usher to Safety + // Return target permanent you control to its owner’s hand. + this.getAdventureSpellAbility().addEffect(new ReturnToHandTargetEffect()); + this.getAdventureSpellAbility().addTarget(new TargetControlledPermanent()); + } + + private ShepherdOfTheFlock(final ShepherdOfTheFlock card) { + super(card); + } + + @Override + public ShepherdOfTheFlock copy() { + return new ShepherdOfTheFlock(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/Shriekhorn.java b/Mage.Sets/src/mage/cards/s/Shriekhorn.java index 62130c56e6..9cab21e01f 100644 --- a/Mage.Sets/src/mage/cards/s/Shriekhorn.java +++ b/Mage.Sets/src/mage/cards/s/Shriekhorn.java @@ -1,8 +1,5 @@ - - package mage.cards.s; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldAbility; import mage.abilities.common.SimpleActivatedAbility; @@ -13,26 +10,32 @@ import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Zone; import mage.counters.CounterType; import mage.target.TargetPlayer; +import java.util.UUID; + /** - * * @author Loki */ public final class Shriekhorn extends CardImpl { - public Shriekhorn (UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{1}"); - this.addAbility(new EntersBattlefieldAbility(new AddCountersSourceEffect(CounterType.CHARGE.createInstance(3)), "Shriekhorn enters the battlefield with three charge counters on it")); - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new PutLibraryIntoGraveTargetEffect(2), new TapSourceCost()); + public Shriekhorn(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{1}"); + + this.addAbility(new EntersBattlefieldAbility( + new AddCountersSourceEffect( + CounterType.CHARGE.createInstance(3) + ), "with three charge counters on it" + )); + + Ability ability = new SimpleActivatedAbility(new PutLibraryIntoGraveTargetEffect(2), new TapSourceCost()); ability.addCost(new RemoveCountersSourceCost(CounterType.CHARGE.createInstance())); ability.addTarget(new TargetPlayer()); this.addAbility(ability); } - public Shriekhorn (final Shriekhorn card) { + public Shriekhorn(final Shriekhorn card) { super(card); } diff --git a/Mage.Sets/src/mage/cards/s/ShriekingGrotesque.java b/Mage.Sets/src/mage/cards/s/ShriekingGrotesque.java index 4cc23ef06a..8303dd981d 100644 --- a/Mage.Sets/src/mage/cards/s/ShriekingGrotesque.java +++ b/Mage.Sets/src/mage/cards/s/ShriekingGrotesque.java @@ -36,7 +36,7 @@ public final class ShriekingGrotesque extends CardImpl { TriggeredAbility ability = new EntersBattlefieldTriggeredAbility(new DiscardTargetEffect(1), false); ability.addTarget(new TargetPlayer()); this.addAbility(new ConditionalInterveningIfTriggeredAbility(ability, new ManaWasSpentCondition(ColoredManaSymbol.B), - "if {B} was spent to cast {this}, target player discards a card."), new ManaSpentToCastWatcher()); + "if {B} was spent to cast this spell, target player discards a card."), new ManaSpentToCastWatcher()); } public ShriekingGrotesque(final ShriekingGrotesque card) { diff --git a/Mage.Sets/src/mage/cards/s/SignpostScarecrow.java b/Mage.Sets/src/mage/cards/s/SignpostScarecrow.java new file mode 100644 index 0000000000..a68cf6434c --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SignpostScarecrow.java @@ -0,0 +1,41 @@ +package mage.cards.s; + +import mage.MageInt; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.keyword.VigilanceAbility; +import mage.abilities.mana.AnyColorManaAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SignpostScarecrow extends CardImpl { + + public SignpostScarecrow(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{4}"); + + this.subtype.add(SubType.SCARECROW); + this.power = new MageInt(2); + this.toughness = new MageInt(4); + + // Vigilance + this.addAbility(VigilanceAbility.getInstance()); + + // {2}: Add one mana of any color. + this.addAbility(new AnyColorManaAbility(new GenericManaCost(2))); + } + + private SignpostScarecrow(final SignpostScarecrow card) { + super(card); + } + + @Override + public SignpostScarecrow copy() { + return new SignpostScarecrow(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SilentAssassin.java b/Mage.Sets/src/mage/cards/s/SilentAssassin.java new file mode 100644 index 0000000000..d433cbf48b --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SilentAssassin.java @@ -0,0 +1,54 @@ +package mage.cards.s; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.common.delayed.AtTheEndOfCombatDelayedTriggeredAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect; +import mage.abilities.effects.common.DestroyTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterBlockingCreature; +import mage.target.TargetPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SilentAssassin extends CardImpl { + + private static final FilterPermanent filter = new FilterBlockingCreature(); + + public SilentAssassin(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{B}{B}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.MERCENARY); + this.subtype.add(SubType.ASSASSIN); + this.power = new MageInt(2); + this.toughness = new MageInt(1); + + // {3}{B}: Destroy target blocking creature at end of combat. + Ability ability = new SimpleActivatedAbility(new CreateDelayedTriggeredAbilityEffect( + new AtTheEndOfCombatDelayedTriggeredAbility( + new DestroyTargetEffect().setText("destroy target blocking creature") + ), true + ), new ManaCostsImpl("{3}{B}")); + ability.addTarget(new TargetPermanent(filter)); + this.addAbility(ability); + } + + private SilentAssassin(final SilentAssassin card) { + super(card); + } + + @Override + public SilentAssassin copy() { + return new SilentAssassin(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SilverflameSquire.java b/Mage.Sets/src/mage/cards/s/SilverflameSquire.java new file mode 100644 index 0000000000..1e607a73ff --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SilverflameSquire.java @@ -0,0 +1,43 @@ +package mage.cards.s; + +import mage.MageInt; +import mage.abilities.effects.common.UntapTargetEffect; +import mage.abilities.effects.common.continuous.BoostTargetEffect; +import mage.cards.AdventureCard; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SilverflameSquire extends AdventureCard { + + public SilverflameSquire(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, new CardType[]{CardType.INSTANT}, "{1}{W}", "On Alert", "{2}{W}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.SOLDIER); + this.power = new MageInt(2); + this.toughness = new MageInt(1); + + // On Alert + // Target creature gets +2/+2 until end of turn. Untap it. + this.getAdventureSpellAbility().addEffect(new BoostTargetEffect(2, 2, Duration.EndOfTurn)); + this.getAdventureSpellAbility().addEffect(new UntapTargetEffect().setText("Untap it")); + this.getAdventureSpellAbility().addTarget(new TargetCreaturePermanent()); + } + + private SilverflameSquire(final SilverflameSquire card) { + super(card); + } + + @Override + public SilverflameSquire copy() { + return new SilverflameSquire(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SkullknockerOgre.java b/Mage.Sets/src/mage/cards/s/SkullknockerOgre.java new file mode 100644 index 0000000000..c4d453f514 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SkullknockerOgre.java @@ -0,0 +1,72 @@ +package mage.cards.s; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.DealsDamageToOpponentTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.game.Game; +import mage.players.Player; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SkullknockerOgre extends CardImpl { + + public SkullknockerOgre(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{R}"); + + this.subtype.add(SubType.OGRE); + this.power = new MageInt(4); + this.toughness = new MageInt(3); + + // Whenever Skullknocker Ogre deals damage to an opponent, that player discards a card at random. If the player does, they draw a card. + this.addAbility(new DealsDamageToOpponentTriggeredAbility( + new SkullknockerOgreEffect(), false, false, true + )); + } + + private SkullknockerOgre(final SkullknockerOgre card) { + super(card); + } + + @Override + public SkullknockerOgre copy() { + return new SkullknockerOgre(this); + } +} + +class SkullknockerOgreEffect extends OneShotEffect { + + SkullknockerOgreEffect() { + super(Outcome.Benefit); + staticText = "that player discards a card at random. If the player does, they draw a card"; + } + + private SkullknockerOgreEffect(final SkullknockerOgreEffect effect) { + super(effect); + } + + @Override + public SkullknockerOgreEffect copy() { + return new SkullknockerOgreEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(this.getTargetPointer().getFirst(game, source)); + if (player == null) { + return false; + } + if (player.discard(1, true, source, game).size() > 0) { + player.drawCards(1, game); + } + return true; + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/s/Snowblind.java b/Mage.Sets/src/mage/cards/s/Snowblind.java new file mode 100644 index 0000000000..ee0d055176 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/Snowblind.java @@ -0,0 +1,103 @@ +package mage.cards.s; + +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.AttachEffect; +import mage.abilities.effects.common.continuous.BoostEnchantedEffect; +import mage.abilities.keyword.EnchantAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterLandPermanent; +import mage.filter.predicate.mageobject.SupertypePredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.target.TargetPermanent; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class Snowblind extends CardImpl { + + public Snowblind(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{3}{G}"); + + this.subtype.add(SubType.AURA); + + // Enchant creature + TargetPermanent auraTarget = new TargetCreaturePermanent(); + this.getSpellAbility().addTarget(auraTarget); + this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); + Ability ability = new EnchantAbility(auraTarget.getTargetName()); + this.addAbility(ability); + + // Enchanted creature gets -X/-Y. If that creature is attacking, X is the number of snow lands defending player controls. Otherwise, X is the number of snow lands its controller controls. Y is equal to X or to enchanted creature's toughness minus 1, whichever is smaller. + this.addAbility(new SimpleStaticAbility(new BoostEnchantedEffect( + SnowblindValue.instanceX, SnowblindValue.instanceY, Duration.WhileOnBattlefield + ).setText("Enchanted creature gets -X/-Y. If that creature is attacking, " + + "X is the number of snow lands defending player controls. " + + "Otherwise, X is the number of snow lands its controller controls. " + + "Y is equal to X or to enchanted creature's toughness minus 1, whichever is smaller." + ))); + } + + private Snowblind(final Snowblind card) { + super(card); + } + + @Override + public Snowblind copy() { + return new Snowblind(this); + } +} + +enum SnowblindValue implements DynamicValue { + instanceX, + instanceY; + + private static final FilterPermanent filter = new FilterLandPermanent(); + + static { + filter.add(new SupertypePredicate(SuperType.SNOW)); + } + + @Override + public int calculate(Game game, Ability sourceAbility, Effect effect) { + Permanent sourcePerm = game.getPermanent(sourceAbility.getSourceId()); + if (sourcePerm == null) { + return 0; + } + Permanent permanent = game.getPermanent(sourcePerm.getAttachedTo()); + if (permanent == null) { + return 0; + } + int xValue = 0; + if (permanent.isAttacking()) { + xValue = game.getBattlefield().countAll( + filter, game.getCombat().getDefendingPlayerId(permanent.getId(), game), game + ); + } else { + xValue = game.getBattlefield().countAll(filter, permanent.getControllerId(), game); + } + if (this == instanceX) { + return -xValue; + } + return -Math.min(xValue, permanent.getToughness().getValue() - 1); + } + + @Override + public DynamicValue copy() { + return this; + } + + @Override + public String getMessage() { + return ""; + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/s/SoTiny.java b/Mage.Sets/src/mage/cards/s/SoTiny.java new file mode 100644 index 0000000000..6b41d69da8 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SoTiny.java @@ -0,0 +1,88 @@ +package mage.cards.s; + +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.dynamicvalue.common.StaticValue; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.AttachEffect; +import mage.abilities.effects.common.continuous.BoostEnchantedEffect; +import mage.abilities.keyword.EnchantAbility; +import mage.abilities.keyword.FlashAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.TargetPermanent; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SoTiny extends CardImpl { + + public SoTiny(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{U}"); + + this.subtype.add(SubType.AURA); + + // Flash + this.addAbility(FlashAbility.getInstance()); + + // Enchant creature + TargetPermanent auraTarget = new TargetCreaturePermanent(); + this.getSpellAbility().addTarget(auraTarget); + this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); + Ability ability = new EnchantAbility(auraTarget.getTargetName()); + this.addAbility(ability); + + // Enchanted creature gets -2/-0. It gets -6/-0 instead as long as its controller has seven or more cards in their graveyard. + this.addAbility(new SimpleStaticAbility( + new BoostEnchantedEffect(SoTinyValue.instance, StaticValue.getZeroValue()) + .setText("enchanted creature gets -2/-0. It gets -6/-0 instead as long as " + + "its controller has seven or more cards in their graveyard") + )); + } + + private SoTiny(final SoTiny card) { + super(card); + } + + @Override + public SoTiny copy() { + return new SoTiny(this); + } +} + +enum SoTinyValue implements DynamicValue { + instance; + + @Override + public int calculate(Game game, Ability sourceAbility, Effect effect) { + Permanent permanent = game.getPermanent(sourceAbility.getSourceId()); + if (permanent == null) { + return -2; + } + Player player = game.getPlayer(game.getControllerId(permanent.getAttachedTo())); + if (player == null || player.getGraveyard().size() < 7) { + return -2; + } + return -6; + } + + @Override + public DynamicValue copy() { + return instance; + } + + @Override + public String getMessage() { + return ""; + } +} diff --git a/Mage.Sets/src/mage/cards/s/SorcerersBroom.java b/Mage.Sets/src/mage/cards/s/SorcerersBroom.java new file mode 100644 index 0000000000..393347aafb --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SorcerersBroom.java @@ -0,0 +1,75 @@ +package mage.cards.s; + +import mage.MageInt; +import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.effects.CreateTokenCopySourceEffect; +import mage.abilities.effects.common.DoIfCostPaid; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.Zone; +import mage.game.Game; +import mage.game.events.GameEvent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SorcerersBroom extends CardImpl { + + public SorcerersBroom(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{2}"); + + this.subtype.add(SubType.SPIRIT); + this.power = new MageInt(2); + this.toughness = new MageInt(1); + + // Whenever you sacrifice another permanent, you may pay {3}. If you do, create a token that's a copy of Sorcerer's Broom. + this.addAbility(new SorcerersBroomTriggeredAbility()); + } + + private SorcerersBroom(final SorcerersBroom card) { + super(card); + } + + @Override + public SorcerersBroom copy() { + return new SorcerersBroom(this); + } +} + +class SorcerersBroomTriggeredAbility extends TriggeredAbilityImpl { + + SorcerersBroomTriggeredAbility() { + super(Zone.BATTLEFIELD, new DoIfCostPaid(new CreateTokenCopySourceEffect(), new GenericManaCost(3))); + } + + private SorcerersBroomTriggeredAbility(final SorcerersBroomTriggeredAbility ability) { + super(ability); + } + + @Override + public SorcerersBroomTriggeredAbility copy() { + return new SorcerersBroomTriggeredAbility(this); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.SACRIFICED_PERMANENT; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + return event.getPlayerId().equals(this.getControllerId()) + && !event.getTargetId().equals(sourceId); + } + + @Override + public String getRule() { + return "Whenever you sacrifice another permanent, you may pay {3}. " + + "If you do, create a token that's a copy of {this}"; + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/s/SpectersShriek.java b/Mage.Sets/src/mage/cards/s/SpectersShriek.java new file mode 100644 index 0000000000..0a5a41119e --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SpectersShriek.java @@ -0,0 +1,94 @@ +package mage.cards.s; + +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.constants.Zone; +import mage.filter.FilterCard; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.players.Player; +import mage.target.TargetCard; +import mage.target.common.TargetCardInHand; +import mage.target.common.TargetOpponent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SpectersShriek extends CardImpl { + + public SpectersShriek(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{B}"); + + // Target opponent reveals their hand. You may choose a nonland card from it. If you do, that player exiles that card. If a nonblack card is exiled this way, exile a card from your hand. + this.getSpellAbility().addEffect(new SpectersShriekEffect()); + this.getSpellAbility().addTarget(new TargetOpponent()); + } + + private SpectersShriek(final SpectersShriek card) { + super(card); + } + + @Override + public SpectersShriek copy() { + return new SpectersShriek(this); + } +} + +class SpectersShriekEffect extends OneShotEffect { + + private static final FilterCard filter = new FilterCard("card in your hand (to exile)"); + + SpectersShriekEffect() { + super(Outcome.Benefit); + staticText = "Target opponent reveals their hand. You may choose a nonland card from it. If you do, " + + "that player exiles that card. If a nonblack card is exiled this way, exile a card from your hand."; + } + + private SpectersShriekEffect(final SpectersShriekEffect effect) { + super(effect); + } + + @Override + public SpectersShriekEffect copy() { + return new SpectersShriekEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + Player player = game.getPlayer(source.getFirstTarget()); + if (controller == null || player == null) { + return false; + } + player.revealCards(source, player.getHand(), game); + if (player.getHand().count(StaticFilters.FILTER_CARD_NON_LAND, game) == 0 + || !controller.chooseUse(outcome, "Exile a card from " + player.getName() + "'s hand?", source, game)) { + return true; + } + TargetCard target = new TargetCardInHand(StaticFilters.FILTER_CARD_NON_LAND); + target.setNotTarget(true); + if (!controller.choose(outcome, player.getHand(), target, game)) { + return false; + } + Card card = game.getCard(target.getFirstTarget()); + if (card == null) { + return false; + } + boolean isBlack = card.getColor(game).isBlack(); + player.moveCards(card, Zone.EXILED, source, game); + if (isBlack || controller.getHand().isEmpty()) { + return true; + } + target = new TargetCardInHand(filter); + target.setNotTarget(true); + return controller.choose(outcome, controller.getHand(), target, game) + && controller.moveCards(game.getCard(target.getFirstTarget()), Zone.EXILED, source, game); + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/s/SphinxOfEnlightenment.java b/Mage.Sets/src/mage/cards/s/SphinxOfEnlightenment.java new file mode 100644 index 0000000000..9ba513d98c --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SphinxOfEnlightenment.java @@ -0,0 +1,47 @@ +package mage.cards.s; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.DrawCardTargetEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.target.common.TargetOpponent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SphinxOfEnlightenment extends CardImpl { + + public SphinxOfEnlightenment(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{U}{U}"); + + this.subtype.add(SubType.SPHINX); + this.power = new MageInt(5); + this.toughness = new MageInt(5); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // When Sphinx of Enlightenment enters the battlefield, target opponent draws a card and you draw three cards. + Ability ability = new EntersBattlefieldTriggeredAbility(new DrawCardTargetEffect(1)); + ability.addEffect(new DrawCardSourceControllerEffect(3).concatBy("and you")); + ability.addTarget(new TargetOpponent()); + this.addAbility(ability); + } + + private SphinxOfEnlightenment(final SphinxOfEnlightenment card) { + super(card); + } + + @Override + public SphinxOfEnlightenment copy() { + return new SphinxOfEnlightenment(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SpinningWheel.java b/Mage.Sets/src/mage/cards/s/SpinningWheel.java new file mode 100644 index 0000000000..f74bb2d6c8 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SpinningWheel.java @@ -0,0 +1,42 @@ +package mage.cards.s; + +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.effects.common.TapTargetEffect; +import mage.abilities.mana.AnyColorManaAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SpinningWheel extends CardImpl { + + public SpinningWheel(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{3}"); + + // {T}: Add one mana of any color. + this.addAbility(new AnyColorManaAbility()); + + // {5}, {T}: Tap target creature. + Ability ability = new SimpleActivatedAbility(new TapTargetEffect(), new GenericManaCost(5)); + ability.addCost(new TapSourceCost()); + ability.addTarget(new TargetCreaturePermanent()); + this.addAbility(ability); + } + + private SpinningWheel(final SpinningWheel card) { + super(card); + } + + @Override + public SpinningWheel copy() { + return new SpinningWheel(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SpiritFlare.java b/Mage.Sets/src/mage/cards/s/SpiritFlare.java new file mode 100644 index 0000000000..c2b78762f6 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SpiritFlare.java @@ -0,0 +1,94 @@ +package mage.cards.s; + +import mage.abilities.Ability; +import mage.abilities.costs.common.PayLifeCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.keyword.FlashbackAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.TargetController; +import mage.constants.TimingRule; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterAttackingOrBlockingCreature; +import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.permanent.ControllerPredicate; +import mage.filter.predicate.permanent.TappedPredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.target.TargetPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SpiritFlare extends CardImpl { + + private static final FilterPermanent filter + = new FilterControlledCreaturePermanent("untapped creature you control"); + private static final FilterPermanent filter2 + = new FilterAttackingOrBlockingCreature("attacking or blocking creature an opponent controls"); + + static { + filter.add(Predicates.not(TappedPredicate.instance)); + filter2.add(new ControllerPredicate(TargetController.OPPONENT)); + } + + public SpiritFlare(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{3}{W}"); + + // Tap target untapped creature you control. If you do, it deals damage equal to its power to target attacking or blocking creature an opponent controls. + this.getSpellAbility().addEffect(new SpiritFlareEffect()); + this.getSpellAbility().addTarget(new TargetPermanent(filter)); + this.getSpellAbility().addTarget(new TargetPermanent(filter2)); + + // Flashback-{1}{W}, Pay 3 life. + FlashbackAbility ability = new FlashbackAbility(new ManaCostsImpl("{1}{W}"), TimingRule.INSTANT); + ability.addCost(new PayLifeCost(3)); + this.addAbility(ability); + } + + private SpiritFlare(final SpiritFlare card) { + super(card); + } + + @Override + public SpiritFlare copy() { + return new SpiritFlare(this); + } +} + +class SpiritFlareEffect extends OneShotEffect { + + SpiritFlareEffect() { + super(Outcome.Benefit); + staticText = "tap target untapped creature you control. If you do, " + + "it deals damage equal to its power to target attacking or blocking creature an opponent controls"; + } + + private SpiritFlareEffect(final SpiritFlareEffect effect) { + super(effect); + } + + @Override + public SpiritFlareEffect copy() { + return new SpiritFlareEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent permanent = game.getPermanent(source.getFirstTarget()); + if (permanent == null || !permanent.tap(game)) { + return false; + } + Permanent permanent1 = game.getPermanent(source.getTargets().get(1).getFirstTarget()); + if (permanent1 == null) { + return false; + } + return permanent1.damage(permanent.getPower().getValue(), permanent.getId(), game) > 0; + } +} diff --git a/Mage.Sets/src/mage/cards/s/SpriteNoble.java b/Mage.Sets/src/mage/cards/s/SpriteNoble.java index 44888832a9..e59d4e4554 100644 --- a/Mage.Sets/src/mage/cards/s/SpriteNoble.java +++ b/Mage.Sets/src/mage/cards/s/SpriteNoble.java @@ -1,7 +1,5 @@ - package mage.cards.s; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.common.SimpleStaticAbility; @@ -11,16 +9,16 @@ import mage.abilities.keyword.FlyingAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Duration; +import mage.constants.SubType; import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.AbilityPredicate; -/** - * - * @author LoneFox +import java.util.UUID; +/** + * @author LoneFox */ public final class SpriteNoble extends CardImpl { @@ -31,8 +29,8 @@ public final class SpriteNoble extends CardImpl { } public SpriteNoble(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{U}{U}"); - this.subtype.add(SubType.FAERIE); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{U}{U}"); + this.subtype.add(SubType.FAERIE, SubType.NOBLE); this.power = new MageInt(2); this.toughness = new MageInt(2); @@ -42,7 +40,7 @@ public final class SpriteNoble extends CardImpl { this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostControlledEffect(0, 1, Duration.WhileOnBattlefield, filter, true))); // {tap}: Other creatures you control with flying get +1/+0 until end of turn. this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new BoostControlledEffect(1, 0, Duration.EndOfTurn, filter, true), - new TapSourceCost())); + new TapSourceCost())); } public SpriteNoble(final SpriteNoble card) { diff --git a/Mage.Sets/src/mage/cards/s/Stabilizer.java b/Mage.Sets/src/mage/cards/s/Stabilizer.java new file mode 100644 index 0000000000..bd70c9553e --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/Stabilizer.java @@ -0,0 +1,78 @@ +package mage.cards.s; + +import mage.MageObject; +import mage.abilities.Ability; +import mage.abilities.LoyaltyAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.ContinuousRuleModifyingEffectImpl; +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 java.util.UUID; + +/** + * @author TheElk801 + */ +public final class Stabilizer extends CardImpl { + + public Stabilizer(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{2}"); + + // Players can't cycle cards. + this.addAbility(new SimpleStaticAbility(new StabilizerEffect())); + } + + private Stabilizer(final Stabilizer card) { + super(card); + } + + @Override + public Stabilizer copy() { + return new Stabilizer(this); + } +} + +class StabilizerEffect extends ContinuousRuleModifyingEffectImpl { + + StabilizerEffect() { + super(Duration.WhileOnBattlefield, Outcome.Detriment); + staticText = "Players can't cycle cards"; + } + + private StabilizerEffect(final StabilizerEffect effect) { + super(effect); + } + + @Override + public StabilizerEffect copy() { + return new StabilizerEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + return true; + } + + @Override + public String getInfoMessage(Ability source, GameEvent event, Game game) { + MageObject mageObject = game.getObject(source.getSourceId()); + if (mageObject == null) { + return null; + } + return "You can't cycle cards (" + mageObject.getIdName() + ")."; + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + if (event.getType() != GameEvent.EventType.ACTIVATE_ABILITY) { + return false; + } + Ability ability = game.getAbility(event.getTargetId(), event.getSourceId()).orElse(null); + return ability instanceof LoyaltyAbility; + } +} diff --git a/Mage.Sets/src/mage/cards/s/SteamcoreWeird.java b/Mage.Sets/src/mage/cards/s/SteamcoreWeird.java index 6cc807ea45..8d3d998008 100644 --- a/Mage.Sets/src/mage/cards/s/SteamcoreWeird.java +++ b/Mage.Sets/src/mage/cards/s/SteamcoreWeird.java @@ -32,7 +32,7 @@ public final class SteamcoreWeird extends CardImpl { TriggeredAbility ability = new EntersBattlefieldTriggeredAbility(new DamageTargetEffect(2, "it")); ability.addTarget(new TargetAnyTarget()); this.addAbility(new ConditionalInterveningIfTriggeredAbility(ability, new ManaWasSpentCondition(ColoredManaSymbol.R), - "if {R} was spent to cast {this}, it deals 2 damage to any target."), + "if {R} was spent to cast this spell, it deals 2 damage to any target."), new ManaSpentToCastWatcher()); } diff --git a/Mage.Sets/src/mage/cards/s/SteelgazeGriffin.java b/Mage.Sets/src/mage/cards/s/SteelgazeGriffin.java new file mode 100644 index 0000000000..303869131e --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SteelgazeGriffin.java @@ -0,0 +1,42 @@ +package mage.cards.s; + +import mage.MageInt; +import mage.abilities.common.DrawSecondCardTriggeredAbility; +import mage.abilities.effects.common.continuous.BoostSourceEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SteelgazeGriffin extends CardImpl { + + public SteelgazeGriffin(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{U}"); + + this.subtype.add(SubType.GRIFFIN); + this.power = new MageInt(2); + this.toughness = new MageInt(4); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // When you draw your second card each turn, Steelgaze Griffin gets +2/+0 until end of turn. + this.addAbility(new DrawSecondCardTriggeredAbility(new BoostSourceEffect(2, 0, Duration.EndOfTurn), false)); + } + + private SteelgazeGriffin(final SteelgazeGriffin card) { + super(card); + } + + @Override + public SteelgazeGriffin copy() { + return new SteelgazeGriffin(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/StolenByTheFae.java b/Mage.Sets/src/mage/cards/s/StolenByTheFae.java new file mode 100644 index 0000000000..08fd09a589 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/StolenByTheFae.java @@ -0,0 +1,57 @@ +package mage.cards.s; + +import mage.abilities.Ability; +import mage.abilities.dynamicvalue.common.ManacostVariableValue; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.ReturnToHandTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.ComparisonType; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.mageobject.ConvertedManaCostPredicate; +import mage.game.Game; +import mage.game.permanent.token.FaerieToken; +import mage.target.common.TargetCreaturePermanent; +import mage.target.targetadjustment.TargetAdjuster; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class StolenByTheFae extends CardImpl { + + public StolenByTheFae(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{X}{U}{U}"); + + // Return target creature with converted mana cost X to its owner's hand. You create X 1/1 blue Faerie creature tokens with flying. + this.getSpellAbility().addEffect(new ReturnToHandTargetEffect() + .setText("Return target creature with converted mana cost X to its owner's hand.")); + this.getSpellAbility().addEffect(new CreateTokenEffect(new FaerieToken(), ManacostVariableValue.instance) + .setText("You create X 1/1 blue Faerie creature tokens with flying.")); + this.getSpellAbility().setTargetAdjuster(StolenByTheFaeAdjuster.instance); + } + + private StolenByTheFae(final StolenByTheFae card) { + super(card); + } + + @Override + public StolenByTheFae copy() { + return new StolenByTheFae(this); + } +} + +enum StolenByTheFaeAdjuster implements TargetAdjuster { + instance; + + @Override + public void adjustTargets(Ability ability, Game game) { + ability.getTargets().clear(); + int xValue = ability.getManaCostsToPay().getX(); + FilterCreaturePermanent filter = new FilterCreaturePermanent("creature with converted mana cost " + xValue); + filter.add(new ConvertedManaCostPredicate(ComparisonType.EQUAL_TO, xValue)); + ability.addTarget(new TargetCreaturePermanent(filter)); + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/s/StonecoilSerpent.java b/Mage.Sets/src/mage/cards/s/StonecoilSerpent.java new file mode 100644 index 0000000000..74c9c5047b --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/StonecoilSerpent.java @@ -0,0 +1,55 @@ +package mage.cards.s; + +import mage.MageInt; +import mage.abilities.common.EntersBattlefieldAbility; +import mage.abilities.effects.common.EntersBattlefieldWithXCountersEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.counters.CounterType; +import mage.abilities.keyword.ProtectionAbility; +import mage.filter.predicate.mageobject.MulticoloredPredicate; +import mage.filter.FilterObject; +import mage.abilities.keyword.ReachAbility; +import mage.abilities.keyword.TrampleAbility; + +import java.util.UUID; + +/** + * + * @author Tsirides + */ +public final class StonecoilSerpent extends CardImpl { + + private static final FilterObject filter = new FilterObject("multicolored"); + + static { + filter.add(MulticoloredPredicate.instance); + } + + public StonecoilSerpent(UUID ownerId, CardSetInfo setInfo) { + super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT,CardType.CREATURE},"{X}"); + this.subtype.add(SubType.SNAKE); + this.power = new MageInt(0); + this.toughness = new MageInt(0); + + //Trample, Reach, Protection from Multicolored + this.addAbility(new ProtectionAbility(filter)); + this.addAbility(ReachAbility.getInstance()); + this.addAbility(TrampleAbility.getInstance()); + + + // Endless One enters the battlefield with X +1/+1 counters on it. + this.addAbility(new EntersBattlefieldAbility(new EntersBattlefieldWithXCountersEffect(CounterType.P1P1.createInstance()))); + } + + public StonecoilSerpent(final StonecoilSerpent card) { + super(card); + } + + @Override + public StonecoilSerpent copy() { + return new StonecoilSerpent(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/StormfistCrusader.java b/Mage.Sets/src/mage/cards/s/StormfistCrusader.java new file mode 100644 index 0000000000..ab4d35ed3d --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/StormfistCrusader.java @@ -0,0 +1,50 @@ +package mage.cards.s; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; +import mage.abilities.dynamicvalue.common.StaticValue; +import mage.abilities.effects.common.DrawCardAllEffect; +import mage.abilities.effects.common.LoseLifeAllPlayersEffect; +import mage.abilities.keyword.MenaceAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.TargetController; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class StormfistCrusader extends CardImpl { + + public StormfistCrusader(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{B}{R}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.KNIGHT); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // Menace + this.addAbility(new MenaceAbility()); + + // At the beginning of your upkeep, each player draws a card and loses 1 life. + Ability ability = new BeginningOfUpkeepTriggeredAbility( + new DrawCardAllEffect(1), TargetController.YOU, false + ); + ability.addEffect(new LoseLifeAllPlayersEffect(new StaticValue(1), "and loses 1 life")); + this.addAbility(ability); + } + + private StormfistCrusader(final StormfistCrusader card) { + super(card); + } + + @Override + public StormfistCrusader copy() { + return new StormfistCrusader(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/StromkirkNoble.java b/Mage.Sets/src/mage/cards/s/StromkirkNoble.java index 03254100e4..1f75187de2 100644 --- a/Mage.Sets/src/mage/cards/s/StromkirkNoble.java +++ b/Mage.Sets/src/mage/cards/s/StromkirkNoble.java @@ -1,7 +1,5 @@ - package mage.cards.s; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; import mage.abilities.common.SimpleEvasionAbility; @@ -15,8 +13,9 @@ import mage.constants.SubType; import mage.counters.CounterType; import mage.filter.common.FilterCreaturePermanent; +import java.util.UUID; + /** - * * @author Alvin * @author ayratn */ @@ -24,7 +23,7 @@ public final class StromkirkNoble extends CardImpl { public StromkirkNoble(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{R}"); - this.subtype.add(SubType.VAMPIRE); + this.subtype.add(SubType.VAMPIRE, SubType.NOBLE); this.power = new MageInt(1); this.toughness = new MageInt(1); @@ -34,7 +33,6 @@ public final class StromkirkNoble extends CardImpl { new CantBeBlockedByCreaturesSourceEffect(new FilterCreaturePermanent(SubType.HUMAN, "Humans"), Duration.WhileOnBattlefield))); // Whenever Stromkirk Noble deals combat damage to a player, put a +1/+1 counter on it. this.addAbility(new DealsCombatDamageToAPlayerTriggeredAbility(new AddCountersSourceEffect(CounterType.P1P1.createInstance()), false)); - } public StromkirkNoble(final StromkirkNoble card) { diff --git a/Mage.Sets/src/mage/cards/s/SunderingStroke.java b/Mage.Sets/src/mage/cards/s/SunderingStroke.java new file mode 100644 index 0000000000..fb3feb97f9 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SunderingStroke.java @@ -0,0 +1,56 @@ +package mage.cards.s; + +import mage.abilities.Ability; +import mage.abilities.condition.Condition; +import mage.abilities.decorator.ConditionalOneShotEffect; +import mage.abilities.effects.common.DamageMultiEffect; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.hint.StaticHint; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.ColoredManaSymbol; +import mage.game.Game; +import mage.target.common.TargetAnyTargetAmount; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SunderingStroke extends CardImpl { + + public SunderingStroke(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{6}{R}"); + + // Sundering Stroke deals 7 damage divided as you choose among one, two, or three targets. If at least seven red mana was spent to cast this spell, instead Sundering Stroke deals 7 damage to each of those permanents and/or players. + this.getSpellAbility().addEffect(new ConditionalOneShotEffect( + new DamageTargetEffect(7), new DamageMultiEffect(7), SunderingStrokeCondtition.instance, + "{this} deals 7 damage divided as you choose among one, two, or three targets. " + + "If at least seven red mana was spent to cast this spell, " + + "instead {this} deals 7 damage to each of those permanents and/or players" + )); + this.getSpellAbility().addTarget(new TargetAnyTargetAmount(7, 3)); + this.getSpellAbility().addHint(new StaticHint( + "(You have to choose how 7 damage is divided even if you spend seven red mana)" + )); + } + + private SunderingStroke(final SunderingStroke card) { + super(card); + } + + @Override + public SunderingStroke copy() { + return new SunderingStroke(this); + } +} + +enum SunderingStrokeCondtition implements Condition { + instance; + + @Override + public boolean apply(Game game, Ability source) { + return source.getManaCostsToPay().getPayment().getColor(ColoredManaSymbol.R) >= 6; + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/s/SyrAlinTheLionsClaw.java b/Mage.Sets/src/mage/cards/s/SyrAlinTheLionsClaw.java new file mode 100644 index 0000000000..d34ae1e9f4 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SyrAlinTheLionsClaw.java @@ -0,0 +1,47 @@ +package mage.cards.s; + +import mage.MageInt; +import mage.abilities.common.AttacksTriggeredAbility; +import mage.abilities.effects.common.continuous.BoostControlledEffect; +import mage.abilities.keyword.FirstStrikeAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.constants.SuperType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SyrAlinTheLionsClaw extends CardImpl { + + public SyrAlinTheLionsClaw(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{W}{W}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.KNIGHT); + this.power = new MageInt(4); + this.toughness = new MageInt(4); + + // First strike + this.addAbility(FirstStrikeAbility.getInstance()); + + // Whenever Syr Alin, the Lion's Claw attacks, other creatures you control get +1/+1 until end of turn. + this.addAbility(new AttacksTriggeredAbility(new BoostControlledEffect( + 1, 1, Duration.EndOfTurn, true + ), false)); + } + + private SyrAlinTheLionsClaw(final SyrAlinTheLionsClaw card) { + super(card); + } + + @Override + public SyrAlinTheLionsClaw copy() { + return new SyrAlinTheLionsClaw(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SyrCarahTheBold.java b/Mage.Sets/src/mage/cards/s/SyrCarahTheBold.java new file mode 100644 index 0000000000..1a7a682d00 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SyrCarahTheBold.java @@ -0,0 +1,160 @@ +package mage.cards.s; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.effects.AsThoughEffectImpl; +import mage.abilities.effects.ContinuousEffect; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.effects.common.asthought.PlayFromNotOwnHandZoneTargetEffect; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; +import mage.game.stack.Spell; +import mage.players.Library; +import mage.players.Player; +import mage.target.common.TargetAnyTarget; +import mage.target.targetpointer.FixedTarget; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SyrCarahTheBold extends CardImpl { + + public SyrCarahTheBold(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{R}{R}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.KNIGHT); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // When Syr Carah, the Bold or an instant or sorcery spell you control deals damage to a player, exile the top card of your library. You may play that card this turn. + this.addAbility(new SyrCarahTheBoldTriggeredAbility()); + + // {T}: Syr Carah deals 1 damage to any target. + Ability ability = new SimpleActivatedAbility(new DamageTargetEffect(1), new TapSourceCost()); + ability.addTarget(new TargetAnyTarget()); + this.addAbility(ability); + } + + private SyrCarahTheBold(final SyrCarahTheBold card) { + super(card); + } + + @Override + public SyrCarahTheBold copy() { + return new SyrCarahTheBold(this); + } +} + +class SyrCarahTheBoldTriggeredAbility extends TriggeredAbilityImpl { + + SyrCarahTheBoldTriggeredAbility() { + super(Zone.BATTLEFIELD, new SyrCarahTheBoldExileEffect(), false); + } + + private SyrCarahTheBoldTriggeredAbility(final SyrCarahTheBoldTriggeredAbility ability) { + super(ability); + } + + @Override + public SyrCarahTheBoldTriggeredAbility copy() { + return new SyrCarahTheBoldTriggeredAbility(this); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.DAMAGED_PLAYER; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + if (event.getSourceId().equals(this.getSourceId())) { + return true; + } + Spell spell = game.getSpellOrLKIStack(event.getSourceId()); + return spell != null && spell.isInstantOrSorcery() + && spell.isControlledBy(this.getControllerId()); + } + + @Override + public String getRule() { + return "Whenever {this} or an instant or sorcery spell you control deals damage to a player, " + + "exile the top card of your library. You may play that card this turn."; + } + +} + +class SyrCarahTheBoldExileEffect extends OneShotEffect { + + SyrCarahTheBoldExileEffect() { + super(Outcome.Detriment); + } + + private SyrCarahTheBoldExileEffect(final SyrCarahTheBoldExileEffect effect) { + super(effect); + } + + @Override + public SyrCarahTheBoldExileEffect copy() { + return new SyrCarahTheBoldExileEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + Permanent sourcePermanent = game.getPermanentOrLKIBattlefield(source.getSourceId()); + if (sourcePermanent == null || controller == null || !controller.getLibrary().hasCards()) { + return false; + } + Library library = controller.getLibrary(); + Card card = library.getFromTop(game); + if (card == null) { + return true; + } + String exileName = sourcePermanent.getIdName() + " "; + controller.moveCardsToExile(card, source, game, true, source.getSourceId(), exileName); + ContinuousEffect effect = new PlayFromNotOwnHandZoneTargetEffect(Duration.EndOfTurn); + effect.setTargetPointer(new FixedTarget(card.getId(), card.getZoneChangeCounter(game))); + game.addEffect(effect, source); + return true; + } +} + +class SyrCarahTheBoldCastFromExileEffect extends AsThoughEffectImpl { + + SyrCarahTheBoldCastFromExileEffect() { + super(AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, Duration.EndOfTurn, Outcome.Benefit); + } + + private SyrCarahTheBoldCastFromExileEffect(final SyrCarahTheBoldCastFromExileEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source) { + return true; + } + + @Override + public SyrCarahTheBoldCastFromExileEffect copy() { + return new SyrCarahTheBoldCastFromExileEffect(this); + } + + @Override + public boolean applies(UUID objectId, Ability source, UUID affectedControllerId, Game game) { + return source.isControlledBy(affectedControllerId) + && objectId.equals(getTargetPointer().getFirst(game, source)); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SyrElenoraTheDiscerning.java b/Mage.Sets/src/mage/cards/s/SyrElenoraTheDiscerning.java new file mode 100644 index 0000000000..0be6760519 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SyrElenoraTheDiscerning.java @@ -0,0 +1,100 @@ +package mage.cards.s; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.Mode; +import mage.abilities.SpellAbility; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.dynamicvalue.common.CardsInControllerHandCount; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.continuous.SetPowerSourceEffect; +import mage.abilities.effects.common.cost.CostModificationEffectImpl; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.game.Game; +import mage.target.Target; +import mage.util.CardUtil; + +import java.util.Collection; +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SyrElenoraTheDiscerning extends CardImpl { + + public SyrElenoraTheDiscerning(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{U}{U}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.KNIGHT); + this.power = new MageInt(0); + this.toughness = new MageInt(4); + + // Syr Elenora the Discerning's power is equal to the number of cards in your hand. + this.addAbility(new SimpleStaticAbility( + Zone.ALL, new SetPowerSourceEffect(CardsInControllerHandCount.instance, Duration.EndOfGame) + )); + + // When Syr Elenora enters the battlefield, draw a card. + this.addAbility(new EntersBattlefieldTriggeredAbility(new DrawCardSourceControllerEffect(1))); + + // Spells your opponents cast that target Syr Elenora cost {2} more to cast. + this.addAbility(new SimpleStaticAbility(new SyrElenoraTheDiscerningCostIncreaseEffect())); + } + + private SyrElenoraTheDiscerning(final SyrElenoraTheDiscerning card) { + super(card); + } + + @Override + public SyrElenoraTheDiscerning copy() { + return new SyrElenoraTheDiscerning(this); + } +} + +class SyrElenoraTheDiscerningCostIncreaseEffect extends CostModificationEffectImpl { + + SyrElenoraTheDiscerningCostIncreaseEffect() { + super(Duration.WhileOnBattlefield, Outcome.Benefit, CostModificationType.INCREASE_COST); + staticText = "Spells your opponents cast that target {this} cost {2} more to cast"; + } + + private SyrElenoraTheDiscerningCostIncreaseEffect(SyrElenoraTheDiscerningCostIncreaseEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source, Ability abilityToModify) { + SpellAbility spellAbility = (SpellAbility) abilityToModify; + CardUtil.adjustCost(spellAbility, -2); + return true; + } + + @Override + public boolean applies(Ability abilityToModify, Ability source, Game game) { + if (!(abilityToModify instanceof SpellAbility) + || !game.getOpponents(source.getControllerId()).contains(abilityToModify.getControllerId())) { + return false; + } + return abilityToModify + .getModes() + .getSelectedModes() + .stream() + .map(uuid -> abilityToModify.getModes().get(uuid)) + .map(Mode::getTargets) + .flatMap(Collection::stream) + .map(Target::getTargets) + .flatMap(Collection::stream) + .anyMatch(uuid -> uuid.equals(source.getSourceId())); + } + + @Override + public SyrElenoraTheDiscerningCostIncreaseEffect copy() { + return new SyrElenoraTheDiscerningCostIncreaseEffect(this); + } + +} diff --git a/Mage.Sets/src/mage/cards/s/SyrFarenTheHengehammer.java b/Mage.Sets/src/mage/cards/s/SyrFarenTheHengehammer.java new file mode 100644 index 0000000000..85b8461de3 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SyrFarenTheHengehammer.java @@ -0,0 +1,60 @@ +package mage.cards.s; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.AttacksTriggeredAbility; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.dynamicvalue.common.SourcePermanentPowerCount; +import mage.abilities.effects.common.continuous.BoostTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterAttackingCreature; +import mage.filter.predicate.permanent.AnotherPredicate; +import mage.target.TargetPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SyrFarenTheHengehammer extends CardImpl { + + private static final DynamicValue xValue = new SourcePermanentPowerCount(); + private static final FilterPermanent filter + = new FilterAttackingCreature("another target attacking creature"); + + static { + filter.add(AnotherPredicate.instance); + } + + public SyrFarenTheHengehammer(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{G}{G}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.KNIGHT); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // Whenever Syr Faren, the Hengehammer attacks, another target attacking creature gets +X/+X until end of turn, where X is Syr Faren's power. + Ability ability = new AttacksTriggeredAbility( + new BoostTargetEffect(xValue, xValue, Duration.EndOfTurn, true), false + ); + ability.addTarget(new TargetPermanent(filter)); + this.addAbility(ability); + } + + private SyrFarenTheHengehammer(final SyrFarenTheHengehammer card) { + super(card); + } + + @Override + public SyrFarenTheHengehammer copy() { + return new SyrFarenTheHengehammer(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SyrKonradTheGrim.java b/Mage.Sets/src/mage/cards/s/SyrKonradTheGrim.java index 6f3cffaebe..967fc74452 100644 --- a/Mage.Sets/src/mage/cards/s/SyrKonradTheGrim.java +++ b/Mage.Sets/src/mage/cards/s/SyrKonradTheGrim.java @@ -65,13 +65,14 @@ class SyrKonradTheGrimTriggeredAbility extends TriggeredAbilityImpl { } @Override - public boolean checkTrigger(GameEvent event, Game game) { + public boolean checkEventType(GameEvent event, Game game) { return event.getType() == GameEvent.EventType.ZONE_CHANGE; } @Override - public boolean checkEventType(GameEvent event, Game game) { + public boolean checkTrigger(GameEvent event, Game game) { ZoneChangeEvent zEvent = (ZoneChangeEvent) event; + // Whenever another creature dies if (zEvent.isDiesEvent() && zEvent.getTarget() != null && !zEvent.getTargetId().equals(this.getSourceId()) @@ -79,6 +80,7 @@ class SyrKonradTheGrimTriggeredAbility extends TriggeredAbilityImpl { return true; } Card card = game.getCard(zEvent.getTargetId()); + // Or a creature card is put into a graveyard from anywhere other than the battlefield if (card == null || !card.isCreature()) { return false; } @@ -86,7 +88,9 @@ class SyrKonradTheGrimTriggeredAbility extends TriggeredAbilityImpl { && zEvent.getFromZone() != Zone.BATTLEFIELD) { return true; } - return zEvent.getFromZone() == Zone.GRAVEYARD; + // Or a creature card leaves your graveyard + return zEvent.getFromZone() == Zone.GRAVEYARD + && zEvent.getPlayerId() == this.getControllerId(); } @Override @@ -95,4 +99,4 @@ class SyrKonradTheGrimTriggeredAbility extends TriggeredAbilityImpl { "from anywhere other than the battlefield, or a creature card leaves your graveyard, " + "{this} deals 1 damage to each opponent."; } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/cards/t/TallAsABeanstalk.java b/Mage.Sets/src/mage/cards/t/TallAsABeanstalk.java new file mode 100644 index 0000000000..fbb5509206 --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TallAsABeanstalk.java @@ -0,0 +1,57 @@ +package mage.cards.t; + +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.AttachEffect; +import mage.abilities.effects.common.continuous.AddCardSubtypeAttachedEffect; +import mage.abilities.effects.common.continuous.BoostEnchantedEffect; +import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect; +import mage.abilities.keyword.EnchantAbility; +import mage.abilities.keyword.ReachAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.target.TargetPermanent; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class TallAsABeanstalk extends CardImpl { + + public TallAsABeanstalk(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{3}{G}"); + + this.subtype.add(SubType.AURA); + + // Enchant creature + TargetPermanent auraTarget = new TargetCreaturePermanent(); + this.getSpellAbility().addTarget(auraTarget); + this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); + Ability ability = new EnchantAbility(auraTarget.getTargetName()); + this.addAbility(ability); + + // Enchanted creature gets +3/+3, has reach, and is a Giant in addition to its other types. + ability = new SimpleStaticAbility( + new BoostEnchantedEffect(3, 3).setText("enchanted creature gets +3/+3,") + ); + ability.addEffect(new GainAbilityAttachedEffect( + ReachAbility.getInstance(), AttachmentType.AURA + ).setText("has reach,")); + ability.addEffect(new AddCardSubtypeAttachedEffect( + SubType.GIANT, Duration.WhileOnBattlefield, AttachmentType.AURA + ).setText("and is a Giant in addition to its other types")); + this.addAbility(ability); + } + + private TallAsABeanstalk(final TallAsABeanstalk card) { + super(card); + } + + @Override + public TallAsABeanstalk copy() { + return new TallAsABeanstalk(this); + } +} diff --git a/Mage.Sets/src/mage/cards/t/TemptingWitch.java b/Mage.Sets/src/mage/cards/t/TemptingWitch.java new file mode 100644 index 0000000000..2af415f528 --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TemptingWitch.java @@ -0,0 +1,59 @@ +package mage.cards.t; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.SacrificeTargetCost; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.LoseLifeTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.filter.common.FilterControlledPermanent; +import mage.game.permanent.token.FoodToken; +import mage.target.TargetPlayer; +import mage.target.common.TargetControlledPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class TemptingWitch extends CardImpl { + + private static final FilterControlledPermanent filter = new FilterControlledPermanent(SubType.FOOD, "a Food"); + + public TemptingWitch(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.WARLOCK); + this.power = new MageInt(1); + this.toughness = new MageInt(3); + + // When Tempting Witch enters the battlefield, create a Food token. + this.addAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new FoodToken()))); + + // {2}, {T}, Sacrifice a Food: Target player loses 3 life. + Ability ability = new SimpleActivatedAbility( + new LoseLifeTargetEffect(3), new GenericManaCost(2) + ); + ability.addCost(new TapSourceCost()); + ability.addCost(new SacrificeTargetCost(new TargetControlledPermanent(filter))); + ability.addTarget(new TargetPlayer()); + this.addAbility(ability); + } + + private TemptingWitch(final TemptingWitch card) { + super(card); + } + + @Override + public TemptingWitch copy() { + return new TemptingWitch(this); + } +} diff --git a/Mage.Sets/src/mage/cards/t/TheCauldronOfEternity.java b/Mage.Sets/src/mage/cards/t/TheCauldronOfEternity.java new file mode 100644 index 0000000000..e4a8026e2e --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TheCauldronOfEternity.java @@ -0,0 +1,104 @@ +package mage.cards.t; + +import mage.MageObject; +import mage.abilities.Ability; +import mage.abilities.SpellAbility; +import mage.abilities.common.ActivateAsSorceryActivatedAbility; +import mage.abilities.common.DiesCreatureTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.common.PayLifeCost; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.PutOnLibraryTargetEffect; +import mage.abilities.effects.common.ReturnFromGraveyardToBattlefieldTargetEffect; +import mage.abilities.effects.common.cost.CostModificationEffectImpl; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.players.Player; +import mage.target.common.TargetCardInYourGraveyard; +import mage.util.CardUtil; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class TheCauldronOfEternity extends CardImpl { + + public TheCauldronOfEternity(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{10}{B}{B}"); + + this.addSuperType(SuperType.LEGENDARY); + + // This spell costs {2} less to cast for each creature card in your graveyard. + this.addAbility(new SimpleStaticAbility(Zone.ALL, new TheCauldronOfEternityCostReductionEffect())); + + // Whenever a creature you control dies, put it on the bottom of its owner's library. + this.addAbility(new DiesCreatureTriggeredAbility( + new PutOnLibraryTargetEffect(false, "put it on the bottom of its owner's library"), + false, StaticFilters.FILTER_CONTROLLED_A_CREATURE, true + )); + + // {2}{B}, {T}, Pay 2 life: Return target creature card from your graveyard to the battlefield. Activate this ability only any time you could cast a sorcery. + Ability ability = new ActivateAsSorceryActivatedAbility( + Zone.BATTLEFIELD, new ReturnFromGraveyardToBattlefieldTargetEffect(), new ManaCostsImpl("{2}{B}") + ); + ability.addCost(new TapSourceCost()); + ability.addCost(new PayLifeCost(2)); + ability.addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD)); + this.addAbility(ability); + } + + private TheCauldronOfEternity(final TheCauldronOfEternity card) { + super(card); + } + + @Override + public TheCauldronOfEternity copy() { + return new TheCauldronOfEternity(this); + } +} + +class TheCauldronOfEternityCostReductionEffect extends CostModificationEffectImpl { + + TheCauldronOfEternityCostReductionEffect() { + super(Duration.WhileOnStack, Outcome.Benefit, CostModificationType.REDUCE_COST); + staticText = "This spell costs {2} less to cast for each creature card in your graveyard"; + } + + private TheCauldronOfEternityCostReductionEffect(final TheCauldronOfEternityCostReductionEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source, Ability abilityToModify) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; + } + int reductionAmount = player + .getGraveyard() + .getCards(game) + .stream() + .filter(MageObject::isCreature) + .mapToInt(card -> 2) + .sum(); + CardUtil.reduceCost(abilityToModify, reductionAmount); + return true; + } + + @Override + public boolean applies(Ability abilityToModify, Ability source, Game game) { + return abilityToModify instanceof SpellAbility + && abilityToModify.getSourceId().equals(source.getSourceId()) + && game.getCard(abilityToModify.getSourceId()) != null; + } + + @Override + public TheCauldronOfEternityCostReductionEffect copy() { + return new TheCauldronOfEternityCostReductionEffect(this); + } +} diff --git a/Mage.Sets/src/mage/cards/t/TheGreatHenge.java b/Mage.Sets/src/mage/cards/t/TheGreatHenge.java new file mode 100644 index 0000000000..3c81dc3e09 --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TheGreatHenge.java @@ -0,0 +1,110 @@ +package mage.cards.t; + +import mage.MageInt; +import mage.Mana; +import mage.abilities.Ability; +import mage.abilities.SpellAbility; +import mage.abilities.common.EntersBattlefieldControlledTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.GainLifeEffect; +import mage.abilities.effects.common.cost.CostModificationEffectImpl; +import mage.abilities.effects.common.counter.AddCountersTargetEffect; +import mage.abilities.mana.SimpleManaAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.counters.CounterType; +import mage.filter.FilterPermanent; +import mage.filter.StaticFilters; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.permanent.TokenPredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.util.CardUtil; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class TheGreatHenge extends CardImpl { + + private static final FilterPermanent filter = new FilterCreaturePermanent(); + + static { + filter.add(Predicates.not(TokenPredicate.instance)); + } + + public TheGreatHenge(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{7}{G}{G}"); + + this.addSuperType(SuperType.LEGENDARY); + + // This spell costs {X} less to cast, where X is the greatest power among creatures you control. + this.addAbility(new SimpleStaticAbility(Zone.ALL, new TheGreatHengeCostReductionEffect())); + + // {T}: Add {G}{G}. You gain 2 life. + Ability ability = new SimpleManaAbility(Zone.BATTLEFIELD, Mana.GreenMana(2), new TapSourceCost()); + ability.addEffect(new GainLifeEffect(2).setText("You gain 2 life.")); + this.addAbility(ability); + + // Whenever a nontoken creature enters the battlefield under your control, put a +1/+1 counter on it and draw a card. + ability = new EntersBattlefieldControlledTriggeredAbility( + Zone.BATTLEFIELD, new AddCountersTargetEffect(CounterType.P1P1.createInstance()), + filter, false, SetTargetPointer.PERMANENT, "Whenever a nontoken creature " + + "enters the battlefield under your control, put a +1/+1 counter on it and draw a card." + ); + ability.addEffect(new DrawCardSourceControllerEffect(1)); + this.addAbility(ability); + } + + private TheGreatHenge(final TheGreatHenge card) { + super(card); + } + + @Override + public TheGreatHenge copy() { + return new TheGreatHenge(this); + } +} + +class TheGreatHengeCostReductionEffect extends CostModificationEffectImpl { + + TheGreatHengeCostReductionEffect() { + super(Duration.WhileOnStack, Outcome.Benefit, CostModificationType.REDUCE_COST); + staticText = "This spell costs {X} less to cast, where X is the greatest power among creatures you control"; + } + + private TheGreatHengeCostReductionEffect(final TheGreatHengeCostReductionEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source, Ability abilityToModify) { + int reductionAmount = game.getBattlefield() + .getAllActivePermanents( + StaticFilters.FILTER_PERMANENT_CREATURE, source.getControllerId(), game + ).stream() + .map(Permanent::getPower) + .mapToInt(MageInt::getValue) + .max() + .orElse(0); + CardUtil.reduceCost(abilityToModify, Math.max(0, reductionAmount)); + return true; + } + + @Override + public boolean applies(Ability abilityToModify, Ability source, Game game) { + return abilityToModify instanceof SpellAbility + && abilityToModify.getSourceId().equals(source.getSourceId()) + && game.getCard(abilityToModify.getSourceId()) != null; + } + + @Override + public TheGreatHengeCostReductionEffect copy() { + return new TheGreatHengeCostReductionEffect(this); + } +} diff --git a/Mage.Sets/src/mage/cards/t/TheMagicMirror.java b/Mage.Sets/src/mage/cards/t/TheMagicMirror.java new file mode 100644 index 0000000000..9090a80225 --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TheMagicMirror.java @@ -0,0 +1,62 @@ +package mage.cards.t; + +import mage.abilities.Ability; +import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.dynamicvalue.common.CountersSourceCount; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.continuous.MaximumHandSizeControllerEffect; +import mage.abilities.effects.common.cost.SourceCostReductionForEachCardInGraveyardEffect; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.counters.CounterType; +import mage.filter.StaticFilters; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class TheMagicMirror extends CardImpl { + + private static final DynamicValue xValue = new CountersSourceCount(CounterType.KNOWLEDGE); + + public TheMagicMirror(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{6}{U}{U}{U}"); + + this.addSuperType(SuperType.LEGENDARY); + + // This spell costs {1} less to cast for each instant and sorcery card in your graveyard. + this.addAbility(new SimpleStaticAbility( + Zone.ALL, new SourceCostReductionForEachCardInGraveyardEffect( + StaticFilters.FILTER_CARD_INSTANT_AND_SORCERY + )).setRuleAtTheTop(true)); + + // You have no maximum hand size. + this.addAbility(new SimpleStaticAbility(new MaximumHandSizeControllerEffect( + Integer.MAX_VALUE, Duration.WhileOnBattlefield, + MaximumHandSizeControllerEffect.HandSizeModification.SET + ))); + + // At the beginning of your upkeep, put a knowledge counter on The Magic Mirror, then draw a card for each knowledge counter on The Magic Mirror. + Ability ability = new BeginningOfUpkeepTriggeredAbility( + new AddCountersSourceEffect(CounterType.KNOWLEDGE.createInstance()) + .setText("put a knowledge counter on {this},"), + TargetController.YOU, false + ); + ability.addEffect(new DrawCardSourceControllerEffect(xValue).concatBy("then")); + this.addAbility(ability); + } + + private TheMagicMirror(final TheMagicMirror card) { + super(card); + } + + @Override + public TheMagicMirror copy() { + return new TheMagicMirror(this); + } +} diff --git a/Mage.Sets/src/mage/cards/t/TheRoyalScions.java b/Mage.Sets/src/mage/cards/t/TheRoyalScions.java new file mode 100644 index 0000000000..83fda327c0 --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TheRoyalScions.java @@ -0,0 +1,129 @@ +package mage.cards.t; + +import mage.abilities.Ability; +import mage.abilities.DelayedTriggeredAbility; +import mage.abilities.LoyaltyAbility; +import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; +import mage.abilities.dynamicvalue.common.CardsInControllerHandCount; +import mage.abilities.effects.Effect; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.DrawDiscardControllerEffect; +import mage.abilities.effects.common.continuous.BoostTargetEffect; +import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; +import mage.abilities.keyword.FirstStrikeAbility; +import mage.abilities.keyword.TrampleAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.target.common.TargetAnyTarget; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class TheRoyalScions extends CardImpl { + + public TheRoyalScions(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.PLANESWALKER}, "{1}{U}{R}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.WILL); + this.subtype.add(SubType.ROWAN); + this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(5)); + + // +1: Draw a card, then discard a card. + this.addAbility(new LoyaltyAbility(new DrawDiscardControllerEffect(1, 1), 1)); + + // +1: Target creature gets +2/+0 and gains first strike and trample until end of turn. + Ability ability = new LoyaltyAbility(new BoostTargetEffect( + 2, 0, Duration.EndOfTurn + ).setText("Target creature gets +2/+0"), 1); + ability.addEffect(new GainAbilityTargetEffect( + FirstStrikeAbility.getInstance(), Duration.EndOfTurn + ).setText("and gains first strike")); + ability.addEffect(new GainAbilityTargetEffect( + TrampleAbility.getInstance(), Duration.EndOfTurn + ).setText("and trample until end of turn")); + ability.addTarget(new TargetCreaturePermanent()); + this.addAbility(ability); + + // −8: Draw four cards. When you do, The Royal Scions deals damage to any target equal to the number of cards in your hand. + this.addAbility(new LoyaltyAbility(new TheRoyalScionsCreateReflexiveTriggerEffect(), -8)); + } + + private TheRoyalScions(final TheRoyalScions card) { + super(card); + } + + @Override + public TheRoyalScions copy() { + return new TheRoyalScions(this); + } +} + +class TheRoyalScionsCreateReflexiveTriggerEffect extends OneShotEffect { + + private static final Effect effect = new DrawCardSourceControllerEffect(4); + + TheRoyalScionsCreateReflexiveTriggerEffect() { + super(Outcome.Benefit); + staticText = "Draw four cards. When you do, {this} deals damage " + + "to any target equal to the number of cards in your hand."; + } + + private TheRoyalScionsCreateReflexiveTriggerEffect(final TheRoyalScionsCreateReflexiveTriggerEffect effect) { + super(effect); + } + + @Override + public TheRoyalScionsCreateReflexiveTriggerEffect copy() { + return new TheRoyalScionsCreateReflexiveTriggerEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + effect.apply(game, source); + game.addDelayedTriggeredAbility(new TheRoyalScionsReflexiveTriggeredAbility(), source); + game.fireEvent(GameEvent.getEvent(GameEvent.EventType.OPTION_USED, source.getOriginalId(), source.getSourceId(), source.getControllerId(), 0)); + return true; + } +} + +class TheRoyalScionsReflexiveTriggeredAbility extends DelayedTriggeredAbility { + + TheRoyalScionsReflexiveTriggeredAbility() { + super(new DamageTargetEffect(CardsInControllerHandCount.instance), Duration.OneUse, true); + this.addTarget(new TargetAnyTarget()); + } + + private TheRoyalScionsReflexiveTriggeredAbility(final TheRoyalScionsReflexiveTriggeredAbility ability) { + super(ability); + } + + @Override + public TheRoyalScionsReflexiveTriggeredAbility copy() { + return new TheRoyalScionsReflexiveTriggeredAbility(this); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.OPTION_USED; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + return event.getPlayerId().equals(this.getControllerId()) + && event.getSourceId().equals(this.getSourceId()); + } + + @Override + public String getRule() { + return "When you do, {this} deals damage to any target equal to the number of cards in your hand."; + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/t/ThermalBlast.java b/Mage.Sets/src/mage/cards/t/ThermalBlast.java index 3f7b28b7bc..6ecf16804a 100644 --- a/Mage.Sets/src/mage/cards/t/ThermalBlast.java +++ b/Mage.Sets/src/mage/cards/t/ThermalBlast.java @@ -1,34 +1,33 @@ package mage.cards.t; -import java.util.UUID; import mage.abilities.condition.common.CardsInControllerGraveCondition; import mage.abilities.decorator.ConditionalOneShotEffect; -import mage.abilities.effects.Effect; import mage.abilities.effects.common.DamageTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author cbt33 */ public final class ThermalBlast extends CardImpl { public ThermalBlast(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{4}{R}"); - + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{4}{R}"); // Thermal Blast deals 3 damage to target creature. // Threshold - Thermal Blast deals 5 damage to that creature instead if seven or more cards are in your graveyard. - Effect effect = new ConditionalOneShotEffect(new DamageTargetEffect(5), - new DamageTargetEffect(3), - new CardsInControllerGraveCondition(7), - "{this} deals 3 damage to target creature.

Threshold — {this} deals 5 damage to that creature instead if seven or more cards are in your graveyard."); + this.getSpellAbility().addEffect(new ConditionalOneShotEffect( + new DamageTargetEffect(5), new DamageTargetEffect(3), + new CardsInControllerGraveCondition(7), + "{this} deals 3 damage to target creature.
Threshold — " + + "{this} deals 5 damage instead if seven or more cards are in your graveyard." + )); this.getSpellAbility().addTarget(new TargetCreaturePermanent()); - this.getSpellAbility().addEffect(effect); } public ThermalBlast(final ThermalBlast card) { diff --git a/Mage.Sets/src/mage/cards/t/ThopterSpyNetwork.java b/Mage.Sets/src/mage/cards/t/ThopterSpyNetwork.java index 8514dc9255..bd4b10cef6 100644 --- a/Mage.Sets/src/mage/cards/t/ThopterSpyNetwork.java +++ b/Mage.Sets/src/mage/cards/t/ThopterSpyNetwork.java @@ -1,9 +1,6 @@ package mage.cards.t; -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; import mage.abilities.TriggeredAbilityImpl; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.DrawCardSourceControllerEffect; @@ -18,8 +15,11 @@ import mage.game.events.GameEvent; import mage.game.permanent.Permanent; import mage.game.permanent.token.ThopterColorlessToken; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + /** - * * @author fireshoes */ public final class ThopterSpyNetwork extends CardImpl { @@ -34,7 +34,7 @@ public final class ThopterSpyNetwork extends CardImpl { this.addAbility(new ThopterSpyNetworkDamageTriggeredAbility()); } - public ThopterSpyNetwork(final ThopterSpyNetwork card) { + private ThopterSpyNetwork(final ThopterSpyNetwork card) { super(card); } @@ -46,11 +46,11 @@ public final class ThopterSpyNetwork extends CardImpl { class ThopterSpyNetworkUpkeepTriggeredAbility extends TriggeredAbilityImpl { - public ThopterSpyNetworkUpkeepTriggeredAbility() { + ThopterSpyNetworkUpkeepTriggeredAbility() { super(Zone.BATTLEFIELD, new CreateTokenEffect(new ThopterColorlessToken(), 1), false); } - public ThopterSpyNetworkUpkeepTriggeredAbility(final ThopterSpyNetworkUpkeepTriggeredAbility ability) { + private ThopterSpyNetworkUpkeepTriggeredAbility(final ThopterSpyNetworkUpkeepTriggeredAbility ability) { super(ability); } @@ -82,13 +82,13 @@ class ThopterSpyNetworkUpkeepTriggeredAbility extends TriggeredAbilityImpl { class ThopterSpyNetworkDamageTriggeredAbility extends TriggeredAbilityImpl { - List damagedPlayerIds = new ArrayList<>(); + private final List damagedPlayerIds = new ArrayList<>(); - public ThopterSpyNetworkDamageTriggeredAbility() { + ThopterSpyNetworkDamageTriggeredAbility() { super(Zone.BATTLEFIELD, new DrawCardSourceControllerEffect(1), false); } - public ThopterSpyNetworkDamageTriggeredAbility(final ThopterSpyNetworkDamageTriggeredAbility ability) { + private ThopterSpyNetworkDamageTriggeredAbility(final ThopterSpyNetworkDamageTriggeredAbility ability) { super(ability); } @@ -100,7 +100,7 @@ class ThopterSpyNetworkDamageTriggeredAbility extends TriggeredAbilityImpl { @Override public boolean checkEventType(GameEvent event, Game game) { return event.getType() == GameEvent.EventType.DAMAGED_PLAYER - || event.getType() == GameEvent.EventType.END_COMBAT_STEP_POST; + || event.getType() == GameEvent.EventType.COMBAT_DAMAGE_STEP_POST; } @Override @@ -115,7 +115,7 @@ class ThopterSpyNetworkDamageTriggeredAbility extends TriggeredAbilityImpl { } } } - if (event.getType() == GameEvent.EventType.END_COMBAT_STEP_POST) { + if (event.getType() == GameEvent.EventType.COMBAT_DAMAGE_STEP_POST) { damagedPlayerIds.clear(); } return false; diff --git a/Mage.Sets/src/mage/cards/t/ThoughtCollapse.java b/Mage.Sets/src/mage/cards/t/ThoughtCollapse.java index e09ad3f024..ed4faf06f7 100644 --- a/Mage.Sets/src/mage/cards/t/ThoughtCollapse.java +++ b/Mage.Sets/src/mage/cards/t/ThoughtCollapse.java @@ -1,6 +1,7 @@ package mage.cards.t; import mage.abilities.Ability; +import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.CounterTargetEffect; import mage.cards.CardImpl; @@ -39,6 +40,8 @@ public final class ThoughtCollapse extends CardImpl { class ThoughtCollapseEffect extends OneShotEffect { + private static final Effect effect = new CounterTargetEffect(); + ThoughtCollapseEffect() { super(Outcome.Benefit); staticText = "Counter target spell. Its controller puts " + @@ -61,6 +64,6 @@ class ThoughtCollapseEffect extends OneShotEffect { return false; } player.moveCards(player.getLibrary().getTopCards(game, 3), Zone.GRAVEYARD, source, game); - return new CounterTargetEffect().apply(game, source); + return effect.apply(game, source); } } \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/t/ThrillOfPossibility.java b/Mage.Sets/src/mage/cards/t/ThrillOfPossibility.java new file mode 100644 index 0000000000..9320896230 --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/ThrillOfPossibility.java @@ -0,0 +1,34 @@ +package mage.cards.t; + +import mage.abilities.costs.common.DiscardCardCost; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ThrillOfPossibility extends CardImpl { + + public ThrillOfPossibility(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{R}"); + + // As an additional cost to cast this spell, discard a card. + this.getSpellAbility().addCost(new DiscardCardCost()); + + // Draw two cards. + this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(2)); + } + + private ThrillOfPossibility(final ThrillOfPossibility card) { + super(card); + } + + @Override + public ThrillOfPossibility copy() { + return new ThrillOfPossibility(this); + } +} diff --git a/Mage.Sets/src/mage/cards/t/ThunderousSnapper.java b/Mage.Sets/src/mage/cards/t/ThunderousSnapper.java new file mode 100644 index 0000000000..2a54b4a295 --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/ThunderousSnapper.java @@ -0,0 +1,49 @@ +package mage.cards.t; + +import mage.MageInt; +import mage.abilities.common.SpellCastControllerTriggeredAbility; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.ComparisonType; +import mage.constants.SubType; +import mage.filter.FilterSpell; +import mage.filter.predicate.mageobject.ConvertedManaCostPredicate; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ThunderousSnapper extends CardImpl { + + private static final FilterSpell filter = new FilterSpell("a spell with converted mana cost 5 or greater"); + + static { + filter.add(new ConvertedManaCostPredicate(ComparisonType.MORE_THAN, 4)); + } + + public ThunderousSnapper(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{G/U}{G/U}{G/U}{G/U}"); + + this.subtype.add(SubType.TURTLE); + this.subtype.add(SubType.HYDRA); + this.power = new MageInt(4); + this.toughness = new MageInt(4); + + // Whenever you cast a spell with converted mana cost 5 or greater, draw a card. + this.addAbility(new SpellCastControllerTriggeredAbility( + new DrawCardSourceControllerEffect(1), filter, false + )); + } + + private ThunderousSnapper(final ThunderousSnapper card) { + super(card); + } + + @Override + public ThunderousSnapper copy() { + return new ThunderousSnapper(this); + } +} diff --git a/Mage.Sets/src/mage/cards/t/TorbranThaneOfRedFell.java b/Mage.Sets/src/mage/cards/t/TorbranThaneOfRedFell.java new file mode 100644 index 0000000000..659c6588b9 --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TorbranThaneOfRedFell.java @@ -0,0 +1,106 @@ +package mage.cards.t; + +import mage.MageInt; +import mage.MageObject; +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.ReplacementEffectImpl; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.util.CardUtil; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class TorbranThaneOfRedFell extends CardImpl { + + public TorbranThaneOfRedFell(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{R}{R}{R}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.DWARF); + this.subtype.add(SubType.NOBLE); + this.power = new MageInt(2); + this.toughness = new MageInt(4); + + // If a red source you control would deal damage to an opponent or a permanent an opponent controls, it deals that much damage plus 2 instead. + this.addAbility(new SimpleStaticAbility(new TorbranThaneOfRedFellEffect())); + } + + private TorbranThaneOfRedFell(final TorbranThaneOfRedFell card) { + super(card); + } + + @Override + public TorbranThaneOfRedFell copy() { + return new TorbranThaneOfRedFell(this); + } +} + +class TorbranThaneOfRedFellEffect extends ReplacementEffectImpl { + + TorbranThaneOfRedFellEffect() { + super(Duration.WhileOnBattlefield, Outcome.Damage); + this.staticText = "If a red source you control would deal damage to an opponent " + + "or a permanent an opponent controls, it deals that much damage plus 2 instead."; + } + + private TorbranThaneOfRedFellEffect(final TorbranThaneOfRedFellEffect effect) { + super(effect); + } + + @Override + public boolean replaceEvent(GameEvent event, Ability source, Game game) { + event.setAmount(CardUtil.addWithOverflowCheck(event.getAmount(), 2)); + return false; + } + + @Override + public boolean checksEventType(GameEvent event, Game game) { + switch (event.getType()) { + case DAMAGE_CREATURE: + case DAMAGE_PLANESWALKER: + case DAMAGE_PLAYER: + return true; + default: + return false; + } + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null + || !player.hasOpponent(getControllerOrSelf(event.getTargetId(), game), game) + || !source.isControlledBy(game.getControllerId(event.getSourceId()))) { + return false; + } + MageObject sourceObject; + Permanent sourcePermanent = game.getPermanentOrLKIBattlefield(event.getSourceId()); + if (sourcePermanent == null) { + sourceObject = game.getObject(event.getSourceId()); + } else { + sourceObject = sourcePermanent; + } + return sourceObject != null + && sourceObject.getColor(game).isRed(); + } + + private static UUID getControllerOrSelf(UUID id, Game game) { + UUID outId = game.getControllerId(id); + return outId == null ? id : outId; + } + + @Override + public TorbranThaneOfRedFellEffect copy() { + return new TorbranThaneOfRedFellEffect(this); + } + +} diff --git a/Mage.Sets/src/mage/cards/t/TormentingVoice.java b/Mage.Sets/src/mage/cards/t/TormentingVoice.java index f50ec68562..d5cbbadc40 100644 --- a/Mage.Sets/src/mage/cards/t/TormentingVoice.java +++ b/Mage.Sets/src/mage/cards/t/TormentingVoice.java @@ -1,31 +1,28 @@ - package mage.cards.t; -import java.util.UUID; -import mage.abilities.costs.common.DiscardTargetCost; +import mage.abilities.costs.common.DiscardCardCost; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.target.common.TargetCardInHand; + +import java.util.UUID; /** - * * @author LevelX2 */ public final class TormentingVoice extends CardImpl { public TormentingVoice(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{1}{R}"); - + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{1}{R}"); // As an additional cost to cast Tormenting Voice, discard a card. - this.getSpellAbility().addCost(new DiscardTargetCost(new TargetCardInHand())); + this.getSpellAbility().addCost(new DiscardCardCost()); // Draw two cards. this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(2)); } - public TormentingVoice(final TormentingVoice card) { + private TormentingVoice(final TormentingVoice card) { super(card); } diff --git a/Mage.Sets/src/mage/cards/t/TorrentOfSouls.java b/Mage.Sets/src/mage/cards/t/TorrentOfSouls.java index 7a694c00b7..9b503932b2 100644 --- a/Mage.Sets/src/mage/cards/t/TorrentOfSouls.java +++ b/Mage.Sets/src/mage/cards/t/TorrentOfSouls.java @@ -42,10 +42,10 @@ public final class TorrentOfSouls extends CardImpl { Target targetPlayer = new TargetPlayer(); this.getSpellAbility().addEffect(new ConditionalOneShotEffect( new ReturnToBattlefieldUnderYourControlTargetEffect(), - new ManaWasSpentCondition(ColoredManaSymbol.B), "Return up to one target creature card from your graveyard to the battlefield if {B} was spent to cast {this}")); + new ManaWasSpentCondition(ColoredManaSymbol.B), "Return up to one target creature card from your graveyard to the battlefield if {B} was spent to cast this spell")); this.getSpellAbility().addEffect(new ConditionalOneShotEffect( new TorrentOfSoulsEffect(), - new ManaWasSpentCondition(ColoredManaSymbol.R), " Creatures target player controls get +2/+0 and gain haste until end of turn if {R} was spent to cast {this}")); + new ManaWasSpentCondition(ColoredManaSymbol.R), " Creatures target player controls get +2/+0 and gain haste until end of turn if {R} was spent to cast this spell")); this.getSpellAbility().addTarget(targetCreature); this.getSpellAbility().addTarget(targetPlayer); diff --git a/Mage.Sets/src/mage/cards/t/TrailOfCrumbs.java b/Mage.Sets/src/mage/cards/t/TrailOfCrumbs.java new file mode 100644 index 0000000000..707eaa5063 --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TrailOfCrumbs.java @@ -0,0 +1,86 @@ +package mage.cards.t; + +import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.DoIfCostPaid; +import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.Zone; +import mage.filter.FilterCard; +import mage.filter.common.FilterPermanentCard; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; +import mage.game.permanent.token.FoodToken; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class TrailOfCrumbs extends CardImpl { + + public TrailOfCrumbs(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{G}"); + + // When Trail of Crumbs enters the battlefield, create a Food token. + this.addAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new FoodToken()))); + + // Whenever you sacrifice a Food, you may pay {1}. If you do, look at the top two cards of your library. You may reveal a permanent card from among them and put it into your hand. Put the rest on the bottom of your library in any order. + this.addAbility(new TrailOfCrumbsTriggeredAbility()); + } + + private TrailOfCrumbs(final TrailOfCrumbs card) { + super(card); + } + + @Override + public TrailOfCrumbs copy() { + return new TrailOfCrumbs(this); + } +} + +class TrailOfCrumbsTriggeredAbility extends TriggeredAbilityImpl { + + private static final FilterCard filter = new FilterPermanentCard(); + + TrailOfCrumbsTriggeredAbility() { + super(Zone.BATTLEFIELD, new DoIfCostPaid(new LookLibraryAndPickControllerEffect( + 2, 1, filter, true, true, Zone.HAND, true + ), new GenericManaCost(1))); + } + + private TrailOfCrumbsTriggeredAbility(final TrailOfCrumbsTriggeredAbility ability) { + super(ability); + } + + @Override + public TrailOfCrumbsTriggeredAbility copy() { + return new TrailOfCrumbsTriggeredAbility(this); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.SACRIFICED_PERMANENT; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + Permanent permanent = game.getPermanentOrLKIBattlefield(event.getTargetId()); + return permanent != null + && event.getPlayerId().equals(this.getControllerId()) + && permanent.hasSubtype(SubType.FOOD, game); + } + + @Override + public String getRule() { + return "Whenever you sacrifice a Food, you may pay {1}. If you do, " + + "look at the top two cards of your library. You may reveal a permanent card from among them " + + "and put it into your hand. Put the rest on the bottom of your library in any order."; + } +} diff --git a/Mage.Sets/src/mage/cards/t/TrainingGrounds.java b/Mage.Sets/src/mage/cards/t/TrainingGrounds.java index 663138e691..354f42c0bd 100644 --- a/Mage.Sets/src/mage/cards/t/TrainingGrounds.java +++ b/Mage.Sets/src/mage/cards/t/TrainingGrounds.java @@ -1,4 +1,3 @@ - package mage.cards.t; import mage.Mana; @@ -28,10 +27,10 @@ public final class TrainingGrounds extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{U}"); // Activated abilities of creatures you control cost up to {2} less to activate. This effect can't reduce the amount of mana an ability costs to activate to less than one mana. - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new TrainingGroundsEffect())); + this.addAbility(new SimpleStaticAbility(new TrainingGroundsEffect())); } - public TrainingGrounds(final TrainingGrounds card) { + private TrainingGrounds(final TrainingGrounds card) { super(card); } @@ -58,47 +57,48 @@ class TrainingGroundsEffect extends CostModificationEffectImpl { @Override public boolean apply(Game game, Ability source, Ability abilityToModify) { Player controller = game.getPlayer(abilityToModify.getControllerId()); - if (controller != null) { - Mana mana = abilityToModify.getManaCostsToPay().getMana(); - int reduceMax = mana.getGeneric(); - if (reduceMax > 0 && mana.count() == mana.getGeneric()) { - reduceMax--; - } - if (reduceMax > 2) { - reduceMax = 2; - } - if (reduceMax > 0) { - ChoiceImpl choice = new ChoiceImpl(true); - Set set = new LinkedHashSet<>(); - - for (int i = 0; i <= reduceMax; i++) { - set.add(String.valueOf(i)); - } - choice.setChoices(set); - choice.setMessage("Reduce ability cost"); - if (!controller.choose(Outcome.Benefit, choice, game)) { - return false; - } - int reduce = Integer.parseInt(choice.getChoice()); - CardUtil.reduceCost(abilityToModify, reduce); - } + if (controller == null) { + return false; + } + Mana mana = abilityToModify.getManaCostsToPay().getMana(); + int reduceMax = mana.getGeneric(); + if (reduceMax > 0 && mana.count() == mana.getGeneric()) { + reduceMax--; + } + if (reduceMax > 2) { + reduceMax = 2; + } + if (reduceMax <= 0) { return true; } + ChoiceImpl choice = new ChoiceImpl(true); + Set set = new LinkedHashSet<>(); + + for (int i = 0; i <= reduceMax; i++) { + set.add(String.valueOf(i)); + } + choice.setChoices(set); + choice.setMessage("Reduce ability cost"); + if (!controller.choose(Outcome.Benefit, choice, game)) { + return false; + } + int reduce = Integer.parseInt(choice.getChoice()); + CardUtil.reduceCost(abilityToModify, reduce); + return true; - return false; } @Override public boolean applies(Ability abilityToModify, Ability source, Game game) { - if (abilityToModify.getAbilityType() == AbilityType.ACTIVATED - || (abilityToModify.getAbilityType() == AbilityType.MANA && (abilityToModify instanceof ActivatedAbility))) { - //Activated abilities of creatures you control - Permanent permanent = game.getPermanent(abilityToModify.getSourceId()); - if (permanent != null && permanent.isControlledBy(source.getControllerId())) { - return true; - } + if (abilityToModify.getAbilityType() != AbilityType.ACTIVATED + && (abilityToModify.getAbilityType() != AbilityType.MANA + || !(abilityToModify instanceof ActivatedAbility))) { + return false; } - return false; + //Activated abilities of creatures you control + Permanent permanent = game.getPermanent(abilityToModify.getSourceId()); + return permanent != null && permanent.isCreature() + && permanent.isControlledBy(source.getControllerId()); } @Override diff --git a/Mage.Sets/src/mage/cards/t/TrappedInTheTower.java b/Mage.Sets/src/mage/cards/t/TrappedInTheTower.java new file mode 100644 index 0000000000..9a20346278 --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TrappedInTheTower.java @@ -0,0 +1,56 @@ +package mage.cards.t; + +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.AttachEffect; +import mage.abilities.effects.common.combat.CantBlockAttackActivateAttachedEffect; +import mage.abilities.keyword.EnchantAbility; +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.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.AbilityPredicate; +import mage.target.TargetPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class TrappedInTheTower extends CardImpl { + + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creature without flying"); + + static { + filter.add(Predicates.not(new AbilityPredicate(FlyingAbility.class))); + } + + public TrappedInTheTower(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{W}"); + + this.subtype.add(SubType.AURA); + + // Enchant creature without flying + TargetPermanent auraTarget = new TargetPermanent(filter); + this.getSpellAbility().addTarget(auraTarget); + this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); + Ability ability = new EnchantAbility(auraTarget.getTargetName()); + this.addAbility(ability); + + // Enchanted creature can't attack or block, and its activated abilities can't be activated. + this.addAbility(new SimpleStaticAbility(new CantBlockAttackActivateAttachedEffect())); + } + + private TrappedInTheTower(final TrappedInTheTower card) { + super(card); + } + + @Override + public TrappedInTheTower copy() { + return new TrappedInTheTower(this); + } +} diff --git a/Mage.Sets/src/mage/cards/t/TrueLovesKiss.java b/Mage.Sets/src/mage/cards/t/TrueLovesKiss.java new file mode 100644 index 0000000000..98d92a92ab --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TrueLovesKiss.java @@ -0,0 +1,37 @@ +package mage.cards.t; + +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.ExileTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.filter.StaticFilters; +import mage.target.TargetPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class TrueLovesKiss extends CardImpl { + + public TrueLovesKiss(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{W}{W}"); + + // Exile target artifact or enchantment. + this.getSpellAbility().addEffect(new ExileTargetEffect()); + this.getSpellAbility().addTarget(new TargetPermanent(StaticFilters.FILTER_PERMANENT_ARTIFACT_OR_ENCHANTMENT)); + + // Draw a card + this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(1)); + } + + private TrueLovesKiss(final TrueLovesKiss card) { + super(card); + } + + @Override + public TrueLovesKiss copy() { + return new TrueLovesKiss(this); + } +} diff --git a/Mage.Sets/src/mage/cards/t/TuinvaleTreefolk.java b/Mage.Sets/src/mage/cards/t/TuinvaleTreefolk.java new file mode 100644 index 0000000000..117552adc9 --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TuinvaleTreefolk.java @@ -0,0 +1,41 @@ +package mage.cards.t; + +import mage.MageInt; +import mage.abilities.effects.common.counter.AddCountersTargetEffect; +import mage.cards.AdventureCard; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.counters.CounterType; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class TuinvaleTreefolk extends AdventureCard { + + public TuinvaleTreefolk(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, new CardType[]{CardType.SORCERY}, "{5}{G}", "Oaken Boon", "{3}{G}"); + + this.subtype.add(SubType.TREEFOLK); + this.subtype.add(SubType.DRUID); + this.power = new MageInt(6); + this.toughness = new MageInt(5); + + // Oaken Boon + // Put two +1/+1 counters on target creature. + this.getAdventureSpellAbility().addEffect(new AddCountersTargetEffect(CounterType.P1P1.createInstance(2))); + this.getAdventureSpellAbility().addTarget(new TargetCreaturePermanent()); + } + + private TuinvaleTreefolk(final TuinvaleTreefolk card) { + super(card); + } + + @Override + public TuinvaleTreefolk copy() { + return new TuinvaleTreefolk(this); + } +} diff --git a/Mage.Sets/src/mage/cards/t/TurnIntoAPumpkin.java b/Mage.Sets/src/mage/cards/t/TurnIntoAPumpkin.java new file mode 100644 index 0000000000..9324626581 --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TurnIntoAPumpkin.java @@ -0,0 +1,47 @@ +package mage.cards.t; + +import mage.abilities.condition.common.AdamantCondition; +import mage.abilities.decorator.ConditionalOneShotEffect; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.ReturnToHandTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.game.permanent.token.FoodToken; +import mage.target.common.TargetNonlandPermanent; +import mage.watchers.common.ManaSpentToCastWatcher; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class TurnIntoAPumpkin extends CardImpl { + + public TurnIntoAPumpkin(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{3}{U}"); + + // Return target nonland permanent to its owner's hand. Draw a card. + this.getSpellAbility().addEffect(new ReturnToHandTargetEffect()); + this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(1).setText("Draw a card.")); + this.getSpellAbility().addTarget(new TargetNonlandPermanent()); + + // Adamant — If at least three blue mana was spent to cast this spell, create a Food token. + this.getSpellAbility().addEffect(new ConditionalOneShotEffect( + new CreateTokenEffect(new FoodToken()), AdamantCondition.BLUE, + "
Adamant — If at least three blue mana " + + "was spent to cast this spell, create a Food token." + )); + this.getSpellAbility().addWatcher(new ManaSpentToCastWatcher()); + } + + private TurnIntoAPumpkin(final TurnIntoAPumpkin card) { + super(card); + } + + @Override + public TurnIntoAPumpkin copy() { + return new TurnIntoAPumpkin(this); + } +} diff --git a/Mage.Sets/src/mage/cards/u/UginsConjurant.java b/Mage.Sets/src/mage/cards/u/UginsConjurant.java index a633fbff27..cf2582e131 100644 --- a/Mage.Sets/src/mage/cards/u/UginsConjurant.java +++ b/Mage.Sets/src/mage/cards/u/UginsConjurant.java @@ -31,7 +31,7 @@ public final class UginsConjurant extends CardImpl { // Ugin’s Conjurant enters the battlefield with X +1/+1 counters on it. this.addAbility(new EntersBattlefieldAbility(new EntersBattlefieldWithXCountersEffect(CounterType.P1P1.createInstance()))); // If damage would be dealt to Ugin’s Conjurant while it has a +1/+1 counter on it, prevent that damage and remove that many +1/+1 counters from Ugin’s Conjurant. - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new PreventDamageAndRemoveCountersEffect())); + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new PreventDamageAndRemoveCountersEffect(true))); } private UginsConjurant(final UginsConjurant card) { diff --git a/Mage.Sets/src/mage/cards/u/UnexplainedVision.java b/Mage.Sets/src/mage/cards/u/UnexplainedVision.java new file mode 100644 index 0000000000..3fb0d06e51 --- /dev/null +++ b/Mage.Sets/src/mage/cards/u/UnexplainedVision.java @@ -0,0 +1,41 @@ +package mage.cards.u; + +import mage.abilities.condition.common.AdamantCondition; +import mage.abilities.decorator.ConditionalOneShotEffect; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.keyword.ScryEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.watchers.common.ManaSpentToCastWatcher; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class UnexplainedVision extends CardImpl { + + public UnexplainedVision(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{4}{U}"); + + // Draw three cards. + this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(3)); + + // Adamant — If at least three blue mana was spent to cast this spell, scry 3. + this.getSpellAbility().addEffect(new ConditionalOneShotEffect( + new ScryEffect(3), AdamantCondition.BLUE, "
Adamant — " + + "If at least three blue mana was spent to cast this spell, scry 3." + )); + this.getSpellAbility().addWatcher(new ManaSpentToCastWatcher()); + } + + private UnexplainedVision(final UnexplainedVision card) { + super(card); + } + + @Override + public UnexplainedVision copy() { + return new UnexplainedVision(this); + } +} diff --git a/Mage.Sets/src/mage/cards/u/UnnervingAssault.java b/Mage.Sets/src/mage/cards/u/UnnervingAssault.java index 5b38d3a21f..d3ab5d6af2 100644 --- a/Mage.Sets/src/mage/cards/u/UnnervingAssault.java +++ b/Mage.Sets/src/mage/cards/u/UnnervingAssault.java @@ -37,7 +37,7 @@ public final class UnnervingAssault extends CardImpl { // Creatures your opponents control get -1/-0 until end of turn if {U} was spent to cast Unnerving Assault, and creatures you control get +1/+0 until end of turn if {R} was spent to cast it. this.getSpellAbility().addEffect(new ConditionalContinuousEffect( new BoostAllEffect(-1, 0, Duration.EndOfTurn, filter, false), - new ManaWasSpentCondition(ColoredManaSymbol.U), "Creatures your opponents control get -1/-0 until end of turn if {U} was spent to cast {this},")); + new ManaWasSpentCondition(ColoredManaSymbol.U), "Creatures your opponents control get -1/-0 until end of turn if {U} was spent to cast this spell,")); this.getSpellAbility().addEffect(new ConditionalContinuousEffect( new BoostAllEffect(1, 0, Duration.EndOfTurn, filter2, false), new ManaWasSpentCondition(ColoredManaSymbol.R), " and creatures you control get +1/+0 until end of turn if {R} was spent to cast it")); diff --git a/Mage.Sets/src/mage/cards/v/VampireAristocrat.java b/Mage.Sets/src/mage/cards/v/VampireAristocrat.java index 0c20539e79..aeb08d03d0 100644 --- a/Mage.Sets/src/mage/cards/v/VampireAristocrat.java +++ b/Mage.Sets/src/mage/cards/v/VampireAristocrat.java @@ -1,7 +1,5 @@ - package mage.cards.v; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; @@ -11,22 +9,22 @@ import mage.abilities.effects.common.continuous.BoostSourceEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Duration; +import mage.constants.SubType; import mage.constants.Zone; import mage.filter.common.FilterControlledCreaturePermanent; import mage.target.common.TargetControlledCreaturePermanent; +import java.util.UUID; + /** - * * @author Loki */ public final class VampireAristocrat extends CardImpl { public VampireAristocrat(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{B}"); - this.subtype.add(SubType.VAMPIRE); - this.subtype.add(SubType.ROGUE); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}"); + this.subtype.add(SubType.VAMPIRE, SubType.NOBLE, SubType.ROGUE); this.power = new MageInt(2); this.toughness = new MageInt(2); diff --git a/Mage.Sets/src/mage/cards/v/VampireNoble.java b/Mage.Sets/src/mage/cards/v/VampireNoble.java index 88099f000d..67189ec9c6 100644 --- a/Mage.Sets/src/mage/cards/v/VampireNoble.java +++ b/Mage.Sets/src/mage/cards/v/VampireNoble.java @@ -1,22 +1,21 @@ - package mage.cards.v; -import java.util.UUID; import mage.MageInt; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; +import java.util.UUID; + /** - * * @author fireshoes */ public final class VampireNoble extends CardImpl { public VampireNoble(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{B}"); - this.subtype.add(SubType.VAMPIRE); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}"); + this.subtype.add(SubType.VAMPIRE, SubType.NOBLE); this.power = new MageInt(3); this.toughness = new MageInt(2); } diff --git a/Mage.Sets/src/mage/cards/v/VampireSovereign.java b/Mage.Sets/src/mage/cards/v/VampireSovereign.java index 1cfbfe42b6..66b5549d08 100644 --- a/Mage.Sets/src/mage/cards/v/VampireSovereign.java +++ b/Mage.Sets/src/mage/cards/v/VampireSovereign.java @@ -1,20 +1,20 @@ package mage.cards.v; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.effects.common.GainLifeEffect; import mage.abilities.effects.common.LoseLifeTargetEffect; -import mage.constants.SubType; import mage.abilities.keyword.FlyingAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; +import mage.constants.SubType; import mage.target.common.TargetOpponent; +import java.util.UUID; + /** - * * @author TheElk801 */ public final class VampireSovereign extends CardImpl { @@ -22,7 +22,7 @@ public final class VampireSovereign extends CardImpl { public VampireSovereign(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{B}{B}"); - this.subtype.add(SubType.VAMPIRE); + this.subtype.add(SubType.VAMPIRE, SubType.NOBLE); this.power = new MageInt(3); this.toughness = new MageInt(4); diff --git a/Mage.Sets/src/mage/cards/v/VantressGargoyle.java b/Mage.Sets/src/mage/cards/v/VantressGargoyle.java new file mode 100644 index 0000000000..0639373464 --- /dev/null +++ b/Mage.Sets/src/mage/cards/v/VantressGargoyle.java @@ -0,0 +1,116 @@ +package mage.cards.v; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.effects.RestrictionEffect; +import mage.abilities.effects.common.PutTopCardOfLibraryIntoGraveEachPlayerEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.constants.TargetController; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class VantressGargoyle extends CardImpl { + + public VantressGargoyle(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{1}{U}"); + + this.subtype.add(SubType.GARGOYLE); + this.power = new MageInt(5); + this.toughness = new MageInt(4); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // Vantress Gargoyle can't attack unless defending player has seven or more cards in their graveyard. + this.addAbility(new SimpleStaticAbility(new VantressGargoyleAttackEffect())); + + // Vantress Gargoyle can't block unless you have four or more cards in hand. + this.addAbility(new SimpleStaticAbility(new VantressGargoyleBlockEffect())); + + // {T}: Each player puts the top card of their library into their graveyard. + this.addAbility(new SimpleActivatedAbility( + new PutTopCardOfLibraryIntoGraveEachPlayerEffect(1, TargetController.ANY), new TapSourceCost() + )); + } + + private VantressGargoyle(final VantressGargoyle card) { + super(card); + } + + @Override + public VantressGargoyle copy() { + return new VantressGargoyle(this); + } +} + +class VantressGargoyleAttackEffect extends RestrictionEffect { + + VantressGargoyleAttackEffect() { + super(Duration.WhileOnBattlefield); + staticText = "{this} can't attack unless defending player has seven or more cards in their graveyard"; + } + + private VantressGargoyleAttackEffect(final VantressGargoyleAttackEffect effect) { + super(effect); + } + + @Override + public boolean applies(Permanent permanent, Ability source, Game game) { + return permanent.getId().equals(source.getSourceId()); + } + + @Override + public boolean canAttack(Permanent attacker, UUID defenderId, Ability source, Game game, boolean canUseChooseDialogs) { + Player player = game.getPlayerOrPlaneswalkerController(defenderId); + return player != null && player.getGraveyard().size() > 6; + } + + @Override + public VantressGargoyleAttackEffect copy() { + return new VantressGargoyleAttackEffect(this); + } +} + +class VantressGargoyleBlockEffect extends RestrictionEffect { + + VantressGargoyleBlockEffect() { + super(Duration.WhileOnBattlefield); + staticText = "{this} can't block unless you have four or more cards in hand"; + } + + private VantressGargoyleBlockEffect(final VantressGargoyleBlockEffect effect) { + super(effect); + } + + @Override + public VantressGargoyleBlockEffect copy() { + return new VantressGargoyleBlockEffect(this); + } + + @Override + public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game, boolean canUseChooseDialogs) { + return false; + } + + @Override + public boolean applies(Permanent permanent, Ability source, Game game) { + Player player = game.getPlayer(source.getControllerId()); + return player != null + && player.getHand().size() < 4 + && permanent.getId().equals(source.getSourceId()); + } +} diff --git a/Mage.Sets/src/mage/cards/v/VantressPaladin.java b/Mage.Sets/src/mage/cards/v/VantressPaladin.java new file mode 100644 index 0000000000..2c1ef9dfef --- /dev/null +++ b/Mage.Sets/src/mage/cards/v/VantressPaladin.java @@ -0,0 +1,50 @@ +package mage.cards.v; + +import mage.MageInt; +import mage.abilities.common.EntersBattlefieldAbility; +import mage.abilities.condition.common.AdamantCondition; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.counters.CounterType; +import mage.watchers.common.ManaSpentToCastWatcher; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class VantressPaladin extends CardImpl { + + public VantressPaladin(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{U}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.KNIGHT); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // Adamant — If at least three blue mana was spent to cast this spell, Vantress Paladin enters the battlefield with an additional +1/+1 counter on it. + this.addAbility(new EntersBattlefieldAbility( + new AddCountersSourceEffect(CounterType.P1P1.createInstance()), + AdamantCondition.BLUE, "
Adamant — " + + "If at least three blue mana was spent to cast this spell, " + + "{this} enters the battlefield with a +1/+1 counter on it.", "" + ), new ManaSpentToCastWatcher()); + } + + private VantressPaladin(final VantressPaladin card) { + super(card); + } + + @Override + public VantressPaladin copy() { + return new VantressPaladin(this); + } +} diff --git a/Mage.Sets/src/mage/cards/v/VenerableKnight.java b/Mage.Sets/src/mage/cards/v/VenerableKnight.java new file mode 100644 index 0000000000..dc14f248f3 --- /dev/null +++ b/Mage.Sets/src/mage/cards/v/VenerableKnight.java @@ -0,0 +1,47 @@ +package mage.cards.v; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.DiesTriggeredAbility; +import mage.abilities.effects.common.counter.AddCountersTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.counters.CounterType; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledPermanent; +import mage.target.TargetPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class VenerableKnight extends CardImpl { + + private static final FilterPermanent filter = new FilterControlledPermanent(SubType.KNIGHT); + + public VenerableKnight(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{W}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.KNIGHT); + this.power = new MageInt(2); + this.toughness = new MageInt(1); + + // When Venerable Knight dies, put a +1/+1 counter on target Knight you control. + Ability ability = new DiesTriggeredAbility(new AddCountersTargetEffect(CounterType.P1P1.createInstance())); + ability.addTarget(new TargetPermanent(filter)); + this.addAbility(ability); + } + + private VenerableKnight(final VenerableKnight card) { + super(card); + } + + @Override + public VenerableKnight copy() { + return new VenerableKnight(this); + } +} diff --git a/Mage.Sets/src/mage/cards/v/VigorMortis.java b/Mage.Sets/src/mage/cards/v/VigorMortis.java index f783c1815e..494e7383c9 100644 --- a/Mage.Sets/src/mage/cards/v/VigorMortis.java +++ b/Mage.Sets/src/mage/cards/v/VigorMortis.java @@ -33,7 +33,7 @@ public final class VigorMortis extends CardImpl { // Return target creature card from your graveyard to the battlefield. If {G} was spent to cast Vigor Mortis, that creature enters the battlefield with an additional +1/+1 counter on it. this.getSpellAbility().addEffect(new VigorMortisReplacementEffect()); // has to be added before the moving effect this.getSpellAbility().addEffect(new ReturnFromGraveyardToBattlefieldTargetEffect()); - this.getSpellAbility().addEffect(new InfoEffect("If {G} was spent to cast {this}, that creature enters the battlefield with an additional +1/+1 counter on it")); + this.getSpellAbility().addEffect(new InfoEffect("If {G} was spent to cast this spell, that creature enters the battlefield with an additional +1/+1 counter on it")); this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(new FilterCreatureCard())); } diff --git a/Mage.Sets/src/mage/cards/v/ViviensArkbow.java b/Mage.Sets/src/mage/cards/v/ViviensArkbow.java index 0db7847a76..82b5814347 100644 --- a/Mage.Sets/src/mage/cards/v/ViviensArkbow.java +++ b/Mage.Sets/src/mage/cards/v/ViviensArkbow.java @@ -50,7 +50,7 @@ public final class ViviensArkbow extends CardImpl { class ViviensArkbowEffect extends OneShotEffect { ViviensArkbowEffect() { - super(Outcome.Benefit); + super(Outcome.PutCardInPlay); staticText = "Look at the top X cards of your library. " + "You may put a creature card with converted mana cost X or less " + "from among them onto the battlefield. Put the rest on the bottom of your library in a random order."; diff --git a/Mage.Sets/src/mage/cards/w/WallOfResistance.java b/Mage.Sets/src/mage/cards/w/WallOfResistance.java new file mode 100644 index 0000000000..06099d7b1d --- /dev/null +++ b/Mage.Sets/src/mage/cards/w/WallOfResistance.java @@ -0,0 +1,59 @@ +package mage.cards.w; + +import mage.MageInt; +import mage.abilities.common.BeginningOfEndStepTriggeredAbility; +import mage.abilities.condition.Condition; +import mage.abilities.condition.common.SourceDealtDamageCondition; +import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.abilities.keyword.DefenderAbility; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.TargetController; +import mage.counters.CounterType; +import mage.watchers.common.DamageDoneWatcher; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class WallOfResistance extends CardImpl { + + private static final Condition condition = new SourceDealtDamageCondition(1); + + public WallOfResistance(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W}"); + + this.subtype.add(SubType.WALL); + this.power = new MageInt(0); + this.toughness = new MageInt(3); + + // Defender + this.addAbility(DefenderAbility.getInstance()); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // At the beginning of each end step, if Wall of Resistance was dealt damage this turn, put a +0/+1 counter on it. + this.addAbility(new ConditionalInterveningIfTriggeredAbility( + new BeginningOfEndStepTriggeredAbility( + new AddCountersSourceEffect(CounterType.P0P1.createInstance()), + TargetController.ANY, false + ), condition, "At the beginning of each end step, " + + "if {this} was dealt damage this turn, put a +0/+1 counter on it." + ), new DamageDoneWatcher()); + } + + private WallOfResistance(final WallOfResistance card) { + super(card); + } + + @Override + public WallOfResistance copy() { + return new WallOfResistance(this); + } +} diff --git a/Mage.Sets/src/mage/cards/w/Wandermare.java b/Mage.Sets/src/mage/cards/w/Wandermare.java new file mode 100644 index 0000000000..1b6e77b317 --- /dev/null +++ b/Mage.Sets/src/mage/cards/w/Wandermare.java @@ -0,0 +1,50 @@ +package mage.cards.w; + +import mage.MageInt; +import mage.abilities.common.SpellCastControllerTriggeredAbility; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.counters.CounterType; +import mage.filter.FilterSpell; +import mage.filter.common.FilterCreatureSpell; +import mage.filter.predicate.mageobject.AdventurePredicate; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class Wandermare extends CardImpl { + + private static final FilterSpell filter + = new FilterCreatureSpell("a creature spell that has an Adventure"); + + static { + filter.add(AdventurePredicate.instance); + } + + public Wandermare(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{G}{W}"); + + this.subtype.add(SubType.HORSE); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // Whenever you cast a creature spell that has an Adventure, put a +1/+1 counter on Wandermare. + this.addAbility(new SpellCastControllerTriggeredAbility( + new AddCountersSourceEffect(CounterType.P1P1.createInstance()), filter, false + )); + } + + private Wandermare(final Wandermare card) { + super(card); + } + + @Override + public Wandermare copy() { + return new Wandermare(this); + } +} diff --git a/Mage.Sets/src/mage/cards/w/WeaponRack.java b/Mage.Sets/src/mage/cards/w/WeaponRack.java new file mode 100644 index 0000000000..70066e2551 --- /dev/null +++ b/Mage.Sets/src/mage/cards/w/WeaponRack.java @@ -0,0 +1,82 @@ +package mage.cards.w; + +import mage.abilities.Ability; +import mage.abilities.common.ActivateAsSorceryActivatedAbility; +import mage.abilities.common.EntersBattlefieldAbility; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Zone; +import mage.counters.CounterType; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class WeaponRack extends CardImpl { + + public WeaponRack(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{4}"); + + // Weapon Rack enters the battlefield with three +1/+1 counters on it. + this.addAbility(new EntersBattlefieldAbility( + new AddCountersSourceEffect(CounterType.P1P1.createInstance(3)), + "{this} enters the battlefield with three +1/+1 counters on it" + )); + + // {T}: Move a +1/+1 counter from Weapon Rack onto target creature. Activate this ability only any time you could cast a sorcery. + Ability ability = new ActivateAsSorceryActivatedAbility( + Zone.BATTLEFIELD, new WeaponRackEffect(), new TapSourceCost() + ); + ability.addTarget(new TargetCreaturePermanent()); + this.addAbility(ability); + } + + private WeaponRack(final WeaponRack card) { + super(card); + } + + @Override + public WeaponRack copy() { + return new WeaponRack(this); + } +} + +class WeaponRackEffect extends OneShotEffect { + + WeaponRackEffect() { + super(Outcome.Benefit); + staticText = "move a +1/+1 counter from {this} onto target creature"; + } + + private WeaponRackEffect(final WeaponRackEffect effect) { + super(effect); + } + + @Override + public WeaponRackEffect copy() { + return new WeaponRackEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent sourcePermanent = game.getPermanent(source.getSourceId()); + if (sourcePermanent == null || !sourcePermanent.getCounters(game).containsKey(CounterType.P1P1)) { + return false; + } + Permanent permanent = game.getPermanent(source.getFirstTarget()); + if (permanent == null || !permanent.addCounters(CounterType.P1P1.createInstance(), source, game)) { + return false; + } + sourcePermanent.removeCounters(CounterType.P1P1.createInstance(), game); + return true; + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/w/WeaselbackRedcap.java b/Mage.Sets/src/mage/cards/w/WeaselbackRedcap.java new file mode 100644 index 0000000000..3526c27452 --- /dev/null +++ b/Mage.Sets/src/mage/cards/w/WeaselbackRedcap.java @@ -0,0 +1,42 @@ +package mage.cards.w; + +import mage.MageInt; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.continuous.BoostSourceEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class WeaselbackRedcap extends CardImpl { + + public WeaselbackRedcap(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{R}"); + + this.subtype.add(SubType.GOBLIN); + this.subtype.add(SubType.KNIGHT); + this.power = new MageInt(1); + this.toughness = new MageInt(1); + + // {1}{R}: Weaselback Redcap gets +2/+0 until end of turn. + this.addAbility(new SimpleActivatedAbility( + new BoostSourceEffect(2, 0, Duration.EndOfTurn), new ManaCostsImpl("{1}{R}") + )); + } + + private WeaselbackRedcap(final WeaselbackRedcap card) { + super(card); + } + + @Override + public WeaselbackRedcap copy() { + return new WeaselbackRedcap(this); + } +} diff --git a/Mage.Sets/src/mage/cards/w/WickedGuardian.java b/Mage.Sets/src/mage/cards/w/WickedGuardian.java new file mode 100644 index 0000000000..23136034fb --- /dev/null +++ b/Mage.Sets/src/mage/cards/w/WickedGuardian.java @@ -0,0 +1,92 @@ +package mage.cards.w; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.predicate.permanent.AnotherPredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.TargetPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class WickedGuardian extends CardImpl { + + public WickedGuardian(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{B}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.NOBLE); + this.power = new MageInt(4); + this.toughness = new MageInt(2); + + // When Wicked Guardian enters the battlefield, you may have it deal 2 damage to another creature you control. If you do, draw a card. + this.addAbility(new EntersBattlefieldTriggeredAbility(new WickedGuardianEffect(), true)); + } + + private WickedGuardian(final WickedGuardian card) { + super(card); + } + + @Override + public WickedGuardian copy() { + return new WickedGuardian(this); + } +} + +class WickedGuardianEffect extends OneShotEffect { + + private static final FilterPermanent filter + = new FilterControlledCreaturePermanent("another creature you control"); + + static { + filter.add(AnotherPredicate.instance); + } + + WickedGuardianEffect() { + super(Outcome.Benefit); + staticText = "have it deal 2 damage to another creature you control. If you do, draw a card"; + } + + private WickedGuardianEffect(final WickedGuardianEffect effect) { + super(effect); + } + + @Override + public WickedGuardianEffect copy() { + return new WickedGuardianEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; + } + if (game.getBattlefield().count(filter, source.getSourceId(), source.getControllerId(), game) == 0) { + return false; + } + TargetPermanent target = new TargetPermanent(0, 1, filter, true); + if (!player.choose(outcome, target, source.getSourceId(), game)) { + return false; + } + Permanent permanent = game.getPermanent(target.getFirstTarget()); + if (permanent == null) { + return false; + } + permanent.damage(2, source.getSourceId(), game); + return player.drawCards(1, game) > 0; + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/w/WickedWolf.java b/Mage.Sets/src/mage/cards/w/WickedWolf.java new file mode 100644 index 0000000000..3888da8973 --- /dev/null +++ b/Mage.Sets/src/mage/cards/w/WickedWolf.java @@ -0,0 +1,77 @@ +package mage.cards.w; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.SacrificeTargetCost; +import mage.abilities.effects.common.FightTargetSourceEffect; +import mage.abilities.effects.common.TapSourceEffect; +import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.abilities.keyword.IndestructibleAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.constants.TargetController; +import mage.counters.CounterType; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledPermanent; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.permanent.ControllerPredicate; +import mage.target.TargetPermanent; +import mage.target.common.TargetControlledPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class WickedWolf extends CardImpl { + + private static final FilterPermanent filter + = new FilterCreaturePermanent("creature you don't control"); + private static final FilterControlledPermanent filter2 + = new FilterControlledPermanent(SubType.FOOD, "a Food"); + + static { + filter.add(new ControllerPredicate(TargetController.NOT_YOU)); + } + + public WickedWolf(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{G}{G}"); + + this.subtype.add(SubType.WOLF); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // When Wicked Wolf enters the battlefield, it fights up to one target creature you don't control. + Ability ability = new EntersBattlefieldTriggeredAbility( + new FightTargetSourceEffect().setText("it fights up to one target creature you don't control") + ); + ability.addTarget(new TargetPermanent(0, 1, filter, false)); + this.addAbility(ability); + + // Sacrifice a Food: Put a +1/+1 counter on Wicked Wolf. It gains indestructible until end of turn. Tap it. + ability = new SimpleActivatedAbility( + new AddCountersSourceEffect(CounterType.P1P1.createInstance()), + new SacrificeTargetCost(new TargetControlledPermanent(filter2)) + ); + ability.addEffect(new GainAbilitySourceEffect( + IndestructibleAbility.getInstance(), Duration.EndOfTurn + ).setText("it gains indestructible until end of turn.")); + ability.addEffect(new TapSourceEffect().setText("Tap it")); + this.addAbility(ability); + } + + private WickedWolf(final WickedWolf card) { + super(card); + } + + @Override + public WickedWolf copy() { + return new WickedWolf(this); + } +} diff --git a/Mage.Sets/src/mage/cards/w/WildGuess.java b/Mage.Sets/src/mage/cards/w/WildGuess.java index bd0a53e392..d70767cd39 100644 --- a/Mage.Sets/src/mage/cards/w/WildGuess.java +++ b/Mage.Sets/src/mage/cards/w/WildGuess.java @@ -1,31 +1,28 @@ - package mage.cards.w; -import java.util.UUID; -import mage.abilities.costs.common.DiscardTargetCost; +import mage.abilities.costs.common.DiscardCardCost; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.target.common.TargetCardInHand; + +import java.util.UUID; /** - * * @author North */ public final class WildGuess extends CardImpl { public WildGuess(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{R}{R}"); - + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{R}{R}"); // As an additional cost to cast Wild Guess, discard a card. - this.getSpellAbility().addCost(new DiscardTargetCost(new TargetCardInHand())); + this.getSpellAbility().addCost(new DiscardCardCost()); // Draw two cards. this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(2)); } - public WildGuess(final WildGuess card) { + private WildGuess(final WildGuess card) { super(card); } diff --git a/Mage.Sets/src/mage/cards/w/WildbornPreserver.java b/Mage.Sets/src/mage/cards/w/WildbornPreserver.java new file mode 100644 index 0000000000..b6429ccdda --- /dev/null +++ b/Mage.Sets/src/mage/cards/w/WildbornPreserver.java @@ -0,0 +1,141 @@ +package mage.cards.w; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.DelayedTriggeredAbility; +import mage.abilities.common.EntersBattlefieldControlledTriggeredAbility; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.costs.mana.ManaCosts; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.abilities.keyword.FlashAbility; +import mage.abilities.keyword.ReachAbility; +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.counters.CounterType; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.SubtypePredicate; +import mage.filter.predicate.permanent.AnotherPredicate; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.players.Player; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class WildbornPreserver extends CardImpl { + + private static final FilterPermanent filter = new FilterCreaturePermanent("another non-Human creature"); + + static { + filter.add(AnotherPredicate.instance); + filter.add(Predicates.not(new SubtypePredicate(SubType.HUMAN))); + } + + public WildbornPreserver(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{G}"); + + this.subtype.add(SubType.ELF); + this.subtype.add(SubType.ARCHER); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // Flash + this.addAbility(FlashAbility.getInstance()); + + // Reach + this.addAbility(ReachAbility.getInstance()); + + // Whenever another non-Human creature enters the battlefield under your control, you may pay {X}. When you do, put X +1/+1 counters on Wildborn Preserver. + this.addAbility(new EntersBattlefieldControlledTriggeredAbility( + new WildbornPreserverCreateReflexiveTriggerEffect(), filter + )); + } + + private WildbornPreserver(final WildbornPreserver card) { + super(card); + } + + @Override + public WildbornPreserver copy() { + return new WildbornPreserver(this); + } +} + +class WildbornPreserverCreateReflexiveTriggerEffect extends OneShotEffect { + + WildbornPreserverCreateReflexiveTriggerEffect() { + super(Outcome.Benefit); + } + + private WildbornPreserverCreateReflexiveTriggerEffect(final WildbornPreserverCreateReflexiveTriggerEffect effect) { + super(effect); + staticText = "you may pay {X}. When you do, put X +1/+1 counters on {this}"; + } + + @Override + public WildbornPreserverCreateReflexiveTriggerEffect copy() { + return new WildbornPreserverCreateReflexiveTriggerEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + ManaCosts cost = new ManaCostsImpl("{X}"); + if (player == null) { + return false; + } + if (!player.chooseUse(outcome, "Pay " + cost.getText() + "?", source, game)) { + return false; + } + int costX = player.announceXMana(0, Integer.MAX_VALUE, "Announce the value for {X}", game, source); + cost.add(new GenericManaCost(costX)); + if (!cost.pay(source, game, source.getSourceId(), source.getControllerId(), false, null)) { + return false; + } + game.addDelayedTriggeredAbility(new WildbornPreserverReflexiveTriggeredAbility(costX), source); + game.fireEvent(GameEvent.getEvent(GameEvent.EventType.OPTION_USED, source.getOriginalId(), source.getSourceId(), source.getControllerId(), 0)); + return true; + } +} + +class WildbornPreserverReflexiveTriggeredAbility extends DelayedTriggeredAbility { + + WildbornPreserverReflexiveTriggeredAbility(int counters) { + super(new AddCountersSourceEffect(CounterType.P1P1.createInstance(counters)), Duration.OneUse, true); + } + + private WildbornPreserverReflexiveTriggeredAbility(final WildbornPreserverReflexiveTriggeredAbility ability) { + super(ability); + } + + @Override + public WildbornPreserverReflexiveTriggeredAbility copy() { + return new WildbornPreserverReflexiveTriggeredAbility(this); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.OPTION_USED; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + return event.getPlayerId().equals(this.getControllerId()) + && event.getSourceId().equals(this.getSourceId()); + } + + @Override + public String getRule() { + return "When you do, put X +1/+1 counters on {this}."; + } +} diff --git a/Mage.Sets/src/mage/cards/w/WildwoodTracker.java b/Mage.Sets/src/mage/cards/w/WildwoodTracker.java new file mode 100644 index 0000000000..8722bc8248 --- /dev/null +++ b/Mage.Sets/src/mage/cards/w/WildwoodTracker.java @@ -0,0 +1,61 @@ +package mage.cards.w; + +import mage.MageInt; +import mage.abilities.common.AttacksOrBlocksTriggeredAbility; +import mage.abilities.condition.Condition; +import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; +import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; +import mage.abilities.effects.common.continuous.BoostSourceEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.SubtypePredicate; +import mage.filter.predicate.permanent.AnotherPredicate; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class WildwoodTracker extends CardImpl { + + private static final FilterPermanent filter = new FilterControlledCreaturePermanent(); + + static { + filter.add(AnotherPredicate.instance); + filter.add(Predicates.not(new SubtypePredicate(SubType.HUMAN))); + } + + private static final Condition condition = new PermanentsOnTheBattlefieldCondition(filter); + + public WildwoodTracker(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{G}"); + + this.subtype.add(SubType.ELF); + this.subtype.add(SubType.WARRIOR); + this.power = new MageInt(1); + this.toughness = new MageInt(1); + + // Whenever Wildwood Tracker attacks or blocks, if you control another non-Human creature, Wildwood Tracker gets +1/+1 until end of turn. + this.addAbility(new ConditionalInterveningIfTriggeredAbility( + new AttacksOrBlocksTriggeredAbility( + new BoostSourceEffect(1, 1, Duration.EndOfTurn), false + ), condition, "Whenever {this} attacks or blocks, if you control another non-Human creature, " + + "{this} gets +1/+1 until end of turn." + )); + } + + private WildwoodTracker(final WildwoodTracker card) { + super(card); + } + + @Override + public WildwoodTracker copy() { + return new WildwoodTracker(this); + } +} diff --git a/Mage.Sets/src/mage/cards/w/WishclawTalisman.java b/Mage.Sets/src/mage/cards/w/WishclawTalisman.java new file mode 100644 index 0000000000..381a63d977 --- /dev/null +++ b/Mage.Sets/src/mage/cards/w/WishclawTalisman.java @@ -0,0 +1,102 @@ +package mage.cards.w; + +import mage.abilities.Ability; +import mage.abilities.common.ActivateIfConditionActivatedAbility; +import mage.abilities.common.EntersBattlefieldAbility; +import mage.abilities.condition.common.MyTurnCondition; +import mage.abilities.costs.common.RemoveCountersSourceCost; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.effects.ContinuousEffect; +import mage.abilities.effects.Effect; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.continuous.GainControlTargetEffect; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.abilities.effects.common.search.SearchLibraryPutInHandEffect; +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.counters.CounterType; +import mage.game.Game; +import mage.players.Player; +import mage.target.TargetPlayer; +import mage.target.common.TargetCardInLibrary; +import mage.target.common.TargetOpponent; +import mage.target.targetpointer.FixedTarget; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class WishclawTalisman extends CardImpl { + + public WishclawTalisman(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{1}{B}"); + + // Wishclaw Talisman enters the battlefield with three wish counters on it. + this.addAbility(new EntersBattlefieldAbility( + new AddCountersSourceEffect(CounterType.WISH.createInstance(3)), + "{this} enters the battlefield with three wish counters on it" + )); + + // {1}, {T}, Remove a wish counter from Wishclaw Talisman: Search your library for a card, put it into your hand, then shuffle your library. An opponent gains control of Wishclaw Talisman. Activate this ability only during your turn. + Ability ability = new ActivateIfConditionActivatedAbility( + Zone.BATTLEFIELD, new WishclawTalismanEffect(), new GenericManaCost(1), MyTurnCondition.instance + ); + ability.addCost(new TapSourceCost()); + ability.addCost(new RemoveCountersSourceCost(CounterType.WISH.createInstance())); + this.addAbility(ability); + } + + private WishclawTalisman(final WishclawTalisman card) { + super(card); + } + + @Override + public WishclawTalisman copy() { + return new WishclawTalisman(this); + } +} + +class WishclawTalismanEffect extends OneShotEffect { + + private static final Effect effect = new SearchLibraryPutInHandEffect(new TargetCardInLibrary()); + + WishclawTalismanEffect() { + super(Outcome.Benefit); + staticText = "Search your library for a card, put it into your hand, then shuffle your library. " + + "An opponent gains control of {this}"; + } + + private WishclawTalismanEffect(final WishclawTalismanEffect effect) { + super(effect); + } + + @Override + public WishclawTalismanEffect copy() { + return new WishclawTalismanEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + effect.apply(game, source); + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; + } + TargetPlayer target = new TargetOpponent(); + target.setNotTarget(true); + if (!player.choose(outcome, target, source.getSourceId(), game)) { + return false; + } + ContinuousEffect continuousEffect + = new GainControlTargetEffect(Duration.Custom, true, target.getFirstTarget()); + continuousEffect.setTargetPointer(new FixedTarget(source.getSourceId(), game)); + game.addEffect(continuousEffect, source); + return true; + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/w/WitchsCottage.java b/Mage.Sets/src/mage/cards/w/WitchsCottage.java index 9c78e1429c..bf659a2d3b 100644 --- a/Mage.Sets/src/mage/cards/w/WitchsCottage.java +++ b/Mage.Sets/src/mage/cards/w/WitchsCottage.java @@ -1,7 +1,8 @@ package mage.cards.w; +import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldAbility; -import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.EntersBattlefieldUntappedTriggeredAbility; import mage.abilities.condition.Condition; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; import mage.abilities.decorator.ConditionalOneShotEffect; @@ -16,9 +17,7 @@ import mage.constants.SubType; import mage.filter.FilterPermanent; import mage.filter.StaticFilters; import mage.filter.common.FilterControlledPermanent; -import mage.game.Game; -import mage.game.events.GameEvent; -import mage.game.permanent.Permanent; +import mage.filter.predicate.permanent.AnotherPredicate; import mage.target.common.TargetCardInYourGraveyard; import java.util.UUID; @@ -30,6 +29,11 @@ public final class WitchsCottage extends CardImpl { private static final FilterPermanent filter = new FilterControlledPermanent(SubType.SWAMP); + + static { + filter.add(AnotherPredicate.instance); + } + private static final Condition condition = new PermanentsOnTheBattlefieldCondition(filter, ComparisonType.FEWER_THAN, 3); @@ -48,7 +52,13 @@ public final class WitchsCottage extends CardImpl { )); // When Witch's Cottage enters the battlefield untapped, you may put target creature card from your graveyard on top of your library. - this.addAbility(new WitchsCottageTriggeredAbility()); + Ability ability = new EntersBattlefieldUntappedTriggeredAbility( + new PutOnLibraryTargetEffect(true) + .setText("put target creature card from your graveyard on top of your library"), + true + ); + ability.addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD)); + this.addAbility(ability); } private WitchsCottage(final WitchsCottage card) { @@ -60,34 +70,3 @@ public final class WitchsCottage extends CardImpl { return new WitchsCottage(this); } } - -class WitchsCottageTriggeredAbility extends EntersBattlefieldTriggeredAbility { - - WitchsCottageTriggeredAbility() { - super(new PutOnLibraryTargetEffect(true), true); - this.addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD)); - } - - private WitchsCottageTriggeredAbility(final WitchsCottageTriggeredAbility ability) { - super(ability); - } - - @Override - public WitchsCottageTriggeredAbility copy() { - return new WitchsCottageTriggeredAbility(this); - } - - @Override - public boolean checkTrigger(GameEvent event, Game game) { - if (!super.checkTrigger(event, game)) { - return false; - } - Permanent permanent = game.getPermanent(event.getTargetId()); - return permanent != null && permanent.isTapped(); - } - - @Override - public String getRule() { - return "When {this} enters the battlefield untapped, you may put target creature card from your graveyard on top of your library."; - } -} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/w/WitchsOven.java b/Mage.Sets/src/mage/cards/w/WitchsOven.java new file mode 100644 index 0000000000..aa1d4807d8 --- /dev/null +++ b/Mage.Sets/src/mage/cards/w/WitchsOven.java @@ -0,0 +1,87 @@ +package mage.cards.w; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.SacrificeTargetCost; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.effects.Effect; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.game.permanent.token.FoodToken; +import mage.target.common.TargetControlledCreaturePermanent; + +import java.util.Collection; +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class WitchsOven extends CardImpl { + + public WitchsOven(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{1}"); + + // {T}, Sacrifice a creature: Create a Food token. If the sacrificed creature's toughness was 4 or greater, create two Food tokens instead. + Ability ability = new SimpleActivatedAbility(new WitchsOvenEffect(), new TapSourceCost()); + ability.addCost(new SacrificeTargetCost( + new TargetControlledCreaturePermanent(StaticFilters.FILTER_CONTROLLED_CREATURE_SHORT_TEXT) + )); + this.addAbility(ability); + } + + private WitchsOven(final WitchsOven card) { + super(card); + } + + @Override + public WitchsOven copy() { + return new WitchsOven(this); + } +} + +class WitchsOvenEffect extends OneShotEffect { + + private static final Effect effect1 = new CreateTokenEffect(new FoodToken(), 1); + private static final Effect effect2 = new CreateTokenEffect(new FoodToken(), 2); + + WitchsOvenEffect() { + super(Outcome.Benefit); + staticText = "Create a Food token. If the sacrificed creature's toughness " + + "was 4 or greater, create two Food tokens instead"; + } + + private WitchsOvenEffect(final WitchsOvenEffect effect) { + super(effect); + } + + @Override + public WitchsOvenEffect copy() { + return new WitchsOvenEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + boolean big = source + .getCosts() + .stream() + .filter(SacrificeTargetCost.class::isInstance) + .map(SacrificeTargetCost.class::cast) + .map(SacrificeTargetCost::getPermanents) + .flatMap(Collection::stream) + .map(Permanent::getToughness) + .mapToInt(MageInt::getValue) + .anyMatch(i -> i > 3); + if (big) { + return effect2.apply(game, source); + } + return effect1.apply(game, source); + } +} diff --git a/Mage.Sets/src/mage/cards/w/WitchsVengeance.java b/Mage.Sets/src/mage/cards/w/WitchsVengeance.java new file mode 100644 index 0000000000..c75558b519 --- /dev/null +++ b/Mage.Sets/src/mage/cards/w/WitchsVengeance.java @@ -0,0 +1,75 @@ +package mage.cards.w; + +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.continuous.BoostAllEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.choices.ChoiceCreatureType; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.mageobject.SubtypePredicate; +import mage.game.Game; +import mage.players.Player; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class WitchsVengeance extends CardImpl { + + public WitchsVengeance(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{1}{B}{B}"); + + // Creatures of the creature type of your choice get -3/-3 until end of turn. + this.getSpellAbility().addEffect(new WitchsVengeanceEffect()); + } + + private WitchsVengeance(final WitchsVengeance card) { + super(card); + } + + @Override + public WitchsVengeance copy() { + return new WitchsVengeance(this); + } +} + +class WitchsVengeanceEffect extends OneShotEffect { + + WitchsVengeanceEffect() { + super(Outcome.Benefit); + staticText = "Creatures of the creature type of your choice get -3/-3 until end of turn."; + } + + private WitchsVengeanceEffect(final WitchsVengeanceEffect effect) { + super(effect); + } + + @Override + public WitchsVengeanceEffect copy() { + return new WitchsVengeanceEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; + } + ChoiceCreatureType choice = new ChoiceCreatureType(); + if (!player.choose(outcome, choice, game)) { + return false; + } + FilterCreaturePermanent filter = new FilterCreaturePermanent(); + filter.add(new SubtypePredicate(SubType.byDescription(choice.getChoice()))); + game.addEffect(new BoostAllEffect( + -3, -3, Duration.EndOfTurn, filter, false + ), source); + return true; + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/w/WolfsQuarry.java b/Mage.Sets/src/mage/cards/w/WolfsQuarry.java new file mode 100644 index 0000000000..befa35de34 --- /dev/null +++ b/Mage.Sets/src/mage/cards/w/WolfsQuarry.java @@ -0,0 +1,31 @@ +package mage.cards.w; + +import mage.abilities.effects.common.CreateTokenEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.game.permanent.token.WolfsQuarryToken; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class WolfsQuarry extends CardImpl { + + public WolfsQuarry(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{4}{G}{G}"); + + // Create three 1/1 green Boar creature tokens with "When this creature dies, create a Food token." + this.getSpellAbility().addEffect(new CreateTokenEffect(new WolfsQuarryToken(), 3)); + } + + private WolfsQuarry(final WolfsQuarry card) { + super(card); + } + + @Override + public WolfsQuarry copy() { + return new WolfsQuarry(this); + } +} diff --git a/Mage.Sets/src/mage/cards/w/WorthyKnight.java b/Mage.Sets/src/mage/cards/w/WorthyKnight.java new file mode 100644 index 0000000000..636dbc351a --- /dev/null +++ b/Mage.Sets/src/mage/cards/w/WorthyKnight.java @@ -0,0 +1,49 @@ +package mage.cards.w; + +import mage.MageInt; +import mage.abilities.common.SpellCastControllerTriggeredAbility; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.filter.FilterSpell; +import mage.filter.predicate.mageobject.SubtypePredicate; +import mage.game.permanent.token.HumanToken; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class WorthyKnight extends CardImpl { + + private static final FilterSpell filter = new FilterSpell("a Knight spell"); + + static { + filter.add(new SubtypePredicate(SubType.KNIGHT)); + } + + public WorthyKnight(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.KNIGHT); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // Whenever you cast a Knight spell, create a 1/1 white Human creature token. + this.addAbility(new SpellCastControllerTriggeredAbility( + new CreateTokenEffect(new HumanToken()), filter, false + )); + } + + private WorthyKnight(final WorthyKnight card) { + super(card); + } + + @Override + public WorthyKnight copy() { + return new WorthyKnight(this); + } +} diff --git a/Mage.Sets/src/mage/cards/y/YorvoLordOfGarenbrig.java b/Mage.Sets/src/mage/cards/y/YorvoLordOfGarenbrig.java new file mode 100644 index 0000000000..d9cdc571ff --- /dev/null +++ b/Mage.Sets/src/mage/cards/y/YorvoLordOfGarenbrig.java @@ -0,0 +1,101 @@ +package mage.cards.y; + +import mage.MageInt; +import mage.ObjectColor; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldAbility; +import mage.abilities.common.EntersBattlefieldControlledTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.counters.CounterType; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.mageobject.ColorPredicate; +import mage.filter.predicate.permanent.AnotherPredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class YorvoLordOfGarenbrig extends CardImpl { + + private static final FilterPermanent filter = new FilterCreaturePermanent(); + + static { + filter.add(AnotherPredicate.instance); + filter.add(new ColorPredicate(ObjectColor.GREEN)); + } + + public YorvoLordOfGarenbrig(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{G}{G}{G}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.GIANT); + this.subtype.add(SubType.NOBLE); + this.power = new MageInt(0); + this.toughness = new MageInt(0); + + // Yorvo, Lord of Garenbrig enters the battlefield with four +1/+1 counters on it. + this.addAbility(new EntersBattlefieldAbility( + new AddCountersSourceEffect(CounterType.P1P1.createInstance(4)), + "{this} enters the battlefield with four +1/+1 counters on it" + )); + + // Whenever another green creature enters the battlefield under your control, put a +1/+1 counter on Yorvo. Then if that creature's power is greater than Yorvo's power, put another +1/+1 counter on Yorvo. + this.addAbility(new EntersBattlefieldControlledTriggeredAbility( + Zone.BATTLEFIELD, new YorvoLordOfGarenbrigEffect(), filter, false, SetTargetPointer.PERMANENT, + "Whenever another green creature enters the battlefield under your control, " + + "put a +1/+1 counter on {this}. Then if that creature's power is greater than {this}'s power, " + + "put another +1/+1 counter on {this}." + )); + } + + private YorvoLordOfGarenbrig(final YorvoLordOfGarenbrig card) { + super(card); + } + + @Override + public YorvoLordOfGarenbrig copy() { + return new YorvoLordOfGarenbrig(this); + } +} + +class YorvoLordOfGarenbrigEffect extends OneShotEffect { + + YorvoLordOfGarenbrigEffect() { + super(Outcome.Benefit); + } + + private YorvoLordOfGarenbrigEffect(final YorvoLordOfGarenbrigEffect effect) { + super(effect); + } + + @Override + public YorvoLordOfGarenbrigEffect copy() { + return new YorvoLordOfGarenbrigEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent sourcePerm = game.getPermanent(source.getSourceId()); + if (sourcePerm == null) { + return false; + } + sourcePerm.addCounters(CounterType.P1P1.createInstance(), source, game); + Permanent permanent = game.getPermanentOrLKIBattlefield(targetPointer.getFirst(game, source)); + if (permanent == null) { + return true; + } + game.applyEffects(); + if (permanent.getPower().getValue() > sourcePerm.getPower().getValue()) { + sourcePerm.addCounters(CounterType.P1P1.createInstance(), source, game); + } + return true; + } +} diff --git a/Mage.Sets/src/mage/sets/Apocalypse.java b/Mage.Sets/src/mage/sets/Apocalypse.java index e327b2f80c..787c55c20a 100644 --- a/Mage.Sets/src/mage/sets/Apocalypse.java +++ b/Mage.Sets/src/mage/sets/Apocalypse.java @@ -66,6 +66,7 @@ public final class Apocalypse extends ExpansionSet { cards.add(new SetCardInfo("Flowstone Charger", 99, Rarity.UNCOMMON, mage.cards.f.FlowstoneCharger.class)); cards.add(new SetCardInfo("Foul Presence", 39, Rarity.UNCOMMON, mage.cards.f.FoulPresence.class)); cards.add(new SetCardInfo("Fungal Shambler", 100, Rarity.RARE, mage.cards.f.FungalShambler.class)); + cards.add(new SetCardInfo("Gaea's Balance", 77, Rarity.UNCOMMON, mage.cards.g.GaeasBalance.class)); cards.add(new SetCardInfo("Gaea's Skyfolk", 101, Rarity.COMMON, mage.cards.g.GaeasSkyfolk.class)); cards.add(new SetCardInfo("Gerrard Capashen", 11, Rarity.RARE, mage.cards.g.GerrardCapashen.class)); cards.add(new SetCardInfo("Gerrard's Verdict", 102, Rarity.UNCOMMON, mage.cards.g.GerrardsVerdict.class)); diff --git a/Mage.Sets/src/mage/sets/Commander2018Edition.java b/Mage.Sets/src/mage/sets/Commander2018Edition.java index ac3896c801..073f6299fa 100644 --- a/Mage.Sets/src/mage/sets/Commander2018Edition.java +++ b/Mage.Sets/src/mage/sets/Commander2018Edition.java @@ -27,7 +27,7 @@ public final class Commander2018Edition extends ExpansionSet { cards.add(new SetCardInfo("Akoum Refuge", 231, Rarity.UNCOMMON, mage.cards.a.AkoumRefuge.class)); cards.add(new SetCardInfo("Akroma's Vengeance", 62, Rarity.RARE, mage.cards.a.AkromasVengeance.class)); cards.add(new SetCardInfo("Aminatou's Augury", 6, Rarity.RARE, mage.cards.a.AminatousAugury.class)); - cards.add(new SetCardInfo("Aminatou, the Fateshifter", 37, Rarity.MYTHIC, mage.cards.a.AminatouTheFateShifter.class)); + cards.add(new SetCardInfo("Aminatou, the Fateshifter", 37, Rarity.MYTHIC, mage.cards.a.AminatouTheFateshifter.class)); cards.add(new SetCardInfo("Ancient Stone Idol", 53, Rarity.RARE, mage.cards.a.AncientStoneIdol.class)); cards.add(new SetCardInfo("Arcane Sanctum", 232, Rarity.UNCOMMON, mage.cards.a.ArcaneSanctum.class)); cards.add(new SetCardInfo("Archetype of Imagination", 81, Rarity.UNCOMMON, mage.cards.a.ArchetypeOfImagination.class)); diff --git a/Mage.Sets/src/mage/sets/Dissension.java b/Mage.Sets/src/mage/sets/Dissension.java index 3aabb0d2ce..0b1ca43840 100644 --- a/Mage.Sets/src/mage/sets/Dissension.java +++ b/Mage.Sets/src/mage/sets/Dissension.java @@ -33,7 +33,7 @@ public final class Dissension extends ExpansionSet { cards.add(new SetCardInfo("Assault Zeppelid", 103, Rarity.COMMON, mage.cards.a.AssaultZeppelid.class)); cards.add(new SetCardInfo("Aurora Eidolon", 1, Rarity.COMMON, mage.cards.a.AuroraEidolon.class)); cards.add(new SetCardInfo("Avatar of Discord", 140, Rarity.RARE, mage.cards.a.AvatarOfDiscord.class)); - cards.add(new SetCardInfo("Azorius Aethermage", 104, Rarity.UNCOMMON, mage.cards.a.AzoriusAEthermage.class)); + cards.add(new SetCardInfo("Azorius Aethermage", 104, Rarity.UNCOMMON, mage.cards.a.AzoriusAethermage.class)); cards.add(new SetCardInfo("Azorius Chancery", 170, Rarity.COMMON, mage.cards.a.AzoriusChancery.class)); cards.add(new SetCardInfo("Azorius First-Wing", 105, Rarity.COMMON, mage.cards.a.AzoriusFirstWing.class)); cards.add(new SetCardInfo("Azorius Guildmage", 141, Rarity.UNCOMMON, mage.cards.a.AzoriusGuildmage.class)); diff --git a/Mage.Sets/src/mage/sets/GameNight2019.java b/Mage.Sets/src/mage/sets/GameNight2019.java new file mode 100644 index 0000000000..ece39af080 --- /dev/null +++ b/Mage.Sets/src/mage/sets/GameNight2019.java @@ -0,0 +1,28 @@ +package mage.sets; + +import mage.cards.ExpansionSet; +import mage.constants.Rarity; +import mage.constants.SetType; + +/** + * @author TheElk801 + */ +public final class GameNight2019 extends ExpansionSet { + + private static final GameNight2019 instance = new GameNight2019(); + + public static GameNight2019 getInstance() { + return instance; + } + + private GameNight2019() { + super("Game Night 2019", "GN2", ExpansionSet.buildDate(2019, 11, 15), SetType.SUPPLEMENTAL); + this.hasBasicLands = false; // TODO: change when spoiled + + cards.add(new SetCardInfo("Calculating Lich", 3, Rarity.MYTHIC, mage.cards.c.CalculatingLich.class)); + cards.add(new SetCardInfo("Earthshaker Giant", 5, Rarity.MYTHIC, mage.cards.e.EarthshakerGiant.class)); + cards.add(new SetCardInfo("Fiendish Duo", 4, Rarity.MYTHIC, mage.cards.f.FiendishDuo.class)); + cards.add(new SetCardInfo("Highcliff Felidar", 1, Rarity.MYTHIC, mage.cards.h.HighcliffFelidar.class)); + cards.add(new SetCardInfo("Sphinx of Enlightenment", 2, Rarity.MYTHIC, mage.cards.s.SphinxOfEnlightenment.class)); + } +} diff --git a/Mage.Sets/src/mage/sets/IceAge.java b/Mage.Sets/src/mage/sets/IceAge.java index 5c0ab4bc85..1e22abab70 100644 --- a/Mage.Sets/src/mage/sets/IceAge.java +++ b/Mage.Sets/src/mage/sets/IceAge.java @@ -32,6 +32,7 @@ public final class IceAge extends ExpansionSet { cards.add(new SetCardInfo("Aggression", 169, Rarity.UNCOMMON, mage.cards.a.Aggression.class)); cards.add(new SetCardInfo("Altar of Bone", 281, Rarity.RARE, mage.cards.a.AltarOfBone.class)); cards.add(new SetCardInfo("Anarchy", 170, Rarity.UNCOMMON, mage.cards.a.Anarchy.class)); + cards.add(new SetCardInfo("Arctic Foxes", 2, Rarity.COMMON, mage.cards.a.ArcticFoxes.class)); cards.add(new SetCardInfo("Arenson's Aura", 3, Rarity.COMMON, mage.cards.a.ArensonsAura.class)); cards.add(new SetCardInfo("Armor of Faith", 4, Rarity.COMMON, mage.cards.a.ArmorOfFaith.class)); cards.add(new SetCardInfo("Arnjlot's Ascent", 57, Rarity.COMMON, mage.cards.a.ArnjlotsAscent.class)); @@ -99,6 +100,7 @@ public final class IceAge extends ExpansionSet { cards.add(new SetCardInfo("Elder Druid", 232, Rarity.RARE, mage.cards.e.ElderDruid.class)); cards.add(new SetCardInfo("Elemental Augury", 286, Rarity.RARE, mage.cards.e.ElementalAugury.class)); cards.add(new SetCardInfo("Elkin Bottle", 317, Rarity.RARE, mage.cards.e.ElkinBottle.class)); + cards.add(new SetCardInfo("Elvish Healer", 22, Rarity.COMMON, mage.cards.e.ElvishHealer.class)); cards.add(new SetCardInfo("Enduring Renewal", 23, Rarity.RARE, mage.cards.e.EnduringRenewal.class)); cards.add(new SetCardInfo("Energy Storm", 24, Rarity.RARE, mage.cards.e.EnergyStorm.class)); cards.add(new SetCardInfo("Enervate", 67, Rarity.COMMON, mage.cards.e.Enervate.class)); @@ -106,6 +108,7 @@ public final class IceAge extends ExpansionSet { cards.add(new SetCardInfo("Errantry", 183, Rarity.COMMON, mage.cards.e.Errantry.class)); cards.add(new SetCardInfo("Essence Filter", 233, Rarity.COMMON, mage.cards.e.EssenceFilter.class)); cards.add(new SetCardInfo("Essence Flare", 69, Rarity.COMMON, mage.cards.e.EssenceFlare.class)); + cards.add(new SetCardInfo("Essence Vortex", 287, Rarity.UNCOMMON, mage.cards.e.EssenceVortex.class)); cards.add(new SetCardInfo("Fanatical Fever", 234, Rarity.UNCOMMON, mage.cards.f.FanaticalFever.class)); cards.add(new SetCardInfo("Fear", 124, Rarity.COMMON, mage.cards.f.Fear.class)); cards.add(new SetCardInfo("Fiery Justice", 288, Rarity.RARE, mage.cards.f.FieryJustice.class)); @@ -118,8 +121,6 @@ public final class IceAge extends ExpansionSet { cards.add(new SetCardInfo("Forbidden Lore", 236, Rarity.RARE, mage.cards.f.ForbiddenLore.class)); cards.add(new SetCardInfo("Force Void", 70, Rarity.UNCOMMON, mage.cards.f.ForceVoid.class)); cards.add(new SetCardInfo("Forest", 380, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Forest", 381, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Forest", 382, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Forgotten Lore", 237, Rarity.UNCOMMON, mage.cards.f.ForgottenLore.class)); cards.add(new SetCardInfo("Formation", 25, Rarity.RARE, mage.cards.f.Formation.class)); cards.add(new SetCardInfo("Foul Familiar", 126, Rarity.COMMON, mage.cards.f.FoulFamiliar.class)); @@ -150,6 +151,7 @@ public final class IceAge extends ExpansionSet { cards.add(new SetCardInfo("Gorilla Pack", 247, Rarity.COMMON, mage.cards.g.GorillaPack.class)); cards.add(new SetCardInfo("Gravebind", 129, Rarity.RARE, mage.cards.g.Gravebind.class)); cards.add(new SetCardInfo("Green Scarab", 28, Rarity.UNCOMMON, mage.cards.g.GreenScarab.class)); + cards.add(new SetCardInfo("Grizzled Wolverine", 192, Rarity.COMMON, mage.cards.g.GrizzledWolverine.class)); cards.add(new SetCardInfo("Hallowed Ground", 29, Rarity.UNCOMMON, mage.cards.h.HallowedGround.class)); cards.add(new SetCardInfo("Halls of Mist", 354, Rarity.RARE, mage.cards.h.HallsOfMist.class)); cards.add(new SetCardInfo("Heal", 30, Rarity.COMMON, mage.cards.h.Heal.class)); @@ -309,6 +311,7 @@ public final class IceAge extends ExpansionSet { cards.add(new SetCardInfo("Snow-Covered Mountain", 379, Rarity.LAND, mage.cards.s.SnowCoveredMountain.class)); cards.add(new SetCardInfo("Snow-Covered Plains", 367, Rarity.LAND, mage.cards.s.SnowCoveredPlains.class)); cards.add(new SetCardInfo("Snow-Covered Swamp", 372, Rarity.LAND, mage.cards.s.SnowCoveredSwamp.class)); + cards.add(new SetCardInfo("Snowblind", 264, Rarity.RARE, mage.cards.s.Snowblind.class)); cards.add(new SetCardInfo("Soldevi Golem", 338, Rarity.RARE, mage.cards.s.SoldeviGolem.class)); cards.add(new SetCardInfo("Soldevi Machinist", 102, Rarity.UNCOMMON, mage.cards.s.SoldeviMachinist.class)); cards.add(new SetCardInfo("Soldevi Simulacrum", 339, Rarity.UNCOMMON, mage.cards.s.SoldeviSimulacrum.class)); diff --git a/Mage.Sets/src/mage/sets/IconicMasters.java b/Mage.Sets/src/mage/sets/IconicMasters.java index b4dcaf5e24..a211bac386 100644 --- a/Mage.Sets/src/mage/sets/IconicMasters.java +++ b/Mage.Sets/src/mage/sets/IconicMasters.java @@ -1,4 +1,3 @@ - package mage.sets; import mage.cards.ExpansionSet; @@ -6,7 +5,6 @@ import mage.constants.Rarity; import mage.constants.SetType; /** - * * @author MajorLazar */ public final class IconicMasters extends ExpansionSet { @@ -28,255 +26,254 @@ public final class IconicMasters extends ExpansionSet { this.numBoosterRare = 1; this.ratioBoosterMythic = 8; - cards.add(new SetCardInfo("Scion of Ugin", 1, Rarity.COMMON, mage.cards.s.ScionOfUgin.class)); + cards.add(new SetCardInfo("Abyssal Persecutor", 78, Rarity.RARE, mage.cards.a.AbyssalPersecutor.class)); cards.add(new SetCardInfo("Abzan Battle Priest", 2, Rarity.UNCOMMON, mage.cards.a.AbzanBattlePriest.class)); cards.add(new SetCardInfo("Abzan Falconer", 3, Rarity.UNCOMMON, mage.cards.a.AbzanFalconer.class)); + cards.add(new SetCardInfo("Aerial Predation", 154, Rarity.COMMON, mage.cards.a.AerialPredation.class)); + cards.add(new SetCardInfo("Aether Vial", 212, Rarity.RARE, mage.cards.a.AetherVial.class)); + cards.add(new SetCardInfo("Aetherize", 40, Rarity.UNCOMMON, mage.cards.a.Aetherize.class)); cards.add(new SetCardInfo("Ainok Bond-Kin", 4, Rarity.COMMON, mage.cards.a.AinokBondKin.class)); cards.add(new SetCardInfo("Ajani's Pridemate", 5, Rarity.UNCOMMON, mage.cards.a.AjanisPridemate.class)); + cards.add(new SetCardInfo("Amass the Components", 41, Rarity.COMMON, mage.cards.a.AmassTheComponents.class)); + cards.add(new SetCardInfo("Ancestral Vision", 42, Rarity.RARE, mage.cards.a.AncestralVision.class)); cards.add(new SetCardInfo("Angel of Mercy", 6, Rarity.COMMON, mage.cards.a.AngelOfMercy.class)); cards.add(new SetCardInfo("Angelic Accord", 7, Rarity.UNCOMMON, mage.cards.a.AngelicAccord.class)); + cards.add(new SetCardInfo("Anger of the Gods", 116, Rarity.RARE, mage.cards.a.AngerOfTheGods.class)); cards.add(new SetCardInfo("Archangel of Thune", 8, Rarity.MYTHIC, mage.cards.a.ArchangelOfThune.class)); + cards.add(new SetCardInfo("Assault Formation", 155, Rarity.UNCOMMON, mage.cards.a.AssaultFormation.class)); cards.add(new SetCardInfo("Auriok Champion", 9, Rarity.RARE, mage.cards.a.AuriokChampion.class)); cards.add(new SetCardInfo("Austere Command", 10, Rarity.RARE, mage.cards.a.AustereCommand.class)); cards.add(new SetCardInfo("Avacyn, Angel of Hope", 11, Rarity.MYTHIC, mage.cards.a.AvacynAngelOfHope.class)); + cards.add(new SetCardInfo("Azorius Chancery", 232, Rarity.UNCOMMON, mage.cards.a.AzoriusChancery.class)); + cards.add(new SetCardInfo("Azorius Charm", 192, Rarity.UNCOMMON, mage.cards.a.AzoriusCharm.class)); + cards.add(new SetCardInfo("Bala Ged Scorpion", 79, Rarity.COMMON, mage.cards.b.BalaGedScorpion.class)); + cards.add(new SetCardInfo("Balustrade Spy", 80, Rarity.COMMON, mage.cards.b.BalustradeSpy.class)); + cards.add(new SetCardInfo("Battle-Rattle Shaman", 117, Rarity.COMMON, mage.cards.b.BattleRattleShaman.class)); cards.add(new SetCardInfo("Benevolent Ancestor", 12, Rarity.COMMON, mage.cards.b.BenevolentAncestor.class)); - cards.add(new SetCardInfo("Blinding Mage", 13, Rarity.COMMON, mage.cards.b.BlindingMage.class)); - cards.add(new SetCardInfo("Burrenton Forge-Tender", 14, Rarity.UNCOMMON, mage.cards.b.BurrentonForgeTender.class)); - cards.add(new SetCardInfo("Disenchant", 15, Rarity.COMMON, mage.cards.d.Disenchant.class)); - cards.add(new SetCardInfo("Doomed Traveler", 16, Rarity.COMMON, mage.cards.d.DoomedTraveler.class)); - cards.add(new SetCardInfo("Dragon Bell Monk", 17, Rarity.COMMON, mage.cards.d.DragonBellMonk.class)); - cards.add(new SetCardInfo("Elesh Norn, Grand Cenobite", 18, Rarity.MYTHIC, mage.cards.e.EleshNornGrandCenobite.class)); - cards.add(new SetCardInfo("Emerge Unscathed", 19, Rarity.COMMON, mage.cards.e.EmergeUnscathed.class)); - cards.add(new SetCardInfo("Emeria Angel", 20, Rarity.RARE, mage.cards.e.EmeriaAngel.class)); - cards.add(new SetCardInfo("Great Teacher's Decree", 21, Rarity.UNCOMMON, mage.cards.g.GreatTeachersDecree.class)); - cards.add(new SetCardInfo("Guard Duty", 22, Rarity.COMMON, mage.cards.g.GuardDuty.class)); - cards.add(new SetCardInfo("Guided Strike", 23, Rarity.COMMON, mage.cards.g.GuidedStrike.class)); - cards.add(new SetCardInfo("Infantry Veteran", 24, Rarity.COMMON, mage.cards.i.InfantryVeteran.class)); - cards.add(new SetCardInfo("Iona's Judgment", 25, Rarity.COMMON, mage.cards.i.IonasJudgment.class)); - cards.add(new SetCardInfo("Path of Bravery", 26, Rarity.RARE, mage.cards.p.PathOfBravery.class)); - cards.add(new SetCardInfo("Pentarch Ward", 27, Rarity.COMMON, mage.cards.p.PentarchWard.class)); - cards.add(new SetCardInfo("Restoration Angel", 28, Rarity.RARE, mage.cards.r.RestorationAngel.class)); - cards.add(new SetCardInfo("Seeker of the Way", 29, Rarity.COMMON, mage.cards.s.SeekerOfTheWay.class)); - cards.add(new SetCardInfo("Serra Angel", 30, Rarity.UNCOMMON, mage.cards.s.SerraAngel.class)); - cards.add(new SetCardInfo("Serra Ascendant", 31, Rarity.RARE, mage.cards.s.SerraAscendant.class)); - cards.add(new SetCardInfo("Stalwart Aven", 32, Rarity.COMMON, mage.cards.s.StalwartAven.class)); - cards.add(new SetCardInfo("Student of Ojutai", 33, Rarity.COMMON, mage.cards.s.StudentOfOjutai.class)); - cards.add(new SetCardInfo("Survival Cache", 34, Rarity.COMMON, mage.cards.s.SurvivalCache.class)); - cards.add(new SetCardInfo("Sustainer of the Realm", 35, Rarity.COMMON, mage.cards.s.SustainerOfTheRealm.class)); - cards.add(new SetCardInfo("Swords to Plowshares", 36, Rarity.UNCOMMON, mage.cards.s.SwordsToPlowshares.class)); - cards.add(new SetCardInfo("Topan Freeblade", 37, Rarity.UNCOMMON, mage.cards.t.TopanFreeblade.class)); - cards.add(new SetCardInfo("Wing Shards", 38, Rarity.UNCOMMON, mage.cards.w.WingShards.class)); - cards.add(new SetCardInfo("Yosei, the Morning Star", 39, Rarity.RARE, mage.cards.y.YoseiTheMorningStar.class)); - cards.add(new SetCardInfo("Aetherize", 40, Rarity.UNCOMMON, mage.cards.a.Aetherize.class)); - cards.add(new SetCardInfo("Amass the Components", 41, Rarity.COMMON, mage.cards.a.AmassTheComponents.class)); - cards.add(new SetCardInfo("Ancestral Vision", 42, Rarity.RARE, mage.cards.a.AncestralVision.class)); cards.add(new SetCardInfo("Bewilder", 43, Rarity.COMMON, mage.cards.b.Bewilder.class)); + cards.add(new SetCardInfo("Bladewing the Risen", 193, Rarity.UNCOMMON, mage.cards.b.BladewingTheRisen.class)); + cards.add(new SetCardInfo("Bladewing's Thrall", 81, Rarity.UNCOMMON, mage.cards.b.BladewingsThrall.class)); + cards.add(new SetCardInfo("Blinding Mage", 13, Rarity.COMMON, mage.cards.b.BlindingMage.class)); + cards.add(new SetCardInfo("Blizzard Specter", 194, Rarity.UNCOMMON, mage.cards.b.BlizzardSpecter.class)); + cards.add(new SetCardInfo("Blood Baron of Vizkopa", 195, Rarity.RARE, mage.cards.b.BloodBaronOfVizkopa.class)); + cards.add(new SetCardInfo("Bloodghast", 82, Rarity.RARE, mage.cards.b.Bloodghast.class)); + cards.add(new SetCardInfo("Bogardan Hellkite", 118, Rarity.RARE, mage.cards.b.BogardanHellkite.class)); + cards.add(new SetCardInfo("Bogbrew Witch", 83, Rarity.UNCOMMON, mage.cards.b.BogbrewWitch.class)); + cards.add(new SetCardInfo("Borderland Marauder", 119, Rarity.COMMON, mage.cards.b.BorderlandMarauder.class)); + cards.add(new SetCardInfo("Boros Garrison", 233, Rarity.UNCOMMON, mage.cards.b.BorosGarrison.class)); + cards.add(new SetCardInfo("Bubbling Cauldron", 213, Rarity.UNCOMMON, mage.cards.b.BubblingCauldron.class)); + cards.add(new SetCardInfo("Burrenton Forge-Tender", 14, Rarity.UNCOMMON, mage.cards.b.BurrentonForgeTender.class)); + cards.add(new SetCardInfo("Butcher's Glee", 84, Rarity.COMMON, mage.cards.b.ButchersGlee.class)); + cards.add(new SetCardInfo("Carven Caryatid", 156, Rarity.UNCOMMON, mage.cards.c.CarvenCaryatid.class)); cards.add(new SetCardInfo("Cephalid Broker", 44, Rarity.UNCOMMON, mage.cards.c.CephalidBroker.class)); + cards.add(new SetCardInfo("Channel", 157, Rarity.MYTHIC, mage.cards.c.Channel.class)); + cards.add(new SetCardInfo("Charmbreaker Devils", 120, Rarity.RARE, mage.cards.c.CharmbreakerDevils.class)); + cards.add(new SetCardInfo("Child of Night", 85, Rarity.COMMON, mage.cards.c.ChildOfNight.class)); + cards.add(new SetCardInfo("Chronicler of Heroes", 196, Rarity.UNCOMMON, mage.cards.c.ChroniclerOfHeroes.class)); cards.add(new SetCardInfo("Claustrophobia", 45, Rarity.COMMON, mage.cards.c.Claustrophobia.class)); cards.add(new SetCardInfo("Condescend", 46, Rarity.UNCOMMON, mage.cards.c.Condescend.class)); cards.add(new SetCardInfo("Consecrated Sphinx", 47, Rarity.MYTHIC, mage.cards.c.ConsecratedSphinx.class)); + cards.add(new SetCardInfo("Coordinated Assault", 121, Rarity.UNCOMMON, mage.cards.c.CoordinatedAssault.class)); + cards.add(new SetCardInfo("Corpsejack Menace", 197, Rarity.UNCOMMON, mage.cards.c.CorpsejackMenace.class)); + cards.add(new SetCardInfo("Crowned Ceratok", 158, Rarity.COMMON, mage.cards.c.CrownedCeratok.class)); + cards.add(new SetCardInfo("Crucible of Fire", 122, Rarity.RARE, mage.cards.c.CrucibleOfFire.class)); cards.add(new SetCardInfo("Cryptic Command", 48, Rarity.RARE, mage.cards.c.CrypticCommand.class)); + cards.add(new SetCardInfo("Curse of Predation", 159, Rarity.RARE, mage.cards.c.CurseOfPredation.class)); + cards.add(new SetCardInfo("Darksteel Axe", 214, Rarity.COMMON, mage.cards.d.DarksteelAxe.class)); cards.add(new SetCardInfo("Day of the Dragons", 49, Rarity.RARE, mage.cards.d.DayOfTheDragons.class)); + cards.add(new SetCardInfo("Dead Reveler", 86, Rarity.COMMON, mage.cards.d.DeadReveler.class)); cards.add(new SetCardInfo("Diminish", 50, Rarity.COMMON, mage.cards.d.Diminish.class)); + cards.add(new SetCardInfo("Dimir Aqueduct", 234, Rarity.UNCOMMON, mage.cards.d.DimirAqueduct.class)); + cards.add(new SetCardInfo("Disenchant", 15, Rarity.COMMON, mage.cards.d.Disenchant.class)); cards.add(new SetCardInfo("Dissolve", 51, Rarity.COMMON, mage.cards.d.Dissolve.class)); cards.add(new SetCardInfo("Distortion Strike", 52, Rarity.UNCOMMON, mage.cards.d.DistortionStrike.class)); - cards.add(new SetCardInfo("Doorkeeper", 53, Rarity.COMMON, mage.cards.d.Doorkeeper.class)); - cards.add(new SetCardInfo("Elusive Spellfist", 54, Rarity.COMMON, mage.cards.e.ElusiveSpellfist.class)); - cards.add(new SetCardInfo("Flusterstorm", 55, Rarity.RARE, mage.cards.f.Flusterstorm.class)); - cards.add(new SetCardInfo("Fog Bank", 56, Rarity.UNCOMMON, mage.cards.f.FogBank.class)); - cards.add(new SetCardInfo("Frost Lynx", 57, Rarity.COMMON, mage.cards.f.FrostLynx.class)); - cards.add(new SetCardInfo("Illusory Ambusher", 58, Rarity.UNCOMMON, mage.cards.i.IllusoryAmbusher.class)); - cards.add(new SetCardInfo("Illusory Angel", 59, Rarity.UNCOMMON, mage.cards.i.IllusoryAngel.class)); - cards.add(new SetCardInfo("Jace's Phantasm", 60, Rarity.COMMON, mage.cards.j.JacesPhantasm.class)); - cards.add(new SetCardInfo("Jhessian Thief", 61, Rarity.COMMON, mage.cards.j.JhessianThief.class)); - cards.add(new SetCardInfo("Jin-Gitaxias, Core Augur", 62, Rarity.MYTHIC, mage.cards.j.JinGitaxiasCoreAugur.class)); - cards.add(new SetCardInfo("Keiga, the Tide Star", 63, Rarity.RARE, mage.cards.k.KeigaTheTideStar.class)); - cards.add(new SetCardInfo("Mahamoti Djinn", 64, Rarity.UNCOMMON, mage.cards.m.MahamotiDjinn.class)); - cards.add(new SetCardInfo("Mana Drain", 65, Rarity.MYTHIC, mage.cards.m.ManaDrain.class)); - cards.add(new SetCardInfo("Mana Leak", 66, Rarity.COMMON, mage.cards.m.ManaLeak.class)); - cards.add(new SetCardInfo("Mnemonic Wall", 67, Rarity.COMMON, mage.cards.m.MnemonicWall.class)); - cards.add(new SetCardInfo("Ojutai's Breath", 68, Rarity.COMMON, mage.cards.o.OjutaisBreath.class)); - cards.add(new SetCardInfo("Phantom Monster", 69, Rarity.COMMON, mage.cards.p.PhantomMonster.class)); - cards.add(new SetCardInfo("Repeal", 70, Rarity.COMMON, mage.cards.r.Repeal.class)); - cards.add(new SetCardInfo("Riverwheel Aerialists", 71, Rarity.COMMON, mage.cards.r.RiverwheelAerialists.class)); - cards.add(new SetCardInfo("Shriekgeist", 72, Rarity.COMMON, mage.cards.s.Shriekgeist.class)); - cards.add(new SetCardInfo("Skywise Teachings", 73, Rarity.UNCOMMON, mage.cards.s.SkywiseTeachings.class)); - cards.add(new SetCardInfo("Sphinx of Uthuun", 74, Rarity.RARE, mage.cards.s.SphinxOfUthuun.class)); - cards.add(new SetCardInfo("Teferi, Mage of Zhalfir", 75, Rarity.RARE, mage.cards.t.TeferiMageOfZhalfir.class)); - cards.add(new SetCardInfo("Thought Scour", 76, Rarity.COMMON, mage.cards.t.ThoughtScour.class)); - cards.add(new SetCardInfo("Windfall", 77, Rarity.UNCOMMON, mage.cards.w.Windfall.class)); - cards.add(new SetCardInfo("Abyssal Persecutor", 78, Rarity.RARE, mage.cards.a.AbyssalPersecutor.class)); - cards.add(new SetCardInfo("Bala Ged Scorpion", 79, Rarity.COMMON, mage.cards.b.BalaGedScorpion.class)); - cards.add(new SetCardInfo("Balustrade Spy", 80, Rarity.COMMON, mage.cards.b.BalustradeSpy.class)); - cards.add(new SetCardInfo("Bladewing's Thrall", 81, Rarity.UNCOMMON, mage.cards.b.BladewingsThrall.class)); - cards.add(new SetCardInfo("Bloodghast", 82, Rarity.RARE, mage.cards.b.Bloodghast.class)); - cards.add(new SetCardInfo("Bogbrew Witch", 83, Rarity.UNCOMMON, mage.cards.b.BogbrewWitch.class)); - cards.add(new SetCardInfo("Butcher's Glee", 84, Rarity.COMMON, mage.cards.b.ButchersGlee.class)); - cards.add(new SetCardInfo("Child of Night", 85, Rarity.COMMON, mage.cards.c.ChildOfNight.class)); - cards.add(new SetCardInfo("Dead Reveler", 86, Rarity.COMMON, mage.cards.d.DeadReveler.class)); cards.add(new SetCardInfo("Doom Blade", 87, Rarity.UNCOMMON, mage.cards.d.DoomBlade.class)); - cards.add(new SetCardInfo("Duress", 88, Rarity.COMMON, mage.cards.d.Duress.class)); - cards.add(new SetCardInfo("Eternal Thirst", 89, Rarity.COMMON, mage.cards.e.EternalThirst.class)); - cards.add(new SetCardInfo("Festering Newt", 90, Rarity.COMMON, mage.cards.f.FesteringNewt.class)); - cards.add(new SetCardInfo("Foul-Tongue Invocation", 91, Rarity.COMMON, mage.cards.f.FoulTongueInvocation.class)); - cards.add(new SetCardInfo("Grisly Spectacle", 92, Rarity.COMMON, mage.cards.g.GrislySpectacle.class)); - cards.add(new SetCardInfo("Indulgent Tormentor", 93, Rarity.UNCOMMON, mage.cards.i.IndulgentTormentor.class)); - cards.add(new SetCardInfo("Haunting Hymn", 94, Rarity.UNCOMMON, mage.cards.h.HauntingHymn.class)); - cards.add(new SetCardInfo("Kokusho, the Evening Star", 95, Rarity.RARE, mage.cards.k.KokushoTheEveningStar.class)); - cards.add(new SetCardInfo("Lord of the Pit", 96, Rarity.RARE, mage.cards.l.LordOfThePit.class)); - cards.add(new SetCardInfo("Mer-Ek Nightblade", 97, Rarity.UNCOMMON, mage.cards.m.MerEkNightblade.class)); - cards.add(new SetCardInfo("Necropotence", 98, Rarity.MYTHIC, mage.cards.n.Necropotence.class)); - cards.add(new SetCardInfo("Night of Souls' Betrayal", 99, Rarity.RARE, mage.cards.n.NightOfSoulsBetrayal.class)); - cards.add(new SetCardInfo("Noxious Dragon", 100, Rarity.UNCOMMON, mage.cards.n.NoxiousDragon.class)); - cards.add(new SetCardInfo("Ob Nixilis, the Fallen", 101, Rarity.MYTHIC, mage.cards.o.ObNixilisTheFallen.class)); - cards.add(new SetCardInfo("Phyrexian Rager", 102, Rarity.COMMON, mage.cards.p.PhyrexianRager.class)); - cards.add(new SetCardInfo("Rakdos Drake", 103, Rarity.COMMON, mage.cards.r.RakdosDrake.class)); - cards.add(new SetCardInfo("Reave Soul", 104, Rarity.COMMON, mage.cards.r.ReaveSoul.class)); - cards.add(new SetCardInfo("Rotfeaster Maggot", 105, Rarity.COMMON, mage.cards.r.RotfeasterMaggot.class)); - cards.add(new SetCardInfo("Rune-Scarred Demon", 106, Rarity.RARE, mage.cards.r.RuneScarredDemon.class)); - cards.add(new SetCardInfo("Sanguine Bond", 107, Rarity.UNCOMMON, mage.cards.s.SanguineBond.class)); - cards.add(new SetCardInfo("Sheoldred, Whispering One", 108, Rarity.MYTHIC, mage.cards.s.SheoldredWhisperingOne.class)); - cards.add(new SetCardInfo("Tavern Swindler", 109, Rarity.UNCOMMON, mage.cards.t.TavernSwindler.class)); - cards.add(new SetCardInfo("Thoughtseize", 110, Rarity.RARE, mage.cards.t.Thoughtseize.class)); - cards.add(new SetCardInfo("Thrill-Kill Assassin", 111, Rarity.COMMON, mage.cards.t.ThrillKillAssassin.class)); - cards.add(new SetCardInfo("Virulent Swipe", 112, Rarity.COMMON, mage.cards.v.VirulentSwipe.class)); - cards.add(new SetCardInfo("Wight of Precinct Six", 113, Rarity.COMMON, mage.cards.w.WightOfPrecinctSix.class)); - cards.add(new SetCardInfo("Ulcerate", 114, Rarity.UNCOMMON, mage.cards.u.Ulcerate.class)); - cards.add(new SetCardInfo("Wrench Mind", 115, Rarity.COMMON, mage.cards.w.WrenchMind.class)); - cards.add(new SetCardInfo("Anger of the Gods", 116, Rarity.RARE, mage.cards.a.AngerOfTheGods.class)); - cards.add(new SetCardInfo("Battle-Rattle Shaman", 117, Rarity.COMMON, mage.cards.b.BattleRattleShaman.class)); - cards.add(new SetCardInfo("Bogardan Hellkite", 118, Rarity.RARE, mage.cards.b.BogardanHellkite.class)); - cards.add(new SetCardInfo("Borderland Marauder", 119, Rarity.COMMON, mage.cards.b.BorderlandMarauder.class)); - cards.add(new SetCardInfo("Charmbreaker Devils", 120, Rarity.RARE, mage.cards.c.CharmbreakerDevils.class)); - cards.add(new SetCardInfo("Coordinated Assault", 121, Rarity.UNCOMMON, mage.cards.c.CoordinatedAssault.class)); - cards.add(new SetCardInfo("Crucible of Fire", 122, Rarity.RARE, mage.cards.c.CrucibleOfFire.class)); + cards.add(new SetCardInfo("Doomed Traveler", 16, Rarity.COMMON, mage.cards.d.DoomedTraveler.class)); + cards.add(new SetCardInfo("Doorkeeper", 53, Rarity.COMMON, mage.cards.d.Doorkeeper.class)); cards.add(new SetCardInfo("Draconic Roar", 123, Rarity.COMMON, mage.cards.d.DraconicRoar.class)); + cards.add(new SetCardInfo("Dragon Bell Monk", 17, Rarity.COMMON, mage.cards.d.DragonBellMonk.class)); cards.add(new SetCardInfo("Dragon Egg", 124, Rarity.COMMON, mage.cards.d.DragonEgg.class)); cards.add(new SetCardInfo("Dragon Tempest", 125, Rarity.UNCOMMON, mage.cards.d.DragonTempest.class)); + cards.add(new SetCardInfo("Dragonloft Idol", 215, Rarity.UNCOMMON, mage.cards.d.DragonloftIdol.class)); cards.add(new SetCardInfo("Dragonlord's Servant", 126, Rarity.COMMON, mage.cards.d.DragonlordsServant.class)); + cards.add(new SetCardInfo("Duress", 88, Rarity.COMMON, mage.cards.d.Duress.class)); + cards.add(new SetCardInfo("Durkwood Baloth", 160, Rarity.COMMON, mage.cards.d.DurkwoodBaloth.class)); + cards.add(new SetCardInfo("Duskdale Wurm", 161, Rarity.COMMON, mage.cards.d.DuskdaleWurm.class)); cards.add(new SetCardInfo("Earth Elemental", 127, Rarity.COMMON, mage.cards.e.EarthElemental.class)); + cards.add(new SetCardInfo("Electrolyze", 198, Rarity.UNCOMMON, mage.cards.e.Electrolyze.class)); + cards.add(new SetCardInfo("Elesh Norn, Grand Cenobite", 18, Rarity.MYTHIC, mage.cards.e.EleshNornGrandCenobite.class)); + cards.add(new SetCardInfo("Elusive Spellfist", 54, Rarity.COMMON, mage.cards.e.ElusiveSpellfist.class)); + cards.add(new SetCardInfo("Emerge Unscathed", 19, Rarity.COMMON, mage.cards.e.EmergeUnscathed.class)); + cards.add(new SetCardInfo("Emeria Angel", 20, Rarity.RARE, mage.cards.e.EmeriaAngel.class)); + cards.add(new SetCardInfo("Enlarge", 162, Rarity.UNCOMMON, mage.cards.e.Enlarge.class)); + cards.add(new SetCardInfo("Eternal Thirst", 89, Rarity.COMMON, mage.cards.e.EternalThirst.class)); + cards.add(new SetCardInfo("Evolving Wilds", 235, Rarity.COMMON, mage.cards.e.EvolvingWilds.class)); + cards.add(new SetCardInfo("Festering Newt", 90, Rarity.COMMON, mage.cards.f.FesteringNewt.class)); cards.add(new SetCardInfo("Fireball", 128, Rarity.UNCOMMON, mage.cards.f.Fireball.class)); + cards.add(new SetCardInfo("Firemane Angel", 199, Rarity.RARE, mage.cards.f.FiremaneAngel.class)); + cards.add(new SetCardInfo("Flusterstorm", 55, Rarity.RARE, mage.cards.f.Flusterstorm.class)); + cards.add(new SetCardInfo("Fog Bank", 56, Rarity.UNCOMMON, mage.cards.f.FogBank.class)); + cards.add(new SetCardInfo("Foul-Tongue Invocation", 91, Rarity.COMMON, mage.cards.f.FoulTongueInvocation.class)); + cards.add(new SetCardInfo("Frost Lynx", 57, Rarity.COMMON, mage.cards.f.FrostLynx.class)); cards.add(new SetCardInfo("Furnace Whelp", 129, Rarity.COMMON, mage.cards.f.FurnaceWhelp.class)); cards.add(new SetCardInfo("Fury Charm", 130, Rarity.COMMON, mage.cards.f.FuryCharm.class)); + cards.add(new SetCardInfo("Genesis Hydra", 163, Rarity.RARE, mage.cards.g.GenesisHydra.class)); + cards.add(new SetCardInfo("Genesis Wave", 164, Rarity.RARE, mage.cards.g.GenesisWave.class)); + cards.add(new SetCardInfo("Glimpse the Unthinkable", 200, Rarity.RARE, mage.cards.g.GlimpseTheUnthinkable.class)); + cards.add(new SetCardInfo("Golgari Rot Farm", 236, Rarity.UNCOMMON, mage.cards.g.GolgariRotFarm.class)); + cards.add(new SetCardInfo("Graven Cairns", 237, Rarity.RARE, mage.cards.g.GravenCairns.class)); + cards.add(new SetCardInfo("Great Teacher's Decree", 21, Rarity.UNCOMMON, mage.cards.g.GreatTeachersDecree.class)); + cards.add(new SetCardInfo("Greater Basilisk", 165, Rarity.COMMON, mage.cards.g.GreaterBasilisk.class)); + cards.add(new SetCardInfo("Grisly Spectacle", 92, Rarity.COMMON, mage.cards.g.GrislySpectacle.class)); + cards.add(new SetCardInfo("Grove of the Burnwillows", 238, Rarity.RARE, mage.cards.g.GroveOfTheBurnwillows.class)); + cards.add(new SetCardInfo("Gruul Turf", 239, Rarity.UNCOMMON, mage.cards.g.GruulTurf.class)); + cards.add(new SetCardInfo("Guard Duty", 22, Rarity.COMMON, mage.cards.g.GuardDuty.class)); + cards.add(new SetCardInfo("Guardian Idol", 216, Rarity.COMMON, mage.cards.g.GuardianIdol.class)); + cards.add(new SetCardInfo("Guided Strike", 23, Rarity.COMMON, mage.cards.g.GuidedStrike.class)); cards.add(new SetCardInfo("Guttersnipe", 131, Rarity.UNCOMMON, mage.cards.g.Guttersnipe.class)); cards.add(new SetCardInfo("Hammerhand", 132, Rarity.COMMON, mage.cards.h.Hammerhand.class)); + cards.add(new SetCardInfo("Haunting Hymn", 93, Rarity.UNCOMMON, mage.cards.h.HauntingHymn.class)); cards.add(new SetCardInfo("Heat Ray", 133, Rarity.COMMON, mage.cards.h.HeatRay.class)); + cards.add(new SetCardInfo("Heroes' Bane", 166, Rarity.UNCOMMON, mage.cards.h.HeroesBane.class)); cards.add(new SetCardInfo("Hoarding Dragon", 134, Rarity.UNCOMMON, mage.cards.h.HoardingDragon.class)); + cards.add(new SetCardInfo("Horizon Canopy", 240, Rarity.RARE, mage.cards.h.HorizonCanopy.class)); + cards.add(new SetCardInfo("Hunt the Weak", 167, Rarity.COMMON, mage.cards.h.HuntTheWeak.class)); + cards.add(new SetCardInfo("Hunting Pack", 168, Rarity.UNCOMMON, mage.cards.h.HuntingPack.class)); + cards.add(new SetCardInfo("Hypersonic Dragon", 201, Rarity.RARE, mage.cards.h.HypersonicDragon.class)); + cards.add(new SetCardInfo("Illusory Ambusher", 58, Rarity.UNCOMMON, mage.cards.i.IllusoryAmbusher.class)); + cards.add(new SetCardInfo("Illusory Angel", 59, Rarity.UNCOMMON, mage.cards.i.IllusoryAngel.class)); + cards.add(new SetCardInfo("Indulgent Tormentor", 94, Rarity.UNCOMMON, mage.cards.i.IndulgentTormentor.class)); + cards.add(new SetCardInfo("Infantry Veteran", 24, Rarity.COMMON, mage.cards.i.InfantryVeteran.class)); + cards.add(new SetCardInfo("Inspiring Call", 169, Rarity.UNCOMMON, mage.cards.i.InspiringCall.class)); + cards.add(new SetCardInfo("Iona's Judgment", 25, Rarity.COMMON, mage.cards.i.IonasJudgment.class)); + cards.add(new SetCardInfo("Ivy Elemental", 170, Rarity.COMMON, mage.cards.i.IvyElemental.class)); + cards.add(new SetCardInfo("Izzet Boilerworks", 241, Rarity.UNCOMMON, mage.cards.i.IzzetBoilerworks.class)); + cards.add(new SetCardInfo("Jace's Phantasm", 60, Rarity.COMMON, mage.cards.j.JacesPhantasm.class)); + cards.add(new SetCardInfo("Jaddi Offshoot", 171, Rarity.COMMON, mage.cards.j.JaddiOffshoot.class)); + cards.add(new SetCardInfo("Jhessian Thief", 61, Rarity.COMMON, mage.cards.j.JhessianThief.class)); + cards.add(new SetCardInfo("Jin-Gitaxias, Core Augur", 62, Rarity.MYTHIC, mage.cards.j.JinGitaxiasCoreAugur.class)); + cards.add(new SetCardInfo("Jugan, the Rising Star", 172, Rarity.RARE, mage.cards.j.JuganTheRisingStar.class)); + cards.add(new SetCardInfo("Jungle Barrier", 202, Rarity.UNCOMMON, mage.cards.j.JungleBarrier.class)); + cards.add(new SetCardInfo("Keiga, the Tide Star", 63, Rarity.RARE, mage.cards.k.KeigaTheTideStar.class)); cards.add(new SetCardInfo("Keldon Halberdier", 135, Rarity.COMMON, mage.cards.k.KeldonHalberdier.class)); cards.add(new SetCardInfo("Kiki-Jiki, Mirror Breaker", 136, Rarity.MYTHIC, mage.cards.k.KikiJikiMirrorBreaker.class)); cards.add(new SetCardInfo("Kiln Fiend", 137, Rarity.COMMON, mage.cards.k.KilnFiend.class)); - cards.add(new SetCardInfo("Mark of Mutiny", 138, Rarity.COMMON, mage.cards.m.MarkOfMutiny.class)); - cards.add(new SetCardInfo("Magus of the Moon", 139, Rarity.RARE, mage.cards.m.MagusOfTheMoon.class)); - cards.add(new SetCardInfo("Monastery Swiftspear", 140, Rarity.UNCOMMON, mage.cards.m.MonasterySwiftspear.class)); - cards.add(new SetCardInfo("Pillar of Flame", 141, Rarity.COMMON, mage.cards.p.PillarOfFlame.class)); - cards.add(new SetCardInfo("Prodigal Pyromancer", 142, Rarity.UNCOMMON, mage.cards.p.ProdigalPyromancer.class)); - cards.add(new SetCardInfo("Rift Bolt", 143, Rarity.UNCOMMON, mage.cards.r.RiftBolt.class)); - cards.add(new SetCardInfo("Ryusei, the Falling Star", 144, Rarity.RARE, mage.cards.r.RyuseiTheFallingStar.class)); - cards.add(new SetCardInfo("Scourge of Valkas", 145, Rarity.RARE, mage.cards.s.ScourgeOfValkas.class)); - cards.add(new SetCardInfo("Splatter Thug", 146, Rarity.COMMON, mage.cards.s.SplatterThug.class)); - cards.add(new SetCardInfo("Staggershock", 147, Rarity.UNCOMMON, mage.cards.s.Staggershock.class)); - cards.add(new SetCardInfo("Surreal Memoir", 148, Rarity.UNCOMMON, mage.cards.s.SurrealMemoir.class)); - cards.add(new SetCardInfo("Thundermaw Hellkite", 149, Rarity.MYTHIC, mage.cards.t.ThundermawHellkite.class)); - cards.add(new SetCardInfo("Tormenting Voice", 150, Rarity.COMMON, mage.cards.t.TormentingVoice.class)); - cards.add(new SetCardInfo("Trumpet Blast", 151, Rarity.COMMON, mage.cards.t.TrumpetBlast.class)); - cards.add(new SetCardInfo("Urabrask the Hidden", 152, Rarity.MYTHIC, mage.cards.u.UrabraskTheHidden.class)); - cards.add(new SetCardInfo("Vent Sentinel", 153, Rarity.COMMON, mage.cards.v.VentSentinel.class)); - cards.add(new SetCardInfo("Aerial Predation", 154, Rarity.COMMON, mage.cards.a.AerialPredation.class)); - cards.add(new SetCardInfo("Assault Formation", 155, Rarity.UNCOMMON, mage.cards.a.AssaultFormation.class)); - cards.add(new SetCardInfo("Carven Caryatid", 156, Rarity.UNCOMMON, mage.cards.c.CarvenCaryatid.class)); - cards.add(new SetCardInfo("Channel", 157, Rarity.MYTHIC, mage.cards.c.Channel.class)); - cards.add(new SetCardInfo("Crowned Ceratok", 158, Rarity.COMMON, mage.cards.c.CrownedCeratok.class)); - cards.add(new SetCardInfo("Curse of Predation", 159, Rarity.RARE, mage.cards.c.CurseOfPredation.class)); - cards.add(new SetCardInfo("Durkwood Baloth", 160, Rarity.COMMON, mage.cards.d.DurkwoodBaloth.class)); - cards.add(new SetCardInfo("Duskdale Wurm", 161, Rarity.COMMON, mage.cards.d.DuskdaleWurm.class)); - cards.add(new SetCardInfo("Enlarge", 162, Rarity.UNCOMMON, mage.cards.e.Enlarge.class)); - cards.add(new SetCardInfo("Genesis Hydra", 163, Rarity.RARE, mage.cards.g.GenesisHydra.class)); - cards.add(new SetCardInfo("Genesis Wave", 164, Rarity.RARE, mage.cards.g.GenesisWave.class)); - cards.add(new SetCardInfo("Greater Basilisk", 165, Rarity.COMMON, mage.cards.g.GreaterBasilisk.class)); - cards.add(new SetCardInfo("Heroes' Bane", 166, Rarity.UNCOMMON, mage.cards.h.HeroesBane.class)); - cards.add(new SetCardInfo("Hunting Pack", 167, Rarity.UNCOMMON, mage.cards.h.HuntingPack.class)); - cards.add(new SetCardInfo("Hunt the Weak", 168, Rarity.COMMON, mage.cards.h.HuntTheWeak.class)); - cards.add(new SetCardInfo("Inspiring Call", 169, Rarity.UNCOMMON, mage.cards.i.InspiringCall.class)); - cards.add(new SetCardInfo("Ivy Elemental", 170, Rarity.COMMON, mage.cards.i.IvyElemental.class)); - cards.add(new SetCardInfo("Jaddi Offshoot", 171, Rarity.COMMON, mage.cards.j.JaddiOffshoot.class)); - cards.add(new SetCardInfo("Jugan, the Rising Star", 172, Rarity.RARE, mage.cards.j.JuganTheRisingStar.class)); + cards.add(new SetCardInfo("Knight of the Reliquary", 203, Rarity.RARE, mage.cards.k.KnightOfTheReliquary.class)); + cards.add(new SetCardInfo("Kokusho, the Evening Star", 95, Rarity.RARE, mage.cards.k.KokushoTheEveningStar.class)); + cards.add(new SetCardInfo("Kolaghan Monument", 217, Rarity.UNCOMMON, mage.cards.k.KolaghanMonument.class)); cards.add(new SetCardInfo("Lead the Stampede", 173, Rarity.COMMON, mage.cards.l.LeadTheStampede.class)); + cards.add(new SetCardInfo("Lightning Helix", 204, Rarity.UNCOMMON, mage.cards.l.LightningHelix.class)); + cards.add(new SetCardInfo("Lord of the Pit", 96, Rarity.RARE, mage.cards.l.LordOfThePit.class)); cards.add(new SetCardInfo("Lotus Cobra", 174, Rarity.RARE, mage.cards.l.LotusCobra.class)); cards.add(new SetCardInfo("Lure", 175, Rarity.UNCOMMON, mage.cards.l.Lure.class)); - cards.add(new SetCardInfo("Nantuko Shaman", 176, Rarity.COMMON, mage.cards.n.NantukoShaman.class)); - cards.add(new SetCardInfo("Nature's Claim", 177, Rarity.COMMON, mage.cards.n.NaturesClaim.class)); - cards.add(new SetCardInfo("Netcaster Spider", 178, Rarity.COMMON, mage.cards.n.NetcasterSpider.class)); - cards.add(new SetCardInfo("Obstinate Baloth", 179, Rarity.RARE, mage.cards.o.ObstinateBaloth.class)); - cards.add(new SetCardInfo("Overgrown Battlement", 180, Rarity.UNCOMMON, mage.cards.o.OvergrownBattlement.class)); - cards.add(new SetCardInfo("Phantom Tiger", 181, Rarity.COMMON, mage.cards.p.PhantomTiger.class)); - cards.add(new SetCardInfo("Prey's Vengeance", 182, Rarity.COMMON, mage.cards.p.PreysVengeance.class)); - cards.add(new SetCardInfo("Primeval Titan", 183, Rarity.MYTHIC, mage.cards.p.PrimevalTitan.class)); - cards.add(new SetCardInfo("Rampaging Baloths", 184, Rarity.RARE, mage.cards.r.RampagingBaloths.class)); - cards.add(new SetCardInfo("Search for Tomorrow", 185, Rarity.COMMON, mage.cards.s.SearchForTomorrow.class)); - cards.add(new SetCardInfo("Sultai Flayer", 186, Rarity.UNCOMMON, mage.cards.s.SultaiFlayer.class)); - cards.add(new SetCardInfo("Timberland Guide", 187, Rarity.COMMON, mage.cards.t.TimberlandGuide.class)); - cards.add(new SetCardInfo("Undercity Troll", 188, Rarity.UNCOMMON, mage.cards.u.UndercityTroll.class)); - cards.add(new SetCardInfo("Vorinclex, Voice of Hunger", 189, Rarity.MYTHIC, mage.cards.v.VorinclexVoiceOfHunger.class)); - cards.add(new SetCardInfo("Wall of Roots", 190, Rarity.COMMON, mage.cards.w.WallOfRoots.class)); - cards.add(new SetCardInfo("Wildsize", 191, Rarity.COMMON, mage.cards.w.Wildsize.class)); - cards.add(new SetCardInfo("Azorius Charm", 192, Rarity.UNCOMMON, mage.cards.a.AzoriusCharm.class)); - cards.add(new SetCardInfo("Bladewing the Risen", 193, Rarity.UNCOMMON, mage.cards.b.BladewingTheRisen.class)); - cards.add(new SetCardInfo("Blizzard Specter", 194, Rarity.UNCOMMON, mage.cards.b.BlizzardSpecter.class)); - cards.add(new SetCardInfo("Blood Baron of Vizkopa", 195, Rarity.RARE, mage.cards.b.BloodBaronOfVizkopa.class)); - cards.add(new SetCardInfo("Chronicler of Heroes", 196, Rarity.UNCOMMON, mage.cards.c.ChroniclerOfHeroes.class)); - cards.add(new SetCardInfo("Corpsejack Menace", 197, Rarity.UNCOMMON, mage.cards.c.CorpsejackMenace.class)); - cards.add(new SetCardInfo("Electrolyze", 198, Rarity.UNCOMMON, mage.cards.e.Electrolyze.class)); - cards.add(new SetCardInfo("Firemane Angel", 199, Rarity.RARE, mage.cards.f.FiremaneAngel.class)); - cards.add(new SetCardInfo("Glimpse the Unthinkable", 200, Rarity.RARE, mage.cards.g.GlimpseTheUnthinkable.class)); - cards.add(new SetCardInfo("Hypersonic Dragon", 201, Rarity.RARE, mage.cards.h.HypersonicDragon.class)); - cards.add(new SetCardInfo("Jungle Barrier", 202, Rarity.UNCOMMON, mage.cards.j.JungleBarrier.class)); - cards.add(new SetCardInfo("Knight of the Reliquary", 203, Rarity.RARE, mage.cards.k.KnightOfTheReliquary.class)); - cards.add(new SetCardInfo("Lightning Helix", 204, Rarity.UNCOMMON, mage.cards.l.LightningHelix.class)); + cards.add(new SetCardInfo("Magus of the Moon", 138, Rarity.RARE, mage.cards.m.MagusOfTheMoon.class)); + cards.add(new SetCardInfo("Mahamoti Djinn", 64, Rarity.UNCOMMON, mage.cards.m.MahamotiDjinn.class)); cards.add(new SetCardInfo("Malfegor", 205, Rarity.RARE, mage.cards.m.Malfegor.class)); - cards.add(new SetCardInfo("Rosheen Meanderer", 206, Rarity.UNCOMMON, mage.cards.r.RosheenMeanderer.class)); - cards.add(new SetCardInfo("Savageborn Hydra", 207, Rarity.RARE, mage.cards.s.SavagebornHydra.class)); - cards.add(new SetCardInfo("Simic Sky Swallower", 208, Rarity.RARE, mage.cards.s.SimicSkySwallower.class)); - cards.add(new SetCardInfo("Spiritmonger", 209, Rarity.RARE, mage.cards.s.Spiritmonger.class)); - cards.add(new SetCardInfo("Supreme Verdict", 210, Rarity.RARE, mage.cards.s.SupremeVerdict.class)); - cards.add(new SetCardInfo("Vizkopa Guildmage", 211, Rarity.UNCOMMON, mage.cards.v.VizkopaGuildmage.class)); - cards.add(new SetCardInfo("Aether Vial", 212, Rarity.RARE, mage.cards.a.AetherVial.class)); - cards.add(new SetCardInfo("Bubbling Cauldron", 213, Rarity.UNCOMMON, mage.cards.b.BubblingCauldron.class)); - cards.add(new SetCardInfo("Darksteel Axe", 214, Rarity.COMMON, mage.cards.d.DarksteelAxe.class)); - cards.add(new SetCardInfo("Dragonloft Idol", 215, Rarity.UNCOMMON, mage.cards.d.DragonloftIdol.class)); - cards.add(new SetCardInfo("Guardian Idol", 216, Rarity.COMMON, mage.cards.g.GuardianIdol.class)); - cards.add(new SetCardInfo("Kolaghan Monument", 217, Rarity.UNCOMMON, mage.cards.k.KolaghanMonument.class)); + cards.add(new SetCardInfo("Mana Drain", 65, Rarity.MYTHIC, mage.cards.m.ManaDrain.class)); + cards.add(new SetCardInfo("Mana Leak", 66, Rarity.COMMON, mage.cards.m.ManaLeak.class)); cards.add(new SetCardInfo("Manakin", 218, Rarity.COMMON, mage.cards.m.Manakin.class)); + cards.add(new SetCardInfo("Mark of Mutiny", 139, Rarity.COMMON, mage.cards.m.MarkOfMutiny.class)); + cards.add(new SetCardInfo("Mer-Ek Nightblade", 97, Rarity.UNCOMMON, mage.cards.m.MerEkNightblade.class)); cards.add(new SetCardInfo("Mind Stone", 219, Rarity.COMMON, mage.cards.m.MindStone.class)); cards.add(new SetCardInfo("Mindcrank", 220, Rarity.UNCOMMON, mage.cards.m.Mindcrank.class)); cards.add(new SetCardInfo("Mishra's Bauble", 221, Rarity.UNCOMMON, mage.cards.m.MishrasBauble.class)); + cards.add(new SetCardInfo("Mnemonic Wall", 67, Rarity.COMMON, mage.cards.m.MnemonicWall.class)); + cards.add(new SetCardInfo("Monastery Swiftspear", 140, Rarity.UNCOMMON, mage.cards.m.MonasterySwiftspear.class)); cards.add(new SetCardInfo("Moonglove Extract", 222, Rarity.COMMON, mage.cards.m.MoongloveExtract.class)); - cards.add(new SetCardInfo("Oblivion Stone", 223, Rarity.RARE, mage.cards.o.OblivionStone.class)); - cards.add(new SetCardInfo("Palladium Myr", 224, Rarity.UNCOMMON, mage.cards.p.PalladiumMyr.class)); - cards.add(new SetCardInfo("Pristine Talisman", 225, Rarity.UNCOMMON, mage.cards.p.PristineTalisman.class)); - cards.add(new SetCardInfo("Runed Servitor", 226, Rarity.COMMON, mage.cards.r.RunedServitor.class)); - cards.add(new SetCardInfo("Sandstone Oracle", 227, Rarity.UNCOMMON, mage.cards.s.SandstoneOracle.class)); - cards.add(new SetCardInfo("Serum Powder", 228, Rarity.RARE, mage.cards.s.SerumPowder.class)); - cards.add(new SetCardInfo("Star Compass", 229, Rarity.COMMON, mage.cards.s.StarCompass.class)); - cards.add(new SetCardInfo("Thran Dynamo", 230, Rarity.UNCOMMON, mage.cards.t.ThranDynamo.class)); - cards.add(new SetCardInfo("Trepanation Blade", 231, Rarity.UNCOMMON, mage.cards.t.TrepanationBlade.class)); - cards.add(new SetCardInfo("Azorius Chancery", 232, Rarity.UNCOMMON, mage.cards.a.AzoriusChancery.class)); - cards.add(new SetCardInfo("Boros Garrison", 233, Rarity.UNCOMMON, mage.cards.b.BorosGarrison.class)); - cards.add(new SetCardInfo("Dimir Aqueduct", 234, Rarity.UNCOMMON, mage.cards.d.DimirAqueduct.class)); - cards.add(new SetCardInfo("Evolving Wilds", 235, Rarity.COMMON, mage.cards.e.EvolvingWilds.class)); - cards.add(new SetCardInfo("Golgari Rot Farm", 236, Rarity.UNCOMMON, mage.cards.g.GolgariRotFarm.class)); - cards.add(new SetCardInfo("Graven Cairns", 237, Rarity.RARE, mage.cards.g.GravenCairns.class)); - cards.add(new SetCardInfo("Grove of the Burnwillows", 238, Rarity.RARE, mage.cards.g.GroveOfTheBurnwillows.class)); - cards.add(new SetCardInfo("Gruul Turf", 239, Rarity.UNCOMMON, mage.cards.g.GruulTurf.class)); - cards.add(new SetCardInfo("Horizon Canopy", 240, Rarity.RARE, mage.cards.h.HorizonCanopy.class)); - cards.add(new SetCardInfo("Izzet Boilerworks", 241, Rarity.UNCOMMON, mage.cards.i.IzzetBoilerworks.class)); + cards.add(new SetCardInfo("Nantuko Shaman", 176, Rarity.COMMON, mage.cards.n.NantukoShaman.class)); + cards.add(new SetCardInfo("Nature's Claim", 177, Rarity.COMMON, mage.cards.n.NaturesClaim.class)); + cards.add(new SetCardInfo("Necropotence", 98, Rarity.MYTHIC, mage.cards.n.Necropotence.class)); + cards.add(new SetCardInfo("Netcaster Spider", 178, Rarity.COMMON, mage.cards.n.NetcasterSpider.class)); + cards.add(new SetCardInfo("Night of Souls' Betrayal", 99, Rarity.RARE, mage.cards.n.NightOfSoulsBetrayal.class)); cards.add(new SetCardInfo("Nimbus Maze", 242, Rarity.RARE, mage.cards.n.NimbusMaze.class)); + cards.add(new SetCardInfo("Noxious Dragon", 100, Rarity.UNCOMMON, mage.cards.n.NoxiousDragon.class)); + cards.add(new SetCardInfo("Ob Nixilis, the Fallen", 101, Rarity.MYTHIC, mage.cards.o.ObNixilisTheFallen.class)); + cards.add(new SetCardInfo("Oblivion Stone", 223, Rarity.RARE, mage.cards.o.OblivionStone.class)); + cards.add(new SetCardInfo("Obstinate Baloth", 179, Rarity.RARE, mage.cards.o.ObstinateBaloth.class)); + cards.add(new SetCardInfo("Ojutai's Breath", 68, Rarity.COMMON, mage.cards.o.OjutaisBreath.class)); cards.add(new SetCardInfo("Orzhov Basilica", 243, Rarity.UNCOMMON, mage.cards.o.OrzhovBasilica.class)); + cards.add(new SetCardInfo("Overgrown Battlement", 180, Rarity.UNCOMMON, mage.cards.o.OvergrownBattlement.class)); + cards.add(new SetCardInfo("Palladium Myr", 224, Rarity.UNCOMMON, mage.cards.p.PalladiumMyr.class)); + cards.add(new SetCardInfo("Path of Bravery", 26, Rarity.RARE, mage.cards.p.PathOfBravery.class)); + cards.add(new SetCardInfo("Pentarch Ward", 27, Rarity.COMMON, mage.cards.p.PentarchWard.class)); + cards.add(new SetCardInfo("Phantom Monster", 69, Rarity.COMMON, mage.cards.p.PhantomMonster.class)); + cards.add(new SetCardInfo("Phantom Tiger", 181, Rarity.COMMON, mage.cards.p.PhantomTiger.class)); + cards.add(new SetCardInfo("Phyrexian Rager", 102, Rarity.COMMON, mage.cards.p.PhyrexianRager.class)); + cards.add(new SetCardInfo("Pillar of Flame", 141, Rarity.COMMON, mage.cards.p.PillarOfFlame.class)); + cards.add(new SetCardInfo("Prey's Vengeance", 182, Rarity.COMMON, mage.cards.p.PreysVengeance.class)); + cards.add(new SetCardInfo("Primeval Titan", 183, Rarity.MYTHIC, mage.cards.p.PrimevalTitan.class)); + cards.add(new SetCardInfo("Pristine Talisman", 225, Rarity.UNCOMMON, mage.cards.p.PristineTalisman.class)); + cards.add(new SetCardInfo("Prodigal Pyromancer", 142, Rarity.UNCOMMON, mage.cards.p.ProdigalPyromancer.class)); cards.add(new SetCardInfo("Radiant Fountain", 244, Rarity.COMMON, mage.cards.r.RadiantFountain.class)); cards.add(new SetCardInfo("Rakdos Carnarium", 245, Rarity.UNCOMMON, mage.cards.r.RakdosCarnarium.class)); + cards.add(new SetCardInfo("Rakdos Drake", 103, Rarity.COMMON, mage.cards.r.RakdosDrake.class)); + cards.add(new SetCardInfo("Rampaging Baloths", 184, Rarity.RARE, mage.cards.r.RampagingBaloths.class)); + cards.add(new SetCardInfo("Reave Soul", 104, Rarity.COMMON, mage.cards.r.ReaveSoul.class)); + cards.add(new SetCardInfo("Repeal", 70, Rarity.COMMON, mage.cards.r.Repeal.class)); + cards.add(new SetCardInfo("Restoration Angel", 28, Rarity.RARE, mage.cards.r.RestorationAngel.class)); + cards.add(new SetCardInfo("Rift Bolt", 143, Rarity.UNCOMMON, mage.cards.r.RiftBolt.class)); cards.add(new SetCardInfo("River of Tears", 246, Rarity.RARE, mage.cards.r.RiverOfTears.class)); + cards.add(new SetCardInfo("Riverwheel Aerialists", 71, Rarity.COMMON, mage.cards.r.RiverwheelAerialists.class)); + cards.add(new SetCardInfo("Rosheen Meanderer", 206, Rarity.UNCOMMON, mage.cards.r.RosheenMeanderer.class)); + cards.add(new SetCardInfo("Rotfeaster Maggot", 105, Rarity.COMMON, mage.cards.r.RotfeasterMaggot.class)); + cards.add(new SetCardInfo("Rune-Scarred Demon", 106, Rarity.RARE, mage.cards.r.RuneScarredDemon.class)); + cards.add(new SetCardInfo("Runed Servitor", 226, Rarity.COMMON, mage.cards.r.RunedServitor.class)); + cards.add(new SetCardInfo("Ryusei, the Falling Star", 144, Rarity.RARE, mage.cards.r.RyuseiTheFallingStar.class)); + cards.add(new SetCardInfo("Sandstone Oracle", 227, Rarity.UNCOMMON, mage.cards.s.SandstoneOracle.class)); + cards.add(new SetCardInfo("Sanguine Bond", 107, Rarity.UNCOMMON, mage.cards.s.SanguineBond.class)); + cards.add(new SetCardInfo("Savageborn Hydra", 207, Rarity.RARE, mage.cards.s.SavagebornHydra.class)); + cards.add(new SetCardInfo("Scion of Ugin", 1, Rarity.COMMON, mage.cards.s.ScionOfUgin.class)); + cards.add(new SetCardInfo("Scourge of Valkas", 145, Rarity.RARE, mage.cards.s.ScourgeOfValkas.class)); + cards.add(new SetCardInfo("Search for Tomorrow", 185, Rarity.COMMON, mage.cards.s.SearchForTomorrow.class)); + cards.add(new SetCardInfo("Seeker of the Way", 29, Rarity.COMMON, mage.cards.s.SeekerOfTheWay.class)); cards.add(new SetCardInfo("Selesnya Sanctuary", 247, Rarity.UNCOMMON, mage.cards.s.SelesnyaSanctuary.class)); + cards.add(new SetCardInfo("Serra Angel", 30, Rarity.UNCOMMON, mage.cards.s.SerraAngel.class)); + cards.add(new SetCardInfo("Serra Ascendant", 31, Rarity.RARE, mage.cards.s.SerraAscendant.class)); + cards.add(new SetCardInfo("Serum Powder", 228, Rarity.RARE, mage.cards.s.SerumPowder.class)); + cards.add(new SetCardInfo("Sheoldred, Whispering One", 108, Rarity.MYTHIC, mage.cards.s.SheoldredWhisperingOne.class)); cards.add(new SetCardInfo("Shimmering Grotto", 248, Rarity.COMMON, mage.cards.s.ShimmeringGrotto.class)); + cards.add(new SetCardInfo("Shriekgeist", 72, Rarity.COMMON, mage.cards.s.Shriekgeist.class)); cards.add(new SetCardInfo("Simic Growth Chamber", 249, Rarity.UNCOMMON, mage.cards.s.SimicGrowthChamber.class)); - + cards.add(new SetCardInfo("Simic Sky Swallower", 208, Rarity.RARE, mage.cards.s.SimicSkySwallower.class)); + cards.add(new SetCardInfo("Skywise Teachings", 73, Rarity.UNCOMMON, mage.cards.s.SkywiseTeachings.class)); + cards.add(new SetCardInfo("Sphinx of Uthuun", 74, Rarity.RARE, mage.cards.s.SphinxOfUthuun.class)); + cards.add(new SetCardInfo("Spiritmonger", 209, Rarity.RARE, mage.cards.s.Spiritmonger.class)); + cards.add(new SetCardInfo("Splatter Thug", 146, Rarity.COMMON, mage.cards.s.SplatterThug.class)); + cards.add(new SetCardInfo("Staggershock", 147, Rarity.UNCOMMON, mage.cards.s.Staggershock.class)); + cards.add(new SetCardInfo("Stalwart Aven", 32, Rarity.COMMON, mage.cards.s.StalwartAven.class)); + cards.add(new SetCardInfo("Star Compass", 229, Rarity.COMMON, mage.cards.s.StarCompass.class)); + cards.add(new SetCardInfo("Student of Ojutai", 33, Rarity.COMMON, mage.cards.s.StudentOfOjutai.class)); + cards.add(new SetCardInfo("Sultai Flayer", 186, Rarity.UNCOMMON, mage.cards.s.SultaiFlayer.class)); + cards.add(new SetCardInfo("Supreme Verdict", 210, Rarity.RARE, mage.cards.s.SupremeVerdict.class)); + cards.add(new SetCardInfo("Surreal Memoir", 148, Rarity.UNCOMMON, mage.cards.s.SurrealMemoir.class)); + cards.add(new SetCardInfo("Survival Cache", 34, Rarity.COMMON, mage.cards.s.SurvivalCache.class)); + cards.add(new SetCardInfo("Sustainer of the Realm", 35, Rarity.COMMON, mage.cards.s.SustainerOfTheRealm.class)); + cards.add(new SetCardInfo("Swords to Plowshares", 36, Rarity.UNCOMMON, mage.cards.s.SwordsToPlowshares.class)); + cards.add(new SetCardInfo("Tavern Swindler", 109, Rarity.UNCOMMON, mage.cards.t.TavernSwindler.class)); + cards.add(new SetCardInfo("Teferi, Mage of Zhalfir", 75, Rarity.RARE, mage.cards.t.TeferiMageOfZhalfir.class)); + cards.add(new SetCardInfo("Thought Scour", 76, Rarity.COMMON, mage.cards.t.ThoughtScour.class)); + cards.add(new SetCardInfo("Thoughtseize", 110, Rarity.RARE, mage.cards.t.Thoughtseize.class)); + cards.add(new SetCardInfo("Thran Dynamo", 230, Rarity.UNCOMMON, mage.cards.t.ThranDynamo.class)); + cards.add(new SetCardInfo("Thrill-Kill Assassin", 111, Rarity.COMMON, mage.cards.t.ThrillKillAssassin.class)); + cards.add(new SetCardInfo("Thundermaw Hellkite", 149, Rarity.MYTHIC, mage.cards.t.ThundermawHellkite.class)); + cards.add(new SetCardInfo("Timberland Guide", 187, Rarity.COMMON, mage.cards.t.TimberlandGuide.class)); + cards.add(new SetCardInfo("Topan Freeblade", 37, Rarity.UNCOMMON, mage.cards.t.TopanFreeblade.class)); + cards.add(new SetCardInfo("Tormenting Voice", 150, Rarity.COMMON, mage.cards.t.TormentingVoice.class)); + cards.add(new SetCardInfo("Trepanation Blade", 231, Rarity.UNCOMMON, mage.cards.t.TrepanationBlade.class)); + cards.add(new SetCardInfo("Trumpet Blast", 151, Rarity.COMMON, mage.cards.t.TrumpetBlast.class)); + cards.add(new SetCardInfo("Ulcerate", 112, Rarity.UNCOMMON, mage.cards.u.Ulcerate.class)); + cards.add(new SetCardInfo("Undercity Troll", 188, Rarity.UNCOMMON, mage.cards.u.UndercityTroll.class)); + cards.add(new SetCardInfo("Urabrask the Hidden", 152, Rarity.MYTHIC, mage.cards.u.UrabraskTheHidden.class)); + cards.add(new SetCardInfo("Vent Sentinel", 153, Rarity.COMMON, mage.cards.v.VentSentinel.class)); + cards.add(new SetCardInfo("Virulent Swipe", 113, Rarity.COMMON, mage.cards.v.VirulentSwipe.class)); + cards.add(new SetCardInfo("Vizkopa Guildmage", 211, Rarity.UNCOMMON, mage.cards.v.VizkopaGuildmage.class)); + cards.add(new SetCardInfo("Vorinclex, Voice of Hunger", 189, Rarity.MYTHIC, mage.cards.v.VorinclexVoiceOfHunger.class)); + cards.add(new SetCardInfo("Wall of Roots", 190, Rarity.COMMON, mage.cards.w.WallOfRoots.class)); + cards.add(new SetCardInfo("Wight of Precinct Six", 114, Rarity.COMMON, mage.cards.w.WightOfPrecinctSix.class)); + cards.add(new SetCardInfo("Wildsize", 191, Rarity.COMMON, mage.cards.w.Wildsize.class)); + cards.add(new SetCardInfo("Windfall", 77, Rarity.UNCOMMON, mage.cards.w.Windfall.class)); + cards.add(new SetCardInfo("Wing Shards", 38, Rarity.UNCOMMON, mage.cards.w.WingShards.class)); + cards.add(new SetCardInfo("Wrench Mind", 115, Rarity.COMMON, mage.cards.w.WrenchMind.class)); + cards.add(new SetCardInfo("Yosei, the Morning Star", 39, Rarity.RARE, mage.cards.y.YoseiTheMorningStar.class)); } } diff --git a/Mage.Sets/src/mage/sets/MastersEditionIII.java b/Mage.Sets/src/mage/sets/MastersEditionIII.java index 20f24d901e..61c5d64e4f 100644 --- a/Mage.Sets/src/mage/sets/MastersEditionIII.java +++ b/Mage.Sets/src/mage/sets/MastersEditionIII.java @@ -96,6 +96,7 @@ public final class MastersEditionIII extends ExpansionSet { cards.add(new SetCardInfo("Forest", 228, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Forest", 229, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Forest", 230, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Forked Lightning", 100, Rarity.UNCOMMON, mage.cards.f.ForkedLightning.class)); cards.add(new SetCardInfo("Freyalise's Winds", 119, Rarity.RARE, mage.cards.f.FreyalisesWinds.class)); cards.add(new SetCardInfo("Frost Giant", 101, Rarity.UNCOMMON, mage.cards.f.FrostGiant.class)); cards.add(new SetCardInfo("Gabriel Angelfire", 148, Rarity.RARE, mage.cards.g.GabrielAngelfire.class)); diff --git a/Mage.Sets/src/mage/sets/MercadianMasques.java b/Mage.Sets/src/mage/sets/MercadianMasques.java index d1ed0a59ca..259ea4bb02 100644 --- a/Mage.Sets/src/mage/sets/MercadianMasques.java +++ b/Mage.Sets/src/mage/sets/MercadianMasques.java @@ -235,6 +235,7 @@ public final class MercadianMasques extends ExpansionSet { cards.add(new SetCardInfo("Plains", 334, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Power Matrix", 309, Rarity.RARE, mage.cards.p.PowerMatrix.class)); cards.add(new SetCardInfo("Primeval Shambler", 152, Rarity.UNCOMMON, mage.cards.p.PrimevalShambler.class)); + cards.add(new SetCardInfo("Puffer Extract", 310, Rarity.UNCOMMON, mage.cards.p.PufferExtract.class)); cards.add(new SetCardInfo("Pulverize", 207, Rarity.RARE, mage.cards.p.Pulverize.class)); cards.add(new SetCardInfo("Putrefaction", 153, Rarity.UNCOMMON, mage.cards.p.Putrefaction.class)); cards.add(new SetCardInfo("Puppet's Verdict", 208, Rarity.RARE, mage.cards.p.PuppetsVerdict.class)); @@ -286,6 +287,7 @@ public final class MercadianMasques extends ExpansionSet { cards.add(new SetCardInfo("Sever Soul", 159, Rarity.COMMON, mage.cards.s.SeverSoul.class)); cards.add(new SetCardInfo("Shock Troops", 212, Rarity.COMMON, mage.cards.s.ShockTroops.class)); cards.add(new SetCardInfo("Shoving Match", 103, Rarity.UNCOMMON, mage.cards.s.ShovingMatch.class)); + cards.add(new SetCardInfo("Silent Assassin", 160, Rarity.RARE, mage.cards.s.SilentAssassin.class)); cards.add(new SetCardInfo("Silverglade Elemental", 269, Rarity.COMMON, mage.cards.s.SilvergladeElemental.class)); cards.add(new SetCardInfo("Silverglade Pathfinder", 270, Rarity.UNCOMMON, mage.cards.s.SilvergladePathfinder.class)); cards.add(new SetCardInfo("Sizzle", 213, Rarity.COMMON, mage.cards.s.Sizzle.class)); diff --git a/Mage.Sets/src/mage/sets/Mirage.java b/Mage.Sets/src/mage/sets/Mirage.java index 5b885dbccd..9fa3fd6af0 100644 --- a/Mage.Sets/src/mage/sets/Mirage.java +++ b/Mage.Sets/src/mage/sets/Mirage.java @@ -49,6 +49,7 @@ public final class Mirage extends ExpansionSet { cards.add(new SetCardInfo("Benthic Djinn", 257, Rarity.RARE, mage.cards.b.BenthicDjinn.class)); cards.add(new SetCardInfo("Binding Agony", 106, Rarity.COMMON, mage.cards.b.BindingAgony.class)); cards.add(new SetCardInfo("Blighted Shaman", 107, Rarity.UNCOMMON, mage.cards.b.BlightedShaman.class)); + cards.add(new SetCardInfo("Blind Fury", 158, Rarity.UNCOMMON, mage.cards.b.BlindFury.class)); cards.add(new SetCardInfo("Blinding Light", 5, Rarity.UNCOMMON, mage.cards.b.BlindingLight.class)); cards.add(new SetCardInfo("Blistering Barrier", 159, Rarity.COMMON, mage.cards.b.BlisteringBarrier.class)); cards.add(new SetCardInfo("Bone Harvest", 108, Rarity.COMMON, mage.cards.b.BoneHarvest.class)); @@ -78,6 +79,7 @@ public final class Mirage extends ExpansionSet { cards.add(new SetCardInfo("Coral Fighters", 59, Rarity.UNCOMMON, mage.cards.c.CoralFighters.class)); cards.add(new SetCardInfo("Crash of Rhinos", 210, Rarity.COMMON, mage.cards.c.CrashOfRhinos.class)); cards.add(new SetCardInfo("Crimson Hellkite", 167, Rarity.RARE, mage.cards.c.CrimsonHellkite.class)); + cards.add(new SetCardInfo("Crimson Roc", 168, Rarity.UNCOMMON, mage.cards.c.CrimsonRoc.class)); cards.add(new SetCardInfo("Crypt Cobra", 114, Rarity.UNCOMMON, mage.cards.c.CryptCobra.class)); cards.add(new SetCardInfo("Crystal Golem", 298, Rarity.UNCOMMON, mage.cards.c.CrystalGolem.class)); cards.add(new SetCardInfo("Crystal Vein", 325, Rarity.UNCOMMON, mage.cards.c.CrystalVein.class)); @@ -207,6 +209,7 @@ public final class Mirage extends ExpansionSet { cards.add(new SetCardInfo("Mountain", 346, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Mtenda Griffin", 28, Rarity.UNCOMMON, mage.cards.m.MtendaGriffin.class)); cards.add(new SetCardInfo("Mtenda Herder", 29, Rarity.COMMON, mage.cards.m.MtendaHerder.class)); + cards.add(new SetCardInfo("Mtenda Lion", 230, Rarity.COMMON, mage.cards.m.MtendaLion.class)); cards.add(new SetCardInfo("Mystical Tutor", 80, Rarity.UNCOMMON, mage.cards.m.MysticalTutor.class)); cards.add(new SetCardInfo("Natural Balance", 231, Rarity.RARE, mage.cards.n.NaturalBalance.class)); cards.add(new SetCardInfo("Nettletooth Djinn", 232, Rarity.UNCOMMON, mage.cards.n.NettletoothDjinn.class)); @@ -248,6 +251,7 @@ public final class Mirage extends ExpansionSet { cards.add(new SetCardInfo("Reckless Embermage", 189, Rarity.RARE, mage.cards.r.RecklessEmbermage.class)); cards.add(new SetCardInfo("Regeneration", 236, Rarity.COMMON, mage.cards.r.Regeneration.class)); cards.add(new SetCardInfo("Reign of Chaos", 190, Rarity.UNCOMMON, mage.cards.r.ReignOfChaos.class)); + cards.add(new SetCardInfo("Reign of Terror", 137, Rarity.UNCOMMON, mage.cards.r.ReignOfTerror.class)); cards.add(new SetCardInfo("Reparations", 278, Rarity.RARE, mage.cards.r.Reparations.class)); cards.add(new SetCardInfo("Restless Dead", 138, Rarity.COMMON, mage.cards.r.RestlessDead.class)); cards.add(new SetCardInfo("Ritual of Steel", 36, Rarity.COMMON, mage.cards.r.RitualOfSteel.class)); @@ -325,6 +329,7 @@ public final class Mirage extends ExpansionSet { cards.add(new SetCardInfo("Volcanic Dragon", 201, Rarity.RARE, mage.cards.v.VolcanicDragon.class)); cards.add(new SetCardInfo("Volcanic Geyser", 202, Rarity.UNCOMMON, mage.cards.v.VolcanicGeyser.class)); cards.add(new SetCardInfo("Waiting in the Weeds", 252, Rarity.RARE, mage.cards.w.WaitingInTheWeeds.class)); + cards.add(new SetCardInfo("Wall of Resistance", 46, Rarity.COMMON, mage.cards.w.WallOfResistance.class)); cards.add(new SetCardInfo("Wall of Roots", 253, Rarity.COMMON, mage.cards.w.WallOfRoots.class)); cards.add(new SetCardInfo("Ward of Lights", 47, Rarity.COMMON, mage.cards.w.WardOfLights.class)); cards.add(new SetCardInfo("Warping Wurm", 287, Rarity.RARE, mage.cards.w.WarpingWurm.class)); diff --git a/Mage.Sets/src/mage/sets/Portal.java b/Mage.Sets/src/mage/sets/Portal.java index 822317e27b..36eb3c8f52 100644 --- a/Mage.Sets/src/mage/sets/Portal.java +++ b/Mage.Sets/src/mage/sets/Portal.java @@ -106,6 +106,7 @@ public final class Portal extends ExpansionSet { cards.add(new SetCardInfo("Forest", 213, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Forest", 214, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Forest", 215, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Forked Lightning", 130, Rarity.RARE, mage.cards.f.ForkedLightning.class)); cards.add(new SetCardInfo("Fruition", 166, Rarity.COMMON, mage.cards.f.Fruition.class)); cards.add(new SetCardInfo("Giant Octopus", 56, Rarity.COMMON, mage.cards.g.GiantOctopus.class)); cards.add(new SetCardInfo("Giant Spider", 167, Rarity.COMMON, mage.cards.g.GiantSpider.class)); diff --git a/Mage.Sets/src/mage/sets/Scourge.java b/Mage.Sets/src/mage/sets/Scourge.java index 51df2d1077..2ac19bcedc 100644 --- a/Mage.Sets/src/mage/sets/Scourge.java +++ b/Mage.Sets/src/mage/sets/Scourge.java @@ -143,6 +143,7 @@ public final class Scourge extends ExpansionSet { cards.add(new SetCardInfo("Soul Collector", 74, Rarity.RARE, mage.cards.s.SoulCollector.class)); cards.add(new SetCardInfo("Spark Spray", 105, Rarity.COMMON, mage.cards.s.SparkSpray.class)); cards.add(new SetCardInfo("Sprouting Vines", 128, Rarity.COMMON, mage.cards.s.SproutingVines.class)); + cards.add(new SetCardInfo("Stabilizer", 142, Rarity.RARE, mage.cards.s.Stabilizer.class)); cards.add(new SetCardInfo("Stifle", 52, Rarity.RARE, mage.cards.s.Stifle.class)); cards.add(new SetCardInfo("Sulfuric Vortex", 106, Rarity.RARE, mage.cards.s.SulfuricVortex.class)); cards.add(new SetCardInfo("Temple of the False God", 143, Rarity.UNCOMMON, mage.cards.t.TempleOfTheFalseGod.class)); diff --git a/Mage.Sets/src/mage/sets/Tempest.java b/Mage.Sets/src/mage/sets/Tempest.java index e1ec411d32..5e2ab52b91 100644 --- a/Mage.Sets/src/mage/sets/Tempest.java +++ b/Mage.Sets/src/mage/sets/Tempest.java @@ -112,6 +112,7 @@ public final class Tempest extends ExpansionSet { cards.add(new SetCardInfo("Energizer", 285, Rarity.RARE, mage.cards.e.Energizer.class)); cards.add(new SetCardInfo("Enfeeblement", 133, Rarity.COMMON, mage.cards.e.Enfeeblement.class)); cards.add(new SetCardInfo("Enraging Licid", 171, Rarity.UNCOMMON, mage.cards.e.EnragingLicid.class)); + cards.add(new SetCardInfo("Escaped Shapeshifter", 62, Rarity.RARE, mage.cards.e.EscapedShapeshifter.class)); cards.add(new SetCardInfo("Essence Bottle", 286, Rarity.UNCOMMON, mage.cards.e.EssenceBottle.class)); cards.add(new SetCardInfo("Evincar's Justice", 134, Rarity.COMMON, mage.cards.e.EvincarsJustice.class)); cards.add(new SetCardInfo("Excavator", 287, Rarity.UNCOMMON, mage.cards.e.Excavator.class)); diff --git a/Mage.Sets/src/mage/sets/ThroneOfEldraine.java b/Mage.Sets/src/mage/sets/ThroneOfEldraine.java index ac1778d5aa..2a8c83a769 100644 --- a/Mage.Sets/src/mage/sets/ThroneOfEldraine.java +++ b/Mage.Sets/src/mage/sets/ThroneOfEldraine.java @@ -20,81 +20,313 @@ public final class ThroneOfEldraine extends ExpansionSet { super("Throne of Eldraine", "ELD", ExpansionSet.buildDate(2019, 10, 4), SetType.EXPANSION); this.blockName = "Throne of Eldraine"; this.hasBoosters = true; - this.hasBasicLands = false;// false until basics officially spoiled this.numBoosterLands = 1; this.numBoosterCommon = 10; this.numBoosterUncommon = 3; this.numBoosterRare = 1; this.ratioBoosterMythic = 8; - this.maxCardNumberInBooster = 269; // unconfirmed for now + this.maxCardNumberInBooster = 269; + cards.add(new SetCardInfo("Acclaimed Contender", 1, Rarity.RARE, mage.cards.a.AcclaimedContender.class)); cards.add(new SetCardInfo("Alela, Artful Provocateur", 324, Rarity.MYTHIC, mage.cards.a.AlelaArtfulProvocateur.class)); cards.add(new SetCardInfo("All That Glitters", 2, Rarity.UNCOMMON, mage.cards.a.AllThatGlitters.class)); cards.add(new SetCardInfo("Animating Faerie", 38, Rarity.UNCOMMON, mage.cards.a.AnimatingFaerie.class)); cards.add(new SetCardInfo("Arcane Signet", 331, Rarity.COMMON, mage.cards.a.ArcaneSignet.class)); cards.add(new SetCardInfo("Arcanist's Owl", 206, Rarity.UNCOMMON, mage.cards.a.ArcanistsOwl.class)); + cards.add(new SetCardInfo("Archon of Absolution", 3, Rarity.UNCOMMON, mage.cards.a.ArchonOfAbsolution.class)); + cards.add(new SetCardInfo("Ardenvale Paladin", 4, Rarity.COMMON, mage.cards.a.ArdenvalePaladin.class)); + cards.add(new SetCardInfo("Ardenvale Tactician", 5, Rarity.COMMON, mage.cards.a.ArdenvaleTactician.class)); + cards.add(new SetCardInfo("Ayara, First of Locthwain", 75, Rarity.RARE, mage.cards.a.AyaraFirstOfLocthwain.class)); cards.add(new SetCardInfo("Bake into a Pie", 76, Rarity.COMMON, mage.cards.b.BakeIntoAPie.class)); cards.add(new SetCardInfo("Banish into Fable", 325, Rarity.RARE, mage.cards.b.BanishIntoFable.class)); + cards.add(new SetCardInfo("Barge In", 112, Rarity.COMMON, mage.cards.b.BargeIn.class)); + cards.add(new SetCardInfo("Barrow Witches", 77, Rarity.COMMON, mage.cards.b.BarrowWitches.class)); + cards.add(new SetCardInfo("Bartered Cow", 6, Rarity.COMMON, mage.cards.b.BarteredCow.class)); cards.add(new SetCardInfo("Beanstalk Giant", 149, Rarity.UNCOMMON, mage.cards.b.BeanstalkGiant.class)); cards.add(new SetCardInfo("Belle of the Brawl", 78, Rarity.UNCOMMON, mage.cards.b.BelleOfTheBrawl.class)); + cards.add(new SetCardInfo("Beloved Princess", 7, Rarity.COMMON, mage.cards.b.BelovedPrincess.class)); + cards.add(new SetCardInfo("Blacklance Paragon", 79, Rarity.RARE, mage.cards.b.BlacklanceParagon.class)); + cards.add(new SetCardInfo("Bloodhaze Wolverine", 113, Rarity.COMMON, mage.cards.b.BloodhazeWolverine.class)); + cards.add(new SetCardInfo("Blow Your House Down", 114, Rarity.COMMON, mage.cards.b.BlowYourHouseDown.class)); + cards.add(new SetCardInfo("Bog Naughty", 80, Rarity.UNCOMMON, mage.cards.b.BogNaughty.class)); + cards.add(new SetCardInfo("Bonecrusher Giant", 115, Rarity.RARE, mage.cards.b.BonecrusherGiant.class)); + cards.add(new SetCardInfo("Bramblefort Fink", 311, Rarity.UNCOMMON, mage.cards.b.BramblefortFink.class)); + cards.add(new SetCardInfo("Brazen Borrower", 39, Rarity.MYTHIC, mage.cards.b.BrazenBorrower.class)); + cards.add(new SetCardInfo("Brimstone Trebuchet", 116, Rarity.COMMON, mage.cards.b.BrimstoneTrebuchet.class)); + cards.add(new SetCardInfo("Burning-Yard Trainer", 117, Rarity.UNCOMMON, mage.cards.b.BurningYardTrainer.class)); + cards.add(new SetCardInfo("Castle Ardenvale", 238, Rarity.RARE, mage.cards.c.CastleArdenvale.class)); + cards.add(new SetCardInfo("Castle Embereth", 239, Rarity.RARE, mage.cards.c.CastleEmbereth.class)); + cards.add(new SetCardInfo("Castle Garenbrig", 240, Rarity.RARE, mage.cards.c.CastleGarenbrig.class)); + cards.add(new SetCardInfo("Castle Locthwain", 241, Rarity.RARE, mage.cards.c.CastleLocthwain.class)); + cards.add(new SetCardInfo("Castle Vantress", 242, Rarity.RARE, mage.cards.c.CastleVantress.class)); + cards.add(new SetCardInfo("Cauldron Familiar", 81, Rarity.UNCOMMON, mage.cards.c.CauldronFamiliar.class)); + cards.add(new SetCardInfo("Cauldron's Gift", 83, Rarity.UNCOMMON, mage.cards.c.CauldronsGift.class)); + cards.add(new SetCardInfo("Charmed Sleep", 40, Rarity.COMMON, mage.cards.c.CharmedSleep.class)); + cards.add(new SetCardInfo("Charming Prince", 8, Rarity.RARE, mage.cards.c.CharmingPrince.class)); cards.add(new SetCardInfo("Chittering Witch", 319, Rarity.RARE, mage.cards.c.ChitteringWitch.class)); cards.add(new SetCardInfo("Chulane, Teller of Tales", 326, Rarity.MYTHIC, mage.cards.c.ChulaneTellerOfTales.class)); + cards.add(new SetCardInfo("Clackbridge Troll", 84, Rarity.RARE, mage.cards.c.ClackbridgeTroll.class)); + cards.add(new SetCardInfo("Claim the Firstborn", 118, Rarity.UNCOMMON, mage.cards.c.ClaimTheFirstborn.class)); + cards.add(new SetCardInfo("Clockwork Servant", 216, Rarity.UNCOMMON, mage.cards.c.ClockworkServant.class)); cards.add(new SetCardInfo("Command Tower", 333, Rarity.COMMON, mage.cards.c.CommandTower.class)); cards.add(new SetCardInfo("Corridor Monitor", 41, Rarity.COMMON, mage.cards.c.CorridorMonitor.class)); + cards.add(new SetCardInfo("Covetous Urge", 207, Rarity.UNCOMMON, mage.cards.c.CovetousUrge.class)); + cards.add(new SetCardInfo("Crashing Drawbridge", 217, Rarity.COMMON, mage.cards.c.CrashingDrawbridge.class)); cards.add(new SetCardInfo("Crystal Slipper", 119, Rarity.COMMON, mage.cards.c.CrystalSlipper.class)); + cards.add(new SetCardInfo("Curious Pair", 150, Rarity.COMMON, mage.cards.c.CuriousPair.class)); + cards.add(new SetCardInfo("Dance of the Manse", 186, Rarity.RARE, mage.cards.d.DanceOfTheManse.class)); + cards.add(new SetCardInfo("Deafening Silence", 10, Rarity.UNCOMMON, mage.cards.d.DeafeningSilence.class)); + cards.add(new SetCardInfo("Deathless Knight", 208, Rarity.UNCOMMON, mage.cards.d.DeathlessKnight.class)); + cards.add(new SetCardInfo("Didn't Say Please", 42, Rarity.COMMON, mage.cards.d.DidntSayPlease.class)); + cards.add(new SetCardInfo("Doom Foretold", 187, Rarity.RARE, mage.cards.d.DoomForetold.class)); + cards.add(new SetCardInfo("Drown in the Loch", 188, Rarity.UNCOMMON, mage.cards.d.DrownInTheLoch.class)); + cards.add(new SetCardInfo("Dwarven Mine", 243, Rarity.COMMON, mage.cards.d.DwarvenMine.class)); + cards.add(new SetCardInfo("Edgewall Innkeeper", 151, Rarity.UNCOMMON, mage.cards.e.EdgewallInnkeeper.class)); + cards.add(new SetCardInfo("Elite Headhunter", 209, Rarity.UNCOMMON, mage.cards.e.EliteHeadhunter.class)); + cards.add(new SetCardInfo("Embercleave", 120, Rarity.MYTHIC, mage.cards.e.Embercleave.class)); cards.add(new SetCardInfo("Embereth Paladin", 121, Rarity.COMMON, mage.cards.e.EmberethPaladin.class)); cards.add(new SetCardInfo("Embereth Shieldbreaker", 122, Rarity.UNCOMMON, mage.cards.e.EmberethShieldbreaker.class)); cards.add(new SetCardInfo("Embereth Skyblazer", 321, Rarity.RARE, mage.cards.e.EmberethSkyblazer.class)); + cards.add(new SetCardInfo("Emry, Lurker of the Loch", 43, Rarity.RARE, mage.cards.e.EmryLurkerOfTheLoch.class)); + cards.add(new SetCardInfo("Enchanted Carriage", 218, Rarity.UNCOMMON, mage.cards.e.EnchantedCarriage.class)); + cards.add(new SetCardInfo("Epic Downfall", 85, Rarity.UNCOMMON, mage.cards.e.EpicDownfall.class)); + cards.add(new SetCardInfo("Escape to the Wilds", 189, Rarity.RARE, mage.cards.e.EscapeToTheWilds.class)); cards.add(new SetCardInfo("Eye Collector", 86, Rarity.COMMON, mage.cards.e.EyeCollector.class)); + cards.add(new SetCardInfo("Fabled Passage", 244, Rarity.RARE, mage.cards.f.FabledPassage.class)); + cards.add(new SetCardInfo("Fae of Wishes", 44, Rarity.RARE, mage.cards.f.FaeOfWishes.class)); + cards.add(new SetCardInfo("Faeburrow Elder", 190, Rarity.RARE, mage.cards.f.FaeburrowElder.class)); cards.add(new SetCardInfo("Faerie Formation", 316, Rarity.RARE, mage.cards.f.FaerieFormation.class)); + cards.add(new SetCardInfo("Faerie Guidemother", 11, Rarity.COMMON, mage.cards.f.FaerieGuidemother.class)); + cards.add(new SetCardInfo("Faerie Vandal", 45, Rarity.UNCOMMON, mage.cards.f.FaerieVandal.class)); + cards.add(new SetCardInfo("Feasting Troll King", 152, Rarity.RARE, mage.cards.f.FeastingTrollKing.class)); + cards.add(new SetCardInfo("Fell the Pheasant", 153, Rarity.COMMON, mage.cards.f.FellThePheasant.class)); + cards.add(new SetCardInfo("Ferocity of the Wilds", 123, Rarity.UNCOMMON, mage.cards.f.FerocityOfTheWilds.class)); + cards.add(new SetCardInfo("Fervent Champion", 124, Rarity.RARE, mage.cards.f.FerventChampion.class)); + cards.add(new SetCardInfo("Festive Funeral", 87, Rarity.COMMON, mage.cards.f.FestiveFuneral.class)); + cards.add(new SetCardInfo("Fierce Witchstalker", 154, Rarity.COMMON, mage.cards.f.FierceWitchstalker.class)); cards.add(new SetCardInfo("Fireborn Knight", 210, Rarity.UNCOMMON, mage.cards.f.FirebornKnight.class)); + cards.add(new SetCardInfo("Fires of Invention", 125, Rarity.RARE, mage.cards.f.FiresOfInvention.class)); cards.add(new SetCardInfo("Flaxen Intruder", 155, Rarity.UNCOMMON, mage.cards.f.FlaxenIntruder.class)); + cards.add(new SetCardInfo("Fling", 126, Rarity.COMMON, mage.cards.f.Fling.class)); + cards.add(new SetCardInfo("Flutterfox", 12, Rarity.COMMON, mage.cards.f.Flutterfox.class)); + cards.add(new SetCardInfo("Folio of Fancies", 46, Rarity.RARE, mage.cards.f.FolioOfFancies.class)); + cards.add(new SetCardInfo("Foreboding Fruit", 88, Rarity.COMMON, mage.cards.f.ForebodingFruit.class)); + cards.add(new SetCardInfo("Forest", 266, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Forest", 267, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Forest", 268, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Forest", 269, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Forever Young", 89, Rarity.COMMON, mage.cards.f.ForeverYoung.class)); + cards.add(new SetCardInfo("Fortifying Provisions", 13, Rarity.COMMON, mage.cards.f.FortifyingProvisions.class)); cards.add(new SetCardInfo("Foulmire Knight", 90, Rarity.UNCOMMON, mage.cards.f.FoulmireKnight.class)); cards.add(new SetCardInfo("Frogify", 47, Rarity.UNCOMMON, mage.cards.f.Frogify.class)); + cards.add(new SetCardInfo("Gadwick, the Wizened", 48, Rarity.RARE, mage.cards.g.GadwickTheWizened.class)); + cards.add(new SetCardInfo("Garenbrig Carver", 156, Rarity.COMMON, mage.cards.g.GarenbrigCarver.class)); + cards.add(new SetCardInfo("Garenbrig Paladin", 157, Rarity.COMMON, mage.cards.g.GarenbrigPaladin.class)); + cards.add(new SetCardInfo("Garenbrig Squire", 158, Rarity.COMMON, mage.cards.g.GarenbrigSquire.class)); + cards.add(new SetCardInfo("Garrison Griffin", 305, Rarity.COMMON, mage.cards.g.GarrisonGriffin.class)); cards.add(new SetCardInfo("Garruk, Cursed Huntsman", 191, Rarity.MYTHIC, mage.cards.g.GarrukCursedHuntsman.class)); + cards.add(new SetCardInfo("Giant Killer", 14, Rarity.RARE, mage.cards.g.GiantKiller.class)); + cards.add(new SetCardInfo("Giant Opportunity", 159, Rarity.UNCOMMON, mage.cards.g.GiantOpportunity.class)); + cards.add(new SetCardInfo("Giant's Skewer", 91, Rarity.COMMON, mage.cards.g.GiantsSkewer.class)); cards.add(new SetCardInfo("Gilded Goose", 160, Rarity.RARE, mage.cards.g.GildedGoose.class)); + cards.add(new SetCardInfo("Gingerbread Cabin", 245, Rarity.COMMON, mage.cards.g.GingerbreadCabin.class)); + cards.add(new SetCardInfo("Gingerbrute", 219, Rarity.COMMON, mage.cards.g.Gingerbrute.class)); + cards.add(new SetCardInfo("Glass Casket", 15, Rarity.UNCOMMON, mage.cards.g.GlassCasket.class)); cards.add(new SetCardInfo("Gluttonous Troll", 327, Rarity.RARE, mage.cards.g.GluttonousTroll.class)); cards.add(new SetCardInfo("Golden Egg", 220, Rarity.COMMON, mage.cards.g.GoldenEgg.class)); + cards.add(new SetCardInfo("Grumgully, the Generous", 192, Rarity.UNCOMMON, mage.cards.g.GrumgullyTheGenerous.class)); + cards.add(new SetCardInfo("Happily Ever After", 16, Rarity.RARE, mage.cards.h.HappilyEverAfter.class)); + cards.add(new SetCardInfo("Harmonious Archon", 17, Rarity.MYTHIC, mage.cards.h.HarmoniousArchon.class)); + cards.add(new SetCardInfo("Henge Walker", 221, Rarity.COMMON, mage.cards.h.HengeWalker.class)); cards.add(new SetCardInfo("Heraldic Banner", 222, Rarity.UNCOMMON, mage.cards.h.HeraldicBanner.class)); + cards.add(new SetCardInfo("Hushbringer", 18, Rarity.RARE, mage.cards.h.Hushbringer.class)); + cards.add(new SetCardInfo("Hypnotic Sprite", 49, Rarity.UNCOMMON, mage.cards.h.HypnoticSprite.class)); + cards.add(new SetCardInfo("Idyllic Grange", 246, Rarity.COMMON, mage.cards.i.IdyllicGrange.class)); + cards.add(new SetCardInfo("Improbable Alliance", 193, Rarity.UNCOMMON, mage.cards.i.ImprobableAlliance.class)); + cards.add(new SetCardInfo("Inquisitive Puppet", 223, Rarity.UNCOMMON, mage.cards.i.InquisitivePuppet.class)); + cards.add(new SetCardInfo("Insatiable Appetite", 162, Rarity.COMMON, mage.cards.i.InsatiableAppetite.class)); cards.add(new SetCardInfo("Inspiring Veteran", 194, Rarity.UNCOMMON, mage.cards.i.InspiringVeteran.class)); + cards.add(new SetCardInfo("Into the Story", 50, Rarity.UNCOMMON, mage.cards.i.IntoTheStory.class)); + cards.add(new SetCardInfo("Irencrag Feat", 127, Rarity.RARE, mage.cards.i.IrencragFeat.class)); + cards.add(new SetCardInfo("Irencrag Pyromancer", 128, Rarity.RARE, mage.cards.i.IrencragPyromancer.class)); + cards.add(new SetCardInfo("Island", 254, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Island", 255, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Island", 256, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Island", 257, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Joust", 129, Rarity.UNCOMMON, mage.cards.j.Joust.class)); + cards.add(new SetCardInfo("Jousting Dummy", 224, Rarity.COMMON, mage.cards.j.JoustingDummy.class)); cards.add(new SetCardInfo("Keeper of Fables", 163, Rarity.UNCOMMON, mage.cards.k.KeeperOfFables.class)); + cards.add(new SetCardInfo("Kenrith's Transformation", 164, Rarity.UNCOMMON, mage.cards.k.KenrithsTransformation.class)); + cards.add(new SetCardInfo("Kenrith, the Returned King", 303, Rarity.MYTHIC, mage.cards.k.KenrithTheReturnedKing.class)); + cards.add(new SetCardInfo("Knight of the Keep", 19, Rarity.COMMON, mage.cards.k.KnightOfTheKeep.class)); cards.add(new SetCardInfo("Knights' Charge", 328, Rarity.RARE, mage.cards.k.KnightsCharge.class)); cards.add(new SetCardInfo("Korvold, Fae-Cursed King", 329, Rarity.MYTHIC, mage.cards.k.KorvoldFaeCursedKing.class)); + cards.add(new SetCardInfo("Lash of Thorns", 92, Rarity.COMMON, mage.cards.l.LashOfThorns.class)); + cards.add(new SetCardInfo("Linden, the Steadfast Queen", 20, Rarity.RARE, mage.cards.l.LindenTheSteadfastQueen.class)); + cards.add(new SetCardInfo("Loch Dragon", 211, Rarity.UNCOMMON, mage.cards.l.LochDragon.class)); + cards.add(new SetCardInfo("Lochmere Serpent", 195, Rarity.RARE, mage.cards.l.LochmereSerpent.class)); + cards.add(new SetCardInfo("Locthwain Gargoyle", 225, Rarity.COMMON, mage.cards.l.LocthwainGargoyle.class)); + cards.add(new SetCardInfo("Locthwain Paladin", 93, Rarity.COMMON, mage.cards.l.LocthwainPaladin.class)); + cards.add(new SetCardInfo("Lonesome Unicorn", 21, Rarity.COMMON, mage.cards.l.LonesomeUnicorn.class)); + cards.add(new SetCardInfo("Lost Legion", 94, Rarity.COMMON, mage.cards.l.LostLegion.class)); cards.add(new SetCardInfo("Lovestruck Beast", 165, Rarity.RARE, mage.cards.l.LovestruckBeast.class)); + cards.add(new SetCardInfo("Lucky Clover", 226, Rarity.UNCOMMON, mage.cards.l.LuckyClover.class)); cards.add(new SetCardInfo("Mace of the Valiant", 314, Rarity.RARE, mage.cards.m.MaceOfTheValiant.class)); + cards.add(new SetCardInfo("Mad Ratter", 130, Rarity.UNCOMMON, mage.cards.m.MadRatter.class)); + cards.add(new SetCardInfo("Malevolent Noble", 95, Rarity.COMMON, mage.cards.m.MalevolentNoble.class)); + cards.add(new SetCardInfo("Mantle of Tides", 52, Rarity.COMMON, mage.cards.m.MantleOfTides.class)); cards.add(new SetCardInfo("Maraleaf Pixie", 196, Rarity.UNCOMMON, mage.cards.m.MaraleafPixie.class)); + cards.add(new SetCardInfo("Maraleaf Rider", 166, Rarity.COMMON, mage.cards.m.MaraleafRider.class)); + cards.add(new SetCardInfo("Memory Theft", 96, Rarity.COMMON, mage.cards.m.MemoryTheft.class)); + cards.add(new SetCardInfo("Merchant of the Vale", 131, Rarity.COMMON, mage.cards.m.MerchantOfTheVale.class)); + cards.add(new SetCardInfo("Merfolk Secretkeeper", 53, Rarity.COMMON, mage.cards.m.MerfolkSecretkeeper.class)); cards.add(new SetCardInfo("Midnight Clock", 54, Rarity.RARE, mage.cards.m.MidnightClock.class)); + cards.add(new SetCardInfo("Mirrormade", 55, Rarity.RARE, mage.cards.m.Mirrormade.class)); + cards.add(new SetCardInfo("Mistford River Turtle", 56, Rarity.COMMON, mage.cards.m.MistfordRiverTurtle.class)); + cards.add(new SetCardInfo("Moonlit Scavengers", 57, Rarity.COMMON, mage.cards.m.MoonlitScavengers.class)); + cards.add(new SetCardInfo("Mountain", 262, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Mountain", 263, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Mountain", 264, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Mountain", 265, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Murderous Rider", 97, Rarity.RARE, mage.cards.m.MurderousRider.class)); + cards.add(new SetCardInfo("Mysterious Pathlighter", 22, Rarity.UNCOMMON, mage.cards.m.MysteriousPathlighter.class)); + cards.add(new SetCardInfo("Mystic Sanctuary", 247, Rarity.COMMON, mage.cards.m.MysticSanctuary.class)); + cards.add(new SetCardInfo("Mystical Dispute", 58, Rarity.UNCOMMON, mage.cards.m.MysticalDispute.class)); + cards.add(new SetCardInfo("Oakhame Adversary", 167, Rarity.UNCOMMON, mage.cards.o.OakhameAdversary.class)); + cards.add(new SetCardInfo("Oakhame Ranger", 212, Rarity.UNCOMMON, mage.cards.o.OakhameRanger.class)); + cards.add(new SetCardInfo("Oathsworn Knight", 98, Rarity.RARE, mage.cards.o.OathswornKnight.class)); + cards.add(new SetCardInfo("Ogre Errant", 132, Rarity.COMMON, mage.cards.o.OgreErrant.class)); + cards.add(new SetCardInfo("Oko's Accomplices", 310, Rarity.COMMON, mage.cards.o.OkosAccomplices.class)); + cards.add(new SetCardInfo("Oko's Hospitality", 312, Rarity.RARE, mage.cards.o.OkosHospitality.class)); cards.add(new SetCardInfo("Oko, Thief of Crowns", 197, Rarity.MYTHIC, mage.cards.o.OkoThiefOfCrowns.class)); + cards.add(new SetCardInfo("Oko, the Trickster", 309, Rarity.MYTHIC, mage.cards.o.OkoTheTrickster.class)); + cards.add(new SetCardInfo("Once Upon a Time", 169, Rarity.RARE, mage.cards.o.OnceUponATime.class)); + cards.add(new SetCardInfo("Once and Future", 168, Rarity.UNCOMMON, mage.cards.o.OnceAndFuture.class)); + cards.add(new SetCardInfo("Opportunistic Dragon", 133, Rarity.RARE, mage.cards.o.OpportunisticDragon.class)); + cards.add(new SetCardInfo("Opt", 59, Rarity.COMMON, mage.cards.o.Opt.class)); cards.add(new SetCardInfo("Order of Midnight", 99, Rarity.UNCOMMON, mage.cards.o.OrderOfMidnight.class)); + cards.add(new SetCardInfo("Outflank", 23, Rarity.COMMON, mage.cards.o.Outflank.class)); + cards.add(new SetCardInfo("Outlaws' Merriment", 198, Rarity.MYTHIC, mage.cards.o.OutlawsMerriment.class)); + cards.add(new SetCardInfo("Outmuscle", 170, Rarity.COMMON, mage.cards.o.Outmuscle.class)); + cards.add(new SetCardInfo("Overwhelmed Apprentice", 60, Rarity.UNCOMMON, mage.cards.o.OverwhelmedApprentice.class)); cards.add(new SetCardInfo("Piper of the Swarm", 100, Rarity.RARE, mage.cards.p.PiperOfTheSwarm.class)); + cards.add(new SetCardInfo("Plains", 250, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Plains", 251, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Plains", 252, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Plains", 253, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Prized Griffin", 24, Rarity.COMMON, mage.cards.p.PrizedGriffin.class)); + cards.add(new SetCardInfo("Prophet of the Peak", 227, Rarity.COMMON, mage.cards.p.ProphetOfThePeak.class)); + cards.add(new SetCardInfo("Queen of Ice", 61, Rarity.COMMON, mage.cards.q.QueenOfIce.class)); + cards.add(new SetCardInfo("Questing Beast", 171, Rarity.MYTHIC, mage.cards.q.QuestingBeast.class)); + cards.add(new SetCardInfo("Raging Redcap", 134, Rarity.COMMON, mage.cards.r.RagingRedcap.class)); + cards.add(new SetCardInfo("Rally for the Throne", 25, Rarity.UNCOMMON, mage.cards.r.RallyForTheThrone.class)); + cards.add(new SetCardInfo("Rampart Smasher", 213, Rarity.UNCOMMON, mage.cards.r.RampartSmasher.class)); cards.add(new SetCardInfo("Rankle, Master of Pranks", 101, Rarity.MYTHIC, mage.cards.r.RankleMasterOfPranks.class)); + cards.add(new SetCardInfo("Realm-Cloaked Giant", 26, Rarity.MYTHIC, mage.cards.r.RealmCloakedGiant.class)); + cards.add(new SetCardInfo("Reaper of Night", 102, Rarity.COMMON, mage.cards.r.ReaperOfNight.class)); + cards.add(new SetCardInfo("Reave Soul", 103, Rarity.COMMON, mage.cards.r.ReaveSoul.class)); + cards.add(new SetCardInfo("Redcap Melee", 135, Rarity.UNCOMMON, mage.cards.r.RedcapMelee.class)); + cards.add(new SetCardInfo("Redcap Raiders", 136, Rarity.COMMON, mage.cards.r.RedcapRaiders.class)); + cards.add(new SetCardInfo("Resolute Rider", 214, Rarity.UNCOMMON, mage.cards.r.ResoluteRider.class)); + cards.add(new SetCardInfo("Return of the Wildspeaker", 172, Rarity.RARE, mage.cards.r.ReturnOfTheWildspeaker.class)); + cards.add(new SetCardInfo("Return to Nature", 173, Rarity.COMMON, mage.cards.r.ReturnToNature.class)); + cards.add(new SetCardInfo("Revenge of Ravens", 104, Rarity.UNCOMMON, mage.cards.r.RevengeOfRavens.class)); + cards.add(new SetCardInfo("Righteousness", 27, Rarity.UNCOMMON, mage.cards.r.Righteousness.class)); + cards.add(new SetCardInfo("Rimrock Knight", 137, Rarity.COMMON, mage.cards.r.RimrockKnight.class)); + cards.add(new SetCardInfo("Robber of the Rich", 138, Rarity.MYTHIC, mage.cards.r.RobberOfTheRich.class)); cards.add(new SetCardInfo("Rosethorn Acolyte", 174, Rarity.COMMON, mage.cards.r.RosethornAcolyte.class)); + cards.add(new SetCardInfo("Rosethorn Halberd", 175, Rarity.COMMON, mage.cards.r.RosethornHalberd.class)); + cards.add(new SetCardInfo("Roving Keep", 228, Rarity.COMMON, mage.cards.r.RovingKeep.class)); + cards.add(new SetCardInfo("Rowan's Battleguard", 306, Rarity.UNCOMMON, mage.cards.r.RowansBattleguard.class)); + cards.add(new SetCardInfo("Rowan's Stalwarts", 307, Rarity.RARE, mage.cards.r.RowansStalwarts.class)); + cards.add(new SetCardInfo("Rowan, Fearless Sparkmage", 304, Rarity.MYTHIC, mage.cards.r.RowanFearlessSparkmage.class)); cards.add(new SetCardInfo("Run Away Together", 62, Rarity.COMMON, mage.cards.r.RunAwayTogether.class)); + cards.add(new SetCardInfo("Sage of the Falls", 63, Rarity.UNCOMMON, mage.cards.s.SageOfTheFalls.class)); cards.add(new SetCardInfo("Savvy Hunter", 200, Rarity.UNCOMMON, mage.cards.s.SavvyHunter.class)); + cards.add(new SetCardInfo("Scalding Cauldron", 229, Rarity.COMMON, mage.cards.s.ScaldingCauldron.class)); + cards.add(new SetCardInfo("Scorching Dragonfire", 139, Rarity.COMMON, mage.cards.s.ScorchingDragonfire.class)); + cards.add(new SetCardInfo("Searing Barrage", 140, Rarity.COMMON, mage.cards.s.SearingBarrage.class)); + cards.add(new SetCardInfo("Seven Dwarves", 141, Rarity.COMMON, mage.cards.s.SevenDwarves.class)); + cards.add(new SetCardInfo("Shambling Suit", 230, Rarity.UNCOMMON, mage.cards.s.ShamblingSuit.class)); + cards.add(new SetCardInfo("Shepherd of the Flock", 28, Rarity.UNCOMMON, mage.cards.s.ShepherdOfTheFlock.class)); cards.add(new SetCardInfo("Shimmer Dragon", 317, Rarity.RARE, mage.cards.s.ShimmerDragon.class)); cards.add(new SetCardInfo("Shinechaser", 201, Rarity.UNCOMMON, mage.cards.s.Shinechaser.class)); cards.add(new SetCardInfo("Shining Armor", 29, Rarity.COMMON, mage.cards.s.ShiningArmor.class)); + cards.add(new SetCardInfo("Signpost Scarecrow", 231, Rarity.COMMON, mage.cards.s.SignpostScarecrow.class)); cards.add(new SetCardInfo("Silverflame Ritual", 30, Rarity.COMMON, mage.cards.s.SilverflameRitual.class)); + cards.add(new SetCardInfo("Silverflame Squire", 31, Rarity.COMMON, mage.cards.s.SilverflameSquire.class)); cards.add(new SetCardInfo("Silverwing Squadron", 315, Rarity.RARE, mage.cards.s.SilverwingSquadron.class)); + cards.add(new SetCardInfo("Skullknocker Ogre", 142, Rarity.UNCOMMON, mage.cards.s.SkullknockerOgre.class)); cards.add(new SetCardInfo("Slaying Fire", 143, Rarity.UNCOMMON, mage.cards.s.SlayingFire.class)); cards.add(new SetCardInfo("Smitten Swordmaster", 105, Rarity.COMMON, mage.cards.s.SmittenSwordmaster.class)); + cards.add(new SetCardInfo("So Tiny", 64, Rarity.COMMON, mage.cards.s.SoTiny.class)); + cards.add(new SetCardInfo("Sorcerer's Broom", 232, Rarity.UNCOMMON, mage.cards.s.SorcerersBroom.class)); + cards.add(new SetCardInfo("Sorcerous Spyglass", 233, Rarity.RARE, mage.cards.s.SorcerousSpyglass.class)); + cards.add(new SetCardInfo("Specter's Shriek", 106, Rarity.UNCOMMON, mage.cards.s.SpectersShriek.class)); + cards.add(new SetCardInfo("Spinning Wheel", 234, Rarity.UNCOMMON, mage.cards.s.SpinningWheel.class)); + cards.add(new SetCardInfo("Sporecap Spider", 176, Rarity.COMMON, mage.cards.s.SporecapSpider.class)); cards.add(new SetCardInfo("Steelbane Hydra", 322, Rarity.RARE, mage.cards.s.SteelbaneHydra.class)); cards.add(new SetCardInfo("Steelclaw Lance", 202, Rarity.UNCOMMON, mage.cards.s.SteelclawLance.class)); + cards.add(new SetCardInfo("Steelgaze Griffin", 65, Rarity.COMMON, mage.cards.s.SteelgazeGriffin.class)); + cards.add(new SetCardInfo("Stolen by the Fae", 66, Rarity.RARE, mage.cards.s.StolenByTheFae.class)); + cards.add(new SetCardInfo("Stonecoil Serpent", 235, Rarity.RARE, mage.cards.s.StonecoilSerpent.class)); + cards.add(new SetCardInfo("Stormfist Crusader", 203, Rarity.RARE, mage.cards.s.StormfistCrusader.class)); + cards.add(new SetCardInfo("Sundering Stroke", 144, Rarity.RARE, mage.cards.s.SunderingStroke.class)); + cards.add(new SetCardInfo("Swamp", 258, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Swamp", 259, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Swamp", 260, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Swamp", 261, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Syr Alin, the Lion's Claw", 32, Rarity.UNCOMMON, mage.cards.s.SyrAlinTheLionsClaw.class)); + cards.add(new SetCardInfo("Syr Carah, the Bold", 145, Rarity.UNCOMMON, mage.cards.s.SyrCarahTheBold.class)); + cards.add(new SetCardInfo("Syr Elenora, the Discerning", 67, Rarity.UNCOMMON, mage.cards.s.SyrElenoraTheDiscerning.class)); + cards.add(new SetCardInfo("Syr Faren, the Hengehammer", 177, Rarity.UNCOMMON, mage.cards.s.SyrFarenTheHengehammer.class)); cards.add(new SetCardInfo("Syr Gwyn, Hero of Ashvale", 330, Rarity.MYTHIC, mage.cards.s.SyrGwynHeroOfAshvale.class)); cards.add(new SetCardInfo("Syr Konrad, the Grim", 107, Rarity.UNCOMMON, mage.cards.s.SyrKonradTheGrim.class)); + cards.add(new SetCardInfo("Tall as a Beanstalk", 178, Rarity.COMMON, mage.cards.t.TallAsABeanstalk.class)); cards.add(new SetCardInfo("Taste of Death", 320, Rarity.RARE, mage.cards.t.TasteOfDeath.class)); + cards.add(new SetCardInfo("Tempting Witch", 108, Rarity.COMMON, mage.cards.t.TemptingWitch.class)); + cards.add(new SetCardInfo("The Cauldron of Eternity", 82, Rarity.MYTHIC, mage.cards.t.TheCauldronOfEternity.class)); cards.add(new SetCardInfo("The Circle of Loyalty", 9, Rarity.MYTHIC, mage.cards.t.TheCircleOfLoyalty.class)); + cards.add(new SetCardInfo("The Great Henge", 161, Rarity.MYTHIC, mage.cards.t.TheGreatHenge.class)); + cards.add(new SetCardInfo("The Magic Mirror", 51, Rarity.MYTHIC, mage.cards.t.TheMagicMirror.class)); + cards.add(new SetCardInfo("The Royal Scions", 199, Rarity.MYTHIC, mage.cards.t.TheRoyalScions.class)); cards.add(new SetCardInfo("Thorn Mammoth", 323, Rarity.RARE, mage.cards.t.ThornMammoth.class)); cards.add(new SetCardInfo("Thornwood Falls", 313, Rarity.COMMON, mage.cards.t.ThornwoodFalls.class)); + cards.add(new SetCardInfo("Thrill of Possibility", 146, Rarity.COMMON, mage.cards.t.ThrillOfPossibility.class)); + cards.add(new SetCardInfo("Thunderous Snapper", 215, Rarity.UNCOMMON, mage.cards.t.ThunderousSnapper.class)); cards.add(new SetCardInfo("Tome Raider", 68, Rarity.COMMON, mage.cards.t.TomeRaider.class)); cards.add(new SetCardInfo("Tome of Legends", 332, Rarity.RARE, mage.cards.t.TomeOfLegends.class)); + cards.add(new SetCardInfo("Torbran, Thane of Red Fell", 147, Rarity.RARE, mage.cards.t.TorbranThaneOfRedFell.class)); cards.add(new SetCardInfo("Tournament Grounds", 248, Rarity.UNCOMMON, mage.cards.t.TournamentGrounds.class)); + cards.add(new SetCardInfo("Trail of Crumbs", 179, Rarity.UNCOMMON, mage.cards.t.TrailOfCrumbs.class)); + cards.add(new SetCardInfo("Trapped in the Tower", 33, Rarity.COMMON, mage.cards.t.TrappedInTheTower.class)); + cards.add(new SetCardInfo("True Love's Kiss", 34, Rarity.COMMON, mage.cards.t.TrueLovesKiss.class)); + cards.add(new SetCardInfo("Tuinvale Treefolk", 180, Rarity.COMMON, mage.cards.t.TuinvaleTreefolk.class)); + cards.add(new SetCardInfo("Turn into a Pumpkin", 69, Rarity.UNCOMMON, mage.cards.t.TurnIntoAPumpkin.class)); + cards.add(new SetCardInfo("Unexplained Vision", 70, Rarity.COMMON, mage.cards.u.UnexplainedVision.class)); + cards.add(new SetCardInfo("Vantress Gargoyle", 71, Rarity.RARE, mage.cards.v.VantressGargoyle.class)); + cards.add(new SetCardInfo("Vantress Paladin", 72, Rarity.COMMON, mage.cards.v.VantressPaladin.class)); + cards.add(new SetCardInfo("Venerable Knight", 35, Rarity.UNCOMMON, mage.cards.v.VenerableKnight.class)); + cards.add(new SetCardInfo("Wandermare", 204, Rarity.UNCOMMON, mage.cards.w.Wandermare.class)); + cards.add(new SetCardInfo("Weapon Rack", 236, Rarity.COMMON, mage.cards.w.WeaponRack.class)); + cards.add(new SetCardInfo("Weaselback Redcap", 148, Rarity.COMMON, mage.cards.w.WeaselbackRedcap.class)); + cards.add(new SetCardInfo("Wicked Guardian", 109, Rarity.COMMON, mage.cards.w.WickedGuardian.class)); + cards.add(new SetCardInfo("Wicked Wolf", 181, Rarity.RARE, mage.cards.w.WickedWolf.class)); + cards.add(new SetCardInfo("Wildborn Preserver", 182, Rarity.RARE, mage.cards.w.WildbornPreserver.class)); + cards.add(new SetCardInfo("Wildwood Tracker", 183, Rarity.COMMON, mage.cards.w.WildwoodTracker.class)); cards.add(new SetCardInfo("Wind-Scarred Crag", 308, Rarity.COMMON, mage.cards.w.WindScarredCrag.class)); cards.add(new SetCardInfo("Wintermoor Commander", 205, Rarity.UNCOMMON, mage.cards.w.WintermoorCommander.class)); + cards.add(new SetCardInfo("Wishclaw Talisman", 110, Rarity.RARE, mage.cards.w.WishclawTalisman.class)); cards.add(new SetCardInfo("Wishful Merfolk", 73, Rarity.COMMON, mage.cards.w.WishfulMerfolk.class)); cards.add(new SetCardInfo("Witch's Cottage", 249, Rarity.COMMON, mage.cards.w.WitchsCottage.class)); + cards.add(new SetCardInfo("Witch's Oven", 237, Rarity.UNCOMMON, mage.cards.w.WitchsOven.class)); + cards.add(new SetCardInfo("Witch's Vengeance", 111, Rarity.RARE, mage.cards.w.WitchsVengeance.class)); cards.add(new SetCardInfo("Witching Well", 74, Rarity.COMMON, mage.cards.w.WitchingWell.class)); + cards.add(new SetCardInfo("Wolf's Quarry", 184, Rarity.COMMON, mage.cards.w.WolfsQuarry.class)); cards.add(new SetCardInfo("Workshop Elders", 318, Rarity.RARE, mage.cards.w.WorkshopElders.class)); + cards.add(new SetCardInfo("Worthy Knight", 36, Rarity.RARE, mage.cards.w.WorthyKnight.class)); + cards.add(new SetCardInfo("Yorvo, Lord of Garenbrig", 185, Rarity.RARE, mage.cards.y.YorvoLordOfGarenbrig.class)); + cards.add(new SetCardInfo("Youthful Knight", 37, Rarity.COMMON, mage.cards.y.YouthfulKnight.class)); // This is here to prevent the incomplete adventure implementation from causing problems and will be removed cards.removeIf(setCardInfo -> AdventureCard.class.isAssignableFrom(setCardInfo.getCardClass())); diff --git a/Mage.Sets/src/mage/sets/ThroneOfEldraineCollectorsEdition.java b/Mage.Sets/src/mage/sets/ThroneOfEldraineCollectorsEdition.java new file mode 100644 index 0000000000..9606cef6f0 --- /dev/null +++ b/Mage.Sets/src/mage/sets/ThroneOfEldraineCollectorsEdition.java @@ -0,0 +1,118 @@ +package mage.sets; + +import mage.cards.AdventureCard; +import mage.cards.ExpansionSet; +import mage.constants.Rarity; +import mage.constants.SetType; + +/** + * @author TheElk801 + */ +public final class ThroneOfEldraineCollectorsEdition extends ExpansionSet { + + private static final ThroneOfEldraineCollectorsEdition instance = new ThroneOfEldraineCollectorsEdition(); + + public static ThroneOfEldraineCollectorsEdition getInstance() { + return instance; + } + + private ThroneOfEldraineCollectorsEdition() { + super("Throne of Eldraine Collector's Edition", "CELD", ExpansionSet.buildDate(2019, 10, 4), SetType.PROMOTIONAL); + this.hasBasicLands = false; + + cards.add(new SetCardInfo("Acclaimed Contender", 334, Rarity.RARE, mage.cards.a.AcclaimedContender.class)); + cards.add(new SetCardInfo("Animating Faerie", 280, Rarity.UNCOMMON, mage.cards.a.AnimatingFaerie.class)); + cards.add(new SetCardInfo("Ardenvale Tactician", 273, Rarity.COMMON, mage.cards.a.ArdenvaleTactician.class)); + cards.add(new SetCardInfo("Ayara, First of Locthwain", 350, Rarity.RARE, mage.cards.a.AyaraFirstOfLocthwain.class)); + cards.add(new SetCardInfo("Beanstalk Giant", 295, Rarity.UNCOMMON, mage.cards.b.BeanstalkGiant.class)); + cards.add(new SetCardInfo("Blacklance Paragon", 351, Rarity.RARE, mage.cards.b.BlacklanceParagon.class)); + cards.add(new SetCardInfo("Bonecrusher Giant", 291, Rarity.RARE, mage.cards.b.BonecrusherGiant.class)); + cards.add(new SetCardInfo("Brazen Borrower", 281, Rarity.MYTHIC, mage.cards.b.BrazenBorrower.class)); + cards.add(new SetCardInfo("Castle Ardenvale", 386, Rarity.RARE, mage.cards.c.CastleArdenvale.class)); + cards.add(new SetCardInfo("Castle Embereth", 387, Rarity.RARE, mage.cards.c.CastleEmbereth.class)); + cards.add(new SetCardInfo("Castle Garenbrig", 388, Rarity.RARE, mage.cards.c.CastleGarenbrig.class)); + cards.add(new SetCardInfo("Castle Locthwain", 389, Rarity.RARE, mage.cards.c.CastleLocthwain.class)); + cards.add(new SetCardInfo("Castle Vantress", 390, Rarity.RARE, mage.cards.c.CastleVantress.class)); + cards.add(new SetCardInfo("Charming Prince", 335, Rarity.RARE, mage.cards.c.CharmingPrince.class)); + cards.add(new SetCardInfo("Clackbridge Troll", 353, Rarity.RARE, mage.cards.c.ClackbridgeTroll.class)); + cards.add(new SetCardInfo("Curious Pair", 296, Rarity.COMMON, mage.cards.c.CuriousPair.class)); + cards.add(new SetCardInfo("Dance of the Manse", 377, Rarity.RARE, mage.cards.d.DanceOfTheManse.class)); + cards.add(new SetCardInfo("Doom Foretold", 378, Rarity.RARE, mage.cards.d.DoomForetold.class)); + cards.add(new SetCardInfo("Embercleave", 359, Rarity.MYTHIC, mage.cards.e.Embercleave.class)); + cards.add(new SetCardInfo("Embereth Shieldbreaker", 292, Rarity.UNCOMMON, mage.cards.e.EmberethShieldbreaker.class)); + cards.add(new SetCardInfo("Emry, Lurker of the Loch", 342, Rarity.RARE, mage.cards.e.EmryLurkerOfTheLoch.class)); + cards.add(new SetCardInfo("Escape to the Wilds", 379, Rarity.RARE, mage.cards.e.EscapeToTheWilds.class)); + cards.add(new SetCardInfo("Fabled Passage", 391, Rarity.RARE, mage.cards.f.FabledPassage.class)); + cards.add(new SetCardInfo("Fae of Wishes", 282, Rarity.RARE, mage.cards.f.FaeOfWishes.class)); + cards.add(new SetCardInfo("Faeburrow Elder", 380, Rarity.RARE, mage.cards.f.FaeburrowElder.class)); + cards.add(new SetCardInfo("Faerie Guidemother", 274, Rarity.COMMON, mage.cards.f.FaerieGuidemother.class)); + cards.add(new SetCardInfo("Feasting Troll King", 368, Rarity.RARE, mage.cards.f.FeastingTrollKing.class)); + cards.add(new SetCardInfo("Fervent Champion", 360, Rarity.RARE, mage.cards.f.FerventChampion.class)); + cards.add(new SetCardInfo("Fires of Invention", 361, Rarity.RARE, mage.cards.f.FiresOfInvention.class)); + cards.add(new SetCardInfo("Flaxen Intruder", 297, Rarity.UNCOMMON, mage.cards.f.FlaxenIntruder.class)); + cards.add(new SetCardInfo("Folio of Fancies", 343, Rarity.RARE, mage.cards.f.FolioOfFancies.class)); + cards.add(new SetCardInfo("Foulmire Knight", 286, Rarity.UNCOMMON, mage.cards.f.FoulmireKnight.class)); + cards.add(new SetCardInfo("Gadwick, the Wizened", 344, Rarity.RARE, mage.cards.g.GadwickTheWizened.class)); + cards.add(new SetCardInfo("Garenbrig Carver", 298, Rarity.COMMON, mage.cards.g.GarenbrigCarver.class)); + cards.add(new SetCardInfo("Garruk, Cursed Huntsman", 270, Rarity.MYTHIC, mage.cards.g.GarrukCursedHuntsman.class)); + cards.add(new SetCardInfo("Giant Killer", 275, Rarity.RARE, mage.cards.g.GiantKiller.class)); + cards.add(new SetCardInfo("Gilded Goose", 369, Rarity.RARE, mage.cards.g.GildedGoose.class)); + cards.add(new SetCardInfo("Happily Ever After", 337, Rarity.RARE, mage.cards.h.HappilyEverAfter.class)); + cards.add(new SetCardInfo("Harmonious Archon", 338, Rarity.MYTHIC, mage.cards.h.HarmoniousArchon.class)); + cards.add(new SetCardInfo("Hushbringer", 339, Rarity.RARE, mage.cards.h.Hushbringer.class)); + cards.add(new SetCardInfo("Hypnotic Sprite", 283, Rarity.UNCOMMON, mage.cards.h.HypnoticSprite.class)); + cards.add(new SetCardInfo("Irencrag Feat", 362, Rarity.RARE, mage.cards.i.IrencragFeat.class)); + cards.add(new SetCardInfo("Irencrag Pyromancer", 363, Rarity.RARE, mage.cards.i.IrencragPyromancer.class)); + cards.add(new SetCardInfo("Linden, the Steadfast Queen", 340, Rarity.RARE, mage.cards.l.LindenTheSteadfastQueen.class)); + cards.add(new SetCardInfo("Lochmere Serpent", 381, Rarity.RARE, mage.cards.l.LochmereSerpent.class)); + cards.add(new SetCardInfo("Lonesome Unicorn", 276, Rarity.COMMON, mage.cards.l.LonesomeUnicorn.class)); + cards.add(new SetCardInfo("Lovestruck Beast", 299, Rarity.RARE, mage.cards.l.LovestruckBeast.class)); + cards.add(new SetCardInfo("Merchant of the Vale", 293, Rarity.COMMON, mage.cards.m.MerchantOfTheVale.class)); + cards.add(new SetCardInfo("Merfolk Secretkeeper", 284, Rarity.COMMON, mage.cards.m.MerfolkSecretkeeper.class)); + cards.add(new SetCardInfo("Midnight Clock", 346, Rarity.RARE, mage.cards.m.MidnightClock.class)); + cards.add(new SetCardInfo("Mirrormade", 347, Rarity.RARE, mage.cards.m.Mirrormade.class)); + cards.add(new SetCardInfo("Murderous Rider", 287, Rarity.RARE, mage.cards.m.MurderousRider.class)); + cards.add(new SetCardInfo("Oakhame Ranger", 302, Rarity.UNCOMMON, mage.cards.o.OakhameRanger.class)); + cards.add(new SetCardInfo("Oathsworn Knight", 354, Rarity.RARE, mage.cards.o.OathswornKnight.class)); + cards.add(new SetCardInfo("Oko, Thief of Crowns", 271, Rarity.MYTHIC, mage.cards.o.OkoThiefOfCrowns.class)); + cards.add(new SetCardInfo("Once Upon a Time", 371, Rarity.RARE, mage.cards.o.OnceUponATime.class)); + cards.add(new SetCardInfo("Opportunistic Dragon", 364, Rarity.RARE, mage.cards.o.OpportunisticDragon.class)); + cards.add(new SetCardInfo("Order of Midnight", 288, Rarity.UNCOMMON, mage.cards.o.OrderOfMidnight.class)); + cards.add(new SetCardInfo("Outlaws' Merriment", 382, Rarity.MYTHIC, mage.cards.o.OutlawsMerriment.class)); + cards.add(new SetCardInfo("Piper of the Swarm", 355, Rarity.RARE, mage.cards.p.PiperOfTheSwarm.class)); + cards.add(new SetCardInfo("Queen of Ice", 285, Rarity.COMMON, mage.cards.q.QueenOfIce.class)); + cards.add(new SetCardInfo("Questing Beast", 372, Rarity.MYTHIC, mage.cards.q.QuestingBeast.class)); + cards.add(new SetCardInfo("Rankle, Master of Pranks", 356, Rarity.MYTHIC, mage.cards.r.RankleMasterOfPranks.class)); + cards.add(new SetCardInfo("Realm-Cloaked Giant", 277, Rarity.MYTHIC, mage.cards.r.RealmCloakedGiant.class)); + cards.add(new SetCardInfo("Reaper of Night", 289, Rarity.COMMON, mage.cards.r.ReaperOfNight.class)); + cards.add(new SetCardInfo("Return of the Wildspeaker", 373, Rarity.RARE, mage.cards.r.ReturnOfTheWildspeaker.class)); + cards.add(new SetCardInfo("Rimrock Knight", 294, Rarity.COMMON, mage.cards.r.RimrockKnight.class)); + cards.add(new SetCardInfo("Robber of the Rich", 365, Rarity.MYTHIC, mage.cards.r.RobberOfTheRich.class)); + cards.add(new SetCardInfo("Rosethorn Acolyte", 300, Rarity.COMMON, mage.cards.r.RosethornAcolyte.class)); + cards.add(new SetCardInfo("Shepherd of the Flock", 278, Rarity.UNCOMMON, mage.cards.s.ShepherdOfTheFlock.class)); + cards.add(new SetCardInfo("Silverflame Squire", 279, Rarity.COMMON, mage.cards.s.SilverflameSquire.class)); + cards.add(new SetCardInfo("Smitten Swordmaster", 290, Rarity.COMMON, mage.cards.s.SmittenSwordmaster.class)); + cards.add(new SetCardInfo("Sorcerous Spyglass", 384, Rarity.RARE, mage.cards.s.SorcerousSpyglass.class)); + cards.add(new SetCardInfo("Stolen by the Fae", 348, Rarity.RARE, mage.cards.s.StolenByTheFae.class)); + cards.add(new SetCardInfo("Stonecoil Serpent", 385, Rarity.RARE, mage.cards.s.StonecoilSerpent.class)); + cards.add(new SetCardInfo("Stormfist Crusader", 383, Rarity.RARE, mage.cards.s.StormfistCrusader.class)); + cards.add(new SetCardInfo("Sundering Stroke", 366, Rarity.RARE, mage.cards.s.SunderingStroke.class)); + cards.add(new SetCardInfo("The Cauldron of Eternity", 352, Rarity.MYTHIC, mage.cards.t.TheCauldronOfEternity.class)); + cards.add(new SetCardInfo("The Circle of Loyalty", 336, Rarity.MYTHIC, mage.cards.t.TheCircleOfLoyalty.class)); + cards.add(new SetCardInfo("The Great Henge", 370, Rarity.MYTHIC, mage.cards.t.TheGreatHenge.class)); + cards.add(new SetCardInfo("The Magic Mirror", 345, Rarity.MYTHIC, mage.cards.t.TheMagicMirror.class)); + cards.add(new SetCardInfo("The Royal Scions", 272, Rarity.MYTHIC, mage.cards.t.TheRoyalScions.class)); + cards.add(new SetCardInfo("Torbran, Thane of Red Fell", 367, Rarity.RARE, mage.cards.t.TorbranThaneOfRedFell.class)); + cards.add(new SetCardInfo("Tuinvale Treefolk", 301, Rarity.COMMON, mage.cards.t.TuinvaleTreefolk.class)); + cards.add(new SetCardInfo("Vantress Gargoyle", 349, Rarity.RARE, mage.cards.v.VantressGargoyle.class)); + cards.add(new SetCardInfo("Wicked Wolf", 374, Rarity.RARE, mage.cards.w.WickedWolf.class)); + cards.add(new SetCardInfo("Wildborn Preserver", 375, Rarity.RARE, mage.cards.w.WildbornPreserver.class)); + cards.add(new SetCardInfo("Wishclaw Talisman", 357, Rarity.RARE, mage.cards.w.WishclawTalisman.class)); + cards.add(new SetCardInfo("Witch's Vengeance", 358, Rarity.RARE, mage.cards.w.WitchsVengeance.class)); + cards.add(new SetCardInfo("Worthy Knight", 341, Rarity.RARE, mage.cards.w.WorthyKnight.class)); + cards.add(new SetCardInfo("Yorvo, Lord of Garenbrig", 376, Rarity.RARE, mage.cards.y.YorvoLordOfGarenbrig.class)); + + // This is here to prevent the incomplete adventure implementation from causing problems and will be removed + cards.removeIf(setCardInfo -> AdventureCard.class.isAssignableFrom(setCardInfo.getCardClass())); + } +} diff --git a/Mage.Sets/src/mage/sets/TimeSpiral.java b/Mage.Sets/src/mage/sets/TimeSpiral.java index a730e26950..1e80b06faa 100644 --- a/Mage.Sets/src/mage/sets/TimeSpiral.java +++ b/Mage.Sets/src/mage/sets/TimeSpiral.java @@ -1,6 +1,5 @@ package mage.sets; -import java.util.List; import mage.cards.Card; import mage.cards.ExpansionSet; import mage.cards.repository.CardCriteria; @@ -8,6 +7,8 @@ import mage.cards.repository.CardRepository; import mage.constants.Rarity; import mage.constants.SetType; +import java.util.List; + public final class TimeSpiral extends ExpansionSet { private static final TimeSpiral instance = new TimeSpiral(); @@ -233,7 +234,7 @@ public final class TimeSpiral extends ExpansionSet { cards.add(new SetCardInfo("Sage of Epityr", 74, Rarity.COMMON, mage.cards.s.SageOfEpityr.class)); cards.add(new SetCardInfo("Saltcrusted Steppe", 277, Rarity.UNCOMMON, mage.cards.s.SaltcrustedSteppe.class)); cards.add(new SetCardInfo("Sangrophage", 127, Rarity.COMMON, mage.cards.s.Sangrophage.class)); - cards.add(new SetCardInfo("Sarpadian Empires, Vol. VII", 263, Rarity.RARE, mage.cards.s.SarpadianEmpiresVolVii.class)); + cards.add(new SetCardInfo("Sarpadian Empires, Vol. VII", 263, Rarity.RARE, mage.cards.s.SarpadianEmpiresVolVII.class)); cards.add(new SetCardInfo("Savage Thallid", 213, Rarity.COMMON, mage.cards.s.SavageThallid.class)); cards.add(new SetCardInfo("Scarwood Treefolk", 214, Rarity.COMMON, mage.cards.s.ScarwoodTreefolk.class)); cards.add(new SetCardInfo("Scion of the Ur-Dragon", 246, Rarity.RARE, mage.cards.s.ScionOfTheUrDragon.class)); diff --git a/Mage.Sets/src/mage/sets/Torment.java b/Mage.Sets/src/mage/sets/Torment.java index 71f87ed2f8..2680b1ba0c 100644 --- a/Mage.Sets/src/mage/sets/Torment.java +++ b/Mage.Sets/src/mage/sets/Torment.java @@ -147,6 +147,7 @@ public final class Torment extends ExpansionSet { cards.add(new SetCardInfo("Slithery Stalker", 84, Rarity.UNCOMMON, mage.cards.s.SlitheryStalker.class)); cards.add(new SetCardInfo("Sonic Seizure", 115, Rarity.COMMON, mage.cards.s.SonicSeizure.class)); cards.add(new SetCardInfo("Soul Scourge", 85, Rarity.COMMON, mage.cards.s.SoulScourge.class)); + cards.add(new SetCardInfo("Spirit Flare", 15, Rarity.COMMON, mage.cards.s.SpiritFlare.class)); cards.add(new SetCardInfo("Stern Judge", 16, Rarity.UNCOMMON, mage.cards.s.SternJudge.class)); cards.add(new SetCardInfo("Strength of Isolation", 17, Rarity.UNCOMMON, mage.cards.s.StrengthOfIsolation.class)); cards.add(new SetCardInfo("Strength of Lunacy", 86, Rarity.UNCOMMON, mage.cards.s.StrengthOfLunacy.class)); diff --git a/Mage.Sets/src/mage/sets/Visions.java b/Mage.Sets/src/mage/sets/Visions.java index 63ca9aeb98..31852388b5 100644 --- a/Mage.Sets/src/mage/sets/Visions.java +++ b/Mage.Sets/src/mage/sets/Visions.java @@ -86,6 +86,7 @@ public final class Visions extends ExpansionSet { 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)); cards.add(new SetCardInfo("Infantry Veteran", 9, Rarity.COMMON, mage.cards.i.InfantryVeteran.class)); + cards.add(new SetCardInfo("Infernal Harvest", 62, Rarity.COMMON, mage.cards.i.InfernalHarvest.class)); cards.add(new SetCardInfo("Inspiration", 35, Rarity.COMMON, mage.cards.i.Inspiration.class)); cards.add(new SetCardInfo("Iron-Heart Chimera", 146, Rarity.UNCOMMON, mage.cards.i.IronHeartChimera.class)); cards.add(new SetCardInfo("Jamuraan Lion", 10, Rarity.COMMON, mage.cards.j.JamuraanLion.class)); diff --git a/Mage.Sets/src/mage/sets/Weatherlight.java b/Mage.Sets/src/mage/sets/Weatherlight.java index b8be7cb40e..f93876f43d 100644 --- a/Mage.Sets/src/mage/sets/Weatherlight.java +++ b/Mage.Sets/src/mage/sets/Weatherlight.java @@ -38,6 +38,7 @@ public final class Weatherlight extends ExpansionSet { cards.add(new SetCardInfo("Alms", 3, Rarity.COMMON, mage.cards.a.Alms.class)); cards.add(new SetCardInfo("Ancestral Knowledge", 32, Rarity.RARE, mage.cards.a.AncestralKnowledge.class)); cards.add(new SetCardInfo("Angelic Renewal", 4, Rarity.COMMON, mage.cards.a.AngelicRenewal.class)); + cards.add(new SetCardInfo("Apathy", 33, Rarity.COMMON, mage.cards.a.Apathy.class)); cards.add(new SetCardInfo("Arctic Wolves", 118, Rarity.UNCOMMON, mage.cards.a.ArcticWolves.class)); cards.add(new SetCardInfo("Ardent Militia", 5, Rarity.COMMON, mage.cards.a.ArdentMilitia.class)); cards.add(new SetCardInfo("Argivian Find", 6, Rarity.UNCOMMON, mage.cards.a.ArgivianFind.class)); diff --git a/Mage.Tests/pom.xml b/Mage.Tests/pom.xml index eab8881662..e64596f21c 100644 --- a/Mage.Tests/pom.xml +++ b/Mage.Tests/pom.xml @@ -6,7 +6,7 @@ org.mage mage-root - 1.4.37 + 1.4.39 mage-tests diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/ArchfiendOfSpiteTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/ArchfiendOfSpiteTest.java new file mode 100644 index 0000000000..4037097d6b --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/ArchfiendOfSpiteTest.java @@ -0,0 +1,31 @@ +package org.mage.test.cards.single; + +import mage.constants.PhaseStep; +import mage.constants.Zone; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +public class ArchfiendOfSpiteTest extends CardTestPlayerBase { + + @Test + public void damageTriggerTest() { + addCard(Zone.BATTLEFIELD, playerA, "Archfiend of Spite"); + addCard(Zone.BATTLEFIELD, playerB, "Mountain", 1); + addCard(Zone.HAND, playerB, "Lightning Bolt", 1); + setStopAt(1, PhaseStep.UNTAP); + execute(); + + assertPermanentCount(playerA, "Archfiend of Spite", 1); + assertLife(playerB, 20); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerB, "Lightning Bolt", "Archfiend of Spite"); + setStopAt(1, PhaseStep.POSTCOMBAT_MAIN); + setStrictChooseMode(true); + execute(); + + assertPermanentCount(playerA, "Archfiend of Spite", 1); + assertPermanentCount(playerB, "Mountain", 1); + assertDamageReceived(playerA, "Archfiend of Spite", 3); + assertLife(playerB, 17); + } +} diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/SyrKonradTheGrimTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/SyrKonradTheGrimTest.java new file mode 100644 index 0000000000..f24543cf40 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/SyrKonradTheGrimTest.java @@ -0,0 +1,33 @@ +package org.mage.test.cards.single; + +import mage.constants.PhaseStep; +import mage.constants.Zone; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +public class SyrKonradTheGrimTest extends CardTestPlayerBase { + + @Test + public void leavesOwnGraveyardTriggerTest() { + addCard(Zone.HAND, playerA, "Rest in Peace"); + addCard(Zone.BATTLEFIELD, playerA, "Plains", 2); + addCard(Zone.BATTLEFIELD, playerA, "Syr Konrad, the Grim"); + // These leaving the graveyard *should* cause loss of life + addCard(Zone.GRAVEYARD, playerA, "Grizzly Bears", 2); + // These ones *shouldn't* + addCard(Zone.GRAVEYARD, playerB, "Grizzly Bears"); + setStopAt(1, PhaseStep.UNTAP); + execute(); + + assertLife(playerB, 20); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Rest in Peace"); + setStopAt(1, PhaseStep.POSTCOMBAT_MAIN); + execute(); + + assertGraveyardCount(playerA, 0); + assertGraveyardCount(playerB, 0); + assertLife(playerA, 20); + assertLife(playerB, 18); + } +} diff --git a/Mage.Verify/pom.xml b/Mage.Verify/pom.xml index a4fb3c8fcd..e19bf29e08 100644 --- a/Mage.Verify/pom.xml +++ b/Mage.Verify/pom.xml @@ -6,7 +6,7 @@ org.mage mage-root - 1.4.37 + 1.4.39 mage-verify @@ -49,7 +49,7 @@ org.mage mage-client - 1.4.37 + 1.4.39 diff --git a/Mage.Verify/src/test/java/mage/verify/VerifyCardDataTest.java b/Mage.Verify/src/test/java/mage/verify/VerifyCardDataTest.java index d6ba12acdf..d5ec909522 100644 --- a/Mage.Verify/src/test/java/mage/verify/VerifyCardDataTest.java +++ b/Mage.Verify/src/test/java/mage/verify/VerifyCardDataTest.java @@ -48,6 +48,7 @@ public class VerifyCardDataTest { private static final boolean CHECK_SOURCE_TOKENS = false; private static final HashMap> skipCheckLists = new HashMap<>(); + private static final Set subtypesToIgnore = new HashSet<>(); private static void skipListCreate(String listName) { skipCheckLists.put(listName, new LinkedHashSet<>()); @@ -668,8 +669,20 @@ public class VerifyCardDataTest { } } - if (!eqSet(card.getSubtype(null).stream().map(SubType::toString).collect(Collectors.toSet()), expected)) { - fail(card, "subtypes", card.getSubtype(null) + " != " + expected); + // Remove subtypes that need to be ignored + Collection actual = card + .getSubtype(null) + .stream() + .map(SubType::toString) + .collect(Collectors.toSet()); + actual.removeIf(subtypesToIgnore::contains); + + if (expected != null) { + expected.removeIf(subtypesToIgnore::contains); + } + + if (!eqSet(actual, expected)) { + fail(card, "subtypes", actual + " != " + expected); } } diff --git a/Mage/pom.xml b/Mage/pom.xml index d23f0dc18d..32afbc41b0 100644 --- a/Mage/pom.xml +++ b/Mage/pom.xml @@ -6,7 +6,7 @@ org.mage mage-root - 1.4.37 + 1.4.39 mage diff --git a/Mage/src/main/java/mage/abilities/Modes.java b/Mage/src/main/java/mage/abilities/Modes.java index d74e678baf..77b8bb3afe 100644 --- a/Mage/src/main/java/mage/abilities/Modes.java +++ b/Mage/src/main/java/mage/abilities/Modes.java @@ -9,6 +9,7 @@ import mage.filter.FilterPlayer; import mage.game.Game; import mage.players.Player; import mage.target.common.TargetOpponent; +import mage.util.RandomUtil; import java.util.*; @@ -27,6 +28,8 @@ public class Modes extends LinkedHashMap { private final Map duplicateModes = new LinkedHashMap<>(); private OptionalAdditionalModeSourceCosts optionalAdditionalModeSourceCosts = null; // only set if costs have to be paid private Filter maxModesFilter = null; // calculates the max number of available modes + private boolean isRandom = false; + private String chooseText = null; public Modes() { this.currentMode = new Mode(); @@ -56,6 +59,8 @@ public class Modes extends LinkedHashMap { this.optionalAdditionalModeSourceCosts = modes.optionalAdditionalModeSourceCosts; this.maxModesFilter = modes.maxModesFilter; // can't change so no copy needed + this.isRandom = modes.isRandom; + this.chooseText = modes.chooseText; if (modes.getSelectedModes().isEmpty()) { this.currentMode = values().iterator().next(); } else { @@ -163,6 +168,11 @@ public class Modes extends LinkedHashMap { if (this.size() > 1) { this.selectedModes.clear(); this.duplicateModes.clear(); + if (this.isRandom) { + List modes = getAvailableModes(source, game); + this.addSelectedMode(modes.get(RandomUtil.nextInt(modes.size())).getId()); + return true; + } // check if mode modifying abilities exist Card card = game.getCard(source.getSourceId()); if (card != null) { @@ -332,7 +342,9 @@ public class Modes extends LinkedHashMap { return this.getMode().getEffects().getText(this.getMode()); } StringBuilder sb = new StringBuilder(); - if (this.getMaxModesFilter() != null) { + if (this.chooseText != null) { + sb.append(chooseText); + } else if (this.getMaxModesFilter() != null) { sb.append("choose one or more. Each mode must target ").append(getMaxModesFilter().getMessage()); } else if (this.getMinModes() == 0 && this.getMaxModes() == 1) { sb.append("choose up to one"); @@ -357,11 +369,13 @@ public class Modes extends LinkedHashMap { } if (isEachModeMoreThanOnce()) { - sb.append(". You may choose the same mode more than once.
"); - } else { - sb.append(" —
"); + sb.append(". You may choose the same mode more than once."); + } else if (chooseText == null) { + sb.append(" —"); } + sb.append("
"); + for (Mode mode : this.values()) { sb.append("&bull "); sb.append(mode.getEffects().getTextStartingUpperCase(mode)); @@ -401,4 +415,11 @@ public class Modes extends LinkedHashMap { this.optionalAdditionalModeSourceCosts = optionalAdditionalModeSourceCosts; } + public void setRandom(boolean isRandom) { + this.isRandom = isRandom; + } + + public void setChooseText(String chooseText) { + this.chooseText = chooseText; + } } diff --git a/Mage/src/main/java/mage/abilities/common/BecomesTargetTriggeredAbility.java b/Mage/src/main/java/mage/abilities/common/BecomesTargetTriggeredAbility.java index 54263a11bc..1833985830 100644 --- a/Mage/src/main/java/mage/abilities/common/BecomesTargetTriggeredAbility.java +++ b/Mage/src/main/java/mage/abilities/common/BecomesTargetTriggeredAbility.java @@ -1,35 +1,42 @@ - package mage.abilities.common; import mage.abilities.TriggeredAbilityImpl; import mage.abilities.effects.Effect; +import mage.constants.SetTargetPointer; import mage.constants.Zone; import mage.filter.FilterStackObject; import mage.filter.StaticFilters; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.stack.StackObject; +import mage.target.targetpointer.FixedTarget; /** - * * @author North */ public class BecomesTargetTriggeredAbility extends TriggeredAbilityImpl { private final FilterStackObject filter; + private final SetTargetPointer setTargetPointer; public BecomesTargetTriggeredAbility(Effect effect) { this(effect, StaticFilters.FILTER_SPELL_OR_ABILITY); } public BecomesTargetTriggeredAbility(Effect effect, FilterStackObject filter) { + this(effect, filter, SetTargetPointer.NONE); + } + + public BecomesTargetTriggeredAbility(Effect effect, FilterStackObject filter, SetTargetPointer setTargetPointer) { super(Zone.BATTLEFIELD, effect); this.filter = filter.copy(); + this.setTargetPointer = setTargetPointer; } public BecomesTargetTriggeredAbility(final BecomesTargetTriggeredAbility ability) { super(ability); this.filter = ability.filter.copy(); + this.setTargetPointer = ability.setTargetPointer; } @Override @@ -45,7 +52,25 @@ public class BecomesTargetTriggeredAbility extends TriggeredAbilityImpl { @Override public boolean checkTrigger(GameEvent event, Game game) { StackObject sourceObject = game.getStack().getStackObject(event.getSourceId()); - return event.getTargetId().equals(getSourceId()) && filter.match(sourceObject, getSourceId(), getControllerId(), game); + if (!event.getTargetId().equals(getSourceId()) + || !filter.match(sourceObject, getSourceId(), getControllerId(), game)) { + return false; + } + switch (setTargetPointer) { + case PLAYER: + this.getEffects().stream() + .forEach(effect -> effect.setTargetPointer( + new FixedTarget(sourceObject.getControllerId(), game) + )); + break; + case SPELL: + this.getEffects().stream() + .forEach(effect -> effect.setTargetPointer( + new FixedTarget(sourceObject.getId(), game) + )); + break; + } + return true; } @Override diff --git a/Mage/src/main/java/mage/abilities/common/BeginningOfUpkeepTriggeredAbility.java b/Mage/src/main/java/mage/abilities/common/BeginningOfUpkeepTriggeredAbility.java index 87ed534a99..7969e308b5 100644 --- a/Mage/src/main/java/mage/abilities/common/BeginningOfUpkeepTriggeredAbility.java +++ b/Mage/src/main/java/mage/abilities/common/BeginningOfUpkeepTriggeredAbility.java @@ -1,7 +1,6 @@ package mage.abilities.common; -import java.util.Locale; import mage.abilities.TriggeredAbilityImpl; import mage.abilities.effects.Effect; import mage.constants.TargetController; @@ -11,8 +10,9 @@ import mage.game.events.GameEvent; import mage.game.permanent.Permanent; import mage.target.targetpointer.FixedTarget; +import java.util.Locale; + /** - * * @author Loki */ public class BeginningOfUpkeepTriggeredAbility extends TriggeredAbilityImpl { @@ -91,6 +91,7 @@ public class BeginningOfUpkeepTriggeredAbility extends TriggeredAbilityImpl { } break; case ANY: + case ACTIVE: if (setTargetPointer && getTargets().isEmpty()) { for (Effect effect : this.getEffects()) { effect.setTargetPointer(new FixedTarget(event.getPlayerId())); @@ -137,6 +138,8 @@ public class BeginningOfUpkeepTriggeredAbility extends TriggeredAbilityImpl { return sb.insert(0, generateZoneString()).insert(0, "At the beginning of each opponent's upkeep, ").toString(); case ANY: return sb.insert(0, generateZoneString()).insert(0, "At the beginning of each upkeep, ").toString(); + case ACTIVE: + return sb.insert(0, generateZoneString()).insert(0, "At the beginning of each player's upkeep, ").toString(); case CONTROLLER_ATTACHED_TO: return sb.insert(0, generateZoneString()).insert(0, "At the beginning of the upkeep of enchanted creature's controller, ").toString(); } diff --git a/Mage/src/main/java/mage/abilities/common/DrawSecondCardTriggeredAbility.java b/Mage/src/main/java/mage/abilities/common/DrawSecondCardTriggeredAbility.java new file mode 100644 index 0000000000..becd3c41d1 --- /dev/null +++ b/Mage/src/main/java/mage/abilities/common/DrawSecondCardTriggeredAbility.java @@ -0,0 +1,67 @@ +package mage.abilities.common; + +import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.effects.Effect; +import mage.constants.Zone; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.watchers.common.CardsAmountDrawnThisTurnWatcher; + +/** + * @author TheElk801 + */ +public class DrawSecondCardTriggeredAbility extends TriggeredAbilityImpl { + + private boolean triggeredOnce = false; + + public DrawSecondCardTriggeredAbility(Effect effect, boolean optional) { + super(Zone.ALL, effect, optional); + this.addWatcher(new CardsAmountDrawnThisTurnWatcher()); + } + + private DrawSecondCardTriggeredAbility(final DrawSecondCardTriggeredAbility ability) { + super(ability); + this.triggeredOnce = ability.triggeredOnce; + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.DREW_CARD + || event.getType() == GameEvent.EventType.END_PHASE_POST; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + if (event.getType() == GameEvent.EventType.END_PHASE_POST) { + triggeredOnce = false; + return false; + } + if (event.getType() != GameEvent.EventType.DREW_CARD + || !event.getPlayerId().equals(controllerId) + || game.getPermanent(sourceId) == null) { + return false; + } + if (triggeredOnce) { + return false; + } + CardsAmountDrawnThisTurnWatcher watcher = game.getState().getWatcher(CardsAmountDrawnThisTurnWatcher.class); + if (watcher == null) { + return false; + } + if (watcher.getAmountCardsDrawn(controllerId) > 1) { + triggeredOnce = true; + return true; + } + return false; + } + + @Override + public String getRule() { + return "Whenever you draw your second card each turn, " + super.getRule(); + } + + @Override + public DrawSecondCardTriggeredAbility copy() { + return new DrawSecondCardTriggeredAbility(this); + } +} diff --git a/Mage/src/main/java/mage/abilities/common/EntersBattlefieldUntappedTriggeredAbility.java b/Mage/src/main/java/mage/abilities/common/EntersBattlefieldUntappedTriggeredAbility.java new file mode 100644 index 0000000000..8aa7c5aa6d --- /dev/null +++ b/Mage/src/main/java/mage/abilities/common/EntersBattlefieldUntappedTriggeredAbility.java @@ -0,0 +1,40 @@ +package mage.abilities.common; + +import mage.abilities.effects.Effect; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; + +/** + * @author TheElk801 + */ +public class EntersBattlefieldUntappedTriggeredAbility extends EntersBattlefieldTriggeredAbility { + + public EntersBattlefieldUntappedTriggeredAbility(Effect effect, boolean optional) { + super(effect, optional); + this.noRule = true; + } + + private EntersBattlefieldUntappedTriggeredAbility(final EntersBattlefieldUntappedTriggeredAbility ability) { + super(ability); + } + + @Override + public EntersBattlefieldUntappedTriggeredAbility copy() { + return new EntersBattlefieldUntappedTriggeredAbility(this); + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + if (!super.checkTrigger(event, game)) { + return false; + } + Permanent permanent = game.getPermanent(event.getTargetId()); + return permanent != null && !permanent.isTapped(); + } + + @Override + public String getRule() { + return "When {this} enters the battlefield untapped, " + super.getRule(); + } +} \ No newline at end of file diff --git a/Mage/src/main/java/mage/abilities/condition/common/AdamantCondition.java b/Mage/src/main/java/mage/abilities/condition/common/AdamantCondition.java index 63b511921e..4e45cdf04f 100644 --- a/Mage/src/main/java/mage/abilities/condition/common/AdamantCondition.java +++ b/Mage/src/main/java/mage/abilities/condition/common/AdamantCondition.java @@ -8,19 +8,20 @@ import mage.constants.ColoredManaSymbol; import mage.game.Game; import mage.watchers.common.ManaSpentToCastWatcher; +import java.util.Arrays; + /** * @author TheElk801 */ - - public enum AdamantCondition implements Condition { WHITE(ColoredManaSymbol.W), BLUE(ColoredManaSymbol.U), BLACK(ColoredManaSymbol.B), RED(ColoredManaSymbol.R), - GREEN(ColoredManaSymbol.G); + GREEN(ColoredManaSymbol.G), + ANY(null); - protected ColoredManaSymbol coloredManaSymbol; + private final ColoredManaSymbol coloredManaSymbol; private AdamantCondition(ColoredManaSymbol coloredManaSymbol) { this.coloredManaSymbol = coloredManaSymbol; @@ -29,7 +30,13 @@ public enum AdamantCondition implements Condition { @Override public boolean apply(Game game, Ability source) { if (source.getAbilityType() == AbilityType.SPELL) { - return (source.getManaCostsToPay().getPayment().getColor(coloredManaSymbol) > 0); + if (coloredManaSymbol == null) { + return Arrays + .stream(ColoredManaSymbol.values()) + .map(source.getManaCostsToPay().getPayment()::getColor) + .anyMatch(i -> i > 2); + } + return source.getManaCostsToPay().getPayment().getColor(coloredManaSymbol) > 2; } ManaSpentToCastWatcher watcher = game.getState().getWatcher(ManaSpentToCastWatcher.class, source.getSourceId()); if (watcher == null) { @@ -39,6 +46,12 @@ public enum AdamantCondition implements Condition { if (payment == null) { return false; } + if (coloredManaSymbol == null) { + return Arrays + .stream(ColoredManaSymbol.values()) + .map(payment::getColor) + .anyMatch(i -> i > 2); + } return payment.getColor(coloredManaSymbol) > 2; } } diff --git a/Mage/src/main/java/mage/abilities/dynamicvalue/common/CardsInControllerGraveyardCount.java b/Mage/src/main/java/mage/abilities/dynamicvalue/common/CardsInControllerGraveyardCount.java index c69bea308f..3242e4d845 100644 --- a/Mage/src/main/java/mage/abilities/dynamicvalue/common/CardsInControllerGraveyardCount.java +++ b/Mage/src/main/java/mage/abilities/dynamicvalue/common/CardsInControllerGraveyardCount.java @@ -4,6 +4,7 @@ import mage.abilities.Ability; import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.effects.Effect; import mage.filter.FilterCard; +import mage.filter.StaticFilters; import mage.game.Game; import mage.players.Player; @@ -17,7 +18,7 @@ public class CardsInControllerGraveyardCount implements DynamicValue { private Integer amount; public CardsInControllerGraveyardCount() { - this(new FilterCard(), 1); + this(StaticFilters.FILTER_CARD, 1); } public CardsInControllerGraveyardCount(FilterCard filter) { diff --git a/Mage/src/main/java/mage/abilities/effects/ContinuousEffect.java b/Mage/src/main/java/mage/abilities/effects/ContinuousEffect.java index 66f262c750..3666e45af7 100644 --- a/Mage/src/main/java/mage/abilities/effects/ContinuousEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/ContinuousEffect.java @@ -7,6 +7,7 @@ import mage.constants.Duration; import mage.constants.Layer; import mage.constants.SubLayer; import mage.game.Game; +import mage.target.targetpointer.TargetPointer; import java.util.EnumSet; import java.util.List; @@ -77,4 +78,7 @@ public interface ContinuousEffect extends Effect { boolean isTemporary(); void setTemporary(boolean temporary); + + @Override + ContinuousEffect setTargetPointer(TargetPointer targetPointer); } diff --git a/Mage/src/main/java/mage/abilities/effects/ContinuousEffectImpl.java b/Mage/src/main/java/mage/abilities/effects/ContinuousEffectImpl.java index 7cc9ed6c86..e414bfb3c1 100644 --- a/Mage/src/main/java/mage/abilities/effects/ContinuousEffectImpl.java +++ b/Mage/src/main/java/mage/abilities/effects/ContinuousEffectImpl.java @@ -10,6 +10,7 @@ import mage.abilities.dynamicvalue.common.StaticValue; import mage.constants.*; import mage.game.Game; import mage.players.Player; +import mage.target.targetpointer.TargetPointer; import java.util.*; @@ -334,4 +335,10 @@ public abstract class ContinuousEffectImpl extends EffectImpl implements Continu dependendToTypes.add(dependencyType); } + @Override + public ContinuousEffect setTargetPointer(TargetPointer targetPointer) { + super.setTargetPointer(targetPointer); + return this; + } + } diff --git a/Mage/src/main/java/mage/abilities/effects/PreventDamageAndRemoveCountersEffect.java b/Mage/src/main/java/mage/abilities/effects/PreventDamageAndRemoveCountersEffect.java index 81c1e19e28..813f1ad790 100644 --- a/Mage/src/main/java/mage/abilities/effects/PreventDamageAndRemoveCountersEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/PreventDamageAndRemoveCountersEffect.java @@ -13,18 +13,21 @@ import mage.game.events.GameEvent; import mage.game.permanent.Permanent; /** - * * @author antoni-g */ public class PreventDamageAndRemoveCountersEffect extends PreventionEffectImpl { + private final boolean thatMany; - public PreventDamageAndRemoveCountersEffect() { + public PreventDamageAndRemoveCountersEffect(boolean thatMany) { super(Duration.WhileOnBattlefield, Integer.MAX_VALUE, false, false); - staticText = "If damage would be dealt to {this}, prevent that damage and remove that many +1/+1 counters from it"; + this.thatMany = thatMany; + staticText = "If damage would be dealt to {this} while it has a +1/+1 counter on it, " + + "prevent that damage and remove " + (thatMany ? "that many +1/+1 counters" : "a +1/+1 counter") + " from it"; } - public PreventDamageAndRemoveCountersEffect(final PreventDamageAndRemoveCountersEffect effect) { + private PreventDamageAndRemoveCountersEffect(final PreventDamageAndRemoveCountersEffect effect) { super(effect); + this.thatMany = effect.thatMany; } @Override @@ -42,19 +45,22 @@ public class PreventDamageAndRemoveCountersEffect extends PreventionEffectImpl { int damage = event.getAmount(); preventDamageAction(event, source, game); Permanent permanent = game.getPermanent(source.getSourceId()); - if (permanent != null) { - permanent.removeCounters(CounterType.P1P1.createInstance(damage), game); //MTG ruling (this) loses counters even if the damage isn't prevented + if (permanent == null) { + return false; } + if (!thatMany) { + damage = 1; + } + permanent.removeCounters(CounterType.P1P1.createInstance(damage), game); //MTG ruling (this) loses counters even if the damage isn't prevented return false; } @Override public boolean applies(GameEvent event, Ability source, Game game) { - if (super.applies(event, source, game)) { - if (event.getTargetId().equals(source.getSourceId())) { - return true; - } - } - return false; + Permanent permanent = game.getPermanent(event.getTargetId()); + return super.applies(event, source, game) + && permanent != null + && event.getTargetId().equals(source.getSourceId()) + && permanent.getCounters(game).containsKey(CounterType.P1P1); } } diff --git a/Mage/src/main/java/mage/abilities/effects/common/PreventCombatDamageBySourceEffect.java b/Mage/src/main/java/mage/abilities/effects/common/PreventCombatDamageBySourceEffect.java index 5c9c3fbb91..6f7abdc467 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/PreventCombatDamageBySourceEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/PreventCombatDamageBySourceEffect.java @@ -1,5 +1,3 @@ - - package mage.abilities.effects.common; import mage.abilities.Ability; @@ -9,33 +7,27 @@ import mage.game.Game; import mage.game.events.GameEvent; /** - * * @author jeffwadsworth */ public class PreventCombatDamageBySourceEffect extends PreventionEffectImpl { public PreventCombatDamageBySourceEffect(Duration duration) { - super(duration, Integer.MAX_VALUE, true); - staticText = "Prevent all combat damage that would be dealt by {this}" + duration.toString(); + super(duration, Integer.MAX_VALUE, true); + staticText = "Prevent all combat damage that would be dealt by {this}" + duration.toString(); } public PreventCombatDamageBySourceEffect(final PreventCombatDamageBySourceEffect effect) { - super(effect); + super(effect); } @Override public PreventCombatDamageBySourceEffect copy() { - return new PreventCombatDamageBySourceEffect(this); + return new PreventCombatDamageBySourceEffect(this); } @Override public boolean applies(GameEvent event, Ability source, Game game) { - if (super.applies(event, source, game)) { - if (event.getSourceId().equals(source.getSourceId())) { - return true; - } - } - return false; + return super.applies(event, source, game) + && event.getSourceId().equals(source.getSourceId()); } - -} \ No newline at end of file +} diff --git a/Mage/src/main/java/mage/abilities/effects/common/continuous/CastFromHandWithoutPayingManaCostEffect.java b/Mage/src/main/java/mage/abilities/effects/common/continuous/CastFromHandWithoutPayingManaCostEffect.java index dcd3f9695e..a330989828 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/continuous/CastFromHandWithoutPayingManaCostEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/continuous/CastFromHandWithoutPayingManaCostEffect.java @@ -10,7 +10,8 @@ import mage.abilities.effects.ContinuousEffectImpl; import mage.cards.Card; import mage.cards.SplitCardHalf; import mage.constants.*; -import mage.filter.common.FilterNonlandCard; +import mage.filter.FilterCard; +import mage.filter.StaticFilters; import mage.game.Game; import mage.game.stack.Spell; import mage.players.Player; @@ -19,13 +20,26 @@ import java.util.UUID; public class CastFromHandWithoutPayingManaCostEffect extends ContinuousEffectImpl { + private final FilterCard filter; + private final boolean fromHand; + public CastFromHandWithoutPayingManaCostEffect() { - super(Duration.WhileOnBattlefield, Outcome.Detriment); - staticText = "You may cast nonland cards from your hand without paying their mana costs"; + this(StaticFilters.FILTER_CARDS_NON_LAND, true); } - public CastFromHandWithoutPayingManaCostEffect(final CastFromHandWithoutPayingManaCostEffect effect) { + public CastFromHandWithoutPayingManaCostEffect(FilterCard filter, boolean fromHand) { + super(Duration.WhileOnBattlefield, Outcome.Detriment); + this.filter = filter; + this.fromHand = fromHand; + staticText = "You may cast " + filter.getMessage() + + (fromHand ? " from your hand" : "") + + " without paying their mana costs"; + } + + private CastFromHandWithoutPayingManaCostEffect(final CastFromHandWithoutPayingManaCostEffect effect) { super(effect); + this.filter = effect.filter; + this.fromHand = effect.fromHand; } @Override @@ -36,12 +50,19 @@ public class CastFromHandWithoutPayingManaCostEffect extends ContinuousEffectImp @Override public boolean apply(Layer layer, SubLayer sublayer, Ability source, Game game) { Player controller = game.getPlayer(source.getControllerId()); - if (controller != null) { - controller.getAlternativeSourceCosts().add(new AlternativeCostSourceAbility( - null, new CompoundCondition(SourceIsSpellCondition.instance, new IsBeingCastFromHandCondition()), null, new FilterNonlandCard(), true)); - return true; + if (controller == null) { + return false; } - return false; + Condition condition; + if (fromHand) { + condition = new CompoundCondition(SourceIsSpellCondition.instance, IsBeingCastFromHandCondition.instance); + } else { + condition = SourceIsSpellCondition.instance; + } + controller.getAlternativeSourceCosts().add(new AlternativeCostSourceAbility( + null, condition, null, filter, true + )); + return true; } @Override @@ -55,7 +76,8 @@ public class CastFromHandWithoutPayingManaCostEffect extends ContinuousEffectImp } } -class IsBeingCastFromHandCondition implements Condition { +enum IsBeingCastFromHandCondition implements Condition { + instance; @Override public boolean apply(Game game, Ability source) { diff --git a/Mage/src/main/java/mage/abilities/effects/common/cost/SourceCostReductionForEachCardInGraveyardEffect.java b/Mage/src/main/java/mage/abilities/effects/common/cost/SourceCostReductionForEachCardInGraveyardEffect.java index 54257d349e..ab50288e85 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/cost/SourceCostReductionForEachCardInGraveyardEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/cost/SourceCostReductionForEachCardInGraveyardEffect.java @@ -1,4 +1,3 @@ - package mage.abilities.effects.common.cost; import mage.abilities.Ability; @@ -7,12 +6,12 @@ import mage.constants.CostModificationType; import mage.constants.Duration; import mage.constants.Outcome; import mage.filter.FilterCard; +import mage.filter.StaticFilters; import mage.game.Game; import mage.players.Player; import mage.util.CardUtil; /** - * * @author Styxo */ public class SourceCostReductionForEachCardInGraveyardEffect extends CostModificationEffectImpl { @@ -20,7 +19,7 @@ public class SourceCostReductionForEachCardInGraveyardEffect extends CostModific private FilterCard filter; public SourceCostReductionForEachCardInGraveyardEffect() { - this(new FilterCard()); + this(StaticFilters.FILTER_CARD); } public SourceCostReductionForEachCardInGraveyardEffect(FilterCard filter) { @@ -29,7 +28,7 @@ public class SourceCostReductionForEachCardInGraveyardEffect extends CostModific staticText = "{this} costs {1} less to cast for each " + filter.getMessage() + " in your graveyard"; } - SourceCostReductionForEachCardInGraveyardEffect(SourceCostReductionForEachCardInGraveyardEffect effect) { + private SourceCostReductionForEachCardInGraveyardEffect(SourceCostReductionForEachCardInGraveyardEffect effect) { super(effect); this.filter = effect.filter.copy(); } diff --git a/Mage/src/main/java/mage/cards/decks/Constructed.java b/Mage/src/main/java/mage/cards/decks/Constructed.java index aaa95e435b..8718c63540 100644 --- a/Mage/src/main/java/mage/cards/decks/Constructed.java +++ b/Mage/src/main/java/mage/cards/decks/Constructed.java @@ -16,8 +16,8 @@ public class Constructed extends DeckValidator { private static final Logger logger = Logger.getLogger(DeckValidator.class); - protected static final List anyNumberCardsAllowed = new ArrayList<>(Arrays.asList( - "Relentless Rats", "Shadowborn Apostle", "Rat Colony", "Persistent Petitioners" + private static final List anyNumberCardsAllowed = new ArrayList<>(Arrays.asList( + "Relentless Rats", "Shadowborn Apostle", "Rat Colony", "Persistent Petitioners", "Seven Dwarves" )); protected static final List basicLandNames = new ArrayList<>(Arrays.asList( "Forest", "Island", "Mountain", "Swamp", "Plains", "Wastes", "Snow-Covered Forest", @@ -67,14 +67,8 @@ public class Constructed extends DeckValidator { Map counts = new HashMap<>(); countCards(counts, deck.getCards()); countCards(counts, deck.getSideboard()); - for (Entry entry : counts.entrySet()) { - if (entry.getValue() > 4) { - if (!basicLandNames.contains(entry.getKey()) && !anyNumberCardsAllowed.contains(entry.getKey())) { - invalid.put(entry.getKey(), "Too many: " + entry.getValue()); - valid = false; - } - } - } + valid = checkCounts(4, counts) && valid; + for (String bannedCard : banned) { if (counts.containsKey(bannedCard)) { invalid.put(bannedCard, "Banned"); @@ -179,4 +173,21 @@ public class Constructed extends DeckValidator { } return legal; } + + protected boolean checkCounts(int maxCopies, Map counts) { + boolean valid = true; + for (Entry entry : counts.entrySet()) { + if (entry.getValue() > maxCopies + && !basicLandNames.contains(entry.getKey()) + && !anyNumberCardsAllowed.contains(entry.getKey())) { + invalid.put(entry.getKey(), "Too many: " + entry.getValue()); + valid = false; + } + if (entry.getValue() > 7 && entry.getKey().equals("Seven Dwarves")) { + invalid.put(entry.getKey(), "Too many: " + entry.getValue()); + valid = false; + } + } + return valid; + } } diff --git a/Mage/src/main/java/mage/cards/repository/CardRepository.java b/Mage/src/main/java/mage/cards/repository/CardRepository.java index 4e57a12ddd..3d58cbefb4 100644 --- a/Mage/src/main/java/mage/cards/repository/CardRepository.java +++ b/Mage/src/main/java/mage/cards/repository/CardRepository.java @@ -35,7 +35,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 = 222; + private static final long CARD_CONTENT_VERSION = 226; private Dao cardDao; private Set classNames; private RepositoryEventSource eventSource = new RepositoryEventSource(); diff --git a/Mage/src/main/java/mage/constants/SubType.java b/Mage/src/main/java/mage/constants/SubType.java index d11656ccc5..e74f2a8552 100644 --- a/Mage/src/main/java/mage/constants/SubType.java +++ b/Mage/src/main/java/mage/constants/SubType.java @@ -10,6 +10,7 @@ import java.util.stream.Collectors; public enum SubType { //205.3k Instants and sorceries share their lists of subtypes; these subtypes are called spell types. + ADVENTURE("Adventure", SubTypeSet.SpellType), ARCANE("Arcane", SubTypeSet.SpellType), TRAP("Trap", SubTypeSet.SpellType), // 205.3i: Lands have their own unique set of subtypes; these subtypes are called land types. @@ -228,6 +229,7 @@ public enum SubType { MONK("Monk", SubTypeSet.CreatureType), MONKEY("Monkey", SubTypeSet.CreatureType), MOONFOLK("Moonfolk", SubTypeSet.CreatureType), + MOUSE("Mouse", SubTypeSet.CreatureType), MUTANT("Mutant", SubTypeSet.CreatureType), MYR("Myr", SubTypeSet.CreatureType), MYSTIC("Mystic", SubTypeSet.CreatureType), @@ -257,6 +259,7 @@ public enum SubType { OYSTER("Oyster", SubTypeSet.CreatureType), // P PANGOLIN("Pangolin", SubTypeSet.CreatureType), + PEASANT("Peasant", SubTypeSet.CreatureType), PEGASUS("Pegasus", SubTypeSet.CreatureType), PENTAVITE("Pentavite", SubTypeSet.CreatureType), PEST("Pest", SubTypeSet.CreatureType), diff --git a/Mage/src/main/java/mage/counters/CounterType.java b/Mage/src/main/java/mage/counters/CounterType.java index 1478bd84c5..401631f780 100644 --- a/Mage/src/main/java/mage/counters/CounterType.java +++ b/Mage/src/main/java/mage/counters/CounterType.java @@ -67,6 +67,7 @@ public enum CounterType { INTERVENTION("intervention"), ISOLATION("isolation"), JAVELIN("javelin"), + KNOWLEDGE("knowledge"), KI("ki"), LANDMARK("landmark"), LEVEL("level"), diff --git a/Mage/src/main/java/mage/filter/StaticFilters.java b/Mage/src/main/java/mage/filter/StaticFilters.java index 27e4b7db7a..2888e8840a 100644 --- a/Mage/src/main/java/mage/filter/StaticFilters.java +++ b/Mage/src/main/java/mage/filter/StaticFilters.java @@ -133,12 +133,25 @@ public final class StaticFilters { FILTER_CARD_A_NON_LAND.setLockedFilter(true); } + + public static final FilterNonlandCard FILTER_CARDS_NON_LAND = new FilterNonlandCard("nonland cards"); + + static { + FILTER_CARDS_NON_LAND.setLockedFilter(true); + } + public static final FilterInstantOrSorceryCard FILTER_CARD_INSTANT_OR_SORCERY = new FilterInstantOrSorceryCard(); static { FILTER_CARD_INSTANT_OR_SORCERY.setLockedFilter(true); } + public static final FilterInstantOrSorceryCard FILTER_CARD_INSTANT_AND_SORCERY = new FilterInstantOrSorceryCard("instant and sorcery card"); + + static { + FILTER_CARD_INSTANT_AND_SORCERY.setLockedFilter(true); + } + public static final FilterPermanent FILTER_PERMANENT = new FilterPermanent(); static { diff --git a/Mage/src/main/java/mage/filter/predicate/mageobject/AdventurePredicate.java b/Mage/src/main/java/mage/filter/predicate/mageobject/AdventurePredicate.java new file mode 100644 index 0000000000..90927d92ca --- /dev/null +++ b/Mage/src/main/java/mage/filter/predicate/mageobject/AdventurePredicate.java @@ -0,0 +1,23 @@ +package mage.filter.predicate.mageobject; + +import mage.MageObject; +import mage.filter.predicate.Predicate; +import mage.game.Game; + +/** + * @author TheElk801 + * TODO: make this actually work + */ +public enum AdventurePredicate implements Predicate { + instance; + + @Override + public boolean apply(MageObject input, Game game) { + return false; + } + + @Override + public String toString() { + return "Adventure"; + } +} diff --git a/Mage/src/main/java/mage/game/permanent/token/DwarfToken.java b/Mage/src/main/java/mage/game/permanent/token/DwarfToken.java new file mode 100644 index 0000000000..861d0bad56 --- /dev/null +++ b/Mage/src/main/java/mage/game/permanent/token/DwarfToken.java @@ -0,0 +1,28 @@ +package mage.game.permanent.token; + +import mage.MageInt; +import mage.constants.CardType; +import mage.constants.SubType; + +/** + * @author TheElk801 + */ +public final class DwarfToken extends TokenImpl { + + public DwarfToken() { + super("Dwarf", "1/1 red Dwarf creature token"); + cardType.add(CardType.CREATURE); + color.setRed(true); + subtype.add(SubType.DWARF); + power = new MageInt(1); + toughness = new MageInt(1); + } + + private DwarfToken(final DwarfToken token) { + super(token); + } + + public DwarfToken copy() { + return new DwarfToken(this); + } +} diff --git a/Mage/src/main/java/mage/game/permanent/token/FaerieToken.java b/Mage/src/main/java/mage/game/permanent/token/FaerieToken.java index f2ac0a9340..bc53e43870 100644 --- a/Mage/src/main/java/mage/game/permanent/token/FaerieToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/FaerieToken.java @@ -1,19 +1,17 @@ - - package mage.game.permanent.token; -import mage.constants.CardType; -import mage.constants.SubType; + import mage.MageInt; import mage.abilities.keyword.FlyingAbility; +import mage.constants.CardType; +import mage.constants.SubType; /** - * * @author spjspj */ public final class FaerieToken extends TokenImpl { public FaerieToken() { - super("Faerie", "1/1 blue Faerie creature tokens with flying"); + super("Faerie", "1/1 blue Faerie creature token with flying"); cardType.add(CardType.CREATURE); color.setBlue(true); subtype.add(SubType.FAERIE); diff --git a/Mage/src/main/java/mage/game/permanent/token/FoodToken.java b/Mage/src/main/java/mage/game/permanent/token/FoodToken.java index 0107d5e614..9cc5e12305 100644 --- a/Mage/src/main/java/mage/game/permanent/token/FoodToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/FoodToken.java @@ -9,6 +9,7 @@ import mage.abilities.effects.common.GainLifeEffect; import mage.constants.CardType; import mage.constants.SubType; import mage.constants.Zone; +import mage.util.RandomUtil; import java.util.ArrayList; import java.util.Arrays; @@ -27,17 +28,8 @@ public final class FoodToken extends TokenImpl { } public FoodToken() { - this(null, 0); - } - - public FoodToken(String setCode) { - this(setCode, 0); - } - - public FoodToken(String setCode, int tokenType) { super("Food", "Food token"); availableImageSetCodes = tokenImageSets; - setOriginalExpansionSetCode(setCode); cardType.add(CardType.ARTIFACT); subtype.add(SubType.FOOD); @@ -50,6 +42,15 @@ public final class FoodToken extends TokenImpl { this.addAbility(ability); } + @Override + public void setExpansionSetCodeForImage(String code) { + super.setExpansionSetCodeForImage(code); + + if (getOriginalExpansionSetCode() != null && getOriginalExpansionSetCode().equals("ELD")) { + setTokenType(RandomUtil.nextInt(4) + 1); // 1...4 + } + } + public FoodToken(final FoodToken token) { super(token); } diff --git a/Mage/src/main/java/mage/game/permanent/token/GiantOpportunityToken.java b/Mage/src/main/java/mage/game/permanent/token/GiantOpportunityToken.java new file mode 100644 index 0000000000..d8bee08b4e --- /dev/null +++ b/Mage/src/main/java/mage/game/permanent/token/GiantOpportunityToken.java @@ -0,0 +1,28 @@ +package mage.game.permanent.token; + +import mage.MageInt; +import mage.constants.CardType; +import mage.constants.SubType; + +/** + * @author TheElk801 + */ +public final class GiantOpportunityToken extends TokenImpl { + + public GiantOpportunityToken() { + super("Giant", "7/7 green Giant creature token"); + cardType.add(CardType.CREATURE); + subtype.add(SubType.GIANT); + color.setGreen(true); + power = new MageInt(7); + toughness = new MageInt(7); + } + + private GiantOpportunityToken(final GiantOpportunityToken token) { + super(token); + } + + public GiantOpportunityToken copy() { + return new GiantOpportunityToken(this); + } +} diff --git a/Mage/src/main/java/mage/game/permanent/token/GoatToken.java b/Mage/src/main/java/mage/game/permanent/token/GoatToken.java index d2d509018c..16c0ca7ba7 100644 --- a/Mage/src/main/java/mage/game/permanent/token/GoatToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/GoatToken.java @@ -1,16 +1,14 @@ - - package mage.game.permanent.token; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; import mage.MageInt; import mage.constants.CardType; import mage.constants.SubType; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + /** - * * @author LoneFox */ public final class GoatToken extends TokenImpl { @@ -18,7 +16,7 @@ public final class GoatToken extends TokenImpl { static final private List tokenImageSets = new ArrayList<>(); static { - tokenImageSets.addAll(Arrays.asList("EVE", "M13", "M14", "C14")); + tokenImageSets.addAll(Arrays.asList("EVE", "M13", "M14", "C14", "ELD")); } public GoatToken() { @@ -46,5 +44,5 @@ public final class GoatToken extends TokenImpl { public GoatToken copy() { return new GoatToken(this); - } + } } diff --git a/Mage/src/main/java/mage/game/permanent/token/HumanToken.java b/Mage/src/main/java/mage/game/permanent/token/HumanToken.java index b1509f116b..3b565946ca 100644 --- a/Mage/src/main/java/mage/game/permanent/token/HumanToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/HumanToken.java @@ -18,7 +18,7 @@ public final class HumanToken extends TokenImpl { subtype.add(SubType.HUMAN); power = new MageInt(1); toughness = new MageInt(1); - availableImageSetCodes.addAll(Arrays.asList("DKA", "AVR", "FNMP", "RNA")); + availableImageSetCodes.addAll(Arrays.asList("DKA", "AVR", "FNMP", "RNA", "ELD")); } public HumanToken(final HumanToken token) { diff --git a/Mage/src/main/java/mage/game/permanent/token/KnightToken.java b/Mage/src/main/java/mage/game/permanent/token/KnightToken.java index e69e3735b0..35f63cd23b 100644 --- a/Mage/src/main/java/mage/game/permanent/token/KnightToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/KnightToken.java @@ -1,16 +1,16 @@ package mage.game.permanent.token; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; import mage.MageInt; import mage.abilities.keyword.VigilanceAbility; import mage.constants.CardType; import mage.constants.SubType; import mage.util.RandomUtil; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + /** - * * @author LevelX2 */ public final class KnightToken extends TokenImpl { @@ -18,7 +18,7 @@ public final class KnightToken extends TokenImpl { static final private List tokenImageSets = new ArrayList<>(); static { - tokenImageSets.addAll(Arrays.asList("ORI", "RTR", "C15", "CMA", "DOM")); + tokenImageSets.addAll(Arrays.asList("ORI", "RTR", "C15", "CMA", "DOM", "ELD")); } public KnightToken() { diff --git a/Mage/src/main/java/mage/game/permanent/token/MouseToken.java b/Mage/src/main/java/mage/game/permanent/token/MouseToken.java new file mode 100644 index 0000000000..5f7428f9b9 --- /dev/null +++ b/Mage/src/main/java/mage/game/permanent/token/MouseToken.java @@ -0,0 +1,29 @@ +package mage.game.permanent.token; + +import mage.MageInt; +import mage.constants.CardType; +import mage.constants.SubType; + +/** + * @author TheElk801 + */ +public final class MouseToken extends TokenImpl { + + public MouseToken() { + super("Mouse", "1/1 white Mouse creature token"); + cardType.add(CardType.CREATURE); + color.setWhite(true); + subtype.add(SubType.MOUSE); + power = new MageInt(1); + toughness = new MageInt(1); + } + + private MouseToken(final MouseToken token) { + super(token); + } + + @Override + public MouseToken copy() { + return new MouseToken(this); + } +} diff --git a/Mage/src/main/java/mage/game/permanent/token/OutlawsMerrimentClericToken.java b/Mage/src/main/java/mage/game/permanent/token/OutlawsMerrimentClericToken.java new file mode 100644 index 0000000000..e6553091f6 --- /dev/null +++ b/Mage/src/main/java/mage/game/permanent/token/OutlawsMerrimentClericToken.java @@ -0,0 +1,35 @@ +package mage.game.permanent.token; + +import mage.MageInt; +import mage.abilities.keyword.HasteAbility; +import mage.abilities.keyword.LifelinkAbility; +import mage.constants.CardType; +import mage.constants.SubType; + +/** + * @author TheElk801 + */ +public final class OutlawsMerrimentClericToken extends TokenImpl { + + public OutlawsMerrimentClericToken() { + super("Human Cleric", "2/1 Human Cleric with lifelink and haste"); + cardType.add(CardType.CREATURE); + subtype.add(SubType.HUMAN); + subtype.add(SubType.CLERIC); + color.setWhite(true); + color.setRed(true); + power = new MageInt(2); + toughness = new MageInt(1); + + this.addAbility(LifelinkAbility.getInstance()); + this.addAbility(HasteAbility.getInstance()); + } + + private OutlawsMerrimentClericToken(final OutlawsMerrimentClericToken token) { + super(token); + } + + public OutlawsMerrimentClericToken copy() { + return new OutlawsMerrimentClericToken(this); + } +} diff --git a/Mage/src/main/java/mage/game/permanent/token/OutlawsMerrimentRogueToken.java b/Mage/src/main/java/mage/game/permanent/token/OutlawsMerrimentRogueToken.java new file mode 100644 index 0000000000..11d4f52d8f --- /dev/null +++ b/Mage/src/main/java/mage/game/permanent/token/OutlawsMerrimentRogueToken.java @@ -0,0 +1,40 @@ +package mage.game.permanent.token; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.keyword.HasteAbility; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.target.common.TargetAnyTarget; + +/** + * @author TheElk801 + */ +public final class OutlawsMerrimentRogueToken extends TokenImpl { + + public OutlawsMerrimentRogueToken() { + super("Human Rogue", "1/2 Human Rogue with haste and \"When this creature enters the battlefield, it deals 1 damage to any target.\""); + cardType.add(CardType.CREATURE); + subtype.add(SubType.HUMAN); + subtype.add(SubType.ROGUE); + color.setWhite(true); + color.setRed(true); + power = new MageInt(1); + toughness = new MageInt(2); + + this.addAbility(HasteAbility.getInstance()); + Ability ability = new EntersBattlefieldTriggeredAbility(new DamageTargetEffect(1, "it")); + ability.addTarget(new TargetAnyTarget()); + this.addAbility(ability); + } + + private OutlawsMerrimentRogueToken(final OutlawsMerrimentRogueToken token) { + super(token); + } + + public OutlawsMerrimentRogueToken copy() { + return new OutlawsMerrimentRogueToken(this); + } +} diff --git a/Mage/src/main/java/mage/game/permanent/token/OutlawsMerrimentWarriorToken.java b/Mage/src/main/java/mage/game/permanent/token/OutlawsMerrimentWarriorToken.java new file mode 100644 index 0000000000..fdf816a51d --- /dev/null +++ b/Mage/src/main/java/mage/game/permanent/token/OutlawsMerrimentWarriorToken.java @@ -0,0 +1,35 @@ +package mage.game.permanent.token; + +import mage.MageInt; +import mage.abilities.keyword.HasteAbility; +import mage.abilities.keyword.TrampleAbility; +import mage.constants.CardType; +import mage.constants.SubType; + +/** + * @author TheElk801 + */ +public final class OutlawsMerrimentWarriorToken extends TokenImpl { + + public OutlawsMerrimentWarriorToken() { + super("Human Warrior", "3/1 Human Warrior with trample and haste"); + cardType.add(CardType.CREATURE); + subtype.add(SubType.HUMAN); + subtype.add(SubType.WARRIOR); + color.setWhite(true); + color.setRed(true); + power = new MageInt(3); + toughness = new MageInt(1); + + this.addAbility(TrampleAbility.getInstance()); + this.addAbility(HasteAbility.getInstance()); + } + + private OutlawsMerrimentWarriorToken(final OutlawsMerrimentWarriorToken token) { + super(token); + } + + public OutlawsMerrimentWarriorToken copy() { + return new OutlawsMerrimentWarriorToken(this); + } +} diff --git a/Mage/src/main/java/mage/game/permanent/token/RatToken.java b/Mage/src/main/java/mage/game/permanent/token/RatToken.java index 20e05a5937..9cf4c9b9fc 100644 --- a/Mage/src/main/java/mage/game/permanent/token/RatToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/RatToken.java @@ -1,30 +1,35 @@ - - package mage.game.permanent.token; import mage.MageInt; import mage.constants.CardType; import mage.constants.SubType; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + /** - * * @author LevelX2 */ public final class RatToken extends TokenImpl { - public RatToken() { - this("GTC"); + static final private List tokenImageSets = new ArrayList<>(); + + static { + tokenImageSets.addAll(Arrays.asList("GTC", "ELD")); } - - public RatToken(String setCode) { + + public RatToken() { super("Rat", "1/1 black Rat creature token"); - this.setOriginalExpansionSetCode(setCode); cardType.add(CardType.CREATURE); color.setBlack(true); subtype.add(SubType.RAT); power = new MageInt(1); toughness = new MageInt(1); + + availableImageSetCodes = tokenImageSets; } + public RatToken(final RatToken token) { super(token); } diff --git a/Mage/src/main/java/mage/game/permanent/token/WolfsQuarryToken.java b/Mage/src/main/java/mage/game/permanent/token/WolfsQuarryToken.java new file mode 100644 index 0000000000..60f4b9f96d --- /dev/null +++ b/Mage/src/main/java/mage/game/permanent/token/WolfsQuarryToken.java @@ -0,0 +1,32 @@ +package mage.game.permanent.token; + +import mage.MageInt; +import mage.abilities.common.DiesTriggeredAbility; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.constants.CardType; +import mage.constants.SubType; + +/** + * @author TheElk801 + */ +public final class WolfsQuarryToken extends TokenImpl { + + public WolfsQuarryToken() { + super("Boar", "1/1 green Boar creature token with \"When this creature dies, create a Food token.\""); + cardType.add(CardType.CREATURE); + color.setGreen(true); + subtype.add(SubType.BOAR); + power = new MageInt(1); + toughness = new MageInt(1); + + this.addAbility(new DiesTriggeredAbility(new CreateTokenEffect(new FoodToken()))); + } + + private WolfsQuarryToken(final WolfsQuarryToken token) { + super(token); + } + + public WolfsQuarryToken copy() { + return new WolfsQuarryToken(this); + } +} diff --git a/Mage/src/main/java/mage/target/TargetAmount.java b/Mage/src/main/java/mage/target/TargetAmount.java index df3f372fd1..84ced7d035 100644 --- a/Mage/src/main/java/mage/target/TargetAmount.java +++ b/Mage/src/main/java/mage/target/TargetAmount.java @@ -1,5 +1,3 @@ - - package mage.target; import mage.abilities.Ability; @@ -7,11 +5,14 @@ import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.dynamicvalue.common.StaticValue; import mage.constants.Outcome; import mage.game.Game; -import java.util.*; + +import java.util.ArrayList; +import java.util.List; +import java.util.Set; +import java.util.UUID; import java.util.stream.Collectors; /** - * * @author BetaSteward_at_googlemail.com */ public abstract class TargetAmount extends TargetImpl { @@ -63,8 +64,8 @@ public abstract class TargetAmount extends TargetImpl { public void setAmountDefinition(DynamicValue amount) { this.amount = amount; - } - + } + public void setAmount(Ability source, Game game) { remainingAmount = amount.calculate(game, source, null); amountWasSet = true; @@ -82,6 +83,13 @@ public abstract class TargetAmount extends TargetImpl { } } + @Override + public void remove(UUID id) { + int amount = getTargetAmount(id); + super.remove(id); + this.remainingAmount += amount; + } + @Override public boolean chooseTarget(Outcome outcome, UUID playerId, Ability source, Game game) { if (!amountWasSet) { @@ -111,7 +119,7 @@ public abstract class TargetAmount extends TargetImpl { if (!amountWasSet) { setAmount(source, game); } - for (UUID targetId: targets) { + for (UUID targetId : targets) { for (int n = 1; n <= target.remainingAmount; n++) { TargetAmount t = target.copy(); t.addTarget(targetId, n, source, game, true); @@ -120,8 +128,7 @@ public abstract class TargetAmount extends TargetImpl { Set newTargets = targets.stream().filter(newTarget -> !newTarget.equals(targetId)).collect(Collectors.toSet()); addTargets(t, newTargets, options, source, game); } - } - else { + } else { options.add(t); } } diff --git a/Mage/src/main/java/mage/target/common/TargetAnyTargetAmount.java b/Mage/src/main/java/mage/target/common/TargetAnyTargetAmount.java index 37c8d4f8fb..544c8a6de3 100644 --- a/Mage/src/main/java/mage/target/common/TargetAnyTargetAmount.java +++ b/Mage/src/main/java/mage/target/common/TargetAnyTargetAmount.java @@ -1,193 +1,56 @@ package mage.target.common; -import java.util.HashSet; -import java.util.Set; -import java.util.UUID; -import mage.MageObject; -import mage.abilities.Ability; import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.dynamicvalue.common.StaticValue; +import mage.constants.CardType; import mage.constants.Zone; -import mage.filter.Filter; -import mage.filter.StaticFilters; import mage.filter.common.FilterCreaturePlayerOrPlaneswalker; -import mage.game.Game; -import mage.game.permanent.Permanent; -import mage.players.Player; -import mage.target.TargetAmount; +import mage.filter.common.FilterPermanentOrPlayer; +import mage.filter.predicate.mageobject.CardTypePredicate; /** - * * @author BetaSteward_at_googlemail.com */ -public class TargetAnyTargetAmount extends TargetAmount { +public class TargetAnyTargetAmount extends TargetPermanentOrPlayerAmount { - protected final FilterCreaturePlayerOrPlaneswalker filter; + private static final FilterPermanentOrPlayer defaultFilter + = new FilterCreaturePlayerOrPlaneswalker("targets"); + + static { + defaultFilter.getPermanentFilter().add(new CardTypePredicate(CardType.CREATURE)); + } public TargetAnyTargetAmount(int amount) { + this(amount, 0); + } + + public TargetAnyTargetAmount(int amount, int maxNumberOfTargets) { // 107.1c If a rule or ability instructs a player to choose “any number,” that player may choose // any positive number or zero, unless something (such as damage or counters) is being divided // or distributed among “any number” of players and/or objects. In that case, a nonzero number // of players and/or objects must be chosen if possible. - this(new StaticValue(amount)); + this(new StaticValue(amount), maxNumberOfTargets); this.minNumberOfTargets = 1; } public TargetAnyTargetAmount(DynamicValue amount) { - super(amount); + this(amount, 0); + } + + public TargetAnyTargetAmount(DynamicValue amount, int maxNumberOfTargets) { + super(amount, maxNumberOfTargets); this.zone = Zone.ALL; - this.filter = new FilterCreaturePlayerOrPlaneswalker("targets"); + this.filter = defaultFilter; this.targetName = filter.getMessage(); } - public TargetAnyTargetAmount(final TargetAnyTargetAmount target) { + private TargetAnyTargetAmount(final TargetAnyTargetAmount target) { super(target); this.filter = target.filter.copy(); } - @Override - public Filter getFilter() { - return this.filter; - } - - @Override - public boolean canTarget(UUID objectId, Game game) { - Permanent permanent = game.getPermanent(objectId); - if (permanent != null) { - return filter.match(permanent, game); - } - Player player = game.getPlayer(objectId); - return player != null && filter.match(player, game); - } - - @Override - public boolean canTarget(UUID objectId, Ability source, Game game) { - Permanent permanent = game.getPermanent(objectId); - Player player = game.getPlayer(objectId); - - if (source != null) { - MageObject targetSource = source.getSourceObject(game); - if (permanent != null) { - return permanent.canBeTargetedBy(targetSource, source.getControllerId(), game) && filter.match(permanent, source.getSourceId(), source.getControllerId(), game); - } - if (player != null) { - return player.canBeTargetedBy(targetSource, source.getControllerId(), game) && filter.match(player, game); - } - } - - if (permanent != null) { - return filter.match(permanent, game); - } - return player != null && filter.match(player, game); - } - - @Override - public boolean canTarget(UUID playerId, UUID objectId, Ability source, Game game) { - return canTarget(objectId, source, game); - } - - @Override - public boolean canChoose(UUID sourceId, UUID sourceControllerId, Game game) { - int count = 0; - MageObject targetSource = game.getObject(sourceId); - for (UUID playerId : game.getState().getPlayersInRange(sourceControllerId, game)) { - Player player = game.getPlayer(playerId); - if (player != null && player.canBeTargetedBy(targetSource, sourceControllerId, game) && filter.match(player, game)) { - count++; - if (count >= this.minNumberOfTargets) { - return true; - } - } - } - for (Permanent permanent : game.getBattlefield().getActivePermanents(StaticFilters.FILTER_PERMANENT, sourceControllerId, game)) { - if (permanent.canBeTargetedBy(targetSource, sourceControllerId, game) && filter.match(permanent, sourceId, sourceControllerId, game)) { - count++; - if (count >= this.minNumberOfTargets) { - return true; - } - } - } - return false; - } - - @Override - public boolean canChoose(UUID sourceControllerId, Game game) { - int count = 0; - for (UUID playerId : game.getState().getPlayersInRange(sourceControllerId, game)) { - Player player = game.getPlayer(playerId); - if (player != null && filter.match(player, game)) { - count++; - if (count >= this.minNumberOfTargets) { - return true; - } - } - } - for (Permanent permanent : game.getBattlefield().getActivePermanents(StaticFilters.FILTER_PERMANENT, sourceControllerId, game)) { - if (filter.match(permanent, null, sourceControllerId, game)) { - count++; - if (count >= this.minNumberOfTargets) { - return true; - } - } - } - return false; - } - - @Override - public Set possibleTargets(UUID sourceId, UUID sourceControllerId, Game game) { - Set possibleTargets = new HashSet<>(); - MageObject targetSource = game.getObject(sourceId); - for (UUID playerId : game.getState().getPlayersInRange(sourceControllerId, game)) { - Player player = game.getPlayer(playerId); - if (player != null && player.canBeTargetedBy(targetSource, sourceControllerId, game) && filter.match(player, game)) { - possibleTargets.add(playerId); - } - } - for (Permanent permanent : game.getBattlefield().getActivePermanents(StaticFilters.FILTER_PERMANENT, sourceControllerId, game)) { - if (permanent.canBeTargetedBy(targetSource, sourceControllerId, game) && filter.match(permanent, sourceId, sourceControllerId, game)) { - possibleTargets.add(permanent.getId()); - } - } - return possibleTargets; - } - - @Override - public Set possibleTargets(UUID sourceControllerId, Game game) { - Set possibleTargets = new HashSet<>(); - for (UUID playerId : game.getState().getPlayersInRange(sourceControllerId, game)) { - Player player = game.getPlayer(playerId); - if (player != null && filter.match(player, game)) { - possibleTargets.add(playerId); - } - } - for (Permanent permanent : game.getBattlefield().getActivePermanents(StaticFilters.FILTER_PERMANENT, sourceControllerId, game)) { - if (filter.match(permanent, null, sourceControllerId, game)) { - possibleTargets.add(permanent.getId()); - } - } - return possibleTargets; - } - - @Override - public String getTargetedName(Game game) { - StringBuilder sb = new StringBuilder(); - for (UUID targetId : getTargets()) { - Permanent permanent = game.getPermanent(targetId); - if (permanent != null) { - sb.append(permanent.getLogName()).append('(').append(getTargetAmount(targetId)).append(") "); - } else { - Player player = game.getPlayer(targetId); - if (player != null) { - sb.append(player.getLogName()).append('(').append(getTargetAmount(targetId)).append(") "); - } - } - } - return sb.toString(); - } - @Override public TargetAnyTargetAmount copy() { return new TargetAnyTargetAmount(this); } - } diff --git a/Mage/src/main/java/mage/target/common/TargetCreatureOrPlaneswalkerAmount.java b/Mage/src/main/java/mage/target/common/TargetCreatureOrPlaneswalkerAmount.java index b373715695..3485646d4d 100644 --- a/Mage/src/main/java/mage/target/common/TargetCreatureOrPlaneswalkerAmount.java +++ b/Mage/src/main/java/mage/target/common/TargetCreatureOrPlaneswalkerAmount.java @@ -1,179 +1,38 @@ - /* - * 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.target.common; +package mage.target.common; - import java.util.HashSet; - import java.util.Set; - import java.util.UUID; - import mage.constants.Zone; - import mage.MageObject; - import mage.abilities.Ability; - import mage.abilities.dynamicvalue.DynamicValue; - import mage.abilities.dynamicvalue.common.StaticValue; - import mage.filter.Filter; - import mage.filter.common.FilterCreatureOrPlaneswalkerPermanent; - import mage.game.Game; - import mage.game.permanent.Permanent; - import mage.target.TargetAmount; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.filter.common.FilterCreatureOrPlaneswalkerPermanent; - /** - * - * @author BetaSteward_at_googlemail.com - */ - public class TargetCreatureOrPlaneswalkerAmount extends TargetAmount { +/** + * @author BetaSteward_at_googlemail.com + */ +public class TargetCreatureOrPlaneswalkerAmount extends TargetPermanentAmount { - protected final FilterCreatureOrPlaneswalkerPermanent filter; - - public TargetCreatureOrPlaneswalkerAmount(int amount) { - // 107.1c If a rule or ability instructs a player to choose “any number,” that player may choose - // any positive number or zero, unless something (such as damage or counters) is being divided - // or distributed among “any number” of players and/or objects. In that case, a nonzero number - // of players and/or objects must be chosen if possible. - this(amount, new FilterCreatureOrPlaneswalkerPermanent()); - } - - public TargetCreatureOrPlaneswalkerAmount(DynamicValue amount) { - this(amount, new FilterCreatureOrPlaneswalkerPermanent()); - } - - public TargetCreatureOrPlaneswalkerAmount(int amount, FilterCreatureOrPlaneswalkerPermanent filter) { - this(new StaticValue(amount), filter); - } - - public TargetCreatureOrPlaneswalkerAmount(DynamicValue amount, FilterCreatureOrPlaneswalkerPermanent filter) { - super(amount); - this.zone = Zone.ALL; - this.filter = filter; - this.targetName = filter.getMessage(); - } - - public TargetCreatureOrPlaneswalkerAmount(final TargetCreatureOrPlaneswalkerAmount target) { - super(target); - this.filter = target.filter.copy(); - } - - @Override - public Filter getFilter() { - return this.filter; - } - - @Override - public boolean canTarget(UUID objectId, Game game) { - Permanent permanent = game.getPermanent(objectId); - return permanent != null && filter.match(permanent, game); - } - - @Override - public boolean canTarget(UUID objectId, Ability source, Game game) { - Permanent permanent = game.getPermanent(objectId); - if (permanent != null) { - if (source != null) { - MageObject targetSource = source.getSourceObject(game); - return permanent.canBeTargetedBy(targetSource, source.getControllerId(), game) && filter.match(permanent, source.getSourceId(), source.getControllerId(), game); - } else { - return filter.match(permanent, game); - } - } - return false; - } - - @Override - public boolean canTarget(UUID playerId, UUID objectId, Ability source, Game game) { - return canTarget(objectId, source, game); - } - - @Override - public boolean canChoose(UUID sourceId, UUID sourceControllerId, Game game) { - int count = 0; - MageObject targetSource = game.getObject(sourceId); - for (Permanent permanent : game.getBattlefield().getActivePermanents(new FilterCreatureOrPlaneswalkerPermanent(), sourceControllerId, game)) { - if (permanent.canBeTargetedBy(targetSource, sourceControllerId, game) && filter.match(permanent, sourceId, sourceControllerId, game)) { - count++; - if (count >= this.minNumberOfTargets) { - return true; - } - } - } - return false; - } - - @Override - public boolean canChoose(UUID sourceControllerId, Game game) { - int count = 0; - for (Permanent permanent : game.getBattlefield().getActivePermanents(new FilterCreatureOrPlaneswalkerPermanent(), sourceControllerId, game)) { - if (filter.match(permanent, null, sourceControllerId, game)) { - count++; - if (count >= this.minNumberOfTargets) { - return true; - } - } - } - return false; - } - - @Override - public Set possibleTargets(UUID sourceId, UUID sourceControllerId, Game game) { - Set possibleTargets = new HashSet<>(); - MageObject targetSource = game.getObject(sourceId); - for (Permanent permanent : game.getBattlefield().getActivePermanents(new FilterCreatureOrPlaneswalkerPermanent(), sourceControllerId, game)) { - if (permanent.canBeTargetedBy(targetSource, sourceControllerId, game) && filter.match(permanent, sourceId, sourceControllerId, game)) { - possibleTargets.add(permanent.getId()); - } - } - return possibleTargets; - } - - @Override - public Set possibleTargets(UUID sourceControllerId, Game game) { - Set possibleTargets = new HashSet<>(); - for (Permanent permanent : game.getBattlefield().getActivePermanents(new FilterCreatureOrPlaneswalkerPermanent(), sourceControllerId, game)) { - if (filter.match(permanent, null, sourceControllerId, game)) { - possibleTargets.add(permanent.getId()); - } - } - return possibleTargets; - } - - @Override - public String getTargetedName(Game game) { - StringBuilder sb = new StringBuilder(); - for (UUID targetId : getTargets()) { - Permanent permanent = game.getPermanent(targetId); - if (permanent != null) { - sb.append(permanent.getLogName()).append('(').append(getTargetAmount(targetId)).append(") "); - } - } - return sb.toString(); - } - - @Override - public TargetCreatureOrPlaneswalkerAmount copy() { - return new TargetCreatureOrPlaneswalkerAmount(this); - } + private static final FilterCreatureOrPlaneswalkerPermanent defaultFilter + = new FilterCreatureOrPlaneswalkerPermanent(); + public TargetCreatureOrPlaneswalkerAmount(int amount) { + super(amount, defaultFilter); } + + public TargetCreatureOrPlaneswalkerAmount(DynamicValue amount) { + super(amount, defaultFilter); + } + + public TargetCreatureOrPlaneswalkerAmount(int amount, FilterCreatureOrPlaneswalkerPermanent filter) { + super(amount, filter); + } + + public TargetCreatureOrPlaneswalkerAmount(DynamicValue amount, FilterCreatureOrPlaneswalkerPermanent filter) { + super(amount, filter); + } + + private TargetCreatureOrPlaneswalkerAmount(final TargetCreatureOrPlaneswalkerAmount target) { + super(target); + } + + @Override + public TargetCreatureOrPlaneswalkerAmount copy() { + return new TargetCreatureOrPlaneswalkerAmount(this); + } +} diff --git a/Mage/src/main/java/mage/target/common/TargetCreatureOrPlayerAmount.java b/Mage/src/main/java/mage/target/common/TargetCreatureOrPlayerAmount.java index 06e7ebba6e..00fa98bf45 100644 --- a/Mage/src/main/java/mage/target/common/TargetCreatureOrPlayerAmount.java +++ b/Mage/src/main/java/mage/target/common/TargetCreatureOrPlayerAmount.java @@ -1,29 +1,23 @@ - package mage.target.common; -import java.util.HashSet; -import java.util.Set; -import java.util.UUID; -import mage.MageObject; -import mage.abilities.Ability; import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.dynamicvalue.common.StaticValue; +import mage.constants.CardType; import mage.constants.Zone; -import mage.filter.Filter; -import mage.filter.StaticFilters; -import mage.filter.common.FilterCreatureOrPlayer; -import mage.game.Game; -import mage.game.permanent.Permanent; -import mage.players.Player; -import mage.target.TargetAmount; +import mage.filter.common.FilterPermanentOrPlayer; +import mage.filter.predicate.mageobject.CardTypePredicate; /** - * * @author BetaSteward_at_googlemail.com */ -public class TargetCreatureOrPlayerAmount extends TargetAmount { +public class TargetCreatureOrPlayerAmount extends TargetPermanentOrPlayerAmount { - protected final FilterCreatureOrPlayer filter; + private static final FilterPermanentOrPlayer defaultFilter + = new FilterPermanentOrPlayer("creatures and/or players"); + + static { + defaultFilter.getPermanentFilter().add(new CardTypePredicate(CardType.CREATURE)); + } public TargetCreatureOrPlayerAmount(int amount) { // 107.1c If a rule or ability instructs a player to choose “any number,” that player may choose @@ -37,156 +31,17 @@ public class TargetCreatureOrPlayerAmount extends TargetAmount { public TargetCreatureOrPlayerAmount(DynamicValue amount) { super(amount); this.zone = Zone.ALL; - this.filter = new FilterCreatureOrPlayer("creatures and/or players"); + this.filter = defaultFilter; this.targetName = filter.getMessage(); } - public TargetCreatureOrPlayerAmount(final TargetCreatureOrPlayerAmount target) { + private TargetCreatureOrPlayerAmount(final TargetCreatureOrPlayerAmount target) { super(target); this.filter = target.filter.copy(); } - @Override - public Filter getFilter() { - return this.filter; - } - - @Override - public boolean canTarget(UUID objectId, Game game) { - Permanent permanent = game.getPermanent(objectId); - if (permanent != null) { - return filter.match(permanent, game); - } - Player player = game.getPlayer(objectId); - return player != null && filter.match(player, game); - } - - @Override - public boolean canTarget(UUID objectId, Ability source, Game game) { - Permanent permanent = game.getPermanent(objectId); - Player player = game.getPlayer(objectId); - - if (source != null) { - MageObject targetSource = source.getSourceObject(game); - if (permanent != null) { - return permanent.canBeTargetedBy(targetSource, source.getControllerId(), game) && filter.match(permanent, source.getSourceId(), source.getControllerId(), game); - } - if (player != null) { - return player.canBeTargetedBy(targetSource, source.getControllerId(), game) && filter.match(player, game); - } - } - - if (permanent != null) { - return filter.match(permanent, game); - } - return player != null && filter.match(player, game); - } - - @Override - public boolean canTarget(UUID playerId, UUID objectId, Ability source, Game game) { - return canTarget(objectId, source, game); - } - - @Override - public boolean canChoose(UUID sourceId, UUID sourceControllerId, Game game) { - int count = 0; - MageObject targetSource = game.getObject(sourceId); - for (UUID playerId : game.getState().getPlayersInRange(sourceControllerId, game)) { - Player player = game.getPlayer(playerId); - if (player != null && player.canBeTargetedBy(targetSource, sourceControllerId, game) && filter.match(player, game)) { - count++; - if (count >= this.minNumberOfTargets) { - return true; - } - } - } - for (Permanent permanent : game.getBattlefield().getActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, sourceControllerId, game)) { - if (permanent.canBeTargetedBy(targetSource, sourceControllerId, game) && filter.match(permanent, sourceId, sourceControllerId, game)) { - count++; - if (count >= this.minNumberOfTargets) { - return true; - } - } - } - return false; - } - - @Override - public boolean canChoose(UUID sourceControllerId, Game game) { - int count = 0; - for (UUID playerId : game.getState().getPlayersInRange(sourceControllerId, game)) { - Player player = game.getPlayer(playerId); - if (player != null && filter.match(player, game)) { - count++; - if (count >= this.minNumberOfTargets) { - return true; - } - } - } - for (Permanent permanent : game.getBattlefield().getActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, sourceControllerId, game)) { - if (filter.match(permanent, null, sourceControllerId, game)) { - count++; - if (count >= this.minNumberOfTargets) { - return true; - } - } - } - return false; - } - - @Override - public Set possibleTargets(UUID sourceId, UUID sourceControllerId, Game game) { - Set possibleTargets = new HashSet<>(); - MageObject targetSource = game.getObject(sourceId); - for (UUID playerId : game.getState().getPlayersInRange(sourceControllerId, game)) { - Player player = game.getPlayer(playerId); - if (player != null && player.canBeTargetedBy(targetSource, sourceControllerId, game) && filter.match(player, game)) { - possibleTargets.add(playerId); - } - } - for (Permanent permanent : game.getBattlefield().getActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, sourceControllerId, game)) { - if (permanent.canBeTargetedBy(targetSource, sourceControllerId, game) && filter.match(permanent, sourceId, sourceControllerId, game)) { - possibleTargets.add(permanent.getId()); - } - } - return possibleTargets; - } - - @Override - public Set possibleTargets(UUID sourceControllerId, Game game) { - Set possibleTargets = new HashSet<>(); - for (UUID playerId : game.getState().getPlayersInRange(sourceControllerId, game)) { - Player player = game.getPlayer(playerId); - if (player != null && filter.match(player, game)) { - possibleTargets.add(playerId); - } - } - for (Permanent permanent : game.getBattlefield().getActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, sourceControllerId, game)) { - if (filter.match(permanent, null, sourceControllerId, game)) { - possibleTargets.add(permanent.getId()); - } - } - return possibleTargets; - } - - @Override - public String getTargetedName(Game game) { - StringBuilder sb = new StringBuilder(); - for (UUID targetId : getTargets()) { - Permanent permanent = game.getPermanent(targetId); - if (permanent != null) { - sb.append(permanent.getLogName()).append('(').append(getTargetAmount(targetId)).append(") "); - } else { - Player player = game.getPlayer(targetId); - sb.append(player.getLogName()).append('(').append(getTargetAmount(targetId)).append(") "); - } - } - return sb.toString(); - } - @Override public TargetCreatureOrPlayerAmount copy() { return new TargetCreatureOrPlayerAmount(this); } - } diff --git a/Mage/src/main/java/mage/target/common/TargetCreaturePermanentAmount.java b/Mage/src/main/java/mage/target/common/TargetCreaturePermanentAmount.java index fae796583a..855cb08516 100644 --- a/Mage/src/main/java/mage/target/common/TargetCreaturePermanentAmount.java +++ b/Mage/src/main/java/mage/target/common/TargetCreaturePermanentAmount.java @@ -1,145 +1,32 @@ - package mage.target.common; -import java.util.HashSet; -import java.util.Set; -import java.util.UUID; -import mage.MageObject; -import mage.abilities.Ability; import mage.abilities.dynamicvalue.DynamicValue; -import mage.abilities.dynamicvalue.common.StaticValue; -import mage.constants.Zone; -import mage.filter.Filter; import mage.filter.StaticFilters; import mage.filter.common.FilterCreaturePermanent; -import mage.game.Game; -import mage.game.permanent.Permanent; -import mage.target.TargetAmount; /** - * * @author North */ -public class TargetCreaturePermanentAmount extends TargetAmount { - - protected final FilterCreaturePermanent filter; +public class TargetCreaturePermanentAmount extends TargetPermanentAmount { public TargetCreaturePermanentAmount(int amount) { - this(amount, new FilterCreaturePermanent()); + super(amount, StaticFilters.FILTER_PERMANENT_CREATURE); } public TargetCreaturePermanentAmount(DynamicValue amount) { - this(amount, new FilterCreaturePermanent()); + this(amount, StaticFilters.FILTER_PERMANENT_CREATURE); } public TargetCreaturePermanentAmount(int amount, FilterCreaturePermanent filter) { - this(new StaticValue(amount), filter); + super(amount, filter); } public TargetCreaturePermanentAmount(DynamicValue amount, FilterCreaturePermanent filter) { - super(amount); - this.zone = Zone.ALL; - this.filter = filter; - this.targetName = filter.getMessage(); + super(amount, filter); } - public TargetCreaturePermanentAmount(final TargetCreaturePermanentAmount target) { + private TargetCreaturePermanentAmount(final TargetCreaturePermanentAmount target) { super(target); - this.filter = target.filter.copy(); - } - - @Override - public Filter getFilter() { - return this.filter; - } - - @Override - public boolean canTarget(UUID id, Game game) { - Permanent permanent = game.getPermanent(id); - return permanent != null && filter.match(permanent, game); - } - - @Override - public boolean canTarget(UUID id, Ability source, Game game) { - Permanent permanent = game.getPermanent(id); - if (permanent != null) { - if (source != null) { - MageObject targetSource = game.getObject(source.getSourceId()); - return permanent.canBeTargetedBy(targetSource, source.getControllerId(), game) && filter.match(permanent, source.getSourceId(), source.getControllerId(), game); - } else { - return filter.match(permanent, game); - } - } - return false; - } - - @Override - public boolean canTarget(UUID playerId, UUID id, Ability source, Game game) { - return canTarget(id, source, game); - } - - @Override - public boolean canChoose(UUID sourceId, UUID sourceControllerId, Game game) { - int count = 0; - MageObject targetSource = game.getObject(sourceId); - for (Permanent permanent : game.getBattlefield().getActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, sourceControllerId, game)) { - if (permanent.canBeTargetedBy(targetSource, sourceControllerId, game) && filter.match(permanent, sourceId, sourceControllerId, game)) { - count++; - if (count >= this.minNumberOfTargets) { - return true; - } - } - } - return false; - } - - @Override - public boolean canChoose(UUID sourceControllerId, Game game) { - int count = 0; - for (Permanent permanent : game.getBattlefield().getActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, sourceControllerId, game)) { - if (filter.match(permanent, null, sourceControllerId, game)) { - count++; - if (count >= this.minNumberOfTargets) { - return true; - } - } - } - return false; - } - - @Override - public Set possibleTargets(UUID sourceId, UUID sourceControllerId, Game game) { - Set possibleTargets = new HashSet<>(); - MageObject targetSource = game.getObject(sourceId); - for (Permanent permanent : game.getBattlefield().getActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, sourceControllerId, game)) { - if (permanent.canBeTargetedBy(targetSource, sourceControllerId, game) && filter.match(permanent, sourceId, sourceControllerId, game)) { - possibleTargets.add(permanent.getId()); - } - } - return possibleTargets; - } - - @Override - public Set possibleTargets(UUID sourceControllerId, Game game) { - Set possibleTargets = new HashSet<>(); - for (Permanent permanent : game.getBattlefield().getActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, sourceControllerId, game)) { - if (filter.match(permanent, null, sourceControllerId, game)) { - possibleTargets.add(permanent.getId()); - } - } - return possibleTargets; - } - - @Override - public String getTargetedName(Game game) { - StringBuilder sb = new StringBuilder(); - for (UUID targetId : getTargets()) { - Permanent permanent = game.getPermanent(targetId); - if (permanent != null) { - sb.append(permanent.getLogName()).append('(').append(getTargetAmount(targetId)).append(") "); - } - } - return sb.toString(); } @Override diff --git a/Mage/src/main/java/mage/target/common/TargetPermanentAmount.java b/Mage/src/main/java/mage/target/common/TargetPermanentAmount.java new file mode 100644 index 0000000000..b6c9afedc3 --- /dev/null +++ b/Mage/src/main/java/mage/target/common/TargetPermanentAmount.java @@ -0,0 +1,150 @@ +package mage.target.common; + +import mage.MageObject; +import mage.abilities.Ability; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.dynamicvalue.common.StaticValue; +import mage.constants.Zone; +import mage.filter.Filter; +import mage.filter.FilterPermanent; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.target.TargetAmount; + +import java.util.Objects; +import java.util.Set; +import java.util.UUID; +import java.util.stream.Collectors; + +/** + * @author TheElk801 + */ +public abstract class TargetPermanentAmount extends TargetAmount { + + protected final FilterPermanent filter; + + TargetPermanentAmount(int amount, FilterPermanent filter) { + // 107.1c If a rule or ability instructs a player to choose “any number,” that player may choose + // any positive number or zero, unless something (such as damage or counters) is being divided + // or distributed among “any number” of players and/or objects. In that case, a nonzero number + // of players and/or objects must be chosen if possible. + this(new StaticValue(amount), filter); + } + + TargetPermanentAmount(DynamicValue amount, FilterPermanent filter) { + super(amount); + this.zone = Zone.ALL; + this.filter = filter; + this.targetName = filter.getMessage(); + } + + TargetPermanentAmount(final TargetPermanentAmount target) { + super(target); + this.filter = target.filter.copy(); + } + + @Override + public Filter getFilter() { + return this.filter; + } + + @Override + public boolean canTarget(UUID objectId, Game game) { + Permanent permanent = game.getPermanent(objectId); + return permanent != null && filter.match(permanent, game); + } + + @Override + public boolean canTarget(UUID objectId, Ability source, Game game) { + if (getMaxNumberOfTargets() > 0 && getTargets().size() >= getMaxNumberOfTargets()) { + return getTargets().contains(objectId); + } + Permanent permanent = game.getPermanent(objectId); + if (permanent == null) { + return false; + } + if (source == null) { + return filter.match(permanent, game); + } + MageObject targetSource = source.getSourceObject(game); + return permanent.canBeTargetedBy(targetSource, source.getControllerId(), game) + && filter.match(permanent, source.getSourceId(), source.getControllerId(), game); + } + + @Override + public boolean canTarget(UUID playerId, UUID objectId, Ability source, Game game) { + return canTarget(objectId, source, game); + } + + @Override + public boolean canChoose(UUID sourceId, UUID sourceControllerId, Game game) { + int count = 0; + for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, sourceControllerId, sourceId, game)) { + count++; + if (count >= this.minNumberOfTargets) { + return true; + } + } + return false; + } + + @Override + public boolean canChoose(UUID sourceControllerId, Game game) { + int count = 0; + for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, sourceControllerId, game)) { + count++; + if (count >= this.minNumberOfTargets) { + return true; + } + } + return false; + } + + @Override + public Set possibleTargets(UUID sourceId, UUID sourceControllerId, Game game) { + if (getMaxNumberOfTargets() > 0 && getTargets().size() >= getMaxNumberOfTargets()) { + return getTargets() + .stream() + .collect(Collectors.toSet()); + } + MageObject targetSource = game.getObject(sourceId); + return game + .getBattlefield() + .getActivePermanents(filter, sourceControllerId, sourceId, game) + .stream() + .filter(Objects::nonNull) + .filter(permanent -> permanent.canBeTargetedBy(targetSource, sourceControllerId, game)) + .map(Permanent::getId) + .collect(Collectors.toSet()); + } + + @Override + public Set possibleTargets(UUID sourceControllerId, Game game) { + if (getMaxNumberOfTargets() > 0 && getTargets().size() >= getMaxNumberOfTargets()) { + return getTargets() + .stream() + .collect(Collectors.toSet()); + } + return game + .getBattlefield() + .getActivePermanents(filter, sourceControllerId, game) + .stream() + .map(Permanent::getId) + .collect(Collectors.toSet()); + } + + @Override + public String getTargetedName(Game game) { + StringBuilder sb = new StringBuilder(); + for (UUID targetId : getTargets()) { + Permanent permanent = game.getPermanent(targetId); + if (permanent != null) { + sb.append(permanent.getLogName()).append('(').append(getTargetAmount(targetId)).append(") "); + } + } + return sb.toString(); + } + + @Override + public abstract TargetPermanentAmount copy(); +} diff --git a/Mage/src/main/java/mage/target/common/TargetPermanentOrPlayerAmount.java b/Mage/src/main/java/mage/target/common/TargetPermanentOrPlayerAmount.java new file mode 100644 index 0000000000..adc75fae2c --- /dev/null +++ b/Mage/src/main/java/mage/target/common/TargetPermanentOrPlayerAmount.java @@ -0,0 +1,222 @@ +package mage.target.common; + +import mage.MageObject; +import mage.abilities.Ability; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.filter.Filter; +import mage.filter.common.FilterPermanentOrPlayer; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.TargetAmount; + +import java.util.HashSet; +import java.util.Objects; +import java.util.Set; +import java.util.UUID; + +/** + * @author TheElk801 + */ +public abstract class TargetPermanentOrPlayerAmount extends TargetAmount { + + protected FilterPermanentOrPlayer filter; + + TargetPermanentOrPlayerAmount(DynamicValue amount) { + this(amount, 0); + } + + TargetPermanentOrPlayerAmount(DynamicValue amount, int maxNumberOfTargets) { + super(amount); + this.maxNumberOfTargets = maxNumberOfTargets; + } + + TargetPermanentOrPlayerAmount(final TargetPermanentOrPlayerAmount target) { + super(target); + this.filter = target.filter.copy(); + } + + @Override + public Filter getFilter() { + return this.filter; + } + + @Override + public boolean canTarget(UUID objectId, Game game) { + + // max targets limit reached (only selected can be choosen again) + if (getMaxNumberOfTargets() > 0 && getTargets().size() >= getMaxNumberOfTargets()) { + return getTargets().contains(objectId); + } + + Permanent permanent = game.getPermanent(objectId); + if (permanent != null) { + return filter.match(permanent, game); + } + Player player = game.getPlayer(objectId); + return player != null && filter.match(player, game); + } + + @Override + public boolean canTarget(UUID objectId, Ability source, Game game) { + + // max targets limit reached (only selected can be choosen again) + if (getMaxNumberOfTargets() > 0 && getTargets().size() >= getMaxNumberOfTargets()) { + return getTargets().contains(objectId); + } + + Permanent permanent = game.getPermanent(objectId); + Player player = game.getPlayer(objectId); + + if (source != null) { + MageObject targetSource = source.getSourceObject(game); + if (permanent != null) { + return permanent.canBeTargetedBy(targetSource, source.getControllerId(), game) + && filter.match(permanent, source.getSourceId(), source.getControllerId(), game); + } + if (player != null) { + return player.canBeTargetedBy(targetSource, source.getControllerId(), game) + && filter.match(player, game); + } + } + + if (permanent != null) { + return filter.match(permanent, game); + } + return player != null && filter.match(player, game); + } + + @Override + public boolean canTarget(UUID playerId, UUID objectId, Ability source, Game game) { + return canTarget(objectId, source, game); + } + + @Override + public boolean canChoose(UUID sourceId, UUID sourceControllerId, Game game) { + // no max targets limit here + int count = 0; + MageObject targetSource = game.getObject(sourceId); + for (UUID playerId : game.getState().getPlayersInRange(sourceControllerId, game)) { + Player player = game.getPlayer(playerId); + if (player == null + || !player.canBeTargetedBy(targetSource, sourceControllerId, game) + || !filter.match(player, game)) { + continue; + } + count++; + if (count >= this.minNumberOfTargets) { + return true; + } + } + for (Permanent permanent : game.getBattlefield().getActivePermanents(filter.getPermanentFilter(), sourceControllerId, game)) { + if (!permanent.canBeTargetedBy(targetSource, sourceControllerId, game)) { + continue; + } + count++; + if (count >= this.minNumberOfTargets) { + return true; + } + } + return false; + } + + @Override + public boolean canChoose(UUID sourceControllerId, Game game) { + // no max targets limit here + int count = 0; + for (UUID playerId : game.getState().getPlayersInRange(sourceControllerId, game)) { + Player player = game.getPlayer(playerId); + if (player == null || !filter.match(player, game)) { + continue; + } + count++; + if (count >= this.minNumberOfTargets) { + return true; + } + } + for (Permanent permanent : game.getBattlefield().getActivePermanents(filter.getPermanentFilter(), sourceControllerId, game)) { + count++; + if (count >= this.minNumberOfTargets) { + return true; + } + } + return false; + } + + @Override + public Set possibleTargets(UUID sourceId, UUID sourceControllerId, Game game) { + Set possibleTargets = new HashSet<>(); + + // max targets limit reached (only selected can be choosen again) + if (getMaxNumberOfTargets() > 0 && getTargets().size() >= getMaxNumberOfTargets()) { + possibleTargets.addAll(getTargets()); + return possibleTargets; + } + + MageObject targetSource = game.getObject(sourceId); + + game.getState() + .getPlayersInRange(sourceControllerId, game) + .stream() + .map(game::getPlayer) + .filter(Objects::nonNull) + .filter(player -> player.canBeTargetedBy(targetSource, sourceControllerId, game) + && filter.match(player, game) + ) + .map(Player::getId) + .forEach(possibleTargets::add); + + game.getBattlefield() + .getActivePermanents(filter.getPermanentFilter(), sourceControllerId, game) + .stream() + .filter(Objects::nonNull) + .filter(permanent -> permanent.canBeTargetedBy(targetSource, sourceControllerId, game)) + .map(Permanent::getId) + .forEach(possibleTargets::add); + + return possibleTargets; + } + + @Override + public Set possibleTargets(UUID sourceControllerId, Game game) { + Set possibleTargets = new HashSet<>(); + + // max targets limit reached (only selected can be choosen again) + if (getMaxNumberOfTargets() > 0 && getTargets().size() >= getMaxNumberOfTargets()) { + possibleTargets.addAll(getTargets()); + return possibleTargets; + } + + game.getState() + .getPlayersInRange(sourceControllerId, game) + .stream() + .map(game::getPlayer) + .filter(Objects::nonNull) + .filter(player -> filter.match(player, game)) + .map(Player::getId) + .forEach(possibleTargets::add); + + game.getBattlefield() + .getActivePermanents(filter.getPermanentFilter(), sourceControllerId, game) + .stream() + .map(Permanent::getId) + .forEach(possibleTargets::add); + + return possibleTargets; + } + + @Override + public String getTargetedName(Game game) { + StringBuilder sb = new StringBuilder(); + for (UUID targetId : getTargets()) { + Permanent permanent = game.getPermanent(targetId); + if (permanent != null) { + sb.append(permanent.getLogName()).append('(').append(getTargetAmount(targetId)).append(") "); + } else { + Player player = game.getPlayer(targetId); + sb.append(player.getLogName()).append('(').append(getTargetAmount(targetId)).append(") "); + } + } + return sb.toString(); + } +} diff --git a/Mage/src/main/java/mage/util/CardUtil.java b/Mage/src/main/java/mage/util/CardUtil.java index 851d83c8de..85770a50a3 100644 --- a/Mage/src/main/java/mage/util/CardUtil.java +++ b/Mage/src/main/java/mage/util/CardUtil.java @@ -9,12 +9,14 @@ import mage.abilities.costs.VariableCost; import mage.abilities.costs.mana.*; import mage.cards.Card; import mage.constants.EmptyNames; +import mage.filter.Filter; import mage.game.Game; import mage.game.permanent.Permanent; import mage.game.permanent.token.Token; import mage.util.functions.CopyTokenFunction; import java.text.SimpleDateFormat; +import java.util.Objects; import java.util.UUID; /** @@ -87,6 +89,10 @@ public final class CardUtil { ManaCosts adjustedCost = new ManaCostsImpl<>(); boolean updated = false; for (ManaCost manaCost : manaCosts) { + if (manaCost instanceof SnowManaCost) { + adjustedCost.add(manaCost); + continue; + } Mana mana = manaCost.getOptions().get(0); int colorless = mana != null ? mana.getGeneric() : 0; if (restToReduce != 0 && colorless > 0) { @@ -107,7 +113,15 @@ public final class CardUtil { if (!updated && reduceCount < 0) { adjustedCost.add(new GenericManaCost(-reduceCount)); } - adjustedCost.setSourceFilter(manaCosts.getSourceFilter()); + Filter filter = manaCosts.stream() + .filter(manaCost -> !(manaCost instanceof SnowManaCost)) + .map(ManaCost::getSourceFilter) + .filter(Objects::nonNull) + .findFirst() + .orElse(null); + if (filter != null) { + adjustedCost.setSourceFilter(filter); + } return adjustedCost; } diff --git a/Utils/known-sets.txt b/Utils/known-sets.txt index 7bf3b5eeaf..638e5cb57a 100644 --- a/Utils/known-sets.txt +++ b/Utils/known-sets.txt @@ -90,6 +90,8 @@ From the Vault: Transform|FromTheVaultTransform| From the Vault: Twenty|FromTheVaultTwenty| Future Sight|FutureSight| Game Day|GameDay| +Game Night|GameNight| +Game Night 2019|GameNight2019| Gatecrash|Gatecrash| Global Series: Jiang Yanggu & Mu Yanling|GlobalSeriesJiangYangguAndMuYanling| Grand Prix|GrandPrixPromos| @@ -187,6 +189,7 @@ Tenth Edition|TenthEdition| The Dark|TheDark| Theros|Theros| Throne of Eldraine|ThroneOfEldraine| +Throne of Eldraine Collector's Edition|ThroneOfEldraineCollectorsEdition| Time Spiral|TimeSpiral| Time Spiral "Timeshifted"|TimeSpiralTimeshifted| Torment|Torment| diff --git a/Utils/mtg-cards-data.txt b/Utils/mtg-cards-data.txt index 34afcae8be..e96203d62f 100644 --- a/Utils/mtg-cards-data.txt +++ b/Utils/mtg-cards-data.txt @@ -35993,62 +35993,300 @@ Island|Commander 2019|291|C||Basic Land - Island|||({T}: Add {U}.)| Swamp|Commander 2019|294|C||Basic Land - Swamp|||({T}: Add {B}.)| Mountain|Commander 2019|297|C||Basic Land - Mountain|||({T}: Add {R}.)| Forest|Commander 2019|300|C||Basic Land - Forest|||({T}: Add {G}.)| +Acclaimed Contender|Throne of Eldraine|1|R|{2}{W}|Creature - Human Knight|3|3|When Acclaimed Contender enters the battlefield, if you control another Knight, look at the top five cards of your library. You may reveal a Knight, Aura, Equipment, or legendary artifact card from among them and put it into your hand. Put the rest on the bottom of your library in a random order.| All That Glitters|Throne of Eldraine|2|U|{1}{W}|Enchantment - Aura|||Enchant creature$Enchanted creature gets +1/+1 for each artifact and/or enchantment you control.| +Archon of Absolution|Throne of Eldraine|3|U|{3}{W}|Creature - Archon|3|2|Flying$Protection from white$Creatures can't attack you or a planeswalker you control unless their controller pays {1} for each of those creatures.| +Ardenvale Paladin|Throne of Eldraine|4|C|{3}{W}|Creature - Human Knight|2|5|Adamant — If at least three white mana was spent to cast this spell, Ardenvale Paladin enters the battlefield with a +1/+1 counter on it.| +Ardenvale Tactician|Throne of Eldraine|5|C|{1}{W}{W}|Creature - Human Knight|2|3|Flying| +Dizzying Swoop|Throne of Eldraine|5|C|{1}{W}|Instant - Adventure|2|3|Tap up to two target creatures.| +Bartered Cow|Throne of Eldraine|6|C|{3}{W}|Creature - Ox|3|3|When Bartered Cow dies or when you discard it, create a Food token.| +Beloved Princess|Throne of Eldraine|7|C|{W}|Creature - Human Noble|1|1|Lifelink$Beloved Princess can't be blocked by creatures with power 3 or greater.| +Charming Prince|Throne of Eldraine|8|R|{1}{W}|Creature - Human Noble|2|2|When Charming Prince enters the battlefield, choose one —$• Scry 2.$• You gain 3 life.$• Exile another target creature you own. Return it to the battlefield under your control at the beginning of the next end step.| The Circle of Loyalty|Throne of Eldraine|9|M|{4}{W}{W}|Legendary Artifact|||This spell costs {1} less to cast for each Knight you control.$Creatures you control get +1/+1.$Whenever you cast a legendary spell, create a 2/2 white Knight creature token with vigilance.${3}{W}, {T}: Create a 2/2 white Knight creature token with vigilance.| +Deafening Silence|Throne of Eldraine|10|U|{W}|Enchantment|||Each player can't cast more than one noncreature spell each turn.| +Faerie Guidemother|Throne of Eldraine|11|C|{W}|Creature - Faerie|1|1|Flying| +Gift of the Fae|Throne of Eldraine|11|C|{1}{W}|Sorcery - Adventure|1|1|Target creature gets +2/+1 and gains flying until end of turn.| +Flutterfox|Throne of Eldraine|12|C|{1}{W}|Creature - Fox|2|2|As long as you control an artifact or enchantment, Flutterfox has flying.| +Fortifying Provisions|Throne of Eldraine|13|C|{2}{W}|Enchantment|||Creatures you control get +0/+1.$When Fortifying Provisions enters the battlefield, create a Food token.| +Chop Down|Throne of Eldraine|14|R|{2}{W}|Instant - Adventure|1|2|Destroy target creature with power 4 or greater.| +Giant Killer|Throne of Eldraine|14|R|{W}|Creature - Human Peasant|1|2|{1}{W}, {T}: Tap target creature.| +Glass Casket|Throne of Eldraine|15|U|{1}{W}|Artifact|||When Glass Casket enters the battlefield, exile target creature an opponent controls with converted mana cost 3 or less until Glass Casket leaves the battlefield.| +Happily Ever After|Throne of Eldraine|16|R|{2}{W}|Enchantment|||When Happily Ever After enters the battlefield, each player gains 5 life and draws a card.$At the beginning of your upkeep, if there are five colors among permanents you control, there are six or more card types among permanents you control and/or cards in your graveyard, and your life total is greater than or equal to your starting life total, you win the game.| +Harmonious Archon|Throne of Eldraine|17|M|{4}{W}{W}|Creature - Archon|4|5|Flying$Non-Archon creatures have base power and toughness 3/3.$When Harmonious Archon enters the battlefield, create two 1/1 white Human creature tokens.| +Hushbringer|Throne of Eldraine|18|R|{1}{W}|Creature - Faerie|1|2|Flying, lifelink$Creatures entering the battlefield or dying don't cause abilities to trigger.| +Knight of the Keep|Throne of Eldraine|19|C|{2}{W}|Creature - Human Knight|3|2|| +Linden, the Steadfast Queen|Throne of Eldraine|20|R|{W}{W}{W}|Legendary Creature - Human Noble|3|3|Vigilance$Whenever a white creature you control attacks, you gain 1 life.| +Lonesome Unicorn|Throne of Eldraine|21|C|{4}{W}|Creature - Unicorn|3|3|Vigilance| +Rider in Need|Throne of Eldraine|21|C|{2}{W}|Sorcery - Adventure|3|3|Create a 2/2 white Knight creature token with vigilance.| +Mysterious Pathlighter|Throne of Eldraine|22|U|{2}{W}|Creature - Faerie|2|2|Flying$Each creature you control that has an Adventure enters the battlefield with an additional +1/+1 counter on it.| +Outflank|Throne of Eldraine|23|C|{W}|Instant|||Outflank deals damage to target attacking or blocking creature equal to the number of creatures you control.| +Prized Griffin|Throne of Eldraine|24|C|{4}{W}|Creature - Griffin|3|4|Flying| +Rally for the Throne|Throne of Eldraine|25|U|{2}{W}|Instant|||Create two 1/1 white Human creature tokens.$Adamant — If at least three white mana was spent to cast this spell, you gain 1 life for each creature you control.| +Cast Off|Throne of Eldraine|26|M|{3}{W}{W}|Sorcery - Adventure|7|7|Destroy all non-Giant creatures.| +Realm-Cloaked Giant|Throne of Eldraine|26|M|{5}{W}{W}|Creature - Giant|7|7|Vigilance| +Righteousness|Throne of Eldraine|27|U|{W}|Instant|||Target blocking creature gets +7/+7 until end of turn.| +Shepherd of the Flock|Throne of Eldraine|28|U|{1}{W}|Creature - Human Peasant|3|1|| +Usher to Safety|Throne of Eldraine|28|U|{W}|Instant - Adventure|3|1|Return target permanent you control to its owner's hand.| Shining Armor|Throne of Eldraine|29|C|{1}{W}|Artifact - Equipment|||Flash$When Shining Armor enters the battlefield, attach it to target Knight you control.$Equipped creature gets +0/+2 and has vigilance.$Equip {3}| Silverflame Ritual|Throne of Eldraine|30|C|{3}{W}|Sorcery|||Put a +1/+1 counter on each creature you control.$Adamant — If at least three white mana was spent to cast this spell, creatures you control gain vigilance until end of turn.| +On Alert|Throne of Eldraine|31|C|{2}{W}|Instant - Adventure|2|1|Target creature gets +2/+2 until end of turn. Untap it.| +Silverflame Squire|Throne of Eldraine|31|C|{1}{W}|Creature - Human Soldier|2|1|| +Syr Alin, the Lion's Claw|Throne of Eldraine|32|U|{3}{W}{W}|Legendary Creature - Human Knight|4|4|First strike$Whenever Syr Alin, the Lion's Claw attacks, other creatures you control get +1/+1 until end of turn.| +Trapped in the Tower|Throne of Eldraine|33|C|{1}{W}|Enchantment - Aura|||Enchant creature without flying$Enchanted creature can't attack or block, and its activated abilities can't be activated.| +True Love's Kiss|Throne of Eldraine|34|C|{2}{W}{W}|Instant|||Exile target artifact or enchantment.$Draw a card| +Venerable Knight|Throne of Eldraine|35|U|{W}|Creature - Human Knight|2|1|When Venerable Knight dies, put a +1/+1 counter on target Knight you control.| +Worthy Knight|Throne of Eldraine|36|R|{1}{W}|Creature - Human Knight|2|2|Whenever you cast a Knight spell, create a 1/1 white Human creature token.| +Youthful Knight|Throne of Eldraine|37|C|{1}{W}|Creature - Human Knight|2|1|First strike| Animating Faerie|Throne of Eldraine|38|U|{2}{U}|Creature - Faerie|2|2|Flying| Bring to Life|Throne of Eldraine|38|U|{2}{U}|Sorcery - Adventure|2|2|Target noncreature artifact you control becomes a 0/0 artifact creature. Put four +1/+1 counters on it.| +Brazen Borrower|Throne of Eldraine|39|M|{1}{U}{U}|Creature - Faerie Rogue|3|1|Flash$Flying$Brazen Borrower can block only creatures with flying.| +Petty Theft|Throne of Eldraine|39|M|{1}{U}|Instant - Adventure|3|1|Return target nonland permanent an opponent controls to its owner's hand.| +Charmed Sleep|Throne of Eldraine|40|C|{1}{U}{U}|Enchantment - Aura|||Enchant creature$When Charmed Sleep enters the battlefield, tap enchanted creature.$Enchanted creature doesn't untap during its controller's untap step.| Corridor Monitor|Throne of Eldraine|41|C|{1}{U}|Artifact Creature - Construct|1|4|When Corridor Monitor enters the battlefield, untap target artifact or creature you control.| +Didn't Say Please|Throne of Eldraine|42|C|{1}{U}{U}|Instant|||Counter target spell. Its controller puts the top three cards of their library into their graveyard.| +Emry, Lurker of the Loch|Throne of Eldraine|43|R|{2}{U}|Legendary Creature - Merfolk Wizard|1|2|This spell costs {1} less to cast for each artifact you control.$When Emry, Lurker of the Loch enters the battlefield, put the top four cards of your library into your graveyard.${T}: Choose target artifact card in your graveyard. You may cast that card this turn.| +Fae of Wishes|Throne of Eldraine|44|R|{1}{U}|Creature - Faerie Wizard|1|4|Flying${1}{U}, Discard two cards: Return Fae of Wishes to its owner's hand.| +Granted|Throne of Eldraine|44|R|{3}{U}|Sorcery - Adventure|1|4|You may choose a noncreature card you own from outside the game, reveal it, and put it into your hand.| Faerie Vandal|Throne of Eldraine|45|U|{1}{U}|Creature - Faerie Rogue|1|2|Flash$Flying$Whenever you draw your second card each turn, put a +1/+1 counter on Faerie Vandal.| +Folio of Fancies|Throne of Eldraine|46|R|{1}{U}|Artifact|||Players have no maximum hand size.${X}{X}, {T}: Each player draws X cards.${2}{U}, {T}: Each opponent puts a number of cards equal to the number of cards in their hand from the top of their library into their graveyard.| Frogify|Throne of Eldraine|47|U|{1}{U}|Enchantment - Aura|||Enchant creature$Enchanted creature loses all abilities and is a blue Frog creature with base power and toughness 1/1.| +Gadwick, the Wizened|Throne of Eldraine|48|R|{X}{U}{U}{U}|Legendary Creature - Human Wizard|3|3|When Gadwick, the Wizened enters the battlefield, draw X cards.$Whenever you cast a blue spell, tap target nonland permanent an opponent controls.| +Hypnotic Sprite|Throne of Eldraine|49|U|{U}{U}|Creature - Faerie|2|1|Flying| +Mesmeric Glare|Throne of Eldraine|49|U|{2}{U}|Instant - Adventure|2|1|Counter target spell with converted mana cost 3 or less.| +Into the Story|Throne of Eldraine|50|U|{5}{U}{U}|Instant|||This spell costs {3} less to cast if an opponent has seven or more cards in their graveyard.$Draw four cards.| +The Magic Mirror|Throne of Eldraine|51|M|{6}{U}{U}{U}|Legendary Artifact|||This spell costs {1} less to cast for each instant and sorcery card in your graveyard.$You have no maximum hand size.$At the beginning of your upkeep, put a knowledge counter on The Magic Mirror, then draw a card for each knowledge counter on The Magic Mirror.| +Mantle of Tides|Throne of Eldraine|52|C|{U}|Artifact - Equipment|||Equipped creature gets +1/+2.$Whenever you draw your second card each turn, attach Mantle of Tides to target creature you control.$Equip {3}| +Merfolk Secretkeeper|Throne of Eldraine|53|C|{U}|Creature - Merfolk Wizard|0|4|| +Venture Deeper|Throne of Eldraine|53|C|{U}|Sorcery - Adventure|0|4|Target player puts the top four cards of their library into their graveyard.| Midnight Clock|Throne of Eldraine|54|R|{2}{U}|Artifact|||{T}: Add {U}.${2}{U}: Put an hour counter on Midnight Clock.$At the beginning of each upkeep, put an hour counter on Midnight Clock.$When the twelfth hour counter is put on Midnight Clock, shuffle your hand and graveyard into your library, then draw seven cards. Exile Midnight Clock.| +Mirrormade|Throne of Eldraine|55|R|{1}{U}{U}|Enchantment|||You may have Mirrormade enter the battlefield as a copy of any artifact or enchantment on the battlefield.| +Mistford River Turtle|Throne of Eldraine|56|C|{3}{U}|Creature - Turtle|1|5|Whenever Mistford River Turtle attacks, another target attacking non-Human creature can't be blocked this turn.| +Moonlit Scavengers|Throne of Eldraine|57|C|{5}{U}|Creature - Merfolk Rogue|4|5|When Moonlit Scavengers enters the battlefield, if you control an artifact or enchantment, return target creature an opponent controls to its owner's hand.| +Mystical Dispute|Throne of Eldraine|58|U|{2}{U}|Instant|||This spell costs {2} less to cast if it targets a blue spell.$Counter target spell unless its controller pays {3}.| +Opt|Throne of Eldraine|59|C|{U}|Instant|||Scry 1.$Draw a card.| +Overwhelmed Apprentice|Throne of Eldraine|60|U|{U}|Creature - Human Wizard|1|2|When Overwhelmed Apprentice enters the battlefield, each opponent puts the top two cards of their library into their graveyard. Then you scry 2.| +Queen of Ice|Throne of Eldraine|61|C|{2}{U}|Creature - Human Noble Wizard|2|3|Whenever Queen of Ice deals combat damage to a creature, tap that creature. It doesn't untap during its controller's next untap step.| +Rage of Winter|Throne of Eldraine|61|C|{1}{U}|Sorcery - Adventure|2|3|Tap target creature. It doesn't untap during its controller's next untap step.| Run Away Together|Throne of Eldraine|62|C|{1}{U}|Instant|||Choose two target creatures controlled by different players. Return those creatures to their owners' hands.| +Sage of the Falls|Throne of Eldraine|63|U|{4}{U}|Creature - Merfolk Wizard|2|5|Whenever Sage of the Falls or another non-Human creature enters the battlefield under you control, you may draw a card. If you do, discard a card.| +So Tiny|Throne of Eldraine|64|C|{U}|Enchantment - Aura|||Flash$Enchant creature$Enchanted creature gets -2/-0. It gets -6/-0 instead as long as its controller has seven or more cards in their graveyard.| +Steelgaze Griffin|Throne of Eldraine|65|C|{4}{U}|Creature - Griffin|2|4|Flying$When you draw your second card each turn, Steelgaze Griffin gets +2/+0 until end of turn.| +Stolen by the Fae|Throne of Eldraine|66|R|{X}{U}{U}|Sorcery|||Return target creature with converted mana cost X to its owner's hand. You create X 1/1 blue Faerie creature tokens with flying.| +Syr Elenora, the Discerning|Throne of Eldraine|67|U|{3}{U}{U}|Legendary Creature - Human Knight|*|4|Syr Elenora, the Discerning's power is equal to the number of cards in your hand.$When Syr Elenora enters the battlefield, draw a card.$Spells your opponents cast that target Syr Elenora cost {2} more to cast.| Tome Raider|Throne of Eldraine|68|C|{2}{U}|Creature - Faerie|1|1|Flying$When Tome Raider enters the battlefield, draw a card.| +Turn into a Pumpkin|Throne of Eldraine|69|U|{3}{U}|Instant|||Return target nonland permanent to its owner's hand. Draw a card.$Adamant — If at least three blue mana was spent to cast this spell, create a Food token.| +Unexplained Vision|Throne of Eldraine|70|C|{4}{U}|Sorcery|||Draw three cards.$Adamant — If at least three blue mana was spent to cast this spell, scry 3.| +Vantress Gargoyle|Throne of Eldraine|71|R|{1}{U}|Artifact Creature - Gargoyle|5|4|Flying$Vantress Gargoyle can't attack unless defending player has seven or more cards in their graveyard.$Vantress Gargoyle can't block unless you have four or more cards in hand.${T}: Each player puts the top card of their library into their graveyard.| +Vantress Paladin|Throne of Eldraine|72|C|{3}{U}|Creature - Human Knight|2|2|Flying$Adamant — If at least three blue mana was spent to cast this spell, Vantress Paladin enters the battlefield with an additional +1/+1 counter on it.| Wishful Merfolk|Throne of Eldraine|73|C|{1}{U}|Creature - Merfolk|3|2|Defender${1}{U}: Wishful Merfolk loses defender and becomes a Human until end of turn.| Witching Well|Throne of Eldraine|74|C|{U}|Artifact|||When Witching Well enters the battlefield, scry 2.${3}{U}, Sacrifice Witching Well: Draw two cards.| +Ayara, First of Locthwain|Throne of Eldraine|75|R|{B}{B}{B}|Legendary Creature - Elf Noble|2|3|Whenever Ayara, First of Locthwain or another black creature enters the battlefield under your control, each opponent loses 1 life and you gain 1 life.${T}, Sacrifice another black creature: Draw a card.| Bake into a Pie|Throne of Eldraine|76|C|{2}{B}{B}|Instant|||Destroy target creature. Create a Food token.| +Barrow Witches|Throne of Eldraine|77|C|{4}{B}|Creature - Human Warlock|3|4|When Barrow Witches enters the battlefield, return target Knight card from your graveyard to your hand.| Belle of the Brawl|Throne of Eldraine|78|U|{2}{B}|Creature - Human Knight|3|2|Menace$Whenever Belle of the Brawl attacks, other Knights you control get +1/+0 until end of turn.| +Blacklance Paragon|Throne of Eldraine|79|R|{1}{B}|Creature - Human Knight|3|1|Flash$When Blacklance Paragon enters the battlefield, target Knight gains deathtouch and lifelink until end of turn.| +Bog Naughty|Throne of Eldraine|80|U|{3}{B}{B}|Creature - Faerie|3|3|Flying${2}{B}, Sacrifice a Food: Target creature gets -3/-3 until end of turn.| +Cauldron Familiar|Throne of Eldraine|81|U|{B}|Creature - Cat|1|1|When Cauldron Familiar enters the battlefield, each opponent loses 1 life and you gain 1 life.$Sacrifice a Food: Return Cauldron Familiar from your graveyard to the battlefield.| +The Cauldron of Eternity|Throne of Eldraine|82|M|{10}{B}{B}|Legendary Artifact|||This spell costs {2} less for each creature card in your graveyard.$Whenever a creature you control dies, put it on the bottom of its owner's library.${2}{B}, {T}, Pay 2 life: Return target creature card from your graveyard to the battlefield. Activate this ability only any time you could cast a sorcery.| +Cauldron's Gift|Throne of Eldraine|83|U|{4}{B}|Sorcery|||Adamant — If at least three black mana was spent to cast this spell, put the top four cards of your library into your graveyard.$You may choose a creature card in your graveyard. If you do, return it to the battlefield with an additional +1/+1 counter on it.| +Clackbridge Troll|Throne of Eldraine|84|R|{3}{B}{B}|Creature - Troll|8|8|Trample, haste$When Clackbridge Troll enters the battlefield, target opponent creates three 0/1 white Goat creature tokens.$At the beginning of combat on your turn, any opponent may sacrifice a creature. If a player does, tap Clackbridge Troll, you gain 3 life, and you draw a card.| +Epic Downfall|Throne of Eldraine|85|U|{1}{B}|Sorcery|||Exile target creature with converted mana cost 3 or greater.| Eye Collector|Throne of Eldraine|86|C|{B}|Creature - Faerie|1|1|Flying$Whenever Eye Collector deals combat damage to a player, each player puts the top card of their library into their graveyard.| +Festive Funeral|Throne of Eldraine|87|C|{4}{B}|Instant|||Target creature gets -X/-X until end of turn, where X is the number of cards in your graveyard.| +Foreboding Fruit|Throne of Eldraine|88|C|{2}{B}|Sorcery|||Target player draws two cards and loses 2 life.$Adamant — If at least three black mana was spent to cast this spell, create a Food token.| +Forever Young|Throne of Eldraine|89|C|{1}{B}|Sorcery|||Put any number of target creature cards from your graveyard on top of your library.$Draw a card.| Foulmire Knight|Throne of Eldraine|90|U|{B}|Creature - Zombie Knight|1|1|Deathtouch| Profane Insight|Throne of Eldraine|90|U|{2}{B}|Instant - Adventure|1|1|You draw a card and you lose 1 life.| +Giant's Skewer|Throne of Eldraine|91|C|{1}{B}|Artifact - Equipment|||Equipped creature gets +2/+1.$Whenever equipped creature deals combat damage to a creature, create a Food token.$Equip {3}| +Lash of Thorns|Throne of Eldraine|92|C|{B}|Instant|||Target creature gets +2/+1 and gains deathtouch until end of turn.| +Locthwain Paladin|Throne of Eldraine|93|C|{3}{B}|Creature - Human Knight|3|2|Menace$Adamant — If at least three black mana was spent to cast this spell, Locthwain Paladin enters the battlefield with a +1/+1 counter on it.| +Lost Legion|Throne of Eldraine|94|C|{1}{B}{B}|Creature - Spirit Knight|2|3|When Lost Legion enters the battlefield, scry 2.| +Malevolent Noble|Throne of Eldraine|95|C|{1}{B}|Creature - Human Noble|2|2|{2}, Sacrifice an artifact or another creature: Put a +1/+1 counter on Malevolent Noble.| +Memory Theft|Throne of Eldraine|96|C|{2}{B}|Sorcery|||Target opponent reveals their hand. You choose a nonland card from it. That player discards that card. You may put a card that has an Adventure that player owns from exile into that player's graveyard.| +Murderous Rider|Throne of Eldraine|97|R|{1}{B}{B}|Creature - Zombie Knight|2|3|Lifelink$When Murderous Rider dies, put it on the bottom of its owner's library.| +Swift End|Throne of Eldraine|97|R|{1}{B}{B}|Instant - Adventure|2|3|Destroy target creature or planeswalker. You lose 2 life.| +Oathsworn Knight|Throne of Eldraine|98|R|{1}{B}{B}|Creature - Human Knight|0|0|Oathsworn Knight enters the battlefield with four +1/+1 counters on it.$Oathsworn Knight attacks each combat if able.$If damage would be dealt to Oathsworn Knight while it has a +1/+1 counter on it, prevent that damage and remove a +1/+1 counter from it.| Alter Fate|Throne of Eldraine|99|U|{1}{B}|Sorcery - Adventure|2|2|Return target creature card from your graveyard to your hand.| Order of Midnight|Throne of Eldraine|99|U|{1}{B}|Creature - Human Knight|2|2|Flying$Order of Midnight can't block.| Piper of the Swarm|Throne of Eldraine|100|R|{1}{B}|Creature - Human Warlock|1|3|Rats you control have menace.${1}{B}, {T}: Create a 1/1 black Rat creature token.${2}{B}{B}, {T}, Sacrifice three Rats: Gain control of target creature.| Rankle, Master of Pranks|Throne of Eldraine|101|M|{2}{B}{B}|Legendary Creature - Faerie Rogue|3|3|Flying, haste$Whenever Rankle, Master of Pranks deals combat damage to a player, choose any number —$• Each player discards a card.$• Each player loses 1 life and draws a card.$• Each player sacrifices a creature.| +Harvest Fear|Throne of Eldraine|102|C|{3}{B}|Sorcery - Adventure|4|5|Target opponent discards two cards.| +Reaper of Night|Throne of Eldraine|102|C|{5}{B}{B}|Creature - Specter|4|5|Whenever Reaper of Night attacks, if defending player has two or fewer cards in hand, it gains flying until end of turn.| +Reave Soul|Throne of Eldraine|103|C|{1}{B}|Sorcery|||Destroy target creature with power 3 or less.| +Revenge of Ravens|Throne of Eldraine|104|U|{3}{B}|Enchantment|||Whenever a creature attacks you or a planeswalker you control, that creature's controller loses 1 life and you gain 1 life.| Curry Favor|Throne of Eldraine|105|C|{B}|Sorcery - Adventure|2|1|You gain X life and each opponent loses X life, where X is the number of Knights you control.| Smitten Swordmaster|Throne of Eldraine|105|C|{1}{B}|Creature - Human Knight|2|1|Lifelink| +Specter's Shriek|Throne of Eldraine|106|U|{B}|Sorcery|||Target opponent reveals their hand. You may choose a nonland card from it. If you do, that player exiles that card. If a nonblack card is exiled this way, exile a card from your hand.| Syr Konrad, the Grim|Throne of Eldraine|107|U|{3}{B}{B}|Legendary Creature - Human Knight|5|4|Whenever another creature dies, or a creature card is put into a graveyard from anywhere other than the battlefield, or a creature card leaves your graveyard, Syr Konrad, the Grim deals 1 damage to each opponent.${1}{B}: Each player puts the top card of their library into their graveyard.| +Tempting Witch|Throne of Eldraine|108|C|{2}{B}|Creature - Human Warlock|1|3|When Tempting Witch enters the battlefield, create a Food token.${2}, {T}, Sacrifice a Food: Target player loses 3 life.| +Wicked Guardian|Throne of Eldraine|109|C|{3}{B}|Creature - Human Noble|4|2|When Wicked Guardian enters the battlefield, you may have it deal 2 damage to another creature you control. If you do, draw a card.| +Wishclaw Talisman|Throne of Eldraine|110|R|{1}{B}|Artifact|||Wishclaw Talisman enters the battlefield with three wish counters on it.${1}, {T}, Remove a wish counter from Wishclaw Talisman: Search your library for a card, put it into your hand, then shuffle your library. An opponent gains control of Wishclaw Talisman. Activate this ability only during your turn.| +Witch's Vengeance|Throne of Eldraine|111|R|{1}{B}{B}|Sorcery|||Creatures of the creature type of your choice get -3/-3 until end of turn.| +Barge In|Throne of Eldraine|112|C|{R}|Instant|||Target attacking creature gets +2/+2 until end of turn. Each attacking non-Human creature gains trample until end of turn.| +Bloodhaze Wolverine|Throne of Eldraine|113|C|{1}{R}|Creature - Wolverine|2|1|Whenever you draw your second card each turn, Bloodhaze Wolverine gets +1/+1 and gains first strike until end of turn.| +Blow Your House Down|Throne of Eldraine|114|C|{2}{R}|Sorcery|||Up to three target creatures can't block this turn. Destroy any of them that are Walls.| +Bonecrusher Giant|Throne of Eldraine|115|R|{2}{R}|Creature - Giant|4|3|Whenever Bonecrusher Giant becomes the target of a spell, Bonecrusher Giant deals 2 damage to that spell's controller.| +Stomp|Throne of Eldraine|115|R|{1}{R}|Instant - Adventure|4|3|Damage can't be prevented this turn. Stomp deals 2 damage to any target.| +Brimstone Trebuchet|Throne of Eldraine|116|C|{2}{R}|Artifact Creature - Wall|1|3|Defender, reach${T}: Brimstone Trebuchet deals 1 damage to each opponent.$Whenever a Knight enters the battlefield under your control, untap Brimstone Trebuchet.| +Burning-Yard Trainer|Throne of Eldraine|117|U|{4}{R}|Creature - Human Knight|3|3|Trample, haste$When Burning-Yard Trainer enters the battlefield, another target Knight you control gets +2/+2 and gains trample and haste until end of turn.| +Claim the Firstborn|Throne of Eldraine|118|U|{R}|Sorcery|||Gain control of target creature with converted mana cost 3 or less until end of turn. Untap that creature. It gains haste until end of turn.| Crystal Slipper|Throne of Eldraine|119|C|{1}{R}|Artifact - Equipment|||Equipped creature gets +1/+0 and has haste.$Equip {1}| +Embercleave|Throne of Eldraine|120|M|{4}{R}{R}|Legendary Artifact - Equipment|||Flash$This spell costs {1} less to cast for each attacking creature you control.$When Embercleave enters the battlefield, attach it to target creature you control.$Equipped creature gets +1/+1 and has double strike and trample.$Equip {3}| Embereth Paladin|Throne of Eldraine|121|C|{3}{R}|Creature - Human Knight|4|1|Haste$Adamant — If at least three red mana was spent to cast this spell, Embereth Paladin enters the battlefield with a +1/+1 counter on it.| Battle Display|Throne of Eldraine|122|U|{R}|Sorcery - Adventure|2|1|Destroy target artifact.| Embereth Shieldbreaker|Throne of Eldraine|122|U|{1}{R}|Creature - Human Knight|2|1|| +Ferocity of the Wilds|Throne of Eldraine|123|U|{2}{R}|Enchantment|||Attacking non-Human creatures you control get +1/+0 and have trample.| +Fervent Champion|Throne of Eldraine|124|R|{R}|Creature - Human Knight|1|1|First strike, haste$Whenever Fervent Champion attacks, another target attacking Knight you control gets +1/+0 until end of turn.$Equip abilities you activate that target Fervent Champion cost {3} less to activate.| +Fires of Invention|Throne of Eldraine|125|R|{3}{R}|Enchantment|||You can cast spells only during your turn and you can cast no more than two spells each turn.$You may cast spells with converted mana cost less than or equal to the number of lands you control without paying their mana costs.| +Fling|Throne of Eldraine|126|C|{1}{R}|Instant|||As an additional cost to cast this spell, sacrifice a creature.$Fling deals damage equal to the sacrificed creature's power to any target.| +Irencrag Feat|Throne of Eldraine|127|R|{1}{R}{R}{R}|Sorcery|||Add seven {R}. You can cast only one more spell this turn.| +Irencrag Pyromancer|Throne of Eldraine|128|R|{2}{R}|Creature - Human Wizard|0|4|Whenever you draw your second card each turn, Irencrag Pyromancer deals 3 damage to any target.| +Joust|Throne of Eldraine|129|U|{1}{R}|Sorcery|||Choose target creature you control and target creature you don't control. The creature you control gets +2/+1 until end of turn if it's a Knight. Then those creatures fight each other.| +Mad Ratter|Throne of Eldraine|130|U|{3}{R}|Creature - Goblin|1|2|Whenever you draw your second card each turn, create two 1/1 black Rat creature tokens.| +Haggle|Throne of Eldraine|131|C|{R}|Instant - Adventure|2|3|You may discard a card. If you do, draw a card.| +Merchant of the Vale|Throne of Eldraine|131|C|{2}{R}|Creature - Human Peasant|2|3|{2}{R}, Discard a card: Draw a card.| +Ogre Errant|Throne of Eldraine|132|C|{3}{R}|Creature - Ogre Knight|3|4|Whenever Ogre Errant attacks, another target attacking Knight gains menace until end of turn.| +Opportunistic Dragon|Throne of Eldraine|133|R|{2}{R}{R}|Creature - Dragon|4|3|Flying$When Opportunistic Dragon enters the battlefield, choose target Human or artifact an opponent controls. For as long as Opportunistic Dragon remains on the battlefield, gain control of that permanent, it loses all abilities, and it can't attack or block.| +Raging Redcap|Throne of Eldraine|134|C|{2}{R}|Creature - Goblin Knight|1|2|Double strike| +Redcap Melee|Throne of Eldraine|135|U|{R}|Instant|||Redcap Melee deals 4 damage to target creature or planeswalker. If a nonred permanent is dealt damage this way, you sacrifice a land.| +Redcap Raiders|Throne of Eldraine|136|C|{2}{R}|Creature - Goblin Warrior|3|2|Whenever Redcap Raiders attacks, you may tap an untapped non-Human creature you control. If you do, Redcap Raiders gets +1/+1 and gains trample until end of turn.| +Boulder Rush|Throne of Eldraine|137|C|{R}|Instant - Adventure|3|1|Target creature gets +2/+0 until end of turn.| +Rimrock Knight|Throne of Eldraine|137|C|{1}{R}|Creature - Dwarf Knight|3|1|Rimrock Knight can't block| +Robber of the Rich|Throne of Eldraine|138|M|{1}{R}|Creature - Human Archer Rogue|2|2|Reach, haste$Whenever Robber of the Rich attacks, if defending player has more cards in hand than you, exile the top card of their library. During any turn you attacked with a Rogue, you may cast that card and you may spend mana as though it were mana of any color to cast that spell.| +Scorching Dragonfire|Throne of Eldraine|139|C|{1}{R}|Instant|||Scorching Dragonfire deals 3 damage to target creature or planeswalker. If that creature or planeswalker would die this turn, exile it instead.| +Searing Barrage|Throne of Eldraine|140|C|{4}{R}|Instant|||Searing Barrage deals 5 damage to target creature.$Adamant — If at least three red mana was spent to cast this spell, Searing Barrage deals 3 damage to that creature's controller.| +Seven Dwarves|Throne of Eldraine|141|C|{1}{R}|Creature - Dwarf|2|2|Seven Dwarves gets +1/+1 for each other creature named Seven Dwarves you control.$A deck can have up to seven cards named Seven Dwarves.| +Skullknocker Ogre|Throne of Eldraine|142|U|{3}{R}|Creature - Ogre|4|3|Whenever Skullknocker Ogre deals damage to an opponent, that player discards a card at random. If the player does, they draw a card.| Slaying Fire|Throne of Eldraine|143|U|{2}{R}|Instant|||Slaying Fire deals 3 damage to any target.$Adamant — If at least three red mana was spent to cast this spell, it deals 4 damage instead.| +Sundering Stroke|Throne of Eldraine|144|R|{6}{R}|Sorcery|||Sundering Stroke deals 7 damage divided as you choose among one, two, or three targets. If at least seven red mana was spent to cast this spell, instead Sundering Stroke deals 7 damage to each of those permanents and/or players.| +Syr Carah, the Bold|Throne of Eldraine|145|U|{3}{R}{R}|Legendary Creature - Human Knight|3|3|When Syr Carah, the Bold or an instant or sorcery spell you control deals damage to a player, exile the top card of your library. You may play that card this turn.${T}: Syr Carah deals 1 damage to any target.| +Thrill of Possibility|Throne of Eldraine|146|C|{1}{R}|Instant|||As an additional cost to cast this spell, discard a card.$Draw two cards.| +Torbran, Thane of Red Fell|Throne of Eldraine|147|R|{1}{R}{R}{R}|Legendary Creature - Dwarf Noble|2|4|If a red source you control would deal damage to an opponent or a permanent an opponent controls, it deals that much damage plus 2 instead.| +Weaselback Redcap|Throne of Eldraine|148|C|{R}|Creature - Goblin Knight|1|1|{1}{R}: Weaselback Redcap gets +2/+0 until end of turn.| Beanstalk Giant|Throne of Eldraine|149|U|{6}{G}|Creature - Giant|*|*|Beanstalk Giant's power and toughness are each equal to the number of lands you control.| Fertile Footsteps|Throne of Eldraine|149|U|{2}{G}|Sorcery - Adventure|*|*|Search your library for a basic land card, put it onto the battlefield, then shuffle your library.| +Curious Pair|Throne of Eldraine|150|C|{1}{G}|Creature - Human Peasant|1|3|| +Treats to Share|Throne of Eldraine|150|C|{G}|Sorcery - Adventure|1|3|Create a Food token.| +Edgewall Innkeeper|Throne of Eldraine|151|U|{G}|Creature - Human Peasant|1|1|Whenever you cast a creature spell that has an Adventure, draw a card.| +Feasting Troll King|Throne of Eldraine|152|R|{2}{G}{G}{G}{G}|Creature - Troll Noble|7|6|Vigilance, trample$When Feasting Troll King enters the battlefield, if you cast it from your hand, create three Food tokens.$Sacrifice three Foods: Return Feasting Troll King from your graveyard to the battlefield. Activate this ability only during your turn.| +Fell the Pheasant|Throne of Eldraine|153|C|{1}{G}|Instant|||Fell the Pheasant deals 5 damage to target creature with flying. Create a Food token.| +Fierce Witchstalker|Throne of Eldraine|154|C|{2}{G}{G}|Creature - Wolf|4|4|Trample$When Fierce Witchstalker enters the battlefield, create a Food token.| Flaxen Intruder|Throne of Eldraine|155|U|{G}|Creature - Human Berserker|1|2|Whenever Flaxen Intruder deals combat damage to a player, you may sacrifice it. When you do, destroy target artifact or enchantment.| Welcome Home|Throne of Eldraine|155|U|{5}{G}{G}|Sorcery - Adventure|1|2|Create three 2/2 green Bear creature tokens.| +Garenbrig Carver|Throne of Eldraine|156|C|{3}{G}|Creature - Human Warrior|3|2|| +Shield's Might|Throne of Eldraine|156|C|{1}{G}|Instant - Adventure|3|2|Target creature gets +2/+2 until end of turn.| +Garenbrig Paladin|Throne of Eldraine|157|C|{4}{G}|Creature - Giant Knight|4|4|Adamant — If at least three green mana was spent to cast this spell, Garenbrig Paladin enters the battlefield with a +1/+1 counter on it.$Garenbrig Paladin can't be blocked by creatures with power 2 or less.| +Garenbrig Squire|Throne of Eldraine|158|C|{1}{G}|Creature - Human Soldier|2|2|Whenever you cast a creature spell that has an Adventure, Garenbrig Squire gets +1/+1 until end of turn.| +Giant Opportunity|Throne of Eldraine|159|U|{2}{G}|Sorcery|||You may sacrifice two Foods. If you do, create a 7/7 green Giant creature token. Otherwise, create three Food tokens.| Gilded Goose|Throne of Eldraine|160|R|{G}|Creature - Bird|0|2|Flying$When Gilded Goose enters the battlefield, create a Food token.${1}{G}, {T}: Create a Food token.${T}, Sacrifice a Food: Add one mana of any color.| +The Great Henge|Throne of Eldraine|161|M|{7}{G}{G}|Legendary Artifact|||This spell costs {X} less to cast, where X is the greatest power among creatures you control.${T}: Add {G}{G}. You gain 2 life.$Whenever a nontoken creature enters the battlefield under your control, put a +1/+1 counter on it and draw a card.| +Insatiable Appetite|Throne of Eldraine|162|C|{1}{G}|Instant|||You may sacrifice a Food. If you do, target creature gets +5/+5 until end of turn. Otherwise, that creature gets +3/+3 until end of turn.| Keeper of Fables|Throne of Eldraine|163|U|{3}{G}{G}|Creature - Cat|4|5|Whenever one or more non-Human creatures you control deal combat damage to a player, draw a card.| +Kenrith's Transformation|Throne of Eldraine|164|U|{1}{G}|Enchantment - Aura|||Enchant creature$When Kenrith's Transformation enters the battlefield, draw a card.$Enchanted creature loses all abilities and is a green Elk creature with base power and toughness 3/3.| Heart's Desire|Throne of Eldraine|165|R|{G}|Sorcery - Adventure|5|5|Create a 1/1 white Human creature token.| Lovestruck Beast|Throne of Eldraine|165|R|{2}{G}|Creature - Beast Noble|5|5|Lovestruck Beast can't attack unless you control a 1/1 creature.| +Maraleaf Rider|Throne of Eldraine|166|C|{1}{G}|Creature - Elf Knight|3|1|Sacrifice a Food: Target creature blocks Maraleaf Rider this turn if able.| +Oakhame Adversary|Throne of Eldraine|167|U|{3}{G}|Creature - Elf Warrior|2|3|This spell costs {2} less to cast if your opponent controls a green permanent.$Deathtouch$Whenever Oakhame Adversary deals combat damage to a player, draw a card.| +Once and Future|Throne of Eldraine|168|U|{3}{G}|Instant|||Return target card from your graveyard to your hand. Put up to one other target card from your graveyard on top of your library. Exile Once and Future.$Adamant — If at least three green mana was spent to cast this spell, instead return those cards to your hand and exile Once and Future.| +Once Upon a Time|Throne of Eldraine|169|R|{1}{G}|Instant|||If this spell is the first spell you've cast this game, you may cast it without paying its mana cost.$Look at the top five cards of your library. You may reveal a creature or land card from among them and put it into your hand. Put the rest on the bottom of your library in a random order.| +Outmuscle|Throne of Eldraine|170|C|{3}{G}|Sorcery|||Put a +1/+1 counter on target creature you control, then it fights target creature you don't control.$Adamant — If at least three green mana was spent to cast this spell, the creature you control gains indestructible until end of turn.| +Questing Beast|Throne of Eldraine|171|M|{2}{G}{G}|Legendary Creature - Beast|4|4|Vigilance, deathtouch, haste$Questing Beast can't be blocked by creatures with power 2 or less.$Combat damage that would be dealt by creatures you control can't be prevented.$Whenever Questing Beast deals combat damage to an opponent, it deals that much damage to target planeswalker that player controls.| +Return of the Wildspeaker|Throne of Eldraine|172|R|{4}{G}|Instant|||Choose one —$• Draw cards equal to the greatest power among non-Human creatures you control.$• Non-Human creatures you control get +3/+3 until end of turn.| +Return to Nature|Throne of Eldraine|173|C|{1}{G}|Instant|||Choose one —$• Destroy target artifact.$• Destroy target enchantment.$• Exile target card from a graveyard.| Rosethorn Acolyte|Throne of Eldraine|174|C|{2}{G}|Creature - Elf Druid|2|3|{T}: Add one mana of any color.| Seasonal Ritual|Throne of Eldraine|174|C|{G}|Sorcery - Adventure|2|3|Add one mana of any color.| +Rosethorn Halberd|Throne of Eldraine|175|C|{G}|Artifact - Equipment|||When Rosethorn Halberd enters the battlefield, attach it to target non-Human creature you control.$Equipped creature gets +2/+1.$Equip {5}| +Sporecap Spider|Throne of Eldraine|176|C|{2}{G}|Creature - Spider|1|5|Reach| +Syr Faren, the Hengehammer|Throne of Eldraine|177|U|{G}{G}|Legendary Creature - Human Knight|2|2|Whenever Syr Faren, the Hengehammer attacks, another target attacking creature gets +X/+X until end of turn, where X is Syr Faren's power.| +Tall as a Beanstalk|Throne of Eldraine|178|C|{3}{G}|Enchantment - Aura|||Enchant creature$Enchanted creature gets +3/+3, has reach, and is a Giant in addition to its other types.| +Trail of Crumbs|Throne of Eldraine|179|U|{1}{G}|Enchantment|||When Trail of Crumbs enters the battlefield, create a Food token.$Whenever you sacrifice a Food, you may pay {1}. If you do, look at the top two cards of your library. You may reveal a permanent card from among them and put it into your hand. Put the rest on the bottom of your library in any order.| +Oaken Boon|Throne of Eldraine|180|C|{3}{G}|Sorcery - Adventure|6|5|Put two +1/+1 counters on target creature.| +Tuinvale Treefolk|Throne of Eldraine|180|C|{5}{G}|Creature - Treefolk Druid|6|5|| +Wicked Wolf|Throne of Eldraine|181|R|{2}{G}{G}|Creature - Wolf|3|3|When Wicked Wolf enters the battlefield, it fights up to one target creature you don't control.$Sacrifice a Food: Put a +1/+1 counter on Wicked Wolf. It gains indestructible until end of turn. Tap it.| +Wildborn Preserver|Throne of Eldraine|182|R|{1}{G}|Creature - Elf Archer|2|2|Flash$Reach$Whenever another non-Human creature enters the battlefield under your control, you may pay {X}. When you do, put X +1/+1 counters on Wildborn Preserver.| +Wildwood Tracker|Throne of Eldraine|183|C|{G}|Creature - Elf Warrior|1|1|Whenever Wildwood Tracker attacks or blocks, if you control another non-Human creature, Wildwood Tracker gets +1/+1 until end of turn.| +Wolf's Quarry|Throne of Eldraine|184|C|{4}{G}{G}|Sorcery|||Create three 1/1 green Boar creature tokens with "When this creature dies, create a Food token."| +Yorvo, Lord of Garenbrig|Throne of Eldraine|185|R|{G}{G}{G}|Legendary Creature - Giant Noble|0|0|Yorvo, Lord of Garenbrig enters the battlefield with four +1/+1 counters on it.$Whenever another green creature enters the battlefield under your control, put a +1/+1 counter on Yorvo. Then if that creature's power is greater than Yorvo's power, put another +1/+1 counter on Yorvo.| +Dance of the Manse|Throne of Eldraine|186|R|{X}{W}{U}|Sorcery|||Return up to X target artifact and/or non-Aura enchantment cards each with converted mana cost X or less from your graveyard to the battlefield. If X is 6 or more, those permanents are 4/4 creatures in addition to their other types.| +Doom Foretold|Throne of Eldraine|187|R|{2}{W}{B}|Enchantment|||At the beginning of each player's upkeep, that player sacrifices a nonland, nontoken permanent. If that player can't, they discard a card, they lose 2 life, you draw a card, you gain 2 life, you create a 2/2 white Knight creature token with vigilance, then you sacrifice Doom Foretold.| +Drown in the Loch|Throne of Eldraine|188|U|{U}{B}|Instant|||Choose one —$• Counter target spell with converted mana cost less than or equal to the number of cards in its controller's graveyard.$• Destroy target creature with converted mana cost less than or equal to the number of cards in its controller's graveyard.| +Escape to the Wilds|Throne of Eldraine|189|R|{3}{R}{G}|Sorcery|||Exile the top five cards of your library. You may play cards exiled this way until the end of your next turn.$You may play an additional land this turn.| +Faeburrow Elder|Throne of Eldraine|190|R|{1}{G}{W}|Creature - Treefolk Druid|0|0|Vigilance$Faeburrow Elder gets +1/+1 for each color among permanents you control.${T}: For each color among permanents you control, add one mana of that color.| Garruk, Cursed Huntsman|Throne of Eldraine|191|M|{4}{B}{G}|Legendary Planeswalker - Garruk|5|0: Create two 2/2 black and green Wolf creature tokens with "When this creature dies, put a loyalty counter on each Garruk you control."$−3: Destroy target creature. Draw a card.$−6: You get an emblem with "Creatures you control get +3/+3 and have trample."| +Grumgully, the Generous|Throne of Eldraine|192|U|{1}{R}{G}|Legendary Creature - Goblin Shaman|3|3|Each other non-Human creature you controls enters the battlefield with an additional +1/+1 counter on it.| +Improbable Alliance|Throne of Eldraine|193|U|{U}{R}|Enchantment|||Whenever you draw your second card each turn, create a 1/1 blue Faerie creature token with flying.${4}{U}{R}: Draw a card, then discard a card.| Inspiring Veteran|Throne of Eldraine|194|U|{R}{W}|Creature - Human Knight|2|2|Other Knights you control get +1/+1.| +Lochmere Serpent|Throne of Eldraine|195|R|{4}{U}{B}|Creature - Serpent|7|7|Flash${U}, Sacrifice an Island: Lochmere Serpent can't be blocked this turn.${B}, Sacrifice a Swamp: You gain 1 life and draw a card.${U}{B}: Exile five target cards from an opponent's graveyard. Return Lochmere Serpent from your graveyard to your hand. Activate this ability only any time you could cast a sorcery.| Maraleaf Pixie|Throne of Eldraine|196|U|{G}{U}|Creature - Faerie|2|2|Flying${T}: Add {G} or {U}.| Oko, Thief of Crowns|Throne of Eldraine|197|M|{1}{G}{U}|Legendary Planeswalker - Oko|4|+2: Create a Food token.$+1: Target artifact or creature loses all abilities and becomes a green Elk creature with base power and toughness 3/3.$−5: Exchange control of target artifact or creature you control and target creature an opponent controls with power 3 or less.| +Outlaws' Merriment|Throne of Eldraine|198|M|{1}{R}{W}{W}|Enchantment|||At the beginning of your upkeep, choose one at random. Create a red and white creature token with those characteristics.$• 3/1 Human Warrior with trample and haste.$• 2/1 Human Cleric with lifelink and haste.$• 1/2 Human Rogue with haste and "When this creature enters the battlefield, it deals 1 damage to any target."| +The Royal Scions|Throne of Eldraine|199|M|{1}{U}{R}|Legendary Planeswalker - Will Rowan|5|+1: Draw a card, then discard a card.$+1: Target creature gets +2/+0 and gains first strike and trample until end of turn.$−8: Draw four cards. When you do, The Royal Scions deals damage to any target equal to the number of cards in your hand.| Savvy Hunter|Throne of Eldraine|200|U|{1}{B}{G}|Creature - Human Warrior|3|3|Whenever Savvy Hunter attacks or blocks, create a Food token.$Sacrifice two Foods: Draw a card.| Shinechaser|Throne of Eldraine|201|U|{1}{W}{U}|Creature - Faerie|1|1|Flying, vigilance$Shinechaser gets +1/+1 as long as you control an artifact.$Shinechaser gets +1/+1 as long as you control an enchantment.| Steelclaw Lance|Throne of Eldraine|202|U|{B}{R}|Artifact - Equipment|||Equipped creature gets +2/+2.$Equip Knight {1}$Equip {3}| +Stormfist Crusader|Throne of Eldraine|203|R|{B}{R}|Creature - Human Knight|2|2|Menace$At the beginning of your upkeep, each player draws a card and loses 1 life.| +Wandermare|Throne of Eldraine|204|U|{1}{G}{W}|Creature - Horse|3|3|Whenever you cast a creature spell that has an Adventure, put a +1/+1 counter on Wandermare.| Wintermoor Commander|Throne of Eldraine|205|U|{W}{B}|Creature - Human Knight|2|*|Deathtouch$Wintermoor Commander's toughness is equal to the number of Knights you control.$Whenever Wintermoor Commander attacks, another target Knight you control gains indestructible until end of turn.| Arcanist's Owl|Throne of Eldraine|206|U|{W/U}{W/U}{W/U}{W/U}|Artifact Creature - Bird|3|3|Flying$When Arcanist's Owl enters the battlefield, look at the top four cards of your library. You may reveal an artifact or enchantment card from among them and put it into your hand. Put the rest on the bottom of your library in a random order.| +Covetous Urge|Throne of Eldraine|207|U|{U/B}{U/B}{U/B}{U/B}|Sorcery|||Target opponent reveals their hand. You choose a nonland card from that player's graveyard or hand and exile it. You may cast that card for as long as it remains exiled, and you may spend mana as though it were mana of any color to cast that spell.| +Deathless Knight|Throne of Eldraine|208|U|{B/G}{B/G}{B/G}{B/G}|Creature - Skeleton Knight|4|2|Haste$When you gain life for the first time each turn, return Deathless Knight from your graveyard to your hand.| +Elite Headhunter|Throne of Eldraine|209|U|{B/R}{B/R}{B/R}{B/R}|Creature - Human Knight|2|3|Menace${B/R}{B/R}{B/R}, Sacrifice another creature or an artifact: Elite Headhunter deals 2 damage to target creature or planeswalker.| Fireborn Knight|Throne of Eldraine|210|U|{R/W}{R/W}{R/W}{R/W}|Creature - Human Knight|2|3|Double strike${R/W}{R/W}{R/W}{R/W}: Fireborn Knight gets +1/+1 until end of turn.| -Golden Egg|Throne of Eldraine|220|C|{2}|Artifact - Food|||When Golden Egg enters the battlefield, draw a card.${1}, {T}: Sacrifice Golden Egg: Add one mana of any color.${2}, {T}, Sacrifice Golden Egg: You gain 3 life.| +Loch Dragon|Throne of Eldraine|211|U|{U/R}{U/R}{U/R}{U/R}|Creature - Dragon|3|2|Flying$Whenever Loch Dragon enters the battlefield or attacks, you may discard a card. If you do, draw a card.| +Bring Back|Throne of Eldraine|212|U|{G/W}{G/W}{G/W}{G/W}|Sorcery - Adventure|2|2|Create two 1/1 white Human creature tokens.| +Oakhame Ranger|Throne of Eldraine|212|U|{G/W}{G/W}{G/W}{G/W}|Creature - Elf Knight|2|2|{T}: Creatures you control get +1/+1 until end of turn.| +Rampart Smasher|Throne of Eldraine|213|U|{R/G}{R/G}{R/G}{R/G}|Creature - Giant|5|5|Rampart Smasher can't be blocked by Knights or Walls.| +Resolute Rider|Throne of Eldraine|214|U|{W/B}{W/B}{W/B}{W/B}|Creature - Human Knight|4|2|{W/B}{W/B}: Resolute Rider gains lifelink until end of turn.${W/B}{W/B}{W/B}: Resolute Rider gains indestructible until end of turn.| +Thunderous Snapper|Throne of Eldraine|215|U|{G/U}{G/U}{G/U}{G/U}|Creature - Turtle Hydra|4|4|Whenever you cast a spell with converted mana cost 5 or greater, draw a card.| +Clockwork Servant|Throne of Eldraine|216|U|{3}|Artifact Creature - Gnome|2|3|Adamant — When Clockwork Servant enters the battlefield, if at least three mana of the same color was spent to cast it, draw a card.| +Crashing Drawbridge|Throne of Eldraine|217|C|{2}|Artifact Creature - Wall|0|4|Defender${T}: Creatures you control gain haste until end of turn.| +Enchanted Carriage|Throne of Eldraine|218|U|{5}|Artifact - Vehicle|4|4|When Enchanted Carriage enters the battlefield, create two 1/1 white Mouse creature tokens.$Crew 2| +Gingerbrute|Throne of Eldraine|219|C|{1}|Artifact Creature - Food Golem|1|1|Haste${1}: Gingerbrute can't be blocked this turn except by creatures with haste.${2}, {T}, Sacrifice Gingerbrute: You gain 3 life.| +Golden Egg|Throne of Eldraine|220|C|{2}|Artifact - Food|||When Golden Egg enters the battlefield, draw a card.${1}, {T}, Sacrifice Golden Egg: Add one mana of any color.${2}, {T}, Sacrifice Golden Egg: You gain 3 life.| +Henge Walker|Throne of Eldraine|221|C|{3}|Artifact Creature - Golem|2|2|Adamant — If at least three mana of the same color was spent to cast this spell, Henge Walker enters the battlefield with a +1/+1 counter on it.| Heraldic Banner|Throne of Eldraine|222|U|{3}|Artifact|||As Heraldic Banner enters the battlefield, choose a color.$Creatures you control of the chosen color get +1/+0.${T}: Add one mana of the chosen color.| +Inquisitive Puppet|Throne of Eldraine|223|U|{1}|Artifact Creature - Construct|0|2|When Inquisitive Puppet enters the battlefield, scry 1.$Exile Inquisitive Puppet: Create a 1/1 white Human creature token.| +Jousting Dummy|Throne of Eldraine|224|C|{2}|Artifact Creature - Scarecrow Knight|2|1|{3}: Jousting Dummy gets +1/+0 until end of turn.| +Locthwain Gargoyle|Throne of Eldraine|225|C|{1}|Artifact Creature - Gargoyle|0|3|{4}: Locthwain Gargoyle gets +2/+0 and gains flying until end of turn.| +Lucky Clover|Throne of Eldraine|226|U|{2}|Artifact|||Whenever you cast an Adventure instant or sorcery spell, copy it. You may choose new targets for the copy.| +Prophet of the Peak|Throne of Eldraine|227|C|{6}|Artifact Creature - Cat|5|5|When Prophet of the Peak enters the battlefield, scry 2.| +Roving Keep|Throne of Eldraine|228|C|{7}|Artifact Creature - Wall|5|7|Defender${7}: Roving Keep gets +2/+0 and gains trample until end of turn. It can attack this turn as though it didn't have defender.| +Scalding Cauldron|Throne of Eldraine|229|C|{1}|Artifact|||{3}, {T}, Sacrifice Scalding Cauldron: It deals 3 damage to target creature.| +Shambling Suit|Throne of Eldraine|230|U|{3}|Artifact Creature - Construct|*|3|Shambling Suit's power is equal to the number of artifacts and/or enchantments you control.| +Signpost Scarecrow|Throne of Eldraine|231|C|{4}|Artifact Creature - Scarecrow|2|4|Vigilance${2}: Add one mana of any color.| +Sorcerer's Broom|Throne of Eldraine|232|U|{2}|Artifact Creature - Spirit|2|1|Whenever you sacrifice another permanent, you may pay {3}. If you do, create a token that's a copy of Sorcerer's Broom.| +Sorcerous Spyglass|Throne of Eldraine|233|R|{2}|Artifact|||As Sorcerous Spyglass enters the battlefield, look at an opponent's hand, then choose any card name.$Activated abilities of sources with the chosen name can't be activated unless they're mana abilities.| +Spinning Wheel|Throne of Eldraine|234|U|{3}|Artifact|||{T}: Add one mana of any color.${5}, {T}: Tap target creature.| +Stonecoil Serpent|Throne of Eldraine|235|R|{X}|Artifact Creature - Snake|0|0|Reach, trample, protection from multicolored$Stonecoil Serpent enters the battlefield with X +1/+1 counters on it.| +Weapon Rack|Throne of Eldraine|236|C|{4}|Artifact|||Weapon Rack enters the battlefield with three +1/+1 counters on it.${T}: Move a +1/+1 counter from Weapon Rack onto target creature. Activate this ability only any time you could cast a sorcery.| +Witch's Oven|Throne of Eldraine|237|U|{1}|Artifact|||{T}, Sacrifice a creature: Create a Food token. If the sacrificed creature's toughness was 4 or greater, create two Food tokens instead.| +Castle Ardenvale|Throne of Eldraine|238|R||Land|||Castle Ardenvale enters the battlefield tapped unless you control a Plains.${T}: Add {W}.${2}{W}{W}, {T}: Create a 1/1 white Human creature token.| +Castle Embereth|Throne of Eldraine|239|R||Land|||Castle Embereth enters the battlefield tapped unless you control a Mountain.${T}: Add {R}.${1}{R}{R}, {T}: Creatures you control get +1/+0 until end of turn.| +Castle Garenbrig|Throne of Eldraine|240|R||Land|||Castle Garenbrig enters the battlefield tapped unless you control a Forest.${T}: Add {G}.${2}{G}{G}, {T}: Add six {G}. Spend this mana only to cast creature spells or activate abilities of creatures.| +Castle Locthwain|Throne of Eldraine|241|R||Land|||Castle Locthwain enters the battlefield tapped unless you control a Swamp.${T}: Add {B}.${1}{B}{B}, {T}: Draw a card, then you lose life equal to the number of cards in your hand.| +Castle Vantress|Throne of Eldraine|242|R||Land|||Castle Vantress enters the battlefield tapped unless you control an Island.${T}: Add {U}.${2}{U}{U}, {T}: Scry 2.| +Dwarven Mine|Throne of Eldraine|243|C||Land - Mountain|||({T}: Add {R}.)$Dwarven Mine enters the battlefield tapped unless you control three or more other Mountains.$When Dwarven Mine enters the battlefield untapped, create a 1/1 red Dwarf creature token.| +Fabled Passage|Throne of Eldraine|244|R||Land|||{T}, Sacrifice Fabled Passage: Search your library for a basic land card, put it onto the battlefield tapped, then shuffle your library. Then if you control four or more lands, untap that land.| +Gingerbread Cabin|Throne of Eldraine|245|C||Land - Forest|||({T}: Add {G}.)$Gingerbread Cabin enters the battlefield tapped unless you control three or more other Forests.$When Gingerbread Cabin enters the battlefield untapped, create a Food token.| +Idyllic Grange|Throne of Eldraine|246|C||Land - Plains|||({T}: Add {W}.)$Idyllic Grange enters the battlefield tapped unless you control three or more other Plains.$When Idyllic Grange enters the battlefield untapped, put a +1/+1 counter on target creature you control.| +Mystic Sanctuary|Throne of Eldraine|247|C||Land - Island|||({T}: Add {U}.)$Mystic Sanctuary enters the battlefield tapped unless you control three or more other Islands.$When Mystic Sanctuary enters the battlefield untapped, you may put target instant or sorcery card from your graveyard on top of your library.| Tournament Grounds|Throne of Eldraine|248|U||Land|||{T}: Add {C}.${T}: Add {R}, {W}, or {B}. Spend this mana only to cast a Knight or Equipment spell.| Witch's Cottage|Throne of Eldraine|249|C||Land - Swamp|||({T}: Add {B}.)$Witch's Cottage enters the battlefield tapped unless you control three or more other Swamps.$When Witch's Cottage enters the battlefield untapped, you may put target creature card from your graveyard on top of your library.| +Plains|Throne of Eldraine|250|C||Basic Land - Plains|||({T}: Add {W}.)| +Island|Throne of Eldraine|254|C||Basic Land - Island|||({T}: Add {U}.)| +Swamp|Throne of Eldraine|258|C||Basic Land - Swamp|||({T}: Add {B}.)| +Mountain|Throne of Eldraine|262|C||Basic Land - Mountain|||({T}: Add {R}.)| +Forest|Throne of Eldraine|266|C||Basic Land - Forest|||({T}: Add {G}.)| +Kenrith, the Returned King|Throne of Eldraine|303|M|{4}{W}|Legendary Creature - Human Noble|5|5|{R}: All creatures gain trample and haste until end of turn.${1}{G}: Put a +1/+1 counter on target creature.${2}{W}: Target player gains 5 life.${3}{U}: Target player draws a card.${4}{B}: Put target creature card from a graveyard onto the battlefield under its owner's control.| +Rowan, Fearless Sparkmage|Throne of Eldraine|304|M|{3}{R}{R}|Legendary Planeswalker - Rowan|5|+1: Up to one target creature gets +3/+0 and gains first strike until end of turn.$−2: Rowan, Fearless Sparkmage deals 1 damage to each of up to two target creatures. Those creatures can't block this turn.$−9: Gain control of all creatures until end of turn. Untap them. They gain haste until end of turn.| +Garrison Griffin|Throne of Eldraine|305|C|{2}{W}|Creature - Griffin|2|2|Flying$Whenever Garrison Griffin attacks, target Knight you control gains flying until end of turn.| +Rowan's Battleguard|Throne of Eldraine|306|U|{3}{R}|Creature - Human Knight|3|3|First strike$As long as you control a Rowan planeswalker, Rowan's Battleguard gets +3/+0.| +Rowan's Stalwarts|Throne of Eldraine|307|R|{4}{R}|Creature - Human Knight|5|2|When Rowan's Stalwarts enters the battlefield, you may search your library and/or graveyard for a card named Rowan, Fearless Sparkmage, reveal it, and put it into your hand. If you search your library this way, shuffle it.| Wind-Scarred Crag|Throne of Eldraine|308|C||Land|||Wind-Scarred Crag enters the battlefield tapped.$When Wind-Scarred Crag enters the battlefield, you gain 1 life.${T}: Add {R} or {W}.| +Oko, the Trickster|Throne of Eldraine|309|M|{4}{G}{U}|Legendary Planeswalker - Oko|4|+1: Put two +1/+1 counters on up to one target creature you control.$0: Until end of turn, Oko, the Trickster becomes a copy of target creature you control. Prevent all damage that would be dealt to him this turn.$−7: Until end of turn, each creature you control has base power and toughness 10/10 and gains trample.| +Oko's Accomplices|Throne of Eldraine|310|C|{2}{U}|Creature - Faerie|2|3|Flying| +Bramblefort Fink|Throne of Eldraine|311|U|{1}{G}|Creature - Ouphe|2|2|{8}: Bramblefort Fink has base power and toughness 10/10 until end of turn. Activate this ability only if you control an Oko planeswalker.| +Oko's Hospitality|Throne of Eldraine|312|R|{3}{G}{U}|Instant|||Creatures you control have base power and toughness 3/3 until end of turn. You may search your library and/or graveyard for a card named Oko, the Trickster, reveal it, and put it into your hand. If you search your library this way, shuffle it.| Thornwood Falls|Throne of Eldraine|313|C||Land|||Thornwood Falls enters the battlefield tapped.$When Thornwood Falls enters the battlefield, you gain 1 life.${T}: Add {G} or {U}.| Mace of the Valiant|Throne of Eldraine|314|R|{2}{W}|Artifact - Equipment|||Equipped creature gets +1/+1 for each charge counter on Mace of the Valiant and has vigilance.$Whenever a creature enters the battlefield under your control, put a charge counter on Mace of the Valiant.$Equip {3}| Silverwing Squadron|Throne of Eldraine|315|R|{5}{W}|Creature - Human Knight|*|*|Flying, vigilance$Silverwing Squadron's power and toughness are each equal to the number of creatures you control.$Whenever Silverwing Squadron attacks, create a number of 2/2 white Knight creature tokens with vigilance equal to the number of opponents you have.| @@ -36070,3 +36308,129 @@ Syr Gwyn, Hero of Ashvale|Throne of Eldraine|330|M|{3}{R}{W}{B}|Legendary Creatu Arcane Signet|Throne of Eldraine|331|C|{2}|Artifact|||{T}: Add one mana of any color in your commander's color identity.| Tome of Legends|Throne of Eldraine|332|R|{2}|Artifact|||Tome of Legends enters the battlefield with a page counter on it.$Whenever your commander enters the battlefield or attacks, put a page counter on Tome of Legends.${1}, {T}, Remove a page counter from Tome of Legends: Draw a card.| Command Tower|Throne of Eldraine|333|C||Land|||{T}: Add one mana of any color in your commander's color identity.| +Garruk, Cursed Huntsman|Throne of Eldraine Collector's Edition|270|M|{4}{B}{G}|Legendary Planeswalker - Garruk|5|0: Create two 2/2 black and green Wolf creature tokens with "When this creature dies, put a loyalty counter on each Garruk you control."$−3: Destroy target creature. Draw a card.$−6: You get an emblem with "Creatures you control get +3/+3 and have trample."| +Oko, Thief of Crowns|Throne of Eldraine Collector's Edition|271|M|{1}{G}{U}|Legendary Planeswalker - Oko|4|+2: Create a Food token.$+1: Target artifact or creature loses all abilities and becomes a green Elk creature with base power and toughness 3/3.$−5: Exchange control of target artifact or creature you control and target creature an opponent controls with power 3 or less.| +The Royal Scions|Throne of Eldraine Collector's Edition|272|M|{1}{U}{R}|Legendary Planeswalker - Will Rowan|5|+1: Draw a card, then discard a card.$+1: Target creature gets +2/+0 and gains first strike and trample until end of turn.$−8: Draw four cards. When you do, The Royal Scions deals damage to any target equal to the number of cards in your hand.| +Ardenvale Tactician|Throne of Eldraine Collector's Edition|273|C|{1}{W}{W}|Creature - Human Knight|2|3|Flying| +Dizzying Swoop|Throne of Eldraine Collector's Edition|273|C|{1}{W}|Instant - Adventure|2|3|Tap up to two target creatures.| +Faerie Guidemother|Throne of Eldraine Collector's Edition|274|C|{W}|Creature - Faerie|1|1|Flying| +Gift of the Fae|Throne of Eldraine Collector's Edition|274|C|{1}{W}|Sorcery - Adventure|1|1|Target creature gets +2/+1 and gains flying until end of turn.| +Chop Down|Throne of Eldraine Collector's Edition|275|R|{2}{W}|Instant - Adventure|1|2|Destroy target creature with power 4 or greater.| +Giant Killer|Throne of Eldraine Collector's Edition|275|R|{W}|Creature - Human Peasant|1|2|{1}{W}, {T}: Tap target creature.| +Lonesome Unicorn|Throne of Eldraine Collector's Edition|276|C|{4}{W}|Creature - Unicorn|3|3|Vigilance| +Rider in Need|Throne of Eldraine Collector's Edition|276|C|{2}{W}|Sorcery - Adventure|3|3|Create a 2/2 white Knight creature token with vigilance.| +Cast Off|Throne of Eldraine Collector's Edition|277|M|{3}{W}{W}|Sorcery - Adventure|7|7|Destroy all non-Giant creatures.| +Realm-Cloaked Giant|Throne of Eldraine Collector's Edition|277|M|{5}{W}{W}|Creature - Giant|7|7|Vigilance| +Shepherd of the Flock|Throne of Eldraine Collector's Edition|278|U|{1}{W}|Creature - Human Peasant|3|1|| +Usher to Safety|Throne of Eldraine Collector's Edition|278|U|{W}|Instant - Adventure|3|1|Return target permanent you control to its owner's hand.| +On Alert|Throne of Eldraine Collector's Edition|279|C|{2}{W}|Instant - Adventure|2|1|Target creature gets +2/+2 until end of turn. Untap it.| +Silverflame Squire|Throne of Eldraine Collector's Edition|279|C|{1}{W}|Creature - Human Soldier|2|1|| +Animating Faerie|Throne of Eldraine Collector's Edition|280|U|{2}{U}|Creature - Faerie|2|2|Flying| +Bring to Life|Throne of Eldraine Collector's Edition|280|U|{2}{U}|Sorcery - Adventure|2|2|Target noncreature artifact you control becomes a 0/0 artifact creature. Put four +1/+1 counters on it.| +Brazen Borrower|Throne of Eldraine Collector's Edition|281|M|{1}{U}{U}|Creature - Faerie Rogue|3|1|Flash$Flying$Brazen Borrower can block only creatures with flying.| +Petty Theft|Throne of Eldraine Collector's Edition|281|M|{1}{U}|Instant - Adventure|3|1|Return target nonland permanent an opponent controls to its owner's hand.| +Fae of Wishes|Throne of Eldraine Collector's Edition|282|R|{1}{U}|Creature - Faerie Wizard|1|4|Flying${1}{U}, Discard two cards: Return Fae of Wishes to its owner's hand.| +Granted|Throne of Eldraine Collector's Edition|282|R|{3}{U}|Sorcery - Adventure|1|4|You may choose a noncreature card you own from outside the game, reveal it, and put it into your hand.| +Hypnotic Sprite|Throne of Eldraine Collector's Edition|283|U|{U}{U}|Creature - Faerie|2|1|Flying| +Mesmeric Glare|Throne of Eldraine Collector's Edition|283|U|{2}{U}|Instant - Adventure|2|1|Counter target spell with converted mana cost 3 or less.| +Merfolk Secretkeeper|Throne of Eldraine Collector's Edition|284|C|{U}|Creature - Merfolk Wizard|0|4|| +Venture Deeper|Throne of Eldraine Collector's Edition|284|C|{U}|Sorcery - Adventure|0|4|Target player puts the top four cards of their library into their graveyard.| +Queen of Ice|Throne of Eldraine Collector's Edition|285|C|{2}{U}|Creature - Human Noble Wizard|2|3|Whenever Queen of Ice deals combat damage to a creature, tap that creature. It doesn't untap during its controller's next untap step.| +Rage of Winter|Throne of Eldraine Collector's Edition|285|C|{1}{U}|Sorcery - Adventure|2|3|Tap target creature. It doesn't untap during its controller's next untap step.| +Foulmire Knight|Throne of Eldraine Collector's Edition|286|U|{B}|Creature - Zombie Knight|1|1|Deathtouch| +Profane Insight|Throne of Eldraine Collector's Edition|286|U|{2}{B}|Instant - Adventure|1|1|You draw a card and you lose 1 life.| +Murderous Rider|Throne of Eldraine Collector's Edition|287|R|{1}{B}{B}|Creature - Zombie Knight|2|3|Lifelink$When Murderous Rider dies, put it on the bottom of its owner's library.| +Swift End|Throne of Eldraine Collector's Edition|287|R|{1}{B}{B}|Instant - Adventure|2|3|Destroy target creature or planeswalker. You lose 2 life.| +Alter Fate|Throne of Eldraine Collector's Edition|288|U|{1}{B}|Sorcery - Adventure|2|2|Return target creature card from your graveyard to your hand.| +Order of Midnight|Throne of Eldraine Collector's Edition|288|U|{1}{B}|Creature - Human Knight|2|2|Flying$Order of Midnight can't block.| +Harvest Fear|Throne of Eldraine Collector's Edition|289|C|{3}{B}|Sorcery - Adventure|4|5|Target opponent discards two cards.| +Reaper of Night|Throne of Eldraine Collector's Edition|289|C|{5}{B}{B}|Creature - Specter|4|5|Whenever Reaper of Night attacks, if defending player has two or fewer cards in hand, it gains flying until end of turn.| +Curry Favor|Throne of Eldraine Collector's Edition|290|C|{B}|Sorcery - Adventure|2|1|You gain X life and each opponent loses X life, where X is the number of Knights you control.| +Smitten Swordmaster|Throne of Eldraine Collector's Edition|290|C|{1}{B}|Creature - Human Knight|2|1|Lifelink| +Bonecrusher Giant|Throne of Eldraine Collector's Edition|291|R|{2}{R}|Creature - Giant|4|3|Whenever Bonecrusher Giant becomes the target of a spell, Bonecrusher Giant deals 2 damage to that spell's controller.| +Stomp|Throne of Eldraine Collector's Edition|291|R|{1}{R}|Instant - Adventure|4|3|Damage can't be prevented this turn. Stomp deals 2 damage to any target.| +Battle Display|Throne of Eldraine Collector's Edition|292|U|{R}|Sorcery - Adventure|2|1|Destroy target artifact.| +Embereth Shieldbreaker|Throne of Eldraine Collector's Edition|292|U|{1}{R}|Creature - Human Knight|2|1|| +Haggle|Throne of Eldraine Collector's Edition|293|C|{R}|Instant - Adventure|2|3|You may discard a card. If you do, draw a card.| +Merchant of the Vale|Throne of Eldraine Collector's Edition|293|C|{2}{R}|Creature - Human Peasant|2|3|{2}{R}, Discard a card: Draw a card.| +Boulder Rush|Throne of Eldraine Collector's Edition|294|C|{R}|Instant - Adventure|3|1|Target creature gets +2/+0 until end of turn.| +Rimrock Knight|Throne of Eldraine Collector's Edition|294|C|{1}{R}|Creature - Dwarf Knight|3|1|Rimrock Knight can't block| +Beanstalk Giant|Throne of Eldraine Collector's Edition|295|U|{6}{G}|Creature - Giant|*|*|Beanstalk Giant's power and toughness are each equal to the number of lands you control.| +Fertile Footsteps|Throne of Eldraine Collector's Edition|295|U|{2}{G}|Sorcery - Adventure|*|*|Search your library for a basic land card, put it onto the battlefield, then shuffle your library.| +Curious Pair|Throne of Eldraine Collector's Edition|296|C|{1}{G}|Creature - Human Peasant|1|3|| +Treats to Share|Throne of Eldraine Collector's Edition|296|C|{G}|Sorcery - Adventure|1|3|Create a Food token.| +Flaxen Intruder|Throne of Eldraine Collector's Edition|297|U|{G}|Creature - Human Berserker|1|2|Whenever Flaxen Intruder deals combat damage to a player, you may sacrifice it. When you do, destroy target artifact or enchantment.| +Welcome Home|Throne of Eldraine Collector's Edition|297|U|{5}{G}{G}|Sorcery - Adventure|1|2|Create three 2/2 green Bear creature tokens.| +Garenbrig Carver|Throne of Eldraine Collector's Edition|298|C|{3}{G}|Creature - Human Warrior|3|2|| +Shield's Might|Throne of Eldraine Collector's Edition|298|C|{1}{G}|Instant - Adventure|3|2|Target creature gets +2/+2 until end of turn.| +Heart's Desire|Throne of Eldraine Collector's Edition|299|R|{G}|Sorcery - Adventure|5|5|Create a 1/1 white Human creature token.| +Lovestruck Beast|Throne of Eldraine Collector's Edition|299|R|{2}{G}|Creature - Beast Noble|5|5|Lovestruck Beast can't attack unless you control a 1/1 creature.| +Rosethorn Acolyte|Throne of Eldraine Collector's Edition|300|C|{2}{G}|Creature - Elf Druid|2|3|{T}: Add one mana of any color.| +Seasonal Ritual|Throne of Eldraine Collector's Edition|300|C|{G}|Sorcery - Adventure|2|3|Add one mana of any color.| +Oaken Boon|Throne of Eldraine Collector's Edition|301|C|{3}{G}|Sorcery - Adventure|6|5|Put two +1/+1 counters on target creature.| +Tuinvale Treefolk|Throne of Eldraine Collector's Edition|301|C|{5}{G}|Creature - Treefolk Druid|6|5|| +Bring Back|Throne of Eldraine Collector's Edition|302|U|{G/W}{G/W}{G/W}{G/W}|Sorcery - Adventure|2|2|Create two 1/1 white Human creature tokens.| +Oakhame Ranger|Throne of Eldraine Collector's Edition|302|U|{G/W}{G/W}{G/W}{G/W}|Creature - Elf Knight|2|2|{T}: Creatures you control get +1/+1 until end of turn.| +Acclaimed Contender|Throne of Eldraine Collector's Edition|334|R|{2}{W}|Creature - Human Knight|3|3|When Acclaimed Contender enters the battlefield, if you control another Knight, look at the top five cards of your library. You may reveal a Knight, Aura, Equipment, or legendary artifact card from among them and put it into your hand. Put the rest on the bottom of your library in a random order.| +Charming Prince|Throne of Eldraine Collector's Edition|335|R|{1}{W}|Creature - Human Noble|2|2|When Charming Prince enters the battlefield, choose one —$• Scry 2.$• You gain 3 life.$• Exile another target creature you own. Return it to the battlefield under your control at the beginning of the next end step.| +The Circle of Loyalty|Throne of Eldraine Collector's Edition|336|M|{4}{W}{W}|Legendary Artifact|||This spell costs {1} less to cast for each Knight you control.$Creatures you control get +1/+1.$Whenever you cast a legendary spell, create a 2/2 white Knight creature token with vigilance.${3}{W}, {T}: Create a 2/2 white Knight creature token with vigilance.| +Happily Ever After|Throne of Eldraine Collector's Edition|337|R|{2}{W}|Enchantment|||When Happily Ever After enters the battlefield, each player gains 5 life and draws a card.$At the beginning of your upkeep, if there are five colors among permanents you control, there are six or more card types among permanents you control and/or cards in your graveyard, and your life total is greater than or equal to your starting life total, you win the game.| +Harmonious Archon|Throne of Eldraine Collector's Edition|338|M|{4}{W}{W}|Creature - Archon|4|5|Flying$Non-Archon creatures have base power and toughness 3/3.$When Harmonious Archon enters the battlefield, create two 1/1 white Human creature tokens.| +Hushbringer|Throne of Eldraine Collector's Edition|339|R|{1}{W}|Creature - Faerie|1|2|Flying, lifelink$Creatures entering the battlefield or dying don't cause abilities to trigger.| +Linden, the Steadfast Queen|Throne of Eldraine Collector's Edition|340|R|{W}{W}{W}|Legendary Creature - Human Noble|3|3|Vigilance$Whenever a white creature you control attacks, you gain 1 life.| +Worthy Knight|Throne of Eldraine Collector's Edition|341|R|{1}{W}|Creature - Human Knight|2|2|Whenever you cast a Knight spell, create a 1/1 white Human creature token.| +Emry, Lurker of the Loch|Throne of Eldraine Collector's Edition|342|R|{2}{U}|Legendary Creature - Merfolk Wizard|1|2|This spell costs {1} less to cast for each artifact you control.$When Emry, Lurker of the Loch enters the battlefield, put the top four cards of your library into your graveyard.${T}: Choose target artifact card in your graveyard. You may cast that card this turn.| +Folio of Fancies|Throne of Eldraine Collector's Edition|343|R|{1}{U}|Artifact|||Players have no maximum hand size.${X}{X}, {T}: Each player draws X cards.${2}{U}, {T}: Each opponent puts a number of cards equal to the number of cards in their hand from the top of their library into their graveyard.| +Gadwick, the Wizened|Throne of Eldraine Collector's Edition|344|R|{X}{U}{U}{U}|Legendary Creature - Human Wizard|3|3|When Gadwick, the Wizened enters the battlefield, draw X cards.$Whenever you cast a blue spell, tap target nonland permanent an opponent controls.| +The Magic Mirror|Throne of Eldraine Collector's Edition|345|M|{6}{U}{U}{U}|Legendary Artifact|||This spell costs {1} less to cast for each instant and sorcery card in your graveyard.$You have no maximum hand size.$At the beginning of your upkeep, put a knowledge counter on The Magic Mirror, then draw a card for each knowledge counter on The Magic Mirror.| +Midnight Clock|Throne of Eldraine Collector's Edition|346|R|{2}{U}|Artifact|||{T}: Add {U}.${2}{U}: Put an hour counter on Midnight Clock.$At the beginning of each upkeep, put an hour counter on Midnight Clock.$When the twelfth hour counter is put on Midnight Clock, shuffle your hand and graveyard into your library, then draw seven cards. Exile Midnight Clock.| +Mirrormade|Throne of Eldraine Collector's Edition|347|R|{1}{U}{U}|Enchantment|||You may have Mirrormade enter the battlefield as a copy of any artifact or enchantment on the battlefield.| +Stolen by the Fae|Throne of Eldraine Collector's Edition|348|R|{X}{U}{U}|Sorcery|||Return target creature with converted mana cost X to its owner's hand. You create X 1/1 blue Faerie creature tokens with flying.| +Vantress Gargoyle|Throne of Eldraine Collector's Edition|349|R|{1}{U}|Artifact Creature - Gargoyle|5|4|Flying$Vantress Gargoyle can't attack unless defending player has seven or more cards in their graveyard.$Vantress Gargoyle can't block unless you have four or more cards in hand.${T}: Each player puts the top card of their library into their graveyard.| +Ayara, First of Locthwain|Throne of Eldraine Collector's Edition|350|R|{B}{B}{B}|Legendary Creature - Elf Noble|2|3|Whenever Ayara, First of Locthwain or another black creature enters the battlefield under your control, each opponent loses 1 life and you gain 1 life.${T}, Sacrifice another black creature: Draw a card.| +Blacklance Paragon|Throne of Eldraine Collector's Edition|351|R|{1}{B}|Creature - Human Knight|3|1|Flash$When Blacklance Paragon enters the battlefield, target Knight gains deathtouch and lifelink until end of turn.| +The Cauldron of Eternity|Throne of Eldraine Collector's Edition|352|M|{10}{B}{B}|Legendary Artifact|||This spell costs {2} less for each creature card in your graveyard.$Whenever a creature you control dies, put it on the bottom of its owner's library.${2}{B}, {T}, Pay 2 life: Return target creature card from your graveyard to the battlefield. Activate this ability only any time you could cast a sorcery.| +Clackbridge Troll|Throne of Eldraine Collector's Edition|353|R|{3}{B}{B}|Creature - Troll|8|8|Trample, haste$When Clackbridge Troll enters the battlefield, target opponent creates three 0/1 white Goat creature tokens.$At the beginning of combat on your turn, any opponent may sacrifice a creature. If a player does, tap Clackbridge Troll, you gain 3 life, and you draw a card.| +Oathsworn Knight|Throne of Eldraine Collector's Edition|354|R|{1}{B}{B}|Creature - Human Knight|0|0|Oathsworn Knight enters the battlefield with four +1/+1 counters on it.$Oathsworn Knight attacks each combat if able.$If damage would be dealt to Oathsworn Knight while it has a +1/+1 counter on it, prevent that damage and remove a +1/+1 counter from it.| +Piper of the Swarm|Throne of Eldraine Collector's Edition|355|R|{1}{B}|Creature - Human Warlock|1|3|Rats you control have menace.${1}{B}, {T}: Create a 1/1 black Rat creature token.${2}{B}{B}, {T}, Sacrifice three Rats: Gain control of target creature.| +Rankle, Master of Pranks|Throne of Eldraine Collector's Edition|356|M|{2}{B}{B}|Legendary Creature - Faerie Rogue|3|3|Flying, haste$Whenever Rankle, Master of Pranks deals combat damage to a player, choose any number —$• Each player discards a card.$• Each player loses 1 life and draws a card.$• Each player sacrifices a creature.| +Wishclaw Talisman|Throne of Eldraine Collector's Edition|357|R|{1}{B}|Artifact|||Wishclaw Talisman enters the battlefield with three wish counters on it.${1}, {T}, Remove a wish counter from Wishclaw Talisman: Search your library for a card, put it into your hand, then shuffle your library. An opponent gains control of Wishclaw Talisman. Activate this ability only during your turn.| +Witch's Vengeance|Throne of Eldraine Collector's Edition|358|R|{1}{B}{B}|Sorcery|||Creatures of the creature type of your choice get -3/-3 until end of turn.| +Embercleave|Throne of Eldraine Collector's Edition|359|M|{4}{R}{R}|Legendary Artifact - Equipment|||Flash$This spell costs {1} less to cast for each attacking creature you control.$When Embercleave enters the battlefield, attach it to target creature you control.$Equipped creature gets +1/+1 and has double strike and trample.$Equip {3}| +Fervent Champion|Throne of Eldraine Collector's Edition|360|R|{R}|Creature - Human Knight|1|1|First strike, haste$Whenever Fervent Champion attacks, another target attacking Knight you control gets +1/+0 until end of turn.$Equip abilities you activate that target Fervent Champion cost {3} less to activate.| +Fires of Invention|Throne of Eldraine Collector's Edition|361|R|{3}{R}|Enchantment|||You can cast spells only during your turn and you can cast no more than two spells each turn.$You may cast spells with converted mana cost less than or equal to the number of lands you control without paying their mana costs.| +Irencrag Feat|Throne of Eldraine Collector's Edition|362|R|{1}{R}{R}{R}|Sorcery|||Add seven {R}. You can cast only one more spell this turn.| +Irencrag Pyromancer|Throne of Eldraine Collector's Edition|363|R|{2}{R}|Creature - Human Wizard|0|4|Whenever you draw your second card each turn, Irencrag Pyromancer deals 3 damage to any target.| +Opportunistic Dragon|Throne of Eldraine Collector's Edition|364|R|{2}{R}{R}|Creature - Dragon|4|3|Flying$When Opportunistic Dragon enters the battlefield, choose target Human or artifact an opponent controls. For as long as Opportunistic Dragon remains on the battlefield, gain control of that permanent, it loses all abilities, and it can't attack or block.| +Robber of the Rich|Throne of Eldraine Collector's Edition|365|M|{1}{R}|Creature - Human Archer Rogue|2|2|Reach, haste$Whenever Robber of the Rich attacks, if defending player has more cards in hand than you, exile the top card of their library. During any turn you attacked with a Rogue, you may cast that card and you may spend mana as though it were mana of any color to cast that spell.| +Sundering Stroke|Throne of Eldraine Collector's Edition|366|R|{6}{R}|Sorcery|||Sundering Stroke deals 7 damage divided as you choose among one, two, or three targets. If at least seven red mana was spent to cast this spell, instead Sundering Stroke deals 7 damage to each of those permanents and/or players.| +Torbran, Thane of Red Fell|Throne of Eldraine Collector's Edition|367|R|{1}{R}{R}{R}|Legendary Creature - Dwarf Noble|2|4|If a red source you control would deal damage to an opponent or a permanent an opponent controls, it deals that much damage plus 2 instead.| +Feasting Troll King|Throne of Eldraine Collector's Edition|368|R|{2}{G}{G}{G}{G}|Creature - Troll Noble|7|6|Vigilance, trample$When Feasting Troll King enters the battlefield, if you cast it from your hand, create three Food tokens.$Sacrifice three Foods: Return Feasting Troll King from your graveyard to the battlefield. Activate this ability only during your turn.| +Gilded Goose|Throne of Eldraine Collector's Edition|369|R|{G}|Creature - Bird|0|2|Flying$When Gilded Goose enters the battlefield, create a Food token.${1}{G}, {T}: Create a Food token.${T}, Sacrifice a Food: Add one mana of any color.| +The Great Henge|Throne of Eldraine Collector's Edition|370|M|{7}{G}{G}|Legendary Artifact|||This spell costs {X} less to cast, where X is the greatest power among creatures you control.${T}: Add {G}{G}. You gain 2 life.$Whenever a nontoken creature enters the battlefield under your control, put a +1/+1 counter on it and draw a card.| +Once Upon a Time|Throne of Eldraine Collector's Edition|371|R|{1}{G}|Instant|||If this spell is the first spell you've cast this game, you may cast it without paying its mana cost.$Look at the top five cards of your library. You may reveal a creature or land card from among them and put it into your hand. Put the rest on the bottom of your library in a random order.| +Questing Beast|Throne of Eldraine Collector's Edition|372|M|{2}{G}{G}|Legendary Creature - Beast|4|4|Vigilance, deathtouch, haste$Questing Beast can't be blocked by creatures with power 2 or less.$Combat damage that would be dealt by creatures you control can't be prevented.$Whenever Questing Beast deals combat damage to an opponent, it deals that much damage to target planeswalker that player controls.| +Return of the Wildspeaker|Throne of Eldraine Collector's Edition|373|R|{4}{G}|Instant|||Choose one —$• Draw cards equal to the greatest power among non-Human creatures you control.$• Non-Human creatures you control get +3/+3 until end of turn.| +Wicked Wolf|Throne of Eldraine Collector's Edition|374|R|{2}{G}{G}|Creature - Wolf|3|3|When Wicked Wolf enters the battlefield, it fights up to one target creature you don't control.$Sacrifice a Food: Put a +1/+1 counter on Wicked Wolf. It gains indestructible until end of turn. Tap it.| +Wildborn Preserver|Throne of Eldraine Collector's Edition|375|R|{1}{G}|Creature - Elf Archer|2|2|Flash$Reach$Whenever another non-Human creature enters the battlefield under your control, you may pay {X}. When you do, put X +1/+1 counters on Wildborn Preserver.| +Yorvo, Lord of Garenbrig|Throne of Eldraine Collector's Edition|376|R|{G}{G}{G}|Legendary Creature - Giant Noble|0|0|Yorvo, Lord of Garenbrig enters the battlefield with four +1/+1 counters on it.$Whenever another green creature enters the battlefield under your control, put a +1/+1 counter on Yorvo. Then if that creature's power is greater than Yorvo's power, put another +1/+1 counter on Yorvo.| +Dance of the Manse|Throne of Eldraine Collector's Edition|377|R|{X}{W}{U}|Sorcery|||Return up to X target artifact and/or non-Aura enchantment cards each with converted mana cost X or less from your graveyard to the battlefield. If X is 6 or more, those permanents are 4/4 creatures in addition to their other types.| +Doom Foretold|Throne of Eldraine Collector's Edition|378|R|{2}{W}{B}|Enchantment|||At the beginning of each player's upkeep, that player sacrifices a nonland, nontoken permanent. If that player can't, they discard a card, they lose 2 life, you draw a card, you gain 2 life, you create a 2/2 white Knight creature token with vigilance, then you sacrifice Doom Foretold.| +Escape to the Wilds|Throne of Eldraine Collector's Edition|379|R|{3}{R}{G}|Sorcery|||Exile the top five cards of your library. You may play cards exiled this way until the end of your next turn.$You may play an additional land this turn.| +Faeburrow Elder|Throne of Eldraine Collector's Edition|380|R|{1}{G}{W}|Creature - Treefolk Druid|0|0|Vigilance$Faeburrow Elder gets +1/+1 for each color among permanents you control.${T}: For each color among permanents you control, add one mana of that color.| +Lochmere Serpent|Throne of Eldraine Collector's Edition|381|R|{4}{U}{B}|Creature - Serpent|7|7|Flash${U}, Sacrifice an Island: Lochmere Serpent can't be blocked this turn.${B}, Sacrifice a Swamp: You gain 1 life and draw a card.${U}{B}: Exile five target cards from an opponent's graveyard. Return Lochmere Serpent from your graveyard to your hand. Activate this ability only any time you could cast a sorcery.| +Outlaws' Merriment|Throne of Eldraine Collector's Edition|382|M|{1}{R}{W}{W}|Enchantment|||At the beginning of your upkeep, choose one at random. Create a red and white creature token with those characteristics.$• 3/1 Human Warrior with trample and haste.$• 2/1 Human Cleric with lifelink and haste.$• 1/2 Human Rogue with haste and "When this creature enters the battlefield, it deals 1 damage to any target."| +Stormfist Crusader|Throne of Eldraine Collector's Edition|383|R|{B}{R}|Creature - Human Knight|2|2|Menace$At the beginning of your upkeep, each player draws a card and loses 1 life.| +Sorcerous Spyglass|Throne of Eldraine Collector's Edition|384|R|{2}|Artifact|||As Sorcerous Spyglass enters the battlefield, look at an opponent's hand, then choose any card name.$Activated abilities of sources with the chosen name can't be activated unless they're mana abilities.| +Stonecoil Serpent|Throne of Eldraine Collector's Edition|385|R|{X}|Artifact Creature - Snake|0|0|Reach, trample, protection from multicolored$Stonecoil Serpent enters the battlefield with X +1/+1 counters on it.| +Castle Ardenvale|Throne of Eldraine Collector's Edition|386|R||Land|||Castle Ardenvale enters the battlefield tapped unless you control a Plains.${T}: Add {W}.${2}{W}{W}, {T}: Create a 1/1 white Human creature token.| +Castle Embereth|Throne of Eldraine Collector's Edition|387|R||Land|||Castle Embereth enters the battlefield tapped unless you control a Mountain.${T}: Add {R}.${1}{R}{R}, {T}: Creatures you control get +1/+0 until end of turn.| +Castle Garenbrig|Throne of Eldraine Collector's Edition|388|R||Land|||Castle Garenbrig enters the battlefield tapped unless you control a Forest.${T}: Add {G}.${2}{G}{G}, {T}: Add six {G}. Spend this mana only to cast creature spells or activate abilities of creatures.| +Castle Locthwain|Throne of Eldraine Collector's Edition|389|R||Land|||Castle Locthwain enters the battlefield tapped unless you control a Swamp.${T}: Add {B}.${1}{B}{B}, {T}: Draw a card, then you lose life equal to the number of cards in your hand.| +Castle Vantress|Throne of Eldraine Collector's Edition|390|R||Land|||Castle Vantress enters the battlefield tapped unless you control an Island.${T}: Add {U}.${2}{U}{U}, {T}: Scry 2.| +Fabled Passage|Throne of Eldraine Collector's Edition|391|R||Land|||{T}, Sacrifice Fabled Passage: Search your library for a basic land card, put it onto the battlefield tapped, then shuffle your library. Then if you control four or more lands, untap that land.| +Highcliff Felidar|Game Night 2019|1|M|{5}{W}{W}|Creature - Cat Beast|5|5|Vigilance$When Highcliff Felidar enters the battlefield, for each opponent, choose a creature with the greatest power among creatures that player controls. Destroy those creatures.| +Sphinx of Enlightenment|Game Night 2019|2|M|{4}{U}{U}|Creature - Sphinx|5|5|Flying$When Sphinx of Enlightenment enters the battlefield, target opponent draws a card and you draw three cards.| +Calculating Lich|Game Night 2019|3|M|{4}{B}{B}|Creature - Zombie Wizard|5|5|Menace$Whenever a creature attacks one of your opponents, that player loses 1 life.| +Fiendish Duo|Game Night 2019|4|M|{4}{R}{R}|Creature - Devil|5|5|First strike$If a source would deal damage to an opponent, it deals double that damage that player instead.| +Earthshaker Giant|Game Night 2019|5|M|{4}{G}{G}|Creature - Giant Druid|6|6|Trample$When Earthshaker Giant enters the battlefield, other creatures you control get +3/+3 and gain trample until end of turn.| diff --git a/Utils/mtg-sets-data.txt b/Utils/mtg-sets-data.txt index 37b5025c86..4b50c8d8d6 100644 --- a/Utils/mtg-sets-data.txt +++ b/Utils/mtg-sets-data.txt @@ -139,6 +139,8 @@ Masters Edition III|ME3| Masters Edition IV|ME4| Masters Edition|MED| Game Day|MGDC| +Game Night|GNT| +Game Night 2019|GN2| Mirage|MIR| Launch Party|MLP| Modern Horizons|MH1| @@ -185,6 +187,7 @@ Super Series|SUS| Theros|THS| Tempest|TMP| Throne of Eldraine|ELD| +Throne of Eldraine Collector's Edition|CELD| Torment|TOR| Tempest Remastered|TPR| Time Spiral "Timeshifted"|TSB| diff --git a/pom.xml b/pom.xml index 8375161005..ee8de698c6 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ org.mage mage-root - 1.4.37 + 1.4.39 pom Mage Root Mage Root POM @@ -86,7 +86,7 @@ - 1.4.37 + 1.4.39 UTF-8 yyyy-MM-dd'T'HH:mm:ss'Z'