mirror of
https://github.com/correl/mage.git
synced 2024-12-26 11:09:27 +00:00
Merge pull request #45 from magefree/master
Merge https://github.com/magefree/mage
This commit is contained in:
commit
4b1c631044
197 changed files with 6318 additions and 1133 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -135,3 +135,4 @@ client_secrets.json
|
|||
|
||||
dependency-reduced-pom.xml
|
||||
mage-bundle
|
||||
/Mage.Client/game-*.json
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
<name>Mage Client</name>
|
||||
|
||||
<dependencies>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.mage</groupId>
|
||||
<artifactId>mage</artifactId>
|
||||
|
@ -68,6 +69,11 @@
|
|||
<artifactId>jetlang</artifactId>
|
||||
<version>0.2.9</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.amazonaws</groupId>
|
||||
<artifactId>aws-java-sdk-s3</artifactId>
|
||||
<version>1.11.286</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.jgoodies</groupId>
|
||||
<artifactId>forms</artifactId>
|
||||
|
@ -147,14 +153,9 @@
|
|||
https://stackoverflow.com/questions/714243/sax2-driver-class-org-apache-crimson-parser-xmlreaderimpl-not-found-when-using
|
||||
-->
|
||||
<dependency>
|
||||
<groupId>batik</groupId>
|
||||
<artifactId>batik-transcoder</artifactId>
|
||||
<version>1.6-1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>crimson</groupId>
|
||||
<artifactId>crimson</artifactId>
|
||||
<version>1.1.3</version>
|
||||
<groupId>org.apache.xmlgraphics</groupId>
|
||||
<artifactId>batik-transcoder</artifactId>
|
||||
<version>1.7</version>
|
||||
</dependency>
|
||||
<!-- svg support end -->
|
||||
<dependency>
|
||||
|
|
|
@ -645,6 +645,8 @@
|
|||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="chkRules" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace min="-2" pref="5" max="-2" attributes="0"/>
|
||||
<Component id="chkUnique" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace min="-2" pref="5" max="-2" attributes="0"/>
|
||||
<Component id="cardCountLabel" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="cardCount" min="-2" pref="48" max="-2" attributes="0"/>
|
||||
|
@ -659,6 +661,7 @@
|
|||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Component id="chkTypes" max="32767" attributes="0"/>
|
||||
<Component id="chkRules" alignment="1" max="32767" attributes="0"/>
|
||||
<Component id="chkUnique" alignment="1" max="32767" attributes="0"/>
|
||||
<Component id="chkNames" alignment="1" max="32767" attributes="0"/>
|
||||
<Group type="102" attributes="0">
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
|
@ -846,6 +849,29 @@
|
|||
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="chkRulesActionPerformed"/>
|
||||
</Events>
|
||||
</Component>
|
||||
<Component class="javax.swing.JCheckBox" name="chkUnique">
|
||||
<Properties>
|
||||
<Property name="selected" type="boolean" value="true"/>
|
||||
<Property name="text" type="java.lang.String" value="Unique"/>
|
||||
<Property name="toolTipText" type="java.lang.String" value="Singleton rules."/>
|
||||
<Property name="focusable" type="boolean" value="false"/>
|
||||
<Property name="horizontalTextPosition" type="int" value="4"/>
|
||||
<Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||
<Dimension value="[69, 16]"/>
|
||||
</Property>
|
||||
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||
<Dimension value="[69, 16]"/>
|
||||
</Property>
|
||||
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||
<Dimension value="[69, 16]"/>
|
||||
</Property>
|
||||
<Property name="verticalTextPosition" type="int" value="3"/>
|
||||
</Properties>
|
||||
<Events>
|
||||
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="chkUniqueActionPerformed"/>
|
||||
</Events>
|
||||
</Component>
|
||||
|
||||
<Component class="javax.swing.JButton" name="jButtonSearch">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" value="Search"/>
|
||||
|
|
|
@ -232,7 +232,7 @@ public class CardSelector extends javax.swing.JPanel implements ComponentListene
|
|||
FilterCard filter = new FilterCard();
|
||||
|
||||
String name = jTextFieldSearch.getText().trim();
|
||||
filter.add(new CardTextPredicate(name, chkNames.isSelected(), chkTypes.isSelected(), chkRules.isSelected()));
|
||||
filter.add(new CardTextPredicate(name, chkNames.isSelected(), chkTypes.isSelected(), chkRules.isSelected(), chkUnique.isSelected()));
|
||||
|
||||
if (limited) {
|
||||
ArrayList<Predicate<MageObject>> predicates = new ArrayList<>();
|
||||
|
@ -543,6 +543,7 @@ public class CardSelector extends javax.swing.JPanel implements ComponentListene
|
|||
chkNames = new javax.swing.JCheckBox();
|
||||
chkTypes = new javax.swing.JCheckBox();
|
||||
chkRules = new javax.swing.JCheckBox();
|
||||
chkUnique = new javax.swing.JCheckBox();
|
||||
jButtonSearch = new javax.swing.JButton();
|
||||
jButtonClean = new javax.swing.JButton();
|
||||
cardCountLabel = new javax.swing.JLabel();
|
||||
|
@ -1062,6 +1063,22 @@ public class CardSelector extends javax.swing.JPanel implements ComponentListene
|
|||
chkRulesActionPerformed(evt);
|
||||
}
|
||||
});
|
||||
|
||||
chkUnique.setSelected(true);
|
||||
chkUnique.setText("Unique");
|
||||
chkUnique.setToolTipText("Singleton results only.");
|
||||
chkUnique.setFocusable(false);
|
||||
chkUnique.setHorizontalTextPosition(javax.swing.SwingConstants.RIGHT);
|
||||
chkUnique.setMaximumSize(new java.awt.Dimension(69, 16));
|
||||
chkUnique.setMinimumSize(new java.awt.Dimension(69, 16));
|
||||
chkUnique.setPreferredSize(new java.awt.Dimension(69, 16));
|
||||
chkUnique.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
|
||||
chkUnique.addActionListener(new java.awt.event.ActionListener() {
|
||||
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||
chkUniqueActionPerformed(evt);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
jButtonSearch.setText("Search");
|
||||
jButtonSearch.setToolTipText("Performs the search.");
|
||||
|
@ -1109,6 +1126,8 @@ public class CardSelector extends javax.swing.JPanel implements ComponentListene
|
|||
.addComponent(chkTypes, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(chkRules, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(chkUnique, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addGap(5, 5, 5)
|
||||
.addComponent(cardCountLabel)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
|
@ -1122,6 +1141,7 @@ public class CardSelector extends javax.swing.JPanel implements ComponentListene
|
|||
.addGroup(cardSelectorBottomPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addComponent(chkTypes, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
||||
.addComponent(chkRules, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
||||
.addComponent(chkUnique, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
||||
.addComponent(chkNames, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
||||
.addGroup(cardSelectorBottomPanelLayout.createSequentialGroup()
|
||||
.addGroup(cardSelectorBottomPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
|
@ -1341,6 +1361,10 @@ public class CardSelector extends javax.swing.JPanel implements ComponentListene
|
|||
// TODO add your handling code here:
|
||||
}//GEN-LAST:event_chkRulesActionPerformed
|
||||
|
||||
private void chkUniqueActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_chkRulesActionPerformed
|
||||
// TODO add your handling code here:
|
||||
}//GEN-LAST:event_chkRulesActionPerformed
|
||||
|
||||
private void btnExpansionSearchActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnExpansionSearchActionPerformed
|
||||
FastSearchUtil.showFastSearchForStringComboBox(cbExpansionSet, "Select set or expansion");
|
||||
}//GEN-LAST:event_btnExpansionSearchActionPerformed
|
||||
|
@ -1418,6 +1442,7 @@ public class CardSelector extends javax.swing.JPanel implements ComponentListene
|
|||
private javax.swing.JCheckBox chkPennyDreadful;
|
||||
private javax.swing.JCheckBox chkPiles;
|
||||
private javax.swing.JCheckBox chkRules;
|
||||
private javax.swing.JCheckBox chkUnique;
|
||||
private javax.swing.JCheckBox chkTypes;
|
||||
private javax.swing.JButton jButtonAddToMain;
|
||||
private javax.swing.JButton jButtonAddToSideboard;
|
||||
|
|
|
@ -41,6 +41,9 @@
|
|||
<Component id="lblFreeMulligans" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="spnFreeMulligans" min="-2" pref="50" max="-2" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="chkSpectatorsAllowed" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace min="-2" pref="13" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<Group type="102" attributes="0">
|
||||
<Component id="txtName" min="-2" pref="178" max="-2" attributes="0"/>
|
||||
|
@ -152,6 +155,7 @@
|
|||
<Component id="spnFreeMulligans" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="lblFreeMulligans" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="chkRollbackTurnsAllowed" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="chkSpectatorsAllowed" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<Group type="103" groupAlignment="3" attributes="0">
|
||||
<Component id="cbGameType" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
|
@ -274,6 +278,13 @@
|
|||
<Property name="toolTipText" type="java.lang.String" value="The number of mulligans a player can use without decreasing the number of drawn cards."/>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Component class="javax.swing.JCheckBox" name="chkSpectatorsAllowed">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" value="Spectators allowed"/>
|
||||
<Property name="toolTipText" type="java.lang.String" value="Allow spectators to view your game."/>
|
||||
</Properties>
|
||||
</Component>
|
||||
|
||||
<Component class="javax.swing.JSpinner" name="spnFreeMulligans">
|
||||
</Component>
|
||||
<Component class="javax.swing.JLabel" name="lblNumPlayers">
|
||||
|
|
|
@ -102,6 +102,7 @@ public class NewTableDialog extends MageDialog {
|
|||
lblGameType = new javax.swing.JLabel();
|
||||
cbGameType = new javax.swing.JComboBox();
|
||||
chkRollbackTurnsAllowed = new javax.swing.JCheckBox();
|
||||
chkSpectatorsAllowed = new javax.swing.JCheckBox();
|
||||
chkRated = new javax.swing.JCheckBox();
|
||||
lblFreeMulligans = new javax.swing.JLabel();
|
||||
spnFreeMulligans = new javax.swing.JSpinner();
|
||||
|
@ -151,6 +152,9 @@ public class NewTableDialog extends MageDialog {
|
|||
chkRollbackTurnsAllowed.setText("Allow rollbacks");
|
||||
chkRollbackTurnsAllowed.setToolTipText("<HTML>Allow to rollback to the start of previous turns<br>\nif all players agree.\n");
|
||||
|
||||
chkSpectatorsAllowed.setText("Allow Spectators");
|
||||
chkSpectatorsAllowed.setToolTipText("<HTML>Allow spectators to watch.\n");
|
||||
|
||||
chkRated.setText("Rated");
|
||||
chkRated.setToolTipText("Indicates if matches will be rated.");
|
||||
|
||||
|
@ -231,7 +235,9 @@ public class NewTableDialog extends MageDialog {
|
|||
.addGap(13, 13, 13)
|
||||
.addComponent(lblFreeMulligans)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(spnFreeMulligans, javax.swing.GroupLayout.PREFERRED_SIZE, 50, javax.swing.GroupLayout.PREFERRED_SIZE))
|
||||
.addComponent(spnFreeMulligans, javax.swing.GroupLayout.PREFERRED_SIZE, 50, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addGap(13, 13, 13)
|
||||
.addComponent(chkSpectatorsAllowed))
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addComponent(txtName, javax.swing.GroupLayout.PREFERRED_SIZE, 178, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
|
@ -325,7 +331,8 @@ public class NewTableDialog extends MageDialog {
|
|||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
|
||||
.addComponent(spnFreeMulligans, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addComponent(lblFreeMulligans)
|
||||
.addComponent(chkRollbackTurnsAllowed))
|
||||
.addComponent(chkRollbackTurnsAllowed)
|
||||
.addComponent(chkSpectatorsAllowed))
|
||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
|
||||
.addComponent(cbGameType, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addComponent(lblGameType)))
|
||||
|
@ -401,6 +408,7 @@ public class NewTableDialog extends MageDialog {
|
|||
options.setRange((RangeOfInfluence) this.cbRange.getSelectedItem());
|
||||
options.setWinsNeeded((Integer) this.spnNumWins.getValue());
|
||||
options.setRollbackTurnsAllowed(chkRollbackTurnsAllowed.isSelected());
|
||||
options.setSpectatorsAllowed(chkSpectatorsAllowed.isSelected());
|
||||
options.setRated(chkRated.isSelected());
|
||||
options.setFreeMulligans((Integer) this.spnFreeMulligans.getValue());
|
||||
options.setPassword(this.txtPassword.getText());
|
||||
|
@ -658,6 +666,7 @@ public class NewTableDialog extends MageDialog {
|
|||
}
|
||||
this.spnNumWins.setValue(Integer.parseInt(PreferencesDialog.getCachedValue(PreferencesDialog.KEY_NEW_TABLE_NUMBER_OF_WINS + versionStr, "2")));
|
||||
this.chkRollbackTurnsAllowed.setSelected(PreferencesDialog.getCachedValue(PreferencesDialog.KEY_NEW_TABLE_ROLLBACK_TURNS_ALLOWED + versionStr, "Yes").equals("Yes"));
|
||||
this.chkSpectatorsAllowed.setSelected(PreferencesDialog.getCachedValue(PreferencesDialog.KEY_NEW_TABLE_SPECTATORS_ALLOWED + versionStr, "Yes").equals("Yes"));
|
||||
this.chkRated.setSelected(PreferencesDialog.getCachedValue(PreferencesDialog.KEY_NEW_TABLE_RATED + versionStr, "No").equals("Yes"));
|
||||
this.spnFreeMulligans.setValue(Integer.parseInt(PreferencesDialog.getCachedValue(PreferencesDialog.KEY_NEW_TABLE_NUMBER_OF_FREE_MULLIGANS + versionStr, "0")));
|
||||
|
||||
|
@ -739,6 +748,7 @@ public class NewTableDialog extends MageDialog {
|
|||
private javax.swing.JComboBox cbSkillLevel;
|
||||
private javax.swing.JComboBox cbTimeLimit;
|
||||
private javax.swing.JCheckBox chkRollbackTurnsAllowed;
|
||||
private javax.swing.JCheckBox chkSpectatorsAllowed;
|
||||
private javax.swing.JCheckBox chkRated;
|
||||
private javax.swing.JLabel jLabel1;
|
||||
private javax.swing.JLabel jLabel2;
|
||||
|
|
|
@ -229,6 +229,7 @@ public class PreferencesDialog extends javax.swing.JDialog {
|
|||
public static final String KEY_NEW_TABLE_GAME_TYPE = "newTableGameType";
|
||||
public static final String KEY_NEW_TABLE_NUMBER_OF_WINS = "newTableNumberOfWins";
|
||||
public static final String KEY_NEW_TABLE_ROLLBACK_TURNS_ALLOWED = "newTableRollbackTurnsAllowed";
|
||||
public static final String KEY_NEW_TABLE_SPECTATORS_ALLOWED = "newTableSpectatorsAllowed";
|
||||
public static final String KEY_NEW_TABLE_NUMBER_OF_FREE_MULLIGANS = "newTableNumberOfFreeMulligans";
|
||||
public static final String KEY_NEW_TABLE_DECK_FILE = "newTableDeckFile";
|
||||
public static final String KEY_NEW_TABLE_RANGE = "newTableRange";
|
||||
|
|
|
@ -64,7 +64,6 @@ public class FeedbackPanel extends javax.swing.JPanel {
|
|||
private static final Logger LOGGER = Logger.getLogger(FeedbackPanel.class);
|
||||
|
||||
public enum FeedbackMode {
|
||||
|
||||
INFORM, QUESTION, CONFIRM, CANCEL, SELECT, END
|
||||
}
|
||||
|
||||
|
|
|
@ -394,7 +394,7 @@ public class HelperPanel extends JPanel {
|
|||
}
|
||||
} else {
|
||||
// inform about other players
|
||||
this.setOpaque(false);
|
||||
this.mainPanel.setOpaque(false);
|
||||
}
|
||||
|
||||
if (buttons.size() == 0) {
|
||||
|
|
|
@ -47,6 +47,8 @@ import mage.client.util.audio.AudioManager;
|
|||
import mage.client.util.object.SaveObjectUtil;
|
||||
import mage.interfaces.callback.CallbackClient;
|
||||
import mage.interfaces.callback.ClientCallback;
|
||||
import mage.remote.ActionData;
|
||||
import mage.remote.Session;
|
||||
import mage.utils.CompressUtil;
|
||||
import mage.view.*;
|
||||
import mage.view.ChatMessage.MessageType;
|
||||
|
@ -102,7 +104,6 @@ public class CallbackClientImpl implements CallbackClient {
|
|||
break;
|
||||
case CHATMESSAGE: {
|
||||
ChatMessage message = (ChatMessage) callback.getData();
|
||||
|
||||
// Drop messages from ignored users
|
||||
if (message.getUsername() != null && IgnoreList.IGNORED_MESSAGE_TYPES.contains(message.getMessageType())) {
|
||||
final String serverAddress = SessionHandler.getSession().getServerHostname().orElseGet(() -> "");
|
||||
|
@ -183,13 +184,22 @@ public class CallbackClientImpl implements CallbackClient {
|
|||
case GAME_INIT: {
|
||||
GamePanel panel = MageFrame.getGame(callback.getObjectId());
|
||||
if (panel != null) {
|
||||
appendJsonEvent("GAME_INIT", callback.getObjectId(), (GameView) callback.getData());
|
||||
panel.init((GameView) callback.getData());
|
||||
}
|
||||
break;
|
||||
}
|
||||
case GAME_OVER: {
|
||||
|
||||
GamePanel panel = MageFrame.getGame(callback.getObjectId());
|
||||
|
||||
if (panel != null) {
|
||||
appendJsonEvent("GAME_OVER", callback.getObjectId(), callback.getData());
|
||||
ActionData actionData = appendJsonEvent("GAME_OVER", callback.getObjectId(), callback.getData());
|
||||
String logFileName = "game-" + actionData.gameId + ".json";
|
||||
|
||||
S3Uploader.upload(logFileName, actionData.gameId.toString());
|
||||
|
||||
panel.endMessage((String) callback.getData(), callback.getMessageId());
|
||||
}
|
||||
break;
|
||||
|
@ -201,6 +211,7 @@ public class CallbackClientImpl implements CallbackClient {
|
|||
GameClientMessage message = (GameClientMessage) callback.getData();
|
||||
GamePanel panel = MageFrame.getGame(callback.getObjectId());
|
||||
if (panel != null) {
|
||||
appendJsonEvent("GAME_ASK", callback.getObjectId(), message);
|
||||
panel.ask(message.getMessage(), message.getGameView(), callback.getMessageId(), message.getOptions());
|
||||
}
|
||||
break;
|
||||
|
@ -208,8 +219,10 @@ public class CallbackClientImpl implements CallbackClient {
|
|||
case GAME_TARGET: // e.g. Pick triggered ability
|
||||
{
|
||||
GameClientMessage message = (GameClientMessage) callback.getData();
|
||||
|
||||
GamePanel panel = MageFrame.getGame(callback.getObjectId());
|
||||
if (panel != null) {
|
||||
appendJsonEvent("GAME_TARGET", callback.getObjectId(), message);
|
||||
panel.pickTarget(message.getMessage(), message.getCardsView(), message.getGameView(),
|
||||
message.getTargets(), message.isFlag(), message.getOptions(), callback.getMessageId());
|
||||
}
|
||||
|
@ -217,8 +230,10 @@ public class CallbackClientImpl implements CallbackClient {
|
|||
}
|
||||
case GAME_SELECT: {
|
||||
GameClientMessage message = (GameClientMessage) callback.getData();
|
||||
|
||||
GamePanel panel = MageFrame.getGame(callback.getObjectId());
|
||||
if (panel != null) {
|
||||
appendJsonEvent("GAME_SELECT", callback.getObjectId(), message);
|
||||
panel.select(message.getMessage(), message.getGameView(), callback.getMessageId(), message.getOptions());
|
||||
}
|
||||
break;
|
||||
|
@ -226,6 +241,7 @@ public class CallbackClientImpl implements CallbackClient {
|
|||
case GAME_CHOOSE_ABILITY: {
|
||||
GamePanel panel = MageFrame.getGame(callback.getObjectId());
|
||||
if (panel != null) {
|
||||
appendJsonEvent("GAME_CHOOSE_PILE", callback.getObjectId(), callback.getData());
|
||||
panel.pickAbility((AbilityPickerView) callback.getData());
|
||||
}
|
||||
break;
|
||||
|
@ -234,15 +250,18 @@ public class CallbackClientImpl implements CallbackClient {
|
|||
GameClientMessage message = (GameClientMessage) callback.getData();
|
||||
GamePanel panel = MageFrame.getGame(callback.getObjectId());
|
||||
if (panel != null) {
|
||||
appendJsonEvent("GAME_CHOOSE_PILE", callback.getObjectId(), message);
|
||||
panel.pickPile(message.getMessage(), message.getPile1(), message.getPile2());
|
||||
}
|
||||
break;
|
||||
}
|
||||
case GAME_CHOOSE_CHOICE: {
|
||||
GameClientMessage message = (GameClientMessage) callback.getData();
|
||||
|
||||
GamePanel panel = MageFrame.getGame(callback.getObjectId());
|
||||
|
||||
if (panel != null) {
|
||||
appendJsonEvent("GAME_CHOOSE_CHOICE", callback.getObjectId(), message);
|
||||
panel.getChoice(message.getChoice(), callback.getObjectId());
|
||||
}
|
||||
break;
|
||||
|
@ -251,35 +270,45 @@ public class CallbackClientImpl implements CallbackClient {
|
|||
GameClientMessage message = (GameClientMessage) callback.getData();
|
||||
GamePanel panel = MageFrame.getGame(callback.getObjectId());
|
||||
if (panel != null) {
|
||||
appendJsonEvent("GAME_PLAY_MANA", callback.getObjectId(), message);
|
||||
panel.playMana(message.getMessage(), message.getGameView(), message.getOptions(), callback.getMessageId());
|
||||
}
|
||||
break;
|
||||
}
|
||||
case GAME_PLAY_XMANA: {
|
||||
GameClientMessage message = (GameClientMessage) callback.getData();
|
||||
|
||||
GamePanel panel = MageFrame.getGame(callback.getObjectId());
|
||||
if (panel != null) {
|
||||
appendJsonEvent("GAME_PLAY_XMANA", callback.getObjectId(), message);
|
||||
panel.playXMana(message.getMessage(), message.getGameView(), callback.getMessageId());
|
||||
}
|
||||
break;
|
||||
}
|
||||
case GAME_GET_AMOUNT: {
|
||||
GameClientMessage message = (GameClientMessage) callback.getData();
|
||||
|
||||
GamePanel panel = MageFrame.getGame(callback.getObjectId());
|
||||
if (panel != null) {
|
||||
appendJsonEvent("GAME_GET_AMOUNT", callback.getObjectId(), message);
|
||||
|
||||
panel.getAmount(message.getMin(), message.getMax(), message.getMessage());
|
||||
}
|
||||
break;
|
||||
}
|
||||
case GAME_UPDATE: {
|
||||
GamePanel panel = MageFrame.getGame(callback.getObjectId());
|
||||
|
||||
if (panel != null) {
|
||||
appendJsonEvent("GAME_UPDATE", callback.getObjectId(), callback.getData());
|
||||
|
||||
panel.updateGame((GameView) callback.getData());
|
||||
}
|
||||
break;
|
||||
}
|
||||
case END_GAME_INFO:
|
||||
MageFrame.getInstance().showGameEndDialog((GameEndView) callback.getData());
|
||||
|
||||
break;
|
||||
case SHOW_USERMESSAGE:
|
||||
List<String> messageData = (List<String>) callback.getData();
|
||||
|
@ -293,6 +322,7 @@ public class CallbackClientImpl implements CallbackClient {
|
|||
GameClientMessage message = (GameClientMessage) callback.getData();
|
||||
GamePanel panel = MageFrame.getGame(callback.getObjectId());
|
||||
if (panel != null) {
|
||||
appendJsonEvent("GAME_INFORM", callback.getObjectId(), message);
|
||||
panel.inform(message.getMessage(), message.getGameView(), callback.getMessageId());
|
||||
}
|
||||
}
|
||||
|
@ -376,6 +406,14 @@ public class CallbackClientImpl implements CallbackClient {
|
|||
});
|
||||
}
|
||||
|
||||
private ActionData appendJsonEvent(String name, UUID gameId, Object value) {
|
||||
Session session = SessionHandler.getSession();
|
||||
ActionData actionData = new ActionData(name, gameId);
|
||||
actionData.value = value;
|
||||
session.appendJsonLog(actionData);
|
||||
return actionData;
|
||||
}
|
||||
|
||||
private void createChatStartMessage(ChatPanelBasic chatPanel) {
|
||||
chatPanel.setStartMessageDone(true);
|
||||
ChatPanelBasic usedPanel = chatPanel;
|
||||
|
|
45
Mage.Client/src/main/java/mage/client/remote/S3Uploader.java
Normal file
45
Mage.Client/src/main/java/mage/client/remote/S3Uploader.java
Normal file
|
@ -0,0 +1,45 @@
|
|||
package mage.client.remote;
|
||||
|
||||
import com.amazonaws.AmazonClientException;
|
||||
import com.amazonaws.auth.BasicAWSCredentials;
|
||||
import com.amazonaws.services.s3.transfer.TransferManager;
|
||||
import com.amazonaws.services.s3.transfer.Upload;
|
||||
import java.io.File;
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
public class S3Uploader {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(S3Uploader.class);
|
||||
|
||||
public static Boolean upload(String filePath, String keyName) throws Exception {
|
||||
String existingBucketName = System.getenv("S3_BUCKET") != null ? System.getenv("S3_BUCKET")
|
||||
: "xmage-game-logs-dev";
|
||||
|
||||
String accessKeyId = System.getenv("AWS_ACCESS_ID");
|
||||
String secretKeyId = System.getenv("AWS_SECRET_KEY");
|
||||
|
||||
if (accessKeyId == null || "".equals(accessKeyId)
|
||||
|| secretKeyId == null || "".equals(secretKeyId)
|
||||
|| existingBucketName == null || "".equals(existingBucketName)) {
|
||||
logger.info("Aborting json log sync.");
|
||||
return false;
|
||||
}
|
||||
|
||||
String path = new File("./" + filePath).getCanonicalPath();
|
||||
logger.info("Syncing " + path + " to bucket: " + existingBucketName + " with AWS Access Id: " + accessKeyId);
|
||||
|
||||
BasicAWSCredentials awsCreds = new BasicAWSCredentials(accessKeyId, secretKeyId);
|
||||
TransferManager tm = new TransferManager(awsCreds);
|
||||
Upload upload = tm.upload(existingBucketName, "/game/" + keyName + ".json", new File(path));
|
||||
|
||||
try {
|
||||
upload.waitForUploadResult();
|
||||
logger.info("Sync Complete For " + path + " to bucket: " + existingBucketName + " with AWS Access Id: " + accessKeyId);
|
||||
new File(path);
|
||||
return true;
|
||||
} catch (AmazonClientException amazonClientException) {
|
||||
logger.fatal("Unable to upload file, upload was aborted.", amazonClientException);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1444,11 +1444,14 @@ class TableTableModel extends AbstractTableModel {
|
|||
if (tables[arg0].isTournament()) {
|
||||
return "Show";
|
||||
} else {
|
||||
owner = tables[arg0].getControllerName();
|
||||
owner = tables[arg0].getControllerName();
|
||||
if (SessionHandler.getSession() != null && owner.equals(SessionHandler.getUserName())) {
|
||||
return "";
|
||||
}
|
||||
return "Watch";
|
||||
if (tables[arg0].getSpectatorsAllowed()) {
|
||||
return "Watch";
|
||||
}
|
||||
return "";
|
||||
}
|
||||
default:
|
||||
return "";
|
||||
|
|
|
@ -302,7 +302,7 @@ public class CardPanelRenderImpl extends CardPanel {
|
|||
= new CardPanelAttributes(cardWidth, cardHeight, isChoosable(), isSelected());
|
||||
|
||||
// Draw card itself
|
||||
cardRenderer.draw(g2d, attribs);
|
||||
cardRenderer.draw(g2d, attribs, image);
|
||||
|
||||
// Done
|
||||
g2d.dispose();
|
||||
|
|
|
@ -17,10 +17,10 @@ import mage.view.PermanentView;
|
|||
|
||||
import java.awt.*;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.awt.image.RasterFormatException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.awt.image.BufferedImage;
|
||||
|
||||
/**
|
||||
* @author stravant@gmail.com
|
||||
|
@ -201,7 +201,8 @@ public abstract class CardRenderer {
|
|||
// The Draw Method
|
||||
// The draw method takes the information caculated by the constructor
|
||||
// and uses it to draw to a concrete size of card and graphics.
|
||||
public void draw(Graphics2D g, CardPanelAttributes attribs) {
|
||||
public void draw(Graphics2D g, CardPanelAttributes attribs, BufferedImage image) {
|
||||
|
||||
// Pre template method layout, to calculate shared layout info
|
||||
layout(attribs.cardWidth, attribs.cardHeight);
|
||||
isSelected = attribs.isSelected;
|
||||
|
@ -211,7 +212,7 @@ public abstract class CardRenderer {
|
|||
drawBorder(g);
|
||||
drawBackground(g);
|
||||
drawArt(g);
|
||||
drawFrame(g);
|
||||
drawFrame(g, image);
|
||||
if (!cardView.isAbility()) {
|
||||
drawOverlays(g);
|
||||
drawCounters(g);
|
||||
|
@ -226,7 +227,7 @@ public abstract class CardRenderer {
|
|||
|
||||
protected abstract void drawArt(Graphics2D g);
|
||||
|
||||
protected abstract void drawFrame(Graphics2D g);
|
||||
protected abstract void drawFrame(Graphics2D g, BufferedImage image);
|
||||
|
||||
// Template methods that are possible to override, but unlikely to be
|
||||
// overridden.
|
||||
|
@ -462,22 +463,44 @@ public abstract class CardRenderer {
|
|||
}
|
||||
} else {
|
||||
StringBuilder sbType = new StringBuilder();
|
||||
for (SuperType superType : cardView.getSuperTypes()) {
|
||||
sbType.append(superType).append(' ');
|
||||
}
|
||||
for (CardType cardType : cardView.getCardTypes()) {
|
||||
sbType.append(cardType.toString()).append(' ');
|
||||
}
|
||||
if (!cardView.getSubTypes().isEmpty()) {
|
||||
sbType.append("- ");
|
||||
for (SubType subType : cardView.getSubTypes()) {
|
||||
sbType.append(subType).append(' ');
|
||||
String spType = getCardSuperTypeLine();
|
||||
String subType = getCardSubTypeLine();
|
||||
if (spType.equalsIgnoreCase("")) {
|
||||
sbType.append(subType);
|
||||
} else {
|
||||
sbType.append(spType);
|
||||
if (!subType.equalsIgnoreCase("")) {
|
||||
sbType.append("- ");
|
||||
sbType.append(subType);
|
||||
}
|
||||
}
|
||||
|
||||
return sbType.toString();
|
||||
}
|
||||
}
|
||||
|
||||
protected String getCardSuperTypeLine() {
|
||||
StringBuilder spType = new StringBuilder();
|
||||
for (SuperType superType : cardView.getSuperTypes()) {
|
||||
spType.append(superType).append(' ');
|
||||
}
|
||||
for (CardType cardType : cardView.getCardTypes()) {
|
||||
spType.append(cardType.toString()).append(' ');
|
||||
}
|
||||
return spType.toString();
|
||||
}
|
||||
|
||||
protected String getCardSubTypeLine() {
|
||||
StringBuilder subType = new StringBuilder();
|
||||
|
||||
if (!cardView.getSubTypes().isEmpty()) {
|
||||
for (SubType sType : cardView.getSubTypes()) {
|
||||
subType.append(sType).append(' ');
|
||||
}
|
||||
}
|
||||
return subType.toString();
|
||||
}
|
||||
|
||||
// Set the card art image (CardPanel will give it to us when it
|
||||
// is loaded and ready)
|
||||
public void setArtImage(Image image) {
|
||||
|
|
|
@ -51,8 +51,8 @@ public final class CardRendererUtils {
|
|||
// Return the buffered image
|
||||
return bimage;
|
||||
}
|
||||
|
||||
private static Color abitbrighter(Color c) {
|
||||
|
||||
public static Color abitbrighter(Color c) {
|
||||
int r = c.getRed();
|
||||
int g = c.getGreen();
|
||||
int b = c.getBlue();
|
||||
|
@ -68,7 +68,7 @@ public final class CardRendererUtils {
|
|||
alpha);
|
||||
}
|
||||
|
||||
private static Color abitdarker(Color c) {
|
||||
public static Color abitdarker(Color c) {
|
||||
int r = c.getRed();
|
||||
int g = c.getGreen();
|
||||
int b = c.getBlue();
|
||||
|
@ -108,6 +108,35 @@ public final class CardRendererUtils {
|
|||
g.drawLine(x + 1 + bevel, y + h - 2, x + 1 + bevel + w - 2 * bevel - 2, y + h - 2);
|
||||
}
|
||||
|
||||
public static void drawZendikarLandBox(Graphics2D g, int x, int y, int w, int h, int bevel, Paint border, Paint fill) {
|
||||
g.setColor(new Color(0, 0, 0, 150));
|
||||
|
||||
g.drawOval(x - 1, y, bevel * 2, h);
|
||||
g.setPaint(border);
|
||||
g.drawOval(x, y, bevel * 2 - 1, h - 1);
|
||||
g.drawOval(x + w - bevel * 2, y, bevel * 2 - 1, h - 1);
|
||||
g.drawOval(x + 1, y + 1, bevel * 2 - 3, h - 3);
|
||||
g.drawOval(x + 1 + w - bevel * 2, y + 1, bevel * 2 - 3, h - 3);
|
||||
|
||||
// The big circle in the middle.. (diameter=2+1/4 of height) - 3/4 above line, 1/2 below 0.75 + .5 + 1= 2.25 = 9/4
|
||||
g.drawOval(x + w / 2 - h - h / 8, y - 3 * h / 4, 9 * h / 4, 9 * h / 4);
|
||||
|
||||
g.drawRect(x + bevel, y, w - 2 * bevel, h - 1);
|
||||
g.drawRect(x + 1 + bevel, y + 1, w - 2 * bevel - 2, h - 3);
|
||||
g.setPaint(fill);
|
||||
g.setColor(abitbrighter(g.getColor()));
|
||||
g.drawLine(x + 1 + bevel, y + 1, x + 1 + bevel + w - 2 * bevel - 2, y + 1);
|
||||
g.setPaint(fill);
|
||||
g.setColor(abitdarker(g.getColor()));
|
||||
g.drawLine(x + 1 + bevel, y + h - 2, x + 1 + bevel + w - 2 * bevel - 2, y + h - 2);
|
||||
|
||||
g.fillOval(x + 2, y + 2, bevel * 2 - 4, h - 4);
|
||||
g.fillOval(x + 2 + w - bevel * 2, y + 2, bevel * 2 - 4, h - 4);
|
||||
g.fillRect(x + bevel, y + 2, w - 2 * bevel, h - 4);
|
||||
|
||||
g.fillOval(x + w / 2 - h - h / 8, y - 3 * h / 4, 9 * h / 4, 9 * h / 4);
|
||||
}
|
||||
|
||||
// Get the width of a mana cost rendered with ManaSymbols.draw
|
||||
public static int getManaCostWidth(String manaCost, int symbolSize) {
|
||||
int width = 0;
|
||||
|
|
|
@ -7,7 +7,11 @@ package org.mage.card.arcane;
|
|||
|
||||
import java.awt.*;
|
||||
import java.awt.font.*;
|
||||
import java.awt.geom.Arc2D;
|
||||
import java.awt.geom.Area;
|
||||
import java.awt.geom.Path2D;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
import java.awt.geom.RoundRectangle2D;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
@ -68,6 +72,13 @@ public class ModernCardRenderer extends CardRenderer {
|
|||
BufferedImage img = CardRendererUtils.toBufferedImage(icon.getImage());
|
||||
return new TexturePaint(img, new Rectangle(0, 0, img.getWidth(), img.getHeight()));
|
||||
}
|
||||
|
||||
private static BufferedImage loadBackgroundImage(String name) {
|
||||
URL url = ModernCardRenderer.class.getResource("/cardrender/background_texture_" + name + ".png");
|
||||
ImageIcon icon = new ImageIcon(url);
|
||||
BufferedImage img = CardRendererUtils.toBufferedImage(icon.getImage());
|
||||
return img;
|
||||
}
|
||||
|
||||
private static BufferedImage loadFramePart(String name) {
|
||||
URL url = ModernCardRenderer.class.getResource("/cardrender/" + name + ".png");
|
||||
|
@ -97,7 +108,18 @@ public class ModernCardRenderer extends CardRenderer {
|
|||
public static final Paint BG_TEXTURE_ARTIFACT = loadBackgroundTexture("artifact");
|
||||
public static final Paint BG_TEXTURE_LAND = loadBackgroundTexture("land");
|
||||
public static final Paint BG_TEXTURE_VEHICLE = loadBackgroundTexture("vehicle");
|
||||
|
||||
|
||||
public static final BufferedImage BG_IMG_WHITE = loadBackgroundImage("white");
|
||||
public static final BufferedImage BG_IMG_BLUE = loadBackgroundImage("blue");
|
||||
public static final BufferedImage BG_IMG_BLACK = loadBackgroundImage("black");
|
||||
public static final BufferedImage BG_IMG_RED = loadBackgroundImage("red");
|
||||
public static final BufferedImage BG_IMG_GREEN = loadBackgroundImage("green");
|
||||
public static final BufferedImage BG_IMG_GOLD = loadBackgroundImage("gold");
|
||||
public static final BufferedImage BG_IMG_ARTIFACT = loadBackgroundImage("artifact");
|
||||
public static final BufferedImage BG_IMG_LAND = loadBackgroundImage("land");
|
||||
public static final BufferedImage BG_IMG_VEHICLE = loadBackgroundImage("vehicle");
|
||||
public static final BufferedImage BG_IMG_COLORLESS = loadBackgroundImage("colorless");
|
||||
|
||||
public static final BufferedImage FRAME_INVENTION = loadFramePart("invention_frame");
|
||||
|
||||
public static final Color BORDER_WHITE = new Color(216, 203, 188);
|
||||
|
@ -279,27 +301,30 @@ public class ModernCardRenderer extends CardRenderer {
|
|||
// Just draw a brown rectangle
|
||||
drawCardBack(g);
|
||||
} else {
|
||||
BufferedImage bufferedImage = new BufferedImage(300, 300, BufferedImage.TYPE_INT_RGB);
|
||||
|
||||
// Set texture to paint with
|
||||
g.setPaint(getBackgroundPaint(cardView.getColor(), cardView.getCardTypes(), cardView.getSubTypes()));
|
||||
BufferedImage bg = getBackgroundImage(cardView.getColor(), cardView.getCardTypes(), cardView.getSubTypes());
|
||||
if (bg == null) {
|
||||
return;
|
||||
}
|
||||
int bgw = bg.getWidth();
|
||||
int bgh = bg.getHeight();
|
||||
|
||||
// Draw main part (most of card)
|
||||
g.fillRoundRect(
|
||||
borderWidth, borderWidth,
|
||||
RoundRectangle2D rr = new RoundRectangle2D.Double(borderWidth, borderWidth,
|
||||
cardWidth - borderWidth * 2, cardHeight - borderWidth * 4 - cornerRadius * 2,
|
||||
cornerRadius - 1, cornerRadius - 1);
|
||||
Area a = new Area(rr);
|
||||
|
||||
// Draw the M15 rounded "swoosh" at the bottom
|
||||
g.fillRoundRect(
|
||||
borderWidth, cardHeight - borderWidth * 4 - cornerRadius * 4,
|
||||
RoundRectangle2D rr2 = new RoundRectangle2D.Double(borderWidth, cardHeight - borderWidth * 4 - cornerRadius * 4,
|
||||
cardWidth - borderWidth * 2, cornerRadius * 4,
|
||||
cornerRadius * 2, cornerRadius * 2);
|
||||
|
||||
// Draw the cutout into the "swoosh" for the textbox to lie over
|
||||
g.fillRect(
|
||||
borderWidth + contentInset, cardHeight - borderWidth * 5,
|
||||
cardWidth - borderWidth * 2 - contentInset * 2, borderWidth * 2);
|
||||
a.add(new Area(rr2));
|
||||
|
||||
// Draw the M15 rounded "swoosh" at the bottom
|
||||
Rectangle r = new Rectangle(borderWidth + contentInset, cardHeight - borderWidth * 5, cardWidth - borderWidth * 2 - contentInset * 2, borderWidth * 2);
|
||||
a.add(new Area(r));
|
||||
g.setClip(a);
|
||||
g.drawImage(bg, 0, 0, cardWidth, cardHeight, 0, 0, bgw, bgh, BOX_BLUE, null);
|
||||
g.setClip(null);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -312,6 +337,8 @@ public class ModernCardRenderer extends CardRenderer {
|
|||
Rectangle2D rect;
|
||||
if (useInventionFrame()) {
|
||||
rect = new Rectangle2D.Float(0, 0, 1, 1);
|
||||
} else if (isZendikarFullArtLand()) {
|
||||
rect = new Rectangle2D.Float(.079f, .11f, .84f, .84f);
|
||||
} else if (cardView.getFrameStyle().isFullArt() || (cardView.isToken())) {
|
||||
rect = new Rectangle2D.Float(.079f, .11f, .84f, .63f);
|
||||
} else {
|
||||
|
@ -330,6 +357,10 @@ public class ModernCardRenderer extends CardRenderer {
|
|||
}
|
||||
}
|
||||
|
||||
private boolean isZendikarFullArtLand() {
|
||||
return cardView.getFrameStyle() == FrameStyle.BFZ_FULL_ART_BASIC || cardView.getFrameStyle() == FrameStyle.ZEN_FULL_ART_BASIC;
|
||||
}
|
||||
|
||||
protected boolean isSourceArtFullArt() {
|
||||
int color = artImage.getRGB(0, artImage.getHeight() / 2);
|
||||
return (((color & 0x00FF0000) > 0x00200000)
|
||||
|
@ -352,7 +383,7 @@ public class ModernCardRenderer extends CardRenderer {
|
|||
if (artImage != null && !cardView.isFaceDown()) {
|
||||
|
||||
boolean useFaceArt = false;
|
||||
if (faceArtImage != null) {
|
||||
if (faceArtImage != null && !isZendikarFullArtLand()) {
|
||||
useFaceArt = true;
|
||||
}
|
||||
|
||||
|
@ -395,7 +426,7 @@ public class ModernCardRenderer extends CardRenderer {
|
|||
totalContentInset + 1, totalContentInset + boxHeight,
|
||||
contentWidth - 2, typeLineY - totalContentInset - boxHeight,
|
||||
sourceRect, shouldPreserveAspect);
|
||||
} else {
|
||||
} else if (!isZendikarFullArtLand()) {
|
||||
drawArtIntoRect(g,
|
||||
totalContentInset + 1, totalContentInset + boxHeight,
|
||||
contentWidth - 2, typeLineY - totalContentInset - boxHeight,
|
||||
|
@ -405,7 +436,7 @@ public class ModernCardRenderer extends CardRenderer {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected void drawFrame(Graphics2D g) {
|
||||
protected void drawFrame(Graphics2D g, BufferedImage image) {
|
||||
// Get the card colors to base the frame on
|
||||
ObjectColor frameColors = getFrameObjectColor();
|
||||
|
||||
|
@ -421,12 +452,13 @@ public class ModernCardRenderer extends CardRenderer {
|
|||
|
||||
// Draw the main card content border
|
||||
g.setPaint(borderPaint);
|
||||
|
||||
if (cardView.getFrameStyle() == FrameStyle.KLD_INVENTION) {
|
||||
g.drawImage(FRAME_INVENTION, 0, 0, cardWidth, cardHeight, null);
|
||||
g.drawRect(
|
||||
totalContentInset, typeLineY,
|
||||
contentWidth - 1, cardHeight - borderWidth * 3 - typeLineY - 1);
|
||||
} else {
|
||||
} else if (!isZendikarFullArtLand()) {
|
||||
g.drawRect(
|
||||
totalContentInset, totalContentInset,
|
||||
contentWidth - 1, cardHeight - borderWidth * 3 - totalContentInset - 1);
|
||||
|
@ -437,11 +469,13 @@ public class ModernCardRenderer extends CardRenderer {
|
|||
g.setPaint(new Color(255, 255, 255, 150));
|
||||
} else {
|
||||
g.setPaint(textboxPaint);
|
||||
|
||||
}
|
||||
g.fillRect(
|
||||
totalContentInset + 1, typeLineY,
|
||||
contentWidth - 2, cardHeight - borderWidth * 3 - typeLineY - 1);
|
||||
|
||||
if (!isZendikarFullArtLand()) {
|
||||
g.fillRect(
|
||||
totalContentInset + 1, typeLineY,
|
||||
contentWidth - 2, cardHeight - borderWidth * 3 - typeLineY - 1);
|
||||
}
|
||||
|
||||
// If it's a planeswalker, extend the textbox left border by some
|
||||
if (cardView.isPlanesWalker()) {
|
||||
|
@ -451,7 +485,7 @@ public class ModernCardRenderer extends CardRenderer {
|
|||
cardWidth / 16, cardHeight - typeLineY - boxHeight - borderWidth * 3);
|
||||
}
|
||||
|
||||
if (cardView.getFrameStyle() != FrameStyle.KLD_INVENTION) {
|
||||
if (cardView.getFrameStyle() != FrameStyle.KLD_INVENTION && !isZendikarFullArtLand()) {
|
||||
// Draw a shadow highlight at the right edge of the content frame
|
||||
g.setColor(new Color(0, 0, 0, 100));
|
||||
g.fillRect(
|
||||
|
@ -470,26 +504,31 @@ public class ModernCardRenderer extends CardRenderer {
|
|||
cardWidth - 2 * borderWidth, boxHeight,
|
||||
contentInset,
|
||||
borderPaint, boxColor);
|
||||
|
||||
// Draw the type line box
|
||||
CardRendererUtils.drawRoundedBox(g,
|
||||
borderWidth, typeLineY,
|
||||
cardWidth - 2 * borderWidth, boxHeight,
|
||||
contentInset,
|
||||
borderPaint, boxColor);
|
||||
if (!isZendikarFullArtLand()) {
|
||||
CardRendererUtils.drawRoundedBox(g,
|
||||
borderWidth, typeLineY,
|
||||
cardWidth - 2 * borderWidth, boxHeight,
|
||||
contentInset,
|
||||
borderPaint, boxColor);
|
||||
|
||||
// Draw a small separator between the type line and box, and shadow
|
||||
// at the left of the texbox, and above the name line
|
||||
g.setColor(new Color(0, 0, 0, 150));
|
||||
g.fillRect(
|
||||
totalContentInset - 1, totalContentInset - 1,
|
||||
contentWidth + 1, 1);
|
||||
g.fillRect(
|
||||
totalContentInset + 1, typeLineY + boxHeight,
|
||||
contentWidth - 2, 1);
|
||||
g.fillRect(
|
||||
cardWidth - totalContentInset - 1, typeLineY + boxHeight,
|
||||
1, cardHeight - borderWidth * 3 - typeLineY - boxHeight);
|
||||
// Draw a small separator between the type line and box, and shadow
|
||||
// at the left of the texbox, and above the name line
|
||||
g.setColor(new Color(0, 0, 0, 150));
|
||||
g.fillRect(
|
||||
totalContentInset - 1, totalContentInset - 1,
|
||||
contentWidth + 1, 1);
|
||||
g.fillRect(
|
||||
totalContentInset + 1, typeLineY + boxHeight,
|
||||
contentWidth - 2, 1);
|
||||
g.fillRect(
|
||||
cardWidth - totalContentInset - 1, typeLineY + boxHeight,
|
||||
1, cardHeight - borderWidth * 3 - typeLineY - boxHeight);
|
||||
// Draw the type line
|
||||
drawTypeLine(g, getCardTypeLine(),
|
||||
totalContentInset, typeLineY,
|
||||
contentWidth, boxHeight, true);
|
||||
}
|
||||
|
||||
// Draw the transform circle
|
||||
int nameOffset = drawTransformationCircle(g, borderPaint);
|
||||
|
@ -502,20 +541,163 @@ public class ModernCardRenderer extends CardRenderer {
|
|||
totalContentInset + nameOffset, totalContentInset,
|
||||
contentWidth - nameOffset, boxHeight);
|
||||
|
||||
// Draw the type line
|
||||
drawTypeLine(g, getCardTypeLine(),
|
||||
totalContentInset, typeLineY,
|
||||
contentWidth, boxHeight);
|
||||
|
||||
// Draw the textbox rules
|
||||
drawRulesText(g, textboxKeywords, textboxRules,
|
||||
totalContentInset + 2, typeLineY + boxHeight + 2,
|
||||
contentWidth - 4, cardHeight - typeLineY - boxHeight - 4 - borderWidth * 3);
|
||||
if (!isZendikarFullArtLand()) {
|
||||
drawRulesText(g, textboxKeywords, textboxRules,
|
||||
totalContentInset + 2, typeLineY + boxHeight + 2,
|
||||
contentWidth - 4, cardHeight - typeLineY - boxHeight - 4 - borderWidth * 3);
|
||||
} else {
|
||||
int x = totalContentInset;
|
||||
int y = typeLineY + boxHeight + (cardHeight - typeLineY - boxHeight - 4 - borderWidth * 3) / 2 - contentInset;
|
||||
int w = contentWidth;
|
||||
int h = boxHeight - 4;
|
||||
|
||||
CardRendererUtils.drawZendikarLandBox(g,
|
||||
x, y, w, h,
|
||||
contentInset,
|
||||
borderPaint, boxColor);
|
||||
drawTypeLine(g, getCardSuperTypeLine(),
|
||||
totalContentInset + contentInset, typeLineY + boxHeight + (cardHeight - typeLineY - boxHeight - 4 - borderWidth * 3) / 2 - contentInset,
|
||||
contentWidth / 2 - boxHeight, boxHeight - 4, false);
|
||||
drawTypeLine(g, getCardSubTypeLine(),
|
||||
totalContentInset + 4 * contentWidth / 7 + boxHeight, typeLineY + boxHeight + (cardHeight - typeLineY - boxHeight - 4 - borderWidth * 3) / 2 - contentInset,
|
||||
3 * contentWidth / 7 - boxHeight - contentInset, boxHeight - 4, true);
|
||||
|
||||
if (cardView.getFrameStyle() == FrameStyle.ZEN_FULL_ART_BASIC) {
|
||||
// Draw curved lines (old Zendikar land style) - bigger (around 6%) inset on curve on bottom than inset (around 4.5%) on top...
|
||||
int x2 = x + contentWidth;
|
||||
int y2 = y;
|
||||
int thisy = totalContentInset + boxHeight;
|
||||
drawZendikarCurvedFace(g, image, x, thisy, x2, y2,
|
||||
boxColor, borderPaint);
|
||||
} else if (cardView.getFrameStyle() == FrameStyle.BFZ_FULL_ART_BASIC) {
|
||||
// Draw curved lines (BFZ land style)
|
||||
int y2 = y;
|
||||
int yb = totalContentInset + boxHeight;
|
||||
int topxdelta = 45 * contentWidth / 1000;
|
||||
int endydelta = 60 * (totalContentInset + y2) / 265;
|
||||
int x2 = x + contentWidth;
|
||||
|
||||
// Curve ends at 60 out of 265
|
||||
drawBFZCurvedFace(g, image, x, yb, x2, y2,
|
||||
topxdelta, endydelta,
|
||||
boxColor, borderPaint);
|
||||
}
|
||||
|
||||
drawRulesText(g, textboxKeywords, textboxRules,
|
||||
x, y,
|
||||
w, h);
|
||||
}
|
||||
|
||||
// Draw the bottom right stuff
|
||||
drawBottomRight(g, borderPaint, boxColor);
|
||||
}
|
||||
|
||||
public void drawZendikarCurvedFace(Graphics2D g2, BufferedImage image, int x, int y, int x2, int y2,
|
||||
Color boxColor, Paint paint) {
|
||||
|
||||
BufferedImage artToUse = faceArtImage;
|
||||
boolean hadToUseFullArt = false;
|
||||
if (faceArtImage == null) {
|
||||
if (artImage == null) {
|
||||
return;
|
||||
}
|
||||
hadToUseFullArt = true;
|
||||
artToUse = artImage;
|
||||
}
|
||||
int srcW = artToUse.getWidth();
|
||||
int srcH = artToUse.getHeight();
|
||||
|
||||
if (hadToUseFullArt) {
|
||||
// Get a box based on the standard scan from gatherer.
|
||||
// Width = 185/223 pixels (centered)
|
||||
// Height = 220/310, 38 pixels from top
|
||||
int subx = 19 * srcW / 223;
|
||||
int suby = 38 * srcH / 310;
|
||||
artToUse = artImage.getSubimage(subx, suby, 185 * srcW / 223, 220 * srcH / 310);
|
||||
}
|
||||
|
||||
Path2D.Double curve = new Path2D.Double();
|
||||
|
||||
int ew = x2 - x;
|
||||
int eh = 700 * (y2 - y) / 335;
|
||||
Arc2D arc = new Arc2D.Double(x, y - 197 * eh / 700, ew, eh, 0, 360, Arc2D.OPEN);
|
||||
Arc2D innerarc = new Arc2D.Double(x + 1, y - 197 * eh / 700 + 1, ew - 2, eh - 2, 0, 360, Arc2D.OPEN);
|
||||
|
||||
curve.append(new Rectangle2D.Double(x, y, x2 - x, y2 - y), false);
|
||||
g2.setClip(new Rectangle2D.Double(x, y, x2 - x, y2 - y));
|
||||
g2.setClip(arc);
|
||||
|
||||
Rectangle2D r = curve.getBounds2D();
|
||||
g2.drawImage(artToUse, x, y, x2 - x, y2 - y, null);
|
||||
g2.setClip(null);
|
||||
g2.setClip(new Rectangle2D.Double(x, y, x2 - x, y2 - y));
|
||||
|
||||
g2.setColor(CardRendererUtils.abitdarker(boxColor));
|
||||
g2.draw(arc);
|
||||
g2.setColor(Color.black);
|
||||
g2.draw(innerarc);
|
||||
|
||||
g2.setClip(null);
|
||||
}
|
||||
|
||||
public void drawBFZCurvedFace(Graphics2D g2, BufferedImage image, int x, int y, int x2, int y2,
|
||||
int topxdelta, int endydelta,
|
||||
Color boxColor, Paint paint) {
|
||||
BufferedImage artToUse = faceArtImage;
|
||||
boolean hadToUseFullArt = false;
|
||||
if (faceArtImage == null) {
|
||||
if (artImage == null) {
|
||||
return;
|
||||
}
|
||||
hadToUseFullArt = true;
|
||||
artToUse = artImage;
|
||||
}
|
||||
int srcW = artToUse.getWidth();
|
||||
int srcH = artToUse.getHeight();
|
||||
|
||||
if (hadToUseFullArt) {
|
||||
// Get a box based on the standard scan from gatherer.
|
||||
// Width = 185/223 pixels (centered)
|
||||
// Height = 220/310, 38 pixels from top
|
||||
int subx = 19 * srcW / 223;
|
||||
int suby = 38 * srcH / 310;
|
||||
artToUse = artImage.getSubimage(subx, suby, 185 * srcW / 223, 220 * srcH / 310);
|
||||
}
|
||||
|
||||
Path2D.Double curve = new Path2D.Double();
|
||||
curve.moveTo(x + topxdelta, y);
|
||||
curve.quadTo(x, y + endydelta / 2, x, y + endydelta);
|
||||
curve.lineTo(x, y2);
|
||||
curve.lineTo(x2, y2);
|
||||
curve.lineTo(x2, y + endydelta);
|
||||
curve.quadTo(x2, y + endydelta / 2, x2 - topxdelta, y);
|
||||
curve.lineTo(x + topxdelta, y);
|
||||
|
||||
Path2D.Double innercurve = new Path2D.Double();
|
||||
innercurve.moveTo(x + topxdelta, y + 1);
|
||||
innercurve.quadTo(x + 1, y + endydelta / 2, x + 1, y + endydelta);
|
||||
innercurve.lineTo(x + 1, y2 - 1);
|
||||
innercurve.lineTo(x2 - 1, y2 - 1);
|
||||
innercurve.lineTo(x2 - 1, y + endydelta);
|
||||
innercurve.quadTo(x2 - 1, y + endydelta / 2, x2 - topxdelta, y + 1);
|
||||
innercurve.lineTo(x + topxdelta, y + 1);
|
||||
|
||||
Rectangle2D r = curve.getBounds2D();
|
||||
int minX = (int) r.getX();
|
||||
|
||||
g2.setClip(curve);
|
||||
g2.drawImage(artToUse, minX, y, (x2 - x) + (x - minX) * 2, y2 - y, null);
|
||||
|
||||
g2.setClip(null);
|
||||
g2.setColor(CardRendererUtils.abitdarker(boxColor));
|
||||
g2.setPaint(paint);
|
||||
g2.draw(curve);
|
||||
|
||||
g2.setColor(Color.black);
|
||||
g2.draw(innercurve);
|
||||
}
|
||||
|
||||
// Draw the name line
|
||||
protected void drawNameLine(Graphics2D g, String baseName, String manaCost, int x, int y, int w, int h) {
|
||||
// Width of the mana symbols
|
||||
|
@ -566,13 +748,13 @@ public class ModernCardRenderer extends CardRenderer {
|
|||
}
|
||||
|
||||
// Draw the type line (color indicator, types, and expansion symbol)
|
||||
protected void drawTypeLine(Graphics2D g, String baseTypeLine, int x, int y, int w, int h) {
|
||||
protected void drawTypeLine(Graphics2D g, String baseTypeLine, int x, int y, int w, int h, boolean withSymbol) {
|
||||
// Draw expansion symbol
|
||||
int expansionSymbolWidth;
|
||||
int expansionSymbolWidth = 0;
|
||||
if (PreferencesDialog.getCachedValue(PreferencesDialog.KEY_CARD_RENDERING_SET_SYMBOL, "false").equals("false")) {
|
||||
if (cardView.isAbility()) {
|
||||
expansionSymbolWidth = 0;
|
||||
} else {
|
||||
} else if (withSymbol) {
|
||||
expansionSymbolWidth = drawExpansionSymbol(g, x, y, w, h);
|
||||
}
|
||||
} else {
|
||||
|
@ -792,9 +974,21 @@ public class ModernCardRenderer extends CardRenderer {
|
|||
}
|
||||
|
||||
// Basic mana draw mana symbol in textbox (for basic lands)
|
||||
if (allRules.size() == 1 && (allRules.get(0) instanceof TextboxBasicManaRule) && cardView.isLand()) {
|
||||
drawBasicManaTextbox(g, x, y, w, h, ((TextboxBasicManaRule) allRules.get(0)).getBasicManaSymbol());
|
||||
return;
|
||||
if (allRules.size() == 1 && (allRules.get(0) instanceof TextboxBasicManaRule) && cardView.isLand() || isZendikarFullArtLand()) {
|
||||
if (!isZendikarFullArtLand()) {
|
||||
drawBasicManaTextbox(g, x, y, w, h, ((TextboxBasicManaRule) allRules.get(0)).getBasicManaSymbol());
|
||||
return;
|
||||
} else // Big circle in the middle for Zendikar lands
|
||||
if (allRules.size() == 1) {
|
||||
// Size of mana symbol = 9/4 * h, 3/4h above line
|
||||
drawBasicManaSymbol(g, x + w / 2 - 9 * h / 8 + 1, y - 3 * h / 4, 9 * h / 4, 9 * h / 4, ((TextboxBasicManaRule) allRules.get(0)).getBasicManaSymbol());
|
||||
return;
|
||||
} else {
|
||||
if (allRules.size() > 1) {
|
||||
drawBasicManaSymbol(g, x + w / 2 - h - h / 8, y - 3 * h / 4, 9 * h / 4, 9 * h / 4, cardView.getFrameColor().toString());
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Go through possible font sizes in descending order to find the best fit
|
||||
|
@ -847,6 +1041,11 @@ public class ModernCardRenderer extends CardRenderer {
|
|||
ManaSymbols.draw(g, symbs, x + (w - manaCostWidth) / 2, y + (h - symbHeight) / 2, symbHeight, Color.black, 2);
|
||||
}
|
||||
|
||||
private void drawBasicManaSymbol(Graphics2D g, int x, int y, int w, int h, String symbol) {
|
||||
String symbs = symbol;
|
||||
ManaSymbols.draw(g, symbs, x, y, w, Color.black, 2);
|
||||
}
|
||||
|
||||
// Get the first line of the textbox, the keyword string
|
||||
private static String getKeywordRulesString(ArrayList<TextboxRule> keywords) {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
|
@ -1073,7 +1272,34 @@ public class ModernCardRenderer extends CardRenderer {
|
|||
return new Color(71, 86, 101);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Determine which background image to use from a set of colors
|
||||
// and the current card.
|
||||
protected static BufferedImage getBackgroundImage(ObjectColor colors, Collection<CardType> types, SubTypeList subTypes) {
|
||||
if (subTypes.contains(SubType.VEHICLE)) {
|
||||
return BG_IMG_VEHICLE;
|
||||
} else if (types.contains(CardType.LAND)) {
|
||||
return BG_IMG_LAND;
|
||||
} else if (types.contains(CardType.ARTIFACT)) {
|
||||
return BG_IMG_ARTIFACT;
|
||||
} else if (colors.isMulticolored()) {
|
||||
return BG_IMG_GOLD;
|
||||
} else if (colors.isWhite()) {
|
||||
return BG_IMG_WHITE;
|
||||
} else if (colors.isBlue()) {
|
||||
return BG_IMG_BLUE;
|
||||
} else if (colors.isBlack()) {
|
||||
return BG_IMG_BLACK;
|
||||
} else if (colors.isRed()) {
|
||||
return BG_IMG_RED;
|
||||
} else if (colors.isGreen()) {
|
||||
return BG_IMG_GREEN;
|
||||
} else {
|
||||
// Colorless
|
||||
return BG_IMG_COLORLESS;
|
||||
}
|
||||
}
|
||||
|
||||
// Get the box color for the given colors
|
||||
protected Color getBoxColor(ObjectColor colors, Collection<CardType> types, boolean isNightCard) {
|
||||
if (cardView.isAbility()) {
|
||||
|
|
|
@ -8,6 +8,7 @@ import mage.view.CardView;
|
|||
|
||||
import java.awt.*;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
|
@ -17,6 +18,7 @@ import java.util.List;
|
|||
public class ModernSplitCardRenderer extends ModernCardRenderer {
|
||||
|
||||
private class HalfCardProps {
|
||||
|
||||
int x, y, w, h, cw, ch;
|
||||
|
||||
String name;
|
||||
|
@ -27,7 +29,11 @@ public class ModernSplitCardRenderer extends ModernCardRenderer {
|
|||
ArrayList<TextboxRule> keywords = new ArrayList<>();
|
||||
}
|
||||
|
||||
private static ArrayList<CardType> ONLY_LAND_TYPE = new ArrayList<CardType>() {{add(CardType.LAND);}};
|
||||
private static ArrayList<CardType> ONLY_LAND_TYPE = new ArrayList<CardType>() {
|
||||
{
|
||||
add(CardType.LAND);
|
||||
}
|
||||
};
|
||||
|
||||
// Right and left halves of the card content
|
||||
private HalfCardProps rightHalf = new HalfCardProps();
|
||||
|
@ -88,20 +94,20 @@ public class ModernSplitCardRenderer extends ModernCardRenderer {
|
|||
// Decide size of divider
|
||||
if (isAftermath()) {
|
||||
dividerSize = borderWidth;
|
||||
dividerAt = (int)(cardHeight*0.54);
|
||||
dividerAt = (int) (cardHeight * 0.54);
|
||||
} else {
|
||||
int availHeight = cardHeight - totalContentInset - 3*borderWidth;
|
||||
dividerSize = borderWidth*2;
|
||||
dividerAt = (int)(totalContentInset + availHeight * 0.5 - borderWidth);
|
||||
int availHeight = cardHeight - totalContentInset - 3 * borderWidth;
|
||||
dividerSize = borderWidth * 2;
|
||||
dividerAt = (int) (totalContentInset + availHeight * 0.5 - borderWidth);
|
||||
}
|
||||
|
||||
// Decide size of each halves box
|
||||
rightHalf.x = leftHalf.x = totalContentInset;
|
||||
rightHalf.w = leftHalf.w = cardWidth - 2*totalContentInset;
|
||||
rightHalf.w = leftHalf.w = cardWidth - 2 * totalContentInset;
|
||||
leftHalf.y = totalContentInset;
|
||||
leftHalf.h = dividerAt - totalContentInset;
|
||||
rightHalf.y = dividerAt + dividerSize;
|
||||
rightHalf.h = cardHeight - rightHalf.y - borderWidth*3;
|
||||
rightHalf.h = cardHeight - rightHalf.y - borderWidth * 3;
|
||||
|
||||
// Content width / height (Exchanged from width / height if the card part is rotated)
|
||||
if (isAftermath()) {
|
||||
|
@ -126,7 +132,7 @@ public class ModernSplitCardRenderer extends ModernCardRenderer {
|
|||
private ObjectColor getColorFromManaCostHack(ManaCosts costs) {
|
||||
ObjectColor c = new ObjectColor();
|
||||
List<String> symbols = costs.getSymbols();
|
||||
for (String symbol: symbols) {
|
||||
for (String symbol : symbols) {
|
||||
if (symbol.contains("W")) {
|
||||
c.setWhite(true);
|
||||
} else if (symbol.contains("U")) {
|
||||
|
@ -154,18 +160,18 @@ public class ModernSplitCardRenderer extends ModernCardRenderer {
|
|||
// Draw main part (most of card)
|
||||
g.fillRoundRect(
|
||||
borderWidth, borderWidth,
|
||||
cardWidth - 2*borderWidth, leftHalf.h + contentInset - borderWidth - 2*cornerRadius + (cornerRadius - 1),
|
||||
cardWidth - 2 * borderWidth, leftHalf.h + contentInset - borderWidth - 2 * cornerRadius + (cornerRadius - 1),
|
||||
cornerRadius - 1, cornerRadius - 1);
|
||||
|
||||
// Draw the M15 rounded "swoosh" at the bottom
|
||||
g.fillRoundRect(
|
||||
borderWidth, dividerAt - borderWidth - 4*cornerRadius,
|
||||
cardWidth - 2*borderWidth, cornerRadius * 4,
|
||||
borderWidth, dividerAt - borderWidth - 4 * cornerRadius,
|
||||
cardWidth - 2 * borderWidth, cornerRadius * 4,
|
||||
cornerRadius * 2, cornerRadius * 2);
|
||||
|
||||
// Draw the cutout into the "swoosh" for the textbox to lie over
|
||||
g.fillRect(
|
||||
borderWidth + contentInset, dividerAt - 2*borderWidth,
|
||||
borderWidth + contentInset, dividerAt - 2 * borderWidth,
|
||||
cardWidth - borderWidth * 2 - contentInset * 2, borderWidth * 2);
|
||||
}
|
||||
|
||||
|
@ -176,8 +182,8 @@ public class ModernSplitCardRenderer extends ModernCardRenderer {
|
|||
// Draw the M15 rounded "swoosh"es at the top and bottom
|
||||
g.fillRoundRect(
|
||||
borderWidth, dividerAt + dividerSize + borderWidth,
|
||||
cardWidth - 2*borderWidth, rightHalf.h - 2*borderWidth,
|
||||
cornerRadius*2, cornerRadius*2);
|
||||
cardWidth - 2 * borderWidth, rightHalf.h - 2 * borderWidth,
|
||||
cornerRadius * 2, cornerRadius * 2);
|
||||
|
||||
// Draw the cutout into the "swoosh" for the textbox to lie over
|
||||
g.fillRect(
|
||||
|
@ -236,8 +242,8 @@ public class ModernSplitCardRenderer extends ModernCardRenderer {
|
|||
// Background of textbox
|
||||
g.setPaint(textboxPaint);
|
||||
g.fillRect(
|
||||
1, typeLineY,
|
||||
half.cw - 2, half.ch - typeLineY - 1);
|
||||
1, typeLineY,
|
||||
half.cw - 2, half.ch - typeLineY - 1);
|
||||
|
||||
// Draw the name line box
|
||||
CardRendererUtils.drawRoundedBox(g,
|
||||
|
@ -261,7 +267,7 @@ public class ModernSplitCardRenderer extends ModernCardRenderer {
|
|||
// Draw the type line
|
||||
drawTypeLine(g, half.typeLineString,
|
||||
0, typeLineY,
|
||||
half.cw, boxHeight - 4);
|
||||
half.cw, boxHeight - 4, true);
|
||||
|
||||
// Draw the textbox rules
|
||||
drawRulesText(g, half.keywords, half.rules,
|
||||
|
@ -270,13 +276,13 @@ public class ModernSplitCardRenderer extends ModernCardRenderer {
|
|||
}
|
||||
|
||||
private Graphics2D getUnmodifiedHalfContext(Graphics2D g) {
|
||||
Graphics2D g2 = (Graphics2D)g.create();
|
||||
Graphics2D g2 = (Graphics2D) g.create();
|
||||
g2.translate(leftHalf.x, leftHalf.y);
|
||||
return g2;
|
||||
}
|
||||
|
||||
private Graphics2D getAftermathHalfContext(Graphics2D g) {
|
||||
Graphics2D g2 = (Graphics2D)g.create();
|
||||
Graphics2D g2 = (Graphics2D) g.create();
|
||||
g2.translate(rightHalf.x, rightHalf.y);
|
||||
g2.rotate(Math.PI / 2);
|
||||
g2.translate(0, -rightHalf.w);
|
||||
|
@ -284,7 +290,7 @@ public class ModernSplitCardRenderer extends ModernCardRenderer {
|
|||
}
|
||||
|
||||
private Graphics2D getLeftHalfContext(Graphics2D g) {
|
||||
Graphics2D g2 = (Graphics2D)g.create();
|
||||
Graphics2D g2 = (Graphics2D) g.create();
|
||||
g2.translate(leftHalf.x, leftHalf.y);
|
||||
g2.rotate(-Math.PI / 2);
|
||||
g2.translate(-leftHalf.cw, 0);
|
||||
|
@ -292,7 +298,7 @@ public class ModernSplitCardRenderer extends ModernCardRenderer {
|
|||
}
|
||||
|
||||
private Graphics2D getRightHalfContext(Graphics2D g) {
|
||||
Graphics2D g2 = (Graphics2D)g.create();
|
||||
Graphics2D g2 = (Graphics2D) g.create();
|
||||
g2.translate(rightHalf.x, rightHalf.y);
|
||||
g2.rotate(-Math.PI / 2);
|
||||
g2.translate(-rightHalf.cw, 0);
|
||||
|
@ -300,13 +306,13 @@ public class ModernSplitCardRenderer extends ModernCardRenderer {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected void drawFrame(Graphics2D g) {
|
||||
protected void drawFrame(Graphics2D g, BufferedImage image) {
|
||||
if (isAftermath()) {
|
||||
drawSplitHalfFrame(getUnmodifiedHalfContext(g), leftHalf, (int)(leftHalf.ch * TYPE_LINE_Y_FRAC));
|
||||
drawSplitHalfFrame(getUnmodifiedHalfContext(g), leftHalf, (int) (leftHalf.ch * TYPE_LINE_Y_FRAC));
|
||||
drawSplitHalfFrame(getAftermathHalfContext(g), rightHalf, (rightHalf.ch - boxHeight) / 2);
|
||||
} else {
|
||||
drawSplitHalfFrame(getLeftHalfContext(g), leftHalf, (int)(leftHalf.ch * TYPE_LINE_Y_FRAC));
|
||||
drawSplitHalfFrame(getRightHalfContext(g), rightHalf, (int)(rightHalf.ch * TYPE_LINE_Y_FRAC));
|
||||
drawSplitHalfFrame(getLeftHalfContext(g), leftHalf, (int) (leftHalf.ch * TYPE_LINE_Y_FRAC));
|
||||
drawSplitHalfFrame(getRightHalfContext(g), rightHalf, (int) (rightHalf.ch * TYPE_LINE_Y_FRAC));
|
||||
if (isFuse()) {
|
||||
Graphics2D g2 = getRightHalfContext(g);
|
||||
int totalFuseBoxWidth = rightHalf.cw * 2 + 2 * borderWidth + dividerSize;
|
||||
|
@ -319,7 +325,7 @@ public class ModernSplitCardRenderer extends ModernCardRenderer {
|
|||
borderPaint, boxColor);
|
||||
drawNameLine(g2, "Fuse (You may cast both halves from your hand)", "",
|
||||
0, rightHalf.ch,
|
||||
totalFuseBoxWidth - 2*borderWidth, boxHeight);
|
||||
totalFuseBoxWidth - 2 * borderWidth, boxHeight);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -66,7 +66,7 @@ public class GathererSets implements Iterable<DownloadJob> {
|
|||
//"APAC" -- gatherer do not have that set, scrly have PALP
|
||||
//"ARENA" -- is't many set with different codes, not one
|
||||
"CLASH", "CP", "DD3GVL", "DPA", "EURO", "FNMP", "GPX", "GRC", "GUR", "H17", "JR", "MBP", "MGDC", "MLP", "MPRP", "MPS-AKH", "PTC", "S00", "S99", "SUS", "SWS", "UGIN", "UGL", "V10", "V17", "WMCQ", // need to fix
|
||||
"H09", "PD2", "PD3", "UNH", "CM1", "E02", "V11", "M25", "UST", "IMA", "DD2", "EVG", "DDC", "DDE", "DDD", "DDT", "8EB", "9EB", "CHR" // ok
|
||||
"H09", "PD2", "PD3", "UNH", "CM1", "E02", "V11", "A25", "UST", "IMA", "DD2", "EVG", "DDC", "DDE", "DDD", "DDT", "8EB", "9EB", "CHR" // ok
|
||||
// current testing
|
||||
};
|
||||
|
||||
|
|
|
@ -208,7 +208,7 @@ public enum ScryfallImageSource implements CardImageSource {
|
|||
supportedSets.add("RIX");
|
||||
supportedSets.add("WMCQ");
|
||||
supportedSets.add("PPRO");
|
||||
// supportedSets.add("A25");
|
||||
supportedSets.add("A25");
|
||||
// supportedSets.add("DOM");
|
||||
// supportedSets.add("M19");
|
||||
|
||||
|
|
|
@ -268,7 +268,7 @@ public enum WizardCardsImageSource implements CardImageSource {
|
|||
supportedSets.add("V17"); // From the Vault: Transform
|
||||
supportedSets.add("UST"); // Unstable
|
||||
supportedSets.add("RIX"); // Rivals of Ixalan
|
||||
// supportedSets.add("A25"); // Masters 25
|
||||
supportedSets.add("A25"); // Masters 25
|
||||
// supportedSets.add("DOM"); // Dominaria
|
||||
// supportedSets.add("M19"); // Core 2019
|
||||
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 57 KiB |
Binary file not shown.
Before Width: | Height: | Size: 685 B After Width: | Height: | Size: 19 KiB |
|
@ -73,6 +73,6 @@ dd3evg=ddaevg
|
|||
dd3gvl=ddagvl
|
||||
dd3jvc=ddajvc
|
||||
# Remove setname as soon as the images can be downloaded
|
||||
ignore.urls=TOK,M19,M25,DOM,H17
|
||||
ignore.urls=TOK,M19,DOM,H17
|
||||
# sets ordered by release time (newest goes first)
|
||||
token.lookup.order=M19,M25,DOM,E02,RIX,UST,XLN,IMA,H17,C17,V17,E01,DDT,CMA,HOU,MM3,DDS,AKH,DD3DVD,DD3EVG,DD3GVL,DD3JVC,H09,AER,PCA,C16,V16,MPS,KLD,DDR,CN2,EMN,EMA,SOI,DDQ,CP,CMA,ARENA,SUS,APAC,EURO,UGIN,C15,OGW,EXP,DDP,BFZ,DRB,V09,V10,V11,V12,V13,V14,V15,TPR,MPRP,DD3,DDO,ORI,MM2,PTC,DTK,FRF,KTK,M15,VMA,CNS,JOU,BNG,THS,DDL,M14,MMA,DGM,GTC,RTR,M13,AVR,DDI,DKA,ISD,M12,NPH,MBS,SOM,M11,ROE,DDE,WWK,ZEN,M10,GVL,ARB,DVD,CFX,JVC,ALA,EVE,SHM,EVG,MOR,LRW,10E,CLS,CHK,GRC
|
||||
token.lookup.order=M19,A25,DOM,E02,RIX,UST,XLN,IMA,H17,C17,V17,E01,DDT,CMA,HOU,MM3,DDS,AKH,DD3DVD,DD3EVG,DD3GVL,DD3JVC,H09,AER,PCA,C16,V16,MPS,KLD,DDR,CN2,EMN,EMA,SOI,DDQ,CP,CMA,ARENA,SUS,APAC,EURO,UGIN,C15,OGW,EXP,DDP,BFZ,DRB,V09,V10,V11,V12,V13,V14,V15,TPR,MPRP,DD3,DDO,ORI,MM2,PTC,DTK,FRF,KTK,M15,VMA,CNS,JOU,BNG,THS,DDL,M14,MMA,DGM,GTC,RTR,M13,AVR,DDI,DKA,ISD,M12,NPH,MBS,SOM,M11,ROE,DDE,WWK,ZEN,M10,GVL,ARB,DVD,CFX,JVC,ALA,EVE,SHM,EVG,MOR,LRW,10E,CLS,CHK,GRC
|
|
@ -25,6 +25,7 @@
|
|||
<artifactId>jspf-core</artifactId>
|
||||
<version>0.9.1</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.jboss.remoting</groupId>
|
||||
<artifactId>jboss-remoting</artifactId>
|
||||
|
@ -50,7 +51,11 @@
|
|||
<artifactId>trove</artifactId>
|
||||
<version>1.0.2</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.google.code.gson</groupId>
|
||||
<artifactId>gson</artifactId>
|
||||
<version>2.8.2</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<!-- to get the reference to local repository with com\googlecode\jspf\jspf-core\0.9.1\ -->
|
||||
<repositories>
|
||||
|
|
138
Mage.Common/src/main/java/mage/remote/ActionData.java
Normal file
138
Mage.Common/src/main/java/mage/remote/ActionData.java
Normal file
|
@ -0,0 +1,138 @@
|
|||
/*
|
||||
* Copyright 2018 nanarpuss_at_googlemail.com. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are
|
||||
* permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
* conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
* of conditions and the following disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* The views and conclusions contained in the software and documentation are those of the
|
||||
* authors and should not be interpreted as representing official policies, either expressed
|
||||
* or implied, of BetaSteward_at_googlemail.com.
|
||||
*/
|
||||
package mage.remote;
|
||||
|
||||
import com.google.gson.ExclusionStrategy;
|
||||
import com.google.gson.FieldAttributes;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.google.gson.annotations.Expose;
|
||||
import java.util.UUID;
|
||||
|
||||
public class ActionData {
|
||||
|
||||
@Expose
|
||||
public UUID gameId;
|
||||
@Expose
|
||||
public String sessionId;
|
||||
@Expose
|
||||
public String type;
|
||||
@Expose
|
||||
public Object value;
|
||||
@Expose
|
||||
public String message;
|
||||
|
||||
public String toJson() {
|
||||
GsonBuilder gsonBuilder = new GsonBuilder();
|
||||
Gson gson = gsonBuilder.setExclusionStrategies(new CustomExclusionStrategy()).create();
|
||||
|
||||
return gson.toJson(this);
|
||||
}
|
||||
|
||||
public ActionData(String type, UUID gameId, String sessionId) {
|
||||
this.type = type;
|
||||
this.sessionId = sessionId;
|
||||
this.gameId = gameId;
|
||||
}
|
||||
|
||||
public ActionData(String type, UUID gameId) {
|
||||
this.type = type;
|
||||
this.gameId = gameId;
|
||||
}
|
||||
|
||||
public class CustomExclusionStrategy implements ExclusionStrategy {
|
||||
|
||||
// FIXME: Very crude way of whitelisting, as it applies to all levels of the JSON tree.
|
||||
private final java.util.Set<String> KEEP = new java.util.HashSet<>(
|
||||
java.util.Arrays.asList(
|
||||
new String[]{
|
||||
"id",
|
||||
"choice",
|
||||
"damage",
|
||||
"abilityType",
|
||||
"ability",
|
||||
"abilities",
|
||||
"method",
|
||||
"data",
|
||||
"options",
|
||||
"life",
|
||||
"players",
|
||||
"zone",
|
||||
"step",
|
||||
"phase",
|
||||
"attackers",
|
||||
"blockers",
|
||||
"tapped",
|
||||
"damage",
|
||||
"combat",
|
||||
"paid",
|
||||
"hand",
|
||||
"stack",
|
||||
"convertedManaCost",
|
||||
"gameId",
|
||||
"canPlayInHand",
|
||||
"gameView",
|
||||
"sessionId",
|
||||
"power",
|
||||
"choices",
|
||||
"targets",
|
||||
"loyalty",
|
||||
"toughness",
|
||||
"power",
|
||||
"type",
|
||||
"priorityTime",
|
||||
"manaCost",
|
||||
"value",
|
||||
"message",
|
||||
"cardsView",
|
||||
"name",
|
||||
"count",
|
||||
"counters",
|
||||
"battlefield",
|
||||
"parentId"
|
||||
}));
|
||||
|
||||
public CustomExclusionStrategy() {
|
||||
}
|
||||
|
||||
// This method is called for all fields. if the method returns true the
|
||||
// field is excluded from serialization
|
||||
@Override
|
||||
public boolean shouldSkipField(FieldAttributes f) {
|
||||
String name = f.getName();
|
||||
return !KEEP.contains(name);
|
||||
}
|
||||
|
||||
// This method is called for all classes. If the method returns true the
|
||||
// class is excluded.
|
||||
@Override
|
||||
public boolean shouldSkipClass(Class<?> clazz) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -24,8 +24,7 @@
|
|||
* The views and conclusions contained in the software and documentation are those of the
|
||||
* authors and should not be interpreted as representing official policies, either expressed
|
||||
* or implied, of BetaSteward_at_googlemail.com.
|
||||
*/
|
||||
|
||||
*/
|
||||
package mage.remote;
|
||||
|
||||
import mage.remote.interfaces.ChatSession;
|
||||
|
@ -46,4 +45,5 @@ import mage.remote.interfaces.Testable;
|
|||
*/
|
||||
public interface Session extends ClientData, Connect, GamePlay, GameTypes, ServerState, ChatSession, Feedback, PlayerActions, Replays, Testable {
|
||||
|
||||
public void appendJsonLog(ActionData actionData);
|
||||
}
|
||||
|
|
|
@ -27,12 +27,14 @@
|
|||
*/
|
||||
package mage.remote;
|
||||
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.lang.reflect.UndeclaredThrowableException;
|
||||
import java.net.*;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import javax.swing.*;
|
||||
import mage.MageException;
|
||||
import mage.cards.decks.DeckCardLists;
|
||||
import mage.cards.repository.CardInfo;
|
||||
|
@ -799,6 +801,9 @@ public class SessionImpl implements Session {
|
|||
public boolean sendPlayerUUID(UUID gameId, UUID data) {
|
||||
try {
|
||||
if (isConnected()) {
|
||||
ActionData actionData = new ActionData("SEND_PLAYER_UUID", gameId, getSessionId());
|
||||
actionData.value = data;
|
||||
appendJsonLog(actionData);
|
||||
server.sendPlayerUUID(gameId, sessionId, data);
|
||||
return true;
|
||||
}
|
||||
|
@ -814,6 +819,10 @@ public class SessionImpl implements Session {
|
|||
public boolean sendPlayerBoolean(UUID gameId, boolean data) {
|
||||
try {
|
||||
if (isConnected()) {
|
||||
ActionData actionData = new ActionData("SEND_PLAYER_BOOLEAN", gameId, getSessionId());
|
||||
actionData.value = data;
|
||||
appendJsonLog(actionData);
|
||||
|
||||
server.sendPlayerBoolean(gameId, sessionId, data);
|
||||
return true;
|
||||
}
|
||||
|
@ -829,6 +838,10 @@ public class SessionImpl implements Session {
|
|||
public boolean sendPlayerInteger(UUID gameId, int data) {
|
||||
try {
|
||||
if (isConnected()) {
|
||||
ActionData actionData = new ActionData("SEND_PLAYER_INTEGER", gameId, getSessionId());
|
||||
actionData.value = data;
|
||||
appendJsonLog(actionData);
|
||||
|
||||
server.sendPlayerInteger(gameId, sessionId, data);
|
||||
return true;
|
||||
}
|
||||
|
@ -844,6 +857,10 @@ public class SessionImpl implements Session {
|
|||
public boolean sendPlayerString(UUID gameId, String data) {
|
||||
try {
|
||||
if (isConnected()) {
|
||||
ActionData actionData = new ActionData("SEND_PLAYER_STRING", gameId, getSessionId());
|
||||
actionData.value = data;
|
||||
appendJsonLog(actionData);
|
||||
|
||||
server.sendPlayerString(gameId, sessionId, data);
|
||||
return true;
|
||||
}
|
||||
|
@ -859,6 +876,9 @@ public class SessionImpl implements Session {
|
|||
public boolean sendPlayerManaType(UUID gameId, UUID playerId, ManaType data) {
|
||||
try {
|
||||
if (isConnected()) {
|
||||
ActionData actionData = new ActionData("SEND_PLAYER_MANA_TYPE", gameId, getSessionId());
|
||||
actionData.value = data;
|
||||
appendJsonLog(actionData);
|
||||
server.sendPlayerManaType(gameId, playerId, sessionId, data);
|
||||
return true;
|
||||
}
|
||||
|
@ -870,6 +890,17 @@ public class SessionImpl implements Session {
|
|||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void appendJsonLog(ActionData actionData) {
|
||||
actionData.sessionId = getSessionId();
|
||||
String logFileName = "game-" + actionData.gameId + ".json";
|
||||
try (PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter(logFileName, true)))) {
|
||||
out.println(actionData.toJson());
|
||||
} catch (IOException e) {
|
||||
System.err.println(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public DraftPickView sendCardPick(UUID draftId, UUID cardId, Set<UUID> hiddenCards) {
|
||||
try {
|
||||
|
@ -1275,6 +1306,11 @@ public class SessionImpl implements Session {
|
|||
public boolean sendPlayerAction(PlayerAction passPriorityAction, UUID gameId, Object data) {
|
||||
try {
|
||||
if (isConnected()) {
|
||||
ActionData actionData = new ActionData("SEND_PLAYER_ACTION", gameId, getSessionId());
|
||||
|
||||
actionData.value = data;
|
||||
appendJsonLog(actionData);
|
||||
|
||||
server.sendPlayerAction(passPriorityAction, gameId, sessionId, data);
|
||||
return true;
|
||||
}
|
||||
|
@ -1437,12 +1473,9 @@ public class SessionImpl implements Session {
|
|||
@Override
|
||||
public boolean endUserSession(String userSessionId) {
|
||||
try {
|
||||
if (JOptionPane.showConfirmDialog(null, "Are you sure you mean to end userSessionId " + userSessionId + '?', "WARNING",
|
||||
JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION) {
|
||||
if (isConnected()) {
|
||||
server.endUserSession(sessionId, userSessionId);
|
||||
return true;
|
||||
}
|
||||
if (isConnected()) {
|
||||
server.endUserSession(sessionId, userSessionId);
|
||||
return true;
|
||||
}
|
||||
} catch (MageException ex) {
|
||||
handleMageException(ex);
|
||||
|
@ -1455,12 +1488,9 @@ public class SessionImpl implements Session {
|
|||
@Override
|
||||
public boolean muteUserChat(String userName, long durationMinutes) {
|
||||
try {
|
||||
if (JOptionPane.showConfirmDialog(null, "Are you sure you mean to mute user " + userName + " for " + durationMinutes + " minutes?", "WARNING",
|
||||
JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION) {
|
||||
if (isConnected()) {
|
||||
server.muteUser(sessionId, userName, durationMinutes);
|
||||
return true;
|
||||
}
|
||||
if (isConnected()) {
|
||||
server.muteUser(sessionId, userName, durationMinutes);
|
||||
return true;
|
||||
}
|
||||
} catch (MageException ex) {
|
||||
handleMageException(ex);
|
||||
|
@ -1473,12 +1503,9 @@ public class SessionImpl implements Session {
|
|||
@Override
|
||||
public boolean setActivation(String userName, boolean active) {
|
||||
try {
|
||||
if (JOptionPane.showConfirmDialog(null, "Are you sure you mean to set active to " + active + " for user: " + userName + '?', "WARNING",
|
||||
JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION) {
|
||||
if (isConnected()) {
|
||||
server.setActivation(sessionId, userName, active);
|
||||
return true;
|
||||
}
|
||||
if (isConnected()) {
|
||||
server.setActivation(sessionId, userName, active);
|
||||
return true;
|
||||
}
|
||||
} catch (MageException ex) {
|
||||
handleMageException(ex);
|
||||
|
@ -1491,20 +1518,9 @@ public class SessionImpl implements Session {
|
|||
@Override
|
||||
public boolean toggleActivation(String userName) {
|
||||
try {
|
||||
if (JOptionPane.showConfirmDialog(null, "Did you want to set user: " + userName + " to active?", "WARNING",
|
||||
JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION) {
|
||||
return setActivation(userName, true);
|
||||
}
|
||||
if (JOptionPane.showConfirmDialog(null, "Did you want to set user: " + userName + " to INactive?", "WARNING",
|
||||
JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION) {
|
||||
return setActivation(userName, false);
|
||||
}
|
||||
if (JOptionPane.showConfirmDialog(null, "Are you sure you mean to toggle activation for user: " + userName + '?', "WARNING",
|
||||
JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION) {
|
||||
if (isConnected()) {
|
||||
server.toggleActivation(sessionId, userName);
|
||||
return true;
|
||||
}
|
||||
if (isConnected()) {
|
||||
server.toggleActivation(sessionId, userName);
|
||||
return true;
|
||||
}
|
||||
} catch (MageException ex) {
|
||||
handleMageException(ex);
|
||||
|
@ -1517,12 +1533,9 @@ public class SessionImpl implements Session {
|
|||
@Override
|
||||
public boolean lockUser(String userName, long durationMinute) {
|
||||
try {
|
||||
if (JOptionPane.showConfirmDialog(null, "Are you sure you mean to lock user: " + userName + " for " + durationMinute + " minutes?", "WARNING",
|
||||
JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION) {
|
||||
if (isConnected()) {
|
||||
server.lockUser(sessionId, userName, durationMinute);
|
||||
return true;
|
||||
}
|
||||
if (isConnected()) {
|
||||
server.lockUser(sessionId, userName, durationMinute);
|
||||
return true;
|
||||
}
|
||||
} catch (MageException ex) {
|
||||
handleMageException(ex);
|
||||
|
|
|
@ -53,6 +53,8 @@ import mage.target.Target;
|
|||
import mage.target.Targets;
|
||||
import mage.util.SubTypeList;
|
||||
|
||||
import com.google.gson.annotations.Expose;
|
||||
|
||||
/**
|
||||
* @author BetaSteward_at_googlemail.com
|
||||
*/
|
||||
|
@ -61,11 +63,17 @@ public class CardView extends SimpleCardView {
|
|||
private static final long serialVersionUID = 1L;
|
||||
|
||||
protected UUID parentId;
|
||||
@Expose
|
||||
protected String name;
|
||||
@Expose
|
||||
protected String displayName;
|
||||
@Expose
|
||||
protected List<String> rules;
|
||||
@Expose
|
||||
protected String power;
|
||||
@Expose
|
||||
protected String toughness;
|
||||
@Expose
|
||||
protected String loyalty = "";
|
||||
protected String startingLoyalty;
|
||||
protected EnumSet<CardType> cardTypes;
|
||||
|
@ -110,7 +118,6 @@ public class CardView extends SimpleCardView {
|
|||
protected ArtRect artRect = ArtRect.NORMAL;
|
||||
|
||||
protected List<UUID> targets;
|
||||
|
||||
protected UUID pairedCard;
|
||||
protected List<UUID> bandedCards;
|
||||
protected boolean paid;
|
||||
|
|
|
@ -32,6 +32,11 @@ import java.io.Serializable;
|
|||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.google.gson.annotations.Expose;
|
||||
|
||||
import mage.choices.Choice;
|
||||
|
||||
/**
|
||||
|
@ -39,18 +44,29 @@ import mage.choices.Choice;
|
|||
* @author BetaSteward_at_googlemail.com
|
||||
*/
|
||||
public class GameClientMessage implements Serializable {
|
||||
@Expose
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Expose
|
||||
private GameView gameView;
|
||||
@Expose
|
||||
private CardsView cardsView;
|
||||
@Expose
|
||||
private CardsView cardsView2;
|
||||
@Expose
|
||||
private String message;
|
||||
@Expose
|
||||
private boolean flag;
|
||||
@Expose
|
||||
private String[] strings;
|
||||
@Expose
|
||||
private Set<UUID> targets;
|
||||
@Expose
|
||||
private int min;
|
||||
@Expose
|
||||
private int max;
|
||||
@Expose
|
||||
private Map<String, Serializable> options;
|
||||
@Expose
|
||||
private Choice choice;
|
||||
|
||||
public GameClientMessage(GameView gameView) {
|
||||
|
@ -155,4 +171,11 @@ public class GameClientMessage implements Serializable {
|
|||
return choice;
|
||||
}
|
||||
|
||||
public String toJson() {
|
||||
Gson gson = new GsonBuilder()
|
||||
.excludeFieldsWithoutExposeAnnotation()
|
||||
.create();
|
||||
return gson.toJson(this);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -28,11 +28,17 @@
|
|||
package mage.view;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
import mage.MageObject;
|
||||
import mage.abilities.costs.Cost;
|
||||
import mage.cards.Card;
|
||||
|
@ -54,6 +60,8 @@ import mage.game.stack.StackObject;
|
|||
import mage.players.Player;
|
||||
import mage.watchers.common.CastSpellLastTurnWatcher;
|
||||
import org.apache.log4j.Logger;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
|
||||
/**
|
||||
*
|
||||
|
@ -64,7 +72,6 @@ public class GameView implements Serializable {
|
|||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private static final Logger LOGGER = Logger.getLogger(GameView.class);
|
||||
|
||||
private final int priorityTime;
|
||||
private final List<PlayerView> players = new ArrayList<>();
|
||||
private CardsView hand;
|
||||
|
@ -351,4 +358,8 @@ public class GameView implements Serializable {
|
|||
return rollbackTurnsAllowed;
|
||||
}
|
||||
|
||||
public String toJson() {
|
||||
Gson gson = new GsonBuilder().create();
|
||||
return gson.toJson(this);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,6 +28,8 @@
|
|||
|
||||
package mage.view;
|
||||
|
||||
import com.google.gson.annotations.Expose;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.UUID;
|
||||
|
||||
|
@ -36,6 +38,7 @@ import java.util.UUID;
|
|||
* @author BetaSteward_at_googlemail.com
|
||||
*/
|
||||
public class SimpleCardView implements Serializable {
|
||||
@Expose
|
||||
protected UUID id;
|
||||
protected String expansionSetCode;
|
||||
protected String tokenSetCode;
|
||||
|
|
|
@ -65,6 +65,7 @@ public class TableView implements Serializable {
|
|||
private final boolean limited;
|
||||
private final boolean rated;
|
||||
private final boolean passworded;
|
||||
private final boolean spectatorsAllowed;
|
||||
|
||||
public TableView(Table table) {
|
||||
this.tableId = table.getId();
|
||||
|
@ -139,6 +140,7 @@ public class TableView implements Serializable {
|
|||
this.limited = table.getMatch().getOptions().isLimited();
|
||||
this.rated = table.getMatch().getOptions().isRated();
|
||||
this.passworded = !table.getMatch().getOptions().getPassword().isEmpty();
|
||||
this.spectatorsAllowed = table.getMatch().getOptions().isSpectatorsAllowed();
|
||||
} else {
|
||||
// TOURNAMENT
|
||||
if (table.getTournament().getOptions().getNumberRounds() > 0) {
|
||||
|
@ -186,6 +188,7 @@ public class TableView implements Serializable {
|
|||
this.limited = table.getTournament().getOptions().getMatchOptions().isLimited();
|
||||
this.rated = table.getTournament().getOptions().getMatchOptions().isRated();
|
||||
this.passworded = !table.getTournament().getOptions().getPassword().isEmpty();
|
||||
this.spectatorsAllowed = table.getTournament().getOptions().isWatchingAllowed();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -200,6 +203,11 @@ public class TableView implements Serializable {
|
|||
public String getControllerName() {
|
||||
return controllerName;
|
||||
}
|
||||
|
||||
public boolean getSpectatorsAllowed() {
|
||||
return spectatorsAllowed;
|
||||
}
|
||||
|
||||
|
||||
public String getGameType() {
|
||||
return gameType;
|
||||
|
|
|
@ -345,22 +345,53 @@ public class ConsolePanel extends javax.swing.JPanel {
|
|||
|
||||
private void btnEndSessionActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnEndSessionActionPerformed
|
||||
int row = this.tblUsers.convertRowIndexToModel(tblUsers.getSelectedRow());
|
||||
ConsoleFrame.getSession().endUserSession((String) tableUserModel.getValueAt(row, TableUserModel.POS_GAME_INFO));
|
||||
String userSessionId = (String) tableUserModel.getValueAt(row, TableUserModel.POS_GAME_INFO);
|
||||
|
||||
if (JOptionPane.showConfirmDialog(null, "Are you sure you mean to end userSessionId " + userSessionId + '?', "WARNING",
|
||||
JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION) {
|
||||
ConsoleFrame.getSession().endUserSession(userSessionId);
|
||||
}
|
||||
}//GEN-LAST:event_btnEndSessionActionPerformed
|
||||
|
||||
private void btnMuteUserActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnMuteUserActionPerformed
|
||||
int row = this.tblUsers.convertRowIndexToModel(tblUsers.getSelectedRow());
|
||||
ConsoleFrame.getSession().muteUserChat((String) tableUserModel.getValueAt(row, TableUserModel.POS_USER_NAME), ((Number) spinnerMuteDurationMinutes.getValue()).longValue());
|
||||
int row = this.tblUsers.convertRowIndexToModel(tblUsers.getSelectedRow());
|
||||
String userName = (String) tableUserModel.getValueAt(row, TableUserModel.POS_USER_NAME);
|
||||
long durationMinute = ((Number) spinnerMuteDurationMinutes.getValue()).longValue();
|
||||
if (JOptionPane.showConfirmDialog(null, "Are you sure you mean to mute user: " + userName + " for " + durationMinute + " minutes?", "WARNING",
|
||||
JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION) {
|
||||
ConsoleFrame.getSession().muteUserChat(userName, durationMinute);
|
||||
}
|
||||
}//GEN-LAST:event_btnMuteUserActionPerformed
|
||||
|
||||
private void btnDeActivateActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnDeActivateActionPerformed
|
||||
int row = this.tblUsers.convertRowIndexToModel(tblUsers.getSelectedRow());
|
||||
ConsoleFrame.getSession().toggleActivation((String) tableUserModel.getValueAt(row, TableUserModel.POS_USER_NAME));
|
||||
String userName = (String) tableUserModel.getValueAt(row, TableUserModel.POS_USER_NAME);
|
||||
|
||||
if (JOptionPane.showConfirmDialog(null, "Did you want to set user: " + userName + " to active?", "WARNING",
|
||||
JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION) {
|
||||
ConsoleFrame.getSession().setActivation(userName, true);
|
||||
return;
|
||||
}
|
||||
if (JOptionPane.showConfirmDialog(null, "Did you want to set user: " + userName + " to inactive?", "WARNING",
|
||||
JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION) {
|
||||
ConsoleFrame.getSession().setActivation(userName, false);
|
||||
return;
|
||||
}
|
||||
if (JOptionPane.showConfirmDialog(null, "Are you sure you mean to toggle activation for user: " + userName + '?', "WARNING",
|
||||
JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION) {
|
||||
ConsoleFrame.getSession().toggleActivation(userName);
|
||||
return;
|
||||
}
|
||||
}//GEN-LAST:event_btnDeActivateActionPerformed
|
||||
|
||||
private void btnLockUserActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnLockUserActionPerformed
|
||||
int row = this.tblUsers.convertRowIndexToModel(tblUsers.getSelectedRow());
|
||||
ConsoleFrame.getSession().lockUser((String) tableUserModel.getValueAt(row, TableUserModel.POS_USER_NAME), ((Number) spinnerMuteDurationMinutes.getValue()).longValue());
|
||||
String userName = (String) tableUserModel.getValueAt(row, TableUserModel.POS_USER_NAME);
|
||||
long durationMinute = ((Number) spinnerMuteDurationMinutes.getValue()).longValue();
|
||||
if (JOptionPane.showConfirmDialog(null, "Are you sure you mean to lock user: " + userName + " for " + durationMinute + " minutes?", "WARNING",
|
||||
JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION) {
|
||||
ConsoleFrame.getSession().lockUser(userName, durationMinute);
|
||||
}
|
||||
}//GEN-LAST:event_btnLockUserActionPerformed
|
||||
|
||||
private void btnRemoveTableActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnRemoveTableActionPerformed
|
||||
|
|
|
@ -76,6 +76,12 @@
|
|||
<version>${project.version}</version>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-compress</artifactId>
|
||||
<version>1.16.1</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>${project.groupId}</groupId>
|
||||
<artifactId>mage-game-commanderfreeforall</artifactId>
|
||||
|
|
|
@ -990,7 +990,7 @@ public class TableController {
|
|||
|| !match.isDoneSideboarding()
|
||||
|| (!matchPlayer.hasQuit() && match.getGame() != null && matchPlayer.getPlayer().isInGame())) {
|
||||
Optional<User> user = UserManager.instance.getUser(userPlayerEntry.getKey());
|
||||
if (!user.isPresent() || user.get().isActive()) {
|
||||
if (!user.isPresent() || !user.get().isActive()) {
|
||||
logger.warn("- Active user of match is missing: " + matchPlayer.getName());
|
||||
logger.warn("-- matchId:" + match.getId());
|
||||
logger.warn("-- userId:" + userPlayerEntry.getKey());
|
||||
|
|
|
@ -94,9 +94,12 @@ class ActOfAuthorityEffect extends OneShotEffect {
|
|||
public boolean apply(Game game, Ability source) {
|
||||
Permanent targetPermanent = game.getPermanent(this.getTargetPointer().getFirst(game, source));
|
||||
if (targetPermanent != null && new ExileTargetEffect().apply(game, source)) {
|
||||
ContinuousEffect effect = new ActOfAuthorityGainControlEffect(Duration.Custom, targetPermanent.getControllerId());
|
||||
effect.setTargetPointer(new FixedTarget(source.getSourceId()));
|
||||
game.addEffect(effect, source);
|
||||
Permanent sourcePermanent = source.getSourcePermanentIfItStillExists(game);
|
||||
if (sourcePermanent != null) {
|
||||
ContinuousEffect effect = new ActOfAuthorityGainControlEffect(Duration.Custom, targetPermanent.getControllerId());
|
||||
effect.setTargetPointer(new FixedTarget(sourcePermanent, game));
|
||||
game.addEffect(effect, source);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
|
|
@ -109,7 +109,7 @@ class AdarkarValkyrieEffect extends OneShotEffect {
|
|||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
DelayedTriggeredAbility delayedAbility = new AdarkarValkyrieDelayedTriggeredAbility(new FixedTarget(this.getTargetPointer().getFirst(game, source)));
|
||||
DelayedTriggeredAbility delayedAbility = new AdarkarValkyrieDelayedTriggeredAbility(getTargetPointer().getFixedTarget(game, source));
|
||||
game.addDelayedTriggeredAbility(delayedAbility, source);
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -51,17 +51,17 @@ import mage.target.targetpointer.FixedTarget;
|
|||
public class AmbuscadeShaman extends CardImpl {
|
||||
|
||||
public AmbuscadeShaman(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{B}");
|
||||
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}");
|
||||
this.subtype.add(SubType.ORC);
|
||||
this.subtype.add(SubType.SHAMAN);
|
||||
this.power = new MageInt(2);
|
||||
this.toughness = new MageInt(2);
|
||||
|
||||
// Whenever Ambuscade Shaman or another creature enters the battlefield under your control, that creature gets +2/+2 until end of turn.
|
||||
Effect effect = new BoostTargetEffect(2,2, Duration.EndOfTurn);
|
||||
Effect effect = new BoostTargetEffect(2, 2, Duration.EndOfTurn);
|
||||
effect.setText("that creature gets +2/+2 until end of turn");
|
||||
this.addAbility(new AmbuscadeShamanTriggeredAbility(effect));
|
||||
|
||||
|
||||
// Dash {3}{B} <i>(You may cast this spell for its dash cost. If you do, it gains haste, and it's returned from the battlefield to its owner's hand at the beginning of the next end step.)</i>);
|
||||
this.addAbility(new DashAbility(this, "{3}{B}"));
|
||||
|
||||
|
@ -103,9 +103,7 @@ class AmbuscadeShamanTriggeredAbility extends TriggeredAbilityImpl {
|
|||
Permanent permanent = game.getPermanent(targetId);
|
||||
if (permanent.getControllerId().equals(this.controllerId)
|
||||
&& permanent.isCreature()) {
|
||||
for (Effect effect : this.getEffects()) {
|
||||
effect.setTargetPointer(new FixedTarget(event.getTargetId()));
|
||||
}
|
||||
this.getEffects().setTargetPointer(new FixedTarget(permanent, game));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
@ -115,4 +113,4 @@ class AmbuscadeShamanTriggeredAbility extends TriggeredAbilityImpl {
|
|||
public String getRule() {
|
||||
return "Whenever {this} or another creature enters the battlefield under your control, that creature gets +2/+2 until end of turn.";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -45,16 +45,16 @@ import mage.target.targetpointer.FixedTarget;
|
|||
/**
|
||||
*
|
||||
* @author KholdFuzion
|
||||
|
||||
*
|
||||
*/
|
||||
public class AnkhOfMishra extends CardImpl {
|
||||
|
||||
|
||||
public AnkhOfMishra(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{2}");
|
||||
super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{2}");
|
||||
|
||||
// Whenever a land enters the battlefield, Ankh of Mishra deals 2 damage to that land's controller.
|
||||
this.addAbility(new AnkhOfMishraAbility());
|
||||
|
||||
|
||||
}
|
||||
|
||||
public AnkhOfMishra(final AnkhOfMishra card) {
|
||||
|
@ -70,16 +70,16 @@ public class AnkhOfMishra extends CardImpl {
|
|||
class AnkhOfMishraAbility extends TriggeredAbilityImpl {
|
||||
|
||||
public AnkhOfMishraAbility() {
|
||||
super(Zone.BATTLEFIELD, new DamageTargetEffect(2));
|
||||
super(Zone.BATTLEFIELD, new DamageTargetEffect(2));
|
||||
}
|
||||
|
||||
AnkhOfMishraAbility(final AnkhOfMishraAbility ability) {
|
||||
super(ability);
|
||||
super(ability);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AnkhOfMishraAbility copy() {
|
||||
return new AnkhOfMishraAbility(this);
|
||||
return new AnkhOfMishraAbility(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -104,6 +104,6 @@ class AnkhOfMishraAbility extends TriggeredAbilityImpl {
|
|||
|
||||
@Override
|
||||
public String getRule() {
|
||||
return "Whenever a land enters the battlefield, Ankh of Mishra deals 2 damage to that land's controller.";
|
||||
return "Whenever a land enters the battlefield, {this} deals 2 damage to that land's controller.";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,6 +29,7 @@ package mage.cards.a;
|
|||
|
||||
import java.util.UUID;
|
||||
import mage.MageInt;
|
||||
import mage.MageObject;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.effects.ContinuousEffect;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
|
@ -53,7 +54,7 @@ import mage.target.targetpointer.FixedTarget;
|
|||
public class ArbiterOfTheIdeal extends CardImpl {
|
||||
|
||||
public ArbiterOfTheIdeal(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{4}{U}{U}");
|
||||
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{U}{U}");
|
||||
this.subtype.add(SubType.SPHINX);
|
||||
|
||||
this.power = new MageInt(4);
|
||||
|
@ -79,6 +80,7 @@ public class ArbiterOfTheIdeal extends CardImpl {
|
|||
class ArbiterOfTheIdealEffect extends OneShotEffect {
|
||||
|
||||
private static final FilterCard filter = new FilterCard();
|
||||
|
||||
static {
|
||||
filter.add(Predicates.or(
|
||||
new CardTypePredicate(CardType.ARTIFACT),
|
||||
|
@ -102,32 +104,25 @@ class ArbiterOfTheIdealEffect extends OneShotEffect {
|
|||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Player player = game.getPlayer(source.getControllerId());
|
||||
if (player == null) {
|
||||
Player controller = game.getPlayer(source.getControllerId());
|
||||
MageObject sourceObject = source.getSourceObject(game);
|
||||
if (controller == null || sourceObject == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (player.getLibrary().hasCards()) {
|
||||
Card card = player.getLibrary().getFromTop(game);
|
||||
Cards cards = new CardsImpl();
|
||||
cards.add(card);
|
||||
player.revealCards("Arbiter of the Ideal", cards, game);
|
||||
|
||||
if (card != null) {
|
||||
if (filter.match(card, game) && player.chooseUse(outcome, new StringBuilder("Put ").append(card.getName()).append("onto battlefield?").toString(), source, game)) {
|
||||
card.putOntoBattlefield(game, Zone.LIBRARY, source.getSourceId(), source.getControllerId());
|
||||
Permanent permanent = game.getPermanent(card.getId());
|
||||
if (permanent != null) {
|
||||
permanent.addCounters(new Counter("Manifestation"), source, game);
|
||||
ContinuousEffect effect = new AddCardTypeTargetEffect(Duration.Custom, CardType.ENCHANTMENT);
|
||||
effect.setTargetPointer(new FixedTarget(permanent.getId()));
|
||||
game.addEffect(effect, source);
|
||||
}
|
||||
Card card = controller.getLibrary().getFromTop(game);
|
||||
if (card != null) {
|
||||
controller.revealCards(sourceObject.getIdName(), new CardsImpl(card), game);
|
||||
if (filter.match(card, game) && controller.chooseUse(outcome, "Put " + card.getName() + "onto battlefield?", source, game)) {
|
||||
controller.moveCards(card, Zone.BATTLEFIELD, source, game);
|
||||
Permanent permanent = game.getPermanent(card.getId());
|
||||
if (permanent != null) {
|
||||
permanent.addCounters(new Counter("Manifestation"), source, game);
|
||||
ContinuousEffect effect = new AddCardTypeTargetEffect(Duration.Custom, CardType.ENCHANTMENT);
|
||||
effect.setTargetPointer(new FixedTarget(permanent, game));
|
||||
game.addEffect(effect, source);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,23 +29,18 @@ package mage.cards.a;
|
|||
|
||||
import java.util.UUID;
|
||||
import mage.MageInt;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.TriggeredAbilityImpl;
|
||||
import mage.abilities.effects.Effect;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.abilities.effects.common.GainLifeEffect;
|
||||
import mage.abilities.keyword.FlyingAbility;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.SubType;
|
||||
import mage.constants.Zone;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.game.events.GameEvent.EventType;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.players.Player;
|
||||
import mage.target.targetpointer.FixedTarget;
|
||||
|
||||
/**
|
||||
* @author Loki
|
||||
|
@ -53,7 +48,7 @@ import mage.target.targetpointer.FixedTarget;
|
|||
public class ArchonOfRedemption extends CardImpl {
|
||||
|
||||
public ArchonOfRedemption(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{W}{W}");
|
||||
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{W}{W}");
|
||||
this.subtype.add(SubType.ARCHON);
|
||||
|
||||
this.power = new MageInt(3);
|
||||
|
@ -75,8 +70,9 @@ public class ArchonOfRedemption extends CardImpl {
|
|||
}
|
||||
|
||||
class ArchonOfRedemptionTriggeredAbility extends TriggeredAbilityImpl {
|
||||
|
||||
ArchonOfRedemptionTriggeredAbility() {
|
||||
super(Zone.BATTLEFIELD, new ArchonOfRedemptionEffect(), true);
|
||||
super(Zone.BATTLEFIELD, null, true);
|
||||
}
|
||||
|
||||
ArchonOfRedemptionTriggeredAbility(final ArchonOfRedemptionTriggeredAbility ability) {
|
||||
|
@ -95,15 +91,13 @@ class ArchonOfRedemptionTriggeredAbility extends TriggeredAbilityImpl {
|
|||
|
||||
@Override
|
||||
public boolean checkTrigger(GameEvent event, Game game) {
|
||||
UUID targetId = event.getTargetId();
|
||||
Permanent permanent = game.getPermanent(targetId);
|
||||
if (permanent.getControllerId().equals(this.controllerId)
|
||||
Permanent permanent = game.getPermanent(event.getTargetId());
|
||||
if (permanent.getControllerId().equals(getControllerId())
|
||||
&& permanent.isCreature()
|
||||
&& (targetId.equals(this.getSourceId())
|
||||
|| (permanent.getAbilities().contains(FlyingAbility.getInstance()) && !targetId.equals(this.getSourceId())))) {
|
||||
for (Effect effect : this.getEffects()) {
|
||||
effect.setTargetPointer(new FixedTarget(event.getTargetId()));
|
||||
}
|
||||
&& (permanent.getId().equals(getSourceId())
|
||||
|| (permanent.getAbilities().contains(FlyingAbility.getInstance())))) {
|
||||
this.getEffects().clear();
|
||||
this.addEffect(new GainLifeEffect(permanent.getPower().getValue()));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
@ -111,35 +105,6 @@ class ArchonOfRedemptionTriggeredAbility extends TriggeredAbilityImpl {
|
|||
|
||||
@Override
|
||||
public String getRule() {
|
||||
return "Whenever {this} or another creature with flying enters the battlefield under your control, you may gain life equal to that creature's power";
|
||||
return "Whenever {this} or another creature with flying enters the battlefield under your control, you may gain life equal to that creature's power.";
|
||||
}
|
||||
}
|
||||
|
||||
class ArchonOfRedemptionEffect extends OneShotEffect {
|
||||
ArchonOfRedemptionEffect() {
|
||||
super(Outcome.GainLife);
|
||||
}
|
||||
|
||||
ArchonOfRedemptionEffect(final ArchonOfRedemptionEffect effect) {
|
||||
super(effect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Permanent p = game.getPermanent(targetPointer.getFirst(game, source));
|
||||
Player player = game.getPlayer(source.getControllerId());
|
||||
if (p == null) {
|
||||
p = (Permanent) game.getLastKnownInformation(targetPointer.getFirst(game, source), Zone.BATTLEFIELD);
|
||||
}
|
||||
if (p != null && player != null) {
|
||||
player.gainLife(p.getPower().getValue(), game);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ArchonOfRedemptionEffect copy() {
|
||||
return new ArchonOfRedemptionEffect(this);
|
||||
}
|
||||
}
|
|
@ -29,7 +29,7 @@ package mage.cards.a;
|
|||
|
||||
import java.util.UUID;
|
||||
import mage.MageInt;
|
||||
import mage.abilities.common.OnEventTriggeredAbility;
|
||||
import mage.abilities.common.BeginningOfEndStepTriggeredAbility;
|
||||
import mage.abilities.effects.common.ReturnToHandSourceEffect;
|
||||
import mage.abilities.keyword.FlyingAbility;
|
||||
import mage.abilities.keyword.HasteAbility;
|
||||
|
@ -37,7 +37,7 @@ import mage.cards.CardImpl;
|
|||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.SubType;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.constants.TargetController;
|
||||
|
||||
/**
|
||||
*
|
||||
|
@ -46,7 +46,7 @@ import mage.game.events.GameEvent;
|
|||
public class ArchwingDragon extends CardImpl {
|
||||
|
||||
public ArchwingDragon(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{R}{R}");
|
||||
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{R}{R}");
|
||||
this.subtype.add(SubType.DRAGON);
|
||||
|
||||
this.power = new MageInt(4);
|
||||
|
@ -54,8 +54,10 @@ public class ArchwingDragon extends CardImpl {
|
|||
|
||||
this.addAbility(FlyingAbility.getInstance());
|
||||
this.addAbility(HasteAbility.getInstance());
|
||||
|
||||
// At the beginning of the end step, return Archwing Dragon to its owner's hand.
|
||||
this.addAbility(new OnEventTriggeredAbility(GameEvent.EventType.END_TURN_STEP_PRE, "beginning of the end step", new ReturnToHandSourceEffect(true), false));
|
||||
this.addAbility(new BeginningOfEndStepTriggeredAbility(new ReturnToHandSourceEffect(true), TargetController.ANY, false));
|
||||
|
||||
}
|
||||
|
||||
public ArchwingDragon(final ArchwingDragon card) {
|
||||
|
|
|
@ -53,7 +53,7 @@ import mage.target.targetpointer.FixedTarget;
|
|||
public class ArrogantBloodlord extends CardImpl {
|
||||
|
||||
public ArrogantBloodlord(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{B}{B}");
|
||||
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{B}{B}");
|
||||
this.subtype.add(SubType.VAMPIRE);
|
||||
this.subtype.add(SubType.KNIGHT);
|
||||
|
||||
|
@ -104,11 +104,8 @@ class ArrogantBloodlordTriggeredAbility extends TriggeredAbilityImpl {
|
|||
&& Objects.equals(blocked, arrogantBloodlord)) {
|
||||
return true;
|
||||
}
|
||||
if (blocker != null && Objects.equals(blocker, arrogantBloodlord)
|
||||
&& game.getPermanent(event.getTargetId()).getPower().getValue() < 2) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
return blocker != null && Objects.equals(blocker, arrogantBloodlord)
|
||||
&& game.getPermanent(event.getTargetId()).getPower().getValue() < 2;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -133,7 +130,7 @@ class ArrogantBloodlordEffect extends OneShotEffect {
|
|||
Permanent permanent = game.getPermanent(source.getSourceId());
|
||||
if (permanent != null) {
|
||||
AtTheEndOfCombatDelayedTriggeredAbility delayedAbility = new AtTheEndOfCombatDelayedTriggeredAbility(new DestroyTargetEffect());
|
||||
delayedAbility.getEffects().get(0).setTargetPointer(new FixedTarget(source.getSourceId()));
|
||||
delayedAbility.getEffects().get(0).setTargetPointer(new FixedTarget(permanent, game));
|
||||
game.addDelayedTriggeredAbility(delayedAbility, source);
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -37,16 +37,13 @@ import mage.abilities.effects.common.CounterUnlessPaysEffect;
|
|||
import mage.abilities.keyword.BandingAbility;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.AbilityType;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.SubType;
|
||||
import mage.constants.SuperType;
|
||||
import mage.constants.Zone;
|
||||
import mage.filter.FilterStackObject;
|
||||
import mage.filter.predicate.Predicate;
|
||||
import mage.game.Game;
|
||||
import mage.game.stack.StackAbility;
|
||||
import mage.target.common.TargetActivatedOrTriggeredAbility;
|
||||
import mage.filter.FilterAbility;
|
||||
import mage.filter.predicate.ability.ArtifactSourcePredicate;
|
||||
import mage.target.common.TargetActivatedAbility;
|
||||
|
||||
/**
|
||||
*
|
||||
|
@ -54,26 +51,26 @@ import mage.target.common.TargetActivatedOrTriggeredAbility;
|
|||
*/
|
||||
public class AyeshaTanaka extends CardImpl {
|
||||
|
||||
private final static FilterStackObject filter = new FilterStackObject("activated ability from an artifact source");
|
||||
private final static FilterAbility filter = new FilterAbility("activated ability from an artifact source");
|
||||
|
||||
static {
|
||||
filter.add(new ArtifactSourcePredicate());
|
||||
}
|
||||
|
||||
public AyeshaTanaka(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{W}{W}{U}{U}");
|
||||
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{W}{W}{U}{U}");
|
||||
addSuperType(SuperType.LEGENDARY);
|
||||
this.subtype.add(SubType.HUMAN);
|
||||
this.subtype.add(SubType.ARTIFICER);
|
||||
this.power = new MageInt(2);
|
||||
this.toughness = new MageInt(2);
|
||||
|
||||
|
||||
// Banding
|
||||
this.addAbility(BandingAbility.getInstance());
|
||||
|
||||
// {T}: Counter target activated ability from an artifact source unless that ability's controller pays {W}.
|
||||
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new CounterUnlessPaysEffect(new ManaCostsImpl("{W}")), new TapSourceCost());
|
||||
ability.addTarget(new TargetActivatedOrTriggeredAbility(filter));
|
||||
ability.addTarget(new TargetActivatedAbility(filter));
|
||||
this.addAbility(ability);
|
||||
}
|
||||
|
||||
|
@ -86,22 +83,3 @@ public class AyeshaTanaka extends CardImpl {
|
|||
return new AyeshaTanaka(this);
|
||||
}
|
||||
}
|
||||
|
||||
class ArtifactSourcePredicate implements Predicate<Ability> {
|
||||
|
||||
public ArtifactSourcePredicate() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Ability input, Game game) {
|
||||
if (input instanceof StackAbility) {
|
||||
return input.getSourceObject(game).isArtifact() && input.getAbilityType() == AbilityType.ACTIVATED;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Source(Artifact)";
|
||||
}
|
||||
}
|
||||
|
|
127
Mage.Sets/src/mage/cards/b/BlazeOfGlory.java
Normal file
127
Mage.Sets/src/mage/cards/b/BlazeOfGlory.java
Normal file
|
@ -0,0 +1,127 @@
|
|||
/*
|
||||
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are
|
||||
* permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
* conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
* of conditions and the following disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* The views and conclusions contained in the software and documentation are those of the
|
||||
* authors and should not be interpreted as representing official policies, either expressed
|
||||
* or implied, of BetaSteward_at_googlemail.com.
|
||||
*/
|
||||
package mage.cards.b;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.common.CastOnlyDuringPhaseStepSourceAbility;
|
||||
import mage.abilities.condition.common.BeforeBlockersAreDeclaredCondition;
|
||||
import mage.abilities.effects.RequirementEffect;
|
||||
import mage.abilities.effects.common.combat.CanBlockAdditionalCreatureTargetEffect;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.Duration;
|
||||
import mage.constants.TurnPhase;
|
||||
import mage.filter.common.FilterCreaturePermanent;
|
||||
import mage.filter.predicate.ObjectPlayer;
|
||||
import mage.filter.predicate.ObjectPlayerPredicate;
|
||||
import mage.game.Controllable;
|
||||
import mage.game.Game;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.target.common.TargetCreaturePermanent;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author L_J
|
||||
*/
|
||||
public class BlazeOfGlory extends CardImpl {
|
||||
|
||||
private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creature defending player controls");
|
||||
|
||||
static {
|
||||
filter.add(new BlazeOfGloryDefendingPlayerControlsPredicate());
|
||||
}
|
||||
|
||||
public BlazeOfGlory(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{W}");
|
||||
|
||||
// Cast Blaze of Glory only during combat before blockers are declared.
|
||||
this.addAbility(new CastOnlyDuringPhaseStepSourceAbility(TurnPhase.COMBAT, BeforeBlockersAreDeclaredCondition.instance));
|
||||
|
||||
// Target creature defending player controls can block any number of creatures this turn. It blocks each attacking creature this turn if able.
|
||||
this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter));
|
||||
this.getSpellAbility().addEffect(new CanBlockAdditionalCreatureTargetEffect(Duration.EndOfTurn, 0));
|
||||
this.getSpellAbility().addEffect(new BlazeOfGloryRequirementEffect());
|
||||
}
|
||||
|
||||
public BlazeOfGlory(final BlazeOfGlory card) {
|
||||
super(card);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlazeOfGlory copy() {
|
||||
return new BlazeOfGlory(this);
|
||||
}
|
||||
}
|
||||
|
||||
class BlazeOfGloryDefendingPlayerControlsPredicate implements ObjectPlayerPredicate<ObjectPlayer<Controllable>> {
|
||||
|
||||
@Override
|
||||
public boolean apply(ObjectPlayer<Controllable> input, Game game) {
|
||||
return game.getCombat().getPlayerDefenders(game).contains(input.getObject().getControllerId());
|
||||
}
|
||||
}
|
||||
|
||||
class BlazeOfGloryRequirementEffect extends RequirementEffect {
|
||||
|
||||
public BlazeOfGloryRequirementEffect() {
|
||||
super(Duration.EndOfTurn);
|
||||
this.staticText = "It blocks each attacking creature this turn if able";
|
||||
}
|
||||
|
||||
public BlazeOfGloryRequirementEffect(final BlazeOfGloryRequirementEffect effect) {
|
||||
super(effect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean applies(Permanent permanent, Ability source, Game game) {
|
||||
return permanent.getId().equals(targetPointer.getFirst(game, source));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean mustAttack(Game game) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean mustBlock(Game game) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean mustBlockAllAttackers(Game game) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlazeOfGloryRequirementEffect copy() {
|
||||
return new BlazeOfGloryRequirementEffect(this);
|
||||
}
|
||||
|
||||
}
|
|
@ -53,7 +53,7 @@ import java.util.UUID;
|
|||
*/
|
||||
public class BrassTalonChimera extends CardImpl {
|
||||
|
||||
private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("Chimera creature you control");
|
||||
private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("Chimera creature");
|
||||
|
||||
static {
|
||||
filter.add(new SubtypePredicate(SubType.CHIMERA));
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
*/
|
||||
package mage.cards.b;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.MageInt;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.common.SimpleActivatedAbility;
|
||||
|
@ -35,17 +36,12 @@ import mage.abilities.costs.mana.ManaCostsImpl;
|
|||
import mage.abilities.effects.common.CounterTargetEffect;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.AbilityType;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.SubType;
|
||||
import mage.constants.Zone;
|
||||
import mage.filter.FilterStackObject;
|
||||
import mage.filter.predicate.Predicate;
|
||||
import mage.game.Game;
|
||||
import mage.game.stack.StackAbility;
|
||||
import mage.target.common.TargetActivatedOrTriggeredAbility;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.filter.FilterAbility;
|
||||
import mage.filter.predicate.ability.ArtifactSourcePredicate;
|
||||
import mage.target.common.TargetActivatedAbility;
|
||||
|
||||
/**
|
||||
*
|
||||
|
@ -53,7 +49,7 @@ import java.util.UUID;
|
|||
*/
|
||||
public class BrownOuphe extends CardImpl {
|
||||
|
||||
private final static FilterStackObject filter = new FilterStackObject("activated ability from an artifact source");
|
||||
private final static FilterAbility filter = new FilterAbility("activated ability from an artifact source");
|
||||
|
||||
static {
|
||||
filter.add(new ArtifactSourcePredicate());
|
||||
|
@ -69,7 +65,7 @@ public class BrownOuphe extends CardImpl {
|
|||
// {1}{G}, {tap}: Counter target activated ability from an artifact source.
|
||||
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new CounterTargetEffect(), new ManaCostsImpl<>("{1}{G}"));
|
||||
ability.addCost(new TapSourceCost());
|
||||
ability.addTarget(new TargetActivatedOrTriggeredAbility(filter));
|
||||
ability.addTarget(new TargetActivatedAbility(filter));
|
||||
this.addAbility(ability);
|
||||
}
|
||||
|
||||
|
@ -82,22 +78,3 @@ public class BrownOuphe extends CardImpl {
|
|||
return new BrownOuphe(this);
|
||||
}
|
||||
}
|
||||
|
||||
class ArtifactSourcePredicate implements Predicate<Ability> {
|
||||
|
||||
public ArtifactSourcePredicate() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Ability input, Game game) {
|
||||
if (input instanceof StackAbility) {
|
||||
return input.getSourceObject(game).isArtifact() && input.getAbilityType() == AbilityType.ACTIVATED;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Source(Artifact)";
|
||||
}
|
||||
}
|
||||
|
|
121
Mage.Sets/src/mage/cards/b/BuildersBane.java
Normal file
121
Mage.Sets/src/mage/cards/b/BuildersBane.java
Normal file
|
@ -0,0 +1,121 @@
|
|||
/*
|
||||
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are
|
||||
* permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
* conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
* of conditions and the following disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* The views and conclusions contained in the software and documentation are those of the
|
||||
* authors and should not be interpreted as representing official policies, either expressed
|
||||
* or implied, of BetaSteward_at_googlemail.com.
|
||||
*/
|
||||
package mage.cards.b;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.SpellAbility;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.Zone;
|
||||
import mage.game.Game;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.players.Player;
|
||||
import mage.target.common.TargetArtifactPermanent;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author sinsedrix
|
||||
*/
|
||||
public class BuildersBane extends CardImpl {
|
||||
|
||||
public BuildersBane(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{X}{X}{R}");
|
||||
|
||||
// Destroy X target artifacts. Builder's Bane deals damage to each player equal to the number of artifacts he or she controlled put into a graveyard this way.
|
||||
this.getSpellAbility().addTarget(new TargetArtifactPermanent());
|
||||
this.getSpellAbility().addEffect(new BuildersBaneEffect());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void adjustTargets(Ability ability, Game game) {
|
||||
if (ability instanceof SpellAbility) {
|
||||
ability.getTargets().clear();
|
||||
int xValue = ability.getManaCostsToPay().getX();
|
||||
ability.addTarget(new TargetArtifactPermanent(xValue, xValue));
|
||||
}
|
||||
}
|
||||
|
||||
public BuildersBane(final BuildersBane card) {
|
||||
super(card);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BuildersBane copy() {
|
||||
return new BuildersBane(this);
|
||||
}
|
||||
}
|
||||
|
||||
class BuildersBaneEffect extends OneShotEffect {
|
||||
|
||||
public BuildersBaneEffect() {
|
||||
super(Outcome.DestroyPermanent);
|
||||
this.staticText = "Destroy X target artifacts. {this} deals damage to each player equal to the number of artifacts he or she controlled put into a graveyard this way";
|
||||
}
|
||||
|
||||
public BuildersBaneEffect(final BuildersBaneEffect effect) {
|
||||
super(effect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BuildersBaneEffect copy() {
|
||||
return new BuildersBaneEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Map<UUID, Integer> destroyedArtifactPerPlayer = new HashMap<>();
|
||||
|
||||
// Destroy X target artifacts.
|
||||
for (UUID targetID : this.targetPointer.getTargets(game, source)) {
|
||||
Permanent permanent = game.getPermanent(targetID);
|
||||
if (permanent != null) {
|
||||
if (permanent.destroy(source.getSourceId(), game, false)) {
|
||||
if (game.getState().getZone(permanent.getId()) == Zone.GRAVEYARD) {
|
||||
destroyedArtifactPerPlayer.merge(permanent.getControllerId(), 1, Integer::sum);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Builder's Bane deals damage to each player equal to the number of artifacts he or she controlled put into a graveyard this way.
|
||||
for (Map.Entry<UUID, Integer> entry : destroyedArtifactPerPlayer.entrySet()) {
|
||||
Player player = game.getPlayer(entry.getKey());
|
||||
if(player != null) {
|
||||
player.damage(entry.getValue(), source.getSourceId(), game, false, true);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -28,21 +28,16 @@
|
|||
package mage.cards.c;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.abilities.effects.common.UntapAllEffect;
|
||||
import mage.abilities.effects.common.continuous.BoostControlledEffect;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.Duration;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.SubType;
|
||||
import mage.filter.StaticFilters;
|
||||
import mage.filter.common.FilterCreaturePermanent;
|
||||
import mage.filter.predicate.mageobject.SubtypePredicate;
|
||||
import mage.game.Game;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.players.Player;
|
||||
|
||||
/**
|
||||
* @author Loki
|
||||
|
@ -57,8 +52,9 @@ public class CallToGlory extends CardImpl {
|
|||
|
||||
public CallToGlory(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{W}");
|
||||
|
||||
this.getSpellAbility().addEffect(new CalltoGloryFirstEffect());
|
||||
|
||||
//Untap all creatures you control. Samurai creatures you control get +1/+1 until end of turn.
|
||||
this.getSpellAbility().addEffect(new UntapAllEffect(StaticFilters.FILTER_CONTROLLED_CREATURE));
|
||||
this.getSpellAbility().addEffect(new BoostControlledEffect(1, 1, Duration.EndOfTurn, filter, false));
|
||||
}
|
||||
|
||||
|
@ -70,35 +66,4 @@ public class CallToGlory extends CardImpl {
|
|||
public CallToGlory copy() {
|
||||
return new CallToGlory(this);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class CalltoGloryFirstEffect extends OneShotEffect {
|
||||
|
||||
public CalltoGloryFirstEffect() {
|
||||
super(Outcome.Untap);
|
||||
staticText = "Untap all creatures you control";
|
||||
}
|
||||
|
||||
public CalltoGloryFirstEffect(final CalltoGloryFirstEffect effect) {
|
||||
super(effect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Player player = game.getPlayer(source.getControllerId());
|
||||
if (player != null) {
|
||||
for (Permanent creature : game.getBattlefield().getAllActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, player.getId(), game)) {
|
||||
creature.untap(game);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CalltoGloryFirstEffect copy() {
|
||||
return new CalltoGloryFirstEffect(this);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
package mage.cards.c;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.MageObject;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.common.SimpleStaticAbility;
|
||||
import mage.abilities.effects.ContinuousRuleModifyingEffectImpl;
|
||||
|
@ -48,7 +49,7 @@ import mage.game.events.GameEvent.EventType;
|
|||
public class CityOfSolitude extends CardImpl {
|
||||
|
||||
public CityOfSolitude(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{2}{G}");
|
||||
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{G}");
|
||||
|
||||
// Players can cast spells and activate abilities only during their own turns.
|
||||
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new CityOfSolitudeEffect()));
|
||||
|
@ -74,12 +75,22 @@ class CityOfSolitudeEffect extends ContinuousRuleModifyingEffectImpl {
|
|||
CityOfSolitudeEffect(final CityOfSolitudeEffect effect) {
|
||||
super(effect);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean checksEventType(GameEvent event, Game game) {
|
||||
return event.getType() == EventType.CAST_SPELL || event.getType() == EventType.ACTIVATE_ABILITY;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String getInfoMessage(Ability source, GameEvent event, Game game) {
|
||||
MageObject sourceObject = game.getObject(source.getSourceId());
|
||||
MageObject eventObject = game.getObject(event.getSourceId());
|
||||
if (sourceObject != null && eventObject != null) {
|
||||
return "You can cast or activate anability of " + eventObject.getIdName() + " only during your own turns (" + sourceObject.getIdName() + "). ";
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean applies(GameEvent event, Ability source, Game game) {
|
||||
return !game.getActivePlayerId().equals(event.getPlayerId());
|
||||
|
@ -89,4 +100,4 @@ class CityOfSolitudeEffect extends ContinuousRuleModifyingEffectImpl {
|
|||
public CityOfSolitudeEffect copy() {
|
||||
return new CityOfSolitudeEffect(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -41,9 +41,9 @@ import mage.abilities.effects.common.ReturnFromGraveyardToBattlefieldTargetEffec
|
|||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.SubType;
|
||||
import mage.constants.Duration;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.SubType;
|
||||
import mage.constants.Zone;
|
||||
import mage.filter.common.FilterCreatureCard;
|
||||
import mage.game.Game;
|
||||
|
@ -60,7 +60,7 @@ import mage.target.targetpointer.FixedTarget;
|
|||
public class CoffinQueen extends CardImpl {
|
||||
|
||||
public CoffinQueen(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{B}");
|
||||
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}");
|
||||
this.subtype.add(SubType.ZOMBIE);
|
||||
this.subtype.add(SubType.WIZARD);
|
||||
this.power = new MageInt(1);
|
||||
|
@ -68,14 +68,14 @@ public class CoffinQueen extends CardImpl {
|
|||
|
||||
// You may choose not to untap Coffin Queen during your untap step.
|
||||
this.addAbility(new SkipUntapOptionalAbility());
|
||||
|
||||
|
||||
// {2}{B}, {tap}: Put target creature card from a graveyard onto the battlefield under your control. When Coffin Queen becomes untapped or you lose control of Coffin Queen, exile that creature.
|
||||
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new ReturnFromGraveyardToBattlefieldTargetEffect(), new ManaCostsImpl("{2}{B}"));
|
||||
ability.addCost(new TapSourceCost());
|
||||
ability.addTarget(new TargetCardInGraveyard(new FilterCreatureCard("creature card from a graveyard")));
|
||||
ability.addEffect(new CoffinQueenCreateDelayedTriggerEffect());
|
||||
ability.addEffect(new CoffinQueenCreateDelayedTriggerEffect());
|
||||
this.addAbility(ability);
|
||||
|
||||
|
||||
}
|
||||
|
||||
public CoffinQueen(final CoffinQueen card) {
|
||||
|
@ -87,33 +87,30 @@ public class CoffinQueen extends CardImpl {
|
|||
return new CoffinQueen(this);
|
||||
}
|
||||
}
|
||||
|
||||
class CoffinQueenCreateDelayedTriggerEffect extends OneShotEffect {
|
||||
|
||||
|
||||
public CoffinQueenCreateDelayedTriggerEffect() {
|
||||
super(Outcome.Detriment);
|
||||
this.staticText = "When Coffin Queen becomes untapped or you lose control of Coffin Queen, exile that creature";
|
||||
this.staticText = "When {this} becomes untapped or you lose control of {this}, exile that creature.";
|
||||
}
|
||||
|
||||
|
||||
public CoffinQueenCreateDelayedTriggerEffect(final CoffinQueenCreateDelayedTriggerEffect effect) {
|
||||
super(effect);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public CoffinQueenCreateDelayedTriggerEffect copy() {
|
||||
return new CoffinQueenCreateDelayedTriggerEffect(this);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Permanent controlledCreature = game.getPermanent(source.getFirstTarget());
|
||||
if (controlledCreature != null) {
|
||||
DelayedTriggeredAbility delayedAbility = new CoffinQueenDelayedTriggeredAbility();
|
||||
delayedAbility.getEffects().get(0).setTargetPointer(new FixedTarget(controlledCreature.getId()));
|
||||
delayedAbility.setSourceId(source.getSourceId());
|
||||
delayedAbility.setControllerId(source.getControllerId());
|
||||
delayedAbility.setSourceObject(source.getSourceObject(game), game);
|
||||
delayedAbility.init(game);
|
||||
game.addDelayedTriggeredAbility(delayedAbility);
|
||||
delayedAbility.getEffects().get(0).setTargetPointer(new FixedTarget(controlledCreature, game));
|
||||
game.addDelayedTriggeredAbility(delayedAbility, source);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
@ -123,7 +120,7 @@ class CoffinQueenCreateDelayedTriggerEffect extends OneShotEffect {
|
|||
class CoffinQueenDelayedTriggeredAbility extends DelayedTriggeredAbility {
|
||||
|
||||
CoffinQueenDelayedTriggeredAbility() {
|
||||
super(new ExileTargetEffect(), Duration.EndOfGame, true);
|
||||
super(new ExileTargetEffect(), Duration.EndOfGame, true);
|
||||
}
|
||||
|
||||
CoffinQueenDelayedTriggeredAbility(CoffinQueenDelayedTriggeredAbility ability) {
|
||||
|
@ -136,7 +133,6 @@ class CoffinQueenDelayedTriggeredAbility extends DelayedTriggeredAbility {
|
|||
|| event.getType() == EventType.UNTAPPED;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean checkTrigger(GameEvent event, Game game) {
|
||||
if (EventType.LOST_CONTROL == event.getType()
|
||||
|
@ -146,14 +142,14 @@ class CoffinQueenDelayedTriggeredAbility extends DelayedTriggeredAbility {
|
|||
return EventType.UNTAPPED == event.getType()
|
||||
&& event.getTargetId() != null && event.getTargetId().equals(getSourceId());
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public CoffinQueenDelayedTriggeredAbility copy() {
|
||||
return new CoffinQueenDelayedTriggeredAbility(this);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String getRule() {
|
||||
return "When {this} becomes untapped or you lose control of {this}, exile that creature";
|
||||
return "When {this} becomes untapped or you lose control of {this}, exile that creature.";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -81,7 +81,7 @@ public class ConduitOfRuin extends CardImpl {
|
|||
|
||||
// The first creature spell you cast each turn costs {2} less to cast.
|
||||
Effect effect = new SpellsCostReductionControllerEffect(filterCost, 2);
|
||||
effect.setText("The first creature spell you cast each turn costs {2} less to cast");
|
||||
effect.setText("The first creature spell you cast each turn costs {2} less to cast.");
|
||||
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, effect), new ConduitOfRuinWatcher());
|
||||
}
|
||||
|
||||
|
|
142
Mage.Sets/src/mage/cards/c/CruelFate.java
Normal file
142
Mage.Sets/src/mage/cards/c/CruelFate.java
Normal file
|
@ -0,0 +1,142 @@
|
|||
/*
|
||||
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are
|
||||
* permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
* conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
* of conditions and the following disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* The views and conclusions contained in the software and documentation are those of the
|
||||
* authors and should not be interpreted as representing official policies, either expressed
|
||||
* or implied, of BetaSteward_at_googlemail.com.
|
||||
*/
|
||||
package mage.cards.c;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.cards.Card;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.cards.Cards;
|
||||
import mage.cards.CardsImpl;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.Zone;
|
||||
import mage.filter.FilterCard;
|
||||
import mage.game.Game;
|
||||
import mage.players.Player;
|
||||
import mage.target.TargetCard;
|
||||
import mage.target.common.TargetOpponent;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author TheElk801 & L_J
|
||||
*/
|
||||
public class CruelFate extends CardImpl {
|
||||
|
||||
public CruelFate(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{4}{U}");
|
||||
|
||||
// Look at the top five cards of target opponent's library. Put one of those cards into that player's graveyard and the rest on top of his or her library in any order.
|
||||
this.getSpellAbility().addEffect(new CruelFateEffect());
|
||||
this.getSpellAbility().addTarget(new TargetOpponent());
|
||||
|
||||
}
|
||||
|
||||
public CruelFate(final CruelFate card) {
|
||||
super(card);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CruelFate copy() {
|
||||
return new CruelFate(this);
|
||||
}
|
||||
}
|
||||
|
||||
class CruelFateEffect extends OneShotEffect {
|
||||
|
||||
public CruelFateEffect() {
|
||||
super(Outcome.DrawCard);
|
||||
this.staticText = "Look at the top five cards of target opponent's library. Put one of those cards into that player's graveyard and the rest on top of his or her library in any order";
|
||||
}
|
||||
|
||||
public CruelFateEffect(final CruelFateEffect effect) {
|
||||
super(effect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CruelFateEffect copy() {
|
||||
return new CruelFateEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Card sourceCard = game.getCard(source.getSourceId());
|
||||
if (sourceCard != null) {
|
||||
Player you = game.getPlayer(source.getControllerId());
|
||||
Player player = game.getPlayer(source.getFirstTarget());
|
||||
if (player != null && you != null) {
|
||||
Cards cards = new CardsImpl();
|
||||
int count = Math.min(player.getLibrary().size(), 5);
|
||||
for (int i = 0; i < count; i++) {
|
||||
Card card = player.getLibrary().removeFromTop(game);
|
||||
if (card != null) {
|
||||
cards.add(card);
|
||||
}
|
||||
}
|
||||
|
||||
you.lookAtCards(sourceCard.getIdName(), cards, game);
|
||||
|
||||
// card to put into opponent's graveyard
|
||||
TargetCard target = new TargetCard(Zone.LIBRARY, new FilterCard("card to put into target opponent's graveyard"));
|
||||
if (player.canRespond()) {
|
||||
if (cards.size() > 1) {
|
||||
you.choose(Outcome.Detriment, cards, target, game);
|
||||
Card card = cards.get(target.getFirstTarget(), game);
|
||||
if (card != null) {
|
||||
cards.remove(card);
|
||||
card.moveToZone(Zone.GRAVEYARD, source.getSourceId(), game, true);
|
||||
}
|
||||
}
|
||||
else if (cards.size() == 1) {
|
||||
Card card = cards.get(cards.iterator().next(), game);
|
||||
card.moveToZone(Zone.GRAVEYARD, source.getSourceId(), game, true);
|
||||
}
|
||||
}
|
||||
// cards to put on the top of opponent's library
|
||||
TargetCard target2 = new TargetCard(Zone.LIBRARY, new FilterCard("card to put on the top of target opponent's library"));
|
||||
while (player.canRespond() && cards.size() > 1) {
|
||||
you.choose(Outcome.Neutral, cards, target2, game);
|
||||
Card card = cards.get(target2.getFirstTarget(), game);
|
||||
if (card != null) {
|
||||
cards.remove(card);
|
||||
card.moveToZone(Zone.LIBRARY, source.getSourceId(), game, true);
|
||||
}
|
||||
target2.clearChosen();
|
||||
}
|
||||
if (cards.size() == 1) {
|
||||
Card card = cards.get(cards.iterator().next(), game);
|
||||
card.moveToZone(Zone.LIBRARY, source.getSourceId(), game, true);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
110
Mage.Sets/src/mage/cards/d/DeepWood.java
Normal file
110
Mage.Sets/src/mage/cards/d/DeepWood.java
Normal file
|
@ -0,0 +1,110 @@
|
|||
/*
|
||||
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are
|
||||
* permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
* conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
* of conditions and the following disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* The views and conclusions contained in the software and documentation are those of the
|
||||
* authors and should not be interpreted as representing official policies, either expressed
|
||||
* or implied, of BetaSteward_at_googlemail.com.
|
||||
*/
|
||||
package mage.cards.d;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.common.CastOnlyDuringPhaseStepSourceAbility;
|
||||
import mage.abilities.condition.common.AttackedThisStepCondition;
|
||||
import mage.abilities.effects.PreventionEffectImpl;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.Duration;
|
||||
import mage.constants.PhaseStep;
|
||||
import mage.constants.TurnPhase;
|
||||
import mage.filter.common.FilterAttackingCreature;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.DamagePlayerEvent;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.watchers.common.PlayerAttackedStepWatcher;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author L_J
|
||||
*/
|
||||
public class DeepWood extends CardImpl {
|
||||
|
||||
public DeepWood(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{G}");
|
||||
|
||||
// Cast Deep Wood only during the declare attackers step and only if you've been attacked this step.
|
||||
Ability ability = new CastOnlyDuringPhaseStepSourceAbility(
|
||||
TurnPhase.COMBAT, PhaseStep.DECLARE_ATTACKERS, AttackedThisStepCondition.instance,
|
||||
"Cast {this} only during the declare attackers step and only if you've been attacked this step."
|
||||
);
|
||||
ability.addWatcher(new PlayerAttackedStepWatcher());
|
||||
this.addAbility(ability);
|
||||
|
||||
// Prevent all damage that would be dealt to you this turn by attacking creatures.
|
||||
this.getSpellAbility().addEffect(new DeepWoodEffect());
|
||||
}
|
||||
|
||||
public DeepWood(final DeepWood card) {
|
||||
super(card);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DeepWood copy() {
|
||||
return new DeepWood(this);
|
||||
}
|
||||
}
|
||||
|
||||
class DeepWoodEffect extends PreventionEffectImpl {
|
||||
|
||||
private static final FilterAttackingCreature filter = new FilterAttackingCreature();
|
||||
|
||||
DeepWoodEffect() {
|
||||
super(Duration.EndOfTurn, Integer.MAX_VALUE, false);
|
||||
staticText = "Prevent all damage that would be dealt to you this turn by attacking creatures";
|
||||
}
|
||||
|
||||
DeepWoodEffect(final DeepWoodEffect effect) {
|
||||
super(effect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DeepWoodEffect copy() {
|
||||
return new DeepWoodEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean applies(GameEvent event, Ability source, Game game) {
|
||||
if (super.applies(event, source, game) && event instanceof DamagePlayerEvent && event.getAmount() > 0) {
|
||||
DamagePlayerEvent damageEvent = (DamagePlayerEvent) event;
|
||||
if (event.getTargetId().equals(source.getControllerId())) {
|
||||
Permanent permanent = game.getPermanentOrLKIBattlefield(damageEvent.getSourceId());
|
||||
if (permanent != null && filter.match(permanent, game)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -124,7 +124,7 @@ class DefiantVanguardEffect extends OneShotEffect {
|
|||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Player controller = game.getPlayer(source.getControllerId());
|
||||
Permanent thisCreature = game.getPermanentOrLKIBattlefield(source.getId());
|
||||
Permanent thisCreature = game.getPermanentOrLKIBattlefield(source.getSourceId());
|
||||
if (controller != null && thisCreature != null) {
|
||||
BlockedAttackerWatcher watcher = (BlockedAttackerWatcher) game.getState().getWatchers().get(BlockedAttackerWatcher.class.getSimpleName());
|
||||
if (watcher != null) {
|
||||
|
@ -136,10 +136,10 @@ class DefiantVanguardEffect extends OneShotEffect {
|
|||
}
|
||||
}
|
||||
}
|
||||
thisCreature.destroy(source.getSourceId(), game, false);
|
||||
for (Permanent creature : toDestroy) {
|
||||
creature.destroy(source.getSourceId(), game, false);
|
||||
}
|
||||
thisCreature.destroy(source.getSourceId(), game, false);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,17 +28,14 @@
|
|||
package mage.cards.d;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
import mage.MageInt;
|
||||
import mage.abilities.TriggeredAbilityImpl;
|
||||
import mage.abilities.effects.common.*;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.*;
|
||||
import mage.filter.common.*;
|
||||
import mage.filter.predicate.mageobject.SubtypePredicate;
|
||||
import mage.filter.predicate.permanent.AnotherPredicate;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.DamageEvent;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.target.targetpointer.FixedTarget;
|
||||
|
@ -48,12 +45,6 @@ import mage.target.targetpointer.FixedTarget;
|
|||
*/
|
||||
public class DinosaurHunter extends CardImpl {
|
||||
|
||||
private static final FilterControlledCreaturePermanent filterAnotherDino = new FilterControlledCreaturePermanent();
|
||||
static {
|
||||
filterAnotherDino.add(new AnotherPredicate());
|
||||
filterAnotherDino.add(new SubtypePredicate(SubType.DINOSAUR));
|
||||
}
|
||||
|
||||
public DinosaurHunter(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{B}");
|
||||
|
||||
|
@ -78,11 +69,6 @@ public class DinosaurHunter extends CardImpl {
|
|||
|
||||
class DinosaurHunterAbility extends TriggeredAbilityImpl {
|
||||
|
||||
private static final FilterCreaturePermanent filter = new FilterCreaturePermanent();
|
||||
static {
|
||||
filter.add(new SubtypePredicate(SubType.DINOSAUR));
|
||||
}
|
||||
|
||||
DinosaurHunterAbility() {
|
||||
super(Zone.BATTLEFIELD, new DestroyTargetEffect());
|
||||
}
|
||||
|
@ -103,11 +89,13 @@ class DinosaurHunterAbility extends TriggeredAbilityImpl {
|
|||
|
||||
@Override
|
||||
public boolean checkTrigger(GameEvent event, Game game) {
|
||||
Permanent sourcePermanet = game.getPermanent(event.getSourceId());
|
||||
Permanent targetPermanet = game.getPermanent(event.getTargetId());
|
||||
if (sourcePermanet != null && targetPermanet != null && event.getSourceId().equals(sourceId) && filter.match(targetPermanet, game)) {
|
||||
getEffects().get(0).setTargetPointer(new FixedTarget(event.getTargetId()));
|
||||
return true;
|
||||
if (((DamageEvent) event).isCombatDamage()
|
||||
&& event.getSourceId().equals(getSourceId())) {
|
||||
Permanent targetPermanet = game.getPermanentOrLKIBattlefield(event.getTargetId());
|
||||
if (targetPermanet.hasSubtype(SubType.DINOSAUR, game)) {
|
||||
getEffects().get(0).setTargetPointer(new FixedTarget(targetPermanet, game));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -116,4 +104,4 @@ class DinosaurHunterAbility extends TriggeredAbilityImpl {
|
|||
public String getRule() {
|
||||
return "Whenever {this} deals combat damage to a Dinosaur, destroy that creature.";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -108,7 +108,8 @@ class DjinnIlluminatusGainReplicateEffect extends ContinuousEffectImpl {
|
|||
if ((stackObject instanceof Spell)
|
||||
&& !stackObject.isCopy()
|
||||
&& stackObject.getControllerId().equals(source.getControllerId())
|
||||
&& djinn.getControllerId().equals(source.getControllerId())) { // verify that the controller of the djinn cast that spell
|
||||
&& djinn.getControllerId().equals(source.getControllerId()) // verify that the controller of the djinn cast that spell
|
||||
&& !stackObject.getManaCost().isEmpty()) { //handle cases like Ancestral Vision
|
||||
Spell spell = (Spell) stackObject;
|
||||
if (filter.match(stackObject, game)) {
|
||||
ReplicateAbility replicateAbility = replicateAbilities.computeIfAbsent(spell.getId(), k -> new ReplicateAbility(spell.getCard(), spell.getSpellAbility().getManaCosts().getText()));
|
||||
|
|
|
@ -31,7 +31,6 @@ import java.util.UUID;
|
|||
import mage.MageInt;
|
||||
import mage.abilities.TriggeredAbilityImpl;
|
||||
import mage.abilities.common.PutIntoGraveFromAnywhereSourceTriggeredAbility;
|
||||
import mage.abilities.effects.Effect;
|
||||
import mage.abilities.effects.common.DestroyTargetEffect;
|
||||
import mage.abilities.effects.common.ShuffleIntoLibrarySourceEffect;
|
||||
import mage.abilities.keyword.FearAbility;
|
||||
|
@ -105,11 +104,7 @@ class DreadTriggeredAbility extends TriggeredAbilityImpl {
|
|||
if (event.getPlayerId().equals(this.getControllerId())) {
|
||||
Permanent permanent = game.getPermanent(event.getSourceId());
|
||||
if (permanent != null && permanent.isCreature()) {
|
||||
for (Effect effect : this.getEffects()) {
|
||||
if (effect instanceof DestroyTargetEffect) {
|
||||
effect.setTargetPointer(new FixedTarget(event.getSourceId()));
|
||||
}
|
||||
}
|
||||
this.getEffects().setTargetPointer(new FixedTarget(permanent, game));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
73
Mage.Sets/src/mage/cards/d/DreadCharge.java
Normal file
73
Mage.Sets/src/mage/cards/d/DreadCharge.java
Normal file
|
@ -0,0 +1,73 @@
|
|||
/*
|
||||
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are
|
||||
* permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
* conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
* of conditions and the following disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* The views and conclusions contained in the software and documentation are those of the
|
||||
* authors and should not be interpreted as representing official policies, either expressed
|
||||
* or implied, of BetaSteward_at_googlemail.com.
|
||||
*/
|
||||
package mage.cards.d;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.ObjectColor;
|
||||
import mage.abilities.effects.common.combat.CantBeBlockedByCreaturesAllEffect;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.Duration;
|
||||
import mage.constants.TargetController;
|
||||
import mage.filter.common.FilterCreaturePermanent;
|
||||
import mage.filter.predicate.Predicates;
|
||||
import mage.filter.predicate.mageobject.ColorPredicate;
|
||||
import mage.filter.predicate.permanent.ControllerPredicate;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author L_J
|
||||
*/
|
||||
public class DreadCharge extends CardImpl {
|
||||
|
||||
private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("Black creatures you control");
|
||||
private static final FilterCreaturePermanent filter2 = new FilterCreaturePermanent("except by black creatures");
|
||||
|
||||
static {
|
||||
filter.add(new ColorPredicate(ObjectColor.BLACK));
|
||||
filter2.add(Predicates.not(new ColorPredicate(ObjectColor.BLACK)));
|
||||
filter.add(new ControllerPredicate(TargetController.YOU));
|
||||
}
|
||||
|
||||
public DreadCharge(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{3}{B}");
|
||||
|
||||
// Black creatures you control can't be blocked this turn except by black creatures.
|
||||
this.getSpellAbility().addEffect(new CantBeBlockedByCreaturesAllEffect(filter, filter2, Duration.EndOfTurn));
|
||||
}
|
||||
|
||||
public DreadCharge(final DreadCharge card) {
|
||||
super(card);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DreadCharge copy() {
|
||||
return new DreadCharge(this);
|
||||
}
|
||||
}
|
145
Mage.Sets/src/mage/cards/e/EunuchsIntrigues.java
Normal file
145
Mage.Sets/src/mage/cards/e/EunuchsIntrigues.java
Normal file
|
@ -0,0 +1,145 @@
|
|||
/*
|
||||
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are
|
||||
* permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
* conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
* of conditions and the following disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* The views and conclusions contained in the software and documentation are those of the
|
||||
* authors and should not be interpreted as representing official policies, either expressed
|
||||
* or implied, of BetaSteward_at_googlemail.com.
|
||||
*/
|
||||
package mage.cards.e;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.abilities.effects.RestrictionEffect;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.Duration;
|
||||
import mage.constants.Outcome;
|
||||
import mage.filter.common.FilterCreaturePermanent;
|
||||
import mage.filter.predicate.permanent.ControllerIdPredicate;
|
||||
import mage.game.Game;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.players.Player;
|
||||
import mage.target.Target;
|
||||
import mage.target.TargetPermanent;
|
||||
import mage.target.common.TargetOpponent;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author TheElk801 & L_J
|
||||
*/
|
||||
public class EunuchsIntrigues extends CardImpl {
|
||||
|
||||
public EunuchsIntrigues(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{R}");
|
||||
|
||||
// Target opponent chooses a creature he or she controls. Other creatures he or she controls can't block this turn.
|
||||
this.getSpellAbility().addEffect(new EunuchsIntriguesEffect());
|
||||
this.getSpellAbility().addTarget(new TargetOpponent());
|
||||
}
|
||||
|
||||
public EunuchsIntrigues(final EunuchsIntrigues card) {
|
||||
super(card);
|
||||
}
|
||||
|
||||
@Override
|
||||
public EunuchsIntrigues copy() {
|
||||
return new EunuchsIntrigues(this);
|
||||
}
|
||||
}
|
||||
|
||||
class EunuchsIntriguesEffect extends OneShotEffect {
|
||||
|
||||
EunuchsIntriguesEffect() {
|
||||
super(Outcome.Benefit);
|
||||
this.staticText = "Target opponent chooses a creature he or she controls. Other creatures he or she controls can't block this turn.";
|
||||
}
|
||||
|
||||
EunuchsIntriguesEffect(final EunuchsIntriguesEffect effect) {
|
||||
super(effect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public EunuchsIntriguesEffect copy() {
|
||||
return new EunuchsIntriguesEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Player player = game.getPlayer(source.getFirstTarget());
|
||||
if (player == null) {
|
||||
return false;
|
||||
}
|
||||
FilterCreaturePermanent filter = new FilterCreaturePermanent("creature you control");
|
||||
filter.add(new ControllerIdPredicate(player.getId()));
|
||||
Target target = new TargetPermanent(1, 1, filter, true);
|
||||
if (target.canChoose(source.getSourceId(), player.getId(), game)) {
|
||||
while (!target.isChosen() && target.canChoose(player.getId(), game) && player.canRespond()) {
|
||||
player.chooseTarget(Outcome.DestroyPermanent, target, source, game);
|
||||
}
|
||||
Permanent permanent = game.getPermanent(target.getFirstTarget());
|
||||
if (permanent != null) {
|
||||
game.informPlayers(player.getLogName() + " has chosen " + permanent.getLogName() + " as his only creature able to block this turn");
|
||||
}
|
||||
}
|
||||
game.addEffect(new EunuchsIntriguesRestrictionEffect(target.getFirstTarget()), source);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
class EunuchsIntriguesRestrictionEffect extends RestrictionEffect {
|
||||
|
||||
protected UUID targetId;
|
||||
|
||||
public EunuchsIntriguesRestrictionEffect(UUID targetId) {
|
||||
super(Duration.EndOfTurn);
|
||||
this.targetId = targetId;
|
||||
}
|
||||
|
||||
public EunuchsIntriguesRestrictionEffect(final EunuchsIntriguesRestrictionEffect effect) {
|
||||
super(effect);
|
||||
targetId = effect.targetId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EunuchsIntriguesRestrictionEffect copy() {
|
||||
return new EunuchsIntriguesRestrictionEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean applies(Permanent permanent, Ability source, Game game) {
|
||||
if (permanent.getControllerId().equals(source.getFirstTarget())) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game) {
|
||||
if (targetId != null && blocker.getId().equals(targetId)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -80,7 +80,7 @@ class ExaltedDragonCostToAttackBlockEffect extends PayCostToAttackBlockEffectImp
|
|||
ExaltedDragonCostToAttackBlockEffect() {
|
||||
super(Duration.WhileOnBattlefield, Outcome.Detriment, RestrictType.ATTACK,
|
||||
new SacrificeTargetCost(new TargetControlledPermanent(new FilterControlledLandPermanent("a land"))));
|
||||
staticText = "{this} can't attack unless you sacrifice a land <i>(This cost is paid as attackers are declared.)</i>";
|
||||
staticText = "{this} can't attack unless you sacrifice a land. <i>(This cost is paid as attackers are declared.)</i>";
|
||||
}
|
||||
|
||||
ExaltedDragonCostToAttackBlockEffect(ExaltedDragonCostToAttackBlockEffect effect) {
|
||||
|
|
|
@ -94,6 +94,7 @@ class ExhumeEffect extends OneShotEffect {
|
|||
FilterCreatureCard filterCreatureCard = new FilterCreatureCard("creature card from your graveyard");
|
||||
filterCreatureCard.add(new OwnerIdPredicate(playerId));
|
||||
TargetCardInGraveyard target = new TargetCardInGraveyard(filterCreatureCard);
|
||||
target.setNotTarget(true);
|
||||
if (target.canChoose(playerId, game)
|
||||
&& player.chooseTarget(outcome, target, source, game)) {
|
||||
Card card = game.getCard(target.getFirstTarget());
|
||||
|
|
|
@ -28,24 +28,22 @@
|
|||
package mage.cards.e;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.MageObject;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.TriggeredAbilityImpl;
|
||||
import mage.abilities.effects.Effect;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.abilities.effects.ReplacementEffectImpl;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.Duration;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.Zone;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.DamageEvent;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.players.Player;
|
||||
import mage.target.targetpointer.FixedTarget;
|
||||
import mage.target.TargetSource;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author MarcoMarin
|
||||
*
|
||||
* @author L_J
|
||||
*/
|
||||
public class EyeForAnEye extends CardImpl {
|
||||
|
||||
|
@ -53,8 +51,7 @@ public class EyeForAnEye extends CardImpl {
|
|||
super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{W}{W}");
|
||||
|
||||
// The next time a source of your choice would deal damage to you this turn, instead that source deals that much damage to you and Eye for an Eye deals that much damage to that source's controller.
|
||||
this.addAbility(new EyeForAnEyeTriggeredAbility(new EyeForAnEyeEffect()));
|
||||
|
||||
this.getSpellAbility().addEffect(new EyeForAnEyeEffect());
|
||||
}
|
||||
|
||||
public EyeForAnEye(final EyeForAnEye card) {
|
||||
|
@ -67,48 +64,19 @@ public class EyeForAnEye extends CardImpl {
|
|||
}
|
||||
}
|
||||
|
||||
class EyeForAnEyeTriggeredAbility extends TriggeredAbilityImpl {
|
||||
class EyeForAnEyeEffect extends ReplacementEffectImpl {
|
||||
|
||||
public EyeForAnEyeTriggeredAbility(Effect effect) {
|
||||
super(Zone.BATTLEFIELD, effect);
|
||||
}
|
||||
|
||||
public EyeForAnEyeTriggeredAbility(final EyeForAnEyeTriggeredAbility ability) {
|
||||
super(ability);
|
||||
}
|
||||
|
||||
@Override
|
||||
public EyeForAnEyeTriggeredAbility copy() {
|
||||
return new EyeForAnEyeTriggeredAbility(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkEventType(GameEvent event, Game game) {
|
||||
return event.getType() == GameEvent.EventType.DAMAGED_PLAYER;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkTrigger(GameEvent event, Game game) {
|
||||
MageObject sourceObject = game.getObject(event.getSourceId());
|
||||
this.getEffects().get(0).setValue("damageAmount", event.getAmount());
|
||||
this.getEffects().get(0).setTargetPointer(new FixedTarget(game.getControllerId(sourceObject.getId())));
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRule() {
|
||||
return "The next time a source of your choice would deal damage to you this turn, instead that source deals that much damage to you and {this} deals that much damage to that source's controller.";
|
||||
}
|
||||
}
|
||||
|
||||
class EyeForAnEyeEffect extends OneShotEffect {
|
||||
private final TargetSource damageSource;
|
||||
|
||||
public EyeForAnEyeEffect() {
|
||||
super(Outcome.Damage);
|
||||
super(Duration.EndOfTurn, Outcome.RedirectDamage);
|
||||
staticText = "The next time a source of your choice would deal damage to you this turn, instead that source deals that much damage to you and {this} deals that much damage to that source's controller";
|
||||
this.damageSource = new TargetSource();
|
||||
}
|
||||
|
||||
public EyeForAnEyeEffect(final EyeForAnEyeEffect effect) {
|
||||
super(effect);
|
||||
this.damageSource = effect.damageSource.copy();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -116,15 +84,48 @@ class EyeForAnEyeEffect extends OneShotEffect {
|
|||
return new EyeForAnEyeEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(Ability source, Game game) {
|
||||
this.damageSource.choose(Outcome.PreventDamage, source.getControllerId(), source.getSourceId(), game);
|
||||
super.init(source, game);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checksEventType(GameEvent event, Game game) {
|
||||
return event.getType() == GameEvent.EventType.DAMAGE_PLAYER;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Integer damageAmount = (Integer) this.getValue("damageAmount");
|
||||
UUID targetId = this.targetPointer.getFirst(game, source);
|
||||
if (damageAmount != null && targetId != null) {
|
||||
Player player = game.getPlayer(targetId);
|
||||
if (player != null) {
|
||||
player.damage(damageAmount, targetId, game, false, true);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean replaceEvent(GameEvent event, Ability source, Game game) {
|
||||
Player controller = game.getPlayer(source.getControllerId());
|
||||
DamageEvent damageEvent = (DamageEvent) event;
|
||||
if (controller != null) {
|
||||
controller.damage(damageEvent.getAmount(), damageEvent.getSourceId(), game, damageEvent.isCombatDamage(), damageEvent.isPreventable(), damageEvent.getAppliedEffects());
|
||||
UUID sourceControllerId = game.getControllerId(damageEvent.getSourceId());
|
||||
if (sourceControllerId != null) {
|
||||
Player sourceController = game.getPlayer(sourceControllerId);
|
||||
if (sourceController != null) {
|
||||
sourceController.damage(damageEvent.getAmount(), source.getSourceId(), game, false, true);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean applies(GameEvent event, Ability source, Game game) {
|
||||
Player controller = game.getPlayer(source.getControllerId());
|
||||
DamageEvent damageEvent = (DamageEvent) event;
|
||||
if (controller != null) {
|
||||
if (controller.getId() == damageEvent.getTargetId() && damageEvent.getSourceId().equals(damageSource.getFirstTarget())) {
|
||||
this.discard();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
|
110
Mage.Sets/src/mage/cards/f/Foreshadow.java
Normal file
110
Mage.Sets/src/mage/cards/f/Foreshadow.java
Normal file
|
@ -0,0 +1,110 @@
|
|||
/*
|
||||
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are
|
||||
* permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
* conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
* of conditions and the following disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* The views and conclusions contained in the software and documentation are those of the
|
||||
* authors and should not be interpreted as representing official policies, either expressed
|
||||
* or implied, of BetaSteward_at_googlemail.com.
|
||||
*/
|
||||
package mage.cards.f;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.common.delayed.AtTheBeginOfNextUpkeepDelayedTriggeredAbility;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect;
|
||||
import mage.abilities.effects.common.DrawCardSourceControllerEffect;
|
||||
import mage.abilities.effects.common.NameACardEffect;
|
||||
import mage.cards.Card;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.Zone;
|
||||
import mage.game.Game;
|
||||
import mage.players.Player;
|
||||
import mage.target.common.TargetOpponent;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Quercitron & L_J
|
||||
*/
|
||||
public class Foreshadow extends CardImpl {
|
||||
|
||||
public Foreshadow(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{1}{U}");
|
||||
|
||||
// Choose a card name, then target opponent puts the top card of his or her library into his or her graveyard. If that card has the chosen name, you draw a card.
|
||||
this.getSpellAbility().addEffect(new NameACardEffect(NameACardEffect.TypeOfName.ALL));
|
||||
this.getSpellAbility().addEffect(new ForeshadowEffect());
|
||||
this.getSpellAbility().addTarget(new TargetOpponent());
|
||||
|
||||
// Draw a card at the beginning of the next turn's upkeep.
|
||||
this.getSpellAbility().addEffect(new CreateDelayedTriggeredAbilityEffect(
|
||||
new AtTheBeginOfNextUpkeepDelayedTriggeredAbility(new DrawCardSourceControllerEffect(1)), false));
|
||||
}
|
||||
|
||||
public Foreshadow(final Foreshadow card) {
|
||||
super(card);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Foreshadow copy() {
|
||||
return new Foreshadow(this);
|
||||
}
|
||||
}
|
||||
|
||||
class ForeshadowEffect extends OneShotEffect {
|
||||
|
||||
public ForeshadowEffect() {
|
||||
super(Outcome.DrawCard);
|
||||
this.staticText = ", then target opponent puts the top card of his or her library into his or her graveyard. If that card has the chosen name, you draw a card";
|
||||
}
|
||||
|
||||
public ForeshadowEffect(final ForeshadowEffect effect) {
|
||||
super(effect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ForeshadowEffect copy() {
|
||||
return new ForeshadowEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Player controller = game.getPlayer(source.getControllerId());
|
||||
Player targetPlayer = game.getPlayer(source.getFirstTarget());
|
||||
String cardName = (String) game.getState().getValue(source.getSourceId().toString() + NameACardEffect.INFO_KEY);
|
||||
if (controller != null && targetPlayer != null && cardName != null && !cardName.isEmpty()) {
|
||||
Card card = targetPlayer.getLibrary().getFromTop(game);
|
||||
if (card != null) {
|
||||
controller.moveCards(card, Zone.GRAVEYARD, source, game);
|
||||
if (card.getName().equals(cardName)) {
|
||||
controller.drawCards(1, game);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
153
Mage.Sets/src/mage/cards/g/GlyphOfDoom.java
Normal file
153
Mage.Sets/src/mage/cards/g/GlyphOfDoom.java
Normal file
|
@ -0,0 +1,153 @@
|
|||
/*
|
||||
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are
|
||||
* permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
* conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
* of conditions and the following disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* The views and conclusions contained in the software and documentation are those of the
|
||||
* authors and should not be interpreted as representing official policies, either expressed
|
||||
* or implied, of BetaSteward_at_googlemail.com.
|
||||
*/
|
||||
package mage.cards.g;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import mage.MageObjectReference;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.common.delayed.AtTheEndOfCombatDelayedTriggeredAbility;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.abilities.effects.common.InfoEffect;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.SubType;
|
||||
import mage.constants.Outcome;
|
||||
import mage.filter.StaticFilters;
|
||||
import mage.filter.common.FilterCreaturePermanent;
|
||||
import mage.filter.predicate.mageobject.SubtypePredicate;
|
||||
import mage.game.Game;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.players.Player;
|
||||
import mage.target.common.TargetCreaturePermanent;
|
||||
import mage.watchers.common.BlockedAttackerWatcher;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author LevelX2 & L_J
|
||||
*/
|
||||
public class GlyphOfDoom extends CardImpl {
|
||||
|
||||
private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("Wall creature");
|
||||
|
||||
static {
|
||||
filter.add(new SubtypePredicate(SubType.WALL));
|
||||
}
|
||||
|
||||
public GlyphOfDoom(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{B}");
|
||||
|
||||
// Choose target Wall creature. At this turn's next end of combat, destroy all creatures that were blocked by that creature this turn.
|
||||
this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter));
|
||||
this.getSpellAbility().addEffect(new InfoEffect("Choose target Wall creature"));
|
||||
this.getSpellAbility().addEffect(new GlyphOfDoomCreateDelayedTriggeredAbilityEffect());
|
||||
this.getSpellAbility().addWatcher(new BlockedAttackerWatcher());
|
||||
}
|
||||
|
||||
public GlyphOfDoom(final GlyphOfDoom card) {
|
||||
super(card);
|
||||
}
|
||||
|
||||
@Override
|
||||
public GlyphOfDoom copy() {
|
||||
return new GlyphOfDoom(this);
|
||||
}
|
||||
}
|
||||
|
||||
class GlyphOfDoomCreateDelayedTriggeredAbilityEffect extends OneShotEffect {
|
||||
|
||||
public GlyphOfDoomCreateDelayedTriggeredAbilityEffect() {
|
||||
super(Outcome.Benefit);
|
||||
this.staticText = "At this turn's next end of combat, destroy all creatures that were blocked by that creature this turn";
|
||||
}
|
||||
|
||||
public GlyphOfDoomCreateDelayedTriggeredAbilityEffect(final GlyphOfDoomCreateDelayedTriggeredAbilityEffect effect) {
|
||||
super(effect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public GlyphOfDoomCreateDelayedTriggeredAbilityEffect copy() {
|
||||
return new GlyphOfDoomCreateDelayedTriggeredAbilityEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
if (!source.getTargets().isEmpty() && source.getFirstTarget() != null) {
|
||||
MageObjectReference mor = new MageObjectReference(source.getFirstTarget(), game);
|
||||
AtTheEndOfCombatDelayedTriggeredAbility delayedAbility = new AtTheEndOfCombatDelayedTriggeredAbility(new GlyphOfDoomEffect(mor));
|
||||
game.addDelayedTriggeredAbility(delayedAbility, source);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
class GlyphOfDoomEffect extends OneShotEffect {
|
||||
|
||||
MageObjectReference targetCreature;
|
||||
|
||||
public GlyphOfDoomEffect(MageObjectReference targetCreature) {
|
||||
super(Outcome.DestroyPermanent);
|
||||
this.targetCreature = targetCreature;
|
||||
}
|
||||
|
||||
public GlyphOfDoomEffect(final GlyphOfDoomEffect effect) {
|
||||
super(effect);
|
||||
targetCreature = effect.targetCreature;
|
||||
}
|
||||
|
||||
@Override
|
||||
public GlyphOfDoomEffect copy() {
|
||||
return new GlyphOfDoomEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Player controller = game.getPlayer(source.getControllerId());
|
||||
if (controller != null && targetCreature != null) {
|
||||
BlockedAttackerWatcher watcher = (BlockedAttackerWatcher) game.getState().getWatchers().get(BlockedAttackerWatcher.class.getSimpleName());
|
||||
if (watcher != null) {
|
||||
List<Permanent> toDestroy = new ArrayList<>();
|
||||
for (Permanent creature : game.getBattlefield().getActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, source.getControllerId(), source.getSourceId(), game)) {
|
||||
if (!creature.getId().equals(targetCreature.getSourceId())) {
|
||||
if (watcher.creatureHasBlockedAttacker(new MageObjectReference(creature, game), targetCreature, game)) {
|
||||
toDestroy.add(creature);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (Permanent creature : toDestroy) {
|
||||
creature.destroy(source.getSourceId(), game, false);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
145
Mage.Sets/src/mage/cards/g/GoblinWarCry.java
Normal file
145
Mage.Sets/src/mage/cards/g/GoblinWarCry.java
Normal file
|
@ -0,0 +1,145 @@
|
|||
/*
|
||||
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are
|
||||
* permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
* conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
* of conditions and the following disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* The views and conclusions contained in the software and documentation are those of the
|
||||
* authors and should not be interpreted as representing official policies, either expressed
|
||||
* or implied, of BetaSteward_at_googlemail.com.
|
||||
*/
|
||||
package mage.cards.g;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.abilities.effects.RestrictionEffect;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.Duration;
|
||||
import mage.constants.Outcome;
|
||||
import mage.filter.common.FilterCreaturePermanent;
|
||||
import mage.filter.predicate.permanent.ControllerIdPredicate;
|
||||
import mage.game.Game;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.players.Player;
|
||||
import mage.target.Target;
|
||||
import mage.target.TargetPermanent;
|
||||
import mage.target.common.TargetOpponent;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author TheElk801 & L_J
|
||||
*/
|
||||
public class GoblinWarCry extends CardImpl {
|
||||
|
||||
public GoblinWarCry(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{R}");
|
||||
|
||||
// Target opponent chooses a creature he or she controls. Other creatures he or she controls can't block this turn.
|
||||
this.getSpellAbility().addEffect(new GoblinWarCryEffect());
|
||||
this.getSpellAbility().addTarget(new TargetOpponent());
|
||||
}
|
||||
|
||||
public GoblinWarCry(final GoblinWarCry card) {
|
||||
super(card);
|
||||
}
|
||||
|
||||
@Override
|
||||
public GoblinWarCry copy() {
|
||||
return new GoblinWarCry(this);
|
||||
}
|
||||
}
|
||||
|
||||
class GoblinWarCryEffect extends OneShotEffect {
|
||||
|
||||
GoblinWarCryEffect() {
|
||||
super(Outcome.Benefit);
|
||||
this.staticText = "Target opponent chooses a creature he or she controls. Other creatures he or she controls can't block this turn.";
|
||||
}
|
||||
|
||||
GoblinWarCryEffect(final GoblinWarCryEffect effect) {
|
||||
super(effect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public GoblinWarCryEffect copy() {
|
||||
return new GoblinWarCryEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Player player = game.getPlayer(source.getFirstTarget());
|
||||
if (player == null) {
|
||||
return false;
|
||||
}
|
||||
FilterCreaturePermanent filter = new FilterCreaturePermanent("creature you control");
|
||||
filter.add(new ControllerIdPredicate(player.getId()));
|
||||
Target target = new TargetPermanent(1, 1, filter, true);
|
||||
if (target.canChoose(source.getSourceId(), player.getId(), game)) {
|
||||
while (!target.isChosen() && target.canChoose(player.getId(), game) && player.canRespond()) {
|
||||
player.chooseTarget(Outcome.DestroyPermanent, target, source, game);
|
||||
}
|
||||
Permanent permanent = game.getPermanent(target.getFirstTarget());
|
||||
if (permanent != null) {
|
||||
game.informPlayers(player.getLogName() + " has chosen " + permanent.getLogName() + " as his only creature able to block this turn");
|
||||
}
|
||||
}
|
||||
game.addEffect(new GoblinWarCryRestrictionEffect(target.getFirstTarget()), source);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
class GoblinWarCryRestrictionEffect extends RestrictionEffect {
|
||||
|
||||
protected UUID targetId;
|
||||
|
||||
public GoblinWarCryRestrictionEffect(UUID targetId) {
|
||||
super(Duration.EndOfTurn);
|
||||
this.targetId = targetId;
|
||||
}
|
||||
|
||||
public GoblinWarCryRestrictionEffect(final GoblinWarCryRestrictionEffect effect) {
|
||||
super(effect);
|
||||
targetId = effect.targetId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public GoblinWarCryRestrictionEffect copy() {
|
||||
return new GoblinWarCryRestrictionEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean applies(Permanent permanent, Ability source, Game game) {
|
||||
if (permanent.getControllerId().equals(source.getFirstTarget())) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game) {
|
||||
if (targetId != null && blocker.getId().equals(targetId)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
170
Mage.Sets/src/mage/cards/h/HarshJustice.java
Normal file
170
Mage.Sets/src/mage/cards/h/HarshJustice.java
Normal file
|
@ -0,0 +1,170 @@
|
|||
/*
|
||||
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are
|
||||
* permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
* conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
* of conditions and the following disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* The views and conclusions contained in the software and documentation are those of the
|
||||
* authors and should not be interpreted as representing official policies, either expressed
|
||||
* or implied, of BetaSteward_at_googlemail.com.
|
||||
*/
|
||||
package mage.cards.h;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.MageObject;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.DelayedTriggeredAbility;
|
||||
import mage.abilities.common.CastOnlyDuringPhaseStepSourceAbility;
|
||||
import mage.abilities.condition.common.AttackedThisStepCondition;
|
||||
import mage.abilities.effects.Effect;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.Duration;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.PhaseStep;
|
||||
import mage.constants.TurnPhase;
|
||||
import mage.filter.common.FilterCreaturePermanent;
|
||||
import mage.filter.predicate.permanent.AttackingPredicate;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.DamagedPlayerEvent;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.game.events.GameEvent.EventType;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.players.Player;
|
||||
import mage.watchers.common.PlayerAttackedStepWatcher;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author LevelX2 & L_J
|
||||
*/
|
||||
public class HarshJustice extends CardImpl {
|
||||
|
||||
public HarshJustice(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{W}");
|
||||
|
||||
// Cast Harsh Justice only during the declare attackers step and only if you've been attacked this step.
|
||||
Ability ability = new CastOnlyDuringPhaseStepSourceAbility(
|
||||
TurnPhase.COMBAT, PhaseStep.DECLARE_ATTACKERS, AttackedThisStepCondition.instance,
|
||||
"Cast {this} only during the declare attackers step and only if you've been attacked this step."
|
||||
);
|
||||
ability.addWatcher(new PlayerAttackedStepWatcher());
|
||||
this.addAbility(ability);
|
||||
|
||||
// This turn, whenever an attacking creature deals combat damage to you, it deals that much damage to its controller.
|
||||
this.getSpellAbility().addEffect(new CreateDelayedTriggeredAbilityEffect(new HarshJusticeTriggeredAbility()));
|
||||
}
|
||||
|
||||
public HarshJustice(final HarshJustice card) {
|
||||
super(card);
|
||||
}
|
||||
|
||||
@Override
|
||||
public HarshJustice copy() {
|
||||
return new HarshJustice(this);
|
||||
}
|
||||
}
|
||||
|
||||
class HarshJusticeTriggeredAbility extends DelayedTriggeredAbility {
|
||||
|
||||
private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("attacking creature");
|
||||
|
||||
static {
|
||||
filter.add(new AttackingPredicate());
|
||||
}
|
||||
|
||||
public HarshJusticeTriggeredAbility() {
|
||||
super(new HarshJusticeEffect(), Duration.EndOfTurn, false);
|
||||
}
|
||||
|
||||
public HarshJusticeTriggeredAbility(final HarshJusticeTriggeredAbility ability) {
|
||||
super(ability);
|
||||
}
|
||||
|
||||
@Override
|
||||
public HarshJusticeTriggeredAbility copy() {
|
||||
return new HarshJusticeTriggeredAbility(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkEventType(GameEvent event, Game game) {
|
||||
return event.getType() == EventType.DAMAGED_PLAYER;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkTrigger(GameEvent event, Game game) {
|
||||
Player controller = game.getPlayer(this.getControllerId());
|
||||
DamagedPlayerEvent damageEvent = (DamagedPlayerEvent) event;
|
||||
Permanent damagePermanent = game.getPermanentOrLKIBattlefield(damageEvent.getSourceId());
|
||||
if (controller != null && damagePermanent != null) {
|
||||
if (damageEvent.isCombatDamage() && controller.getId().equals(damageEvent.getTargetId()) && filter.match(damagePermanent, game)) {
|
||||
for (Effect effect : this.getEffects()) {
|
||||
effect.setValue("damage", damageEvent.getAmount());
|
||||
effect.setValue("sourceId", damageEvent.getSourceId());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRule() {
|
||||
return "This turn, whenever an attacking creature deals combat damage to you, " + super.getRule();
|
||||
}
|
||||
}
|
||||
|
||||
class HarshJusticeEffect extends OneShotEffect {
|
||||
|
||||
public HarshJusticeEffect() {
|
||||
super(Outcome.Benefit);
|
||||
this.staticText = "it deals that much damage to its controller";
|
||||
}
|
||||
|
||||
public HarshJusticeEffect(final HarshJusticeEffect effect) {
|
||||
super(effect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public HarshJusticeEffect copy() {
|
||||
return new HarshJusticeEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
int damage = (Integer) this.getValue("damage");
|
||||
UUID sourceId = (UUID) this.getValue("sourceId");
|
||||
MageObject sourceObject = game.getObject(source.getSourceId());
|
||||
if (sourceObject != null && damage > 0 && sourceId != null) {
|
||||
Permanent targetObject = game.getPermanentOrLKIBattlefield(sourceId);
|
||||
if (targetObject != null) {
|
||||
Player controller = game.getPlayer(targetObject.getControllerId());
|
||||
if (controller != null) {
|
||||
game.informPlayers(sourceObject.getLogName() + ": " + targetObject.getLogName() + " deals " + damage + " damage to " + controller.getLogName());
|
||||
controller.damage(damage, sourceId, game, false, true);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -29,10 +29,9 @@ package mage.cards.h;
|
|||
|
||||
import java.util.UUID;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.common.delayed.AtTheEndOfTurnStepPostDelayedTriggeredAbility;
|
||||
import mage.abilities.effects.Effect;
|
||||
import mage.abilities.DelayedTriggeredAbility;
|
||||
import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbility;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect;
|
||||
import mage.abilities.effects.common.ExileTargetEffect;
|
||||
import mage.abilities.effects.common.CreateTokenCopyTargetEffect;
|
||||
import mage.cards.CardImpl;
|
||||
|
@ -52,7 +51,7 @@ import mage.target.targetpointer.FixedTarget;
|
|||
public class HeatShimmer extends CardImpl {
|
||||
|
||||
public HeatShimmer(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{2}{R}");
|
||||
super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{R}");
|
||||
|
||||
// Create a token that's a copy of target creature. That token has haste and "At the beginning of the end step, exile this permanent."
|
||||
this.getSpellAbility().addEffect(new HeatShimmerEffect());
|
||||
|
@ -89,15 +88,15 @@ class HeatShimmerEffect extends OneShotEffect {
|
|||
public boolean apply(Game game, Ability source) {
|
||||
Player controller = game.getPlayer(source.getControllerId());
|
||||
Permanent permanent = game.getPermanentOrLKIBattlefield(getTargetPointer().getFirst(game, source));
|
||||
if (controller != null && permanent != null) {
|
||||
if (controller != null
|
||||
&& permanent != null) {
|
||||
CreateTokenCopyTargetEffect effect = new CreateTokenCopyTargetEffect(source.getControllerId(), null, true);
|
||||
effect.setTargetPointer(new FixedTarget(permanent, game));
|
||||
effect.apply(game, source);
|
||||
for (Permanent addedToken : effect.getAddedPermanent()) {
|
||||
Effect exileEffect = new ExileTargetEffect();
|
||||
exileEffect.setTargetPointer(new FixedTarget(addedToken, game));
|
||||
new CreateDelayedTriggeredAbilityEffect(new AtTheEndOfTurnStepPostDelayedTriggeredAbility(exileEffect), false).apply(game, source);
|
||||
}
|
||||
ExileTargetEffect exileEffect = new ExileTargetEffect();
|
||||
exileEffect.setTargetPointer(new FixedTarget(effect.getAddedPermanent().get(0), game));
|
||||
DelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(exileEffect);
|
||||
game.addDelayedTriggeredAbility(delayedAbility, source);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
|
110
Mage.Sets/src/mage/cards/h/HeavyFog.java
Normal file
110
Mage.Sets/src/mage/cards/h/HeavyFog.java
Normal file
|
@ -0,0 +1,110 @@
|
|||
/*
|
||||
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are
|
||||
* permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
* conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
* of conditions and the following disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* The views and conclusions contained in the software and documentation are those of the
|
||||
* authors and should not be interpreted as representing official policies, either expressed
|
||||
* or implied, of BetaSteward_at_googlemail.com.
|
||||
*/
|
||||
package mage.cards.h;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.common.CastOnlyDuringPhaseStepSourceAbility;
|
||||
import mage.abilities.condition.common.AttackedThisStepCondition;
|
||||
import mage.abilities.effects.PreventionEffectImpl;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.Duration;
|
||||
import mage.constants.PhaseStep;
|
||||
import mage.constants.TurnPhase;
|
||||
import mage.filter.common.FilterAttackingCreature;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.DamagePlayerEvent;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.watchers.common.PlayerAttackedStepWatcher;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author L_J
|
||||
*/
|
||||
public class HeavyFog extends CardImpl {
|
||||
|
||||
public HeavyFog(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{G}");
|
||||
|
||||
// Cast Deep Wood only during the declare attackers step and only if you've been attacked this step.
|
||||
Ability ability = new CastOnlyDuringPhaseStepSourceAbility(
|
||||
TurnPhase.COMBAT, PhaseStep.DECLARE_ATTACKERS, AttackedThisStepCondition.instance,
|
||||
"Cast {this} only during the declare attackers step and only if you've been attacked this step."
|
||||
);
|
||||
ability.addWatcher(new PlayerAttackedStepWatcher());
|
||||
this.addAbility(ability);
|
||||
|
||||
// Prevent all damage that would be dealt to you this turn by attacking creatures.
|
||||
this.getSpellAbility().addEffect(new HeavyFogEffect());
|
||||
}
|
||||
|
||||
public HeavyFog(final HeavyFog card) {
|
||||
super(card);
|
||||
}
|
||||
|
||||
@Override
|
||||
public HeavyFog copy() {
|
||||
return new HeavyFog(this);
|
||||
}
|
||||
}
|
||||
|
||||
class HeavyFogEffect extends PreventionEffectImpl {
|
||||
|
||||
private static final FilterAttackingCreature filter = new FilterAttackingCreature();
|
||||
|
||||
HeavyFogEffect() {
|
||||
super(Duration.EndOfTurn, Integer.MAX_VALUE, false);
|
||||
staticText = "Prevent all damage that would be dealt to you this turn by attacking creatures";
|
||||
}
|
||||
|
||||
HeavyFogEffect(final HeavyFogEffect effect) {
|
||||
super(effect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public HeavyFogEffect copy() {
|
||||
return new HeavyFogEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean applies(GameEvent event, Ability source, Game game) {
|
||||
if (super.applies(event, source, game) && event instanceof DamagePlayerEvent && event.getAmount() > 0) {
|
||||
DamagePlayerEvent damageEvent = (DamagePlayerEvent) event;
|
||||
if (event.getTargetId().equals(source.getControllerId())) {
|
||||
Permanent permanent = game.getPermanentOrLKIBattlefield(damageEvent.getSourceId());
|
||||
if (permanent != null && filter.match(permanent, game)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -48,7 +48,7 @@ import mage.filter.predicate.mageobject.CardTypePredicate;
|
|||
*/
|
||||
public class HeraldOfThePantheon extends CardImpl {
|
||||
|
||||
private static final FilterCard filter = new FilterCard("enchantment spells");
|
||||
private static final FilterCard filter = new FilterCard("Enchantment spells");
|
||||
private static final FilterSpell filter2 = new FilterSpell("an enchantment spell");
|
||||
|
||||
static {
|
||||
|
|
108
Mage.Sets/src/mage/cards/h/HonorablePassage.java
Normal file
108
Mage.Sets/src/mage/cards/h/HonorablePassage.java
Normal file
|
@ -0,0 +1,108 @@
|
|||
/*
|
||||
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are
|
||||
* permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
* conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
* of conditions and the following disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* The views and conclusions contained in the software and documentation are those of the
|
||||
* authors and should not be interpreted as representing official policies, either expressed
|
||||
* or implied, of BetaSteward_at_googlemail.com.
|
||||
*/
|
||||
package mage.cards.h;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.MageObject;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.Mode;
|
||||
import mage.abilities.effects.PreventionEffectData;
|
||||
import mage.abilities.effects.common.PreventNextDamageFromChosenSourceToTargetEffect;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.Duration;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.players.Player;
|
||||
import mage.target.common.TargetCreatureOrPlayer;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author L_J
|
||||
*/
|
||||
public class HonorablePassage extends CardImpl {
|
||||
|
||||
public HonorablePassage(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{1}{W}");
|
||||
|
||||
// The next time a source of your choice would deal damage to target creature or player this turn, prevent that damage. If damage from a red source is prevented this way, Honorable Passage deals that much damage to the source's controller.
|
||||
this.getSpellAbility().addEffect(new HonorablePassageEffect());
|
||||
this.getSpellAbility().addTarget(new TargetCreatureOrPlayer());
|
||||
}
|
||||
|
||||
public HonorablePassage(final HonorablePassage card) {
|
||||
super(card);
|
||||
}
|
||||
|
||||
@Override
|
||||
public HonorablePassage copy() {
|
||||
return new HonorablePassage(this);
|
||||
}
|
||||
}
|
||||
|
||||
class HonorablePassageEffect extends PreventNextDamageFromChosenSourceToTargetEffect {
|
||||
|
||||
public HonorablePassageEffect() {
|
||||
super(Duration.EndOfTurn);
|
||||
}
|
||||
|
||||
public HonorablePassageEffect(final HonorablePassageEffect effect) {
|
||||
super(effect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public HonorablePassageEffect copy() {
|
||||
return new HonorablePassageEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean replaceEvent(GameEvent event, Ability source, Game game) {
|
||||
int damage = event.getAmount();
|
||||
PreventionEffectData preventEffectData = preventDamageAction(event, source, game);
|
||||
if (preventEffectData.getPreventedDamage() > 0) {
|
||||
MageObject sourceObject = game.getObject(event.getSourceId());
|
||||
if (sourceObject != null && sourceObject.getColor(game).isRed()) {
|
||||
UUID sourceControllerId = game.getControllerId(event.getSourceId());
|
||||
if (sourceControllerId != null) {
|
||||
Player sourceController = game.getPlayer(sourceControllerId);
|
||||
if (sourceController != null) {
|
||||
sourceController.damage(damage, source.getSourceId(), game, false, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
this.used = true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getText(Mode mode) {
|
||||
return "The next time a source of your choice would deal damage to target creature or player this turn, prevent that damage. If damage from a red source is prevented this way, {this} deals that much damage to the source's controller";
|
||||
}
|
||||
}
|
|
@ -41,10 +41,10 @@ import mage.cards.CardImpl;
|
|||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.AsThoughEffectType;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.SubType;
|
||||
import mage.constants.Duration;
|
||||
import mage.constants.ManaType;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.SubType;
|
||||
import mage.constants.Zone;
|
||||
import mage.filter.FilterPermanent;
|
||||
import mage.filter.predicate.Predicates;
|
||||
|
@ -118,8 +118,8 @@ class HostageTakerExileEffect extends OneShotEffect {
|
|||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Permanent card = game.getPermanent(targetPointer.getFirst(game, source));
|
||||
Permanent permanent = game.getPermanent(source.getSourceId());
|
||||
Permanent card = game.getPermanent(getTargetPointer().getFirst(game, source));
|
||||
Permanent permanent = game.getPermanentOrLKIBattlefield(source.getSourceId());
|
||||
if (permanent != null && card != null) {
|
||||
Player controller = game.getPlayer(card.getControllerId());
|
||||
if (controller != null) {
|
||||
|
|
|
@ -104,10 +104,7 @@ class HotSoupTriggeredAbility extends TriggeredAbilityImpl {
|
|||
Permanent equipment = game.getPermanent(this.getSourceId());
|
||||
if (equipment != null && equipment.getAttachedTo() != null) {
|
||||
if (Objects.equals(event.getTargetId(), equipment.getAttachedTo())) {
|
||||
for(Effect effect : this.getEffects())
|
||||
{
|
||||
effect.setTargetPointer(new FixedTarget(equipment.getAttachedTo()));
|
||||
}
|
||||
this.getEffects().setTargetPointer(new FixedTarget(equipment.getAttachedTo(), game));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -118,4 +115,4 @@ class HotSoupTriggeredAbility extends TriggeredAbilityImpl {
|
|||
public String getRule() {
|
||||
return "Whenever equipped creature is dealt damage, " + super.getRule();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,6 +31,7 @@ import java.util.UUID;
|
|||
import mage.MageInt;
|
||||
import mage.MageObject;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.TriggeredAbility;
|
||||
import mage.abilities.common.SimpleStaticAbility;
|
||||
import mage.abilities.effects.ContinuousRuleModifyingEffectImpl;
|
||||
import mage.abilities.keyword.FlashAbility;
|
||||
|
@ -39,9 +40,9 @@ import mage.cards.CardImpl;
|
|||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.AbilityType;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.SubType;
|
||||
import mage.constants.Duration;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.SubType;
|
||||
import mage.constants.Zone;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.EntersTheBattlefieldEvent;
|
||||
|
@ -55,7 +56,7 @@ import mage.game.permanent.Permanent;
|
|||
public class HushwingGryff extends CardImpl {
|
||||
|
||||
public HushwingGryff(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{W}");
|
||||
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{W}");
|
||||
this.subtype.add(SubType.HIPPOGRIFF);
|
||||
|
||||
this.power = new MageInt(2);
|
||||
|
@ -92,10 +93,15 @@ class HushwingGryffEffect extends ContinuousRuleModifyingEffectImpl {
|
|||
|
||||
@Override
|
||||
public String getInfoMessage(Ability source, GameEvent event, Game game) {
|
||||
MageObject mageObject = game.getObject(event.getSourceId());
|
||||
MageObject enteringObject = game.getObject(event.getSourceId());
|
||||
MageObject sourceObject = game.getObject(source.getSourceId());
|
||||
if (mageObject != null && sourceObject != null) {
|
||||
return sourceObject.getLogName() + " prevented ability of " + mageObject.getLogName() + " to trigger";
|
||||
Ability ability = (Ability) getValue("targetAbility");
|
||||
if (enteringObject != null && sourceObject != null && ability != null) {
|
||||
MageObject abilitObject = game.getObject(ability.getSourceId());
|
||||
if (abilitObject != null) {
|
||||
return sourceObject.getLogName() + " prevented ability of " + abilitObject.getLogName()
|
||||
+ " to trigger for " + enteringObject.getLogName() + " entering the battlefield.";
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
@ -111,7 +117,7 @@ class HushwingGryffEffect extends ContinuousRuleModifyingEffectImpl {
|
|||
if (ability != null && ability.getAbilityType() == AbilityType.TRIGGERED) {
|
||||
Permanent permanent = ((EntersTheBattlefieldEvent) event).getTarget();
|
||||
if (permanent != null && permanent.isCreature()) {
|
||||
return true;
|
||||
return (((TriggeredAbility) ability).checkTrigger(event, game));
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
package mage.cards.i;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.MageObject;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.abilities.effects.RestrictionEffect;
|
||||
|
@ -88,7 +89,7 @@ class InterdictPredicate implements Predicate<Ability> {
|
|||
@Override
|
||||
public boolean apply(Ability input, Game game) {
|
||||
if (input instanceof StackAbility && input.getAbilityType() == AbilityType.ACTIVATED) {
|
||||
Permanent sourceObject = game.getPermanentOrLKIBattlefield(input.getSourceId());
|
||||
MageObject sourceObject = input.getSourceObject(game);
|
||||
if (sourceObject != null) {
|
||||
return (sourceObject.isArtifact()
|
||||
|| sourceObject.isEnchantment()
|
||||
|
@ -120,9 +121,12 @@ class InterdictCounterEffect extends OneShotEffect {
|
|||
public boolean apply(Game game, Ability source) {
|
||||
StackObject stackObject = game.getStack().getStackObject(source.getFirstTarget());
|
||||
if (stackObject != null && game.getStack().counter(source.getFirstTarget(), source.getSourceId(), game)) {
|
||||
InterdictCantActivateEffect effect = new InterdictCantActivateEffect();
|
||||
effect.setTargetPointer(new FixedTarget(stackObject.getSourceId()));
|
||||
game.getContinuousEffects().addEffect(effect, source);
|
||||
Permanent sourcePermanent = stackObject.getStackAbility().getSourcePermanentIfItStillExists(game);
|
||||
if (sourcePermanent != null) {
|
||||
InterdictCantActivateEffect effect = new InterdictCantActivateEffect();
|
||||
effect.setTargetPointer(new FixedTarget(sourcePermanent, game));
|
||||
game.getContinuousEffects().addEffect(effect, source);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
@ -143,7 +147,7 @@ class InterdictCantActivateEffect extends RestrictionEffect {
|
|||
|
||||
@Override
|
||||
public boolean applies(Permanent permanent, Ability source, Game game) {
|
||||
return getTargetPointer().getFirst(game, source).equals(permanent.getId());
|
||||
return permanent.getId().equals(getTargetPointer().getFirst(game, source));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -48,7 +48,7 @@ import mage.filter.predicate.mageobject.CardTypePredicate;
|
|||
public class JacesSanctum extends CardImpl {
|
||||
|
||||
|
||||
private static final FilterCard filter = new FilterCard("instant and sorcery spells");
|
||||
private static final FilterCard filter = new FilterCard("Instant and sorcery spells");
|
||||
|
||||
private static final FilterSpell filter2 = new FilterSpell("an instant or sorcery spell");
|
||||
|
||||
|
|
73
Mage.Sets/src/mage/cards/j/JustFate.java
Normal file
73
Mage.Sets/src/mage/cards/j/JustFate.java
Normal file
|
@ -0,0 +1,73 @@
|
|||
/*
|
||||
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are
|
||||
* permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
* conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
* of conditions and the following disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* The views and conclusions contained in the software and documentation are those of the
|
||||
* authors and should not be interpreted as representing official policies, either expressed
|
||||
* or implied, of BetaSteward_at_googlemail.com.
|
||||
*/
|
||||
package mage.cards.j;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.common.CastOnlyDuringPhaseStepSourceAbility;
|
||||
import mage.abilities.condition.common.AttackedThisStepCondition;
|
||||
import mage.abilities.effects.common.DestroyTargetEffect;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.PhaseStep;
|
||||
import mage.constants.TurnPhase;
|
||||
import mage.target.common.TargetAttackingCreature;
|
||||
import mage.watchers.common.PlayerAttackedStepWatcher;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author TheElk801
|
||||
*/
|
||||
public class JustFate extends CardImpl {
|
||||
|
||||
public JustFate(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{W}");
|
||||
|
||||
// Cast Just Fate only during the declare attackers step and only if you've been attacked this step.
|
||||
Ability ability = new CastOnlyDuringPhaseStepSourceAbility(
|
||||
TurnPhase.COMBAT, PhaseStep.DECLARE_ATTACKERS, AttackedThisStepCondition.instance,
|
||||
"Cast {this} only during the declare attackers step and only if you've been attacked this step."
|
||||
);
|
||||
ability.addWatcher(new PlayerAttackedStepWatcher());
|
||||
this.addAbility(ability);
|
||||
|
||||
// Destroy target attacking creature.
|
||||
this.getSpellAbility().addEffect(new DestroyTargetEffect());
|
||||
this.getSpellAbility().addTarget(new TargetAttackingCreature());
|
||||
}
|
||||
|
||||
public JustFate(final JustFate card) {
|
||||
super(card);
|
||||
}
|
||||
|
||||
@Override
|
||||
public JustFate copy() {
|
||||
return new JustFate(this);
|
||||
}
|
||||
}
|
|
@ -16,7 +16,7 @@ public class KaerveksSpite extends CardImpl {
|
|||
super(ownerId, cardSetInfo, new CardType[]{CardType.INSTANT}, "{B}{B}{B}");
|
||||
|
||||
// As an additional cost to cast Kaervek's Spite, sacrifice all permanents you control and discard your hand.
|
||||
this.getSpellAbility().addCost(new SacrificeAllCost(new FilterControlledPermanent("all permanents you control")));
|
||||
this.getSpellAbility().addCost(new SacrificeAllCost(new FilterControlledPermanent("permanents you control")));
|
||||
this.getSpellAbility().addCost(new DiscardHandCost());
|
||||
|
||||
// Target player loses 5 life.
|
||||
|
|
75
Mage.Sets/src/mage/cards/k/KaronasZealot.java
Normal file
75
Mage.Sets/src/mage/cards/k/KaronasZealot.java
Normal file
|
@ -0,0 +1,75 @@
|
|||
/*
|
||||
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are
|
||||
* permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
* conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
* of conditions and the following disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* The views and conclusions contained in the software and documentation are those of the
|
||||
* authors and should not be interpreted as representing official policies, either expressed
|
||||
* or implied, of BetaSteward_at_googlemail.com.
|
||||
*/
|
||||
package mage.cards.k;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.MageInt;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.common.TurnedFaceUpSourceTriggeredAbility;
|
||||
import mage.abilities.costs.mana.ManaCostsImpl;
|
||||
import mage.abilities.effects.common.RedirectDamageFromSourceToTargetEffect;
|
||||
import mage.abilities.keyword.MorphAbility;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.SubType;
|
||||
import mage.constants.Duration;
|
||||
import mage.target.common.TargetCreaturePermanent;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author L_J
|
||||
*/
|
||||
public class KaronasZealot extends CardImpl {
|
||||
|
||||
public KaronasZealot(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{W}");
|
||||
this.subtype.add(SubType.HUMAN);
|
||||
this.subtype.add(SubType.CLERIC);
|
||||
this.power = new MageInt(2);
|
||||
this.toughness = new MageInt(5);
|
||||
|
||||
// Morph {3}{W}{W}
|
||||
this.addAbility(new MorphAbility(this, new ManaCostsImpl("{3}{W}{W}")));
|
||||
|
||||
// When Karona's Zealot is turned face up, all damage that would be dealt to it this turn is dealt to target creature instead.
|
||||
Ability ability = new TurnedFaceUpSourceTriggeredAbility(new RedirectDamageFromSourceToTargetEffect(Duration.EndOfTurn, Integer.MAX_VALUE, false)
|
||||
.setText("all damage that would be dealt to it this turn is dealt to target creature instead"));
|
||||
ability.addTarget(new TargetCreaturePermanent());
|
||||
this.addAbility(ability);
|
||||
}
|
||||
|
||||
public KaronasZealot(final KaronasZealot card) {
|
||||
super(card);
|
||||
}
|
||||
|
||||
@Override
|
||||
public KaronasZealot copy() {
|
||||
return new KaronasZealot(this);
|
||||
}
|
||||
}
|
80
Mage.Sets/src/mage/cards/k/KongmingsContraptions.java
Normal file
80
Mage.Sets/src/mage/cards/k/KongmingsContraptions.java
Normal file
|
@ -0,0 +1,80 @@
|
|||
/*
|
||||
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are
|
||||
* permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
* conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
* of conditions and the following disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* The views and conclusions contained in the software and documentation are those of the
|
||||
* authors and should not be interpreted as representing official policies, either expressed
|
||||
* or implied, of BetaSteward_at_googlemail.com.
|
||||
*/
|
||||
package mage.cards.k;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.MageInt;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.condition.CompoundCondition;
|
||||
import mage.abilities.condition.common.AttackedThisStepCondition;
|
||||
import mage.abilities.condition.common.IsStepCondition;
|
||||
import mage.abilities.costs.common.TapSourceCost;
|
||||
import mage.abilities.decorator.ConditionalActivatedAbility;
|
||||
import mage.abilities.effects.common.DamageTargetEffect;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.SubType;
|
||||
import mage.constants.PhaseStep;
|
||||
import mage.constants.Zone;
|
||||
import mage.filter.common.FilterAttackingCreature;
|
||||
import mage.target.TargetPermanent;
|
||||
import mage.watchers.common.PlayerAttackedStepWatcher;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author L_J
|
||||
*/
|
||||
public class KongmingsContraptions extends CardImpl {
|
||||
|
||||
public KongmingsContraptions(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{W}");
|
||||
this.subtype.add(SubType.HUMAN);
|
||||
this.subtype.add(SubType.SOLDIER);
|
||||
this.power = new MageInt(2);
|
||||
this.toughness = new MageInt(4);
|
||||
|
||||
// {T}: Kongming's Contraptions deals 2 damage to target attacking creature. Activate this ability only during the declare attackers step and only if you've been attacked this step.
|
||||
Ability ability = new ConditionalActivatedAbility(Zone.BATTLEFIELD, new DamageTargetEffect(2), new TapSourceCost(),
|
||||
new CompoundCondition("during the declare attackers step and only if you've been attacked this step",
|
||||
new IsStepCondition(PhaseStep.DECLARE_ATTACKERS, false), AttackedThisStepCondition.instance)
|
||||
);
|
||||
ability.addTarget(new TargetPermanent(new FilterAttackingCreature()));
|
||||
this.addAbility(ability, new PlayerAttackedStepWatcher());
|
||||
}
|
||||
|
||||
public KongmingsContraptions(final KongmingsContraptions card) {
|
||||
super(card);
|
||||
}
|
||||
|
||||
@Override
|
||||
public KongmingsContraptions copy() {
|
||||
return new KongmingsContraptions(this);
|
||||
}
|
||||
|
||||
}
|
|
@ -30,6 +30,7 @@ package mage.cards.k;
|
|||
import java.util.UUID;
|
||||
import mage.MageInt;
|
||||
import mage.abilities.common.SimpleStaticAbility;
|
||||
import mage.abilities.effects.Effect;
|
||||
import mage.abilities.effects.common.cost.SpellsCostReductionControllerEffect;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
|
@ -61,7 +62,9 @@ public class KrosanDrover extends CardImpl {
|
|||
this.toughness = new MageInt(2);
|
||||
|
||||
// Creature spells you cast with converted mana cost 6 or greater cost {2} less to cast.
|
||||
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new SpellsCostReductionControllerEffect(filter, 2)));
|
||||
Effect effect = new SpellsCostReductionControllerEffect(filter, 2);
|
||||
effect.setText("Creature spells you cast with converted mana cost 6 or greater cost {2} less to cast.");
|
||||
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, effect));
|
||||
}
|
||||
|
||||
public KrosanDrover(final KrosanDrover card) {
|
||||
|
|
|
@ -35,7 +35,6 @@ import mage.abilities.common.LeavesBattlefieldTriggeredAbility;
|
|||
import mage.abilities.common.SimpleActivatedAbility;
|
||||
import mage.abilities.costs.AdjustingSourceCosts;
|
||||
import mage.abilities.costs.mana.ManaCostsImpl;
|
||||
import mage.abilities.effects.Effect;
|
||||
import mage.abilities.effects.common.GainLifeTargetEffect;
|
||||
import mage.abilities.effects.common.LoseLifeTargetEffect;
|
||||
import mage.abilities.effects.common.RegenerateSourceEffect;
|
||||
|
@ -58,7 +57,7 @@ import mage.util.CardUtil;
|
|||
public class LaquatussChampion extends CardImpl {
|
||||
|
||||
public LaquatussChampion(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{4}{B}{B}");
|
||||
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{B}{B}");
|
||||
this.subtype.add(SubType.NIGHTMARE);
|
||||
this.subtype.add(SubType.HORROR);
|
||||
|
||||
|
@ -126,9 +125,7 @@ class LaquatussChampionLeavesBattlefieldTriggeredAbility extends LeavesBattlefie
|
|||
String key = CardUtil.getCardZoneString("targetPlayer", this.getSourceId(), game, true);
|
||||
Object object = game.getState().getValue(key);
|
||||
if (object instanceof UUID) {
|
||||
for (Effect effect : this.getEffects()) {
|
||||
effect.setTargetPointer(new FixedTarget((UUID) object));
|
||||
}
|
||||
this.getEffects().setTargetPointer(new FixedTarget((UUID) object));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -118,7 +118,7 @@ class LeviathanCostToAttackBlockEffect extends PayCostToAttackBlockEffectImpl {
|
|||
LeviathanCostToAttackBlockEffect() {
|
||||
super(Duration.WhileOnBattlefield, Outcome.Detriment, RestrictType.ATTACK,
|
||||
new SacrificeTargetCost(new TargetControlledPermanent(2, 2, filter, false)));
|
||||
staticText = "{this} can't attack unless you sacrifice two Islands <i>(This cost is paid as attackers are declared.)</i>";
|
||||
staticText = "{this} can't attack unless you sacrifice two Islands. <i>(This cost is paid as attackers are declared.)</i>";
|
||||
}
|
||||
|
||||
LeviathanCostToAttackBlockEffect(LeviathanCostToAttackBlockEffect effect) {
|
||||
|
|
|
@ -47,7 +47,7 @@ import mage.target.common.TargetCreaturePermanent;
|
|||
|
||||
public class LyevDecree extends CardImpl {
|
||||
|
||||
private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creatures your opponent controls");
|
||||
private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creatures your opponents control");
|
||||
static {
|
||||
filter.add(new ControllerPredicate(TargetController.OPPONENT));
|
||||
}
|
||||
|
@ -56,7 +56,7 @@ public class LyevDecree extends CardImpl {
|
|||
super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{1}{W}");
|
||||
|
||||
|
||||
// Detain up to two target creatures your opponent controls.
|
||||
// Detain up to two target creatures your opponents control.
|
||||
this.getSpellAbility().addEffect(new DetainTargetEffect());
|
||||
Target target = new TargetCreaturePermanent(0,2,filter,false);
|
||||
this.getSpellAbility().addTarget(target);
|
||||
|
|
|
@ -44,7 +44,7 @@ import mage.filter.predicate.mageobject.CardTypePredicate;
|
|||
*/
|
||||
public class ManaMatrix extends CardImpl {
|
||||
|
||||
private static final FilterCard filter = new FilterCard("instant and enchantment spells");
|
||||
private static final FilterCard filter = new FilterCard("Instant and enchantment spells");
|
||||
|
||||
static {
|
||||
filter.add(Predicates.or(
|
||||
|
|
112
Mage.Sets/src/mage/cards/m/MercadiasDownfall.java
Normal file
112
Mage.Sets/src/mage/cards/m/MercadiasDownfall.java
Normal file
|
@ -0,0 +1,112 @@
|
|||
/*
|
||||
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are
|
||||
* permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
* conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
* of conditions and the following disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* The views and conclusions contained in the software and documentation are those of the
|
||||
* authors and should not be interpreted as representing official policies, either expressed
|
||||
* or implied, of BetaSteward_at_googlemail.com.
|
||||
*/
|
||||
package mage.cards.m;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.dynamicvalue.DynamicValue;
|
||||
import mage.abilities.dynamicvalue.common.StaticValue;
|
||||
import mage.abilities.effects.Effect;
|
||||
import mage.abilities.effects.common.continuous.BoostAllEffect;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.Duration;
|
||||
import mage.constants.SuperType;
|
||||
import mage.filter.common.FilterAttackingCreature;
|
||||
import mage.filter.common.FilterLandPermanent;
|
||||
import mage.filter.predicate.Predicates;
|
||||
import mage.filter.predicate.mageobject.SupertypePredicate;
|
||||
import mage.game.Game;
|
||||
import mage.game.combat.CombatGroup;
|
||||
import mage.game.permanent.Permanent;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author jeffwadsworth
|
||||
*/
|
||||
public class MercadiasDownfall extends CardImpl {
|
||||
|
||||
private static String rule = "Each attacking creature gets +1/+0 until end of turn for each nonbasic land defending player controls";
|
||||
|
||||
public MercadiasDownfall(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{R}");
|
||||
|
||||
// Each attacking creature gets +1/+0 until end of turn for each nonbasic land defending player controls.
|
||||
this.getSpellAbility().addEffect(new BoostAllEffect(new DefendersNonBasicLandCount(), new StaticValue(0), Duration.EndOfTurn, new FilterAttackingCreature(), true, rule));
|
||||
|
||||
}
|
||||
|
||||
public MercadiasDownfall(final MercadiasDownfall card) {
|
||||
super(card);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MercadiasDownfall copy() {
|
||||
return new MercadiasDownfall(this);
|
||||
}
|
||||
|
||||
class DefendersNonBasicLandCount implements DynamicValue {
|
||||
|
||||
UUID defenderId;
|
||||
|
||||
@Override
|
||||
public int calculate(Game game, Ability sourceAbility, Effect effect) {
|
||||
for (CombatGroup group : game.getCombat().getGroups()) {
|
||||
defenderId = group.getDefenderId();
|
||||
if (group.isDefenderIsPlaneswalker()) {
|
||||
Permanent permanent = game.getPermanent(defenderId);
|
||||
if (permanent != null) {
|
||||
defenderId = permanent.getControllerId();
|
||||
}
|
||||
}
|
||||
FilterLandPermanent filter = new FilterLandPermanent("nonbasic land");
|
||||
filter.add(Predicates.not(new SupertypePredicate(SuperType.BASIC)));
|
||||
System.out.println("The number of nonbasic lands is " + game.getBattlefield().countAll(filter, defenderId, game));
|
||||
return game.getBattlefield().countAll(filter, defenderId, game);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DynamicValue copy() {
|
||||
return new DefendersNonBasicLandCount();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "X";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMessage() {
|
||||
return "the number of nonbasic lands defending player controls";
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -50,10 +50,10 @@ public class MerfolkRaiders extends CardImpl {
|
|||
this.power = new MageInt(2);
|
||||
this.toughness = new MageInt(3);
|
||||
|
||||
// Phasing
|
||||
this.addAbility(PhasingAbility.getInstance());
|
||||
// Islandwalk
|
||||
this.addAbility(new IslandwalkAbility());
|
||||
// Phasing
|
||||
this.addAbility(PhasingAbility.getInstance());
|
||||
}
|
||||
|
||||
public MerfolkRaiders(final MerfolkRaiders card) {
|
||||
|
|
|
@ -49,7 +49,7 @@ import mage.filter.predicate.mageobject.SubtypePredicate;
|
|||
*/
|
||||
public class MilitantInquisitor extends CardImpl {
|
||||
|
||||
private static final FilterControlledPermanent filter = new FilterControlledPermanent("equipment you control");
|
||||
private static final FilterControlledPermanent filter = new FilterControlledPermanent("Equipment you control");
|
||||
|
||||
static {
|
||||
filter.add(new CardTypePredicate(CardType.ARTIFACT));
|
||||
|
|
|
@ -105,7 +105,7 @@ class MinionOfTheWastesEffect extends OneShotEffect {
|
|||
controller.loseLife(payAmount, game, false);
|
||||
game.informPlayers(new StringBuilder(sourceCard.getLogName()).append(": ").append(controller.getLogName())
|
||||
.append(" pays ").append(payAmount).append(" life").toString());
|
||||
game.addEffect(new SetPowerToughnessSourceEffect(payAmount, payAmount, Duration.WhileOnBattlefield, SubLayer.SetPT_7b), source);
|
||||
game.addEffect(new SetPowerToughnessSourceEffect(payAmount, payAmount, Duration.Custom, SubLayer.SetPT_7b), source);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
|
99
Mage.Sets/src/mage/cards/m/MoralityShift.java
Normal file
99
Mage.Sets/src/mage/cards/m/MoralityShift.java
Normal file
|
@ -0,0 +1,99 @@
|
|||
/*
|
||||
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are
|
||||
* permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
* conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
* of conditions and the following disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* The views and conclusions contained in the software and documentation are those of the
|
||||
* authors and should not be interpreted as representing official policies, either expressed
|
||||
* or implied, of BetaSteward_at_googlemail.com.
|
||||
*/
|
||||
package mage.cards.m;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.cards.Card;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.Outcome;
|
||||
import mage.game.Game;
|
||||
import mage.players.Player;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author jeffwadsworth
|
||||
*/
|
||||
public class MoralityShift extends CardImpl {
|
||||
|
||||
public MoralityShift(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{5}{B}{B}");
|
||||
|
||||
|
||||
// Exchange your graveyard and library. Then shuffle your library.
|
||||
this.getSpellAbility().addEffect(new MoralityShiftEffect());
|
||||
|
||||
}
|
||||
|
||||
public MoralityShift(final MoralityShift card) {
|
||||
super(card);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MoralityShift copy() {
|
||||
return new MoralityShift(this);
|
||||
}
|
||||
}
|
||||
|
||||
class MoralityShiftEffect extends OneShotEffect {
|
||||
|
||||
MoralityShiftEffect() {
|
||||
super(Outcome.AIDontUseIt);
|
||||
staticText = "Exchange your graveyard and library. Then shuffle your library.";
|
||||
}
|
||||
|
||||
MoralityShiftEffect(MoralityShiftEffect effect) {
|
||||
super(effect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MoralityShiftEffect copy() {
|
||||
return new MoralityShiftEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Player controller = game.getPlayer(source.getControllerId());
|
||||
if (controller != null) {
|
||||
List<Card> copyLibrary = controller.getLibrary().getCards(game);
|
||||
Set<Card> copyGraveyard = controller.getGraveyard().getCards(game);
|
||||
controller.getLibrary().clear();
|
||||
controller.getGraveyard().clear();
|
||||
controller.getGraveyard().addAll(copyLibrary);
|
||||
controller.getLibrary().addAll(copyGraveyard, game);
|
||||
controller.shuffleLibrary(source, game);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
70
Mage.Sets/src/mage/cards/m/MoxLotus.java
Normal file
70
Mage.Sets/src/mage/cards/m/MoxLotus.java
Normal file
|
@ -0,0 +1,70 @@
|
|||
/*
|
||||
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are
|
||||
* permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
* conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
* of conditions and the following disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* The views and conclusions contained in the software and documentation are those of the
|
||||
* authors and should not be interpreted as representing official policies, either expressed
|
||||
* or implied, of BetaSteward_at_googlemail.com.
|
||||
*/
|
||||
package mage.cards.m;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.Mana;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.costs.common.TapSourceCost;
|
||||
import mage.abilities.costs.mana.ManaCostsImpl;
|
||||
import mage.abilities.effects.common.AddManaOfAnyColorEffect;
|
||||
import mage.abilities.mana.SimpleManaAbility;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.Zone;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author spjspj/psjpsj
|
||||
*/
|
||||
public class MoxLotus extends CardImpl {
|
||||
|
||||
public MoxLotus(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{15}");
|
||||
|
||||
// {t}: Add infinity (or 1*10^9 to account for a potential mana reflection) to your mana pool.
|
||||
this.addAbility(new SimpleManaAbility(Zone.BATTLEFIELD, Mana.ColorlessMana(1000000000), new TapSourceCost()));
|
||||
|
||||
// {100}: Add one mana of any color to your mana pool.
|
||||
Ability ability = new SimpleManaAbility(Zone.BATTLEFIELD, new AddManaOfAnyColorEffect(1), new ManaCostsImpl("{100}"));
|
||||
this.addAbility(ability);
|
||||
|
||||
// You don't lose life due to mana burn.
|
||||
// Situation normal??
|
||||
}
|
||||
|
||||
public MoxLotus(final MoxLotus card) {
|
||||
super(card);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MoxLotus copy() {
|
||||
return new MoxLotus(this);
|
||||
}
|
||||
}
|
|
@ -128,7 +128,7 @@ class NamelessRaceEffect extends OneShotEffect {
|
|||
controller.loseLife(payAmount, game, false);
|
||||
game.informPlayers(new StringBuilder(sourceCard.getLogName()).append(": ").append(controller.getLogName())
|
||||
.append(" pays ").append(payAmount).append(" life").toString());
|
||||
game.addEffect(new SetPowerToughnessSourceEffect(payAmount, payAmount, Duration.WhileOnBattlefield, SubLayer.SetPT_7b), source);
|
||||
game.addEffect(new SetPowerToughnessSourceEffect(payAmount, payAmount, Duration.Custom, SubLayer.SetPT_7b), source);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
|
|
@ -51,18 +51,23 @@ import mage.target.common.TargetCreatureOrPlayer;
|
|||
public class NivMizzetTheFiremind extends CardImpl {
|
||||
|
||||
public NivMizzetTheFiremind(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{U}{U}{R}{R}");
|
||||
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{U}{U}{R}{R}");
|
||||
addSuperType(SuperType.LEGENDARY);
|
||||
this.subtype.add(SubType.DRAGON);
|
||||
this.subtype.add(SubType.WIZARD);
|
||||
|
||||
|
||||
this.power = new MageInt(4);
|
||||
this.toughness = new MageInt(4);
|
||||
|
||||
// Flying
|
||||
this.addAbility(FlyingAbility.getInstance());
|
||||
|
||||
// Whenever you draw a card, Niv-Mizzet, the Firemind deals 1 damage to target creature or player.
|
||||
Ability ability = new DrawCardControllerTriggeredAbility(new DamageTargetEffect(1), false);
|
||||
ability.addTarget(new TargetCreatureOrPlayer());
|
||||
this.addAbility(ability);
|
||||
|
||||
// {T}: Draw a card.
|
||||
this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new DrawCardSourceControllerEffect(1), new TapSourceCost()));
|
||||
}
|
||||
|
||||
|
|
|
@ -29,7 +29,6 @@ package mage.cards.n;
|
|||
|
||||
import java.util.UUID;
|
||||
import mage.abilities.TriggeredAbilityImpl;
|
||||
import mage.abilities.effects.Effect;
|
||||
import mage.abilities.effects.common.DestroyTargetEffect;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
|
@ -48,7 +47,7 @@ import mage.target.targetpointer.FixedTarget;
|
|||
public class NoMercy extends CardImpl {
|
||||
|
||||
public NoMercy(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{2}{B}{B}");
|
||||
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{B}{B}");
|
||||
|
||||
// Whenever a creature deals damage to you, destroy it.
|
||||
this.addAbility(new NoMercyTriggeredAbility());
|
||||
|
@ -88,9 +87,7 @@ public class NoMercy extends CardImpl {
|
|||
if (event.getPlayerId().equals(this.getControllerId())) {
|
||||
Permanent permanent = game.getPermanent(event.getSourceId());
|
||||
if (permanent != null && permanent.isCreature()) {
|
||||
for (Effect effect : this.getEffects()) {
|
||||
effect.setTargetPointer(new FixedTarget(event.getSourceId()));
|
||||
}
|
||||
this.getEffects().setTargetPointer(new FixedTarget(permanent, game));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
94
Mage.Sets/src/mage/cards/o/OrimsPrayer.java
Normal file
94
Mage.Sets/src/mage/cards/o/OrimsPrayer.java
Normal file
|
@ -0,0 +1,94 @@
|
|||
/*
|
||||
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are
|
||||
* permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
* conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
* of conditions and the following disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* The views and conclusions contained in the software and documentation are those of the
|
||||
* authors and should not be interpreted as representing official policies, either expressed
|
||||
* or implied, of BetaSteward_at_googlemail.com.
|
||||
*/
|
||||
package mage.cards.o;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.abilities.TriggeredAbilityImpl;
|
||||
import mage.abilities.dynamicvalue.common.AttackingCreatureCount;
|
||||
import mage.abilities.effects.common.GainLifeEffect;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.Zone;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.game.events.GameEvent.EventType;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author L_J
|
||||
*/
|
||||
public class OrimsPrayer extends CardImpl {
|
||||
|
||||
public OrimsPrayer(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{W}{W}");
|
||||
|
||||
// Whenever one or more creatures attack you, you gain 1 life for each attacking creature.
|
||||
this.addAbility(new OrimsPrayerTriggeredAbility());
|
||||
}
|
||||
|
||||
public OrimsPrayer(final OrimsPrayer card) {
|
||||
super(card);
|
||||
}
|
||||
|
||||
@Override
|
||||
public OrimsPrayer copy() {
|
||||
return new OrimsPrayer(this);
|
||||
}
|
||||
}
|
||||
|
||||
class OrimsPrayerTriggeredAbility extends TriggeredAbilityImpl {
|
||||
|
||||
public OrimsPrayerTriggeredAbility() {
|
||||
super(Zone.BATTLEFIELD, new GainLifeEffect(new AttackingCreatureCount()));
|
||||
}
|
||||
|
||||
public OrimsPrayerTriggeredAbility(final OrimsPrayerTriggeredAbility ability) {
|
||||
super(ability);
|
||||
}
|
||||
|
||||
@Override
|
||||
public OrimsPrayerTriggeredAbility copy() {
|
||||
return new OrimsPrayerTriggeredAbility(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkEventType(GameEvent event, Game game) {
|
||||
return event.getType() == EventType.DECLARED_ATTACKERS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkTrigger(GameEvent event, Game game) {
|
||||
return game.getCombat().getDefenders().contains(getControllerId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRule() {
|
||||
return "Whenever one or more creatures attack you, " + super.getRule();
|
||||
}
|
||||
}
|
|
@ -107,11 +107,11 @@ class PandemoniumEffect extends OneShotEffect {
|
|||
if (enteringCreature != null) {
|
||||
Permanent targetPermanent = game.getPermanent(source.getTargets().getFirstTarget());
|
||||
if (targetPermanent != null) {
|
||||
targetPermanent.damage(enteringCreature.getPower().getValue(), source.getSourceId(), game, false, true);
|
||||
targetPermanent.damage(enteringCreature.getPower().getValue(), enteringCreature.getId(), game, false, true);
|
||||
} else {
|
||||
Player targetPlayer = game.getPlayer(source.getTargets().getFirstTarget());
|
||||
if (targetPlayer != null) {
|
||||
targetPlayer.damage(enteringCreature.getPower().getValue(), source.getSourceId(), game, false, true);
|
||||
targetPlayer.damage(enteringCreature.getPower().getValue(), enteringCreature.getId(), game, false, true);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
|
181
Mage.Sets/src/mage/cards/p/ParallelThoughts.java
Normal file
181
Mage.Sets/src/mage/cards/p/ParallelThoughts.java
Normal file
|
@ -0,0 +1,181 @@
|
|||
/*
|
||||
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are
|
||||
* permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
* conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
* of conditions and the following disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* The views and conclusions contained in the software and documentation are those of the
|
||||
* authors and should not be interpreted as representing official policies, either expressed
|
||||
* or implied, of BetaSteward_at_googlemail.com.
|
||||
*/
|
||||
package mage.cards.p;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.UUID;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
|
||||
import mage.abilities.common.SimpleStaticAbility;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.abilities.effects.ReplacementEffectImpl;
|
||||
import mage.cards.Card;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.cards.Cards;
|
||||
import mage.cards.CardsImpl;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.Duration;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.Zone;
|
||||
import mage.filter.FilterCard;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.game.events.GameEvent.EventType;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.players.Player;
|
||||
import mage.target.common.TargetCardInLibrary;
|
||||
import mage.util.CardUtil;
|
||||
import mage.util.RandomUtil;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author jeffwadsworth
|
||||
*/
|
||||
public class ParallelThoughts extends CardImpl {
|
||||
|
||||
public ParallelThoughts(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{3}{U}{U}");
|
||||
|
||||
// When Parallel Thoughts enters the battlefield, search your library for seven cards, exile them in a face-down pile, and shuffle that pile. Then shuffle your library.
|
||||
this.addAbility(new EntersBattlefieldTriggeredAbility(new ParallelThoughtsSearchEffect()));
|
||||
|
||||
// If you would draw a card, you may instead put the top card of the pile you exiled into your hand.
|
||||
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new ParallelThoughtsReplacementEffect()));
|
||||
|
||||
}
|
||||
|
||||
public ParallelThoughts(final ParallelThoughts card) {
|
||||
super(card);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ParallelThoughts copy() {
|
||||
return new ParallelThoughts(this);
|
||||
}
|
||||
}
|
||||
|
||||
class ParallelThoughtsSearchEffect extends OneShotEffect {
|
||||
|
||||
ParallelThoughtsSearchEffect() {
|
||||
super(Outcome.Neutral);
|
||||
this.staticText = "search your library for seven cards, exile them in a face-down pile, and shuffle that pile. Then shuffle your library";
|
||||
}
|
||||
|
||||
ParallelThoughtsSearchEffect(final ParallelThoughtsSearchEffect effect) {
|
||||
super(effect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ParallelThoughtsSearchEffect copy() {
|
||||
return new ParallelThoughtsSearchEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Player controller = game.getPlayer(source.getControllerId());
|
||||
Permanent permanent = game.getPermanentOrLKIBattlefield(source.getSourceId());
|
||||
Cards cardsInExilePile = new CardsImpl();
|
||||
if (controller != null
|
||||
&& permanent != null) {
|
||||
TargetCardInLibrary target = new TargetCardInLibrary(7, new FilterCard());
|
||||
if (controller.searchLibrary(target, game)) {
|
||||
for (UUID targetId : target.getTargets()) {
|
||||
Card card = controller.getLibrary().getCard(targetId, game);
|
||||
if (card != null) {
|
||||
cardsInExilePile.add(card);
|
||||
}
|
||||
}
|
||||
// shuffle that exiled pile
|
||||
|
||||
UUID[] shuffled = cardsInExilePile.toArray(new UUID[0]);
|
||||
for (int n = shuffled.length - 1; n > 0; n--) {
|
||||
int r = RandomUtil.nextInt(n + 1);
|
||||
UUID temp = shuffled[n];
|
||||
shuffled[n] = shuffled[r];
|
||||
shuffled[r] = temp;
|
||||
}
|
||||
cardsInExilePile.clear();
|
||||
cardsInExilePile.addAll(Arrays.asList(shuffled));
|
||||
|
||||
// move to exile zone and turn face down
|
||||
|
||||
for (Card card : cardsInExilePile.getCards(game)) {
|
||||
controller.moveCardsToExile(card, source, game, false, CardUtil.getCardExileZoneId(game, source), permanent.getLogName());
|
||||
card.setFaceDown(true, game);
|
||||
}
|
||||
|
||||
// shuffle controller library
|
||||
|
||||
controller.shuffleLibrary(source, game);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
class ParallelThoughtsReplacementEffect extends ReplacementEffectImpl {
|
||||
|
||||
ParallelThoughtsReplacementEffect() {
|
||||
super(Duration.WhileOnBattlefield, Outcome.DrawCard);
|
||||
staticText = "If you would draw a card, you may instead put the top card of the pile you exiled with Parallel Thoughts into your hand";
|
||||
}
|
||||
|
||||
ParallelThoughtsReplacementEffect(final ParallelThoughtsReplacementEffect effect) {
|
||||
super(effect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ParallelThoughtsReplacementEffect copy() {
|
||||
return new ParallelThoughtsReplacementEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean replaceEvent(GameEvent event, Ability source, Game game) {
|
||||
Player controller = game.getPlayer(source.getControllerId());
|
||||
if (controller != null
|
||||
&& !game.getExile().getExileZone(CardUtil.getCardExileZoneId(game, source)).getCards(game).isEmpty()) {
|
||||
Card card = game.getExile().getExileZone(CardUtil.getCardExileZoneId(game, source)).getCards(game).iterator().next();
|
||||
if (card != null) {
|
||||
controller.moveCards(card, Zone.HAND, source, game);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checksEventType(GameEvent event, Game game) {
|
||||
return event.getType() == EventType.DRAW_CARD;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean applies(GameEvent event, Ability source, Game game) {
|
||||
return source.getControllerId().equals(event.getPlayerId());
|
||||
}
|
||||
}
|
115
Mage.Sets/src/mage/cards/p/Penance.java
Normal file
115
Mage.Sets/src/mage/cards/p/Penance.java
Normal file
|
@ -0,0 +1,115 @@
|
|||
/*
|
||||
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are
|
||||
* permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
* conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
* of conditions and the following disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* The views and conclusions contained in the software and documentation are those of the
|
||||
* authors and should not be interpreted as representing official policies, either expressed
|
||||
* or implied, of BetaSteward_at_googlemail.com.
|
||||
*/
|
||||
package mage.cards.p;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.ObjectColor;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.common.SimpleActivatedAbility;
|
||||
import mage.abilities.costs.common.PutCardFromHandOnTopOfLibraryCost;
|
||||
import mage.abilities.effects.PreventionEffectImpl;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.Duration;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.Zone;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.target.TargetSource;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author jeffwadsworth
|
||||
*/
|
||||
public class Penance extends CardImpl {
|
||||
|
||||
public Penance(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{W}");
|
||||
|
||||
// Put a card from your hand on top of your library: The next time a black or red source of your choice would deal damage this turn, prevent that damage.
|
||||
this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new PenanceEffect(), new PutCardFromHandOnTopOfLibraryCost()));
|
||||
|
||||
}
|
||||
|
||||
public Penance(final Penance card) {
|
||||
super(card);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Penance copy() {
|
||||
return new Penance(this);
|
||||
}
|
||||
}
|
||||
|
||||
class PenanceEffect extends PreventionEffectImpl {
|
||||
|
||||
private final TargetSource target;
|
||||
|
||||
public PenanceEffect() {
|
||||
super(Duration.EndOfTurn, Integer.MAX_VALUE, false, false);
|
||||
this.staticText = "The next time a black or red source of your choice would deal damage to you this turn, prevent that damage.";
|
||||
this.target = new TargetSource();
|
||||
}
|
||||
|
||||
public PenanceEffect(final PenanceEffect effect) {
|
||||
super(effect);
|
||||
this.target = effect.target.copy();
|
||||
}
|
||||
|
||||
@Override
|
||||
public PenanceEffect copy() {
|
||||
return new PenanceEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(Ability source, Game game) {
|
||||
this.target.choose(Outcome.PreventDamage, source.getControllerId(), source.getSourceId(), game);
|
||||
super.init(source, game);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean replaceEvent(GameEvent event, Ability source, Game game) {
|
||||
this.used = true;
|
||||
this.discard(); // only one use
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean applies(GameEvent event, Ability source, Game game) {
|
||||
if (!this.used
|
||||
&& super.applies(event, source, game)) {
|
||||
if (event.getTargetId().equals(source.getControllerId())
|
||||
&& event.getSourceId().equals(target.getFirstTarget())) {
|
||||
return (game.getObject(target.getFirstTarget()).getColor(game).contains(ObjectColor.BLACK)
|
||||
|| game.getObject(target.getFirstTarget()).getColor(game).contains(ObjectColor.RED));
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -46,7 +46,7 @@ public class PlanarGate extends CardImpl {
|
|||
super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{6}");
|
||||
|
||||
// Creature spells you cast cost up to {2} less to cast.
|
||||
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new SpellsCostReductionControllerEffect(new FilterCreatureCard("creature spells"), 2, true)));
|
||||
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new SpellsCostReductionControllerEffect(new FilterCreatureCard("Creature spells"), 2, true)));
|
||||
}
|
||||
|
||||
public PlanarGate(final PlanarGate card) {
|
||||
|
|
|
@ -93,11 +93,6 @@ class ProgenitusProtectionAbility extends ProtectionAbility {
|
|||
return new ProgenitusProtectionAbility(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRule() {
|
||||
return "Protection from everything";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canTarget(MageObject source, Game game) {
|
||||
return false;
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue