1
0
Fork 0
mirror of https://github.com/correl/mage.git synced 2025-04-14 09:09:38 -09:00

Merge origin/master

This commit is contained in:
LevelX2 2018-01-02 23:48:27 +01:00
commit 02f6ce7639
67 changed files with 3282 additions and 278 deletions
Mage.Client/src
Mage.Sets/src/mage
Mage/src/main/java/mage
Utils

View file

@ -50,6 +50,7 @@ import mage.client.chat.ChatPanelBasic;
import mage.client.components.*;
import mage.client.components.ext.dlg.DialogManager;
import mage.client.components.tray.MageTray;
import mage.client.constants.Constants;
import mage.client.constants.Constants.DeckEditorMode;
import mage.client.deckeditor.DeckEditorPane;
import mage.client.deckeditor.collection.viewer.CollectionViewerPane;
@ -92,8 +93,6 @@ import org.mage.plugins.card.images.DownloadPictures;
import org.mage.plugins.card.info.CardInfoPaneImpl;
import org.mage.plugins.card.utils.impl.ImageManagerImpl;
import static org.mage.plugins.card.utils.CardImageUtils.getImagesDir;
/**
* @author BetaSteward_at_googlemail.com
*/
@ -239,10 +238,10 @@ public class MageFrame extends javax.swing.JFrame implements MageClient {
SessionHandler.startSession(this);
callbackClient = new CallbackClientImpl(this);
connectDialog = new ConnectDialog();
desktopPane.add(connectDialog, JLayeredPane.POPUP_LAYER);
desktopPane.add(connectDialog, JLayeredPane.MODAL_LAYER);
errorDialog = new ErrorDialog();
errorDialog.setLocation(100, 100);
desktopPane.add(errorDialog, JLayeredPane.POPUP_LAYER);
desktopPane.add(errorDialog, JLayeredPane.MODAL_LAYER);
UI.addComponent(MageComponents.DESKTOP_PANE, desktopPane);
PING_TASK_EXECUTOR.scheduleAtFixedRate(() -> SessionHandler.ping(), 60, 60, TimeUnit.SECONDS);
@ -285,6 +284,9 @@ public class MageFrame extends javax.swing.JFrame implements MageClient {
balloonTip.setPositioner(new LeftAbovePositioner(0, 0));
balloonTip.setVisible(false);
// tooltips delay in ms
ToolTipManager.sharedInstance().setDismissDelay(Constants.TOOLTIPS_DELAY_MS);
mageToolbar.add(createSwitchPanelsButton(), 0);
mageToolbar.add(new javax.swing.JToolBar.Separator(), 1);
@ -429,16 +431,21 @@ public class MageFrame extends javax.swing.JFrame implements MageClient {
}
}
private boolean isChrismasTime(){
public static boolean isChrismasTime(Date currentTime){
// from december 15 to january 15
Calendar cal = Calendar.getInstance();
Calendar cal = new GregorianCalendar();
cal.setTime(currentTime);
int currentYear = cal.get(Calendar.YEAR);
Date currentTime = cal.getTime();
if (cal.get(Calendar.MONTH) == Calendar.JANUARY){
currentYear = currentYear - 1;
}
Date chrisFrom = new GregorianCalendar(currentYear, Calendar.DECEMBER, 15).getTime();
Date chrisTo = new GregorianCalendar(currentYear + 1, Calendar.JANUARY, 15 + 1).getTime();
Date chrisTo = new GregorianCalendar(currentYear + 1, Calendar.JANUARY, 15 + 1).getTime(); // end of the 15 day
return currentTime.after(chrisFrom) && currentTime.before(chrisTo);
return ((currentTime.equals(chrisFrom) || currentTime.after(chrisFrom))
&& currentTime.before(chrisTo));
}
private void addMageLabel() {
@ -448,7 +455,7 @@ public class MageFrame extends javax.swing.JFrame implements MageClient {
String filename;
float ratio;
if (isChrismasTime()){
if (isChrismasTime(Calendar.getInstance().getTime())){
// chrismass logo
LOGGER.info("Yo Ho Ho, Merry Christmas and a Happy New Year");
filename = "/label-xmage-christmas.png";
@ -945,7 +952,7 @@ public class MageFrame extends javax.swing.JFrame implements MageClient {
}//GEN-LAST:event_btnConnectActionPerformed
public void btnAboutActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnAboutActionPerformed
JInternalFrame[] windows = desktopPane.getAllFramesInLayer(JLayeredPane.POPUP_LAYER);
JInternalFrame[] windows = desktopPane.getAllFramesInLayer(JLayeredPane.MODAL_LAYER);
for (JInternalFrame window : windows) {
if (window instanceof AboutDialog) {
// don't open the window twice.
@ -953,7 +960,7 @@ public class MageFrame extends javax.swing.JFrame implements MageClient {
}
}
AboutDialog aboutDialog = new AboutDialog();
desktopPane.add(aboutDialog, JLayeredPane.POPUP_LAYER);
desktopPane.add(aboutDialog, JLayeredPane.MODAL_LAYER);
aboutDialog.showDialog(VERSION);
}//GEN-LAST:event_btnAboutActionPerformed
@ -1096,7 +1103,7 @@ public class MageFrame extends javax.swing.JFrame implements MageClient {
public void showUserRequestDialog(final UserRequestMessage userRequestMessage) {
final UserRequestDialog userRequestDialog = new UserRequestDialog();
userRequestDialog.setLocation(100, 100);
desktopPane.add(userRequestDialog, JLayeredPane.POPUP_LAYER);
desktopPane.add(userRequestDialog, JLayeredPane.MODAL_LAYER);
if (SwingUtilities.isEventDispatchThread()) {
userRequestDialog.showDialog(userRequestMessage);
} else {

View file

@ -69,6 +69,9 @@ public final class Constants {
public static final int POWBOX_TEXT_MAX_LEFT = 212;
public static final int DAMAGE_MAX_LEFT = 180;
// tooltip hints delay in ms (need more time to display long hints withour hiding)
public static final int TOOLTIPS_DELAY_MS = 60 * 1000;
public static final Border EMPTY_BORDER = BorderFactory.createEmptyBorder(2, 2, 2, 2);
public static final double SCALE_FACTOR = 0.5;

View file

@ -500,6 +500,109 @@
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="jToggleCardViewActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JToolBar$Separator" name="jSeparator5">
</Component>
<Container class="javax.swing.JToolBar" name="tbRarities">
<Properties>
<Property name="floatable" type="boolean" value="false"/>
<Property name="rollover" type="boolean" value="true"/>
<Property name="toolTipText" type="java.lang.String" value="Hold the ALT-key while clicking to deselect all other card rarities or hold the CTRL-key to only select all other card rarities."/>
</Properties>
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignBoxLayout"/>
<SubComponents>
<Component class="javax.swing.JToggleButton" name="tbCommon">
<Properties>
<Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
<Image iconType="3" name="/buttons/rarity_common_20.png"/>
</Property>
<Property name="selected" type="boolean" value="true"/>
<Property name="toolTipText" type="java.lang.String" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
<Connection code="&quot;&lt;html&gt;&lt;strong&gt;Common&lt;/strong&gt;&lt;br/&gt;&quot; &#xd;&#xa;+ tbRarities.getToolTipText()" type="code"/>
</Property>
<Property name="actionCommand" type="java.lang.String" value="Common"/>
<Property name="focusable" type="boolean" value="false"/>
<Property name="horizontalTextPosition" type="int" value="0"/>
<Property name="verticalTextPosition" type="int" value="3"/>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="tbCommonActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JToggleButton" name="tbUncommon">
<Properties>
<Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
<Image iconType="3" name="/buttons/rarity_uncommon_20.png"/>
</Property>
<Property name="selected" type="boolean" value="true"/>
<Property name="toolTipText" type="java.lang.String" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
<Connection code="&quot;&lt;html&gt;&lt;strong&gt;Uncommon&lt;/strong&gt;&lt;br/&gt;&quot; &#xd;&#xa;+ tbUncommon.getToolTipText()" type="code"/>
</Property>
<Property name="actionCommand" type="java.lang.String" value="Uncommon"/>
<Property name="focusable" type="boolean" value="false"/>
<Property name="horizontalTextPosition" type="int" value="0"/>
<Property name="verticalTextPosition" type="int" value="3"/>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="tbUncommonActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JToggleButton" name="tbRare">
<Properties>
<Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
<Image iconType="3" name="/buttons/rarity_rare_20.png"/>
</Property>
<Property name="selected" type="boolean" value="true"/>
<Property name="toolTipText" type="java.lang.String" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
<Connection code="&quot;&lt;html&gt;&lt;strong&gt;Rare&lt;/strong&gt;&lt;br/&gt;&quot; &#xd;&#xa;+ tbRarities.getToolTipText()" type="code"/>
</Property>
<Property name="actionCommand" type="java.lang.String" value="Rare"/>
<Property name="focusable" type="boolean" value="false"/>
<Property name="horizontalTextPosition" type="int" value="0"/>
<Property name="verticalTextPosition" type="int" value="3"/>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="tbRareActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JToggleButton" name="tbMythic">
<Properties>
<Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
<Image iconType="3" name="/buttons/rarity_mythic_20.png"/>
</Property>
<Property name="selected" type="boolean" value="true"/>
<Property name="toolTipText" type="java.lang.String" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
<Connection code="&quot;&lt;html&gt;&lt;strong&gt;Mythic&lt;/strong&gt;&lt;br/&gt;&quot; &#xd;&#xa;+ tbRarities.getToolTipText()" type="code"/>
</Property>
<Property name="actionCommand" type="java.lang.String" value="Mythic"/>
<Property name="focusable" type="boolean" value="false"/>
<Property name="horizontalTextPosition" type="int" value="0"/>
<Property name="verticalTextPosition" type="int" value="3"/>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="tbMythicActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JToggleButton" name="tbSpecial">
<Properties>
<Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
<Image iconType="3" name="/buttons/rarity_special_20.png"/>
</Property>
<Property name="selected" type="boolean" value="true"/>
<Property name="toolTipText" type="java.lang.String" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
<Connection code="&quot;&lt;html&gt;&lt;strong&gt;Special&lt;/strong&gt;&lt;br/&gt;&quot; &#xd;&#xa;+ tbRarities.getToolTipText()" type="code"/>
</Property>
<Property name="actionCommand" type="java.lang.String" value="Special"/>
<Property name="focusable" type="boolean" value="false"/>
<Property name="horizontalTextPosition" type="int" value="0"/>
<Property name="verticalTextPosition" type="int" value="3"/>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="tbSpecialActionPerformed"/>
</Events>
</Component>
</SubComponents>
</Container>
</SubComponents>
</Container>
<Container class="javax.swing.JScrollPane" name="cardSelectorScrollPane">

View file

@ -55,6 +55,7 @@ import mage.client.util.GUISizeHelper;
import mage.client.util.gui.FastSearchUtil;
import mage.client.util.sets.ConstructedFormats;
import mage.constants.CardType;
import mage.constants.Rarity;
import mage.filter.FilterCard;
import mage.filter.predicate.Predicate;
import mage.filter.predicate.Predicates;
@ -214,8 +215,8 @@ public class CardSelector extends javax.swing.JPanel implements ComponentListene
this.cards.add(card);
}
filterCards();
}
}
public void loadCards(BigCard bigCard) {
this.bigCard = bigCard;
this.btnBooster.setVisible(true);
@ -225,7 +226,7 @@ public class CardSelector extends javax.swing.JPanel implements ComponentListene
// cbExpansionSet.setModel(new DefaultComboBoxModel<>(ConstructedFormats.getTypes()));
// Action event on Expansion set triggers loadCards method
cbExpansionSet.setSelectedIndex(0);
}
}
private FilterCard buildFilter() {
FilterCard filter = new FilterCard();
@ -328,6 +329,24 @@ public class CardSelector extends javax.swing.JPanel implements ComponentListene
// criteria.types(CardType.TRIBAL);
// criteria.types(CardType.CONSPIRACY);
if (this.tbCommon.isSelected()) {
criteria.rarities(Rarity.COMMON);
criteria.rarities(Rarity.LAND);
}
if (this.tbUncommon.isSelected()) {
criteria.rarities(Rarity.UNCOMMON);
}
if (this.tbRare.isSelected()) {
criteria.rarities(Rarity.RARE);
}
if (this.tbMythic.isSelected()) {
criteria.rarities(Rarity.MYTHIC);
}
if (this.tbSpecial.isSelected()) {
criteria.rarities(Rarity.SPECIAL);
criteria.rarities(Rarity.BONUS);
}
if (this.cbExpansionSet.isVisible()) {
String expansionSelection = this.cbExpansionSet.getSelectedItem().toString();
if (!expansionSelection.equals("- All Sets")) {
@ -376,6 +395,19 @@ public class CardSelector extends javax.swing.JPanel implements ComponentListene
filterCards();
}
private void filterCardsRarity(int modifiers, String actionCommand) {
// ALT or CTRL button was pushed
if ((modifiers & ActionEvent.ALT_MASK) == ActionEvent.ALT_MASK || (modifiers & ActionEvent.CTRL_MASK) == ActionEvent.CTRL_MASK) {
boolean invert = (modifiers & ActionEvent.ALT_MASK) == ActionEvent.ALT_MASK;
tbCommon.setSelected(inverter(invert, tbCommon.getActionCommand(), actionCommand));
tbUncommon.setSelected(inverter(invert, tbUncommon.getActionCommand(), actionCommand));
tbRare.setSelected(inverter(invert, tbRare.getActionCommand(), actionCommand));
tbMythic.setSelected(inverter(invert, tbMythic.getActionCommand(), actionCommand));
tbSpecial.setSelected(inverter(invert, tbSpecial.getActionCommand(), actionCommand));
}
filterCards();
}
private void filterCards() {
FilterCard filter = buildFilter();
try {
@ -494,6 +526,13 @@ public class CardSelector extends javax.swing.JPanel implements ComponentListene
jSeparator4 = new javax.swing.JToolBar.Separator();
jToggleListView = new javax.swing.JToggleButton();
jToggleCardView = new javax.swing.JToggleButton();
jSeparator5 = new javax.swing.JToolBar.Separator();
tbRarities = new javax.swing.JToolBar();
tbCommon = new javax.swing.JToggleButton();
tbUncommon = new javax.swing.JToggleButton();
tbRare = new javax.swing.JToggleButton();
tbMythic = new javax.swing.JToggleButton();
tbSpecial = new javax.swing.JToggleButton();
cardSelectorScrollPane = new javax.swing.JScrollPane();
cardSelectorBottomPanel = new javax.swing.JPanel();
jButtonAddToMain = new javax.swing.JButton();
@ -841,6 +880,88 @@ public class CardSelector extends javax.swing.JPanel implements ComponentListene
}
});
tbTypes.add(jToggleCardView);
tbTypes.add(jSeparator5);
tbRarities.setFloatable(false);
tbRarities.setRollover(true);
tbRarities.setToolTipText("Hold the ALT-key while clicking to deselect all other card rarities or hold the CTRL-key to only select all other card rarities.");
tbCommon.setIcon(new javax.swing.ImageIcon(getClass().getResource("/buttons/rarity_common_20.png"))); // NOI18N
tbCommon.setSelected(true);
tbCommon.setToolTipText("<html><strong>Common</strong><br/>"
+ tbRarities.getToolTipText());
tbCommon.setActionCommand("Common");
tbCommon.setFocusable(false);
tbCommon.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
tbCommon.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
tbCommon.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
tbCommonActionPerformed(evt);
}
});
tbRarities.add(tbCommon);
tbUncommon.setIcon(new javax.swing.ImageIcon(getClass().getResource("/buttons/rarity_uncommon_20.png"))); // NOI18N
tbUncommon.setSelected(true);
tbUncommon.setToolTipText("<html><strong>Uncommon</strong><br/>"
+ tbUncommon.getToolTipText());
tbUncommon.setActionCommand("Uncommon");
tbUncommon.setFocusable(false);
tbUncommon.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
tbUncommon.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
tbUncommon.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
tbUncommonActionPerformed(evt);
}
});
tbRarities.add(tbUncommon);
tbRare.setIcon(new javax.swing.ImageIcon(getClass().getResource("/buttons/rarity_rare_20.png"))); // NOI18N
tbRare.setSelected(true);
tbRare.setToolTipText("<html><strong>Rare</strong><br/>"
+ tbRarities.getToolTipText());
tbRare.setActionCommand("Rare");
tbRare.setFocusable(false);
tbRare.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
tbRare.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
tbRare.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
tbRareActionPerformed(evt);
}
});
tbRarities.add(tbRare);
tbMythic.setIcon(new javax.swing.ImageIcon(getClass().getResource("/buttons/rarity_mythic_20.png"))); // NOI18N
tbMythic.setSelected(true);
tbMythic.setToolTipText("<html><strong>Mythic</strong><br/>"
+ tbRarities.getToolTipText());
tbMythic.setActionCommand("Mythic");
tbMythic.setFocusable(false);
tbMythic.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
tbMythic.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
tbMythic.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
tbMythicActionPerformed(evt);
}
});
tbRarities.add(tbMythic);
tbSpecial.setIcon(new javax.swing.ImageIcon(getClass().getResource("/buttons/rarity_special_20.png"))); // NOI18N
tbSpecial.setSelected(true);
tbSpecial.setToolTipText("<html><strong>Special</strong><br/>"
+ tbRarities.getToolTipText());
tbSpecial.setActionCommand("Special");
tbSpecial.setFocusable(false);
tbSpecial.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
tbSpecial.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
tbSpecial.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
tbSpecialActionPerformed(evt);
}
});
tbRarities.add(tbSpecial);
tbTypes.add(tbRarities);
cardSelectorScrollPane.setToolTipText("<HTML>Double click to add the card to the main deck.<br/>\nALT + Double click to add the card to the sideboard.");
@ -1224,6 +1345,26 @@ public class CardSelector extends javax.swing.JPanel implements ComponentListene
FastSearchUtil.showFastSearchForStringComboBox(cbExpansionSet, "Select set or expansion");
}//GEN-LAST:event_btnExpansionSearchActionPerformed
private void tbCommonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_tbCommonActionPerformed
filterCardsRarity(evt.getModifiers(), evt.getActionCommand());
}//GEN-LAST:event_tbCommonActionPerformed
private void tbUncommonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_tbUncommonActionPerformed
filterCardsRarity(evt.getModifiers(), evt.getActionCommand());
}//GEN-LAST:event_tbUncommonActionPerformed
private void tbRareActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_tbRareActionPerformed
filterCardsRarity(evt.getModifiers(), evt.getActionCommand());
}//GEN-LAST:event_tbRareActionPerformed
private void tbMythicActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_tbMythicActionPerformed
filterCardsRarity(evt.getModifiers(), evt.getActionCommand());
}//GEN-LAST:event_tbMythicActionPerformed
private void tbSpecialActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_tbSpecialActionPerformed
filterCardsRarity(evt.getModifiers(), evt.getActionCommand());
}//GEN-LAST:event_tbSpecialActionPerformed
private void toggleViewMode() {
if (currentView instanceof CardGrid) {
jToggleListView.setSelected(true);
@ -1288,6 +1429,7 @@ public class CardSelector extends javax.swing.JPanel implements ComponentListene
private javax.swing.JToolBar.Separator jSeparator2;
private javax.swing.JToolBar.Separator jSeparator3;
private javax.swing.JToolBar.Separator jSeparator4;
private javax.swing.JToolBar.Separator jSeparator5;
private javax.swing.JToolBar.Separator jSeparator6;
private javax.swing.JTextField jTextFieldSearch;
private javax.swing.JToggleButton jToggleCardView;
@ -1297,15 +1439,21 @@ public class CardSelector extends javax.swing.JPanel implements ComponentListene
private javax.swing.JToggleButton tbBlue;
private javax.swing.JToolBar tbColor;
private javax.swing.JToggleButton tbColorless;
private javax.swing.JToggleButton tbCommon;
private javax.swing.JToggleButton tbCreatures;
private javax.swing.JToggleButton tbEnchantments;
private javax.swing.JToggleButton tbGreen;
private javax.swing.JToggleButton tbInstants;
private javax.swing.JToggleButton tbLand;
private javax.swing.JToggleButton tbMythic;
private javax.swing.JToggleButton tbPlaneswalkers;
private javax.swing.JToggleButton tbRare;
private javax.swing.JToolBar tbRarities;
private javax.swing.JToggleButton tbRed;
private javax.swing.JToggleButton tbSorceries;
private javax.swing.JToggleButton tbSpecial;
private javax.swing.JToolBar tbTypes;
private javax.swing.JToggleButton tbUncommon;
private javax.swing.JToggleButton tbWhite;
// End of variables declaration//GEN-END:variables

View file

@ -114,7 +114,14 @@ public class AddLandDialog extends MageDialog {
}
cbLandSet.setModel(new DefaultComboBoxModel(landSetNames.toArray()));
MageFrame.getDesktop().add(this, JLayeredPane.PALETTE_LAYER);
// windows settings
if (this.isModal()){
MageFrame.getDesktop().add(this, JLayeredPane.MODAL_LAYER);
}else{
MageFrame.getDesktop().add(this, JLayeredPane.PALETTE_LAYER);
}
this.setVisible(true);
}

View file

@ -102,10 +102,10 @@ public class ConnectDialog extends MageDialog {
this.txtPassword.addActionListener(connectAction);
registerUserDialog = new RegisterUserDialog(this);
MageFrame.getDesktop().add(registerUserDialog, JLayeredPane.POPUP_LAYER);
MageFrame.getDesktop().add(registerUserDialog, JLayeredPane.MODAL_LAYER);
resetPasswordDialog = new ResetPasswordDialog(this);
MageFrame.getDesktop().add(resetPasswordDialog, JLayeredPane.POPUP_LAYER);
MageFrame.getDesktop().add(resetPasswordDialog, JLayeredPane.MODAL_LAYER);
}
public void showDialog() {

View file

@ -45,8 +45,8 @@ import java.awt.event.MouseEvent;
import java.beans.PropertyVetoException;
import java.lang.reflect.InvocationTargetException;
import java.util.logging.Level;
import javax.swing.JComponent;
import javax.swing.SwingUtilities;
import javax.swing.*;
import mage.client.MageFrame;
import org.apache.log4j.Logger;
@ -74,11 +74,34 @@ public class MageDialog extends javax.swing.JInternalFrame {
@Override
public void show() {
super.show();
this.toFront();
// frames desktop ordering
// more info https://docs.oracle.com/javase/7/docs/api/javax/swing/JLayeredPane.html
// WARNING, use
// - JLayeredPane.DEFAULT_LAYER: tables and games (tabs)
// - JLayeredPane.PALETTE_LAYER: toolbars and info windows like cards list, not modal dialogs (not required user actions)
// - JLayeredPane.MODAL_LAYER: all modal dialogs (user required actions - select cards in game, new game window, error windows)
// - JLayeredPane.POPUP_LAYER: hints and other top level graphics
// - JLayeredPane.DRAG_LAYER: top most layer for critical actions and user controls
/*
JInternalFrame[] frames = MageFrame.getDesktop().getAllFrames();
System.out.println("---");
for(JInternalFrame frame: frames){
int zorder = -1;
if (frame.getParent() != null){
frame.getParent().getComponentZOrder(frame);
}
System.out.println(frame.getClass() + " (" + frame.getTitle() + ") : layer = " + frame.getLayer() + ", zorder = " + zorder);
}
*/
if (modal) {
this.setClosable(false);
}
if (this.modal) {
this.toFront();
if (modal){
startModal();
}
}
@ -108,7 +131,6 @@ public class MageDialog extends javax.swing.JInternalFrame {
}
private synchronized void startModal() {
try {
if (SwingUtilities.isEventDispatchThread()) {
EventQueue theQueue = getToolkit().getSystemEventQueue();

View file

@ -47,6 +47,7 @@ import mage.cards.repository.ExpansionRepository;
import mage.client.MageFrame;
import mage.client.SessionHandler;
import mage.client.table.TournamentPlayerPanel;
import mage.client.util.gui.FastSearchUtil;
import mage.constants.MatchTimeLimit;
import mage.constants.MultiplayerAttackOption;
import mage.constants.RangeOfInfluence;
@ -76,7 +77,7 @@ public class NewTournamentDialog extends MageDialog {
private RandomPacksSelectorDialog randomPackSelector;
private JTextArea txtRandomPacks;
private final List<TournamentPlayerPanel> players = new ArrayList<>();
private final List<JComboBox> packs = new ArrayList<>();
private final List<JPanel> packPanels = new ArrayList<>();
private static final int CONSTRUCTION_TIME_MIN = 6;
private static final int CONSTRUCTION_TIME_MAX = 30;
private boolean isRandom = false;
@ -586,8 +587,13 @@ public class NewTournamentDialog extends MageDialog {
tOptions.getLimitedOptions().getSetCodes().addAll(selected);
}
} else {
for (JComboBox pack : packs) {
tOptions.getLimitedOptions().getSetCodes().add(((ExpansionInfo) pack.getSelectedItem()).getCode());
for (JPanel panel : packPanels) {
JComboBox combo = findComboInComponent(panel);
if(combo != null) {
tOptions.getLimitedOptions().getSetCodes().add(((ExpansionInfo) combo.getSelectedItem()).getCode());
}else{
logger.error("Can't find combo component in " + panel.toString());
}
}
}
tOptions.getMatchOptions().setDeckType("Limited");
@ -884,35 +890,89 @@ public class NewTournamentDialog extends MageDialog {
}
private void createPacks(int numPacks) {
while (packs.size() > numPacks) {
pnlPacks.remove(packs.get(packs.size() - 1));
packs.remove(packs.size() - 1);
while (packPanels.size() > numPacks) {
pnlPacks.remove(packPanels.get(packPanels.size() - 1));
packPanels.remove(packPanels.size() - 1);
}
while (packs.size() < numPacks) {
while (packPanels.size() < numPacks) {
// SELECT PACK
// panel
JPanel setPanel = new JPanel();
setPanel.setLayout(new javax.swing.BoxLayout(setPanel, javax.swing.BoxLayout.LINE_AXIS));
setPanel.setOpaque(false);
//setPanel.setPreferredSize(new Dimension(200, 25));
//setPanel.setMaximumSize(new Dimension(200, 25));
pnlPacks.add(setPanel);
packPanels.add(setPanel); // for later access
// combo set
JComboBox pack = new JComboBox();
pack = new JComboBox();
pack.setModel(new DefaultComboBoxModel(ExpansionRepository.instance.getWithBoostersSortedByReleaseDate()));
pnlPacks.add(pack);
packs.add(pack);
pack.addActionListener(evt -> packActionPerformed(evt));
pack.setAlignmentX(0.0F);
pack.setMinimumSize(new Dimension(50, 25));
pack.setPreferredSize(new Dimension(50, 25));
pack.setMaximumSize(new Dimension(Integer.MAX_VALUE, 25));
setPanel.add(pack);
// search button
JButton searchButton = new JButton();
searchButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/buttons/search_24.png")));
searchButton.setToolTipText("Search and select from list");
searchButton.setAlignmentX(1.0F);
searchButton.setMinimumSize(new java.awt.Dimension(24, 24));
searchButton.setPreferredSize(new java.awt.Dimension(32, 32));
searchButton.setMaximumSize(new java.awt.Dimension(32, 32));
searchButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
// search combo box near button (must be only one combo in panel)
JButton button = (JButton)evt.getSource();
JComboBox combo = findComboInComponent(button.getParent());
if (combo != null) {
FastSearchUtil.showFastSearchForStringComboBox(combo, "Select value");
}
}
});
setPanel.add(searchButton);
}
this.pack();
this.revalidate();
this.repaint();
}
private void packActionPerformed(java.awt.event.ActionEvent evt) {
boolean start = false;
int selectedIndex = 0;
for (JComboBox pack : packs) {
if (!start) {
if (evt.getSource().equals(pack)) {
start = true;
selectedIndex = pack.getSelectedIndex();
}
} else {
pack.setSelectedIndex(selectedIndex);
private JComboBox findComboInComponent(Container panel){
// search combo box near button (must be only one combo in panel)
JComboBox combo = null;
for(Component comp: panel.getComponents()){
if (comp instanceof JComboBox){
combo = (JComboBox)comp;
break;
}
}
return combo;
}
private void packActionPerformed(java.awt.event.ActionEvent evt) {
// fill all bottom combobox with same value
JComboBox curentCombo = (JComboBox)evt.getSource();
int newValue = curentCombo.getSelectedIndex();
// search start index
int startIndex = 0;
for(int i = 0; i < packPanels.size(); i++){
JComboBox pack = findComboInComponent(packPanels.get(i));
if (pack.equals(curentCombo)){
startIndex = i + 1;
break;
}
}
// change all from start index
for(int i = startIndex; i < packPanels.size(); i++){
JComboBox pack = findComboInComponent(packPanels.get(i));
pack.setSelectedIndex(newValue);
}
}
private void createPlayers(int numPlayers) {
@ -1054,16 +1114,22 @@ public class NewTournamentDialog extends MageDialog {
int packNumber = 0;
for (String pack : packsArray) {
packNumber++;
if (this.packs.size() >= packNumber - 1) {
JComboBox comboBox = this.packs.get(packNumber - 1);
ComboBoxModel model = comboBox.getModel();
int size = model.getSize();
for (int i = 0; i < size; i++) {
ExpansionInfo element = (ExpansionInfo) model.getElementAt(i);
if (element.getCode().equals(pack.trim())) {
comboBox.setSelectedIndex(i);
break;
if (this.packPanels.size() >= packNumber - 1) {
JPanel panel = packPanels.get(packNumber - 1);
JComboBox comboBox = findComboInComponent(panel);
if (comboBox != null) {
ComboBoxModel model = comboBox.getModel();
int size = model.getSize();
for (int i = 0; i < size; i++) {
ExpansionInfo element = (ExpansionInfo) model.getElementAt(i);
if (element.getCode().equals(pack.trim())) {
comboBox.setSelectedIndex(i);
break;
}
}
}else{
logger.error("Can't find combo component in " + panel.toString());
}
}

View file

@ -165,7 +165,11 @@ public class PickChoiceDialog extends MageDialog {
}
// window settings
MageFrame.getDesktop().add(this, JLayeredPane.PALETTE_LAYER);
if (this.isModal()){
MageFrame.getDesktop().add(this, JLayeredPane.MODAL_LAYER);
}else{
MageFrame.getDesktop().add(this, JLayeredPane.PALETTE_LAYER);
}
if (mageDialogState != null) {
mageDialogState.setStateToDialog(this);
@ -174,7 +178,7 @@ public class PickChoiceDialog extends MageDialog {
this.setLocation(centered.x, centered.y);
GuiDisplayUtil.keepComponentInsideScreen(centered.x, centered.y, this);
}
// final load
loadData();

View file

@ -35,7 +35,9 @@
package mage.client.dialog;
import java.awt.Point;
import javax.swing.SpinnerNumberModel;
import javax.swing.*;
import mage.client.MageFrame;
import mage.client.util.SettingsManager;
import mage.client.util.gui.GuiDisplayUtil;
@ -60,6 +62,13 @@ public class PickNumberDialog extends MageDialog {
this.btnCancel.setVisible(false);
this.pack();
// window settings
if (this.isModal()){
MageFrame.getDesktop().add(this, JLayeredPane.MODAL_LAYER);
}else{
MageFrame.getDesktop().add(this, JLayeredPane.PALETTE_LAYER);
}
Point centered = SettingsManager.instance.getComponentPosition(getWidth(), getHeight());
this.setLocation(centered.x, centered.y);
GuiDisplayUtil.keepComponentInsideScreen(centered.x, centered.y, this);

View file

@ -114,6 +114,14 @@ public class PickPileDialog extends MageDialog {
this.revalidate();
this.repaint();
this.setModal(true);
// window settings
if (this.isModal()){
MageFrame.getDesktop().add(this, JLayeredPane.MODAL_LAYER);
}else{
MageFrame.getDesktop().add(this, JLayeredPane.PALETTE_LAYER);
}
this.setVisible(true);
}

View file

@ -120,15 +120,19 @@ public class ShowCardsDialog extends MageDialog {
this.cardArea.addCardEventListener(eventListener);
}
if (getParent() != MageFrame.getDesktop() /*|| this.isClosed*/) {
MageFrame.getDesktop().add(this, JLayeredPane.DEFAULT_LAYER);
}
pack();
this.revalidate();
this.repaint();
this.setModal(modal);
// window settings
if (this.isModal()){
MageFrame.getDesktop().add(this, JLayeredPane.MODAL_LAYER);
}else{
MageFrame.getDesktop().add(this, JLayeredPane.PALETTE_LAYER);
}
SwingUtilities.invokeLater(() -> {
if (!positioned) {
int width = ShowCardsDialog.this.getWidth();

View file

@ -1115,7 +1115,7 @@ public final class GamePanel extends javax.swing.JPanel {
}
this.feedbackPanel.getFeedback(required ? FeedbackMode.INFORM : FeedbackMode.CANCEL, message, gameView.getSpecial(), options0, messageId);
if (dialog != null) {
this.pickTarget.add(dialog);
this.pickTarget.add(dialog); // TODO: 01.01.2018, JayDi85: why feedbackPanel saved to pickTarget list? Need to research
}
}

View file

@ -51,7 +51,9 @@ import javax.swing.UIManager;
import mage.client.SessionHandler;
import mage.client.components.MageTextArea;
import mage.client.constants.Constants;
import mage.client.game.FeedbackPanel.FeedbackMode;
import static mage.client.game.FeedbackPanel.FeedbackMode.QUESTION;
import mage.client.util.GUISizeHelper;
import static mage.constants.PlayerAction.REQUEST_AUTO_ANSWER_ID_NO;
@ -82,7 +84,6 @@ public class HelperPanel extends JPanel {
private javax.swing.JButton linkSpecial;
private javax.swing.JButton linkUndo;
private final int defaultDismissTimeout = ToolTipManager.sharedInstance().getDismissDelay();
private final Object tooltipBackground = UIManager.get("info");
private static final String CMD_AUTO_ANSWER_ID_YES = "cmdAutoAnswerIdYes";
@ -232,13 +233,13 @@ public class HelperPanel extends JPanel {
@Override
public void mouseEntered(MouseEvent me) {
ToolTipManager.sharedInstance().setDismissDelay(100000);
ToolTipManager.sharedInstance().setDismissDelay(100 * 1000);
UIManager.put("info", Color.DARK_GRAY);
}
@Override
public void mouseExited(MouseEvent me) {
ToolTipManager.sharedInstance().setDismissDelay(defaultDismissTimeout);
ToolTipManager.sharedInstance().setDismissDelay(Constants.TOOLTIPS_DELAY_MS);
UIManager.put("info", tooltipBackground);
}
});

View file

@ -0,0 +1,52 @@
package mage.client.util.stats;
/**
*
* @author JayDi85
*/
public class MemoryStats {
private float Available = 0;
private float MaxAvailable = 0;
private float Used = 0;
private float Free = 0;
public MemoryStats(float MaxAvailable, float Available, float Used, float Free){
this.setMaxAvailable(MaxAvailable);
this.setAvailable(Available);
this.setUsed(Used);
this.setFree(Free);
}
public float getAvailable() {
return Available;
}
public void setAvailable(float available) {
Available = available;
}
public float getUsed() {
return Used;
}
public void setUsed(float used) {
Used = used;
}
public float getFree() {
return Free;
}
public void setFree(float free) {
Free = free;
}
public float getMaxAvailable() {
return MaxAvailable;
}
public void setMaxAvailable(float maxAvailable) {
MaxAvailable = maxAvailable;
}
}

View file

@ -1,25 +0,0 @@
package mage.client.util.stats;
/**
* @author noxx
*/
public final class MemoryUsageStatUtil {
private MemoryUsageStatUtil() {}
/**
* Returns percentage of available memory used at runtime.
* If not possible to determine, returns -1.
*
* @return
*/
public static float getMemoryFreeStatPercentage() {
Runtime runtime = Runtime.getRuntime();
if (runtime.maxMemory() != 0) {
long usedMem = runtime.totalMemory() - runtime.freeMemory();
return (1 - (1.0f*usedMem)/runtime.maxMemory())*100;
} else {
return -1;
}
}
}

View file

@ -1,5 +1,6 @@
package mage.client.util.stats;
import java.awt.*;
import java.util.List;
import java.util.concurrent.CancellationException;
import java.util.concurrent.ExecutionException;
@ -11,11 +12,13 @@ import org.apache.log4j.Logger;
* This updates the mem usage info in the Mage client every
* MEM_USAGE_UPDATE_TIME ms.
*
* @author noxx
* @author noxx, JayDi85
*/
public class UpdateMemUsageTask extends SwingWorker<Void, Float> {
public class UpdateMemUsageTask extends SwingWorker<Void, MemoryStats> {
private static final int MEM_USAGE_UPDATE_TIME = 2000;
private static final int MEM_USAGE_WARNING_PERCENT = 80; // red color for mem used more than xx%
private final JLabel jLabelToDisplayInfo;
@ -23,24 +26,60 @@ public class UpdateMemUsageTask extends SwingWorker<Void, Float> {
public UpdateMemUsageTask(JLabel jLabelToDisplayInfo) {
this.jLabelToDisplayInfo = jLabelToDisplayInfo;
this.jLabelToDisplayInfo.setToolTipText("<html>Memory usage statistics");
}
@Override
protected Void doInBackground() throws Exception {
while (!isCancelled()) {
float memUsage = MemoryUsageStatUtil.getMemoryFreeStatPercentage();
this.publish(memUsage >= 0 ? memUsage : null);
MemoryStats memoryStats = new MemoryStats(0, 0, 0, 0);
Runtime runtime = Runtime.getRuntime();
if (runtime.maxMemory() != 0) {
memoryStats.setMaxAvailable(runtime.maxMemory());
memoryStats.setAvailable(runtime.totalMemory());
memoryStats.setFree(runtime.freeMemory());
memoryStats.setUsed(runtime.totalMemory() - runtime.freeMemory());
}
this.publish(memoryStats);
TimeUnit.MILLISECONDS.sleep(MEM_USAGE_UPDATE_TIME);
}
return null;
}
@Override
protected void process(List<Float> chunks) {
protected void process(List<MemoryStats> chunks) {
if (chunks != null && !chunks.isEmpty()) {
Float memUsage = chunks.get(chunks.size() - 1);
if (memUsage != null) {
jLabelToDisplayInfo.setText(Math.round(memUsage) + "% Mem free");
MemoryStats memoryStats = chunks.get(chunks.size() - 1);
if (memoryStats != null) {
int max = Math.round(memoryStats.getMaxAvailable() / (1000 * 1000));
int used = Math.round(memoryStats.getUsed() / (1000 * 1000));
int total = Math.round(memoryStats.getAvailable() / (1000 * 1000));
int percent = 0;
if(max != 0){
percent = Math.round((used * 100) / max);
}
jLabelToDisplayInfo.setText("Memory used: " + percent + "% (" + used + " of " + max + " MB)");
String warning = "";
String optimizeHint = "<br><br>If you see low memory warning and have free system memory then try to increase max limit in launcher settings:<br>"
+ " - Go to <i>launcher -> settings -> java tab</i>;<br>"
+ " - Find <i>client java options</i> (it's may contain many commands);<br>"
+ " - Find max available memory setting: <i>-Xmx256m</i> (it's must start with <b>-Xmx</b>);<br>"
+ " - Increase number in that value from 256 to 512, or 512 to 1024;<br>"
+ " - Save new settings and restart application.";
if(percent >= MEM_USAGE_WARNING_PERCENT){
jLabelToDisplayInfo.setForeground(Color.red);
warning = "<br><br><b>WARNING</b><br>"
+ "Application memory limit almost reached. Errors and freezes are very possible.";
}else{
jLabelToDisplayInfo.setForeground(Color.black);
}
this.jLabelToDisplayInfo.setToolTipText("<html>Memory usage statistics" + warning + optimizeHint);
return;
}
}

View file

@ -35,28 +35,30 @@ public final class ManaSymbolsCellRenderer extends DefaultTableCellRenderer {
String manaCost = (String)value;
manaPanel.removeAll();
manaPanel.setLayout(new BoxLayout(manaPanel, BoxLayout.X_AXIS));
StringTokenizer tok = new StringTokenizer(manaCost, " ");
while (tok.hasMoreTokens()) {
String symbol = tok.nextToken();
if(manaCost != null){
StringTokenizer tok = new StringTokenizer(manaCost, " ");
while (tok.hasMoreTokens()) {
String symbol = tok.nextToken();
JLabel symbolLabel = new JLabel();
//symbolLabel.setBorder(new LineBorder(new Color(150, 150, 150))); // debug
symbolLabel.setBorder(new EmptyBorder(0, symbolHorizontalMargin,0, 0));
JLabel symbolLabel = new JLabel();
//symbolLabel.setBorder(new LineBorder(new Color(150, 150, 150))); // debug
symbolLabel.setBorder(new EmptyBorder(0, symbolHorizontalMargin,0, 0));
BufferedImage image = ManaSymbols.getSizedManaSymbol(symbol, symbolWidth);
if (image != null){
// icon
symbolLabel.setIcon(new ImageIcon(image));
}else
{
// text
symbolLabel.setText("{" + symbol + "}");
symbolLabel.setOpaque(baseLabel.isOpaque());
symbolLabel.setForeground(baseLabel.getForeground());
symbolLabel.setBackground(baseLabel.getBackground());
BufferedImage image = ManaSymbols.getSizedManaSymbol(symbol, symbolWidth);
if (image != null){
// icon
symbolLabel.setIcon(new ImageIcon(image));
}else
{
// text
symbolLabel.setText("{" + symbol + "}");
symbolLabel.setOpaque(baseLabel.isOpaque());
symbolLabel.setForeground(baseLabel.getForeground());
symbolLabel.setBackground(baseLabel.getBackground());
}
manaPanel.add(symbolLabel);
}
manaPanel.add(symbolLabel);
}
return manaPanel;

View file

@ -0,0 +1,42 @@
package mage.client.util;
import org.junit.Assert;
import org.junit.Test;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import static mage.client.MageFrame.isChrismasTime;
public class ChrismasTest {
private Date getDate(int Year, int Month, int Day){
Calendar cal = new GregorianCalendar(Year, Month - 1, Day);
return cal.getTime();
}
@Test
public void ignoreDefaultResponse() throws Exception {
// chrismas from 15 december to 15 january
Assert.assertEquals(false, isChrismasTime(getDate(2017, 11, 1)));
Assert.assertEquals(false, isChrismasTime(getDate(2017, 11, 15)));
Assert.assertEquals(false, isChrismasTime(getDate(2017, 11, 30)));
Assert.assertEquals(false, isChrismasTime(getDate(2017, 12, 1)));
Assert.assertEquals(false, isChrismasTime(getDate(2017, 12, 14)));
Assert.assertEquals(true, isChrismasTime(getDate(2017, 12, 15)));
Assert.assertEquals(true, isChrismasTime(getDate(2017, 12, 16)));
Assert.assertEquals(true, isChrismasTime(getDate(2017, 12, 31)));
Assert.assertEquals(true, isChrismasTime(getDate(2018, 1, 1)));
Assert.assertEquals(true, isChrismasTime(getDate(2018, 1, 14)));
Assert.assertEquals(true, isChrismasTime(getDate(2018, 1, 15)));
Assert.assertEquals(false, isChrismasTime(getDate(2018, 1, 16)));
Assert.assertEquals(false, isChrismasTime(getDate(2018, 1, 31)));
Assert.assertEquals(false, isChrismasTime(getDate(2018, 2, 1)));
Assert.assertEquals(false, isChrismasTime(getDate(2018, 12, 1)));
Assert.assertEquals(true, isChrismasTime(getDate(2018, 12, 20)));
Assert.assertEquals(true, isChrismasTime(getDate(2019, 1, 10)));
Assert.assertEquals(false, isChrismasTime(getDate(2019, 1, 25)));
}
}

View file

@ -0,0 +1,79 @@
/*
* 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.a;
import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.costs.common.SacrificeSourceCost;
import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.effects.common.DestroyAllEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Zone;
import mage.filter.FilterPermanent;
import mage.filter.predicate.Predicates;
import mage.filter.predicate.other.ExpansionSetPredicate;
import mage.filter.predicate.permanent.TokenPredicate;
/**
*
* @author L_J
*/
public class ApocalypseChime extends CardImpl {
private static final FilterPermanent filter = new FilterPermanent("nontoken permanents with a name originally printed in the Homelands expansion");
static {
filter.add(Predicates.and(
Predicates.not(new TokenPredicate()),
new ExpansionSetPredicate("HML")
));
}
public ApocalypseChime(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{2}");
// {2}, {T}, Sacrifice Apocalypse Chime: Destroy all nontoken permanents with a name originally printed in the Homelands expansion. They can't be regenerated.
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DestroyAllEffect(filter, true), new ManaCostsImpl("{2}"));
ability.addCost(new TapSourceCost());
ability.addCost(new SacrificeSourceCost());
this.addAbility(ability);
}
public ApocalypseChime(final ApocalypseChime card) {
super(card);
}
@Override
public ApocalypseChime copy() {
return new ApocalypseChime(this);
}
}

View file

@ -25,7 +25,6 @@
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
package mage.cards.a;
import java.util.UUID;
@ -46,14 +45,17 @@ import mage.constants.*;
public class ArdentRecruit extends CardImpl {
public ArdentRecruit(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{W}");
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{W}");
this.subtype.add(SubType.HUMAN);
this.subtype.add(SubType.SOLDIER);
this.power = new MageInt(1);
this.toughness = new MageInt(1);
// Metalcraft Ardent Recruit gets +2/+2 as long as you control three or more artifacts.
ContinuousEffect boostSource = new BoostSourceEffect(2, 2, Duration.WhileOnBattlefield);
ConditionalContinuousEffect effect = new ConditionalContinuousEffect(boostSource, MetalcraftCondition.instance, "Ardent Recruit gets +2/+2 as long as you control three or more artifacts");
ConditionalContinuousEffect effect = new ConditionalContinuousEffect(boostSource, MetalcraftCondition.instance,
"{this} gets +2/+2 as long as you control three or more artifacts");
Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, effect);
ability.setAbilityWord(AbilityWord.METALCRAFT);
this.addAbility(ability);

View 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.a;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.effects.AsThoughEffectImpl;
import mage.abilities.keyword.ShroudAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.*;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.target.TargetPlayer;
/**
*
* @author L_J
*/
public class AutumnWillow extends CardImpl {
public AutumnWillow(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{G}{G}");
addSuperType(SuperType.LEGENDARY);
this.subtype.add(SubType.AVATAR);
this.power = new MageInt(4);
this.toughness = new MageInt(4);
// Shroud
this.addAbility(ShroudAbility.getInstance());
// {G}: Until end of turn, Autumn Willow can be the target of spells and abilities controlled by target player as though it didn't have shroud.
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new AutumnWillowEffect(), new ManaCostsImpl("{G}"));
ability.addTarget(new TargetPlayer());
this.addAbility(ability);
}
public AutumnWillow(final AutumnWillow card) {
super(card);
}
@Override
public AutumnWillow copy() {
return new AutumnWillow(this);
}
}
class AutumnWillowEffect extends AsThoughEffectImpl {
public AutumnWillowEffect() {
super(AsThoughEffectType.SHROUD, Duration.EndOfTurn, Outcome.Benefit);
staticText = "Until end of turn, Autumn Willow can be the target of spells and abilities controlled by target player as though it didn't have shroud";
}
public AutumnWillowEffect(final AutumnWillowEffect effect) {
super(effect);
}
@Override
public boolean apply(Game game, Ability source) {
return true;
}
@Override
public AutumnWillowEffect copy() {
return new AutumnWillowEffect(this);
}
@Override
public boolean applies(UUID sourceId, Ability source, UUID affectedControllerId, Game game) {
if (affectedControllerId.equals(source.getFirstTarget())) {
Permanent creature = game.getPermanent(sourceId);
if (creature != null) {
if (sourceId.equals(source.getSourceId())) {
return true;
}
}
}
return false;
}
}

View file

@ -0,0 +1,117 @@
/*
* 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.DelayedTriggeredAbility;
import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbility;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.CreateTokenEffect;
import mage.abilities.effects.common.SacrificeTargetEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Outcome;
import mage.filter.common.FilterCreaturePermanent;
import mage.filter.predicate.Predicates;
import mage.filter.predicate.mageobject.CardTypePredicate;
import mage.filter.predicate.permanent.AttackingPredicate;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.game.permanent.token.BrokenVisageSpiritToken;
import mage.target.common.TargetCreaturePermanent;
import mage.target.targetpointer.FixedTarget;
/**
*
* @author L_J
*/
public class BrokenVisage extends CardImpl {
private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("nonartifact attacking creature");
static {
filter.add(Predicates.not(new CardTypePredicate(CardType.ARTIFACT)));
filter.add(new AttackingPredicate());
}
public BrokenVisage(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{4}{B}");
// Destroy target nonartifact attacking creature. It can't be regenerated. Create a black Spirit creature token. Its power is equal to that creature's power and its toughness is equal to that creature's toughness. Sacrifice the token at the beginning of the next end step.
this.getSpellAbility().addEffect(new BrokenVisageEffect());
this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter));
}
public BrokenVisage(final BrokenVisage card) {
super(card);
}
@Override
public BrokenVisage copy() {
return new BrokenVisage(this);
}
}
class BrokenVisageEffect extends OneShotEffect {
public BrokenVisageEffect() {
super(Outcome.DestroyPermanent);
this.staticText = "Destroy target nonartifact attacking creature. It can't be regenerated. Create a black Spirit creature token. Its power is equal to that creature's power and its toughness is equal to that creature's toughness. Sacrifice the token at the beginning of the next end step";
}
public BrokenVisageEffect(final BrokenVisageEffect effect) {
super(effect);
}
@Override
public BrokenVisageEffect copy() {
return new BrokenVisageEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Permanent permanent = game.getPermanentOrLKIBattlefield(this.getTargetPointer().getFirst(game, source));
if (permanent != null) {
permanent.destroy(source.getSourceId(), game, true);
CreateTokenEffect effect = new CreateTokenEffect(new BrokenVisageSpiritToken(permanent.getPower().getValue(), permanent.getToughness().getValue()));
effect.apply(game, source);
for (UUID tokenId : effect.getLastAddedTokenIds()) {
Permanent tokenPermanent = game.getPermanent(tokenId);
if (tokenPermanent != null) {
SacrificeTargetEffect sacrificeEffect = new SacrificeTargetEffect("Sacrifice the token at the beginning of the next end step", source.getControllerId());
sacrificeEffect.setTargetPointer(new FixedTarget(tokenPermanent, game));
DelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(sacrificeEffect);
game.addDelayedTriggeredAbility(delayedAbility, source);
}
}
}
return true;
}
}

View file

@ -72,6 +72,7 @@ public class DaughterOfAutumn extends CardImpl {
// {W}: The next 1 damage that would be dealt to target white creature this turn is dealt to Daughter of Autumn instead.
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DaughterOfAutumnPreventDamageTargetEffect(Duration.EndOfTurn, 1), new ManaCostsImpl("{W}"));
ability.addTarget(new TargetCreaturePermanent(filter));
this.addAbility(ability);
}
public DaughterOfAutumn(final DaughterOfAutumn card) {

View file

@ -0,0 +1,78 @@
/*
* 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.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.condition.common.CitysBlessingCondition;
import mage.abilities.decorator.ConditionalContinuousEffect;
import mage.abilities.effects.ContinuousEffect;
import mage.abilities.effects.common.continuous.BoostSourceEffect;
import mage.abilities.keyword.AscendAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.SubType;
import mage.constants.Zone;
/**
*
* @author LevelX2
*/
public class DuskCharger extends CardImpl {
public DuskCharger(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{B}");
this.subtype.add(SubType.HORSE);
this.power = new MageInt(3);
this.toughness = new MageInt(3);
// Ascend
this.addAbility(new AscendAbility());
// Dusk Charger gets +2/+2 as long as you have the city's blessing.
ContinuousEffect boostSource = new BoostSourceEffect(2, 2, Duration.WhileOnBattlefield);
ConditionalContinuousEffect effect = new ConditionalContinuousEffect(boostSource, CitysBlessingCondition.instance,
"{this} gets +2/+2 as long as you have the city's blessing");
Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, effect);
this.addAbility(ability);
}
public DuskCharger(final DuskCharger card) {
super(card);
}
@Override
public DuskCharger copy() {
return new DuskCharger(this);
}
}

View file

@ -0,0 +1,77 @@
/*
* 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.dynamicvalue.IntPlusDynamicValue;
import mage.abilities.dynamicvalue.common.CardsInAllGraveyardsCount;
import mage.abilities.effects.Effect;
import mage.abilities.effects.common.DamageTargetEffect;
import mage.abilities.effects.common.GainLifeEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.filter.FilterCard;
import mage.filter.predicate.mageobject.NamePredicate;
import mage.target.common.TargetCreaturePermanent;
/**
*
* @author L_J
*/
public class FeastOfFlesh extends CardImpl {
private static final FilterCard filter = new FilterCard("cards named Feast of Flesh");
static {
filter.add(new NamePredicate("Feast of Flesh"));
}
public FeastOfFlesh(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{B}");
// Feast of Flesh deals X damage to target creature and you gain X life, where X is 1 plus the number of cards named Feast of Flesh in all graveyards.
IntPlusDynamicValue value = new IntPlusDynamicValue(1, new CardsInAllGraveyardsCount(filter));
Effect effect1 = new DamageTargetEffect(value);
effect1.setText("Feast of Flesh deals X damage to target creature");
Effect effect2 = new GainLifeEffect(value);
effect2.setText("and you gain X life, where X is 1 plus the number of cards named {source} in all graveyards");
this.getSpellAbility().addEffect(effect1);
this.getSpellAbility().addEffect(effect2);
this.getSpellAbility().addTarget(new TargetCreaturePermanent());
}
public FeastOfFlesh(final FeastOfFlesh card) {
super(card);
}
@Override
public FeastOfFlesh copy() {
return new FeastOfFlesh(this);
}
}

View file

@ -28,18 +28,15 @@
package mage.cards.f;
import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.common.BeginningOfUpkeepTriggeredAbility;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.condition.common.LiveLostLastTurnCondition;
import mage.abilities.decorator.ConditionalTriggeredAbility;
import mage.abilities.effects.common.CreateTokenEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Outcome;
import mage.constants.TargetController;
import mage.game.Game;
import mage.game.permanent.token.SoldierToken;
import mage.watchers.common.PlayerLostLifeWatcher;
/**
*
@ -51,8 +48,10 @@ public class FirstResponse extends CardImpl {
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{3}{W}");
// At the beginning of each upkeep, if you lost life last turn, create a 1/1 white Soldier creature token.
this.addAbility(new BeginningOfUpkeepTriggeredAbility(new FirstResponseEffect(), TargetController.ANY, false), new PlayerLostLifeWatcher());
this.addAbility(new ConditionalTriggeredAbility(
new BeginningOfUpkeepTriggeredAbility(new CreateTokenEffect(new SoldierToken()), TargetController.ANY, false),
LiveLostLastTurnCondition.instance,
"At the beginning of each upkeep, if you lost life last turn, create a 1/1 white Soldier creature token."));
}
public FirstResponse(final FirstResponse card) {
@ -64,32 +63,3 @@ public class FirstResponse extends CardImpl {
return new FirstResponse(this);
}
}
class FirstResponseEffect extends OneShotEffect {
public FirstResponseEffect() {
super(Outcome.PutCreatureInPlay);
this.staticText = "if you lost life last turn, create a 1/1 white Soldier creature token";
}
public FirstResponseEffect(final FirstResponseEffect effect) {
super(effect);
}
@Override
public FirstResponseEffect copy() {
return new FirstResponseEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
PlayerLostLifeWatcher watcher = (PlayerLostLifeWatcher) game.getState().getWatchers().get(PlayerLostLifeWatcher.class.getSimpleName());
if (watcher != null) {
if (watcher.getLiveLostLastTurn(source.getControllerId()) > 0) {
return new CreateTokenEffect(new SoldierToken()).apply(game, source);
}
return true;
}
return false;
}
}

View file

@ -0,0 +1,92 @@
/*
* 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.common.AsEntersBattlefieldAbility;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.condition.common.CitysBlessingCondition;
import mage.abilities.decorator.ConditionalContinuousEffect;
import mage.abilities.effects.ContinuousEffect;
import mage.abilities.effects.common.ChooseCreatureTypeEffect;
import mage.abilities.effects.common.continuous.BoostAllOfChosenSubtypeEffect;
import mage.abilities.effects.common.continuous.GainAbilityAllOfChosenSubtypeEffect;
import mage.abilities.keyword.AscendAbility;
import mage.abilities.keyword.VigilanceAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.Outcome;
import mage.constants.TargetController;
import mage.constants.Zone;
import static mage.filter.StaticFilters.FILTER_PERMANENT_CREATURES_CONTROLLED;
import mage.filter.common.FilterCreaturePermanent;
import mage.filter.predicate.permanent.ControllerPredicate;
/**
*
* @author LevelX2
*/
public class GloriousDestiny extends CardImpl {
private final static FilterCreaturePermanent filter = new FilterCreaturePermanent("creatures you control of the chosen type");
static {
filter.add(new ControllerPredicate(TargetController.YOU));
}
public GloriousDestiny(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{W}");
// Ascend
this.addAbility(new AscendAbility());
// As Glorious Destiny enters the battlefield, choose a creature type.
this.addAbility(new AsEntersBattlefieldAbility(new ChooseCreatureTypeEffect(Outcome.BoostCreature)));
// Creatures you control of the chosen type get +1/+1. They have vigilance as long as you have the city's blessing.
Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostAllOfChosenSubtypeEffect(1, 1, Duration.WhileOnBattlefield, filter, true));
ContinuousEffect effect = new ConditionalContinuousEffect(
new GainAbilityAllOfChosenSubtypeEffect(VigilanceAbility.getInstance(), Duration.WhileOnBattlefield, FILTER_PERMANENT_CREATURES_CONTROLLED),
CitysBlessingCondition.instance,
"They have vigilance as long as you have the city's blessing");
ability.addEffect(effect);
this.addAbility(ability);
}
public GloriousDestiny(final GloriousDestiny card) {
super(card);
}
@Override
public GloriousDestiny copy() {
return new GloriousDestiny(this);
}
}

View file

@ -0,0 +1,130 @@
/*
* 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.MageInt;
import mage.ObjectColor;
import mage.abilities.Ability;
import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.effects.RedirectionEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.constants.Duration;
import mage.constants.SuperType;
import mage.constants.Zone;
import mage.filter.common.FilterControlledCreaturePermanent;
import mage.filter.predicate.mageobject.ColorPredicate;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.game.permanent.Permanent;
import mage.target.TargetPermanent;
import mage.target.common.TargetControlledCreaturePermanent;
/**
*
* @author TheElk801 & L_J
*/
public class HazduhrTheAbbot extends CardImpl {
private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("white creature you control");
static {
filter.add(new ColorPredicate(ObjectColor.WHITE));
}
public HazduhrTheAbbot(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{W}{W}");
addSuperType(SuperType.LEGENDARY);
this.subtype.add(SubType.HUMAN);
this.subtype.add(SubType.CLERIC);
this.power = new MageInt(2);
this.toughness = new MageInt(5);
// {X}, {T}: The next X damage that would be dealt this turn to target white creature you control is dealt to Hazduhr the Abbot instead.
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new HazduhrTheAbbotRedirectDamageEffect(Duration.EndOfTurn), new ManaCostsImpl("{X}"));
ability.addCost(new TapSourceCost());
ability.addTarget(new TargetControlledCreaturePermanent(filter));
this.addAbility(ability);
}
public HazduhrTheAbbot(final HazduhrTheAbbot card) {
super(card);
}
@Override
public HazduhrTheAbbot copy() {
return new HazduhrTheAbbot(this);
}
}
class HazduhrTheAbbotRedirectDamageEffect extends RedirectionEffect {
private static FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent();
public HazduhrTheAbbotRedirectDamageEffect(Duration duration) {
super(duration, 0, true);
this.staticText = "The next X damage that would be dealt this turn to target white creature you control is dealt to {this} instead";
}
public HazduhrTheAbbotRedirectDamageEffect(final HazduhrTheAbbotRedirectDamageEffect effect) {
super(effect);
}
@Override
public void init(Ability source, Game game) {
amountToRedirect = source.getManaCostsToPay().getX();
}
@Override
public HazduhrTheAbbotRedirectDamageEffect copy() {
return new HazduhrTheAbbotRedirectDamageEffect(this);
}
@Override
public boolean applies(GameEvent event, Ability source, Game game) {
Permanent permanent = game.getBattlefield().getPermanent(source.getSourceId());
if (permanent != null) {
if (filter.match(permanent, permanent.getId(), permanent.getControllerId(), game)) {
if (event.getTargetId().equals(getTargetPointer().getFirst(game, source))) {
if (event.getTargetId() != null) {
TargetPermanent target = new TargetPermanent();
target.add(source.getSourceId(), game);
redirectTarget = target;
return true;
}
}
}
}
return false;
}
}

View file

@ -27,7 +27,6 @@
*/
package mage.cards.h;
import java.util.UUID;
import mage.MageObject;
import mage.abilities.Ability;
import mage.abilities.common.AsEntersBattlefieldAbility;
@ -35,12 +34,8 @@ import mage.abilities.common.BeginningOfUpkeepTriggeredAbility;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.ChooseCreatureTypeEffect;
import mage.abilities.effects.common.cost.SpellsCostReductionAllOfChosenSubtypeEffect;
import mage.cards.Card;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.cards.Cards;
import mage.cards.CardsImpl;
import mage.abilities.effects.common.cost.SpellsCostReductionControllerEffect;
import mage.cards.*;
import mage.constants.CardType;
import mage.constants.Outcome;
import mage.constants.TargetController;
@ -50,6 +45,8 @@ import mage.filter.predicate.mageobject.ChosenSubtypePredicate;
import mage.game.Game;
import mage.players.Player;
import java.util.UUID;
/**
*
* @author Saga
@ -64,7 +61,7 @@ public class HeraldsHorn extends CardImpl {
// Creature spells you cast of the chosen type cost {1} less to cast.
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD,
new SpellsCostReductionAllOfChosenSubtypeEffect(new FilterCreatureCard("Creature spells you cast of the chosen type"), 1)));
new SpellsCostReductionControllerEffect(new FilterCreatureCard("Creature spells you cast of the chosen type"), 1)));
// At the beginning of your upkeep, look at the top card of your library. If it's a creature card of the chosen type, you may reveal it and put it into your hand.
this.addAbility(new BeginningOfUpkeepTriggeredAbility(Zone.BATTLEFIELD, new HeraldsHornEffect(), TargetController.YOU, false));

View file

@ -112,6 +112,7 @@ class HeroismEffect extends OneShotEffect {
Cost cost = new ManaCostsImpl("{2}{R}");
List<Permanent> permanentsToPrevent = new ArrayList<>();
for (Permanent permanent : game.getState().getBattlefield().getAllActivePermanents(filter, player.getId(), game)) {
cost.clearPaid();
String message = "Pay " + cost.getText() + "? If you don't, " + permanent.getLogName() + "'s combat damage will be prevented this turn.";
if (player != null && player.chooseUse(Outcome.Neutral, message, source, game)) {
if (cost.pay(source, game, source.getSourceId(), player.getId(), false, null)) {

View file

@ -0,0 +1,76 @@
/*
* 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.SimpleActivatedAbility;
import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.costs.mana.GenericManaCost;
import mage.abilities.effects.common.combat.CantBeBlockedByAllTargetEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.constants.Duration;
import mage.constants.Zone;
import mage.filter.common.FilterCreaturePermanent;
import mage.filter.predicate.Predicates;
import mage.filter.predicate.mageobject.SubtypePredicate;
import mage.target.common.TargetCreaturePermanent;
/**
*
* @author L_J
*/
public class JovensTools extends CardImpl {
private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("except by walls");
static {
filter.add(Predicates.not(new SubtypePredicate(SubType.WALL)));
}
public JovensTools(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{6}");
// {4}, {T}: Target creature can't be blocked this turn except by Walls.
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new CantBeBlockedByAllTargetEffect(filter, Duration.EndOfTurn), new GenericManaCost(4));
ability.addCost(new TapSourceCost());
ability.addTarget(new TargetCreaturePermanent());
this.addAbility(ability);
}
public JovensTools(final JovensTools card) {
super(card);
}
@Override
public JovensTools copy() {
return new JovensTools(this);
}
}

View 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.k;
import java.util.UUID;
import mage.abilities.dynamicvalue.IntPlusDynamicValue;
import mage.abilities.dynamicvalue.common.CardsInAllGraveyardsCount;
import mage.abilities.effects.Effect;
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.filter.FilterCard;
import mage.filter.common.FilterCreaturePermanent;
import mage.filter.predicate.mageobject.NamePredicate;
/**
*
* @author L_J
*/
public class KjeldoranWarCry extends CardImpl {
private static final FilterCard filter = new FilterCard("cards named Kjeldoran War Cry");
static {
filter.add(new NamePredicate("Kjeldoran War Cry"));
}
public KjeldoranWarCry(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{1}{W}");
// Creatures you control get +X/+X until end of turn, where X is 1 plus the number of cards named Kjeldoran War Cry in all graveyards.
IntPlusDynamicValue value = new IntPlusDynamicValue(1, new CardsInAllGraveyardsCount(filter));
Effect effect = new BoostControlledEffect(value, value, Duration.EndOfTurn, new FilterCreaturePermanent("creatures"), false, true);
effect.setText("Creatures you control get +X/+X until end of turn, where X is 1 plus the number of cards named {source} in all graveyards");
this.getSpellAbility().addEffect(effect);
}
public KjeldoranWarCry(final KjeldoranWarCry card) {
super(card);
}
@Override
public KjeldoranWarCry copy() {
return new KjeldoranWarCry(this);
}
}

View file

@ -0,0 +1,135 @@
/*
* 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.common.BlocksOrBecomesBlockedTriggeredAbility;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.effects.common.AttachEffect;
import mage.abilities.effects.common.continuous.GainAbilityTargetEffect;
import mage.abilities.effects.common.continuous.LoseAbilityAttachedEffect;
import mage.abilities.keyword.EnchantAbility;
import mage.abilities.keyword.FirstStrikeAbility;
import mage.abilities.keyword.FlyingAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.AttachmentType;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.constants.Duration;
import mage.constants.Outcome;
import mage.constants.Zone;
import mage.filter.StaticFilters;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.game.permanent.Permanent;
import mage.target.TargetPermanent;
import mage.target.common.TargetCreaturePermanent;
import mage.target.targetpointer.FixedTarget;
/**
*
* @author L_J
*/
public class MammothHarness extends CardImpl {
public MammothHarness(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{3}{G}");
this.subtype.add(SubType.AURA);
// Enchant creature
TargetPermanent auraTarget = new TargetCreaturePermanent();
this.getSpellAbility().addTarget(auraTarget);
this.getSpellAbility().addEffect(new AttachEffect(Outcome.LoseAbility));
Ability ability = new EnchantAbility(auraTarget.getTargetName());
this.addAbility(ability);
// Enchanted creature loses flying.
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new LoseAbilityAttachedEffect(FlyingAbility.getInstance(), AttachmentType.AURA)));
// Whenever enchanted creature blocks or becomes blocked by a creature, the other creature gains first strike until end of turn.
this.addAbility(new MammothHarnessTriggeredAbility());
}
public MammothHarness(final MammothHarness card) {
super(card);
}
@Override
public MammothHarness copy() {
return new MammothHarness(this);
}
}
class MammothHarnessTriggeredAbility extends BlocksOrBecomesBlockedTriggeredAbility {
public MammothHarnessTriggeredAbility() {
super(new GainAbilityTargetEffect(FirstStrikeAbility.getInstance(), Duration.EndOfTurn), StaticFilters.FILTER_PERMANENT_CREATURE, false, null, false);
}
public MammothHarnessTriggeredAbility(final MammothHarnessTriggeredAbility ability) {
super(ability);
}
@Override
public boolean checkTrigger(GameEvent event, Game game) {
Permanent sourcePermanent = game.getPermanentOrLKIBattlefield(this.getSourceId());
if (sourcePermanent != null) {
Permanent attachedTo = game.getPermanentOrLKIBattlefield(sourcePermanent.getAttachedTo());
if (sourcePermanent != null) {
if (event.getSourceId().equals(attachedTo.getId())) {
Permanent blocked = game.getPermanent(event.getTargetId());
if (blocked != null && filter.match(blocked, game)) {
this.getEffects().setTargetPointer(new FixedTarget(event.getTargetId()));
return true;
}
}
if (event.getTargetId().equals(attachedTo.getId())) {
Permanent blocker = game.getPermanent(event.getSourceId());
if (blocker != null) {
this.getEffects().setTargetPointer(new FixedTarget(event.getSourceId()));
return true;
}
}
}
}
return false;
}
@Override
public String getRule() {
return " Whenever enchanted creature blocks or becomes blocked by a creature, the other creature gains first strike until end of turn.";
}
@Override
public MammothHarnessTriggeredAbility copy() {
return new MammothHarnessTriggeredAbility(this);
}
}

View file

@ -0,0 +1,172 @@
/*
* 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.common.EntersBattlefieldAbility;
import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.condition.common.SourceHasCounterCondition;
import mage.abilities.decorator.ConditionalContinuousRuleModifyingEffect;
import mage.abilities.costs.Cost;
import mage.abilities.costs.CostImpl;
import mage.abilities.effects.Effect;
import mage.abilities.effects.Effects;
import mage.abilities.effects.common.AttachEffect;
import mage.abilities.effects.common.DontUntapInControllersUntapStepEnchantedEffect;
import mage.abilities.effects.common.counter.AddCountersSourceEffect;
import mage.abilities.effects.common.counter.RemoveCounterSourceEffect;
import mage.abilities.keyword.EnchantAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.*;
import mage.counters.CounterType;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.target.TargetPermanent;
import mage.target.common.TargetCreaturePermanent;
/**
*
* @author L_J
*/
public class Merseine extends CardImpl {
public Merseine(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{2}{U}{U}");
this.subtype.add(SubType.AURA);
// Enchant creature
TargetPermanent auraTarget = new TargetCreaturePermanent();
this.getSpellAbility().addTarget(auraTarget);
this.getSpellAbility().addEffect(new AttachEffect(Outcome.Detriment));
this.addAbility(new EnchantAbility(auraTarget.getTargetName()));
// Merseine enters the battlefield with three net counters on it.
Effect effect = new AddCountersSourceEffect(CounterType.NET.createInstance(3));
effect.setText("with three net counters on it");
this.addAbility(new EntersBattlefieldAbility(effect));
// Enchanted creature doesn't untap during its controller's untap step if Merseine has a net counter on it.
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new ConditionalContinuousRuleModifyingEffect(new DontUntapInControllersUntapStepEnchantedEffect(),
new SourceHasCounterCondition(CounterType.NET)).setText("Enchanted creature doesn't untap during its controller's untap step if Merseine has a net counter on it")));
// Pay enchanted creature's mana cost: Remove a net counter from Merseine. Any player may activate this ability, but only if he or she controls the enchanted creature.
SimpleActivatedAbility ability = new MerseineActivatedAbility();
ability.setMayActivate(TargetController.ANY);
this.addAbility(ability);
}
public Merseine(final Merseine card) {
super(card);
}
@Override
public Merseine copy() {
return new Merseine(this);
}
}
class MerseineActivatedAbility extends SimpleActivatedAbility {
public MerseineActivatedAbility() {
super(Zone.BATTLEFIELD, new RemoveCounterSourceEffect(CounterType.NET.createInstance()), new MerseineCost());
}
private MerseineActivatedAbility(final MerseineActivatedAbility ability) {
super(ability);
}
@Override
public Effects getEffects(Game game, EffectType effectType) {
return super.getEffects(game, effectType);
}
@Override
public boolean canActivate(UUID playerId, Game game) {
Permanent sourcePermanent = game.getBattlefield().getPermanent(this.getSourceId());
if (sourcePermanent != null) {
Permanent attachedTo = game.getPermanent(sourcePermanent.getAttachedTo());
if (attachedTo != null) {
return super.canActivate(attachedTo.getControllerId(), game);
}
}
return false;
}
@Override
public MerseineActivatedAbility copy() {
return new MerseineActivatedAbility(this);
}
@Override
public String getRule() {
return "Pay enchanted creature's mana cost: Remove a net counter from Merseine. Any player may activate this ability, but only if he or she controls the enchanted creature.";
}
}
class MerseineCost extends CostImpl {
public MerseineCost() {
this.text = "Pay enchanted creature's mana cost";
}
public MerseineCost(final MerseineCost cost) {
super(cost);
}
@Override
public MerseineCost copy() {
return new MerseineCost(this);
}
@Override
public boolean canPay(Ability ability, UUID sourceId, UUID controllerId, Game game) {
Permanent sourcePermanent = game.getBattlefield().getPermanent(sourceId);
if (sourcePermanent != null) {
Permanent attachedTo = game.getPermanent(sourcePermanent.getAttachedTo());
if (attachedTo != null) {
return attachedTo.getManaCost().canPay(ability, sourceId, controllerId, game);
}
}
return false;
}
@Override
public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana, Cost costToPay) {
Permanent sourcePermanent = game.getBattlefield().getPermanent(sourceId);
if (sourcePermanent != null) {
Permanent attachedTo = game.getPermanent(sourcePermanent.getAttachedTo());
if (attachedTo != null) {
paid = attachedTo.getManaCost().pay(ability, game, sourceId, controllerId, noMana);
}
}
return paid;
}
}

View file

@ -0,0 +1,79 @@
/*
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
package mage.cards.p;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.common.BeginningOfUpkeepTriggeredAbility;
import mage.abilities.common.DiesTriggeredAbility;
import mage.abilities.condition.common.LiveLostLastTurnCondition;
import mage.abilities.decorator.ConditionalTriggeredAbility;
import mage.abilities.dynamicvalue.common.SourcePermanentToughnessValue;
import mage.abilities.effects.common.GainLifeEffect;
import mage.abilities.effects.common.counter.AddCountersSourceEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.constants.TargetController;
import mage.counters.CounterType;
/**
*
* @author LevelX2
*/
public class PaladinOfAtonement extends CardImpl {
public PaladinOfAtonement(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W}");
this.subtype.add(SubType.VAMPIRE);
this.subtype.add(SubType.KNIGHT);
this.power = new MageInt(1);
this.toughness = new MageInt(1);
// At the beginning of each upkeep, if you lost life last turn, put a +1/+1 counter on Paladin of Atonement.
this.addAbility(new ConditionalTriggeredAbility(
new BeginningOfUpkeepTriggeredAbility(new AddCountersSourceEffect(CounterType.P1P1.createInstance()), TargetController.ANY, false),
LiveLostLastTurnCondition.instance,
"At the beginning of each upkeep, if you lost life last turn, put a +1/+1 counter on {this}"));
// When Paladin of Atonement dies, you gain life equal to it's toughness.
this.addAbility(new DiesTriggeredAbility(new GainLifeEffect(SourcePermanentToughnessValue.getInstance(),
"you gain life equal to it's toughness")));
}
public PaladinOfAtonement(final PaladinOfAtonement card) {
super(card);
}
@Override
public PaladinOfAtonement copy() {
return new PaladinOfAtonement(this);
}
}

View file

@ -0,0 +1,164 @@
/*
* 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.r;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
import mage.ObjectColor;
import mage.abilities.Ability;
import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.costs.common.SacrificeTargetCost;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.CantBeTargetedSourceEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.Outcome;
import mage.constants.SubType;
import mage.constants.Zone;
import mage.filter.FilterObject;
import mage.filter.FilterStackObject;
import mage.filter.FilterPermanent;
import mage.filter.common.FilterControlledCreaturePermanent;
import mage.filter.predicate.Predicates;
import mage.filter.predicate.mageobject.ColorPredicate;
import mage.filter.predicate.mageobject.SubtypePredicate;
import mage.filter.predicate.permanent.TappedPredicate;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.players.Player;
import mage.target.Target;
import mage.target.TargetPermanent;
import mage.target.common.TargetControlledCreaturePermanent;
/**
*
* @author L_J
*/
public class RaidingParty extends CardImpl {
private static final FilterObject filterWhite = new FilterStackObject("white spells or abilities from white sources");
private static final FilterControlledCreaturePermanent filterOrc = new FilterControlledCreaturePermanent("an Orc");
static {
filterWhite.add(new ColorPredicate(ObjectColor.WHITE));
filterOrc.add(new SubtypePredicate(SubType.ORC));
}
public RaidingParty(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{2}{R}");
// Raiding Party can't be the target of white spells or abilities from white sources.
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new CantBeTargetedSourceEffect(filterWhite, Duration.WhileOnBattlefield)));
// Sacrifice an Orc: Each player may tap any number of untapped white creatures he or she controls. For each creature tapped this way, that player chooses up to two Plains. Then destroy all Plains that weren't chosen this way by any player.
this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new RaidingPartyEffect(), new SacrificeTargetCost(new TargetControlledCreaturePermanent(1,1, filterOrc, true))));
}
public RaidingParty(final RaidingParty card) {
super(card);
}
@Override
public RaidingParty copy() {
return new RaidingParty(this);
}
}
class RaidingPartyEffect extends OneShotEffect {
private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("untapped white creatures");
private static final FilterPermanent filter2 = new FilterPermanent("Plains");
static {
filter.add(Predicates.not(new TappedPredicate()));
filter.add(new ColorPredicate(ObjectColor.WHITE));
filter2.add(new SubtypePredicate(SubType.PLAINS));
}
RaidingPartyEffect() {
super(Outcome.Detriment);
staticText = "Each player may tap any number of untapped white creatures he or she controls. For each creature tapped this way, that player chooses up to two Plains. Then destroy all Plains that weren't chosen this way by any player";
}
RaidingPartyEffect(RaidingPartyEffect effect) {
super(effect);
}
@Override
public RaidingPartyEffect copy() {
return new RaidingPartyEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Permanent sourcePermanent = game.getPermanentOrLKIBattlefield(source.getSourceId());
if (sourcePermanent != null) {
Set<UUID> plainsToSave = new HashSet<>();
for (UUID playerId : game.getState().getPlayersInRange(source.getControllerId(), game)) {
Player player = game.getPlayer(playerId);
if (player != null) {
int countBattlefield = game.getBattlefield().getAllActivePermanents(filter, game.getActivePlayerId(), game).size();
int tappedCount = 0;
Target untappedCreatureTarget = new TargetControlledCreaturePermanent(0, Integer.MAX_VALUE, filter, true);
if (player.choose(Outcome.Benefit, untappedCreatureTarget, source.getSourceId(), game)) {
tappedCount = untappedCreatureTarget.getTargets().size();
for (UUID creatureId : untappedCreatureTarget.getTargets()) {
Permanent creature = game.getPermanentOrLKIBattlefield(creatureId);
if (creature != null) {
creature.tap(game);
}
}
}
if (tappedCount > 0) {
Target plainsToSaveTarget = new TargetPermanent(0, tappedCount * 2, filter2, true);
if (player.choose(Outcome.Benefit, plainsToSaveTarget, source.getSourceId(), game)) {
for (UUID plainsId : plainsToSaveTarget.getTargets()) {
plainsToSave.add(plainsId);
Permanent plains = game.getPermanent(plainsId);
if (plains != null) {
game.informPlayers(player.getLogName() + " chose " + plains.getLogName() + " to not be destroyed by " + sourcePermanent.getLogName());
}
}
}
}
}
}
for (Permanent plains : game.getBattlefield().getActivePermanents(filter2, source.getControllerId(), source.getSourceId(), game)) {
if (!plainsToSave.contains(plains.getId())) {
plains.destroy(source.getSourceId(), game, false);
}
}
return true;
}
return false;
}
}

View 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.r;
import java.util.UUID;
import mage.MageInt;
import mage.ObjectColor;
import mage.abilities.TriggeredAbilityImpl;
import mage.abilities.effects.Effect;
import mage.abilities.effects.common.continuous.BoostSourceEffect;
import mage.abilities.keyword.ReachAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.constants.Duration;
import mage.constants.SuperType;
import mage.constants.Zone;
import mage.filter.FilterPermanent;
import mage.filter.common.FilterCreaturePermanent;
import mage.filter.predicate.mageobject.ColorPredicate;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.game.permanent.Permanent;
/**
*
* @author L_J
*/
public class RashkaTheSlayer extends CardImpl {
private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("black creature");
static {
filter.add(new ColorPredicate(ObjectColor.BLACK));
}
public RashkaTheSlayer(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{W}{W}");
this.addSuperType(SuperType.LEGENDARY);
this.subtype.add(SubType.HUMAN);
this.subtype.add(SubType.ARCHER);
this.power = new MageInt(3);
this.toughness = new MageInt(3);
// Reach
this.addAbility(ReachAbility.getInstance());
// Whenever Rashka the Slayer blocks one or more black creatures, Rashka gets +1/+2 until end of turn.
this.addAbility(new RashkaTheSlayerTriggeredAbility(new BoostSourceEffect(1, 2, Duration.EndOfTurn), filter, false));
}
public RashkaTheSlayer(final RashkaTheSlayer card) {
super(card);
}
@Override
public RashkaTheSlayer copy() {
return new RashkaTheSlayer(this);
}
}
class RashkaTheSlayerTriggeredAbility extends TriggeredAbilityImpl {
protected FilterPermanent filter;
public RashkaTheSlayerTriggeredAbility(Effect effect, FilterPermanent filter, boolean optional) {
super(Zone.BATTLEFIELD, effect, optional);
this.filter = filter;
}
public RashkaTheSlayerTriggeredAbility(final RashkaTheSlayerTriggeredAbility ability) {
super(ability);
this.filter = ability.filter;
}
@Override
public boolean checkEventType(GameEvent event, Game game) {
return event.getType() == GameEvent.EventType.BLOCKER_DECLARED;
}
@Override
public boolean checkTrigger(GameEvent event, Game game) {
if (event.getSourceId().equals(this.getSourceId())) {
Permanent blocked = game.getPermanent(event.getTargetId());
if (blocked != null && filter.match(blocked, game)) {
return true;
}
}
return false;
}
@Override
public String getRule() {
return "Whenever {this} blocks a " + filter.getMessage() + ", " + super.getRule();
}
@Override
public RashkaTheSlayerTriggeredAbility copy() {
return new RashkaTheSlayerTriggeredAbility(this);
}
}

View file

@ -62,7 +62,7 @@ public class TheImmortalSun extends CardImpl {
this.addSuperType(SuperType.LEGENDARY);
// Players can't activate loyalty abilities of planeswalkers.
// Players can't activate planeswalkers' loyalty abilities.
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new TheImmortalSunCantActivateEffect()));
// At the beginning of your draw step, draw an additional card.
this.addAbility(new BeginningOfDrawTriggeredAbility(new DrawCardSourceControllerEffect(1), TargetController.YOU, false));
@ -86,7 +86,7 @@ class TheImmortalSunCantActivateEffect extends ContinuousRuleModifyingEffectImpl
public TheImmortalSunCantActivateEffect() {
super(Duration.WhileOnBattlefield, Outcome.Detriment);
staticText = "Players can't activate loyalty abilities of planeswalkers";
staticText = "Players can't activate planeswalkers' loyalty abilities";
}
public TheImmortalSunCantActivateEffect(final TheImmortalSunCantActivateEffect effect) {

View file

@ -0,0 +1,126 @@
/*
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
package mage.cards.t;
import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.common.BeginningOfUpkeepTriggeredAbility;
import mage.abilities.common.EntersBattlefieldAllTriggeredAbility;
import mage.abilities.costs.CostImpl;
import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.SacrificeSourceUnlessPaysEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.constants.Outcome;
import mage.constants.SetTargetPointer;
import mage.constants.TargetController;
import mage.constants.Zone;
import mage.counters.CounterType;
import mage.filter.FilterPermanent;
import mage.filter.predicate.mageobject.SubtypePredicate;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.players.Player;
import mage.target.common.TargetControlledCreaturePermanent;
/**
*
* @author L_J
*/
public class ThelonsChant extends CardImpl {
private static final FilterPermanent filter = new FilterPermanent("a Swamp");
static{
filter.add(new SubtypePredicate(SubType.SWAMP));
}
public ThelonsChant(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{G}{G}");
// At the beginning of your upkeep, sacrifice Thelon's Chant unless you pay {G}.
this.addAbility(new BeginningOfUpkeepTriggeredAbility(new SacrificeSourceUnlessPaysEffect(new ManaCostsImpl("{G}")), TargetController.YOU, false));
// Whenever a player puts a Swamp onto the battlefield, Thelon's Chant deals 3 damage to that player unless he or she puts a -1/-1 counter on a creature he or she controls.
this.addAbility(new EntersBattlefieldAllTriggeredAbility(Zone.BATTLEFIELD, new ThelonsChantEffect(), filter, false, SetTargetPointer.PLAYER,
"Whenever a player puts a Swamp onto the battlefield, {this} deals 3 damage to that player unless he or she puts a -1/-1 counter on a creature he or she controls."));
}
public ThelonsChant(final ThelonsChant card) {
super(card);
}
@Override
public ThelonsChant copy() {
return new ThelonsChant(this);
}
}
class ThelonsChantEffect extends OneShotEffect {
public ThelonsChantEffect() {
super(Outcome.Damage);
staticText = "{this} deals 3 damage to that player unless he or she puts a -1/-1 counter on a creature he or she controls";
}
public ThelonsChantEffect(final ThelonsChantEffect effect) {
super(effect);
}
@Override
public ThelonsChantEffect copy() {
return new ThelonsChantEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Player player = game.getPlayer(targetPointer.getFirst(game, source));
Permanent sourcePermanent = game.getPermanentOrLKIBattlefield(source.getSourceId());
if (player != null && sourcePermanent != null) {
boolean paid = false;
TargetControlledCreaturePermanent target = new TargetControlledCreaturePermanent();
target.setNotTarget(true);
if (player.chooseUse(Outcome.Detriment, "Put a -1/-1 counter on a creature you control? (otherwise " + sourcePermanent.getLogName() + " deals 3 damage to you)", source, game)
&& player.choose(Outcome.UnboostCreature, target, source.getSourceId(), game)) {
Permanent permanent = game.getPermanent(target.getFirstTarget());
if (permanent != null) {
permanent.addCounters(CounterType.M1M1.createInstance(), source, game);
paid = true;
}
}
if (!paid) {
player.damage(3, source.getSourceId(), game, false, true);
}
return true;
}
return false;
}
}

View file

@ -0,0 +1,129 @@
/*
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
package mage.cards.t;
import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.Mode;
import mage.abilities.effects.ContinuousEffectImpl;
import mage.abilities.common.delayed.AtTheBeginOfNextUpkeepDelayedTriggeredAbility;
import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect;
import mage.abilities.effects.common.DrawCardSourceControllerEffect;
import mage.constants.SuperType;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.Layer;
import mage.constants.Outcome;
import mage.constants.SubLayer;
import mage.filter.FilterPermanent;
import mage.filter.predicate.Predicates;
import mage.filter.predicate.mageobject.SupertypePredicate;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.target.TargetPermanent;
/**
*
* @author TheElk801 & L_J
*/
public class ThermalFlux extends CardImpl {
private static final FilterPermanent filterNonsnow = new FilterPermanent("nonsnow permanent");
private static final FilterPermanent filterSnow = new FilterPermanent("snow permanent");
static {
filterNonsnow.add(Predicates.not(new SupertypePredicate(SuperType.SNOW)));
filterSnow.add(new SupertypePredicate(SuperType.SNOW));
}
public ThermalFlux(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{U}");
// Choose one -
// Target nonsnow permanent becomes snow until end of turn.
// Draw a card at the beginning of the next turn's upkeep.
this.getSpellAbility().addTarget(new TargetPermanent(filterNonsnow));
this.getSpellAbility().addEffect(new ThermalFluxEffect(true));
this.getSpellAbility().addEffect(new CreateDelayedTriggeredAbilityEffect(
new AtTheBeginOfNextUpkeepDelayedTriggeredAbility(new DrawCardSourceControllerEffect(1)), false));
// Target snow permanent isn't snow until end of turn.
// Draw a card at the beginning of the next turn's upkeep.
Mode mode = new Mode();
mode.getTargets().add(new TargetPermanent(filterSnow));
mode.getEffects().add(new ThermalFluxEffect(false));
mode.getEffects().add(new CreateDelayedTriggeredAbilityEffect(
new AtTheBeginOfNextUpkeepDelayedTriggeredAbility(new DrawCardSourceControllerEffect(1)), false));
this.getSpellAbility().addMode(mode);
}
public ThermalFlux(final ThermalFlux card) {
super(card);
}
@Override
public ThermalFlux copy() {
return new ThermalFlux(this);
}
}
class ThermalFluxEffect extends ContinuousEffectImpl {
private final boolean addSnow;
public ThermalFluxEffect(boolean addSnow) {
super(Duration.EndOfTurn, Layer.TypeChangingEffects_4, SubLayer.NA, Outcome.Detriment);
this.addSnow = addSnow;
this.staticText = "Target " + (addSnow ? "non" : "") + "snow permanent " + (addSnow ? "becomes" : "isn't") + " snow until end of turn";
}
public ThermalFluxEffect(final ThermalFluxEffect effect) {
super(effect);
this.addSnow = effect.addSnow;
}
@Override
public ThermalFluxEffect copy() {
return new ThermalFluxEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Permanent permanent = game.getPermanent(source.getFirstTarget());
if (permanent != null) {
if (addSnow) {
permanent.addSuperType(SuperType.SNOW);
} else {
permanent.getSuperType().remove(SuperType.SNOW);
}
}
return true;
}
}

View file

@ -0,0 +1,144 @@
/*
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
package mage.cards.t;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.costs.Cost;
import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.effects.ContinuousEffect;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.continuous.GainAbilityTargetEffect;
import mage.abilities.keyword.FirstStrikeAbility;
import mage.abilities.keyword.FlyingAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.Outcome;
import mage.constants.Zone;
import mage.filter.common.FilterAttackingCreature;
import mage.filter.predicate.Predicates;
import mage.filter.predicate.mageobject.AbilityPredicate;
import mage.game.Game;
import mage.game.combat.CombatGroup;
import mage.game.permanent.Permanent;
import mage.players.Player;
import mage.target.targetpointer.FixedTarget;
/**
*
* @author L_J
*/
public class TidalFlats extends CardImpl {
public TidalFlats(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{U}");
// {U}{U}: For each attacking creature without flying, its controller may pay {1}. If he or she doesn't, creatures you control blocking that creature gain first strike until end of turn.
this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new TidalFlatsEffect(), new ManaCostsImpl("{U}{U}")));
}
public TidalFlats(final TidalFlats card) {
super(card);
}
@Override
public TidalFlats copy() {
return new TidalFlats(this);
}
}
class TidalFlatsEffect extends OneShotEffect {
private static final FilterAttackingCreature filter = new FilterAttackingCreature("attacking creature without flying");
static {
filter.add(Predicates.not(new AbilityPredicate(FlyingAbility.class)));
}
public TidalFlatsEffect() {
super(Outcome.Benefit);
this.staticText = "For each attacking creature without flying, its controller may pay {1}. If he or she doesn't, creatures you control blocking that creature gain first strike until end of turn";
}
public TidalFlatsEffect(final TidalFlatsEffect effect) {
super(effect);
}
@Override
public TidalFlatsEffect copy() {
return new TidalFlatsEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
game.getPlayerList();
Player controller = game.getPlayer(source.getControllerId());
if (controller != null) {
Player player = game.getPlayer(game.getActivePlayerId());
Cost cost = new ManaCostsImpl("{1}");
List<Permanent> affectedPermanents = new ArrayList<>();
for (Permanent permanent : game.getState().getBattlefield().getAllActivePermanents(filter, player.getId(), game)) {
cost.clearPaid();
String message = "Pay " + cost.getText() + " for " + permanent.getLogName() + "? If you don't, creatures " + controller.getLogName() + " controls blocking it gain first strike until end of turn.";
if (player != null && player.chooseUse(Outcome.Benefit, message, source, game)) {
if (cost.pay(source, game, source.getSourceId(), player.getId(), false, null)) {
game.informPlayers(player.getLogName() + " paid " + cost.getText() + " for " + permanent.getLogName());
continue;
} else {
game.informPlayers(player.getLogName() + " didn't pay " + cost.getText() + " for " + permanent.getLogName());
affectedPermanents.add(permanent);
}
} else {
game.informPlayers(player.getLogName() + " didn't pay " + cost.getText() + " for " + permanent.getLogName());
affectedPermanents.add(permanent);
}
}
for (Permanent permanent : affectedPermanents) {
CombatGroup group = game.getCombat().findGroup(permanent.getId());
if (group != null) {
for (UUID blockerId : group.getBlockers()) {
Permanent blocker = game.getPermanent(blockerId);
if (blocker != null && blocker.getControllerId() == controller.getId()) {
ContinuousEffect effect = new GainAbilityTargetEffect(FirstStrikeAbility.getInstance(), Duration.EndOfTurn);
effect.setTargetPointer(new FixedTarget(blocker.getId()));
game.addEffect(effect, source);
}
}
}
}
return true;
}
return false;
}
}

View file

@ -0,0 +1,126 @@
/*
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
package mage.cards.t;
import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.common.BeginningOfUpkeepTriggeredAbility;
import mage.abilities.common.EntersBattlefieldAllTriggeredAbility;
import mage.abilities.costs.CostImpl;
import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.SacrificeSourceUnlessPaysEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.constants.Outcome;
import mage.constants.SetTargetPointer;
import mage.constants.TargetController;
import mage.constants.Zone;
import mage.counters.CounterType;
import mage.filter.FilterPermanent;
import mage.filter.predicate.mageobject.SubtypePredicate;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.players.Player;
import mage.target.common.TargetControlledCreaturePermanent;
/**
*
* @author L_J
*/
public class TourachsChant extends CardImpl {
private static final FilterPermanent filter = new FilterPermanent("a Forest");
static{
filter.add(new SubtypePredicate(SubType.FOREST));
}
public TourachsChant(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{B}{B}");
// At the beginning of your upkeep, sacrifice Tourach's Chant unless you pay {B}.
this.addAbility(new BeginningOfUpkeepTriggeredAbility(new SacrificeSourceUnlessPaysEffect(new ManaCostsImpl("{B}")), TargetController.YOU, false));
// Whenever a player puts a Forest onto the battlefield, Tourach's Chant deals 3 damage to that player unless he or she puts a -1/-1 counter on a creature he or she controls.
this.addAbility(new EntersBattlefieldAllTriggeredAbility(Zone.BATTLEFIELD, new TourachsChantEffect(), filter, false, SetTargetPointer.PLAYER,
"Whenever a player puts a Forest onto the battlefield, {this} deals 3 damage to that player unless he or she puts a -1/-1 counter on a creature he or she controls."));
}
public TourachsChant(final TourachsChant card) {
super(card);
}
@Override
public TourachsChant copy() {
return new TourachsChant(this);
}
}
class TourachsChantEffect extends OneShotEffect {
public TourachsChantEffect() {
super(Outcome.Damage);
staticText = "{this} deals 3 damage to that player unless he or she puts a -1/-1 counter on a creature he or she controls";
}
public TourachsChantEffect(final TourachsChantEffect effect) {
super(effect);
}
@Override
public TourachsChantEffect copy() {
return new TourachsChantEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Player player = game.getPlayer(targetPointer.getFirst(game, source));
Permanent sourcePermanent = game.getPermanentOrLKIBattlefield(source.getSourceId());
if (player != null && sourcePermanent != null) {
boolean paid = false;
TargetControlledCreaturePermanent target = new TargetControlledCreaturePermanent();
target.setNotTarget(true);
if (player.chooseUse(Outcome.Detriment, "Put a -1/-1 counter on a creature you control? (otherwise " + sourcePermanent.getLogName() + " deals 3 damage to you)", source, game)
&& player.choose(Outcome.UnboostCreature, target, source.getSourceId(), game)) {
Permanent permanent = game.getPermanent(target.getFirstTarget());
if (permanent != null) {
permanent.addCounters(CounterType.M1M1.createInstance(), source, game);
paid = true;
}
}
if (!paid) {
player.damage(3, source.getSourceId(), game, false, true);
}
return true;
}
return false;
}
}

View file

@ -51,7 +51,7 @@ import mage.target.common.TargetControlledCreaturePermanent;
public class Victimize extends CardImpl {
public Victimize(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{2}{B}");
super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{B}");
// Choose two target creature cards in your graveyard. Sacrifice a creature. If you do, return the chosen cards to the battlefield tapped.
this.getSpellAbility().addEffect(new VictimizeEffect());
@ -90,6 +90,7 @@ class VictimizeEffect extends OneShotEffect {
if (controller != null) {
SacrificeTargetCost cost = new SacrificeTargetCost(new TargetControlledCreaturePermanent(new FilterControlledCreaturePermanent("a creature")));
if (cost.pay(source, game, source.getSourceId(), source.getControllerId(), false, null)) {
game.applyEffects(); // To end effects of the sacrificed creature
controller.moveCards(new CardsImpl(getTargetPointer().getTargets(game, source)).getCards(game),
Zone.BATTLEFIELD, source, game, true, false, false, null);
}

View file

@ -0,0 +1,190 @@
/*
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
package mage.cards.v;
import java.util.UUID;
import mage.MageInt;
import mage.MageObject;
import mage.abilities.Ability;
import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.costs.Cost;
import mage.abilities.costs.CostImpl;
import mage.abilities.effects.ReplacementEffectImpl;
import mage.abilities.effects.common.continuous.BoostSourceEffect;
import mage.abilities.keyword.TrampleAbility;
import mage.cards.Card;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.cards.Cards;
import mage.constants.*;
import mage.filter.FilterCard;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.game.events.ZoneChangeEvent;
import mage.game.permanent.Permanent;
import mage.players.Player;
import mage.target.common.TargetCardInExile;
import mage.util.CardUtil;
/**
* @author jeffwadsworth & L_J
*/
public class VoidMaw extends CardImpl {
public VoidMaw(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{B}{B}");
this.subtype.add(SubType.HORROR);
this.power = new MageInt(4);
this.toughness = new MageInt(5);
// Trample
this.addAbility(TrampleAbility.getInstance());
// If another creature would die, exile it instead.
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new VoidMawEffect()));
// Put a card exiled with Void Maw into its owner's graveyard: Void Maw gets +2/+2 until end of turn.
this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new BoostSourceEffect(2, 2, Duration.EndOfTurn), new VoidMawCost()));
}
public VoidMaw(final VoidMaw card) {
super(card);
}
@Override
public VoidMaw copy() {
return new VoidMaw(this);
}
}
class VoidMawEffect extends ReplacementEffectImpl {
public VoidMawEffect() {
super(Duration.WhileOnBattlefield, Outcome.Benefit);
staticText = "If another creature would die, exile it instead";
}
public VoidMawEffect(final VoidMawEffect effect) {
super(effect);
}
@Override
public VoidMawEffect copy() {
return new VoidMawEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
return true;
}
@Override
public boolean replaceEvent(GameEvent event, Ability source, Game game) {
Player controller = game.getPlayer(source.getControllerId());
MageObject sourceObject = source.getSourceObject(game);
if (controller != null && sourceObject != null) {
if (((ZoneChangeEvent) event).getFromZone() == Zone.BATTLEFIELD) {
Permanent permanent = ((ZoneChangeEvent) event).getTarget();
if (permanent != null) {
UUID exileZoneId = CardUtil.getCardExileZoneId(game, source);
if (controller.moveCardsToExile(permanent, source, game, false, exileZoneId, sourceObject.getIdName())) {
return true;
}
}
}
}
return false;
}
@Override
public boolean checksEventType(GameEvent event, Game game) {
return event.getType() == GameEvent.EventType.ZONE_CHANGE;
}
@Override
public boolean applies(GameEvent event, Ability source, Game game) {
ZoneChangeEvent zEvent = (ZoneChangeEvent) event;
if (zEvent.getToZone() == Zone.GRAVEYARD) {
Permanent permanent = ((ZoneChangeEvent) event).getTarget();
if (permanent != null && permanent.getId() != source.getSourceId()) {
if (zEvent.getTarget() != null) { // if it comes from permanent, check if it was a creature on the battlefield
if (zEvent.getTarget().isCreature()) {
return true;
}
} else if (permanent.isCreature()) {
return true;
}
}
}
return false;
}
}
class VoidMawCost extends CostImpl {
public VoidMawCost() {
this.text = "Put a card exiled with {this} into its owner's graveyard";
}
public VoidMawCost(VoidMawCost cost) {
super(cost);
}
@Override
public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana, Cost costToPay) {
Player controller = game.getPlayer(controllerId);
if (controller != null) {
TargetCardInExile target = new TargetCardInExile(new FilterCard(), CardUtil.getCardExileZoneId(game, ability));
target.setNotTarget(true);
Cards cards = game.getExile().getExileZone(CardUtil.getCardExileZoneId(game, ability));
if (!cards.isEmpty()
&& controller.choose(Outcome.Benefit, cards, target, game)) {
Card card = game.getCard(target.getFirstTarget());
if (card != null) {
if (controller.moveCardToGraveyardWithInfo(card, sourceId, game, Zone.EXILED)) {
paid = true;
}
}
}
}
return paid;
}
@Override
public boolean canPay(Ability ability, UUID sourceId, UUID controllerId, Game game) {
Player player = game.getPlayer(controllerId);
return player != null;
}
@Override
public VoidMawCost copy() {
return new VoidMawCost(this);
}
}

View file

@ -87,6 +87,7 @@ public class Coldsnap extends ExpansionSet {
cards.add(new SetCardInfo("Disciple of Tevesh Szat", 55, Rarity.COMMON, mage.cards.d.DiscipleOfTeveshSzat.class));
cards.add(new SetCardInfo("Drelnoch", 32, Rarity.COMMON, mage.cards.d.Drelnoch.class));
cards.add(new SetCardInfo("Earthen Goo", 80, Rarity.UNCOMMON, mage.cards.e.EarthenGoo.class));
cards.add(new SetCardInfo("Feast of Flesh", 56, Rarity.COMMON, mage.cards.f.FeastOfFlesh.class));
cards.add(new SetCardInfo("Field Marshal", 5, Rarity.RARE, mage.cards.f.FieldMarshal.class));
cards.add(new SetCardInfo("Flashfreeze", 33, Rarity.UNCOMMON, mage.cards.f.Flashfreeze.class));
cards.add(new SetCardInfo("Freyalise's Radiance", 108, Rarity.UNCOMMON, mage.cards.f.FreyalisesRadiance.class));
@ -123,6 +124,7 @@ public class Coldsnap extends ExpansionSet {
cards.add(new SetCardInfo("Kjeldoran Gargoyle", 10, Rarity.UNCOMMON, mage.cards.k.KjeldoranGargoyle.class));
cards.add(new SetCardInfo("Kjeldoran Javelineer", 11, Rarity.COMMON, mage.cards.k.KjeldoranJavelineer.class));
cards.add(new SetCardInfo("Kjeldoran Outrider", 12, Rarity.COMMON, mage.cards.k.KjeldoranOutrider.class));
cards.add(new SetCardInfo("Kjeldoran War Cry", 13, Rarity.COMMON, mage.cards.k.KjeldoranWarCry.class));
cards.add(new SetCardInfo("Krovikan Mist", 38, Rarity.COMMON, mage.cards.k.KrovikanMist.class));
cards.add(new SetCardInfo("Krovikan Rot", 63, Rarity.UNCOMMON, mage.cards.k.KrovikanRot.class));
cards.add(new SetCardInfo("Krovikan Scoundrel", 64, Rarity.COMMON, mage.cards.k.KrovikanScoundrel.class));
@ -189,6 +191,7 @@ public class Coldsnap extends ExpansionSet {
cards.add(new SetCardInfo("Survivor of the Unseen", 48, Rarity.COMMON, mage.cards.s.SurvivorOfTheUnseen.class));
cards.add(new SetCardInfo("Swift Maneuver", 21, Rarity.COMMON, mage.cards.s.SwiftManeuver.class));
cards.add(new SetCardInfo("Tamanoa", 132, Rarity.RARE, mage.cards.t.Tamanoa.class));
cards.add(new SetCardInfo("Thermal Flux", 49, Rarity.COMMON, mage.cards.t.ThermalFlux.class));
cards.add(new SetCardInfo("Thermopod", 100, Rarity.COMMON, mage.cards.t.Thermopod.class));
cards.add(new SetCardInfo("Thrumming Stone", 142, Rarity.RARE, mage.cards.t.ThrummingStone.class));
cards.add(new SetCardInfo("Tresserhorn Sinks", 150, Rarity.UNCOMMON, mage.cards.t.TresserhornSinks.class));
@ -196,6 +199,7 @@ public class Coldsnap extends ExpansionSet {
cards.add(new SetCardInfo("Ursine Fylgja", 22, Rarity.UNCOMMON, mage.cards.u.UrsineFylgja.class));
cards.add(new SetCardInfo("Vanish into Memory", 133, Rarity.UNCOMMON, mage.cards.v.VanishIntoMemory.class));
cards.add(new SetCardInfo("Vexing Sphinx", 50, Rarity.RARE, mage.cards.v.VexingSphinx.class));
cards.add(new SetCardInfo("Void Maw", 74, Rarity.RARE, mage.cards.v.VoidMaw.class));
cards.add(new SetCardInfo("Wall of Shards", 23, Rarity.UNCOMMON, mage.cards.w.WallOfShards.class));
cards.add(new SetCardInfo("White Shield Crusader", 24, Rarity.UNCOMMON, mage.cards.w.WhiteShieldCrusader.class));
cards.add(new SetCardInfo("Wilderness Elemental", 134, Rarity.UNCOMMON, mage.cards.w.WildernessElemental.class));

View file

@ -188,6 +188,10 @@ public class FallenEmpires extends ExpansionSet {
cards.add(new SetCardInfo("Initiates of the Ebon Hand", 16, Rarity.COMMON, InitiatesOfTheEbonHand.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Initiates of the Ebon Hand", 17, Rarity.COMMON, InitiatesOfTheEbonHand.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Initiates of the Ebon Hand", 18, Rarity.COMMON, InitiatesOfTheEbonHand.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Merseine", 47, Rarity.COMMON, mage.cards.m.Merseine.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Merseine", 48, Rarity.COMMON, mage.cards.m.Merseine.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Merseine", 49, Rarity.COMMON, mage.cards.m.Merseine.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Merseine", 50, Rarity.COMMON, mage.cards.m.Merseine.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Mindstab Thrull", 19, Rarity.COMMON, MindstabThrull.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Mindstab Thrull", 20, Rarity.COMMON, MindstabThrull.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Mindstab Thrull", 21, Rarity.COMMON, MindstabThrull.class, NON_FULL_USE_VARIOUS));
@ -212,6 +216,7 @@ public class FallenEmpires extends ExpansionSet {
cards.add(new SetCardInfo("Order of the Ebon Hand", 26, Rarity.COMMON, OrderOfTheEbonHand.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Order of the Ebon Hand", 27, Rarity.COMMON, OrderOfTheEbonHand.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Orgg", 131, Rarity.RARE, mage.cards.o.Orgg.class));
cards.add(new SetCardInfo("Raiding Party", 132, Rarity.UNCOMMON, mage.cards.r.RaidingParty.class));
cards.add(new SetCardInfo("Rainbow Vale", 184, Rarity.RARE, mage.cards.r.RainbowVale.class));
cards.add(new SetCardInfo("Ring of Renewal", 174, Rarity.RARE, mage.cards.r.RingOfRenewal.class));
cards.add(new SetCardInfo("River Merfolk", 51, Rarity.RARE, mage.cards.r.RiverMerfolk.class));
@ -233,6 +238,7 @@ public class FallenEmpires extends ExpansionSet {
cards.add(new SetCardInfo("Thallid Devourer", 91, Rarity.UNCOMMON, mage.cards.t.ThallidDevourer.class));
cards.add(new SetCardInfo("Thelonite Druid", 92, Rarity.UNCOMMON, mage.cards.t.TheloniteDruid.class));
cards.add(new SetCardInfo("Thelonite Monk", 93, Rarity.RARE, mage.cards.t.TheloniteMonk.class));
cards.add(new SetCardInfo("Thelon's Chant", 94, Rarity.UNCOMMON, mage.cards.t.ThelonsChant.class));
cards.add(new SetCardInfo("Thelon's Curse", 95, Rarity.RARE, mage.cards.t.ThelonsCurse.class));
cards.add(new SetCardInfo("Thorn Thallid", 96, Rarity.COMMON, ThornThallid.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Thorn Thallid", 97, Rarity.COMMON, ThornThallid.class, NON_FULL_USE_VARIOUS));
@ -241,7 +247,11 @@ public class FallenEmpires extends ExpansionSet {
cards.add(new SetCardInfo("Thrull Champion", 29, Rarity.RARE, mage.cards.t.ThrullChampion.class));
cards.add(new SetCardInfo("Thrull Retainer", 30, Rarity.UNCOMMON, mage.cards.t.ThrullRetainer.class));
cards.add(new SetCardInfo("Thrull Wizard", 31, Rarity.UNCOMMON, mage.cards.t.ThrullWizard.class));
cards.add(new SetCardInfo("Tidal Flats", 54, Rarity.COMMON, mage.cards.t.TidalFlats.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Tidal Flats", 55, Rarity.COMMON, mage.cards.t.TidalFlats.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Tidal Flats", 56, Rarity.COMMON, mage.cards.t.TidalFlats.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Tidal Influence", 57, Rarity.UNCOMMON, mage.cards.t.TidalInfluence.class));
cards.add(new SetCardInfo("Tourach's Chant", 32, Rarity.UNCOMMON, mage.cards.t.TourachsChant.class));
cards.add(new SetCardInfo("Tourach's Gate", 33, Rarity.RARE, mage.cards.t.TourachsGate.class));
cards.add(new SetCardInfo("Vodalian Knights", 58, Rarity.RARE, mage.cards.v.VodalianKnights.class));
cards.add(new SetCardInfo("Vodalian Mage", 59, Rarity.COMMON, VodalianMage.class, NON_FULL_USE_VARIOUS));

View file

@ -80,6 +80,7 @@ public class FifthEdition extends ExpansionSet {
cards.add(new SetCardInfo("Brainwash", 289, Rarity.COMMON, mage.cards.b.Brainwash.class));
cards.add(new SetCardInfo("Brassclaw Orcs", 213, Rarity.COMMON, BrassclawOrcs.class));
cards.add(new SetCardInfo("Breeding Pit", 10, Rarity.UNCOMMON, mage.cards.b.BreedingPit.class));
cards.add(new SetCardInfo("Broken Visage", 11, Rarity.RARE, mage.cards.b.BrokenVisage.class));
cards.add(new SetCardInfo("Brothers of Fire", 214, Rarity.COMMON, mage.cards.b.BrothersOfFire.class));
cards.add(new SetCardInfo("Brushland", 412, Rarity.RARE, mage.cards.b.Brushland.class));
cards.add(new SetCardInfo("Carapace", 143, Rarity.COMMON, mage.cards.c.Carapace.class));
@ -242,6 +243,7 @@ public class FifthEdition extends ExpansionSet {
cards.add(new SetCardInfo("Jester's Cap", 385, Rarity.RARE, mage.cards.j.JestersCap.class));
cards.add(new SetCardInfo("Johtull Wurm", 168, Rarity.UNCOMMON, mage.cards.j.JohtullWurm.class));
cards.add(new SetCardInfo("Jokulhaups", 246, Rarity.RARE, mage.cards.j.Jokulhaups.class));
cards.add(new SetCardInfo("Joven's Tools", 386, Rarity.UNCOMMON, mage.cards.j.JovensTools.class));
cards.add(new SetCardInfo("Justice", 317, Rarity.UNCOMMON, mage.cards.j.Justice.class));
cards.add(new SetCardInfo("Juxtapose", 95, Rarity.RARE, mage.cards.j.Juxtapose.class));
cards.add(new SetCardInfo("Karma", 318, Rarity.UNCOMMON, mage.cards.k.Karma.class));

View file

@ -83,6 +83,8 @@ public class Homelands extends ExpansionSet {
cards.add(new SetCardInfo("An-Havva Inn", 52, Rarity.UNCOMMON, mage.cards.a.AnHavvaInn.class));
cards.add(new SetCardInfo("An-Havva Township", 136, Rarity.UNCOMMON, mage.cards.a.AnHavvaTownship.class));
cards.add(new SetCardInfo("An-Zerrin Ruins", 87, Rarity.RARE, mage.cards.a.AnZerrinRuins.class));
cards.add(new SetCardInfo("Apocalypse Chime", 126, Rarity.RARE, mage.cards.a.ApocalypseChime.class));
cards.add(new SetCardInfo("Autumn Willow", 53, Rarity.RARE, mage.cards.a.AutumnWillow.class));
cards.add(new SetCardInfo("Aysen Abbey", 137, Rarity.UNCOMMON, mage.cards.a.AysenAbbey.class));
cards.add(new SetCardInfo("Aysen Bureaucrats", 104, Rarity.COMMON, mage.cards.a.AysenBureaucrats.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Aysen Bureaucrats", 105, Rarity.COMMON, mage.cards.a.AysenBureaucrats.class, NON_FULL_USE_VARIOUS));
@ -91,6 +93,7 @@ public class Homelands extends ExpansionSet {
cards.add(new SetCardInfo("Baki's Curse", 27, Rarity.RARE, mage.cards.b.BakisCurse.class));
cards.add(new SetCardInfo("Baron Sengir", 1, Rarity.RARE, mage.cards.b.BaronSengir.class));
cards.add(new SetCardInfo("Black Carriage", 2, Rarity.RARE, mage.cards.b.BlackCarriage.class));
cards.add(new SetCardInfo("Broken Visage", 3, Rarity.RARE, mage.cards.b.BrokenVisage.class));
cards.add(new SetCardInfo("Carapace", 54, Rarity.COMMON, mage.cards.c.Carapace.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Carapace", 55, Rarity.COMMON, mage.cards.c.Carapace.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Castle Sengir", 138, Rarity.UNCOMMON, mage.cards.c.CastleSengir.class));
@ -124,6 +127,7 @@ public class Homelands extends ExpansionSet {
cards.add(new SetCardInfo("Forget", 32, Rarity.RARE, mage.cards.f.Forget.class));
cards.add(new SetCardInfo("Ghost Hounds", 12, Rarity.UNCOMMON, mage.cards.g.GhostHounds.class));
cards.add(new SetCardInfo("Grandmother Sengir", 13, Rarity.RARE, mage.cards.g.GrandmotherSengir.class));
cards.add(new SetCardInfo("Hazduhr the Abbot", 110, Rarity.RARE, mage.cards.h.HazduhrTheAbbot.class));
cards.add(new SetCardInfo("Headstone", 15, Rarity.COMMON, mage.cards.h.Headstone.class));
cards.add(new SetCardInfo("Hungry Mist", 60, Rarity.COMMON, mage.cards.h.HungryMist.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Hungry Mist", 61, Rarity.COMMON, mage.cards.h.HungryMist.class, NON_FULL_USE_VARIOUS));
@ -131,11 +135,13 @@ public class Homelands extends ExpansionSet {
cards.add(new SetCardInfo("Irini Sengir", 17, Rarity.UNCOMMON, mage.cards.i.IriniSengir.class));
cards.add(new SetCardInfo("Jinx", 36, Rarity.COMMON, mage.cards.j.Jinx.class));
cards.add(new SetCardInfo("Joven", 97, Rarity.COMMON, mage.cards.j.Joven.class));
cards.add(new SetCardInfo("Joven's Tools", 133, Rarity.UNCOMMON, mage.cards.j.JovensTools.class));
cards.add(new SetCardInfo("Koskun Falls", 18, Rarity.RARE, mage.cards.k.KoskunFalls.class));
cards.add(new SetCardInfo("Koskun Keep", 139, Rarity.UNCOMMON, mage.cards.k.KoskunKeep.class));
cards.add(new SetCardInfo("Labyrinth Minotaur", 38, Rarity.COMMON, mage.cards.l.LabyrinthMinotaur.class));
cards.add(new SetCardInfo("Leaping Lizard", 63, Rarity.COMMON, mage.cards.l.LeapingLizard.class));
cards.add(new SetCardInfo("Leeches", 111, Rarity.RARE, mage.cards.l.Leeches.class));
cards.add(new SetCardInfo("Mammoth Harness", 64, Rarity.RARE, mage.cards.m.MammothHarness.class));
cards.add(new SetCardInfo("Marjhan", 39, Rarity.RARE, mage.cards.m.Marjhan.class));
cards.add(new SetCardInfo("Memory Lapse", 40, Rarity.COMMON, mage.cards.m.MemoryLapse.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Memory Lapse", 41, Rarity.COMMON, mage.cards.m.MemoryLapse.class, NON_FULL_USE_VARIOUS));
@ -145,6 +151,7 @@ public class Homelands extends ExpansionSet {
cards.add(new SetCardInfo("Mystic Decree", 43, Rarity.RARE, mage.cards.m.MysticDecree.class));
cards.add(new SetCardInfo("Narwhal", 44, Rarity.RARE, mage.cards.n.Narwhal.class));
cards.add(new SetCardInfo("Primal Order", 65, Rarity.RARE, mage.cards.p.PrimalOrder.class));
cards.add(new SetCardInfo("Rashka the Slayer", 115, Rarity.RARE, mage.cards.r.RashkaTheSlayer.class));
cards.add(new SetCardInfo("Reef Pirates", 45, Rarity.COMMON, ReefPirates.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Reef Pirates", 46, Rarity.COMMON, ReefPirates.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Renewal", 66, Rarity.COMMON, mage.cards.r.Renewal.class));

View file

@ -76,6 +76,7 @@ public class MastersEdition extends ExpansionSet {
cards.add(new SetCardInfo("Armageddon", 4, Rarity.RARE, mage.cards.a.Armageddon.class));
cards.add(new SetCardInfo("Artifact Blast", 85, Rarity.COMMON, mage.cards.a.ArtifactBlast.class));
cards.add(new SetCardInfo("Ashnod's Transmogrant", 152, Rarity.COMMON, mage.cards.a.AshnodsTransmogrant.class));
cards.add(new SetCardInfo("Autumn Willow", 113, Rarity.RARE, mage.cards.a.AutumnWillow.class));
cards.add(new SetCardInfo("Balduvian Horde", 86, Rarity.RARE, mage.cards.b.BalduvianHorde.class));
cards.add(new SetCardInfo("Ball Lightning", 87, Rarity.RARE, mage.cards.b.BallLightning.class));
cards.add(new SetCardInfo("Baron Sengir", 58, Rarity.RARE, mage.cards.b.BaronSengir.class));

View file

@ -93,6 +93,7 @@ public class MastersEditionII extends ExpansionSet {
cards.add(new SetCardInfo("Brassclaw Orcs", 119, Rarity.COMMON, BrassclawOrcs.class));
cards.add(new SetCardInfo("Brimstone Dragon", 120, Rarity.RARE, mage.cards.b.BrimstoneDragon.class));
cards.add(new SetCardInfo("Brine Shaman", 80, Rarity.COMMON, mage.cards.b.BrineShaman.class));
cards.add(new SetCardInfo("Broken Visage", 81, Rarity.UNCOMMON, mage.cards.b.BrokenVisage.class));
cards.add(new SetCardInfo("Browse", 43, Rarity.UNCOMMON, mage.cards.b.Browse.class));
cards.add(new SetCardInfo("Burnout", 121, Rarity.UNCOMMON, mage.cards.b.Burnout.class));
cards.add(new SetCardInfo("Carapace", 155, Rarity.COMMON, mage.cards.c.Carapace.class));

View file

@ -1,78 +1,81 @@
/*
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
package mage.sets;
import mage.cards.ExpansionSet;
import mage.constants.Rarity;
import mage.constants.SetType;
/**
*
* @author fireshoes
*/
public class RivalsOfIxalan extends ExpansionSet {
private static final RivalsOfIxalan instance = new RivalsOfIxalan();
public static RivalsOfIxalan getInstance() {
return instance;
}
private RivalsOfIxalan() {
super("Rivals of Ixalan", "RIX", ExpansionSet.buildDate(2018, 1, 19), SetType.EXPANSION);
this.blockName = "Ixalan";
this.parentSet = Ixalan.getInstance();
this.hasBoosters = true;
this.hasBasicLands = false;
this.numBoosterLands = 1;
this.numBoosterCommon = 11;
this.numBoosterUncommon = 3;
this.numBoosterRare = 1;
this.ratioBoosterMythic = 8;
cards.add(new SetCardInfo("Angrath's Ambusher", 202, Rarity.UNCOMMON, mage.cards.a.AngrathsAmbusher.class));
cards.add(new SetCardInfo("Angrath's Fury", 204, Rarity.RARE, mage.cards.a.AngrathsFury.class));
cards.add(new SetCardInfo("Angrath, Minotaur Pirate", 201, Rarity.MYTHIC, mage.cards.a.AngrathMinotaurPirate.class));
cards.add(new SetCardInfo("Brass's Bounty", 94, Rarity.RARE, mage.cards.b.BrasssBounty.class));
cards.add(new SetCardInfo("Captain's Hook", 177, Rarity.RARE, mage.cards.c.CaptainsHook.class));
cards.add(new SetCardInfo("Cinder Barrens", 205, Rarity.RARE, mage.cards.c.CinderBarrens.class));
cards.add(new SetCardInfo("Evolving Wilds", 186, Rarity.RARE, mage.cards.e.EvolvingWilds.class));
cards.add(new SetCardInfo("Ghalta, Primal Hunger", 130, Rarity.RARE, mage.cards.g.GhaltaPrimalHunger.class));
cards.add(new SetCardInfo("Silvergill Adept", 53, Rarity.UNCOMMON, mage.cards.s.SilvergillAdept.class));
cards.add(new SetCardInfo("Storm the Vault", 173, Rarity.RARE, mage.cards.s.StormTheVault.class));
cards.add(new SetCardInfo("Swab Goblin", 203, Rarity.COMMON, mage.cards.s.SwabGoblin.class));
cards.add(new SetCardInfo("Tetzimoc, Primal Death", 86, Rarity.RARE, mage.cards.t.TetzimocPrimalDeath.class));
cards.add(new SetCardInfo("The Immortal Sun", 180, Rarity.MYTHIC, mage.cards.t.TheImmortalSun.class));
cards.add(new SetCardInfo("Vampire Champion", 198, Rarity.COMMON, mage.cards.v.VampireChampion.class));
cards.add(new SetCardInfo("Vault of Catlacan", 173, Rarity.RARE, mage.cards.v.VaultOfCatlacan.class));
cards.add(new SetCardInfo("Vona's Hunger", 90, Rarity.RARE, mage.cards.v.VonasHunger.class));
cards.add(new SetCardInfo("Vraska's Conquistador", 199, Rarity.UNCOMMON, mage.cards.v.VraskasConquistador.class));
cards.add(new SetCardInfo("Vraska's Scorn", 200, Rarity.RARE, mage.cards.v.VraskasScorn.class));
cards.add(new SetCardInfo("Vraska, Scheming Gorgon", 197, Rarity.MYTHIC, mage.cards.v.VraskaSchemingGorgon.class));
}
}
/*
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
package mage.sets;
import mage.cards.ExpansionSet;
import mage.constants.Rarity;
import mage.constants.SetType;
/**
*
* @author fireshoes
*/
public class RivalsOfIxalan extends ExpansionSet {
private static final RivalsOfIxalan instance = new RivalsOfIxalan();
public static RivalsOfIxalan getInstance() {
return instance;
}
private RivalsOfIxalan() {
super("Rivals of Ixalan", "RIX", ExpansionSet.buildDate(2018, 1, 19), SetType.EXPANSION);
this.blockName = "Ixalan";
this.parentSet = Ixalan.getInstance();
this.hasBoosters = true;
this.hasBasicLands = false;
this.numBoosterLands = 1;
this.numBoosterCommon = 11;
this.numBoosterUncommon = 3;
this.numBoosterRare = 1;
this.ratioBoosterMythic = 8;
cards.add(new SetCardInfo("Angrath's Ambusher", 202, Rarity.UNCOMMON, mage.cards.a.AngrathsAmbusher.class));
cards.add(new SetCardInfo("Angrath's Fury", 204, Rarity.RARE, mage.cards.a.AngrathsFury.class));
cards.add(new SetCardInfo("Angrath, Minotaur Pirate", 201, Rarity.MYTHIC, mage.cards.a.AngrathMinotaurPirate.class));
cards.add(new SetCardInfo("Brass's Bounty", 94, Rarity.RARE, mage.cards.b.BrasssBounty.class));
cards.add(new SetCardInfo("Captain's Hook", 177, Rarity.RARE, mage.cards.c.CaptainsHook.class));
cards.add(new SetCardInfo("Cinder Barrens", 205, Rarity.RARE, mage.cards.c.CinderBarrens.class));
cards.add(new SetCardInfo("Dusk Charger", 69, Rarity.COMMON, mage.cards.d.DuskCharger.class));
cards.add(new SetCardInfo("Evolving Wilds", 186, Rarity.RARE, mage.cards.e.EvolvingWilds.class));
cards.add(new SetCardInfo("Ghalta, Primal Hunger", 130, Rarity.RARE, mage.cards.g.GhaltaPrimalHunger.class));
cards.add(new SetCardInfo("Glorious Destiny", 18, Rarity.RARE, mage.cards.g.GloriousDestiny.class));
cards.add(new SetCardInfo("Paladin of Atonement", 16, Rarity.RARE, mage.cards.p.PaladinOfAtonement.class));
cards.add(new SetCardInfo("Silvergill Adept", 53, Rarity.UNCOMMON, mage.cards.s.SilvergillAdept.class));
cards.add(new SetCardInfo("Storm the Vault", 173, Rarity.RARE, mage.cards.s.StormTheVault.class));
cards.add(new SetCardInfo("Swab Goblin", 203, Rarity.COMMON, mage.cards.s.SwabGoblin.class));
cards.add(new SetCardInfo("Tetzimoc, Primal Death", 86, Rarity.RARE, mage.cards.t.TetzimocPrimalDeath.class));
cards.add(new SetCardInfo("The Immortal Sun", 180, Rarity.MYTHIC, mage.cards.t.TheImmortalSun.class));
cards.add(new SetCardInfo("Vampire Champion", 198, Rarity.COMMON, mage.cards.v.VampireChampion.class));
cards.add(new SetCardInfo("Vault of Catlacan", 173, Rarity.RARE, mage.cards.v.VaultOfCatlacan.class));
cards.add(new SetCardInfo("Vona's Hunger", 90, Rarity.RARE, mage.cards.v.VonasHunger.class));
cards.add(new SetCardInfo("Vraska's Conquistador", 199, Rarity.UNCOMMON, mage.cards.v.VraskasConquistador.class));
cards.add(new SetCardInfo("Vraska's Scorn", 200, Rarity.RARE, mage.cards.v.VraskasScorn.class));
cards.add(new SetCardInfo("Vraska, Scheming Gorgon", 197, Rarity.MYTHIC, mage.cards.v.VraskaSchemingGorgon.class));
}
}

View file

@ -0,0 +1,54 @@
/*
* 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.abilities.condition.common;
import mage.abilities.Ability;
import mage.abilities.condition.Condition;
import mage.game.Game;
import mage.watchers.WatcherUtils;
import mage.watchers.common.PlayerLostLifeWatcher;
/**
*
* @author LevelX
*/
public enum LiveLostLastTurnCondition implements Condition {
instance;
@Override
public boolean apply(Game game, Ability source) {
PlayerLostLifeWatcher watcher = (PlayerLostLifeWatcher) game.getState().getWatchers().get(PlayerLostLifeWatcher.class.getSimpleName());
if (watcher != null) {
return watcher.getLiveLostLastTurn(source.getControllerId()) > 0;
} else {
WatcherUtils.logMissingWatcher(game, source, PlayerLostLifeWatcher.class, this.getClass());
}
return false;
}
}

View file

@ -19,7 +19,7 @@ public class ConditionalTriggeredAbility extends TriggeredAbilityImpl {
protected TriggeredAbility ability;
protected Condition condition;
protected String text;
protected String abilityText;
/**
* Triggered ability with a condition. Set the optionality for the trigger
@ -27,22 +27,22 @@ public class ConditionalTriggeredAbility extends TriggeredAbilityImpl {
*
* @param ability
* @param condition
* @param text if null or empty, the rule text of the triggered ability
* itself is used.
* @param text explicit rule text for the ability, if null or empty, the
* rule text generated by the triggered ability itself is used.
*/
public ConditionalTriggeredAbility(TriggeredAbility ability, Condition condition, String text) {
super(ability.getZone(), null);
this.ability = ability;
this.modes = ability.getModes();
this.condition = condition;
this.text = text;
this.abilityText = text;
}
public ConditionalTriggeredAbility(final ConditionalTriggeredAbility triggered) {
super(triggered);
this.ability = triggered.ability.copy();
this.condition = triggered.condition;
this.text = triggered.text;
this.abilityText = triggered.abilityText;
}
@Override
@ -69,10 +69,10 @@ public class ConditionalTriggeredAbility extends TriggeredAbilityImpl {
@Override
public String getRule() {
if (text == null || text.isEmpty()) {
if (abilityText == null || abilityText.isEmpty()) {
return ability.getRule();
}
return text;
return abilityText;
}
@Override

View file

@ -77,6 +77,7 @@ public class DoIfCostPaid extends OneShotEffect {
&& (!optional || player.chooseUse(executingEffects.get(0).getOutcome(), message, source, game))) {
cost.clearPaid();
if (cost.pay(source, game, source.getSourceId(), player.getId(), false)) {
game.applyEffects(); // To end effects e.g. of sacrificed permanents
for (Effect effect : executingEffects) {
effect.setTargetPointer(this.targetPointer);
if (effect instanceof OneShotEffect) {
@ -86,8 +87,7 @@ public class DoIfCostPaid extends OneShotEffect {
}
}
player.resetStoredBookmark(game); // otherwise you can e.g. undo card drawn with Mentor of the Meek
}
else if (!otherwiseEffects.isEmpty()) {
} else if (!otherwiseEffects.isEmpty()) {
for (Effect effect : otherwiseEffects) {
effect.setTargetPointer(this.targetPointer);
if (effect instanceof OneShotEffect) {
@ -97,8 +97,7 @@ public class DoIfCostPaid extends OneShotEffect {
}
}
}
}
else if (!otherwiseEffects.isEmpty()) {
} else if (!otherwiseEffects.isEmpty()) {
for (Effect effect : otherwiseEffects) {
effect.setTargetPointer(this.targetPointer);
if (effect instanceof OneShotEffect) {

View file

@ -29,12 +29,9 @@ package mage.abilities.effects.keyword;
import mage.abilities.Ability;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.keyword.AscendAbility;
import mage.constants.Outcome;
import mage.designations.CitysBlessing;
import mage.designations.DesignationType;
import mage.filter.StaticFilters;
import mage.game.Game;
import mage.players.Player;
/**
*
@ -44,7 +41,7 @@ public class AscendEffect extends OneShotEffect {
public AscendEffect() {
super(Outcome.Detriment);
staticText = "Ascend (If you control ten or more permanents, you get the city's blessing for the rest of the game.)<br>";
staticText = AscendAbility.ASCEND_RULE + "<br>";
}
public AscendEffect(final AscendEffect effect) {
@ -58,20 +55,6 @@ public class AscendEffect extends OneShotEffect {
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
if (controller != null) {
if (game.getBattlefield().countAll(StaticFilters.FILTER_PERMANENT_ARTIFACT_CREATURE_ENCHANTMENT_OR_LAND, controller.getId(), game) > 9) {
if (!controller.hasDesignation(DesignationType.CITYS_BLESSING)) {
controller.addDesignation(new CitysBlessing());
game.informPlayers(controller.getLogName() + " gets the city's blessing for the rest of the game.");
} else {
game.informPlayers(controller.getLogName() + " already has the city's blessing.");
}
} else {
game.informPlayers(controller.getLogName() + " does not get the city's blessing.");
}
return true;
}
return false;
return AscendAbility.checkAscend(game, source, true);
}
}

View 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.abilities.keyword;
import mage.abilities.Ability;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.effects.ContinuousEffectImpl;
import static mage.abilities.keyword.AscendAbility.ASCEND_RULE;
import mage.constants.Duration;
import mage.constants.Layer;
import mage.constants.Outcome;
import mage.constants.SubLayer;
import mage.constants.Zone;
import mage.designations.CitysBlessing;
import mage.designations.DesignationType;
import mage.filter.StaticFilters;
import mage.game.Game;
import mage.players.Player;
/**
*
* @author LevelX2
*/
public class AscendAbility extends SimpleStaticAbility {
public static String ASCEND_RULE = "Ascend <i>(If you control ten or more permanents, you get the city's blessing for the rest of the game.)</i>";
public AscendAbility() {
super(Zone.BATTLEFIELD, new AscendContinuousEffect());
}
public AscendAbility(final AscendAbility ability) {
super(ability);
}
@Override
public AscendAbility copy() {
return new AscendAbility(this);
}
public static boolean checkAscend(Game game, Ability source, boolean verbose) {
Player controller = game.getPlayer(source.getControllerId());
if (controller != null) {
if (!controller.hasDesignation(DesignationType.CITYS_BLESSING)) {
if (game.getBattlefield().countAll(StaticFilters.FILTER_PERMANENT_ARTIFACT_CREATURE_ENCHANTMENT_OR_LAND, controller.getId(), game) > 9) {
controller.addDesignation(new CitysBlessing());
game.informPlayers(controller.getLogName() + " gets the city's blessing for the rest of the game.");
} else {
if (verbose) {
game.informPlayers(controller.getLogName() + " does not get the city's blessing.");
}
}
} else {
if (verbose) {
game.informPlayers(controller.getLogName() + " already has the city's blessing.");
}
}
return true;
}
return false;
}
@Override
public String getRule() {
return ASCEND_RULE;
}
}
class AscendContinuousEffect extends ContinuousEffectImpl {
public AscendContinuousEffect() {
super(Duration.WhileOnBattlefield, Layer.PlayerEffects, SubLayer.NA, Outcome.Benefit);
staticText = ASCEND_RULE;
}
public AscendContinuousEffect(final AscendContinuousEffect effect) {
super(effect);
}
@Override
public boolean apply(Game game, Ability source) {
return AscendAbility.checkAscend(game, source, false);
}
@Override
public AscendContinuousEffect copy() {
return new AscendContinuousEffect(this);
}
}

View file

@ -17,6 +17,7 @@ public enum AsThoughEffectType {
CAST_AS_INSTANT,
ACTIVATE_AS_INSTANT,
DAMAGE,
SHROUD,
HEXPROOF,
PAY,
LOOK_AT_FACE_DOWN,

View file

@ -93,6 +93,7 @@ public enum CounterType {
MINING("mining"),
MIRE("mire"),
MUSTER("muster"),
NET("net"),
P0P1(new BoostCounter(0, 1).name),
P1P0(new BoostCounter(1, 0).name),
P1P1(new BoostCounter(1, 1).name),

View file

@ -61,6 +61,7 @@ public final class StaticFilters {
public static final FilterCreaturePermanent FILTER_PERMANENT_CREATURE = new FilterCreaturePermanent();
public static final FilterCreaturePermanent FILTER_PERMANENT_A_CREATURE = new FilterCreaturePermanent("a creature");
public static final FilterCreaturePermanent FILTER_PERMANENT_CREATURES = new FilterCreaturePermanent("creatures");
public static final FilterCreaturePermanent FILTER_PERMANENT_CREATURES_CONTROLLED = new FilterCreaturePermanent("creatures you control");
public static final FilterCreaturePermanent FILTER_PERMANENT_CREATURE_GOBLINS = new FilterCreaturePermanent(SubType.GOBLIN, "Goblin creatures");
public static final FilterCreaturePermanent FILTER_PERMANENT_CREATURE_SLIVERS = new FilterCreaturePermanent(SubType.SLIVER, "all Sliver creatures");
public static final FilterPlaneswalkerPermanent FILTER_PERMANENT_PLANESWALKER = new FilterPlaneswalkerPermanent();
@ -108,6 +109,8 @@ public final class StaticFilters {
FILTER_ATTACKING_CREATURES.add(new AttackingPredicate());
FILTER_PERMANENT_CREATURES_CONTROLLED.add(new ControllerPredicate(TargetController.YOU));
FILTER_PERMANENT_ARTIFACT_OR_CREATURE.add(Predicates.or(
new CardTypePredicate(CardType.ARTIFACT),
new CardTypePredicate(CardType.CREATURE)

View file

@ -27,11 +27,12 @@
*/
package mage.filter.predicate.permanent;
import java.util.UUID;
import mage.filter.predicate.Predicate;
import mage.game.Game;
import mage.game.permanent.Permanent;
import java.util.UUID;
/**
*
* @author North
@ -46,6 +47,12 @@ public class ControllerIdPredicate implements Predicate<Permanent> {
@Override
public boolean apply(Permanent input, Game game) {
if(controllerId == null){
return false;
}
if(input.getControllerId() == null){
return false;
}
return controllerId.equals(input.getControllerId());
}

View file

@ -965,7 +965,9 @@ public abstract class PermanentImpl extends CardImpl implements Permanent {
public boolean canBeTargetedBy(MageObject source, UUID sourceControllerId, Game game) {
if (source != null) {
if (abilities.containsKey(ShroudAbility.getInstance().getId())) {
return false;
if (!game.getContinuousEffects().asThough(this.getId(), AsThoughEffectType.SHROUD, sourceControllerId, game)) {
return false;
}
}
if (abilities.containsKey(HexproofAbility.getInstance().getId())) {
if (game.getPlayer(this.getControllerId()).hasOpponent(sourceControllerId, game)

View file

@ -0,0 +1,52 @@
/*
* 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.game.permanent.token;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.MageInt;
/**
*
* @author spjspj & L_J
*/
public class BrokenVisageSpiritToken extends Token {
public BrokenVisageSpiritToken() {
this(0,0);
}
public BrokenVisageSpiritToken(int tokenPower, int tokenToughness) {
super("Spirit", new StringBuilder(tokenPower).append('/').append(tokenToughness).append(" black Spirit creature token").toString());
cardType.add(CardType.CREATURE);
color.setBlack(true);
subtype.add(SubType.SPIRIT);
power = new MageInt(tokenPower);
toughness = new MageInt(tokenToughness);
}
}

View file

@ -0,0 +1,46 @@
/*
* 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.watchers;
import mage.MageObject;
import mage.abilities.Ability;
import mage.game.Game;
import org.apache.log4j.Logger;
/**
*
* @author LevelX2
*/
public final class WatcherUtils {
public static void logMissingWatcher(Game game, Ability source, Class watcherClass, Class usingClass) {
MageObject sourceObject = source.getSourceObject(game);
Logger.getLogger(usingClass).error("Needed watcher is not started " + watcherClass.getSimpleName()
+ " - " + (sourceObject == null ? " no source object" : sourceObject.getName()));
}
}

View file

@ -38,7 +38,7 @@ import mage.watchers.Watcher;
/*
* Counts amount of life lost current or last turn by players.
* This watcher is always added in gameImpl.init
* This watcher is automatically started in gameImpl.init for each game
*
* @author LevelX2
*/

View file

@ -1,5 +1,6 @@
Afflict|number|
Annihilator|number|
Ascend|new|
Basic landcycling|cost|
Battle cry|new|
Bestow|card, manaString|

View file

@ -32696,15 +32696,39 @@ Forest|Duel Decks: Mind vs. Might|65|L||Basic Land - Forest|||{T}: Add {G} to yo
Chandra, Gremlin Wrangler|Heroes of the Realm|1|M|{2}{R}{R}|Legendary Planeswalker - Chandra|3||+1: Create a 2/2 red Gremlin creature token.$-2:Chandra, Gremlin Wrangler deals X damage to target creature or player, where X is the number of Gremlins you control.|
Dungeon Master|Heroes of the Realm|1|M|{2}{W}{U}|Legendary Planeswalker - Dungeon Master|||+1: Target opponent creates a 1/1 black Skeleton creature token with “When this creature dies, each opponent loses 2 life.”$+1: Roll a d20. If you roll a 1, skip your next turn. If you roll a 12 or higher, draw a card.$-6: You get an adventuring party. (Your party is a 3/3 red Fighter with first strike, a 1/1 white Cleric with lifelink, a 2/2 black Rogue with hexproof, and a 1/1 blue Wizard with flying.)|
Nira, Hellkite Duelist|Heroes of the Realm|3|M|{W}{U}{B}{R}{G}|Legendary Creature — Dragon|6|6|Flash$Flying, trample, haste$When Nira, Hellkite Duelist enters the battlefield, the next time you would lose the game this turn, instead draw three cards and your life total becomes 5.|
Paladin of Atonement|Rivals of Ixalan|16|R|{1}{W}|Creature - Vampire Knight|1|1|At the beginning of each upkeep, if you lost life last turn, put a +1/+1 counter on Paladin of Atonement.$When Paladin of Atonement dies, you gain life equal to it's toughness.|
Glorious Destiny|Rivals of Ixalan|18|R|{2}{W}|Enchantment|||Ascend <i>(If you control ten or more permanents, you get the city's blessing for the rest of the game.)</i>$As Glorious Destiny enters the battlefield, choose a creature type.$Creatures you control of the chosen type get +1/+1. They have vigilance as long as you have the city's blessing.|
Shrine Altisaur|Rivals of Ixalan|28|R|{4}{W}|Creature - Dinosaur|3|4|If a source would deal damage to another Dinosaur you control, prevent all but 1 of that damage.|
Zetalpa, Primal Dawn|Rivals of Ixalan|30|R|{6}{W}{W}|Legendary Creature - Elder Dinosaur|4|8|Flying, double strike, vigilance, trample, indestructible|
River Darter|Rivals of Ixalan|47|C|{2}{U}|Creature - Merfolk Warrior|2|3|River Darter can't be blocked by Dinosaurs.|
Seafloor Oracle|Rivals of Ixalan|51|R|{2}{W}{W}|Creature - Merfolk Wizard|2|3|Whenever a Merfolk you controls deals combat damage to a player, draw a card.|
Secrets of the Golden City|Rivals of Ixalan|52|C|{1}{U}{U}|Sorcery|||Ascend <i>(If you control ten or more permanents, you get the city's blessing for the rest of the game.)</i>$Draw two cards. If you have the city's blessing, draw three cards instead.|
Silvergill Adept|Rivals of Ixalan|53|U|{1}{U}|Creature - Merfolk Wizard|2|1|As an additional cost to cast Silvergill Adept, reveal a Merfolk card from your hand or pay {3}.$When Silvergill Adept enters the battlefield, draw a card.|
Dusk Charger|Rivals of Ixalan|69|C|{3}{B}|Creature - Horse|3|3|Ascend <i>(If you control ten or more permanents, you get the city's blessing for the rest of the game.)</i>$Dusk Charger gets +2/+2 as long as you have the city's blessing.|
Tetzimoc, Primal Death|Rivals of Ixalan|86|R|{4}{B}{B}|Legendary Creature - Elder Dinosaur|6|6|Deathtouch${B}, Reveal Tetzimoc, Primal Death from your hand: Put a prey counter on target creature. Activate this ability only during your turn.$When Tetzimoc, Primal Death enters the battlefield, destroy each creature your opponents control with a prey counter on it.|
Vona's Hunger|Rivals of Ixalan|90|R|{2}{B}|Instant|||Ascend <i>(If you control ten or more permanents, you get the city's blessing for the rest of the game.)</i>$Each opponent sacrifices a creature. If you have the city's blessing, instead each opponent sacrifices half the creatures he or she controls rounded up.|
Brass's Bounty|Rivals of Ixalan|94|R|{6}{R}|Sorcery|||For each land you control, create a colorless Treasure artifact token with "{t}, Sacrifice this artifact: Add one mana of any color to your mana pool."|
Form of the Dinosaur|Rivals of Ixalan|103|R|{4}{R}{R}|Enchantment|||When Form of the Dinosaur enters the battlefield, your life total becomes 15.$At the beginning of your upkeep, Form of the Dinosaur deals 15 damage to target creature an opponent controls and that creature deals damage equal to its power to you.|
Frilled Deathspitter|Rivals of Ixalan|104|C|{2}{R}|Creature - Dinosaur|3|2|<i>Enrage</i> — Whenever Frilled Deathspitter is dealt damage, it deals 2 damage to target opponent.|
Swaggering Corsair|Rivals of Ixalan|119|C|{2}{R}|Creature - Human Pirate|2|2|<i>Raid</i> — Swaggering Corsair enters the battlefield with a +1/+1 counter on it if you attacked with a creature this turn.|
Tilonalli's Summoner|Rivals of Ixalan|121|R|{1}{R}|Creature - Human Shaman|1|1|Ascend (If you control ten or more permanents, you get the city's blessing for the rest of the game.)$Whenever Tilonalli's Summoner attacks, you may pay {X}{R}. If you do, create X 1/1 Elemental creature tokens tapped and attacking. Exile them at the beginning of the next end step, unless you have the City's blessing.|
Enter the Unknown|Rivals of Ixalan|128|U|{G}|Sorcery|||Target creature you control explores. <i>(Reveal the top card of your library. Put that card into your hand if it's a land. Otherwise, put a +1/+1 counter on this creature, then put the card back or put it into your graveyard.) </i>$You may play an additional land this turn.|
Ghalta, Primal Hunger|Rivals of Ixalan|130|R|{1}{0}{G}{G}|Legendary Creature - Elder Dinosaur|12|12|Ghalta, Primal Hunger costs {X} less to cast, where X is the total power of creatures you control.$Trample|
Path to Discovery|Rivals of Ixalan|142|R|{3}{G}|Enchantment|||Whenever a creature enters the battlefield under your control, it explores. (Reveal the top card of your library. Put that card into your hand if it's a land. Otherwise, put a +1/+1 counter on the creature, then put the card back or put it into your graveyard.)|
Tendershoot Dryad|Rivals of Ixalan|147|R|{4}{G}|Creature - Dryad|2|2|Ascend <i>(If you control ten or more permanents, you get the city's blessing for the rest of the game.)</i>$At the beginning of each upkeep, create a 1/1 green Saproling creature token.$Saprolings you control get +2/+2 as long as you have the city's blessing.|
Thrashing Brontodon|Rivals of Ixalan|148|U|{1}{G}{G}|Creature - Dinosaur|3|4|{1}, Sacrificing Thrashing Brontodon: Destroy target artifact or enchantment.|
Angrath, the Flame-Chained|Rivals of Ixalan|152|M|{3}{B}{R}|Legendary Planeswalker - Angrath|4|+1: Each opponent discards a card and loses 2 life.$-3: Gain control of target creature until end of turn. Untap it. It gains haste until end of turn. Sacrifice it at the beginning of the next end step if it has converted mana cost 3 or less.$-8: Each opponent loses life equal to the number of cards in his or her graveyard.|
Atzocan Seer|Rivals of Ixalan|153|U|{1}{G}{W}|Creature - Human Druid|2|3|{t}: Add one mana of any color to your manan pool.$Sacrifice Atzocan Seer: Return target Dinosaur card from your graveyard to your hand.|
Elenda, the Dusk Rose|Rivals of Ixalan|157|M|{2}{W}{B}|Legendary Creature - Vampire Knight|1|1|Lifelink$Whenever another creature dies, put a +1/+1 counter on Elenda, the Dusk Rose.$When Elenda dies, create X 1/1 white Vampire creature tokens with lifelink, where X is Elenda's power|
Journey to Eternity|Rivals of Ixalan|160|R|{1}{B}{G}|Legendary Enchantment - Aura|||Enchant creature you control$When enchanted creature dies, return it to the battlefield under your control, then return Journey to Eternity to the battlefield transformed under your control.|
Atzal, Cave of Eternity|Rivals of Ixalan|160|R||Legendary Land|||<i>(Transforms from Journey to Eternity.)</i>${t}: Add one mana of any color to your mana pool.${3}{B}{G}, {t}: Return target creature card from your graveyard to the battlefield.|
Kumena, Tyrant of Orzca|Rivals of Ixalan|162|M|{1}{G}{U}|Legendary Creature - Merfolk Shaman|2|4|Tap another untapped Merfolk you control: Kumena, Tyrant of Orzca can't be blocked this turn.$Tap three untapped Merfolk you control: Draw a card.$Tap five untapped Merfolk you control: Put a +1/+1 counter on each Merfolk you control.|
Storm the Vault|Rivals of Ixalan|173|R|{2}{U}{R}|Legendary Enchantment|||Whenever one or more creatures you control deal combat damage to a player, create a colorless Treasure artifact token with "{T}, Sacrifice this artifact: Add one mana of any color to your mana pool."$At the beginning of your end step, if you control five or more artifacts, transform Storm the Vault.|
Vault of Catlacan|Rivals of Ixalan|173|R||Legendary Land|||<i>(Transforms from Storm the Vault.)</i>${T}: Add one mana of any color to your mana pool.${T}: Add {U} to your mana pool for each artifact you control.|
Awakened Amalgamation|Rivals of Ixalan|175|R|{4}|Artifact Creature - Golem|0|0|Awakened Amalgamation's power and toughness are each equal to the number of lands you control with different names.|
Captain's Hook|Rivals of Ixalan|177|R|{3}|Artifact - Equipment|||Equipped creature gets +2/+0, has menace, and is a Pirate in addition to its other creature types.$Whenever Captain's Hook becomes unattached from a permanent, destroy that permanent.$Equip {1}|
The Immortal Sun|Rivals of Ixalan|180|M|{6}|Legendary Artifact|||Players can't activate loyalty abilities of planeswalkers.$At the beginning of your draw step, draw an additional card.$Spells you cast cost {1} less to cast.$Creatures you control get +1/+1.|
Gleaming Barrier|Rivals of Ixalan|178|C|{2}|Artifact Creature - Wall|0|4|Defender$When Gleaming Barrier dies, create a colorless Treasure artifact token with "{t}, Sacrifice this artifact: Add one mana of any color to your mana pool."|
The Immortal Sun|Rivals of Ixalan|180|M|{6}|Legendary Artifact|||Players can't activate planeswalkers' loyalty abilities.$At the beginning of your draw step, draw an additional card.$Spells you cast cost {1} less to cast.$Creatures you control get +1/+1.|
Evolving Wilds|Rivals of Ixalan|186|C||Land|||{T}, Sacrifice Evolving Wilds: Search your library for a basic land card, put it onto the battlefield tapped, then shuffle your library.|
Vraska, Scheming Gorgon|Rivals of Ixalan|197|M|{4}{B}{B}|Legendary Planeswalker - Vraska|5|+2: Creatures you control get +1/+0 until end of turn.$-3: Destroy target creature.$-10: Until end of turn, creatures you control gain deathtouch and "Whenever this creature deals damage to an opponent, that player loses the game."|
Vampire Champion|Rivals of Ixalan|198|C|{3}{B}|Creature - Vampire Soldier|3|3|Deathtouch <i>(Any amount of damage this deals to a creature is enough to destroy it.)</i>|