Merge pull request #30 from magefree/master

Merge https://github.com/magefree/mage
This commit is contained in:
Zzooouhh 2018-01-01 18:14:22 +01:00 committed by GitHub
commit e4bc69156b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
87 changed files with 2618 additions and 563 deletions

View file

@ -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 {

View file

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

View file

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

View file

@ -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);

View file

@ -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>

View file

@ -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;

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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);
}
}
}
}
}

View file

@ -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(",", "")

View file

@ -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

View file

@ -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);
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 565 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 849 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 563 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 753 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 541 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 767 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 639 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 444 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 644 B

View file

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

View file

@ -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;

View file

@ -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);
}

View file

@ -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));
}

View file

@ -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));

View 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());
}
}

View file

@ -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;
}
}
}
}

View file

@ -25,7 +25,6 @@
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
package mage.cards.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);
}

View 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);
}
}

View file

@ -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);
}
}

View file

@ -0,0 +1,77 @@
/*
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
package mage.cards.f;
import java.util.UUID;
import mage.abilities.dynamicvalue.IntPlusDynamicValue;
import mage.abilities.dynamicvalue.common.CardsInAllGraveyardsCount;
import mage.abilities.effects.Effect;
import mage.abilities.effects.common.DamageTargetEffect;
import mage.abilities.effects.common.GainLifeEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.filter.FilterCard;
import mage.filter.predicate.mageobject.NamePredicate;
import mage.target.common.TargetCreaturePermanent;
/**
*
* @author L_J
*/
public class FeastOfFlesh extends CardImpl {
private static final FilterCard filter = new FilterCard("cards named Feast of Flesh");
static {
filter.add(new NamePredicate("Feast of Flesh"));
}
public FeastOfFlesh(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{B}");
// Feast of Flesh deals X damage to target creature and you gain X life, where X is 1 plus the number of cards named Feast of Flesh in all graveyards.
IntPlusDynamicValue value = new IntPlusDynamicValue(1, new CardsInAllGraveyardsCount(filter));
Effect effect1 = new DamageTargetEffect(value);
effect1.setText("Feast of Flesh deals X damage to target creature");
Effect effect2 = new GainLifeEffect(value);
effect2.setText("and you gain X life, where X is 1 plus the number of cards named {source} in all graveyards");
this.getSpellAbility().addEffect(effect1);
this.getSpellAbility().addEffect(effect2);
this.getSpellAbility().addTarget(new TargetCreaturePermanent());
}
public FeastOfFlesh(final FeastOfFlesh card) {
super(card);
}
@Override
public FeastOfFlesh copy() {
return new FeastOfFlesh(this);
}
}

View file

@ -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));

View file

@ -0,0 +1,129 @@
/*
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
package mage.cards.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);
}
}

View file

@ -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);
}
}
@ -106,7 +107,7 @@ class GarbageElementalEffect extends OneShotEffect {
if (controller != null) {
int thisRoll = controller.rollDice(game, 6);
int thatRoll = controller.rollDice(game, 6);
Token token = new GoblinToken();
return token.putOntoBattlefield(Math.abs(thatRoll - thisRoll), game, source.getSourceId(), source.getControllerId());
}

View file

@ -0,0 +1,126 @@
/*
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
package mage.cards.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);
// RecoverPay 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);
}
}

View 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;
}
}

View file

@ -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");

View file

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

View file

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

View file

@ -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);
}

View file

@ -0,0 +1,73 @@
/*
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
package mage.cards.k;
import java.util.UUID;
import mage.abilities.dynamicvalue.IntPlusDynamicValue;
import mage.abilities.dynamicvalue.common.CardsInAllGraveyardsCount;
import mage.abilities.effects.Effect;
import mage.abilities.effects.common.continuous.BoostControlledEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.filter.FilterCard;
import mage.filter.common.FilterCreaturePermanent;
import mage.filter.predicate.mageobject.NamePredicate;
/**
*
* @author L_J
*/
public class KjeldoranWarCry extends CardImpl {
private static final FilterCard filter = new FilterCard("cards named Kjeldoran War Cry");
static {
filter.add(new NamePredicate("Kjeldoran War Cry"));
}
public KjeldoranWarCry(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{1}{W}");
// Creatures you control get +X/+X until end of turn, where X is 1 plus the number of cards named Kjeldoran War Cry in all graveyards.
IntPlusDynamicValue value = new IntPlusDynamicValue(1, new CardsInAllGraveyardsCount(filter));
Effect effect = new BoostControlledEffect(value, value, Duration.EndOfTurn, new FilterCreaturePermanent("creatures"), false, true);
effect.setText("Creatures you control get +X/+X until end of turn, where X is 1 plus the number of cards named {source} in all graveyards");
this.getSpellAbility().addEffect(effect);
}
public KjeldoranWarCry(final KjeldoranWarCry card) {
super(card);
}
@Override
public KjeldoranWarCry copy() {
return new KjeldoranWarCry(this);
}
}

View file

@ -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);
}

View file

@ -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());

View file

@ -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);
}

View file

@ -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);

View file

@ -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));

View 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);
}
}

View file

@ -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;
}
}

View file

@ -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) {

View file

@ -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;

View file

@ -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;
}

View file

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

View file

@ -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));

View file

@ -55,11 +55,11 @@ 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)));
this.addAbility(new LeavesBattlefieldTriggeredAbility(new TitaniasSongEffect(Duration.EndOfTurn), false));
this.addAbility(new LeavesBattlefieldTriggeredAbility(new TitaniasSongEffect(Duration.EndOfTurn), false));
}
public TitaniasSong(final TitaniasSong card) {
@ -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;

View file

@ -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);
}

View file

@ -0,0 +1,115 @@
/*
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
package mage.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;
}
}

View file

@ -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);
}
}

View file

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

View file

@ -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, ""));

View file

@ -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;

View file

@ -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));

View file

@ -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));

View file

@ -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));
}

View file

@ -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
@ -56,15 +59,15 @@ public class UnearthTest extends CardTestPlayerBase {
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 2);
// 3/1 - Trample, haste
// At the beginning of the end step, sacrifice Hellspark Elemental.
// Unearth {1}{R} ({1}{R}: 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.)
// Unearth {1}{R} ({1}{R}: 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, "Hellspark Elemental", 1);
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Unearth");
attack(1, playerA, "Hellspark Elemental");
setStopAt(2, PhaseStep.UNTAP);
execute();
@ -74,22 +77,23 @@ public class UnearthTest extends CardTestPlayerBase {
assertPermanentCount(playerA, "Hellspark Elemental", 0);
assertExileCount("Hellspark Elemental", 1);
}
/**
* 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() {
//{R}: Undead Leotau gets +1/-1 until end of turn.
// Unearth {2}{B}
addCard(Zone.BATTLEFIELD, playerA, "Swamp", 3);
addCard(Zone.GRAVEYARD, playerA, "Undead Leotau", 1); // 3/4
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Unearth");
attack(1, playerA, "Undead Leotau");
setStopAt(2, PhaseStep.UNTAP);
execute();
@ -97,6 +101,35 @@ public class UnearthTest extends CardTestPlayerBase {
assertLife(playerB, 17);
assertPermanentCount(playerA, "Undead Leotau", 0);
assertExileCount("Undead Leotau", 1);
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);
}
}

View file

@ -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;

View file

@ -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);
}
}

View file

@ -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();
}
}

View file

@ -0,0 +1,76 @@
/*
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
package mage.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();
}
}

View file

@ -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) {

View file

@ -25,7 +25,6 @@
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
package mage.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;
}

View file

@ -1,90 +1,112 @@
/*
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
package mage.abilities.effects.common.continuous;
import mage.MageObjectReference;
import mage.abilities.Ability;
import mage.abilities.Mode;
import mage.abilities.effects.ContinuousEffectImpl;
import mage.constants.*;
import mage.game.Game;
import mage.game.permanent.Permanent;
/**
* @author emerald000
*/
public class AddCardTypeSourceEffect extends ContinuousEffectImpl {
private final CardType addedCardType;
public AddCardTypeSourceEffect(CardType addedCardType, Duration duration) {
super(duration, Layer.TypeChangingEffects_4, SubLayer.NA, Outcome.Benefit);
this.addedCardType = addedCardType;
if (addedCardType == CardType.ENCHANTMENT) {
dependencyTypes.add(DependencyType.EnchantmentAddingRemoving);
}
}
public AddCardTypeSourceEffect(final AddCardTypeSourceEffect effect) {
super(effect);
this.addedCardType = effect.addedCardType;
}
@Override
public void init(Ability source, Game game) {
super.init(source, game);
affectedObjectList.add(new MageObjectReference(source.getSourceId(), game.getState().getZoneChangeCounter(source.getSourceId()), game));
}
@Override
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);
return true;
} else if (this.getDuration() == Duration.Custom) {
this.discard();
}
return false;
}
@Override
public AddCardTypeSourceEffect copy() {
return new AddCardTypeSourceEffect(this);
}
@Override
public String getText(Mode mode) {
if (staticText != null && !staticText.isEmpty()) {
return staticText;
}
StringBuilder sb = new StringBuilder();
sb.append("{this} becomes ").append(addedCardType.toString()).append(" in addition to its other types " + this.getDuration().toString());
return sb.toString();
}
}
/*
* 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.continuous;
import java.util.ArrayList;
import mage.MageObjectReference;
import mage.abilities.Ability;
import mage.abilities.Mode;
import mage.abilities.effects.ContinuousEffectImpl;
import mage.constants.*;
import mage.game.Game;
import mage.game.permanent.Permanent;
/**
* @author emerald000
*/
public class AddCardTypeSourceEffect extends ContinuousEffectImpl {
private final ArrayList<CardType> addedCardTypes = new ArrayList<>();
public AddCardTypeSourceEffect(Duration duration, CardType... addedCardType) {
super(duration, Layer.TypeChangingEffects_4, SubLayer.NA, Outcome.Benefit);
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.addedCardTypes.addAll(effect.addedCardTypes);
}
@Override
public void init(Ability source, Game game) {
super.init(source, game);
affectedObjectList.add(new MageObjectReference(source.getSourceId(), game.getState().getZoneChangeCounter(source.getSourceId()), game));
}
@Override
public boolean apply(Game game, Ability source) {
Permanent permanent = game.getPermanent(source.getSourceId());
if (permanent != null && affectedObjectList.contains(new MageObjectReference(permanent, game))) {
for (CardType cardType : addedCardTypes) {
if (!permanent.getCardType().contains(cardType)) {
permanent.addCardType(cardType);
}
}
return true;
} else if (this.getDuration() == Duration.Custom) {
this.discard();
}
return false;
}
@Override
public AddCardTypeSourceEffect copy() {
return new AddCardTypeSourceEffect(this);
}
@Override
public String getText(Mode mode) {
if (staticText != null && !staticText.isEmpty()) {
return staticText;
}
StringBuilder sb = new StringBuilder();
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();
}
}

View file

@ -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();
}
}

View file

@ -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;

View file

@ -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;
}

View file

@ -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,15 +324,13 @@ public class CardCriteria {
where.eq("cardNumber", new SelectArg(0));
}
if (start != null) {
qb.offset(start);
}
if (count != null) {
qb.limit(count);
}
if (sortBy != null) {
qb.orderBy(sortBy, true);
}

View file

@ -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;

View file

@ -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) {

View file

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

View file

@ -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);
}
}