Merge pull request #30 from magefree/master
Merge https://github.com/magefree/mage
|
@ -239,10 +239,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);
|
||||
|
@ -429,16 +429,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 +453,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 +950,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 +958,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 +1101,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 {
|
||||
|
|
|
@ -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=""<html><strong>Common</strong><br/>" 
+ 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=""<html><strong>Uncommon</strong><br/>" 
+ 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=""<html><strong>Rare</strong><br/>" 
+ 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=""<html><strong>Mythic</strong><br/>" 
+ 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=""<html><strong>Special</strong><br/>" 
+ 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">
|
||||
|
|
|
@ -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;
|
||||
|
@ -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
|
||||
|
||||
|
|
|
@ -465,6 +465,12 @@ public class MageBook extends JComponent {
|
|||
LinkedList<Integer> haveNumbers = new LinkedList<>();
|
||||
for (ExpansionSet.SetCardInfo card: cards){
|
||||
int cardNumber = card.getCardNumberAsInt();
|
||||
|
||||
// skip xmage special numbers for cards (TODO: replace full art cards numbers from 180+20 to 180b, 180c and vice versa like scryfall)
|
||||
if(cardNumber > 500){
|
||||
continue;
|
||||
}
|
||||
|
||||
startNumber = min(startNumber, cardNumber);
|
||||
endNumber = Math.max(endNumber, cardNumber);
|
||||
haveNumbers.add(cardNumber);
|
||||
|
|
|
@ -32,52 +32,39 @@
|
|||
<Group type="102" attributes="0">
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Group type="102" alignment="1" attributes="0">
|
||||
<Group type="103" groupAlignment="1" attributes="0">
|
||||
<Group type="102" alignment="1" attributes="0">
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Component id="lblIsland" alignment="0" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="lblMountain" alignment="0" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="lblForest" alignment="0" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="lblLandSet" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<EmptySpace max="32767" attributes="0"/>
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Group type="103" groupAlignment="0" max="-2" attributes="0">
|
||||
<Component id="spnMountain" pref="85" max="32767" attributes="0"/>
|
||||
<Component id="spnIsland" max="32767" attributes="0"/>
|
||||
<Component id="spnForest" max="32767" attributes="0"/>
|
||||
</Group>
|
||||
<Component id="cbLandSet" min="-2" pref="207" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
<Group type="102" alignment="1" attributes="0">
|
||||
<Group type="103" groupAlignment="1" attributes="0">
|
||||
<Group type="102" alignment="0" attributes="0">
|
||||
<Component id="lblSwamp" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace min="-2" pref="14" max="-2" attributes="0"/>
|
||||
<Component id="spnSwamp" max="32767" attributes="0"/>
|
||||
</Group>
|
||||
<Group type="102" alignment="0" attributes="0">
|
||||
<Component id="lblPains" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace min="-2" pref="21" max="-2" attributes="0"/>
|
||||
<Component id="spnPlains" max="32767" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
<EmptySpace min="-2" pref="122" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
<EmptySpace min="-2" max="-2" attributes="0"/>
|
||||
<Component id="lblMountain" alignment="0" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="lblForest" alignment="1" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="lblLandSet" alignment="1" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="lblIsland" alignment="1" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="lblPains" alignment="1" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="lblSwamp" alignment="1" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<EmptySpace type="separate" max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Group type="102" alignment="0" attributes="0">
|
||||
<Component id="btnAutoAdd" pref="122" max="32767" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="btnAdd" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="btnCancel" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<Group type="102" alignment="0" attributes="0">
|
||||
<Component id="btnCancel" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace type="unrelated" max="-2" attributes="0"/>
|
||||
<Component id="btnAutoAdd" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace type="unrelated" max="-2" attributes="0"/>
|
||||
<Component id="btnAdd" min="-2" max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="1" attributes="0">
|
||||
<Group type="103" alignment="0" groupAlignment="1" max="-2" attributes="0">
|
||||
<Component id="spnMountain" alignment="0" pref="85" max="32767" attributes="0"/>
|
||||
<Component id="spnIsland" alignment="0" pref="85" max="32767" attributes="0"/>
|
||||
<Component id="spnForest" alignment="0" max="32767" attributes="0"/>
|
||||
</Group>
|
||||
<Group type="103" alignment="0" groupAlignment="1" max="-2" attributes="0">
|
||||
<Component id="spnSwamp" alignment="0" pref="85" max="32767" attributes="0"/>
|
||||
<Component id="spnPlains" alignment="0" max="32767" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
|
||||
</Group>
|
||||
<Component id="panelSet" max="32767" attributes="0"/>
|
||||
</Group>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
</DimensionLayout>
|
||||
|
@ -85,9 +72,9 @@
|
|||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Group type="102" attributes="0">
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="3" attributes="0">
|
||||
<Component id="cbLandSet" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="lblLandSet" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Component id="lblLandSet" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="panelSet" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="3" attributes="0">
|
||||
|
@ -128,19 +115,7 @@
|
|||
<SubComponents>
|
||||
<Component class="javax.swing.JLabel" name="lblLandSet">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" value="Set"/>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Component class="javax.swing.JComboBox" name="cbLandSet">
|
||||
<Properties>
|
||||
<Property name="model" type="javax.swing.ComboBoxModel" editor="org.netbeans.modules.form.editors2.ComboBoxModelEditor">
|
||||
<StringArray count="4">
|
||||
<StringItem index="0" value="Item 1"/>
|
||||
<StringItem index="1" value="Item 2"/>
|
||||
<StringItem index="2" value="Item 3"/>
|
||||
<StringItem index="3" value="Item 4"/>
|
||||
</StringArray>
|
||||
</Property>
|
||||
<Property name="text" type="java.lang.String" value="Set:"/>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Component class="javax.swing.JLabel" name="lblForest">
|
||||
|
@ -227,5 +202,41 @@
|
|||
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="btnAutoAddActionPerformed"/>
|
||||
</Events>
|
||||
</Component>
|
||||
<Container class="javax.swing.JPanel" name="panelSet">
|
||||
|
||||
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignBoxLayout"/>
|
||||
<SubComponents>
|
||||
<Component class="javax.swing.JComboBox" name="cbLandSet">
|
||||
<Properties>
|
||||
<Property name="model" type="javax.swing.ComboBoxModel" editor="org.netbeans.modules.form.editors2.ComboBoxModelEditor">
|
||||
<StringArray count="4">
|
||||
<StringItem index="0" value="Item 1"/>
|
||||
<StringItem index="1" value="Item 2"/>
|
||||
<StringItem index="2" value="Item 3"/>
|
||||
<StringItem index="3" value="Item 4"/>
|
||||
</StringArray>
|
||||
</Property>
|
||||
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||
<Dimension value="[20, 20]"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Component class="javax.swing.JButton" name="btnSetFastSearch">
|
||||
<Properties>
|
||||
<Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
|
||||
<Image iconType="3" name="/buttons/search_24.png"/>
|
||||
</Property>
|
||||
<Property name="toolTipText" type="java.lang.String" value="Search for set"/>
|
||||
<Property name="alignmentX" type="float" value="1.0"/>
|
||||
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||
<Dimension value="[23, 23]"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
<Events>
|
||||
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="btnSetFastSearchActionPerformed"/>
|
||||
</Events>
|
||||
</Component>
|
||||
</SubComponents>
|
||||
</Container>
|
||||
</SubComponents>
|
||||
</Form>
|
||||
|
|
|
@ -44,6 +44,7 @@ import mage.cards.repository.ExpansionInfo;
|
|||
import mage.cards.repository.ExpansionRepository;
|
||||
import mage.client.MageFrame;
|
||||
import mage.client.constants.Constants.DeckEditorMode;
|
||||
import mage.client.util.gui.FastSearchUtil;
|
||||
import mage.constants.Rarity;
|
||||
import mage.util.RandomUtil;
|
||||
import org.apache.log4j.Logger;
|
||||
|
@ -113,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);
|
||||
}
|
||||
|
||||
|
@ -157,7 +165,6 @@ public class AddLandDialog extends MageDialog {
|
|||
|
||||
jButton2 = new javax.swing.JButton();
|
||||
lblLandSet = new javax.swing.JLabel();
|
||||
cbLandSet = new javax.swing.JComboBox();
|
||||
lblForest = new javax.swing.JLabel();
|
||||
spnForest = new javax.swing.JSpinner();
|
||||
lblIsland = new javax.swing.JLabel();
|
||||
|
@ -171,14 +178,15 @@ public class AddLandDialog extends MageDialog {
|
|||
btnAdd = new javax.swing.JButton();
|
||||
btnCancel = new javax.swing.JButton();
|
||||
btnAutoAdd = new javax.swing.JButton();
|
||||
panelSet = new javax.swing.JPanel();
|
||||
cbLandSet = new javax.swing.JComboBox();
|
||||
btnSetFastSearch = new javax.swing.JButton();
|
||||
|
||||
jButton2.setText("jButton2");
|
||||
|
||||
setTitle("Add Land");
|
||||
|
||||
lblLandSet.setText("Set");
|
||||
|
||||
cbLandSet.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "Item 1", "Item 2", "Item 3", "Item 4" }));
|
||||
lblLandSet.setText("Set:");
|
||||
|
||||
lblForest.setText("Forest");
|
||||
|
||||
|
@ -201,13 +209,42 @@ public class AddLandDialog extends MageDialog {
|
|||
spnSwamp.setModel(new javax.swing.SpinnerNumberModel(0, 0, null, 1));
|
||||
|
||||
btnAdd.setText("Add");
|
||||
btnAdd.addActionListener(evt -> btnAddActionPerformed(evt));
|
||||
btnAdd.addActionListener(new java.awt.event.ActionListener() {
|
||||
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||
btnAddActionPerformed(evt);
|
||||
}
|
||||
});
|
||||
|
||||
btnCancel.setText("Cancel");
|
||||
btnCancel.addActionListener(evt -> btnCancelActionPerformed(evt));
|
||||
btnCancel.addActionListener(new java.awt.event.ActionListener() {
|
||||
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||
btnCancelActionPerformed(evt);
|
||||
}
|
||||
});
|
||||
|
||||
btnAutoAdd.setText("Suggest");
|
||||
btnAutoAdd.addActionListener(evt -> btnAutoAddActionPerformed(evt));
|
||||
btnAutoAdd.addActionListener(new java.awt.event.ActionListener() {
|
||||
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||
btnAutoAddActionPerformed(evt);
|
||||
}
|
||||
});
|
||||
|
||||
panelSet.setLayout(new javax.swing.BoxLayout(panelSet, javax.swing.BoxLayout.LINE_AXIS));
|
||||
|
||||
cbLandSet.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "Item 1", "Item 2", "Item 3", "Item 4" }));
|
||||
cbLandSet.setMinimumSize(new java.awt.Dimension(20, 20));
|
||||
panelSet.add(cbLandSet);
|
||||
|
||||
btnSetFastSearch.setIcon(new javax.swing.ImageIcon(getClass().getResource("/buttons/search_24.png"))); // NOI18N
|
||||
btnSetFastSearch.setToolTipText("Search for set");
|
||||
btnSetFastSearch.setAlignmentX(1.0F);
|
||||
btnSetFastSearch.setPreferredSize(new java.awt.Dimension(23, 23));
|
||||
btnSetFastSearch.addActionListener(new java.awt.event.ActionListener() {
|
||||
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||
btnSetFastSearchActionPerformed(evt);
|
||||
}
|
||||
});
|
||||
panelSet.add(btnSetFastSearch);
|
||||
|
||||
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
|
||||
getContentPane().setLayout(layout);
|
||||
|
@ -216,48 +253,40 @@ public class AddLandDialog extends MageDialog {
|
|||
.addGroup(layout.createSequentialGroup()
|
||||
.addContainerGap()
|
||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
|
||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addComponent(lblIsland)
|
||||
.addComponent(lblMountain)
|
||||
.addComponent(lblForest)
|
||||
.addComponent(lblLandSet))
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
|
||||
.addComponent(spnMountain, javax.swing.GroupLayout.DEFAULT_SIZE, 85, Short.MAX_VALUE)
|
||||
.addComponent(spnIsland)
|
||||
.addComponent(spnForest))
|
||||
.addComponent(cbLandSet, javax.swing.GroupLayout.PREFERRED_SIZE, 207, javax.swing.GroupLayout.PREFERRED_SIZE)))
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
|
||||
.addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup()
|
||||
.addComponent(lblSwamp)
|
||||
.addGap(14, 14, 14)
|
||||
.addComponent(spnSwamp))
|
||||
.addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup()
|
||||
.addComponent(lblPains)
|
||||
.addGap(21, 21, 21)
|
||||
.addComponent(spnPlains)))
|
||||
.addGap(122, 122, 122)))
|
||||
.addContainerGap())
|
||||
.addComponent(lblMountain)
|
||||
.addComponent(lblForest, javax.swing.GroupLayout.Alignment.TRAILING)
|
||||
.addComponent(lblLandSet, javax.swing.GroupLayout.Alignment.TRAILING)
|
||||
.addComponent(lblIsland, javax.swing.GroupLayout.Alignment.TRAILING)
|
||||
.addComponent(lblPains, javax.swing.GroupLayout.Alignment.TRAILING)
|
||||
.addComponent(lblSwamp, javax.swing.GroupLayout.Alignment.TRAILING))
|
||||
.addGap(18, 18, 18)
|
||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addComponent(btnCancel)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
|
||||
.addComponent(btnAutoAdd)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
|
||||
.addComponent(btnAutoAdd, javax.swing.GroupLayout.DEFAULT_SIZE, 122, Short.MAX_VALUE)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(btnAdd)
|
||||
.addGap(0, 0, Short.MAX_VALUE))))
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(btnCancel))
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
|
||||
.addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false)
|
||||
.addComponent(spnMountain, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, 85, Short.MAX_VALUE)
|
||||
.addComponent(spnIsland, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, 85, Short.MAX_VALUE)
|
||||
.addComponent(spnForest, javax.swing.GroupLayout.Alignment.LEADING))
|
||||
.addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false)
|
||||
.addComponent(spnSwamp, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, 85, Short.MAX_VALUE)
|
||||
.addComponent(spnPlains, javax.swing.GroupLayout.Alignment.LEADING)))
|
||||
.addGap(0, 0, Short.MAX_VALUE))
|
||||
.addComponent(panelSet, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
|
||||
.addContainerGap())
|
||||
);
|
||||
layout.setVerticalGroup(
|
||||
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addContainerGap()
|
||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
|
||||
.addComponent(cbLandSet, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addComponent(lblLandSet))
|
||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addComponent(lblLandSet)
|
||||
.addComponent(panelSet, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
|
||||
.addComponent(lblForest)
|
||||
|
@ -312,6 +341,10 @@ public class AddLandDialog extends MageDialog {
|
|||
autoAddLands();
|
||||
}//GEN-LAST:event_btnAutoAddActionPerformed
|
||||
|
||||
private void btnSetFastSearchActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnSetFastSearchActionPerformed
|
||||
FastSearchUtil.showFastSearchForStringComboBox(cbLandSet, FastSearchUtil.DEFAULT_EXPANSION_SEARCH_MESSAGE);
|
||||
}//GEN-LAST:event_btnSetFastSearchActionPerformed
|
||||
|
||||
private void autoAddLands() {
|
||||
int red = 0;
|
||||
int green = 0;
|
||||
|
@ -356,6 +389,7 @@ public class AddLandDialog extends MageDialog {
|
|||
private javax.swing.JButton btnAdd;
|
||||
private javax.swing.JButton btnAutoAdd;
|
||||
private javax.swing.JButton btnCancel;
|
||||
private javax.swing.JButton btnSetFastSearch;
|
||||
private javax.swing.JComboBox cbLandSet;
|
||||
private javax.swing.JButton jButton2;
|
||||
private javax.swing.JLabel lblForest;
|
||||
|
@ -364,6 +398,7 @@ public class AddLandDialog extends MageDialog {
|
|||
private javax.swing.JLabel lblMountain;
|
||||
private javax.swing.JLabel lblPains;
|
||||
private javax.swing.JLabel lblSwamp;
|
||||
private javax.swing.JPanel panelSet;
|
||||
private javax.swing.JSpinner spnForest;
|
||||
private javax.swing.JSpinner spnIsland;
|
||||
private javax.swing.JSpinner spnMountain;
|
||||
|
|
|
@ -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() {
|
||||
|
@ -744,7 +744,7 @@ public class ConnectDialog extends MageDialog {
|
|||
DefaultComboBoxModel flagModel = (DefaultComboBoxModel)cbFlag.getModel();
|
||||
String[] flagItem;
|
||||
|
||||
for(int i = 0; i < flagModel.getSize() - 1; i++){
|
||||
for(int i = 0; i < flagModel.getSize(); i++){
|
||||
flagItem = (String[])flagModel.getElementAt(i);
|
||||
choiceItems.put(flagItem[1], flagItem[0]);
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
@ -181,7 +185,7 @@ public class PickChoiceDialog extends MageDialog {
|
|||
// start selection
|
||||
if((startSelectionValue != null)){
|
||||
int selectIndex = -1;
|
||||
for(int i = 0; i < this.listChoices.getModel().getSize() - 1; i++){
|
||||
for(int i = 0; i < this.listChoices.getModel().getSize(); i++){
|
||||
KeyValueItem listItem = (KeyValueItem)this.listChoices.getModel().getElementAt(i);
|
||||
if (listItem.Key.equals(startSelectionValue)){
|
||||
selectIndex = i;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -32,8 +32,8 @@ public class FastSearchUtil {
|
|||
Map<String, Integer> choiceSorting = new HashMap<>(comboModel.getSize());
|
||||
String item;
|
||||
|
||||
for(int i = 0; i < comboModel.getSize() - 1; i++){
|
||||
item = (String)comboModel.getElementAt(i);
|
||||
for(int i = 0; i < comboModel.getSize(); i++){
|
||||
item = comboModel.getElementAt(i).toString();
|
||||
choiceItems.put(item, item);
|
||||
choiceSorting.put(item, i); // need so sorting
|
||||
}
|
||||
|
@ -44,7 +44,7 @@ public class FastSearchUtil {
|
|||
|
||||
// current selection value restore
|
||||
String needSelectValue;
|
||||
needSelectValue = (String)comboModel.getSelectedItem();
|
||||
needSelectValue = comboModel.getSelectedItem().toString();
|
||||
|
||||
// ask for new value
|
||||
PickChoiceDialog dlg = new PickChoiceDialog();
|
||||
|
@ -52,7 +52,13 @@ public class FastSearchUtil {
|
|||
dlg.showDialog(choice, needSelectValue);
|
||||
if(choice.isChosen()){
|
||||
item = choice.getChoiceKey();
|
||||
comboModel.setSelectedItem(item);
|
||||
|
||||
// compatible select for object's models (use setSelectedIndex instead setSelectedObject)
|
||||
for(int i = 0; i < comboModel.getSize(); i++){
|
||||
if(comboModel.getElementAt(i).toString().equals(item)){
|
||||
combo.setSelectedIndex(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -253,6 +253,7 @@ public enum MythicspoilerComSource implements CardImageSource {
|
|||
supportedSets.add("C17");
|
||||
supportedSets.add("IMA");
|
||||
supportedSets.add("XLN");
|
||||
supportedSets.add("UST");
|
||||
supportedSets.add("RIX");
|
||||
|
||||
sets = new LinkedHashMap<>();
|
||||
|
@ -280,7 +281,8 @@ public enum MythicspoilerComSource implements CardImageSource {
|
|||
cardNameAliases.put("XLN-lookoutsdecision", "lookoutsdispersal");
|
||||
cardNameAliases.put("XLN-infuriatedgladiodon", "ragingswordtooth");
|
||||
cardNameAliases.put("XLN-redoubledvolley", "repeatingbarrage");
|
||||
|
||||
cardNameAliases.put("UST-captialoffense", "capitaloffense");
|
||||
cardNameAliases.put("RIX-tetzimocdeathprimordial", "tetzimocprimaldeath");
|
||||
// <card name, card link>
|
||||
manualLinks = new HashMap<>();
|
||||
HashMap<String, String> links = new HashMap<>();
|
||||
|
@ -417,6 +419,8 @@ public enum MythicspoilerComSource implements CardImageSource {
|
|||
Map<String, String> setLinks = sets.computeIfAbsent(cardSet, k -> getSetLinks(cardSet));
|
||||
String searchName = card.getDownloadName().toLowerCase()
|
||||
.replaceAll(" ", "")
|
||||
.replaceAll("\\.", "")
|
||||
.replaceAll("&", "and")
|
||||
.replaceAll("-", "")
|
||||
.replaceAll("'", "")
|
||||
.replaceAll(",", "")
|
||||
|
|
|
@ -45,6 +45,7 @@ import java.util.concurrent.ExecutorService;
|
|||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.prefs.Preferences;
|
||||
import mage.cards.Sets;
|
||||
import mage.cards.repository.CardCriteria;
|
||||
import mage.cards.repository.CardInfo;
|
||||
import mage.cards.repository.CardRepository;
|
||||
|
@ -265,7 +266,7 @@ public enum WizardCardsImageSource implements CardImageSource {
|
|||
supportedSets.add("IMA"); // Iconic Msters
|
||||
supportedSets.add("E02"); // Explorers of Ixalan
|
||||
supportedSets.add("V17"); // From the Vault: Transform
|
||||
// supportedSets.add("UST"); // Unstable
|
||||
supportedSets.add("UST"); // Unstable
|
||||
// supportedSets.add("RIX"); // Rivals of Ixalan
|
||||
// supportedSets.add("A25"); // Masters 25
|
||||
// supportedSets.add("DOM"); // Dominaria
|
||||
|
@ -363,6 +364,7 @@ public enum WizardCardsImageSource implements CardImageSource {
|
|||
setsAliases.put("HOP", "Planechase");
|
||||
setsAliases.put("HOU", "Hour of Devastation");
|
||||
setsAliases.put("ICE", "Ice Age");
|
||||
setsAliases.put("IMA", "Iconic Masters");
|
||||
setsAliases.put("INV", "Invasion");
|
||||
setsAliases.put("ISD", "Innistrad");
|
||||
setsAliases.put("JOU", "Journey into Nyx");
|
||||
|
@ -455,7 +457,6 @@ public enum WizardCardsImageSource implements CardImageSource {
|
|||
setsAliases.put("WMCQ", "World Magic Cup Qualifier");
|
||||
setsAliases.put("WTH", "Weatherlight");
|
||||
setsAliases.put("WWK", "Worldwake");
|
||||
setsAliases.put("XLN", "Ixalan");
|
||||
setsAliases.put("ZEN", "Zendikar");
|
||||
|
||||
languageAliases = new HashMap<>();
|
||||
|
@ -487,43 +488,44 @@ public enum WizardCardsImageSource implements CardImageSource {
|
|||
if (card.isFlippedSide()) { //doesn't support rotated images
|
||||
return null;
|
||||
}
|
||||
String setNames = setsAliases.get(cardSet);
|
||||
if (setNames != null) {
|
||||
Map<String, String> setLinks = sets.computeIfAbsent(cardSet, k -> getSetLinks(cardSet));
|
||||
if (setLinks == null || setLinks.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
String link = setLinks.get(card.getDownloadName().toLowerCase());
|
||||
if (link == null) {
|
||||
int length = collectorId.length();
|
||||
|
||||
if (Character.isLetter(collectorId.charAt(length - 1))) {
|
||||
length -= 1;
|
||||
}
|
||||
int number = Integer.parseInt(collectorId.substring(0, length));
|
||||
if (number > 0) {
|
||||
String key = card.getDownloadName().toLowerCase() + number;
|
||||
link = setLinks.get(key);
|
||||
}
|
||||
Map<String, String> setLinks = sets.computeIfAbsent(cardSet, k -> getSetLinks(cardSet));
|
||||
if (setLinks == null || setLinks.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
String searchKey = card.getDownloadName().toLowerCase().replace(" ", "").replace("&", "//");
|
||||
String link = setLinks.get(searchKey);
|
||||
if (link == null) {
|
||||
int length = collectorId.length();
|
||||
// Try to find card image with added letter (e.g. from Unstable)
|
||||
if (Character.isLetter(collectorId.charAt(length - 1))) {
|
||||
String key = searchKey + collectorId.charAt(length - 1);
|
||||
link = setLinks.get(key);
|
||||
}
|
||||
// Try to find image with added card number (e.g. basic lands)
|
||||
if (link == null) {
|
||||
String key = searchKey + collectorId;
|
||||
link = setLinks.get(key);
|
||||
if (link == null) {
|
||||
List<String> l = new ArrayList<>(setLinks.values());
|
||||
if (l.size() >= number) {
|
||||
link = l.get(number - 1);
|
||||
} else {;
|
||||
link = l.get(number - 21);
|
||||
if (link != null) {
|
||||
link = link.replace(Integer.toString(number - 20), (Integer.toString(number - 20) + 'a'));
|
||||
int number = Integer.parseInt(collectorId.substring(0, length));
|
||||
if (number > 0) {
|
||||
List<String> l = new ArrayList<>(setLinks.values());
|
||||
if (l.size() >= number) {
|
||||
link = l.get(number - 1);
|
||||
} else {;
|
||||
link = l.get(number - 21);
|
||||
if (link != null) {
|
||||
link = link.replace(Integer.toString(number - 20), (Integer.toString(number - 20) + 'a'));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (link != null && !link.startsWith("http://")) {
|
||||
link = "http://gatherer.wizards.com" + link;
|
||||
}
|
||||
return link;
|
||||
}
|
||||
|
||||
return null;
|
||||
if (link != null && !link.startsWith("http://")) {
|
||||
link = "http://gatherer.wizards.com" + link;
|
||||
}
|
||||
return link;
|
||||
|
||||
}
|
||||
|
||||
|
@ -532,6 +534,9 @@ public enum WizardCardsImageSource implements CardImageSource {
|
|||
ExecutorService executor = Executors.newFixedThreadPool(10);
|
||||
try {
|
||||
String setNames = setsAliases.get(cardSet);
|
||||
if (setNames == null) {
|
||||
setNames = Sets.getInstance().get(cardSet).getName();
|
||||
}
|
||||
String preferedLanguage = PreferencesDialog.getCachedValue(PreferencesDialog.KEY_CARD_IMAGES_PREF_LANGUAGE, "en");
|
||||
for (String setName : setNames.split("\\^")) {
|
||||
// String URLSetName = URLEncoder.encode(setName, "UTF-8");
|
||||
|
@ -557,11 +562,21 @@ public enum WizardCardsImageSource implements CardImageSource {
|
|||
}
|
||||
String cardName = normalizeName(cardsImages.get(i).attr("alt"));
|
||||
if (cardName != null && !cardName.isEmpty()) {
|
||||
if (cardName.equals("Forest") || cardName.equals("Swamp") || cardName.equals("Mountain") || cardName.equals("Island") || cardName.equals("Plains")) {
|
||||
if (cardName.equals("Forest") || cardName.equals("Swamp") || cardName.equals("Mountain") || cardName.equals("Island")
|
||||
|| cardName.equals("Plains") || cardName.equals("Wastes")) {
|
||||
getLandVariations(setLinks, cardSet, multiverseId, cardName);
|
||||
} else {
|
||||
String numberChar = "";
|
||||
int pos1 = cardName.indexOf("(");
|
||||
if (pos1 > 0) {
|
||||
int pos2 = cardName.indexOf("(", pos1 + 1);
|
||||
if (pos2 > 0) {
|
||||
numberChar = cardName.substring(pos2 + 1, pos2 + 2);
|
||||
cardName = cardName.substring(0, pos1);
|
||||
}
|
||||
}
|
||||
Integer preferedMultiverseId = getLocalizedMultiverseId(preferedLanguage, multiverseId);
|
||||
setLinks.put(cardName.toLowerCase(), generateLink(preferedMultiverseId));
|
||||
setLinks.put(cardName.toLowerCase() + numberChar, generateLink(preferedMultiverseId));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -613,7 +628,7 @@ public enum WizardCardsImageSource implements CardImageSource {
|
|||
|
||||
private void getLandVariations(LinkedHashMap<String, String> setLinks, String cardSet, int multiverseId, String cardName) throws IOException, NumberFormatException {
|
||||
CardCriteria criteria = new CardCriteria();
|
||||
criteria.name(cardName);
|
||||
criteria.nameExact(cardName);
|
||||
criteria.setCodes(cardSet);
|
||||
List<CardInfo> cards = CardRepository.instance.findCards(criteria);
|
||||
|
||||
|
@ -697,7 +712,9 @@ public enum WizardCardsImageSource implements CardImageSource {
|
|||
.replace("\u00DB", "U").replace("\u00FB", "u")
|
||||
.replace("\u00DC", "U").replace("\u00FC", "u")
|
||||
.replace("\u00E9", "e").replace("&", "//")
|
||||
.replace(" ", "")
|
||||
.replace("Hintreland Scourge", "Hinterland Scourge");
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -4,7 +4,6 @@ import java.io.File;
|
|||
import java.net.InetSocketAddress;
|
||||
import java.net.Proxy;
|
||||
import java.util.HashMap;
|
||||
import java.util.Objects;
|
||||
import java.util.prefs.Preferences;
|
||||
import mage.client.MageFrame;
|
||||
import mage.client.constants.Constants;
|
||||
|
@ -122,17 +121,17 @@ public final class CardImageUtils {
|
|||
return set;
|
||||
}
|
||||
|
||||
public static String prepareCardNameForFile(String cardName){
|
||||
public static String prepareCardNameForFile(String cardName) {
|
||||
return cardName.replace(":", "").replace("\"", "").replace("//", "-");
|
||||
}
|
||||
|
||||
public static String getImagesDir(){
|
||||
public static String getImagesDir() {
|
||||
// return real images dir (path without separator)
|
||||
|
||||
String path = null;
|
||||
|
||||
// user path
|
||||
if (!PreferencesDialog.getCachedValue(PreferencesDialog.KEY_CARD_IMAGES_USE_DEFAULT, "true").equals("true")){
|
||||
if (!PreferencesDialog.getCachedValue(PreferencesDialog.KEY_CARD_IMAGES_USE_DEFAULT, "true").equals("true")) {
|
||||
path = PreferencesDialog.getCachedValue(PreferencesDialog.KEY_CARD_IMAGES_PATH, null);
|
||||
}
|
||||
|
||||
|
@ -141,8 +140,7 @@ public final class CardImageUtils {
|
|||
path = Constants.IO.DEFAULT_IMAGES_DIR;
|
||||
}
|
||||
|
||||
while(path.endsWith(File.separator))
|
||||
{
|
||||
while (path.endsWith(File.separator)) {
|
||||
path = path.substring(0, path.length() - 1);
|
||||
}
|
||||
|
||||
|
@ -152,7 +150,6 @@ public final class CardImageUtils {
|
|||
public static String buildImagePathToTokens() {
|
||||
String imagesPath = getImagesDir() + File.separator;
|
||||
|
||||
|
||||
if (PreferencesDialog.isSaveImagesToZip()) {
|
||||
return imagesPath + "TOK.zip" + File.separator;
|
||||
} else {
|
||||
|
@ -198,20 +195,25 @@ public final class CardImageUtils {
|
|||
String setPath = buildImagePathToSet(card);
|
||||
|
||||
String prefixType = "";
|
||||
if(card.getType() != 0){
|
||||
if (card.getType() != 0) {
|
||||
prefixType = " " + Integer.toString(card.getType());
|
||||
}
|
||||
|
||||
String cardName = card.getFileName();
|
||||
if (cardName.isEmpty()){
|
||||
if (cardName.isEmpty()) {
|
||||
cardName = prepareCardNameForFile(card.getName());
|
||||
}
|
||||
|
||||
String finalFileName = "";
|
||||
if (card.getUsesVariousArt()){
|
||||
if (card.getUsesVariousArt()) {
|
||||
finalFileName = cardName + '.' + card.getCollectorId() + ".full.jpg";
|
||||
}else{
|
||||
finalFileName = cardName + prefixType + ".full.jpg";
|
||||
} else {
|
||||
int len = card.getCollectorId().length();
|
||||
if (Character.isLetter(card.getCollectorId().charAt(len - 1))) {
|
||||
finalFileName = cardName + card.getCollectorId().charAt(len - 1) + ".full.jpg";
|
||||
} else {
|
||||
finalFileName = cardName + prefixType + ".full.jpg";
|
||||
}
|
||||
}
|
||||
|
||||
// if image file exists, correct name (for case sensitive systems)
|
||||
|
@ -219,17 +221,17 @@ public final class CardImageUtils {
|
|||
TFile dirFile = new TFile(setPath);
|
||||
TFile imageFile = new TFile(setPath + finalFileName);
|
||||
// warning, zip files can be broken
|
||||
try{
|
||||
try {
|
||||
if (dirFile.exists() && !imageFile.exists()) {
|
||||
// search like names
|
||||
for (String fileName: dirFile.list()) {
|
||||
for (String fileName : dirFile.list()) {
|
||||
if (fileName.toLowerCase().equals(finalFileName.toLowerCase())) {
|
||||
finalFileName = fileName;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}catch (Exception ex) {
|
||||
} catch (Exception ex) {
|
||||
log.error("Can't read card name from file, may be it broken: " + setPath);
|
||||
}
|
||||
|
||||
|
|
BIN
Mage.Client/src/main/resources/buttons/rarity_common_20.png
Normal file
After Width: | Height: | Size: 565 B |
BIN
Mage.Client/src/main/resources/buttons/rarity_common_32.png
Normal file
After Width: | Height: | Size: 849 B |
BIN
Mage.Client/src/main/resources/buttons/rarity_mythic_20.png
Normal file
After Width: | Height: | Size: 563 B |
BIN
Mage.Client/src/main/resources/buttons/rarity_mythic_32.png
Normal file
After Width: | Height: | Size: 753 B |
BIN
Mage.Client/src/main/resources/buttons/rarity_rare_20.png
Normal file
After Width: | Height: | Size: 541 B |
BIN
Mage.Client/src/main/resources/buttons/rarity_rare_32.png
Normal file
After Width: | Height: | Size: 767 B |
BIN
Mage.Client/src/main/resources/buttons/rarity_special_20.png
Normal file
After Width: | Height: | Size: 639 B |
BIN
Mage.Client/src/main/resources/buttons/rarity_special_32.png
Normal file
After Width: | Height: | Size: 1 KiB |
BIN
Mage.Client/src/main/resources/buttons/rarity_uncommon_20.png
Normal file
After Width: | Height: | Size: 444 B |
BIN
Mage.Client/src/main/resources/buttons/rarity_uncommon_32.png
Normal file
After Width: | Height: | Size: 644 B |
42
Mage.Client/src/test/java/mage/client/util/ChrismasTest.java
Normal 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)));
|
||||
}
|
||||
|
||||
}
|
|
@ -41,7 +41,7 @@ public class MageVersion implements Serializable, Comparable<MageVersion> {
|
|||
public final static int MAGE_VERSION_MAJOR = 1;
|
||||
public final static int MAGE_VERSION_MINOR = 4;
|
||||
public final static int MAGE_VERSION_PATCH = 26;
|
||||
public final static String MAGE_VERSION_MINOR_PATCH = "V10b";
|
||||
public final static String MAGE_VERSION_MINOR_PATCH = "V10";
|
||||
public final static String MAGE_VERSION_INFO = "";
|
||||
|
||||
private final int major;
|
||||
|
|
|
@ -119,7 +119,7 @@ class ArbiterOfTheIdealEffect extends OneShotEffect {
|
|||
Permanent permanent = game.getPermanent(card.getId());
|
||||
if (permanent != null) {
|
||||
permanent.addCounters(new Counter("Manifestation"), source, game);
|
||||
ContinuousEffect effect = new AddCardTypeTargetEffect(CardType.ENCHANTMENT, Duration.Custom);
|
||||
ContinuousEffect effect = new AddCardTypeTargetEffect(Duration.Custom, CardType.ENCHANTMENT);
|
||||
effect.setTargetPointer(new FixedTarget(permanent.getId()));
|
||||
game.addEffect(effect, source);
|
||||
}
|
||||
|
|
|
@ -46,7 +46,7 @@ public class ArgentMutation extends CardImpl {
|
|||
super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{2}{U}");
|
||||
|
||||
|
||||
this.getSpellAbility().addEffect(new AddCardTypeTargetEffect(CardType.ARTIFACT, Duration.EndOfTurn));
|
||||
this.getSpellAbility().addEffect(new AddCardTypeTargetEffect(Duration.EndOfTurn, CardType.ARTIFACT));
|
||||
this.getSpellAbility().addTarget(new TargetPermanent());
|
||||
this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(1));
|
||||
}
|
||||
|
|
|
@ -65,7 +65,7 @@ public class AshnodsTransmogrant extends CardImpl {
|
|||
// {T}, Sacrifice Ashnod's Transmogrant: Put a +1/+1 counter on target nonartifact creature. That creature becomes an artifact in addition to its other types.
|
||||
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new AddCountersTargetEffect(CounterType.P1P1.createInstance()), new TapSourceCost());
|
||||
ability.addCost(new SacrificeSourceCost());
|
||||
Effect effect = new AddCardTypeTargetEffect(CardType.ARTIFACT, Duration.WhileOnBattlefield);
|
||||
Effect effect = new AddCardTypeTargetEffect(Duration.WhileOnBattlefield, CardType.ARTIFACT);
|
||||
effect.setText("That creature becomes an artifact in addition to its other types");
|
||||
ability.addEffect(effect);
|
||||
ability.addTarget(new TargetCreaturePermanent(filter));
|
||||
|
|
93
Mage.Sets/src/mage/cards/b/BalduvianFrostwaker.java
Normal file
|
@ -0,0 +1,93 @@
|
|||
/*
|
||||
* 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.MageInt;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.common.SimpleActivatedAbility;
|
||||
import mage.abilities.costs.common.TapSourceCost;
|
||||
import mage.abilities.costs.mana.ManaCostsImpl;
|
||||
import mage.abilities.effects.common.continuous.BecomesCreatureTargetEffect;
|
||||
import mage.abilities.keyword.FlyingAbility;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.*;
|
||||
import mage.filter.common.FilterLandPermanent;
|
||||
import mage.filter.predicate.mageobject.SupertypePredicate;
|
||||
import mage.game.permanent.token.Token;
|
||||
import mage.target.TargetPermanent;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author TheElk801 & L_J
|
||||
*/
|
||||
public class BalduvianFrostwaker extends CardImpl {
|
||||
|
||||
private static final FilterLandPermanent filter = new FilterLandPermanent("snow land");
|
||||
|
||||
static {
|
||||
filter.add(new SupertypePredicate(SuperType.SNOW));
|
||||
}
|
||||
|
||||
public BalduvianFrostwaker(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{U}");
|
||||
this.subtype.add(SubType.HUMAN);
|
||||
this.subtype.add(SubType.WIZARD);
|
||||
this.power = new MageInt(1);
|
||||
this.toughness = new MageInt(1);
|
||||
|
||||
// {U}, {T}: Target snow land becomes a 2/2 blue Elemental creature with flying. It's still a land.
|
||||
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new BecomesCreatureTargetEffect(new BalduvianFrostwakerToken(), false, true, Duration.Custom), new ManaCostsImpl("{U}"));
|
||||
ability.addCost(new TapSourceCost());
|
||||
ability.addTarget(new TargetPermanent(filter));
|
||||
this.addAbility(ability);
|
||||
}
|
||||
|
||||
public BalduvianFrostwaker(final BalduvianFrostwaker card) {
|
||||
super(card);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BalduvianFrostwaker copy() {
|
||||
return new BalduvianFrostwaker(this);
|
||||
}
|
||||
}
|
||||
|
||||
class BalduvianFrostwakerToken extends Token {
|
||||
|
||||
public BalduvianFrostwakerToken() {
|
||||
super("Elemental", "2/2 blue Elemental creature with flying");
|
||||
this.cardType.add(CardType.CREATURE);
|
||||
color.setBlue(true);
|
||||
subtype.add(SubType.ELEMENTAL);
|
||||
this.power = new MageInt(2);
|
||||
this.toughness = new MageInt(2);
|
||||
this.addAbility(FlyingAbility.getInstance());
|
||||
}
|
||||
}
|
|
@ -157,15 +157,17 @@ class BaronVonCountTriggeredAbility extends TriggeredAbilityImpl {
|
|||
}
|
||||
Integer doomNumber = (Integer) game.getState().getValue(mageObject.getId() + "_doom");
|
||||
if (spell != null && sourcePermanent != null && mageObject != null && doomNumber > 0) {
|
||||
String doomString = doomNumber.toString();
|
||||
if (spell.getCard().getManaCost().getText().contains(doomString)
|
||||
|| String.valueOf(spell.getPower().getBaseValue()).contains(doomString)
|
||||
|| String.valueOf(spell.getToughness().getBaseValue()).contains(doomString)) {
|
||||
return true;
|
||||
} else {
|
||||
for (String string : spell.getCard().getRules()) {
|
||||
if (string.contains(doomString)) {
|
||||
return true;
|
||||
if (!spell.isFaceDown(game)) {
|
||||
String doomString = doomNumber.toString();
|
||||
if (spell.getCard().getManaCost().getText().contains(doomString)
|
||||
|| String.valueOf(spell.getPower().getBaseValue()).contains(doomString)
|
||||
|| String.valueOf(spell.getToughness().getBaseValue()).contains(doomString)) {
|
||||
return true;
|
||||
} else {
|
||||
for (String string : spell.getCard().getRules()) {
|
||||
if (string.contains(doomString)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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.d;
|
||||
|
||||
import java.util.UUID;
|
||||
|
@ -43,16 +42,17 @@ import mage.constants.SubType;
|
|||
*/
|
||||
public class DregscapeZombie extends CardImpl {
|
||||
|
||||
public DregscapeZombie (UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{B}");
|
||||
public DregscapeZombie(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{B}");
|
||||
this.subtype.add(SubType.ZOMBIE);
|
||||
|
||||
this.power = new MageInt(2);
|
||||
this.toughness = new MageInt(1);
|
||||
// Unearth {B} ({B}: Return this card from your graveyard to the battlefield. It gains haste. Exile it at the beginning of the next end step or if it would leave the battlefield. Unearth only as a sorcery.)
|
||||
this.addAbility(new UnearthAbility(new ManaCostsImpl("{B}")));
|
||||
}
|
||||
|
||||
public DregscapeZombie (final DregscapeZombie card) {
|
||||
public DregscapeZombie(final DregscapeZombie card) {
|
||||
super(card);
|
||||
}
|
||||
|
||||
|
|
65
Mage.Sets/src/mage/cards/e/EvenTheOdds.java
Normal file
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are
|
||||
* permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
* conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
* of conditions and the following disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* The views and conclusions contained in the software and documentation are those of the
|
||||
* authors and should not be interpreted as representing official policies, either expressed
|
||||
* or implied, of BetaSteward_at_googlemail.com.
|
||||
*/
|
||||
package mage.cards.e;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.abilities.common.CastOnlyIfConditionIsTrueAbility;
|
||||
import mage.abilities.condition.common.ControlsPermanentsComparedToOpponentsCondition;
|
||||
import mage.abilities.effects.common.CreateTokenEffect;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.ComparisonType;
|
||||
import mage.filter.StaticFilters;
|
||||
import mage.game.permanent.token.SoldierToken;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author LevelX2
|
||||
*/
|
||||
public class EvenTheOdds extends CardImpl {
|
||||
|
||||
public EvenTheOdds(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{W}");
|
||||
|
||||
// Cast Even the Odds only if you control fewer creatures than each opponent.
|
||||
this.addAbility(new CastOnlyIfConditionIsTrueAbility(new ControlsPermanentsComparedToOpponentsCondition(ComparisonType.FEWER_THAN, StaticFilters.FILTER_PERMANENT_CREATURES)));
|
||||
|
||||
// Create three 1/1 white Soldier creature tokens.
|
||||
this.getSpellAbility().addEffect(new CreateTokenEffect(new SoldierToken(), 3));
|
||||
}
|
||||
|
||||
public EvenTheOdds(final EvenTheOdds card) {
|
||||
super(card);
|
||||
}
|
||||
|
||||
@Override
|
||||
public EvenTheOdds copy() {
|
||||
return new EvenTheOdds(this);
|
||||
}
|
||||
}
|
|
@ -28,18 +28,16 @@
|
|||
package mage.cards.f;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.costs.Cost;
|
||||
import mage.abilities.costs.CostImpl;
|
||||
import mage.abilities.common.CastOnlyIfConditionIsTrueAbility;
|
||||
import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition;
|
||||
import mage.abilities.effects.common.DestroyTargetEffect;
|
||||
import mage.abilities.effects.common.GainLifeEffect;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.ComparisonType;
|
||||
import mage.constants.SubType;
|
||||
import mage.filter.common.FilterControlledCreaturePermanent;
|
||||
import mage.filter.predicate.mageobject.SubtypePredicate;
|
||||
import mage.game.Game;
|
||||
import mage.target.common.TargetCreaturePermanent;
|
||||
|
||||
/**
|
||||
|
@ -49,11 +47,14 @@ import mage.target.common.TargetCreaturePermanent;
|
|||
public class FeastOfBlood extends CardImpl {
|
||||
|
||||
public FeastOfBlood(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{1}{B}");
|
||||
|
||||
super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{1}{B}");
|
||||
|
||||
// Cast Feast of Blood only if you control two or more Vampires.
|
||||
this.getSpellAbility().addCost(new FeastOfBloodCost());
|
||||
this.addAbility(new CastOnlyIfConditionIsTrueAbility(
|
||||
new PermanentsOnTheBattlefieldCondition(
|
||||
new FilterControlledCreaturePermanent(SubType.VAMPIRE, "if you control two or more Vampires"),
|
||||
ComparisonType.MORE_THAN, 1)));
|
||||
|
||||
// Destroy target creature. You gain 4 life.
|
||||
this.getSpellAbility().addTarget(new TargetCreaturePermanent());
|
||||
this.getSpellAbility().addEffect(new DestroyTargetEffect());
|
||||
|
@ -69,36 +70,3 @@ public class FeastOfBlood extends CardImpl {
|
|||
return new FeastOfBlood(this);
|
||||
}
|
||||
}
|
||||
|
||||
class FeastOfBloodCost extends CostImpl {
|
||||
|
||||
private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent();
|
||||
|
||||
static {
|
||||
filter.add(new SubtypePredicate(SubType.VAMPIRE));
|
||||
}
|
||||
|
||||
public FeastOfBloodCost() {
|
||||
this.text = "you must control two or more Vampires";
|
||||
}
|
||||
|
||||
public FeastOfBloodCost(final FeastOfBloodCost cost) {
|
||||
super(cost);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canPay(Ability ability, UUID sourceId, UUID controllerId, Game game) {
|
||||
return game.getBattlefield().contains(filter, controllerId, 2, game);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana, Cost costToPay) {
|
||||
this.paid = true;
|
||||
return paid;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FeastOfBloodCost copy() {
|
||||
return new FeastOfBloodCost(this);
|
||||
}
|
||||
}
|
||||
|
|
77
Mage.Sets/src/mage/cards/f/FeastOfFlesh.java
Normal 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);
|
||||
}
|
||||
}
|
|
@ -27,10 +27,9 @@
|
|||
*/
|
||||
package mage.cards.f;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.MageInt;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
|
||||
import mage.abilities.effects.Effect;
|
||||
import mage.abilities.effects.common.continuous.AddCardTypeSourceEffect;
|
||||
import mage.abilities.keyword.CrewAbility;
|
||||
import mage.abilities.keyword.HasteAbility;
|
||||
|
@ -41,8 +40,6 @@ import mage.constants.CardType;
|
|||
import mage.constants.Duration;
|
||||
import mage.constants.SubType;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author emerald000
|
||||
|
@ -50,7 +47,7 @@ import java.util.UUID;
|
|||
public class FleetwheelCruiser extends CardImpl {
|
||||
|
||||
public FleetwheelCruiser(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{4}");
|
||||
super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{4}");
|
||||
this.subtype.add(SubType.VEHICLE);
|
||||
this.power = new MageInt(5);
|
||||
this.toughness = new MageInt(3);
|
||||
|
@ -62,13 +59,8 @@ public class FleetwheelCruiser extends CardImpl {
|
|||
this.addAbility(HasteAbility.getInstance());
|
||||
|
||||
// When Fleetwheel Cruiser enters the battlefield, it becomes an artifact creature until the end of turn.
|
||||
Effect effect = new AddCardTypeSourceEffect(CardType.ARTIFACT, Duration.EndOfTurn);
|
||||
effect.setText("it becomes an artifact");
|
||||
Ability ability = new EntersBattlefieldTriggeredAbility(effect);
|
||||
effect = new AddCardTypeSourceEffect(CardType.CREATURE, Duration.EndOfTurn);
|
||||
effect.setText(" creature until end of turn");
|
||||
ability.addEffect(effect);
|
||||
this.addAbility(ability);
|
||||
this.addAbility(new EntersBattlefieldTriggeredAbility(
|
||||
new AddCardTypeSourceEffect(Duration.EndOfTurn, CardType.ARTIFACT, CardType.CREATURE)));
|
||||
|
||||
// Crew 2
|
||||
this.addAbility(new CrewAbility(2));
|
||||
|
|
129
Mage.Sets/src/mage/cards/f/FrostwebSpider.java
Normal 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.f;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.MageInt;
|
||||
import mage.abilities.TriggeredAbilityImpl;
|
||||
import mage.abilities.common.delayed.AtTheEndOfCombatDelayedTriggeredAbility;
|
||||
import mage.abilities.effects.Effect;
|
||||
import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect;
|
||||
import mage.abilities.effects.common.counter.AddCountersSourceEffect;
|
||||
import mage.abilities.keyword.FlyingAbility;
|
||||
import mage.abilities.keyword.ReachAbility;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.SubType;
|
||||
import mage.constants.SuperType;
|
||||
import mage.counters.CounterType;
|
||||
import mage.constants.Zone;
|
||||
import mage.filter.FilterPermanent;
|
||||
import mage.filter.common.FilterCreaturePermanent;
|
||||
import mage.filter.predicate.mageobject.AbilityPredicate;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.game.permanent.Permanent;
|
||||
/**
|
||||
*
|
||||
* @author L_J
|
||||
*/
|
||||
public class FrostwebSpider extends CardImpl {
|
||||
|
||||
private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creature with flying");
|
||||
|
||||
static {
|
||||
filter.add(new AbilityPredicate(FlyingAbility.class));
|
||||
}
|
||||
|
||||
public FrostwebSpider(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{G}");
|
||||
this.addSuperType(SuperType.SNOW);
|
||||
this.subtype.add(SubType.SPIDER);
|
||||
this.power = new MageInt(1);
|
||||
this.toughness = new MageInt(3);
|
||||
|
||||
// Reach
|
||||
this.addAbility(ReachAbility.getInstance());
|
||||
|
||||
// Whenever Frostweb Spider blocks a creature with flying, put a +1/+1 counter on Frostweb Spider at end of combat.
|
||||
Effect effect = new CreateDelayedTriggeredAbilityEffect(new AtTheEndOfCombatDelayedTriggeredAbility(new AddCountersSourceEffect(CounterType.P1P1.createInstance())), true);
|
||||
effect.setText("put a +1/+1 counter on {this} at end of combat");
|
||||
this.addAbility(new FrostwebSpiderTriggeredAbility(effect, filter, false));
|
||||
}
|
||||
|
||||
public FrostwebSpider(final FrostwebSpider card) {
|
||||
super(card);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FrostwebSpider copy() {
|
||||
return new FrostwebSpider(this);
|
||||
}
|
||||
}
|
||||
|
||||
class FrostwebSpiderTriggeredAbility extends TriggeredAbilityImpl {
|
||||
|
||||
protected FilterPermanent filter;
|
||||
|
||||
public FrostwebSpiderTriggeredAbility(Effect effect, FilterPermanent filter, boolean optional) {
|
||||
super(Zone.BATTLEFIELD, effect, optional);
|
||||
this.filter = filter;
|
||||
}
|
||||
|
||||
public FrostwebSpiderTriggeredAbility(final FrostwebSpiderTriggeredAbility 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 FrostwebSpiderTriggeredAbility copy() {
|
||||
return new FrostwebSpiderTriggeredAbility(this);
|
||||
}
|
||||
}
|
|
@ -37,6 +37,7 @@ import mage.cards.CardImpl;
|
|||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.SubType;
|
||||
import mage.filter.FilterPermanent;
|
||||
import mage.filter.predicate.permanent.CounterPredicate;
|
||||
import mage.game.Game;
|
||||
|
@ -48,12 +49,12 @@ import mage.players.Player;
|
|||
*
|
||||
* @author spjspj
|
||||
*/
|
||||
public class GarbageElemental extends CardImpl {
|
||||
public class GarbageElementalC extends CardImpl {
|
||||
|
||||
public GarbageElemental(UUID ownerId, CardSetInfo setInfo) {
|
||||
public GarbageElementalC(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{R}");
|
||||
|
||||
this.subtype.add("Elemental");
|
||||
this.subtype.add(SubType.ELEMENTAL);
|
||||
this.power = new MageInt(3);
|
||||
this.toughness = new MageInt(2);
|
||||
|
||||
|
@ -68,13 +69,13 @@ public class GarbageElemental extends CardImpl {
|
|||
|
||||
}
|
||||
|
||||
public GarbageElemental(final GarbageElemental card) {
|
||||
public GarbageElementalC(final GarbageElementalC card) {
|
||||
super(card);
|
||||
}
|
||||
|
||||
@Override
|
||||
public GarbageElemental copy() {
|
||||
return new GarbageElemental(this);
|
||||
public GarbageElementalC copy() {
|
||||
return new GarbageElementalC(this);
|
||||
}
|
||||
}
|
||||
|
126
Mage.Sets/src/mage/cards/g/GarzasAssassin.java
Normal 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.g;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.MageInt;
|
||||
import mage.ObjectColor;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.common.SimpleActivatedAbility;
|
||||
import mage.abilities.costs.Cost;
|
||||
import mage.abilities.costs.CostImpl;
|
||||
import mage.abilities.costs.common.SacrificeSourceCost;
|
||||
import mage.abilities.effects.common.DestroyTargetEffect;
|
||||
import mage.abilities.keyword.RecoverAbility;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.SubType;
|
||||
import mage.constants.Zone;
|
||||
import mage.filter.common.FilterCreaturePermanent;
|
||||
import mage.filter.predicate.Predicates;
|
||||
import mage.filter.predicate.mageobject.ColorPredicate;
|
||||
import mage.game.Game;
|
||||
import mage.players.Player;
|
||||
import mage.target.common.TargetCreaturePermanent;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author choiseul11 & L_J
|
||||
*/
|
||||
public class GarzasAssassin extends CardImpl {
|
||||
|
||||
private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("nonblack creature");
|
||||
|
||||
static {
|
||||
filter.add(Predicates.not(new ColorPredicate(ObjectColor.BLACK)));
|
||||
}
|
||||
|
||||
public GarzasAssassin(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{B}{B}{B}");
|
||||
this.subtype.add(SubType.HUMAN);
|
||||
this.subtype.add(SubType.ASSASSIN);
|
||||
this.power = new MageInt(2);
|
||||
this.toughness = new MageInt(2);
|
||||
|
||||
// Sacrifice Garza's Assassin: Destroy target nonblack creature.
|
||||
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DestroyTargetEffect(), new SacrificeSourceCost());
|
||||
ability.addTarget(new TargetCreaturePermanent(filter));
|
||||
this.addAbility(ability);
|
||||
|
||||
// Recover—Pay half your life, rounded up.
|
||||
this.addAbility(new RecoverAbility(new GarzasAssassinCost(), this));
|
||||
}
|
||||
|
||||
public GarzasAssassin(final GarzasAssassin card) {
|
||||
super(card);
|
||||
}
|
||||
|
||||
@Override
|
||||
public GarzasAssassin copy() {
|
||||
return new GarzasAssassin(this);
|
||||
}
|
||||
}
|
||||
|
||||
class GarzasAssassinCost extends CostImpl {
|
||||
|
||||
GarzasAssassinCost() {
|
||||
this.text = "Pay half your life, rounded up";
|
||||
}
|
||||
|
||||
GarzasAssassinCost(GarzasAssassinCost cost) {
|
||||
super(cost);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canPay(Ability ability, UUID sourceId, UUID controllerId, Game game) {
|
||||
Player controller = game.getPlayer(controllerId);
|
||||
return controller != null && (controller.getLife() < 1 || controller.canPayLifeCost());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana, Cost costToPay) {
|
||||
Player controller = game.getPlayer(controllerId);
|
||||
if (controller != null) {
|
||||
int currentLife = controller.getLife();
|
||||
int lifeToPay = (currentLife + currentLife % 2) / 2; // Divide by two and round up.
|
||||
if (lifeToPay < 0) {
|
||||
this.paid = true;
|
||||
} else {
|
||||
this.paid = (controller.loseLife(lifeToPay, game, false) == lifeToPay);
|
||||
}
|
||||
return this.paid;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public GarzasAssassinCost copy() {
|
||||
return new GarzasAssassinCost(this);
|
||||
}
|
||||
}
|
99
Mage.Sets/src/mage/cards/g/GoblinFurrier.java
Normal file
|
@ -0,0 +1,99 @@
|
|||
/*
|
||||
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are
|
||||
* permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
* conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
* of conditions and the following disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* The views and conclusions contained in the software and documentation are those of the
|
||||
* authors and should not be interpreted as representing official policies, either expressed
|
||||
* or implied, of BetaSteward_at_googlemail.com.
|
||||
*/
|
||||
package mage.cards.g;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.MageInt;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.common.SimpleStaticAbility;
|
||||
import mage.abilities.effects.PreventionEffectImpl;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.SubType;
|
||||
import mage.constants.Duration;
|
||||
import mage.constants.Zone;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.game.permanent.Permanent;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author LevelX2 & L_J
|
||||
*/
|
||||
public class GoblinFurrier extends CardImpl {
|
||||
|
||||
public GoblinFurrier(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{R}");
|
||||
this.subtype.add(SubType.GOBLIN);
|
||||
this.subtype.add(SubType.WARRIOR);
|
||||
this.power = new MageInt(2);
|
||||
this.toughness = new MageInt(2);
|
||||
|
||||
// Prevent all damage that Goblin Furrier would deal to snow creatures.
|
||||
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GoblinFurrierPreventEffectEffect(Duration.WhileOnBattlefield)));
|
||||
}
|
||||
|
||||
public GoblinFurrier(final GoblinFurrier card) {
|
||||
super(card);
|
||||
}
|
||||
|
||||
@Override
|
||||
public GoblinFurrier copy() {
|
||||
return new GoblinFurrier(this);
|
||||
}
|
||||
}
|
||||
|
||||
class GoblinFurrierPreventEffectEffect extends PreventionEffectImpl {
|
||||
|
||||
public GoblinFurrierPreventEffectEffect(Duration duration) {
|
||||
super(duration, Integer.MAX_VALUE, false);
|
||||
staticText = "Prevent all damage that {this} would deal to snow creatures";
|
||||
}
|
||||
|
||||
public GoblinFurrierPreventEffectEffect(final GoblinFurrierPreventEffectEffect effect) {
|
||||
super(effect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public GoblinFurrierPreventEffectEffect copy() {
|
||||
return new GoblinFurrierPreventEffectEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean applies(GameEvent event, Ability source, Game game) {
|
||||
if (super.applies(event, source, game)) {
|
||||
if (event.getSourceId().equals(source.getSourceId())) {
|
||||
Permanent damageTo = game.getPermanent(event.getTargetId());
|
||||
return damageTo != null && damageTo.isSnow();
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
|
@ -27,6 +27,7 @@
|
|||
*/
|
||||
package mage.cards.h;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.MageInt;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.common.SimpleActivatedAbility;
|
||||
|
@ -48,8 +49,6 @@ import mage.game.permanent.Permanent;
|
|||
import mage.target.Target;
|
||||
import mage.target.common.TargetControlledPermanent;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* @author JRHerlehy
|
||||
*/
|
||||
|
@ -74,7 +73,7 @@ public class HeartOfKiran extends CardImpl {
|
|||
|
||||
// You may remove a loyalty counter from a planeswalker you control rather than pay Heart of Kiran's crew cost.
|
||||
Cost cost = new HeartOfKiranAlternateCrewCost(CounterType.LOYALTY, 1);
|
||||
Effect effect = new AddCardTypeSourceEffect(CardType.CREATURE, Duration.EndOfTurn);
|
||||
Effect effect = new AddCardTypeSourceEffect(Duration.EndOfTurn, CardType.CREATURE, CardType.CREATURE);
|
||||
effect.setText("You may remove a loyalty counter from a planeswalker you control rather than pay {this}'s crew cost");
|
||||
this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, effect, cost));
|
||||
}
|
||||
|
@ -91,8 +90,8 @@ public class HeartOfKiran extends CardImpl {
|
|||
|
||||
class HeartOfKiranAlternateCrewCost extends CostImpl {
|
||||
|
||||
private CounterType counterTypeToRemove;
|
||||
private int countersToRemove;
|
||||
private final CounterType counterTypeToRemove;
|
||||
private final int countersToRemove;
|
||||
|
||||
private static final FilterControlledPlaneswalkerPermanent filter = new FilterControlledPlaneswalkerPermanent("planeswalker you control");
|
||||
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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)) {
|
||||
|
|
|
@ -99,6 +99,9 @@ class KarnsTouchEffect extends ContinuousEffectImpl {
|
|||
switch (layer) {
|
||||
case TypeChangingEffects_4:
|
||||
if (sublayer == SubLayer.NA) {
|
||||
if (!artifact.isArtifact()) {
|
||||
artifact.addCardType(CardType.ARTIFACT);
|
||||
}
|
||||
if (!artifact.isCreature()) {
|
||||
artifact.addCardType(CardType.CREATURE);
|
||||
}
|
||||
|
|
73
Mage.Sets/src/mage/cards/k/KjeldoranWarCry.java
Normal file
|
@ -0,0 +1,73 @@
|
|||
/*
|
||||
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are
|
||||
* permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
* conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
* of conditions and the following disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* The views and conclusions contained in the software and documentation are those of the
|
||||
* authors and should not be interpreted as representing official policies, either expressed
|
||||
* or implied, of BetaSteward_at_googlemail.com.
|
||||
*/
|
||||
package mage.cards.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);
|
||||
}
|
||||
}
|
|
@ -50,7 +50,7 @@ public class LiquimetalCoating extends CardImpl {
|
|||
super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{2}");
|
||||
|
||||
// {T}: Target permanent becomes an artifact in addition to its other types until end of turn.
|
||||
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new AddCardTypeTargetEffect(CardType.ARTIFACT, Duration.EndOfTurn), new TapSourceCost());
|
||||
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new AddCardTypeTargetEffect(Duration.EndOfTurn, CardType.ARTIFACT), new TapSourceCost());
|
||||
ability.addTarget(new TargetPermanent());
|
||||
this.addAbility(ability);
|
||||
}
|
||||
|
|
|
@ -60,7 +60,7 @@ public class Memnarch extends CardImpl {
|
|||
this.toughness = new MageInt(5);
|
||||
|
||||
// {1}{U}{U}: Target permanent becomes an artifact in addition to its other types.
|
||||
Effect effect = new AddCardTypeTargetEffect(CardType.ARTIFACT, Duration.WhileOnBattlefield);
|
||||
Effect effect = new AddCardTypeTargetEffect(Duration.WhileOnBattlefield, CardType.ARTIFACT);
|
||||
effect.setText("Target permanent becomes an artifact in addition to its other types");
|
||||
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, effect, new ManaCostsImpl("{1}{U}{U}"));
|
||||
ability.addTarget(new TargetPermanent());
|
||||
|
|
|
@ -103,7 +103,7 @@ class MirrorOfTheForebearsCopyEffect extends OneShotEffect {
|
|||
if (sourcePermanent != null && copyFromPermanent != null) {
|
||||
game.copyPermanent(Duration.EndOfTurn, copyFromPermanent, sourcePermanent.getId(), source, new EmptyApplyToPermanent());
|
||||
if (!copyFromPermanent.isArtifact()) {
|
||||
ContinuousEffect effect = new AddCardTypeTargetEffect(CardType.ARTIFACT, Duration.EndOfTurn);
|
||||
ContinuousEffect effect = new AddCardTypeTargetEffect(Duration.EndOfTurn, CardType.ARTIFACT);
|
||||
effect.setTargetPointer(new FixedTarget(sourcePermanent, game));
|
||||
game.addEffect(effect, source);
|
||||
}
|
||||
|
|
|
@ -55,7 +55,7 @@ public class MyrLandshaper extends CardImpl {
|
|||
this.toughness = new MageInt(1);
|
||||
|
||||
// {tap}: Target land becomes an artifact in addition to its other types until end of turn.
|
||||
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new AddCardTypeTargetEffect(CardType.ARTIFACT, Duration.EndOfTurn), new TapSourceCost());
|
||||
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new AddCardTypeTargetEffect(Duration.EndOfTurn, CardType.ARTIFACT), new TapSourceCost());
|
||||
Target target = new TargetLandPermanent();
|
||||
ability.addTarget(target);
|
||||
this.addAbility(ability);
|
||||
|
|
|
@ -67,7 +67,7 @@ public class PeacewalkerColossus extends CardImpl {
|
|||
this.toughness = new MageInt(6);
|
||||
|
||||
// {1}{W}: Another target Vehicle you control becomes an artifact creature until end of turn.
|
||||
Effect effect = new AddCardTypeTargetEffect(CardType.CREATURE, Duration.EndOfTurn);
|
||||
Effect effect = new AddCardTypeTargetEffect(Duration.EndOfTurn, CardType.CREATURE);
|
||||
effect.setText("Another target Vehicle you control becomes an artifact creature until end of turn");
|
||||
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, effect, new ManaCostsImpl("{1}{W}"));
|
||||
ability.addTarget(new TargetControlledPermanent(filter));
|
||||
|
|
153
Mage.Sets/src/mage/cards/r/RimehornAurochs.java
Normal file
|
@ -0,0 +1,153 @@
|
|||
/*
|
||||
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are
|
||||
* permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
* conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
* of conditions and the following disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* The views and conclusions contained in the software and documentation are those of the
|
||||
* authors and should not be interpreted as representing official policies, either expressed
|
||||
* or implied, of BetaSteward_at_googlemail.com.
|
||||
*/
|
||||
package mage.cards.r;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.MageInt;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.common.AttacksTriggeredAbility;
|
||||
import mage.abilities.common.SimpleActivatedAbility;
|
||||
import mage.abilities.costs.mana.ManaCostsImpl;
|
||||
import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount;
|
||||
import mage.abilities.dynamicvalue.common.StaticValue;
|
||||
import mage.abilities.effects.RequirementEffect;
|
||||
import mage.abilities.effects.common.continuous.BoostSourceEffect;
|
||||
import mage.abilities.keyword.TrampleAbility;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.*;
|
||||
import mage.filter.common.FilterCreaturePermanent;
|
||||
import mage.filter.predicate.permanent.AnotherPredicate;
|
||||
import mage.filter.predicate.permanent.AttackingPredicate;
|
||||
import mage.game.Game;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.target.common.TargetCreaturePermanent;
|
||||
import mage.watchers.common.BlockedAttackerWatcher;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author jeffwadsworth & L_J
|
||||
*/
|
||||
public class RimehornAurochs extends CardImpl {
|
||||
|
||||
private static final FilterCreaturePermanent filter = new FilterCreaturePermanent(SubType.AUROCHS, "other attacking Aurochs");
|
||||
|
||||
static {
|
||||
filter.add(new AttackingPredicate());
|
||||
filter.add(new AnotherPredicate());
|
||||
}
|
||||
|
||||
public RimehornAurochs(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{4}{G}");
|
||||
this.addSuperType(SuperType.SNOW);
|
||||
this.subtype.add(SubType.AUROCHS);
|
||||
this.power = new MageInt(3);
|
||||
this.toughness = new MageInt(3);
|
||||
|
||||
// Trample
|
||||
this.addAbility(TrampleAbility.getInstance());
|
||||
|
||||
// Whenever Rimehorn Aurochs attacks, it gets +1/+0 until end of turn for each other attacking Aurochs.
|
||||
this.addAbility(new AttacksTriggeredAbility(new BoostSourceEffect(new PermanentsOnBattlefieldCount(filter), new StaticValue(0), Duration.EndOfTurn, true), false));
|
||||
|
||||
// {2}{S}: Target creature blocks target creature this turn if able.
|
||||
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new RimehornAurochsEffect(), new ManaCostsImpl("{2}{S}"));
|
||||
ability.addTarget(new TargetCreaturePermanent(new FilterCreaturePermanent("creature that must block")));
|
||||
ability.addTarget(new TargetCreaturePermanent(new FilterCreaturePermanent("creature that is to be blocked")));
|
||||
this.addAbility(ability, new BlockedAttackerWatcher());
|
||||
}
|
||||
|
||||
public RimehornAurochs(final RimehornAurochs card) {
|
||||
super(card);
|
||||
}
|
||||
|
||||
@Override
|
||||
public RimehornAurochs copy() {
|
||||
return new RimehornAurochs(this);
|
||||
}
|
||||
}
|
||||
|
||||
class RimehornAurochsEffect extends RequirementEffect {
|
||||
|
||||
public RimehornAurochsEffect() {
|
||||
this(Duration.EndOfTurn);
|
||||
}
|
||||
|
||||
public RimehornAurochsEffect(Duration duration) {
|
||||
super(duration);
|
||||
staticText = "Target creature blocks target creature this turn if able";
|
||||
}
|
||||
|
||||
public RimehornAurochsEffect(final RimehornAurochsEffect effect) {
|
||||
super(effect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean applies(Permanent permanent, Ability source, Game game) {
|
||||
if (permanent.getId().equals(source.getTargets().get(0).getFirstTarget())) {
|
||||
Permanent blocker = game.getPermanent(source.getTargets().get(0).getFirstTarget());
|
||||
if (blocker != null
|
||||
&& blocker.canBlock(source.getTargets().get(1).getFirstTarget(), game)) {
|
||||
Permanent attacker = (Permanent) game.getPermanent(source.getTargets().get(1).getFirstTarget());
|
||||
if (attacker != null) {
|
||||
BlockedAttackerWatcher blockedAttackerWatcher = (BlockedAttackerWatcher) game.getState().getWatchers().get(BlockedAttackerWatcher.class.getSimpleName());
|
||||
if (blockedAttackerWatcher != null
|
||||
&& blockedAttackerWatcher.creatureHasBlockedAttacker(attacker, blocker, game)) {
|
||||
// has already blocked this turn, so no need to do again
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
discard();
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean mustAttack(Game game) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean mustBlock(Game game) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public UUID mustBlockAttacker(Ability source, Game game) {
|
||||
return source.getTargets().get(1).getFirstTarget();
|
||||
}
|
||||
|
||||
@Override
|
||||
public RimehornAurochsEffect copy() {
|
||||
return new RimehornAurochsEffect(this);
|
||||
}
|
||||
|
||||
}
|
|
@ -27,6 +27,7 @@
|
|||
*/
|
||||
package mage.cards.s;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.MageObject;
|
||||
import mage.ObjectColor;
|
||||
import mage.abilities.Ability;
|
||||
|
@ -34,7 +35,7 @@ import mage.abilities.costs.AlternativeCostSourceAbility;
|
|||
import mage.abilities.costs.common.ExileFromHandCost;
|
||||
import mage.abilities.dynamicvalue.DynamicValue;
|
||||
import mage.abilities.dynamicvalue.common.ExileFromHandCostCardConvertedMana;
|
||||
import mage.abilities.effects.PreventionEffectImpl;
|
||||
import mage.abilities.effects.common.RedirectDamageFromSourceToTargetEffect;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.CardType;
|
||||
|
@ -45,7 +46,6 @@ import mage.filter.predicate.Predicates;
|
|||
import mage.filter.predicate.mageobject.CardIdPredicate;
|
||||
import mage.filter.predicate.mageobject.ColorPredicate;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.DamageEvent;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.players.Player;
|
||||
|
@ -53,8 +53,6 @@ import mage.target.TargetSource;
|
|||
import mage.target.common.TargetCardInHand;
|
||||
import mage.target.common.TargetCreatureOrPlayer;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author LevelX2
|
||||
|
@ -62,7 +60,7 @@ import java.util.UUID;
|
|||
public class ShiningShoal extends CardImpl {
|
||||
|
||||
public ShiningShoal(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{X}{W}{W}");
|
||||
super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{X}{W}{W}");
|
||||
this.subtype.add(SubType.ARCANE);
|
||||
|
||||
// You may exile a white card with converted mana cost X from your hand rather than pay Shining Shoal's mana cost
|
||||
|
@ -72,7 +70,7 @@ public class ShiningShoal extends CardImpl {
|
|||
this.addAbility(new AlternativeCostSourceAbility(new ExileFromHandCost(new TargetCardInHand(filter), true)));
|
||||
|
||||
// The next X damage that a source of your choice would deal to you and/or creatures you control this turn is dealt to target creature or player instead.
|
||||
this.getSpellAbility().addEffect(new ShiningShoalPreventDamageTargetEffect(Duration.EndOfTurn, new ExileFromHandCostCardConvertedMana()));
|
||||
this.getSpellAbility().addEffect(new ShiningShoalRedirectDamageTargetEffect(Duration.EndOfTurn, new ExileFromHandCostCardConvertedMana()));
|
||||
this.getSpellAbility().addTarget(new TargetSource());
|
||||
this.getSpellAbility().addTarget(new TargetCreatureOrPlayer());
|
||||
}
|
||||
|
@ -87,31 +85,29 @@ public class ShiningShoal extends CardImpl {
|
|||
}
|
||||
}
|
||||
|
||||
class ShiningShoalPreventDamageTargetEffect extends PreventionEffectImpl {
|
||||
class ShiningShoalRedirectDamageTargetEffect extends RedirectDamageFromSourceToTargetEffect {
|
||||
|
||||
private final DynamicValue dynamicAmount;
|
||||
private int amount;
|
||||
|
||||
public ShiningShoalPreventDamageTargetEffect(Duration duration, DynamicValue dynamicAmount) {
|
||||
super(duration);
|
||||
public ShiningShoalRedirectDamageTargetEffect(Duration duration, DynamicValue dynamicAmount) {
|
||||
super(duration, 0, true);
|
||||
this.dynamicAmount = dynamicAmount;
|
||||
staticText = "The next X damage that a source of your choice would deal to you and/or creatures you control this turn is dealt to target creature or player instead";
|
||||
}
|
||||
|
||||
public ShiningShoalPreventDamageTargetEffect(final ShiningShoalPreventDamageTargetEffect effect) {
|
||||
public ShiningShoalRedirectDamageTargetEffect(final ShiningShoalRedirectDamageTargetEffect effect) {
|
||||
super(effect);
|
||||
this.amount = effect.amount;
|
||||
this.dynamicAmount = effect.dynamicAmount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ShiningShoalPreventDamageTargetEffect copy() {
|
||||
return new ShiningShoalPreventDamageTargetEffect(this);
|
||||
public ShiningShoalRedirectDamageTargetEffect copy() {
|
||||
return new ShiningShoalRedirectDamageTargetEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(Ability source, Game game) {
|
||||
this.amount = dynamicAmount.calculate(game, source, this);
|
||||
amountToRedirect = dynamicAmount.calculate(game, source, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -119,49 +115,9 @@ class ShiningShoalPreventDamageTargetEffect extends PreventionEffectImpl {
|
|||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean replaceEvent(GameEvent event, Ability source, Game game) {
|
||||
GameEvent preventEvent = new GameEvent(GameEvent.EventType.PREVENT_DAMAGE, source.getFirstTarget(), source.getSourceId(), source.getControllerId(), event.getAmount(), false);
|
||||
if (!game.replaceEvent(preventEvent)) {
|
||||
int prevented;
|
||||
if (event.getAmount() >= this.amount) {
|
||||
int damage = amount;
|
||||
event.setAmount(event.getAmount() - amount);
|
||||
this.used = true;
|
||||
game.fireEvent(GameEvent.getEvent(GameEvent.EventType.PREVENTED_DAMAGE, source.getFirstTarget(), source.getSourceId(), source.getControllerId(), damage));
|
||||
prevented = damage;
|
||||
} else {
|
||||
int damage = event.getAmount();
|
||||
event.setAmount(0);
|
||||
amount -= damage;
|
||||
game.fireEvent(GameEvent.getEvent(GameEvent.EventType.PREVENTED_DAMAGE, source.getFirstTarget(), source.getSourceId(), source.getControllerId(), damage));
|
||||
prevented = damage;
|
||||
}
|
||||
|
||||
// deal damage now
|
||||
if (prevented > 0) {
|
||||
UUID redirectTo = source.getTargets().get(1).getFirstTarget();
|
||||
Permanent permanent = game.getPermanent(redirectTo);
|
||||
MageObject sourceObject = game.getObject(source.getFirstTarget());
|
||||
if (permanent != null) {
|
||||
game.informPlayers(sourceObject.getIdName() + "deals " + prevented + " to " + permanent.getName() + " instead");
|
||||
// keep the original source id as it is redirecting
|
||||
permanent.damage(prevented, event.getSourceId(), game, ((DamageEvent) event).isCombatDamage(), ((DamageEvent) event).isPreventable(), event.getAppliedEffects());
|
||||
}
|
||||
Player player = game.getPlayer(redirectTo);
|
||||
if (player != null) {
|
||||
game.informPlayers(sourceObject.getIdName() + "deals " + prevented + " to " + player.getLogName() + " instead");
|
||||
// keep the original source id as it is redirecting
|
||||
player.damage(prevented, event.getSourceId(), game, ((DamageEvent) event).isCombatDamage(), ((DamageEvent) event).isPreventable(), event.getAppliedEffects());
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean applies(GameEvent event, Ability source, Game game) {
|
||||
if (!this.used && super.applies(event, source, game)) {
|
||||
if (!this.used && event.getFlag()) {
|
||||
|
||||
// get source of the damage event
|
||||
MageObject sourceObject = game.getObject(event.getSourceId());
|
||||
|
@ -173,7 +129,7 @@ class ShiningShoalPreventDamageTargetEffect extends PreventionEffectImpl {
|
|||
return false;
|
||||
}
|
||||
// do the 2 objects match?
|
||||
if (sourceObject.getId() != chosenSourceObject.getId()) {
|
||||
if (!sourceObject.getId().equals(chosenSourceObject.getId())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -183,6 +139,7 @@ class ShiningShoalPreventDamageTargetEffect extends PreventionEffectImpl {
|
|||
if (permanent != null && permanent.isCreature()) {
|
||||
if (permanent.getControllerId().equals(source.getControllerId())) {
|
||||
// it's your creature
|
||||
redirectTarget = source.getTargets().get(1);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -191,6 +148,7 @@ class ShiningShoalPreventDamageTargetEffect extends PreventionEffectImpl {
|
|||
if (player != null) {
|
||||
if (player.getId().equals(source.getControllerId())) {
|
||||
// it is you
|
||||
redirectTarget = source.getTargets().get(1);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -44,12 +44,15 @@ import mage.constants.*;
|
|||
public class SilverskinArmor extends CardImpl {
|
||||
|
||||
public SilverskinArmor(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{2}");
|
||||
super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{2}");
|
||||
this.subtype.add(SubType.EQUIPMENT);
|
||||
|
||||
this.addAbility(new EquipAbility(Outcome.BoostCreature, new ManaCostsImpl("{2}")));
|
||||
// Equipped creature gets +1/+1 and is an artifact in addition to its other types.
|
||||
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostEquippedEffect(1, 1, Duration.WhileOnBattlefield)));
|
||||
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new AddCardTypeAttachedEffect(CardType.ARTIFACT, Duration.WhileOnBattlefield, AttachmentType.EQUIPMENT)));
|
||||
|
||||
// Equip {2}
|
||||
this.addAbility(new EquipAbility(Outcome.BoostCreature, new ManaCostsImpl("{2}")));
|
||||
}
|
||||
|
||||
public SilverskinArmor(final SilverskinArmor card) {
|
||||
|
|
|
@ -56,6 +56,7 @@ public class SydriGalvanicGenius extends CardImpl {
|
|||
|
||||
private static final FilterPermanent filter = new FilterPermanent("artifact creature");
|
||||
private static final FilterArtifactPermanent filterNonCreature = new FilterArtifactPermanent("noncreature artifact");
|
||||
|
||||
static {
|
||||
filter.add(new CardTypePredicate(CardType.ARTIFACT));
|
||||
filter.add(new CardTypePredicate(CardType.CREATURE));
|
||||
|
@ -63,7 +64,7 @@ public class SydriGalvanicGenius extends CardImpl {
|
|||
}
|
||||
|
||||
public SydriGalvanicGenius(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{W}{U}{B}");
|
||||
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{W}{U}{B}");
|
||||
addSuperType(SuperType.LEGENDARY);
|
||||
this.subtype.add(SubType.HUMAN);
|
||||
this.subtype.add(SubType.ARTIFICER);
|
||||
|
@ -119,6 +120,9 @@ class SydriGalvanicGeniusEffect extends ContinuousEffectImpl {
|
|||
switch (layer) {
|
||||
case TypeChangingEffects_4:
|
||||
if (sublayer == SubLayer.NA) {
|
||||
if (!artifact.isArtifact()) {
|
||||
artifact.addCardType(CardType.ARTIFACT);
|
||||
}
|
||||
if (!artifact.isCreature()) {
|
||||
artifact.addCardType(CardType.CREATURE);
|
||||
}
|
||||
|
@ -140,7 +144,6 @@ class SydriGalvanicGeniusEffect extends ContinuousEffectImpl {
|
|||
return false;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean hasLayer(Layer layer) {
|
||||
return layer == Layer.PTChangingEffects_7 || layer == Layer.TypeChangingEffects_4;
|
||||
|
|
|
@ -31,7 +31,6 @@ import java.util.UUID;
|
|||
import mage.abilities.Ability;
|
||||
import mage.abilities.LoyaltyAbility;
|
||||
import mage.abilities.common.PlanswalkerEntersWithLoyalityCountersAbility;
|
||||
import mage.abilities.dynamicvalue.DynamicValue;
|
||||
import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount;
|
||||
import mage.abilities.effects.Effect;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
|
@ -41,12 +40,12 @@ import mage.abilities.effects.common.continuous.SetPowerToughnessTargetEffect;
|
|||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.SubType;
|
||||
import mage.constants.Duration;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.SubType;
|
||||
import mage.constants.SuperType;
|
||||
import mage.filter.FilterCard;
|
||||
import mage.filter.common.FilterControlledPermanent;
|
||||
import mage.filter.StaticFilters;
|
||||
import mage.filter.predicate.mageobject.CardTypePredicate;
|
||||
import mage.game.Game;
|
||||
import mage.players.Player;
|
||||
|
@ -66,7 +65,7 @@ public class TezzeretAgentOfBolas extends CardImpl {
|
|||
}
|
||||
|
||||
public TezzeretAgentOfBolas(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId,setInfo,new CardType[]{CardType.PLANESWALKER},"{2}{U}{B}");
|
||||
super(ownerId, setInfo, new CardType[]{CardType.PLANESWALKER}, "{2}{U}{B}");
|
||||
this.addSuperType(SuperType.LEGENDARY);
|
||||
this.subtype.add(SubType.TEZZERET);
|
||||
|
||||
|
@ -76,7 +75,7 @@ public class TezzeretAgentOfBolas extends CardImpl {
|
|||
this.addAbility(new LoyaltyAbility(new LookLibraryAndPickControllerEffect(5, 1, filter, true), 1));
|
||||
|
||||
// -1: Target artifact becomes an artifact creature with base power and toughness 5/5.
|
||||
Effect effect = new AddCardTypeTargetEffect(CardType.CREATURE, Duration.EndOfGame);
|
||||
Effect effect = new AddCardTypeTargetEffect(Duration.EndOfGame, CardType.ARTIFACT, CardType.CREATURE);
|
||||
effect.setText("Target artifact becomes an artifact creature");
|
||||
LoyaltyAbility ability1 = new LoyaltyAbility(effect, -1);
|
||||
effect = new SetPowerToughnessTargetEffect(5, 5, Duration.EndOfGame);
|
||||
|
@ -105,12 +104,6 @@ public class TezzeretAgentOfBolas extends CardImpl {
|
|||
|
||||
class TezzeretAgentOfBolasEffect2 extends OneShotEffect {
|
||||
|
||||
final static FilterControlledPermanent filter = new FilterControlledPermanent("artifacts");
|
||||
|
||||
static {
|
||||
filter.add(new CardTypePredicate(CardType.ARTIFACT));
|
||||
}
|
||||
|
||||
public TezzeretAgentOfBolasEffect2() {
|
||||
super(Outcome.DrawCard);
|
||||
staticText = "Target player loses X life and you gain X life, where X is twice the number of artifacts you control";
|
||||
|
@ -127,16 +120,16 @@ class TezzeretAgentOfBolasEffect2 extends OneShotEffect {
|
|||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
DynamicValue value = new PermanentsOnBattlefieldCount(filter);
|
||||
int count = value.calculate(game, source, this) * 2;
|
||||
|
||||
Player player = game.getPlayer(source.getFirstTarget());
|
||||
if (player != null) {
|
||||
player.loseLife(count, game, false);
|
||||
}
|
||||
Player controller = game.getPlayer(source.getControllerId());
|
||||
if (controller != null) {
|
||||
controller.gainLife(count, game);
|
||||
int count = new PermanentsOnBattlefieldCount(StaticFilters.FILTER_CONTROLLED_PERMANENT_ARTIFACT).calculate(game, source, this) * 2;
|
||||
if (count > 0) {
|
||||
Player targetPlayer = game.getPlayer(getTargetPointer().getFirst(game, source));
|
||||
if (targetPlayer != null) {
|
||||
targetPlayer.loseLife(count, game, false);
|
||||
}
|
||||
Player controller = game.getPlayer(source.getControllerId());
|
||||
if (controller != null) {
|
||||
controller.gainLife(count, game);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
129
Mage.Sets/src/mage/cards/t/ThermalFlux.java
Normal 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;
|
||||
}
|
||||
}
|
|
@ -65,7 +65,7 @@ public class ThranForge extends CardImpl {
|
|||
.setText("Until end of turn, target nonartifact creature gets +1/+0"),
|
||||
new GenericManaCost(2));
|
||||
ability.addEffect(
|
||||
new AddCardTypeTargetEffect(CardType.ARTIFACT, Duration.EndOfTurn)
|
||||
new AddCardTypeTargetEffect(Duration.EndOfTurn, CardType.ARTIFACT)
|
||||
.setText("and becomes an artifact in addition to its other types")
|
||||
);
|
||||
ability.addTarget(new TargetPermanent(filter));
|
||||
|
|
|
@ -55,7 +55,7 @@ import mage.game.permanent.Permanent;
|
|||
public class TitaniasSong extends CardImpl {
|
||||
|
||||
public TitaniasSong(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{3}{G}");
|
||||
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{3}{G}");
|
||||
|
||||
// Each noncreature artifact loses all abilities and becomes an artifact creature with power and toughness each equal to its converted mana cost. If Titania's Song leaves the battlefield, this effect continues until end of turn.
|
||||
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new TitaniasSongEffect(Duration.WhileOnBattlefield)));
|
||||
|
@ -71,12 +71,15 @@ public class TitaniasSong extends CardImpl {
|
|||
return new TitaniasSong(this);
|
||||
}
|
||||
}
|
||||
|
||||
class TitaniasSongEffect extends ContinuousEffectImpl {
|
||||
|
||||
private static final FilterArtifactPermanent filter = new FilterArtifactPermanent();
|
||||
|
||||
static {
|
||||
filter.add(Predicates.not(new CardTypePredicate(CardType.CREATURE)));
|
||||
}
|
||||
|
||||
public TitaniasSongEffect(Duration duration) {
|
||||
super(duration, Outcome.BecomeCreature);
|
||||
staticText = "Each noncreature artifact loses its abilities and is an artifact creature with power and toughness each equal to its converted mana cost";
|
||||
|
@ -97,8 +100,8 @@ class TitaniasSongEffect extends ContinuousEffectImpl {
|
|||
case TypeChangingEffects_4:
|
||||
if (sublayer == SubLayer.NA) {
|
||||
affectedObjectList.clear();
|
||||
for(Permanent permanent : game.getBattlefield().getAllActivePermanents(filter, game)){
|
||||
if(permanent != null){
|
||||
for (Permanent permanent : game.getBattlefield().getAllActivePermanents(filter, game)) {
|
||||
if (permanent != null) {
|
||||
affectedObjectList.add(new MageObjectReference(permanent, game));
|
||||
permanent.addCardType(CardType.CREATURE);
|
||||
}
|
||||
|
@ -106,18 +109,18 @@ class TitaniasSongEffect extends ContinuousEffectImpl {
|
|||
}
|
||||
break;
|
||||
case AbilityAddingRemovingEffects_6:
|
||||
for (Iterator<MageObjectReference> it = affectedObjectList.iterator(); it.hasNext();) {
|
||||
Permanent permanent = it.next().getPermanent(game);
|
||||
if (permanent != null){
|
||||
permanent.removeAllAbilities(source.getSourceId(), game);
|
||||
}
|
||||
for (Iterator<MageObjectReference> it = affectedObjectList.iterator(); it.hasNext();) {
|
||||
Permanent permanent = it.next().getPermanent(game);
|
||||
if (permanent != null) {
|
||||
permanent.removeAllAbilities(source.getSourceId(), game);
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case PTChangingEffects_7:
|
||||
if (sublayer == SubLayer.SetPT_7b) {
|
||||
for (Iterator<MageObjectReference> it = affectedObjectList.iterator(); it.hasNext();) {
|
||||
Permanent permanent = it.next().getPermanent(game);
|
||||
if (permanent != null){
|
||||
if (permanent != null) {
|
||||
int manaCost = permanent.getConvertedManaCost();
|
||||
permanent.getPower().setValue(manaCost);
|
||||
permanent.getToughness().setValue(manaCost);
|
||||
|
@ -133,7 +136,6 @@ class TitaniasSongEffect extends ContinuousEffectImpl {
|
|||
return false;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean hasLayer(Layer layer) {
|
||||
return layer == Layer.PTChangingEffects_7 || layer == Layer.AbilityAddingRemovingEffects_6 || layer == Layer.TypeChangingEffects_4;
|
||||
|
|
|
@ -35,7 +35,6 @@ import mage.abilities.costs.common.DiscardCardCost;
|
|||
import mage.abilities.costs.common.TapSourceCost;
|
||||
import mage.abilities.costs.mana.ManaCostsImpl;
|
||||
import mage.abilities.effects.ContinuousEffectImpl;
|
||||
import mage.constants.SubType;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.CardType;
|
||||
|
@ -43,6 +42,7 @@ import mage.constants.Duration;
|
|||
import mage.constants.Layer;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.SubLayer;
|
||||
import mage.constants.SubType;
|
||||
import mage.constants.Zone;
|
||||
import mage.filter.common.FilterArtifactPermanent;
|
||||
import mage.filter.predicate.Predicates;
|
||||
|
@ -113,6 +113,9 @@ class ToymakerEffect extends ContinuousEffectImpl {
|
|||
switch (layer) {
|
||||
case TypeChangingEffects_4:
|
||||
if (sublayer == SubLayer.NA) {
|
||||
if (!artifact.isArtifact()) {
|
||||
artifact.addCardType(CardType.ARTIFACT);
|
||||
}
|
||||
if (!artifact.isCreature()) {
|
||||
artifact.addCardType(CardType.CREATURE);
|
||||
}
|
||||
|
|
115
Mage.Sets/src/mage/cards/t/TresserhornSkyknight.java
Normal file
|
@ -0,0 +1,115 @@
|
|||
/*
|
||||
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are
|
||||
* permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
* conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
* of conditions and the following disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* The views and conclusions contained in the software and documentation are those of the
|
||||
* authors and should not be interpreted as representing official policies, either expressed
|
||||
* or implied, of BetaSteward_at_googlemail.com.
|
||||
*/
|
||||
package mage.cards.t;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.MageInt;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.common.SimpleStaticAbility;
|
||||
import mage.abilities.effects.PreventionEffectImpl;
|
||||
import mage.abilities.keyword.FirstStrikeAbility;
|
||||
import mage.abilities.keyword.FlyingAbility;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.Duration;
|
||||
import mage.constants.SubType;
|
||||
import mage.constants.Zone;
|
||||
import mage.filter.common.FilterCreaturePermanent;
|
||||
import mage.filter.predicate.mageobject.AbilityPredicate;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.game.events.DamageCreatureEvent;
|
||||
import mage.game.permanent.Permanent;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author L_J
|
||||
*/
|
||||
public class TresserhornSkyknight extends CardImpl {
|
||||
|
||||
public TresserhornSkyknight(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{5}{B}{B}");
|
||||
this.subtype.add(SubType.ZOMBIE);
|
||||
this.subtype.add(SubType.KNIGHT);
|
||||
this.power = new MageInt(5);
|
||||
this.toughness = new MageInt(3);
|
||||
|
||||
// Flying
|
||||
this.addAbility(FlyingAbility.getInstance());
|
||||
|
||||
// Prevent all damage that would be dealt to Tresserhorn Skyknight by creatures with first strike.
|
||||
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new TresserhornSkyknightEffect()));
|
||||
}
|
||||
|
||||
public TresserhornSkyknight(final TresserhornSkyknight card) {
|
||||
super(card);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TresserhornSkyknight copy() {
|
||||
return new TresserhornSkyknight(this);
|
||||
}
|
||||
}
|
||||
|
||||
class TresserhornSkyknightEffect extends PreventionEffectImpl {
|
||||
|
||||
private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creatures with first strike");
|
||||
|
||||
static {
|
||||
filter.add(new AbilityPredicate(FirstStrikeAbility.class));
|
||||
}
|
||||
|
||||
TresserhornSkyknightEffect() {
|
||||
super(Duration.WhileOnBattlefield, Integer.MAX_VALUE, false);
|
||||
staticText = "Prevent all damage that would be dealt to Tresserhorn Skyknight by creatures with first strike";
|
||||
}
|
||||
|
||||
TresserhornSkyknightEffect(final TresserhornSkyknightEffect effect) {
|
||||
super(effect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TresserhornSkyknightEffect copy() {
|
||||
return new TresserhornSkyknightEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean applies(GameEvent event, Ability source, Game game) {
|
||||
if (super.applies(event, source, game) && event instanceof DamageCreatureEvent && event.getAmount() > 0) {
|
||||
DamageCreatureEvent damageEvent = (DamageCreatureEvent) event;
|
||||
if (event.getTargetId().equals(source.getSourceId())) {
|
||||
Permanent permanent = game.getPermanentOrLKIBattlefield(damageEvent.getSourceId());
|
||||
if (permanent != null && filter.match(permanent, game)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -59,7 +59,7 @@ import mage.target.common.TargetCreaturePermanent;
|
|||
*
|
||||
* @author spjspj
|
||||
*/
|
||||
public class VeryCrypticCommand extends CardImpl {
|
||||
public class VeryCrypticCommandD extends CardImpl {
|
||||
|
||||
private static final FilterStackObject filter = new FilterStackObject("spell or ability with a single target");
|
||||
private static final FilterCreaturePermanent filter2 = new FilterCreaturePermanent("nontoken creature");
|
||||
|
@ -69,7 +69,7 @@ public class VeryCrypticCommand extends CardImpl {
|
|||
filter2.add(Predicates.not(new TokenPredicate()));
|
||||
}
|
||||
|
||||
public VeryCrypticCommand(UUID ownerId, CardSetInfo setInfo) {
|
||||
public VeryCrypticCommandD(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{U}{U}{U}");
|
||||
|
||||
// Choose two -
|
||||
|
@ -101,13 +101,13 @@ public class VeryCrypticCommand extends CardImpl {
|
|||
this.getSpellAbility().getModes().addMode(mode);
|
||||
}
|
||||
|
||||
public VeryCrypticCommand(final VeryCrypticCommand card) {
|
||||
public VeryCrypticCommandD(final VeryCrypticCommandD card) {
|
||||
super(card);
|
||||
}
|
||||
|
||||
@Override
|
||||
public VeryCrypticCommand copy() {
|
||||
return new VeryCrypticCommand(this);
|
||||
public VeryCrypticCommandD copy() {
|
||||
return new VeryCrypticCommandD(this);
|
||||
}
|
||||
}
|
||||
|
190
Mage.Sets/src/mage/cards/v/VoidMaw.java
Normal 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);
|
||||
}
|
||||
}
|
|
@ -76,7 +76,7 @@ public class XathridGorgon extends CardImpl {
|
|||
Effect effect = new GainAbilityTargetEffect(DefenderAbility.getInstance(), Duration.Custom);
|
||||
effect.setText("It gains defender");
|
||||
ability.addEffect(effect);
|
||||
effect = new AddCardTypeTargetEffect(CardType.ARTIFACT, Duration.Custom);
|
||||
effect = new AddCardTypeTargetEffect(Duration.Custom, CardType.ARTIFACT);
|
||||
effect.setText("and becomes a colorless artifact in addition to its other types");
|
||||
ability.addEffect(effect);
|
||||
ability.addEffect(new BecomesColorTargetEffect(new ObjectColor(), Duration.Custom, ""));
|
||||
|
|
|
@ -36,12 +36,12 @@ import mage.abilities.effects.ContinuousEffectImpl;
|
|||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.SubType;
|
||||
import mage.constants.Duration;
|
||||
import mage.constants.Layer;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.PhaseStep;
|
||||
import mage.constants.SubLayer;
|
||||
import mage.constants.SubType;
|
||||
import mage.constants.Zone;
|
||||
import mage.filter.common.FilterArtifactPermanent;
|
||||
import mage.filter.predicate.Predicates;
|
||||
|
@ -125,7 +125,12 @@ class XenicPoltergeistEffect extends ContinuousEffectImpl {
|
|||
UUID permanentId = targetPointer.getFirst(game, source);
|
||||
Permanent permanent = game.getPermanentOrLKIBattlefield(permanentId);
|
||||
if (permanent != null) {
|
||||
permanent.addCardType(CardType.CREATURE);
|
||||
if (!permanent.isArtifact()) {
|
||||
permanent.addCardType(CardType.ARTIFACT);
|
||||
}
|
||||
if (!permanent.isCreature()) {
|
||||
permanent.addCardType(CardType.CREATURE);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
|
|
@ -61,6 +61,7 @@ public class Coldsnap extends ExpansionSet {
|
|||
cards.add(new SetCardInfo("Arctic Nishoba", 102, Rarity.UNCOMMON, mage.cards.a.ArcticNishoba.class));
|
||||
cards.add(new SetCardInfo("Arcum Dagsson", 27, Rarity.RARE, mage.cards.a.ArcumDagsson.class));
|
||||
cards.add(new SetCardInfo("Aurochs Herd", 103, Rarity.COMMON, mage.cards.a.AurochsHerd.class));
|
||||
cards.add(new SetCardInfo("Balduvian Frostwaker", 28, Rarity.UNCOMMON, mage.cards.b.BalduvianFrostwaker.class));
|
||||
cards.add(new SetCardInfo("Balduvian Rage", 76, Rarity.UNCOMMON, mage.cards.b.BalduvianRage.class));
|
||||
cards.add(new SetCardInfo("Balduvian Warlord", 77, Rarity.UNCOMMON, mage.cards.b.BalduvianWarlord.class));
|
||||
cards.add(new SetCardInfo("Blizzard Specter", 126, Rarity.UNCOMMON, mage.cards.b.BlizzardSpecter.class));
|
||||
|
@ -86,16 +87,20 @@ 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));
|
||||
cards.add(new SetCardInfo("Frost Marsh", 146, Rarity.UNCOMMON, mage.cards.f.FrostMarsh.class));
|
||||
cards.add(new SetCardInfo("Frost Raptor", 34, Rarity.COMMON, mage.cards.f.FrostRaptor.class));
|
||||
cards.add(new SetCardInfo("Frostweb Spider", 109, Rarity.COMMON, mage.cards.f.FrostwebSpider.class));
|
||||
cards.add(new SetCardInfo("Frozen Solid", 35, Rarity.COMMON, mage.cards.f.FrozenSolid.class));
|
||||
cards.add(new SetCardInfo("Fury of the Horde", 81, Rarity.RARE, mage.cards.f.FuryOfTheHorde.class));
|
||||
cards.add(new SetCardInfo("Garza Zol, Plague Queen", 129, Rarity.RARE, mage.cards.g.GarzaZolPlagueQueen.class));
|
||||
cards.add(new SetCardInfo("Garza's Assassin", 57, Rarity.RARE, mage.cards.g.GarzasAssassin.class));
|
||||
cards.add(new SetCardInfo("Gelid Shackles", 6, Rarity.COMMON, mage.cards.g.GelidShackles.class));
|
||||
cards.add(new SetCardInfo("Glacial Plating", 7, Rarity.UNCOMMON, mage.cards.g.GlacialPlating.class));
|
||||
cards.add(new SetCardInfo("Goblin Furrier", 82, Rarity.COMMON, mage.cards.g.GoblinFurrier.class));
|
||||
cards.add(new SetCardInfo("Goblin Rimerunner", 83, Rarity.COMMON, mage.cards.g.GoblinRimerunner.class));
|
||||
cards.add(new SetCardInfo("Greater Stone Spirit", 84, Rarity.UNCOMMON, mage.cards.g.GreaterStoneSpirit.class));
|
||||
cards.add(new SetCardInfo("Grim Harvest", 58, Rarity.COMMON, mage.cards.g.GrimHarvest.class));
|
||||
|
@ -119,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));
|
||||
|
@ -150,6 +156,7 @@ public class Coldsnap extends ExpansionSet {
|
|||
cards.add(new SetCardInfo("Rimebound Dead", 69, Rarity.COMMON, mage.cards.r.RimeboundDead.class));
|
||||
cards.add(new SetCardInfo("Rime Transfusion", 68, Rarity.UNCOMMON, mage.cards.r.RimeTransfusion.class));
|
||||
cards.add(new SetCardInfo("Rimefeather Owl", 42, Rarity.RARE, mage.cards.r.RimefeatherOwl.class));
|
||||
cards.add(new SetCardInfo("Rimehorn Aurochs", 118, Rarity.UNCOMMON, mage.cards.r.RimehornAurochs.class));
|
||||
cards.add(new SetCardInfo("Rimescale Dragon", 95, Rarity.RARE, mage.cards.r.RimescaleDragon.class));
|
||||
cards.add(new SetCardInfo("Rimewind Cryomancer", 43, Rarity.UNCOMMON, mage.cards.r.RimewindCryomancer.class));
|
||||
cards.add(new SetCardInfo("Rimewind Taskmage", 44, Rarity.COMMON, mage.cards.r.RimewindTaskmage.class));
|
||||
|
@ -184,12 +191,15 @@ 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));
|
||||
cards.add(new SetCardInfo("Tresserhorn Skyknight", 73, Rarity.UNCOMMON, mage.cards.t.TresserhornSkyknight.class));
|
||||
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));
|
||||
|
|
|
@ -94,6 +94,7 @@ public class FutureSight extends ExpansionSet {
|
|||
cards.add(new SetCardInfo("Emberwilde Augur", 97, Rarity.COMMON, mage.cards.e.EmberwildeAugur.class));
|
||||
cards.add(new SetCardInfo("Emblem of the Warmind", 112, Rarity.UNCOMMON, mage.cards.e.EmblemOfTheWarmind.class));
|
||||
cards.add(new SetCardInfo("Epochrasite", 162, Rarity.RARE, mage.cards.e.Epochrasite.class));
|
||||
cards.add(new SetCardInfo("Even the Odds", 6, Rarity.UNCOMMON, mage.cards.e.EvenTheOdds.class));
|
||||
cards.add(new SetCardInfo("Fatal Attraction", 98, Rarity.COMMON, mage.cards.f.FatalAttraction.class));
|
||||
cards.add(new SetCardInfo("Festering March", 65, Rarity.UNCOMMON, mage.cards.f.FesteringMarch.class));
|
||||
cards.add(new SetCardInfo("Fleshwrither", 84, Rarity.UNCOMMON, mage.cards.f.Fleshwrither.class));
|
||||
|
|
|
@ -60,7 +60,7 @@ public class Unstable extends ExpansionSet {
|
|||
cards.add(new SetCardInfo("Earl of Squirrel", 108, Rarity.RARE, mage.cards.e.EarlOfSquirrel.class));
|
||||
cards.add(new SetCardInfo("Forest", 216, Rarity.LAND, mage.cards.basiclands.Forest.class, new CardGraphicInfo(FrameStyle.UNH_FULL_ART_BASIC, false)));
|
||||
cards.add(new SetCardInfo("GO TO JAIL", 8, Rarity.COMMON, mage.cards.g.GOTOJAIL.class));
|
||||
cards.add(new SetCardInfo("Garbage Elemental", 82, Rarity.UNCOMMON, mage.cards.g.GarbageElemental.class));
|
||||
cards.add(new SetCardInfo("Garbage Elemental", "82c", Rarity.UNCOMMON, mage.cards.g.GarbageElementalC.class));
|
||||
cards.add(new SetCardInfo("Ground Pounder", 110, Rarity.COMMON, mage.cards.g.GroundPounder.class));
|
||||
cards.add(new SetCardInfo("Hammer Helper", 85, Rarity.COMMON, mage.cards.h.HammerHelper.class));
|
||||
cards.add(new SetCardInfo("Hydradoodle", 112, Rarity.RARE, mage.cards.h.Hydradoodle.class));
|
||||
|
@ -81,7 +81,7 @@ public class Unstable extends ExpansionSet {
|
|||
cards.add(new SetCardInfo("Sword of Dungeons & Dragons", 1, Rarity.MYTHIC, mage.cards.s.SwordOfDungeonsAndDragons.class));
|
||||
cards.add(new SetCardInfo("Target Minotaur", 98, Rarity.COMMON, mage.cards.t.TargetMinotaur.class));
|
||||
cards.add(new SetCardInfo("Time Out", 48, Rarity.COMMON, mage.cards.t.TimeOut.class));
|
||||
cards.add(new SetCardInfo("Very Cryptic Command", 49, Rarity.RARE, mage.cards.v.VeryCrypticCommand.class));
|
||||
cards.add(new SetCardInfo("Very Cryptic Command", "49d", Rarity.RARE, mage.cards.v.VeryCrypticCommandD.class));
|
||||
cards.add(new SetCardInfo("Willing Test Subject", 126, Rarity.COMMON, mage.cards.w.WillingTestSubject.class));
|
||||
cards.add(new SetCardInfo("capital offense", 52, Rarity.COMMON, mage.cards.c.CapitalOffense.class));
|
||||
}
|
||||
|
|
|
@ -36,19 +36,22 @@ import org.mage.test.serverside.base.CardTestPlayerBase;
|
|||
*
|
||||
* @author LevelX2
|
||||
*/
|
||||
|
||||
public class UnearthTest extends CardTestPlayerBase {
|
||||
|
||||
/**
|
||||
* Hellspark Elemental (and probably other cards with the unearth ability) - If I unearth the elemental,
|
||||
* attack, and then go to the end of my turn both the "sacrifice" and "exile" clauses will trigger and
|
||||
* the game will ask me which one I want to put on the stack first. If I choose "sacrifice" first and
|
||||
* "exile" second, all good, the exile part resolves first and the elemental is exiled, the sacrifice
|
||||
* part does nothing afterwards. But if I choose "exile" first and "sacrifice" second then the elemental
|
||||
* will be sacrificed and placed on my graveyard and after that the "exile" resolves but does nothing, as
|
||||
* I'm guessing it can't "find" the elemental anymore and so it stays in my graveyard, despite the fact
|
||||
* that because I use its unearth ability it should always be exiled once leaving the battlefield no matter what.
|
||||
* The bug should be easy to reproduce if following the order I mention above (click the exile part,
|
||||
* Hellspark Elemental (and probably other cards with the unearth ability) -
|
||||
* If I unearth the elemental, attack, and then go to the end of my turn
|
||||
* both the "sacrifice" and "exile" clauses will trigger and the game will
|
||||
* ask me which one I want to put on the stack first. If I choose
|
||||
* "sacrifice" first and "exile" second, all good, the exile part resolves
|
||||
* first and the elemental is exiled, the sacrifice part does nothing
|
||||
* afterwards. But if I choose "exile" first and "sacrifice" second then the
|
||||
* elemental will be sacrificed and placed on my graveyard and after that
|
||||
* the "exile" resolves but does nothing, as I'm guessing it can't "find"
|
||||
* the elemental anymore and so it stays in my graveyard, despite the fact
|
||||
* that because I use its unearth ability it should always be exiled once
|
||||
* leaving the battlefield no matter what. The bug should be easy to
|
||||
* reproduce if following the order I mention above (click the exile part,
|
||||
* so the sacrifice goes on the top of the stack).
|
||||
*/
|
||||
@Test
|
||||
|
@ -76,9 +79,10 @@ public class UnearthTest extends CardTestPlayerBase {
|
|||
}
|
||||
|
||||
/**
|
||||
* Reported bug: Cards with unearth (e.g. Undead Leotau) are currently bugged. When you bring a creature back from the graveyard
|
||||
* with unearth, it [should] get exiled at end of turn normally, [but instead] a copy of the card stays on the battlefield
|
||||
* under your control permanently.
|
||||
* Reported bug: Cards with unearth (e.g. Undead Leotau) are currently
|
||||
* bugged. When you bring a creature back from the graveyard with unearth,
|
||||
* it [should] get exiled at end of turn normally, [but instead] a copy of
|
||||
* the card stays on the battlefield under your control permanently.
|
||||
*/
|
||||
@Test
|
||||
public void testUndeadLeotau() {
|
||||
|
@ -99,4 +103,33 @@ public class UnearthTest extends CardTestPlayerBase {
|
|||
assertPermanentCount(playerA, "Undead Leotau", 0);
|
||||
assertExileCount("Undead Leotau", 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* At start of the end phase, creatures phased out by Teferi's Veil still
|
||||
* exiled by unearth if they were put to battlefield by unearth.<br>
|
||||
*
|
||||
* http://www.mtgsalvation.com/forums/magic-fundamentals/magic-rulings/magic-rulings-archives/294911-teferis-veil-and-unearth
|
||||
*/
|
||||
@Test
|
||||
public void testUnearthWithPhasing() {
|
||||
// Whenever a creature you control attacks, it phases out at end of combat.
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Teferi's Veil", 1);
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Swamp", 1);
|
||||
// Unearth {B} ({B}: Return this card from your graveyard to the battlefield. It gains haste. Exile it at the beginning of the next end step or if it would leave the battlefield. Unearth only as a sorcery.)
|
||||
addCard(Zone.GRAVEYARD, playerA, "Dregscape Zombie", 1); // 2/1
|
||||
|
||||
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Unearth");
|
||||
attack(1, playerA, "Dregscape Zombie");
|
||||
|
||||
setStopAt(3, PhaseStep.PRECOMBAT_MAIN);
|
||||
execute();
|
||||
|
||||
assertGraveyardCount(playerA, "Dregscape Zombie", 0);
|
||||
assertLife(playerB, 18);
|
||||
assertExileCount("Dregscape Zombie", 0);
|
||||
|
||||
assertPermanentCount(playerA, "Dregscape Zombie", 1);
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -1,7 +1,29 @@
|
|||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
* 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.common;
|
||||
|
||||
|
|
|
@ -0,0 +1,59 @@
|
|||
/*
|
||||
* 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.common;
|
||||
|
||||
import mage.abilities.condition.Condition;
|
||||
import mage.constants.Zone;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author LevelX2
|
||||
*/
|
||||
public class CastOnlyIfConditionIsTrueAbility extends SimpleStaticAbility {
|
||||
|
||||
public CastOnlyIfConditionIsTrueAbility(Condition condition) {
|
||||
this(condition, null);
|
||||
}
|
||||
|
||||
public CastOnlyIfConditionIsTrueAbility(Condition condition, String effectText) {
|
||||
super(Zone.ALL, new CastOnlyIfConditionIsTrueEffect(condition));
|
||||
this.setRuleAtTheTop(true);
|
||||
if (effectText != null) {
|
||||
getEffects().get(0).setText(effectText);
|
||||
}
|
||||
}
|
||||
|
||||
private CastOnlyIfConditionIsTrueAbility(final CastOnlyIfConditionIsTrueAbility ability) {
|
||||
super(ability);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CastOnlyIfConditionIsTrueAbility copy() {
|
||||
return new CastOnlyIfConditionIsTrueAbility(this);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,85 @@
|
|||
/*
|
||||
* 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.common;
|
||||
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.condition.Condition;
|
||||
import mage.abilities.effects.ContinuousRuleModifyingEffectImpl;
|
||||
import mage.constants.Duration;
|
||||
import mage.constants.Outcome;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.GameEvent;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author LevelX2
|
||||
*/
|
||||
public class CastOnlyIfConditionIsTrueEffect extends ContinuousRuleModifyingEffectImpl {
|
||||
|
||||
private final Condition condition;
|
||||
|
||||
public CastOnlyIfConditionIsTrueEffect(Condition condition) {
|
||||
super(Duration.EndOfGame, Outcome.Detriment);
|
||||
this.condition = condition;
|
||||
staticText = setText();
|
||||
}
|
||||
|
||||
private CastOnlyIfConditionIsTrueEffect(final CastOnlyIfConditionIsTrueEffect effect) {
|
||||
super(effect);
|
||||
this.condition = effect.condition;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checksEventType(GameEvent event, Game game) {
|
||||
return event.getType() == GameEvent.EventType.CAST_SPELL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean applies(GameEvent event, Ability source, Game game) {
|
||||
// has to return true, if the spell cannot be cast in the current phase / step
|
||||
if (event.getSourceId().equals(source.getSourceId())) {
|
||||
if (condition != null && !condition.apply(game, source)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false; // cast not prevented by this effect
|
||||
}
|
||||
|
||||
@Override
|
||||
public CastOnlyIfConditionIsTrueEffect copy() {
|
||||
return new CastOnlyIfConditionIsTrueEffect(this);
|
||||
}
|
||||
|
||||
private String setText() {
|
||||
StringBuilder sb = new StringBuilder("cast {this} only ");
|
||||
if (condition != null) {
|
||||
sb.append(' ').append(condition.toString());
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
|
@ -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.abilities.condition.common;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.condition.Condition;
|
||||
import mage.constants.ComparisonType;
|
||||
import mage.filter.FilterPermanent;
|
||||
import mage.game.Game;
|
||||
import mage.players.Player;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author LevelX2
|
||||
*/
|
||||
public class ControlsPermanentsComparedToOpponentsCondition implements Condition {
|
||||
|
||||
private final ComparisonType type;
|
||||
private final FilterPermanent filterPermanent;
|
||||
|
||||
public ControlsPermanentsComparedToOpponentsCondition(ComparisonType type, FilterPermanent filterPermanent) {
|
||||
this.type = type;
|
||||
this.filterPermanent = filterPermanent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Player controller = game.getPlayer(source.getControllerId());
|
||||
if (controller != null) {
|
||||
int ownNumber = game.getBattlefield().countAll(filterPermanent, source.getControllerId(), game);
|
||||
for (UUID playerId : game.getOpponents(source.getControllerId())) {
|
||||
if (!ComparisonType.compare(ownNumber, type, game.getBattlefield().countAll(filterPermanent, playerId, game))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder("if you control ");
|
||||
sb.append(type.getText1()).append(" ");
|
||||
sb.append(filterPermanent.getMessage()).append(" ");
|
||||
sb.append(type.getText2());
|
||||
sb.append(" each opponent");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
}
|
|
@ -34,6 +34,7 @@ import mage.abilities.effects.OneShotEffect;
|
|||
import mage.cards.Card;
|
||||
import mage.constants.Outcome;
|
||||
import mage.game.Game;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.players.Player;
|
||||
import mage.util.CardUtil;
|
||||
|
||||
|
@ -77,6 +78,11 @@ public class ExileSourceEffect extends OneShotEffect {
|
|||
if (controller != null) {
|
||||
MageObject sourceObject = source.getSourceObjectIfItStillExists(game);
|
||||
if (sourceObject instanceof Card) {
|
||||
if (sourceObject instanceof Permanent) {
|
||||
if (!((Permanent) sourceObject).isPhasedIn()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
UUID exileZoneId = null;
|
||||
String exileZoneName = "";
|
||||
if (toUniqueExileZone) {
|
||||
|
|
|
@ -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.abilities.effects.common.continuous;
|
||||
|
||||
import mage.abilities.Ability;
|
||||
|
@ -38,8 +37,9 @@ import mage.game.permanent.Permanent;
|
|||
* @author nantuko
|
||||
*/
|
||||
public class AddCardTypeAttachedEffect extends ContinuousEffectImpl {
|
||||
private CardType addedCardType;
|
||||
private AttachmentType attachmentType;
|
||||
|
||||
private final CardType addedCardType;
|
||||
private final AttachmentType attachmentType;
|
||||
|
||||
public AddCardTypeAttachedEffect(CardType addedCardType, Duration duration, AttachmentType attachmentType) {
|
||||
super(duration, Layer.TypeChangingEffects_4, SubLayer.NA, Outcome.Benefit);
|
||||
|
@ -59,8 +59,9 @@ public class AddCardTypeAttachedEffect extends ContinuousEffectImpl {
|
|||
Permanent equipment = game.getPermanent(source.getSourceId());
|
||||
if (equipment != null && equipment.getAttachedTo() != null) {
|
||||
Permanent target = game.getPermanent(equipment.getAttachedTo());
|
||||
if (target != null && !target.getCardType().contains(addedCardType))
|
||||
if (target != null && !target.getCardType().contains(addedCardType)) {
|
||||
target.addCardType(addedCardType);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
*/
|
||||
package mage.abilities.effects.common.continuous;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import mage.MageObjectReference;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.Mode;
|
||||
|
@ -40,19 +41,23 @@ import mage.game.permanent.Permanent;
|
|||
*/
|
||||
public class AddCardTypeSourceEffect extends ContinuousEffectImpl {
|
||||
|
||||
private final CardType addedCardType;
|
||||
private final ArrayList<CardType> addedCardTypes = new ArrayList<>();
|
||||
|
||||
public AddCardTypeSourceEffect(CardType addedCardType, Duration duration) {
|
||||
public AddCardTypeSourceEffect(Duration duration, CardType... addedCardType) {
|
||||
super(duration, Layer.TypeChangingEffects_4, SubLayer.NA, Outcome.Benefit);
|
||||
this.addedCardType = addedCardType;
|
||||
if (addedCardType == CardType.ENCHANTMENT) {
|
||||
dependencyTypes.add(DependencyType.EnchantmentAddingRemoving);
|
||||
for (CardType cardType : addedCardType) {
|
||||
this.addedCardTypes.add(cardType);
|
||||
if (cardType == CardType.ENCHANTMENT) {
|
||||
dependencyTypes.add(DependencyType.EnchantmentAddingRemoving);
|
||||
} else if (cardType == CardType.ARTIFACT) {
|
||||
dependencyTypes.add(DependencyType.ArtifactAddingRemoving);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public AddCardTypeSourceEffect(final AddCardTypeSourceEffect effect) {
|
||||
super(effect);
|
||||
this.addedCardType = effect.addedCardType;
|
||||
this.addedCardTypes.addAll(effect.addedCardTypes);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -65,7 +70,11 @@ public class AddCardTypeSourceEffect extends ContinuousEffectImpl {
|
|||
public boolean apply(Game game, Ability source) {
|
||||
Permanent permanent = game.getPermanent(source.getSourceId());
|
||||
if (permanent != null && affectedObjectList.contains(new MageObjectReference(permanent, game))) {
|
||||
permanent.addCardType(addedCardType);
|
||||
for (CardType cardType : addedCardTypes) {
|
||||
if (!permanent.getCardType().contains(cardType)) {
|
||||
permanent.addCardType(cardType);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
} else if (this.getDuration() == Duration.Custom) {
|
||||
this.discard();
|
||||
|
@ -84,7 +93,20 @@ public class AddCardTypeSourceEffect extends ContinuousEffectImpl {
|
|||
return staticText;
|
||||
}
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("{this} becomes ").append(addedCardType.toString()).append(" in addition to its other types " + this.getDuration().toString());
|
||||
sb.append("{this} becomes ");
|
||||
boolean article = false;
|
||||
for (CardType cardType : addedCardTypes) {
|
||||
if (!article) {
|
||||
if (cardType.toString().startsWith("A") || cardType.toString().startsWith("E")) {
|
||||
sb.append("an ");
|
||||
} else {
|
||||
sb.append("a ");
|
||||
}
|
||||
article = true;
|
||||
}
|
||||
sb.append(cardType.toString().toLowerCase()).append(" ");
|
||||
}
|
||||
sb.append(" in addition to its other types ").append(this.getDuration().toString());
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
*/
|
||||
package mage.abilities.effects.common.continuous;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.UUID;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.Mode;
|
||||
|
@ -45,21 +46,24 @@ import mage.game.permanent.Permanent;
|
|||
*/
|
||||
public class AddCardTypeTargetEffect extends ContinuousEffectImpl {
|
||||
|
||||
private final CardType addedCardType;
|
||||
private final ArrayList<CardType> addedCardTypes = new ArrayList<>();
|
||||
|
||||
public AddCardTypeTargetEffect(CardType addedCardType, Duration duration) {
|
||||
public AddCardTypeTargetEffect(Duration duration, CardType... addedCardType) {
|
||||
super(duration, Layer.TypeChangingEffects_4, SubLayer.NA, Outcome.Benefit);
|
||||
this.addedCardType = addedCardType;
|
||||
if (addedCardType == CardType.ENCHANTMENT) {
|
||||
dependencyTypes.add(DependencyType.EnchantmentAddingRemoving);
|
||||
} else if (addedCardType == CardType.ARTIFACT) {
|
||||
dependencyTypes.add(DependencyType.ArtifactAddingRemoving);
|
||||
for (CardType cardType : addedCardType) {
|
||||
this.addedCardTypes.add(cardType);
|
||||
if (cardType == CardType.ENCHANTMENT) {
|
||||
dependencyTypes.add(DependencyType.EnchantmentAddingRemoving);
|
||||
} else if (cardType == CardType.ARTIFACT) {
|
||||
dependencyTypes.add(DependencyType.ArtifactAddingRemoving);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public AddCardTypeTargetEffect(final AddCardTypeTargetEffect effect) {
|
||||
super(effect);
|
||||
this.addedCardType = effect.addedCardType;
|
||||
this.addedCardTypes.addAll(effect.addedCardTypes);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -68,8 +72,10 @@ public class AddCardTypeTargetEffect extends ContinuousEffectImpl {
|
|||
for (UUID targetId : targetPointer.getTargets(game, source)) {
|
||||
Permanent target = game.getPermanent(targetId);
|
||||
if (target != null) {
|
||||
if (!target.getCardType().contains(addedCardType)) {
|
||||
target.addCardType(addedCardType);
|
||||
for (CardType cardType : addedCardTypes) {
|
||||
if (!target.getCardType().contains(cardType)) {
|
||||
target.addCardType(cardType);
|
||||
}
|
||||
}
|
||||
result = true;
|
||||
}
|
||||
|
@ -93,7 +99,23 @@ public class AddCardTypeTargetEffect extends ContinuousEffectImpl {
|
|||
return staticText;
|
||||
}
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("Target ").append(mode.getTargets().get(0).getTargetName()).append(" becomes ").append(addedCardType.toString()).append(" in addition to its other types until end of turn");
|
||||
sb.append("Target ").append(mode.getTargets().get(0).getTargetName()).append(" becomes ");
|
||||
boolean article = false;
|
||||
for (CardType cardType : addedCardTypes) {
|
||||
if (!article) {
|
||||
if (cardType.toString().startsWith("A") || cardType.toString().startsWith("E")) {
|
||||
sb.append("an ");
|
||||
} else {
|
||||
sb.append("a ");
|
||||
}
|
||||
article = true;
|
||||
}
|
||||
sb.append(cardType.toString().toLowerCase()).append(" ");
|
||||
}
|
||||
sb.append("in addition to its other types");
|
||||
if (getDuration().equals(Duration.EndOfTurn)) {
|
||||
sb.append(" until end of turn");
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,29 @@
|
|||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
* 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.effects.common.ruleModifying;
|
||||
|
||||
|
|
|
@ -54,8 +54,8 @@ public class CrewAbility extends SimpleActivatedAbility {
|
|||
private final int value;
|
||||
|
||||
public CrewAbility(int value) {
|
||||
super(Zone.BATTLEFIELD, new AddCardTypeSourceEffect(CardType.ARTIFACT, Duration.EndOfTurn), new CrewCost(value));
|
||||
this.addEffect(new AddCardTypeSourceEffect(CardType.CREATURE, Duration.EndOfTurn));
|
||||
super(Zone.BATTLEFIELD, new AddCardTypeSourceEffect(Duration.EndOfTurn, CardType.ARTIFACT), new CrewCost(value));
|
||||
this.addEffect(new AddCardTypeSourceEffect(Duration.EndOfTurn, CardType.ARTIFACT, CardType.CREATURE));
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
|
|
|
@ -44,6 +44,7 @@ import mage.constants.Rarity;
|
|||
public class CardCriteria {
|
||||
|
||||
private String name;
|
||||
private String nameExact;
|
||||
private String rules;
|
||||
private final List<String> setCodes;
|
||||
private final List<CardType> types;
|
||||
|
@ -126,6 +127,11 @@ public class CardCriteria {
|
|||
return this;
|
||||
}
|
||||
|
||||
public CardCriteria nameExact(String nameExact) {
|
||||
this.nameExact = nameExact;
|
||||
return this;
|
||||
}
|
||||
|
||||
public CardCriteria rules(String rules) {
|
||||
this.rules = rules;
|
||||
return this;
|
||||
|
@ -205,6 +211,10 @@ public class CardCriteria {
|
|||
where.like("name", new SelectArg('%' + name + '%'));
|
||||
clausesCount++;
|
||||
}
|
||||
if (nameExact != null) {
|
||||
where.like("name", new SelectArg(nameExact));
|
||||
clausesCount++;
|
||||
}
|
||||
if (rules != null) {
|
||||
where.like("rules", new SelectArg('%' + rules + '%'));
|
||||
clausesCount++;
|
||||
|
@ -231,7 +241,6 @@ public class CardCriteria {
|
|||
clausesCount++;
|
||||
}
|
||||
|
||||
|
||||
if (types.size() != 7) { //if all types selected - no selection needed (Tribal and Conspiracy not selectable yet)
|
||||
for (CardType type : types) {
|
||||
where.like("types", new SelectArg('%' + type.name() + '%'));
|
||||
|
@ -315,8 +324,6 @@ public class CardCriteria {
|
|||
where.eq("cardNumber", new SelectArg(0));
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (start != null) {
|
||||
qb.offset(start);
|
||||
}
|
||||
|
|
|
@ -58,7 +58,7 @@ public enum CardRepository {
|
|||
// raise this if db structure was changed
|
||||
private static final long CARD_DB_VERSION = 51;
|
||||
// raise this if new cards were added to the server
|
||||
private static final long CARD_CONTENT_VERSION = 96;
|
||||
private static final long CARD_CONTENT_VERSION = 97;
|
||||
private Dao<CardInfo, Object> cardDao;
|
||||
private Set<String> classNames;
|
||||
|
||||
|
|
|
@ -4,12 +4,16 @@ package mage.constants;
|
|||
* Created by IGOUDT on 5-3-2017.
|
||||
*/
|
||||
public enum ComparisonType {
|
||||
MORE_THAN(">"), FEWER_THAN("<"), EQUAL_TO("==");
|
||||
MORE_THAN(">", "more", "than"), FEWER_THAN("<", "fewer", "than"), EQUAL_TO("==", "equal", "to");
|
||||
|
||||
String operator;
|
||||
String text1;
|
||||
String text2;
|
||||
|
||||
ComparisonType(String op) {
|
||||
operator = op;
|
||||
ComparisonType(String op, String text1, String text2) {
|
||||
this.operator = op;
|
||||
this.text1 = text1;
|
||||
this.text2 = text2;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -17,6 +21,13 @@ public enum ComparisonType {
|
|||
return operator;
|
||||
}
|
||||
|
||||
public String getText1() {
|
||||
return text1;
|
||||
}
|
||||
|
||||
public String getText2() {
|
||||
return text2;
|
||||
}
|
||||
|
||||
public static boolean compare(int source, ComparisonType comparison, int target) {
|
||||
switch (comparison) {
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
||||
|
|
|
@ -36,7 +36,7 @@ import mage.constants.CardType;
|
|||
import mage.constants.Duration;
|
||||
import mage.constants.TargetController;
|
||||
import mage.constants.Zone;
|
||||
import mage.filter.common.FilterControlledArtifactPermanent;
|
||||
import static mage.filter.StaticFilters.FILTER_CONTROLLED_PERMANENT_ARTIFACT;
|
||||
import mage.game.command.Emblem;
|
||||
import mage.target.TargetPermanent;
|
||||
|
||||
|
@ -49,13 +49,13 @@ public class TezzeretTheSchemerEmblem extends Emblem {
|
|||
public TezzeretTheSchemerEmblem() {
|
||||
this.setName("Emblem Tezzeret");
|
||||
|
||||
Effect effect = new AddCardTypeTargetEffect(CardType.CREATURE, Duration.EndOfGame);
|
||||
Effect effect = new AddCardTypeTargetEffect(Duration.EndOfGame, CardType.ARTIFACT, CardType.CREATURE);
|
||||
effect.setText("target artifact you control becomes an artifact creature");
|
||||
Ability ability = new BeginningOfCombatTriggeredAbility(Zone.COMMAND, effect, TargetController.YOU, false, true);
|
||||
effect = new SetPowerToughnessTargetEffect(5, 5, Duration.EndOfGame);
|
||||
effect.setText("with base power and toughness 5/5");
|
||||
ability.addEffect(effect);
|
||||
ability.addTarget(new TargetPermanent(new FilterControlledArtifactPermanent()));
|
||||
ability.addTarget(new TargetPermanent(FILTER_CONTROLLED_PERMANENT_ARTIFACT));
|
||||
this.getAbilities().add(ability);
|
||||
}
|
||||
}
|
||||
|
|