diff --git a/Mage.Client/src/main/java/mage/client/dialog/PreferencesDialog.form b/Mage.Client/src/main/java/mage/client/dialog/PreferencesDialog.form index 8008ce940d9..dcbf9fe7373 100644 --- a/Mage.Client/src/main/java/mage/client/dialog/PreferencesDialog.form +++ b/Mage.Client/src/main/java/mage/client/dialog/PreferencesDialog.form @@ -83,10 +83,10 @@ - + - + @@ -114,31 +114,31 @@ - + - - - - - - - - - + + + + + + - + - - + + + + + @@ -155,20 +155,6 @@ - - - - - - - - - - - - - - @@ -183,6 +169,25 @@ + + + + + + + + + + + + + + + + + + + @@ -204,11 +209,9 @@ - - - - - + + + @@ -531,7 +534,7 @@ - + @@ -1223,7 +1226,7 @@ - + @@ -2097,7 +2100,7 @@ - + diff --git a/Mage.Client/src/main/java/mage/client/dialog/PreferencesDialog.java b/Mage.Client/src/main/java/mage/client/dialog/PreferencesDialog.java index 2d464312ebe..6199384a981 100644 --- a/Mage.Client/src/main/java/mage/client/dialog/PreferencesDialog.java +++ b/Mage.Client/src/main/java/mage/client/dialog/PreferencesDialog.java @@ -54,6 +54,7 @@ import javax.swing.JFileChooser; import javax.swing.JLabel; import javax.swing.JOptionPane; import javax.swing.JPanel; +import javax.swing.JSlider; import javax.swing.JTextField; import javax.swing.border.Border; import javax.swing.filechooser.FileFilter; @@ -81,7 +82,7 @@ public class PreferencesDialog extends javax.swing.JDialog { private static final Logger log = Logger.getLogger(PreferencesDialog.class); public static final String KEY_HAND_USE_BIG_CARDS = "handUseBigCards"; - public static final String KEY_SHOW_TOOLTIPS_ANY_ZONE = "showTooltipsInAnyZone"; + public static final String KEY_SHOW_TOOLTIPS_DELAY = "showTooltipsDelay"; public static final String KEY_SHOW_CARD_NAMES = "showCardNames"; public static final String KEY_PERMANENTS_IN_ONE_PILE = "nonLandPermanentsInOnePile"; public static final String KEY_SHOW_PLAYER_NAMES_PERMANENTLY = "showPlayerNamesPermanently"; @@ -338,8 +339,9 @@ public class PreferencesDialog extends javax.swing.JDialog { tabMain = new javax.swing.JPanel(); main_card = new javax.swing.JPanel(); displayBigCardsInHand = new javax.swing.JCheckBox(); - showToolTipsInAnyZone = new javax.swing.JCheckBox(); showCardName = new javax.swing.JCheckBox(); + tooltipDelayLabel = new javax.swing.JLabel(); + tooltipDelay = new javax.swing.JSlider(); main_game = new javax.swing.JPanel(); nonLandPermanentsInOnePile = new javax.swing.JCheckBox(); showPlayerNamesPermanently = new javax.swing.JCheckBox(); @@ -478,17 +480,6 @@ public class PreferencesDialog extends javax.swing.JDialog { } }); - showToolTipsInAnyZone.setSelected(true); - showToolTipsInAnyZone.setText("Show card tooltips while hovering with the mouse pointer over a card"); - showToolTipsInAnyZone.setToolTipText(""); - showToolTipsInAnyZone.setActionCommand(""); - showToolTipsInAnyZone.setCursor(new java.awt.Cursor(java.awt.Cursor.DEFAULT_CURSOR)); - showToolTipsInAnyZone.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - showToolTipsInAnyZoneActionPerformed(evt); - } - }); - showCardName.setSelected(true); showCardName.setText("Show card name on card panel"); showCardName.setToolTipText("Write the card's name on the card to make the card name more recognizable."); @@ -500,30 +491,45 @@ public class PreferencesDialog extends javax.swing.JDialog { } }); + tooltipDelayLabel.setHorizontalAlignment(javax.swing.SwingConstants.CENTER); + tooltipDelayLabel.setText("Delay in milliseconds for showing the card tooltip text"); + tooltipDelayLabel.setToolTipText("The time the appearance of the tooltip window for a card is delayed.
\nIf set to zero, the tooltip window won't be shown at all."); + + tooltipDelay.setMajorTickSpacing(1000); + tooltipDelay.setMaximum(5000); + tooltipDelay.setMinorTickSpacing(100); + tooltipDelay.setPaintLabels(true); + tooltipDelay.setPaintTicks(true); + tooltipDelay.setSnapToTicks(true); + tooltipDelay.setToolTipText("The time the appearance of the tooltip window for a card is delayed.
\nIf set to zero, the tooltip window won't be shown at all."); + tooltipDelay.setValue(300); + javax.swing.GroupLayout main_cardLayout = new javax.swing.GroupLayout(main_card); main_card.setLayout(main_cardLayout); main_cardLayout.setHorizontalGroup( main_cardLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(main_cardLayout.createSequentialGroup() - .addContainerGap() + .addGap(6, 6, 6) .addGroup(main_cardLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(tooltipDelayLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(displayBigCardsInHand, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(tooltipDelay, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addGroup(main_cardLayout.createSequentialGroup() - .addComponent(displayBigCardsInHand, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addContainerGap()) - .addGroup(main_cardLayout.createSequentialGroup() - .addGroup(main_cardLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(showToolTipsInAnyZone) - .addComponent(showCardName)) - .addGap(0, 0, Short.MAX_VALUE)))) + .addComponent(showCardName) + .addGap(0, 0, Short.MAX_VALUE))) + .addContainerGap()) ); main_cardLayout.setVerticalGroup( main_cardLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(main_cardLayout.createSequentialGroup() .addComponent(displayBigCardsInHand) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(showToolTipsInAnyZone) + .addComponent(showCardName) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(showCardName)) + .addComponent(tooltipDelayLabel) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(tooltipDelay, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addContainerGap()) ); main_game.setBorder(javax.swing.BorderFactory.createTitledBorder(javax.swing.BorderFactory.createEtchedBorder(), "Game")); @@ -603,10 +609,9 @@ public class PreferencesDialog extends javax.swing.JDialog { .addGroup(main_gameLayout.createSequentialGroup() .addContainerGap() .addGroup(main_gameLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) - .addGroup(main_gameLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false) - .addComponent(showPlayerNamesPermanently, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(nonLandPermanentsInOnePile, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(showAbilityPickerForced, javax.swing.GroupLayout.Alignment.LEADING)) + .addComponent(showPlayerNamesPermanently, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(nonLandPermanentsInOnePile, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(showAbilityPickerForced) .addComponent(cbConfirmEmptyManaPool, javax.swing.GroupLayout.DEFAULT_SIZE, 485, Short.MAX_VALUE) .addComponent(cbAllowRequestToShowHandCards, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addComponent(cbShowStormCounter, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) @@ -691,10 +696,10 @@ public class PreferencesDialog extends javax.swing.JDialog { tabMainLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(tabMainLayout.createSequentialGroup() .addContainerGap() - .addComponent(main_card, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(main_card, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(main_game, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(main_gamelog, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addContainerGap()) ); @@ -911,7 +916,7 @@ public class PreferencesDialog extends javax.swing.JDialog { .addComponent(jLabelEndOfTurn) .addComponent(checkBoxEndTurnOthers)) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addComponent(phases_stopSettings, javax.swing.GroupLayout.DEFAULT_SIZE, 183, Short.MAX_VALUE) + .addComponent(phases_stopSettings, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addContainerGap()) ); @@ -1696,7 +1701,7 @@ public class PreferencesDialog extends javax.swing.JDialog { ); tabAvatarsLayout.setVerticalGroup( tabAvatarsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(avatarPane, javax.swing.GroupLayout.PREFERRED_SIZE, 418, Short.MAX_VALUE) + .addComponent(avatarPane, javax.swing.GroupLayout.PREFERRED_SIZE, 438, Short.MAX_VALUE) ); tabsPanel.addTab("Avatars", tabAvatars); @@ -1877,7 +1882,7 @@ public class PreferencesDialog extends javax.swing.JDialog { .addComponent(cbProxyType, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) .addGap(18, 18, 18) .addComponent(pnlProxySettings, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addContainerGap(107, Short.MAX_VALUE)) + .addContainerGap(127, Short.MAX_VALUE)) ); pnlProxySettings.getAccessibleContext().setAccessibleDescription(""); @@ -1931,7 +1936,7 @@ public class PreferencesDialog extends javax.swing.JDialog { // main save(prefs, dialog.displayBigCardsInHand, KEY_HAND_USE_BIG_CARDS, "true", "false", UPDATE_CACHE_POLICY); - save(prefs, dialog.showToolTipsInAnyZone, KEY_SHOW_TOOLTIPS_ANY_ZONE, "true", "false", UPDATE_CACHE_POLICY); + save(prefs, dialog.tooltipDelay, KEY_SHOW_TOOLTIPS_DELAY, "true", "false", UPDATE_CACHE_POLICY); save(prefs, dialog.showCardName, KEY_SHOW_CARD_NAMES, "true", "false", UPDATE_CACHE_POLICY); save(prefs, dialog.nonLandPermanentsInOnePile, KEY_PERMANENTS_IN_ONE_PILE, "true", "false", UPDATE_CACHE_POLICY); save(prefs, dialog.showPlayerNamesPermanently, KEY_SHOW_PLAYER_NAMES_PERMANENTLY, "true", "false", UPDATE_CACHE_POLICY); @@ -2222,10 +2227,6 @@ public class PreferencesDialog extends javax.swing.JDialog { // TODO add your handling code here: }//GEN-LAST:event_cbEnableOtherSoundsActionPerformed - private void showToolTipsInAnyZoneActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_showToolTipsInAnyZoneActionPerformed - // TODO add your handling code here: - }//GEN-LAST:event_showToolTipsInAnyZoneActionPerformed - private void cbStopAttackActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cbStopAttackActionPerformed // TODO add your handling code here: }//GEN-LAST:event_cbStopAttackActionPerformed @@ -2349,7 +2350,7 @@ public class PreferencesDialog extends javax.swing.JDialog { private static void loadPhases(Preferences prefs) { load(prefs, dialog.displayBigCardsInHand, KEY_HAND_USE_BIG_CARDS, "true", "true"); - load(prefs, dialog.showToolTipsInAnyZone, KEY_SHOW_TOOLTIPS_ANY_ZONE, "true"); + load(prefs, dialog.tooltipDelay, KEY_SHOW_TOOLTIPS_DELAY, "300"); load(prefs, dialog.showCardName, KEY_SHOW_CARD_NAMES, "true"); load(prefs, dialog.nonLandPermanentsInOnePile, KEY_PERMANENTS_IN_ONE_PILE, "true"); load(prefs, dialog.showPlayerNamesPermanently, KEY_SHOW_PLAYER_NAMES_PERMANENTLY, "true"); @@ -2573,6 +2574,18 @@ public class PreferencesDialog extends javax.swing.JDialog { field.setText(prop); } + private static void load(Preferences prefs, JSlider field, String propName, String defaultValue) { + String prop = prefs.get(propName, defaultValue); + int value; + try { + value = Integer.parseInt(prop); + } catch (NumberFormatException e) { + // It's OK to ignore "e" here because returning a default value is the documented behaviour on invalid input. + value = Integer.parseInt(defaultValue); + } + field.setValue(value); + } + private static void load(Preferences prefs, JComboBox field, String propName, String defaultValue) { String prop = prefs.get(propName, defaultValue); field.setSelectedItem(prop); @@ -2602,6 +2615,13 @@ public class PreferencesDialog extends javax.swing.JDialog { } } + private static void save(Preferences prefs, JSlider slider, String propName, String yesValue, String noValue, boolean updateCache) { + prefs.put(propName, Integer.toString(slider.getValue())); + if (updateCache) { + updateCache(propName, Integer.toString(slider.getValue())); + } + } + private static void save(Preferences prefs, JTextField textField, String propName) { prefs.put(propName, textField.getText().trim()); updateCache(propName, textField.getText().trim()); @@ -2616,6 +2636,18 @@ public class PreferencesDialog extends javax.swing.JDialog { tabsPanel.setSelectedIndex(0); } + public static int getCachedValue(String key, int def) { + String stringValue = getCachedValue(key, String.valueOf(def)); + int value; + try { + value = Integer.parseInt(stringValue); + } catch (NumberFormatException e) { + // It's OK to ignore "e" here because returning a default value is the documented behaviour on invalid input. + value = def; + } + return value; + } + public static String getCachedValue(String key, String def) { if (cache.containsKey(key)) { return cache.get(key); @@ -2852,7 +2884,6 @@ public class PreferencesDialog extends javax.swing.JDialog { private javax.swing.JCheckBox showAbilityPickerForced; private javax.swing.JCheckBox showCardName; private javax.swing.JCheckBox showPlayerNamesPermanently; - private javax.swing.JCheckBox showToolTipsInAnyZone; private javax.swing.JPanel sounds_backgroundMusic; private javax.swing.JPanel sounds_clips; private javax.swing.JPanel tabAvatars; @@ -2862,6 +2893,8 @@ public class PreferencesDialog extends javax.swing.JDialog { private javax.swing.JPanel tabPhases; private javax.swing.JPanel tabSounds; private javax.swing.JTabbedPane tabsPanel; + private javax.swing.JSlider tooltipDelay; + private javax.swing.JLabel tooltipDelayLabel; private javax.swing.JTextField txtBackgroundImagePath; private javax.swing.JTextField txtBattlefieldIBGMPath; private javax.swing.JTextField txtBattlefieldImagePath; diff --git a/Mage.Client/src/main/java/mage/client/plugins/adapters/MageActionCallback.java b/Mage.Client/src/main/java/mage/client/plugins/adapters/MageActionCallback.java index c236a42741b..9226a64c967 100644 --- a/Mage.Client/src/main/java/mage/client/plugins/adapters/MageActionCallback.java +++ b/Mage.Client/src/main/java/mage/client/plugins/adapters/MageActionCallback.java @@ -74,6 +74,7 @@ public class MageActionCallback implements ActionCallback { private TransferData popupData; private JComponent cardInfoPane; private volatile boolean popupTextWindowOpen = false; + private int tooltipDelay; enum EnlargedWindowState { @@ -140,8 +141,8 @@ public class MageActionCallback implements ActionCallback { private void showTooltipPopup(final TransferData data, final Component parentComponent, final Point parentPoint) { if (data.component != null) { - String showTooltips = PreferencesDialog.getCachedValue(PreferencesDialog.KEY_SHOW_TOOLTIPS_ANY_ZONE, "true"); - if (showTooltips.equals("false")) { + tooltipDelay = PreferencesDialog.getCachedValue(PreferencesDialog.KEY_SHOW_TOOLTIPS_DELAY, 300); + if (tooltipDelay == 0) { return; } } @@ -169,7 +170,7 @@ public class MageActionCallback implements ActionCallback { ThreadUtils.threadPool2.submit(new Runnable() { @Override public void run() { - ThreadUtils.sleep(300); + ThreadUtils.sleep(tooltipDelay); if (tooltipCard == null || !tooltipCard.equals(data.card) || session == null || !popupTextWindowOpen || !enlargedWindowState.equals(EnlargedWindowState.CLOSED)) { return; diff --git a/Mage.Sets/src/mage/sets/alarareborn/SagesOfTheAnima.java b/Mage.Sets/src/mage/sets/alarareborn/SagesOfTheAnima.java index 6c47d17f83a..95362b5c595 100644 --- a/Mage.Sets/src/mage/sets/alarareborn/SagesOfTheAnima.java +++ b/Mage.Sets/src/mage/sets/alarareborn/SagesOfTheAnima.java @@ -119,7 +119,7 @@ class SagesOfTheAnimaReplacementEffect extends ReplacementEffectImpl { cards.remove(revealedCard); } } - TargetCard target = new TargetCard(Zone.PICK, new FilterCard()); + TargetCard target = new TargetCard(Zone.LIBRARY, new FilterCard()); while (player.canRespond() && cards.size() > 1) { player.choose(Outcome.Neutral, cards, target, game); Card card = cards.get(target.getFirstTarget(), game); diff --git a/Mage.Sets/src/mage/sets/alliances/Browse.java b/Mage.Sets/src/mage/sets/alliances/Browse.java index 407eeca3648..db9b35396c9 100644 --- a/Mage.Sets/src/mage/sets/alliances/Browse.java +++ b/Mage.Sets/src/mage/sets/alliances/Browse.java @@ -97,14 +97,13 @@ class BrowseEffect extends OneShotEffect { Card card = player.getLibrary().removeFromTop(game); if (card != null) { cards.add(card); - game.setZone(card.getId(), Zone.PICK); } } if (cards.size() > 0) { player.lookAtCards("Browse", cards, game); - TargetCard target = new TargetCard(Zone.PICK, new FilterCard("card to put in your hand")); + TargetCard target = new TargetCard(Zone.LIBRARY, new FilterCard("card to put in your hand")); if (player.choose(Outcome.Benefit, cards, target, game)) { Card card = cards.get(target.getFirstTarget(), game); if (card != null) { diff --git a/Mage.Sets/src/mage/sets/alliances/SoldeviSage1.java b/Mage.Sets/src/mage/sets/alliances/SoldeviSage1.java index 0e262118d58..8f762f5fe25 100644 --- a/Mage.Sets/src/mage/sets/alliances/SoldeviSage1.java +++ b/Mage.Sets/src/mage/sets/alliances/SoldeviSage1.java @@ -110,7 +110,7 @@ class SoldeviSageEffect extends OneShotEffect { } if (drawnCards.size() > 0) { - TargetCard cardToDiscard = new TargetCard(Zone.PICK, new FilterCard("card to discard")); + TargetCard cardToDiscard = new TargetCard(Zone.HAND, new FilterCard("card to discard")); cardToDiscard.setNotTarget(true); if (player.choose(Outcome.Discard, drawnCards, cardToDiscard, game)) { Card card = player.getHand().get(cardToDiscard.getFirstTarget(), game); diff --git a/Mage.Sets/src/mage/sets/avacynrestored/BrunaLightOfAlabaster.java b/Mage.Sets/src/mage/sets/avacynrestored/BrunaLightOfAlabaster.java index 574072de20b..8ce9357753f 100644 --- a/Mage.Sets/src/mage/sets/avacynrestored/BrunaLightOfAlabaster.java +++ b/Mage.Sets/src/mage/sets/avacynrestored/BrunaLightOfAlabaster.java @@ -27,8 +27,7 @@ */ package mage.sets.avacynrestored; -import mage.constants.CardType; -import mage.constants.Rarity; +import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.AttacksOrBlocksTriggeredAbility; @@ -37,21 +36,22 @@ import mage.abilities.keyword.FlyingAbility; import mage.abilities.keyword.VigilanceAbility; import mage.cards.Card; import mage.cards.CardImpl; +import mage.constants.CardType; import mage.constants.Outcome; +import mage.constants.Rarity; import mage.constants.Zone; import mage.filter.FilterCard; import mage.filter.FilterPermanent; import mage.filter.predicate.mageobject.CardTypePredicate; import mage.filter.predicate.mageobject.SubtypePredicate; +import mage.filter.predicate.other.AuraCardCanAttachToPermanentId; +import mage.filter.predicate.other.AuraPermanentCanAttachToPermanentId; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.Target; import mage.target.TargetCard; import mage.target.TargetPermanent; -import java.util.UUID; -import mage.filter.predicate.other.AuraCardCanAttachToPermanentId; -import mage.filter.predicate.other.AuraPermanentCanAttachToPermanentId; /** * @author noxx */ @@ -138,7 +138,7 @@ class BrunaLightOfAlabasterEffect extends OneShotEffect { int count = player.getHand().count(filterAuraCard, game); while (player.canRespond() && count > 0 && player.chooseUse(Outcome.Benefit, "Attach an Aura from your hand?", source, game)) { - TargetCard targetAura = new TargetCard(Zone.PICK, filterAuraCard); + TargetCard targetAura = new TargetCard(Zone.HAND, filterAuraCard); if (player.choose(Outcome.Benefit, player.getHand(), targetAura, game)) { Card aura = game.getCard(targetAura.getFirstTarget()); if (aura != null) { @@ -152,7 +152,7 @@ class BrunaLightOfAlabasterEffect extends OneShotEffect { count = player.getGraveyard().count(filterAuraCard, game); while (player.canRespond() && count > 0 && player.chooseUse(Outcome.Benefit, "Attach an Aura from your graveyard?", source, game)) { - TargetCard targetAura = new TargetCard(Zone.PICK, filterAuraCard); + TargetCard targetAura = new TargetCard(Zone.GRAVEYARD, filterAuraCard); if (player.choose(Outcome.Benefit, player.getGraveyard(), targetAura, game)) { Card aura = game.getCard(targetAura.getFirstTarget()); if (aura != null) { diff --git a/Mage.Sets/src/mage/sets/avacynrestored/LairDelve.java b/Mage.Sets/src/mage/sets/avacynrestored/LairDelve.java index 0021f383139..46fa4bd7673 100644 --- a/Mage.Sets/src/mage/sets/avacynrestored/LairDelve.java +++ b/Mage.Sets/src/mage/sets/avacynrestored/LairDelve.java @@ -38,10 +38,8 @@ import mage.abilities.effects.OneShotEffect; import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardsImpl; -import mage.filter.FilterCard; import mage.game.Game; import mage.players.Player; -import mage.target.TargetCard; /** * @@ -106,20 +104,7 @@ class LairDelveEffect extends OneShotEffect { } } - TargetCard target = new TargetCard(Zone.PICK, new FilterCard("card to put on the bottom of your library")); - while (player.canRespond() && cards.size() > 1) { - player.choose(Outcome.Neutral, cards, target, game); - Card card = cards.get(target.getFirstTarget(), game); - if (card != null) { - cards.remove(card); - card.moveToZone(Zone.LIBRARY, source.getSourceId(), game, false); - } - target.clearChosen(); - } - if (cards.size() == 1) { - Card card = cards.get(cards.iterator().next(), game); - card.moveToZone(Zone.LIBRARY, source.getSourceId(), game, false); - } + player.putCardsOnBottomOfLibrary(cards, game, source, true); return true; } diff --git a/Mage.Sets/src/mage/sets/battleforzendikar/KioraMasterOfTheDepths.java b/Mage.Sets/src/mage/sets/battleforzendikar/KioraMasterOfTheDepths.java index 64440a19c86..5cad5cf83be 100644 --- a/Mage.Sets/src/mage/sets/battleforzendikar/KioraMasterOfTheDepths.java +++ b/Mage.Sets/src/mage/sets/battleforzendikar/KioraMasterOfTheDepths.java @@ -173,7 +173,7 @@ class KioraRevealEffect extends OneShotEffect { if ((creatureCardFound || landCardFound) && controller.chooseUse(Outcome.DrawCard, "Put a creature card and/or a land card into your hand?", source, game)) { - TargetCard target = new TargetCard(Zone.PICK, new FilterCreatureCard("creature card to put into your hand")); + TargetCard target = new TargetCard(Zone.LIBRARY, new FilterCreatureCard("creature card to put into your hand")); if (creatureCardFound && controller.chooseTarget(Outcome.DrawCard, cards, target, source, game)) { Card card = cards.get(target.getFirstTarget(), game); if (card != null) { diff --git a/Mage.Sets/src/mage/sets/bornofthegods/HeroesPodium.java b/Mage.Sets/src/mage/sets/bornofthegods/HeroesPodium.java index 9aa39c10839..fa6145a76c9 100644 --- a/Mage.Sets/src/mage/sets/bornofthegods/HeroesPodium.java +++ b/Mage.Sets/src/mage/sets/bornofthegods/HeroesPodium.java @@ -165,7 +165,6 @@ class HeroesPodiumEffect extends OneShotEffect { if (filter.match(card, game)) { legendaryIncluded = true; } - game.setZone(card.getId(), Zone.PICK); } } player.lookAtCards("Heroes' Podium", cards, game); @@ -178,7 +177,7 @@ class HeroesPodiumEffect extends OneShotEffect { card.moveToZone(Zone.HAND, source.getSourceId(), game, false); return true; } else { - TargetCard target = new TargetCard(Zone.PICK, filter); + TargetCard target = new TargetCard(Zone.LIBRARY, filter); if (player.choose(outcome, cards, target, game)) { Card card = cards.get(target.getFirstTarget(), game); if (card != null) { diff --git a/Mage.Sets/src/mage/sets/bornofthegods/LoyalPegasus.java b/Mage.Sets/src/mage/sets/bornofthegods/LoyalPegasus.java index 0a01871d90d..bd2ab37453b 100644 --- a/Mage.Sets/src/mage/sets/bornofthegods/LoyalPegasus.java +++ b/Mage.Sets/src/mage/sets/bornofthegods/LoyalPegasus.java @@ -53,7 +53,7 @@ public class LoyalPegasus extends CardImpl { // Flying this.addAbility(FlyingAbility.getInstance()); // Loyal Pegasus can't attack or block alone. - this.addAbility(CantAttackAloneAbility.getInstance()); + this.addAbility(new CantAttackAloneAbility()); this.addAbility(CantBlockAloneAbility.getInstance()); } diff --git a/Mage.Sets/src/mage/sets/commander/KodamasReach.java b/Mage.Sets/src/mage/sets/commander/KodamasReach.java index 103a617285c..19c3bae05cf 100644 --- a/Mage.Sets/src/mage/sets/commander/KodamasReach.java +++ b/Mage.Sets/src/mage/sets/commander/KodamasReach.java @@ -106,7 +106,7 @@ class KodamasReachEffect extends OneShotEffect { } controller.revealCards(sourceObject.getIdName(), revealed, game); if (target.getTargets().size() == 2) { - TargetCard target2 = new TargetCard(Zone.PICK, filter); + TargetCard target2 = new TargetCard(Zone.LIBRARY, filter); controller.choose(Outcome.Benefit, revealed, target2, game); Card card = revealed.get(target2.getFirstTarget(), game); if (card != null) { diff --git a/Mage.Sets/src/mage/sets/commander2013/AEthermagesTouch.java b/Mage.Sets/src/mage/sets/commander2013/AEthermagesTouch.java index 5f4e767c3db..f50c8cdaae4 100644 --- a/Mage.Sets/src/mage/sets/commander2013/AEthermagesTouch.java +++ b/Mage.Sets/src/mage/sets/commander2013/AEthermagesTouch.java @@ -112,12 +112,12 @@ class AEthermagesTouchEffect extends OneShotEffect { if (!cards.isEmpty()) { player.revealCards("AEthermage's Touch", cards, game); - TargetCard target = new TargetCard(Zone.PICK, filterPutOntoBattlefield); + TargetCard target = new TargetCard(Zone.LIBRARY, filterPutOntoBattlefield); if (properCardFound && player.choose(Outcome.PutCreatureInPlay, cards, target, game)) { Card card = game.getCard(target.getFirstTarget()); if (card != null) { cards.remove(card); - if (card.putOntoBattlefield(game, Zone.PICK, source.getSourceId(), source.getControllerId())) { + if (card.putOntoBattlefield(game, Zone.LIBRARY, source.getSourceId(), source.getControllerId())) { // It gains \"At the beginning of your end step, return this creature to its owner's hand.\" Ability ability = new BeginningOfEndStepTriggeredAbility(Zone.BATTLEFIELD, new ReturnToHandSourceEffect(true), TargetController.YOU, null, false); ContinuousEffect effect = new GainAbilityTargetEffect(ability, Duration.Custom); diff --git a/Mage.Sets/src/mage/sets/commander2013/LimDulsVault.java b/Mage.Sets/src/mage/sets/commander2013/LimDulsVault.java index 10b1524f4f0..b3a64dece08 100644 --- a/Mage.Sets/src/mage/sets/commander2013/LimDulsVault.java +++ b/Mage.Sets/src/mage/sets/commander2013/LimDulsVault.java @@ -101,7 +101,6 @@ class LimDulsVaultEffect extends OneShotEffect { Card card = player.getLibrary().removeFromTop(game); if (card != null) { cards.add(card); - game.setZone(card.getId(), Zone.PICK); } } player.lookAtCards("Lim-Dul's Vault", cards, game); @@ -112,7 +111,7 @@ class LimDulsVaultEffect extends OneShotEffect { player.shuffleLibrary(game); } - TargetCard target = new TargetCard(Zone.PICK, new FilterCard(doAgain ? textBottom : textTop)); + TargetCard target = new TargetCard(Zone.LIBRARY, new FilterCard(doAgain ? textBottom : textTop)); while (player.canRespond() && cards.size() > 1) { player.choose(Outcome.Neutral, cards, target, game); Card card = cards.get(target.getFirstTarget(), game); diff --git a/Mage.Sets/src/mage/sets/commander2015/ArjunTheShiftingFlame.java b/Mage.Sets/src/mage/sets/commander2015/ArjunTheShiftingFlame.java index 2c146818d31..f716946b9fb 100644 --- a/Mage.Sets/src/mage/sets/commander2015/ArjunTheShiftingFlame.java +++ b/Mage.Sets/src/mage/sets/commander2015/ArjunTheShiftingFlame.java @@ -33,18 +33,12 @@ import mage.abilities.Ability; import mage.abilities.common.SpellCastControllerTriggeredAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.keyword.FlyingAbility; -import mage.cards.Card; import mage.cards.CardImpl; -import mage.cards.Cards; -import mage.cards.CardsImpl; import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.Rarity; -import mage.constants.Zone; -import mage.filter.FilterCard; import mage.game.Game; import mage.players.Player; -import mage.target.TargetCard; /** * @@ -94,25 +88,7 @@ class ArjunTheShiftingFlameEffect extends OneShotEffect { Player you = game.getPlayer(source.getControllerId()); if (you != null) { int count = you.getHand().size(); - Cards cards = new CardsImpl(); - for (Card card : you.getHand().getCards(game)) { - cards.add(card.getId()); - } - TargetCard target = new TargetCard(Zone.PICK, new FilterCard("card to put on the bottom of your library")); - while (you.canRespond() && cards.size() > 1) { - you.choose(Outcome.Neutral, cards, target, game); - Card card = cards.get(target.getFirstTarget(), game); - if (card != null) { - cards.remove(card); - card.moveToZone(Zone.LIBRARY, source.getSourceId(), game, false); - } - target.clearChosen(); - } - if (cards.size() == 1) { - Card card = cards.get(cards.iterator().next(), game); - card.moveToZone(Zone.LIBRARY, source.getSourceId(), game, false); - } - you.getHand().clear(); + you.putCardsOnBottomOfLibrary(you.getHand(), game, source, true); you.drawCards(count, game); } return true; diff --git a/Mage.Sets/src/mage/sets/conflux/WorldlyCounsel.java b/Mage.Sets/src/mage/sets/conflux/WorldlyCounsel.java index bd8ded0fbfb..d288aecf7d7 100644 --- a/Mage.Sets/src/mage/sets/conflux/WorldlyCounsel.java +++ b/Mage.Sets/src/mage/sets/conflux/WorldlyCounsel.java @@ -99,7 +99,6 @@ class WorldlyCounselEffect extends OneShotEffect { Card card = player.getLibrary().removeFromTop(game); if (card != null) { cards.add(card); - game.setZone(card.getId(), Zone.PICK); } } player.lookAtCards("Worldly Counsel", cards, game); @@ -111,7 +110,7 @@ class WorldlyCounselEffect extends OneShotEffect { card.moveToZone(Zone.HAND, source.getSourceId(), game, false); return true; } else { - TargetCard target = new TargetCard(Zone.PICK, new FilterCard("card to put into your hand")); + TargetCard target = new TargetCard(Zone.LIBRARY, new FilterCard("card to put into your hand")); if (player.choose(Outcome.DrawCard, cards, target, game)) { Card card = cards.get(target.getFirstTarget(), game); if (card != null) { @@ -121,22 +120,7 @@ class WorldlyCounselEffect extends OneShotEffect { } } } - - - TargetCard target = new TargetCard(Zone.PICK, new FilterCard("card to put on the bottom of your library")); - while (cards.size() > 1) { - player.choose(Outcome.Neutral, cards, target, game); - Card card = cards.get(target.getFirstTarget(), game); - if (card != null) { - cards.remove(card); - card.moveToZone(Zone.LIBRARY, source.getSourceId(), game, false); - } - target.clearChosen(); - } - if (cards.size() == 1) { - Card card = cards.get(cards.iterator().next(), game); - card.moveToZone(Zone.LIBRARY, source.getSourceId(), game, false); - } + player.putCardsOnBottomOfLibrary(cards, game, source, true); return true; } } diff --git a/Mage.Sets/src/mage/sets/darkascension/CallToTheKindred.java b/Mage.Sets/src/mage/sets/darkascension/CallToTheKindred.java index 7f880c0f522..ba5bd4e5c11 100644 --- a/Mage.Sets/src/mage/sets/darkascension/CallToTheKindred.java +++ b/Mage.Sets/src/mage/sets/darkascension/CallToTheKindred.java @@ -43,7 +43,6 @@ import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.Rarity; import mage.constants.Zone; -import mage.filter.FilterCard; import mage.filter.common.FilterCreatureCard; import mage.filter.predicate.Predicate; import mage.filter.predicate.Predicates; @@ -125,7 +124,6 @@ class CallToTheKindredEffect extends OneShotEffect { Card card = player.getLibrary().removeFromTop(game); if (card != null) { cards.add(card); - game.setZone(card.getId(), Zone.PICK); } } player.lookAtCards("Call to the Kindred", cards, game); @@ -142,32 +140,17 @@ class CallToTheKindredEffect extends OneShotEffect { filter.setMessage(sb.toString()); if (cards.count(filter, game) > 0 && player.chooseUse(Outcome.DrawCard, "Do you wish to put a creature card onto the battlefield?", source, game)) { - TargetCard target = new TargetCard(Zone.PICK, filter); + TargetCard target = new TargetCard(Zone.LIBRARY, filter); if (player.choose(Outcome.PutCreatureInPlay, cards, target, game)) { Card card = cards.get(target.getFirstTarget(), game); if (card != null) { cards.remove(card); - card.putOntoBattlefield(game, Zone.PICK, source.getSourceId(), source.getControllerId()); + card.putOntoBattlefield(game, Zone.LIBRARY, source.getSourceId(), source.getControllerId()); } } } - - TargetCard target = new TargetCard(Zone.PICK, new FilterCard("card to put on the bottom of your library")); - while (player.canRespond() && cards.size() > 1) { - player.choose(Outcome.Neutral, cards, target, game); - Card card = cards.get(target.getFirstTarget(), game); - if (card != null) { - cards.remove(card); - card.moveToZone(Zone.LIBRARY, source.getSourceId(), game, false); - } - target.clearChosen(); - } - if (cards.size() == 1) { - Card card = cards.get(cards.iterator().next(), game); - card.moveToZone(Zone.LIBRARY, source.getSourceId(), game, false); - } - + player.putCardsOnBottomOfLibrary(cards, game, source, true); return true; } } \ No newline at end of file diff --git a/Mage.Sets/src/mage/sets/darkascension/GruesomeDiscovery.java b/Mage.Sets/src/mage/sets/darkascension/GruesomeDiscovery.java index a9223d9c4af..3192b0f5a16 100644 --- a/Mage.Sets/src/mage/sets/darkascension/GruesomeDiscovery.java +++ b/Mage.Sets/src/mage/sets/darkascension/GruesomeDiscovery.java @@ -29,10 +29,6 @@ package mage.sets.darkascension; import java.util.List; import java.util.UUID; -import mage.constants.CardType; -import mage.constants.Outcome; -import mage.constants.Rarity; -import mage.constants.Zone; import mage.abilities.Ability; import mage.abilities.condition.common.MorbidCondition; import mage.abilities.decorator.ConditionalOneShotEffect; @@ -40,6 +36,10 @@ import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.discard.DiscardTargetEffect; import mage.cards.Card; import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.constants.Zone; import mage.filter.FilterCard; import mage.game.Game; import mage.players.Player; @@ -105,7 +105,7 @@ class GruesomeDiscoveryEffect extends OneShotEffect { targetPlayer.discard(2, source, game); } - TargetCard target = new TargetCard(2, Zone.PICK, new FilterCard()); + TargetCard target = new TargetCard(2, Zone.HAND, new FilterCard()); if (player.choose(Outcome.Benefit, targetPlayer.getHand(), target, game)) { List targets = target.getTargets(); for (UUID targetId : targets) { diff --git a/Mage.Sets/src/mage/sets/darkascension/JarOfEyeballs.java b/Mage.Sets/src/mage/sets/darkascension/JarOfEyeballs.java index 857ff6a3238..d8a5d62eb25 100644 --- a/Mage.Sets/src/mage/sets/darkascension/JarOfEyeballs.java +++ b/Mage.Sets/src/mage/sets/darkascension/JarOfEyeballs.java @@ -203,12 +203,11 @@ class JarOfEyeballsEffect extends OneShotEffect { Card card = player.getLibrary().removeFromTop(game); if (card != null) { cards.add(card); - game.setZone(card.getId(), Zone.PICK); } } player.lookAtCards("Jar of Eyeballs", cards, game); - TargetCard target = new TargetCard(Zone.PICK, new FilterCard("card to put into your hand")); + TargetCard target = new TargetCard(Zone.LIBRARY, new FilterCard("card to put into your hand")); if (player.choose(Outcome.DrawCard, cards, target, game)) { Card card = cards.get(target.getFirstTarget(), game); if (card != null) { @@ -216,22 +215,7 @@ class JarOfEyeballsEffect extends OneShotEffect { card.moveToZone(Zone.HAND, source.getSourceId(), game, false); } } - - target = new TargetCard(Zone.PICK, new FilterCard("card to put on the bottom of your library")); - while (cards.size() > 1) { - player.choose(Outcome.Neutral, cards, target, game); - Card card = cards.get(target.getFirstTarget(), game); - if (card != null) { - cards.remove(card); - card.moveToZone(Zone.LIBRARY, source.getSourceId(), game, false); - } - target.clearChosen(); - } - if (cards.size() == 1) { - Card card = cards.get(cards.iterator().next(), game); - card.moveToZone(Zone.LIBRARY, source.getSourceId(), game, false); - } - + player.putCardsOnBottomOfLibrary(cards, game, source, true); return true; } } diff --git a/Mage.Sets/src/mage/sets/dissension/ResearchDevelopment.java b/Mage.Sets/src/mage/sets/dissension/ResearchDevelopment.java index 959e9e2fc81..7f8df2846f9 100644 --- a/Mage.Sets/src/mage/sets/dissension/ResearchDevelopment.java +++ b/Mage.Sets/src/mage/sets/dissension/ResearchDevelopment.java @@ -27,6 +27,8 @@ */ package mage.sets.dissension; +import java.util.Set; +import java.util.UUID; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.CreateTokenEffect; @@ -44,9 +46,6 @@ import mage.game.permanent.token.ElementalToken; import mage.players.Player; import mage.target.TargetCard; -import java.util.Set; -import java.util.UUID; - /** * * @author magenoxx @@ -120,7 +119,7 @@ class ResearchEffect extends OneShotEffect { filteredCards.add(card.getId()); } - TargetCard target = new TargetCard(Zone.PICK, filter); + TargetCard target = new TargetCard(Zone.OUTSIDE, filter); if (player.choose(Outcome.Benefit, filteredCards, target, game)) { Card card = player.getSideboard().get(target.getFirstTarget(), game); if (card != null) { diff --git a/Mage.Sets/src/mage/sets/dragonsmaze/MasterOfCruelties.java b/Mage.Sets/src/mage/sets/dragonsmaze/MasterOfCruelties.java index 776570e5a0f..50a8dd16d8a 100644 --- a/Mage.Sets/src/mage/sets/dragonsmaze/MasterOfCruelties.java +++ b/Mage.Sets/src/mage/sets/dragonsmaze/MasterOfCruelties.java @@ -69,7 +69,7 @@ public class MasterOfCruelties extends CardImpl { // Deathtouch this.addAbility(DeathtouchAbility.getInstance()); // Master of Cruelties can only attack alone. - this.addAbility(CanAttackOnlyAloneAbility.getInstance()); + this.addAbility(new CanAttackOnlyAloneAbility()); // Whenever Master of Cruelties attacks a player and isn't blocked, that player's life total becomes 1. Master of Cruelties assigns no combat damage this combat. this.addAbility(new MasterOfCrueltiesTriggeredAbility()); @@ -111,7 +111,7 @@ class MasterOfCrueltiesTriggeredAbility extends TriggeredAbilityImpl { public boolean checkTrigger(GameEvent event, Game game) { Permanent sourcePermanent = game.getPermanent(getSourceId()); if (sourcePermanent.isAttacking()) { - for (CombatGroup combatGroup: game.getCombat().getGroups()) { + for (CombatGroup combatGroup : game.getCombat().getGroups()) { if (combatGroup.getBlockers().isEmpty() && combatGroup.getAttackers().contains(getSourceId())) { // check if a player is attacked (instead of a planeswalker) Player defendingPlayer = game.getPlayer(combatGroup.getDefenderId()); @@ -184,11 +184,11 @@ class MasterOfCrueltiesNoDamageEffect extends ContinuousRuleModifyingEffectImpl return false; } } - + @Override public boolean applies(GameEvent event, Ability source, Game game) { DamageEvent damageEvent = (DamageEvent) event; - return event.getSourceId().equals(source.getSourceId()) && damageEvent.isCombatDamage(); - + return event.getSourceId().equals(source.getSourceId()) && damageEvent.isCombatDamage(); + } } diff --git a/Mage.Sets/src/mage/sets/dragonsoftarkir/BlessedReincarnation.java b/Mage.Sets/src/mage/sets/dragonsoftarkir/BlessedReincarnation.java index b2a0500f83a..346ae0439ef 100644 --- a/Mage.Sets/src/mage/sets/dragonsoftarkir/BlessedReincarnation.java +++ b/Mage.Sets/src/mage/sets/dragonsoftarkir/BlessedReincarnation.java @@ -125,7 +125,7 @@ class BlessedReincarnationEffect extends OneShotEffect { } if (card.getCardType().contains(CardType.CREATURE)) { - card.putOntoBattlefield(game, Zone.PICK, source.getSourceId(), player.getId()); + card.putOntoBattlefield(game, Zone.LIBRARY, source.getSourceId(), player.getId()); } if (cards.size() > 0) { diff --git a/Mage.Sets/src/mage/sets/eventide/Evershrike.java b/Mage.Sets/src/mage/sets/eventide/Evershrike.java index 776939f0dcd..e764436aead 100644 --- a/Mage.Sets/src/mage/sets/eventide/Evershrike.java +++ b/Mage.Sets/src/mage/sets/eventide/Evershrike.java @@ -123,7 +123,7 @@ class EvershrikeEffect extends OneShotEffect { filterAuraCard.add(new ConvertedManaCostPredicate(ComparisonType.LessThan, xAmount)); int count = controller.getHand().count(filterAuraCard, game); while (controller.canRespond() && count > 0 && controller.chooseUse(Outcome.Benefit, "Do you wish to put an Aura card from your hand onto Evershrike", source, game)) { - TargetCard targetAura = new TargetCard(Zone.PICK, filterAuraCard); + TargetCard targetAura = new TargetCard(Zone.HAND, filterAuraCard); if (controller.choose(Outcome.Benefit, controller.getHand(), targetAura, game)) { Card aura = game.getCard(targetAura.getFirstTarget()); if (aura != null) { diff --git a/Mage.Sets/src/mage/sets/eventide/TalarasBane.java b/Mage.Sets/src/mage/sets/eventide/TalarasBane.java index 13902a46f22..62e483c7bac 100644 --- a/Mage.Sets/src/mage/sets/eventide/TalarasBane.java +++ b/Mage.Sets/src/mage/sets/eventide/TalarasBane.java @@ -105,7 +105,7 @@ class TalarasBaneEffect extends OneShotEffect { Card card = null; if (targetPlayer != null && you != null) { targetPlayer.revealCards("Talaras Bane", targetPlayer.getHand(), game); - TargetCard target = new TargetCard(Zone.PICK, filter); + TargetCard target = new TargetCard(Zone.HAND, filter); if (you.choose(Outcome.Benefit, targetPlayer.getHand(), target, game)) { card = targetPlayer.getHand().get(target.getFirstTarget(), game); } diff --git a/Mage.Sets/src/mage/sets/fifthdawn/PlungeIntoDarkness.java b/Mage.Sets/src/mage/sets/fifthdawn/PlungeIntoDarkness.java index ecfc295f542..f43581055ab 100644 --- a/Mage.Sets/src/mage/sets/fifthdawn/PlungeIntoDarkness.java +++ b/Mage.Sets/src/mage/sets/fifthdawn/PlungeIntoDarkness.java @@ -156,12 +156,11 @@ class PlungeIntoDarknessSearchEffect extends OneShotEffect { Card card = player.getLibrary().removeFromTop(game); if (card != null) { cards.add(card); - game.setZone(card.getId(), Zone.PICK); } } player.lookAtCards("Plunge into Darkness", cards, game); - TargetCard target = new TargetCard(Zone.PICK, new FilterCard("card to put into your hand")); + TargetCard target = new TargetCard(Zone.LIBRARY, new FilterCard("card to put into your hand")); if (player.choose(Outcome.DrawCard, cards, target, game)) { Card card = cards.get(target.getFirstTarget(), game); if (card != null) { diff --git a/Mage.Sets/src/mage/sets/fifthdawn/PossessedPortal.java b/Mage.Sets/src/mage/sets/fifthdawn/PossessedPortal.java new file mode 100644 index 00000000000..246be1f7596 --- /dev/null +++ b/Mage.Sets/src/mage/sets/fifthdawn/PossessedPortal.java @@ -0,0 +1,142 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.fifthdawn; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.BeginningOfEndStepTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.Cost; +import mage.abilities.costs.common.DiscardCardCost; +import mage.abilities.costs.common.SacrificeTargetCost; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.ReplacementEffectImpl; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.constants.TargetController; +import mage.constants.Zone; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.players.Player; +import mage.target.common.TargetControlledPermanent; + +/** + * + * @author emerald000 + */ +public class PossessedPortal extends CardImpl { + + public PossessedPortal(UUID ownerId) { + super(ownerId, 144, "Possessed Portal", Rarity.RARE, new CardType[]{CardType.ARTIFACT}, "{8}"); + this.expansionSetCode = "5DN"; + + // If a player would draw a card, that player skips that draw instead. + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new PossessedPortalReplacementEffect())); + + // At the beginning of each end step, each player sacrifices a permanent unless he or she discards a card. + this.addAbility(new BeginningOfEndStepTriggeredAbility(new PossessedPortalEffect(), TargetController.ANY, false)); + } + + public PossessedPortal(final PossessedPortal card) { + super(card); + } + + @Override + public PossessedPortal copy() { + return new PossessedPortal(this); + } +} + +class PossessedPortalReplacementEffect extends ReplacementEffectImpl { + + PossessedPortalReplacementEffect() { + super(Duration.WhileOnBattlefield, Outcome.Neutral); + this.staticText = "If a player would draw a card, that player skips that draw instead"; + } + + PossessedPortalReplacementEffect(final PossessedPortalReplacementEffect effect) { + super(effect); + } + + @Override + public PossessedPortalReplacementEffect copy() { + return new PossessedPortalReplacementEffect(this); + } + + @Override + public boolean replaceEvent(GameEvent event, Ability source, Game game) { + return true; + } + + @Override + public boolean checksEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.DRAW_CARD; + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + return true; + } +} + +class PossessedPortalEffect extends OneShotEffect { + + PossessedPortalEffect() { + super(Outcome.Benefit); + this.staticText = "each player sacrifices a permanent unless he or she discards a card"; + } + + PossessedPortalEffect(final PossessedPortalEffect effect) { + super(effect); + } + + @Override + public PossessedPortalEffect copy() { + return new PossessedPortalEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + for (UUID playerId : game.getState().getPlayersInRange(source.getControllerId(), game)) { + Player player = game.getPlayer(playerId); + Cost discardCost = new DiscardCardCost(); + if (discardCost.canPay(source, source.getSourceId(), playerId, game) + && player.chooseUse(Outcome.Discard, "Discard a card? (Otherwise sacrifice a permanent)", source, game)) { + discardCost.pay(source, game, source.getSourceId(), playerId, true); + } + else { + Cost sacrificeCost = new SacrificeTargetCost(new TargetControlledPermanent()); + sacrificeCost.pay(source, game, source.getSourceId(), playerId, true); + } + } + return true; + } +} diff --git a/Mage.Sets/src/mage/sets/fifthedition/SylvanLibrary.java b/Mage.Sets/src/mage/sets/fifthedition/SylvanLibrary.java index d20b20c4158..113e73b9d49 100644 --- a/Mage.Sets/src/mage/sets/fifthedition/SylvanLibrary.java +++ b/Mage.Sets/src/mage/sets/fifthedition/SylvanLibrary.java @@ -136,7 +136,7 @@ class SylvanLibraryEffect extends OneShotEffect { } int numberOfCardsToPutBack = cardsPutBack.size(); if (numberOfCardsToPutBack > 1) { - TargetCard target2 = new TargetCard(Zone.PICK, new FilterCard("card to put on the top of your library (last chosen will be on top)")); + TargetCard target2 = new TargetCard(Zone.HAND, new FilterCard("card to put on the top of your library (last chosen will be on top)")); while (controller.canRespond() && cardsPutBack.size() > 1) { controller.choose(Outcome.Benefit, cardsPutBack, target2, game); Card card = cardsPutBack.get(target2.getFirstTarget(), game); diff --git a/Mage.Sets/src/mage/sets/futuresight/GlitteringWish.java b/Mage.Sets/src/mage/sets/futuresight/GlitteringWish.java index 9f2aa2e6e1a..102dbe5da1c 100644 --- a/Mage.Sets/src/mage/sets/futuresight/GlitteringWish.java +++ b/Mage.Sets/src/mage/sets/futuresight/GlitteringWish.java @@ -29,9 +29,6 @@ package mage.sets.futuresight; import java.util.Set; import java.util.UUID; - -import mage.constants.CardType; -import mage.constants.Rarity; import mage.MageObject; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; @@ -39,7 +36,9 @@ import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.Cards; import mage.cards.CardsImpl; +import mage.constants.CardType; import mage.constants.Outcome; +import mage.constants.Rarity; import mage.constants.Zone; import mage.filter.FilterCard; import mage.filter.predicate.Predicate; @@ -128,7 +127,7 @@ class GlitteringWishEffect extends OneShotEffect { filteredCards.add(card.getId()); } - TargetCard target = new TargetCard(Zone.PICK, filter); + TargetCard target = new TargetCard(Zone.OUTSIDE, filter); if (player.choose(Outcome.Benefit, filteredCards, target, game)) { Card card = player.getSideboard().get(target.getFirstTarget(), game); if (card != null) { diff --git a/Mage.Sets/src/mage/sets/gatecrash/DimirCharm.java b/Mage.Sets/src/mage/sets/gatecrash/DimirCharm.java index eca00ed3f00..df95815b303 100644 --- a/Mage.Sets/src/mage/sets/gatecrash/DimirCharm.java +++ b/Mage.Sets/src/mage/sets/gatecrash/DimirCharm.java @@ -119,7 +119,6 @@ class DimirCharmEffect extends OneShotEffect { Card card = player.getLibrary().removeFromTop(game); if(card != null){ cards.add(card); - game.getState().setZone(card.getId(), Zone.PICK); } } if(cards.size() > 0){ diff --git a/Mage.Sets/src/mage/sets/gatecrash/EmberBeast.java b/Mage.Sets/src/mage/sets/gatecrash/EmberBeast.java index 77ebea7de25..3451bdc4a57 100644 --- a/Mage.Sets/src/mage/sets/gatecrash/EmberBeast.java +++ b/Mage.Sets/src/mage/sets/gatecrash/EmberBeast.java @@ -28,12 +28,12 @@ package mage.sets.gatecrash; import java.util.UUID; -import mage.constants.CardType; -import mage.constants.Rarity; import mage.MageInt; import mage.abilities.keyword.CantAttackAloneAbility; import mage.abilities.keyword.CantBlockAloneAbility; import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; /** * @@ -50,7 +50,7 @@ public class EmberBeast extends CardImpl { this.toughness = new MageInt(4); // Ember Beast can't attack or block alone. - this.addAbility(CantAttackAloneAbility.getInstance()); + this.addAbility(new CantAttackAloneAbility()); this.addAbility(CantBlockAloneAbility.getInstance()); } diff --git a/Mage.Sets/src/mage/sets/gatecrash/LordOfTheVoid.java b/Mage.Sets/src/mage/sets/gatecrash/LordOfTheVoid.java index 124f66d644f..8c8719399de 100644 --- a/Mage.Sets/src/mage/sets/gatecrash/LordOfTheVoid.java +++ b/Mage.Sets/src/mage/sets/gatecrash/LordOfTheVoid.java @@ -1,5 +1,5 @@ /* -/* + /* * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are @@ -29,10 +29,6 @@ package mage.sets.gatecrash; import java.util.UUID; -import mage.constants.CardType; -import mage.constants.Outcome; -import mage.constants.Rarity; -import mage.constants.Zone; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; @@ -42,6 +38,10 @@ import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.Cards; import mage.cards.CardsImpl; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.constants.Zone; import mage.filter.common.FilterCreatureCard; import mage.game.Game; import mage.players.Player; @@ -58,13 +58,12 @@ public class LordOfTheVoid extends CardImpl { this.expansionSetCode = "GTC"; this.subtype.add("Demon"); - this.power = new MageInt(7); this.toughness = new MageInt(7); //Flying this.addAbility(FlyingAbility.getInstance()); - + //Whenever Lord of the Void deals combat damage to a player, exile the top seven cards of that player's library, then put a creature card from among them onto the battlefield under your control. this.addAbility(new DealsCombatDamageToAPlayerTriggeredAbility(new LordOfTheVoidEffect(), false, true)); } @@ -79,11 +78,10 @@ public class LordOfTheVoid extends CardImpl { } } - class LordOfTheVoidEffect extends OneShotEffect { public LordOfTheVoidEffect() { - super(Outcome.PutCardInPlay); + super(Outcome.PutCreatureInPlay); this.staticText = "exile the top seven cards of that player's library, then put a creature card from among them onto the battlefield under your control"; } @@ -103,22 +101,16 @@ class LordOfTheVoidEffect extends OneShotEffect { if (player == null || controller == null) { return false; } - + Cards cards = new CardsImpl(); - int max = Math.min(player.getLibrary().size(), 7); - for(int i = 0; i < max; i++){ - Card card = player.getLibrary().removeFromTop(game); - if (card != null) { - card.moveToExile(null, "", source.getSourceId(), game); - cards.add(card); - } - } - if(cards.getCards(new FilterCreatureCard(), game).size() > 0){ + cards.addAll(player.getLibrary().getTopCards(game, 7)); + controller.moveCards(cards, Zone.EXILED, source, game); + if (cards.getCards(new FilterCreatureCard(), game).size() > 0) { TargetCard target = new TargetCard(Zone.EXILED, new FilterCreatureCard()); - if(controller.chooseTarget(Outcome.PutCreatureInPlay, cards, target, source, game)){ + if (controller.chooseTarget(outcome, cards, target, source, game)) { Card card = cards.get(target.getFirstTarget(), game); - if(card != null){ - card.putOntoBattlefield(game, Zone.EXILED, source.getSourceId(), source.getControllerId()); + if (card != null) { + controller.moveCards(cards.getCards(game), Zone.BATTLEFIELD, source, game, false, false, false, null); } } } diff --git a/Mage.Sets/src/mage/sets/iceage/OrcishLibrarian.java b/Mage.Sets/src/mage/sets/iceage/OrcishLibrarian.java index ed8f653acad..1904068c864 100644 --- a/Mage.Sets/src/mage/sets/iceage/OrcishLibrarian.java +++ b/Mage.Sets/src/mage/sets/iceage/OrcishLibrarian.java @@ -105,7 +105,6 @@ class OrcishLibrarianEffect extends OneShotEffect { Card card = player.getLibrary().removeFromTop(game); if (card != null) { cards.add(card); - game.setZone(card.getId(), Zone.PICK); } } @@ -120,7 +119,7 @@ class OrcishLibrarianEffect extends OneShotEffect { } } player.lookAtCards("OrcishLibrarian", cards, game); - TargetCard target = new TargetCard (Zone.PICK, new FilterCard("card to put on the top of target player's library")); + TargetCard target = new TargetCard (Zone.LIBRARY, new FilterCard("card to put on the top of target player's library")); while (player.canRespond() && cards.size() > 0) { player.choose(Outcome.Neutral, cards, target, game); Card card = cards.get(target.getFirstTarget(), game); diff --git a/Mage.Sets/src/mage/sets/innistrad/ForbiddenAlchemy.java b/Mage.Sets/src/mage/sets/innistrad/ForbiddenAlchemy.java index 0ff05dc5e7b..8a110da6ef4 100644 --- a/Mage.Sets/src/mage/sets/innistrad/ForbiddenAlchemy.java +++ b/Mage.Sets/src/mage/sets/innistrad/ForbiddenAlchemy.java @@ -100,14 +100,13 @@ class ForbiddenAlchemyEffect extends OneShotEffect { Card card = player.getLibrary().removeFromTop(game); if (card != null) { cards.add(card); - game.setZone(card.getId(), Zone.PICK); } } if (cards.size() > 0) { player.lookAtCards("Forbidden Alchemy", cards, game); - TargetCard target = new TargetCard(Zone.PICK, new FilterCard("card to put in your hand")); + TargetCard target = new TargetCard(Zone.LIBRARY, new FilterCard("card to put in your hand")); if (player.choose(Outcome.Benefit, cards, target, game)) { Card card = cards.get(target.getFirstTarget(), game); if (card != null) { diff --git a/Mage.Sets/src/mage/sets/innistrad/NightTerrors.java b/Mage.Sets/src/mage/sets/innistrad/NightTerrors.java index f8dc2b78031..2c42fbd3b2e 100644 --- a/Mage.Sets/src/mage/sets/innistrad/NightTerrors.java +++ b/Mage.Sets/src/mage/sets/innistrad/NightTerrors.java @@ -91,7 +91,7 @@ class NightTerrorsEffect extends OneShotEffect { if (player != null && targetPlayer != null) { targetPlayer.revealCards("Night Terrors", targetPlayer.getHand(), game); - TargetCard target = new TargetCard(Zone.PICK, new FilterNonlandCard("nonland card to exile")); + TargetCard target = new TargetCard(Zone.HAND, new FilterNonlandCard("nonland card to exile")); if (player.choose(Outcome.Exile, targetPlayer.getHand(), target, game)) { Card card = targetPlayer.getHand().get(target.getFirstTarget(), game); if (card != null) { diff --git a/Mage.Sets/src/mage/sets/invasion/RevivingVapors.java b/Mage.Sets/src/mage/sets/invasion/RevivingVapors.java index d867fbc732b..5d990487002 100644 --- a/Mage.Sets/src/mage/sets/invasion/RevivingVapors.java +++ b/Mage.Sets/src/mage/sets/invasion/RevivingVapors.java @@ -104,7 +104,7 @@ class RevivingVaporsEffect extends OneShotEffect { if (cards.size() == 1) { card = cards.getRandom(game); } else { - TargetCard target = new TargetCard(Zone.PICK, new FilterCard("card to put into your hand")); + TargetCard target = new TargetCard(Zone.LIBRARY, new FilterCard("card to put into your hand")); target.setRequired(true); if (controller.choose(Outcome.DrawCard, cards, target, game)) { card = cards.get(target.getFirstTarget(), game); diff --git a/Mage.Sets/src/mage/sets/journeyintonyx/SightlessBrawler.java b/Mage.Sets/src/mage/sets/journeyintonyx/SightlessBrawler.java index c12742e364e..8ef66a7f064 100644 --- a/Mage.Sets/src/mage/sets/journeyintonyx/SightlessBrawler.java +++ b/Mage.Sets/src/mage/sets/journeyintonyx/SightlessBrawler.java @@ -32,12 +32,11 @@ import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.Effect; +import mage.abilities.effects.common.combat.CanAttackOnlyAloneEffect; import mage.abilities.effects.common.continuous.BoostEnchantedEffect; -import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect; import mage.abilities.keyword.BestowAbility; import mage.abilities.keyword.CantAttackAloneAbility; import mage.cards.CardImpl; -import mage.constants.AttachmentType; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.Rarity; @@ -61,16 +60,16 @@ public class SightlessBrawler extends CardImpl { // Bestow 4W (If you cast this card for its bestow cost, it's an Aura spell with enchant creature. It becomes a creature again if it's not attached to a creature.) this.addAbility(new BestowAbility(this, "{4}{W}")); // Sightless Brawler can't attack alone. - this.addAbility(CantAttackAloneAbility.getInstance()); + this.addAbility(new CantAttackAloneAbility()); // Enchanted creature gets +3/+2 and can't attack alone. - Effect effect = new BoostEnchantedEffect(3,2, Duration.WhileOnBattlefield); + Effect effect = new BoostEnchantedEffect(3, 2, Duration.WhileOnBattlefield); effect.setText("Enchanted creature gets +3/+2"); Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, effect); - effect = new GainAbilityAttachedEffect(CantAttackAloneAbility.getInstance(), AttachmentType.AURA, Duration.WhileOnBattlefield); + effect = new CanAttackOnlyAloneEffect(); effect.setText("and can't attack alone"); ability.addEffect(effect); - this.addAbility(ability); - + this.addAbility(ability); + } public SightlessBrawler(final SightlessBrawler card) { diff --git a/Mage.Sets/src/mage/sets/judgment/BurningWish.java b/Mage.Sets/src/mage/sets/judgment/BurningWish.java index 8036f321e15..b4a1b6de5a6 100644 --- a/Mage.Sets/src/mage/sets/judgment/BurningWish.java +++ b/Mage.Sets/src/mage/sets/judgment/BurningWish.java @@ -29,16 +29,15 @@ package mage.sets.judgment; import java.util.Set; import java.util.UUID; - -import mage.constants.CardType; -import mage.constants.Rarity; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.Cards; import mage.cards.CardsImpl; +import mage.constants.CardType; import mage.constants.Outcome; +import mage.constants.Rarity; import mage.constants.Zone; import mage.filter.FilterCard; import mage.filter.predicate.mageobject.CardTypePredicate; @@ -116,7 +115,7 @@ class BurningWishEffect extends OneShotEffect { filteredCards.add(card.getId()); } - TargetCard target = new TargetCard(Zone.PICK, filter); + TargetCard target = new TargetCard(Zone.OUTSIDE, filter); if (player.choose(Outcome.Benefit, filteredCards, target, game)) { Card card = player.getSideboard().get(target.getFirstTarget(), game); if (card != null) { diff --git a/Mage.Sets/src/mage/sets/judgment/CunningWish.java b/Mage.Sets/src/mage/sets/judgment/CunningWish.java index 3a334aab0da..2ded7e0fa2e 100644 --- a/Mage.Sets/src/mage/sets/judgment/CunningWish.java +++ b/Mage.Sets/src/mage/sets/judgment/CunningWish.java @@ -29,16 +29,15 @@ package mage.sets.judgment; import java.util.Set; import java.util.UUID; - -import mage.constants.CardType; -import mage.constants.Rarity; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.Cards; import mage.cards.CardsImpl; +import mage.constants.CardType; import mage.constants.Outcome; +import mage.constants.Rarity; import mage.constants.Zone; import mage.filter.FilterCard; import mage.filter.predicate.mageobject.CardTypePredicate; @@ -116,7 +115,7 @@ class CunningWishEffect extends OneShotEffect { filteredCards.add(card.getId()); } - TargetCard target = new TargetCard(Zone.PICK, filter); + TargetCard target = new TargetCard(Zone.OUTSIDE, filter); if (player.choose(Outcome.Benefit, filteredCards, target, game)) { Card card = player.getSideboard().get(target.getFirstTarget(), game); if (card != null) { diff --git a/Mage.Sets/src/mage/sets/judgment/FlashOfInsight.java b/Mage.Sets/src/mage/sets/judgment/FlashOfInsight.java index eda686cff99..e5d93bd9abc 100644 --- a/Mage.Sets/src/mage/sets/judgment/FlashOfInsight.java +++ b/Mage.Sets/src/mage/sets/judgment/FlashOfInsight.java @@ -118,12 +118,11 @@ class FlashOfInsightEffect extends OneShotEffect { Card card = player.getLibrary().removeFromTop(game); if (card != null) { cards.add(card); - game.setZone(card.getId(), Zone.PICK); } } player.lookAtCards(sourceObject.getName(), cards, game); - TargetCard target = new TargetCard(Zone.PICK, new FilterCard("card to put into your hand")); + TargetCard target = new TargetCard(Zone.LIBRARY, new FilterCard("card to put into your hand")); if (player.choose(Outcome.DrawCard, cards, target, game)) { Card card = cards.get(target.getFirstTarget(), game); if (card != null) { @@ -133,27 +132,7 @@ class FlashOfInsightEffect extends OneShotEffect { } } - target = new TargetCard(Zone.PICK, new FilterCard("card to put on the bottom of your library")); - if (cards.size() > 0) { - game.informPlayers(new StringBuilder(sourceObject.getName()).append(": ") - .append(player.getLogName()).append(" puts ") - .append(cards.size() == 1 ? "a":cards.size()) - .append(" card").append(cards.size() > 1 ? "s":"") - .append(" on the bottom of his or her library").toString()); - } - while (player.canRespond() && cards.size() > 1) { - player.choose(Outcome.Neutral, cards, target, game); - Card card = cards.get(target.getFirstTarget(), game); - if (card != null) { - cards.remove(card); - card.moveToZone(Zone.LIBRARY, source.getSourceId(), game, false); - } - target.clearChosen(); - } - if (cards.size() == 1) { - Card card = cards.get(cards.iterator().next(), game); - card.moveToZone(Zone.LIBRARY, source.getSourceId(), game, false); - } + player.putCardsOnBottomOfLibrary(cards, game, source, true); return true; } diff --git a/Mage.Sets/src/mage/sets/judgment/GoldenWish.java b/Mage.Sets/src/mage/sets/judgment/GoldenWish.java index 2b76472ddf7..0ff30edc173 100644 --- a/Mage.Sets/src/mage/sets/judgment/GoldenWish.java +++ b/Mage.Sets/src/mage/sets/judgment/GoldenWish.java @@ -29,16 +29,15 @@ package mage.sets.judgment; import java.util.Set; import java.util.UUID; - -import mage.constants.CardType; -import mage.constants.Rarity; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.Cards; import mage.cards.CardsImpl; +import mage.constants.CardType; import mage.constants.Outcome; +import mage.constants.Rarity; import mage.constants.Zone; import mage.filter.FilterCard; import mage.filter.predicate.Predicates; @@ -119,7 +118,7 @@ class GoldenWishEffect extends OneShotEffect { filteredCards.add(card.getId()); } - TargetCard target = new TargetCard(Zone.PICK, filter); + TargetCard target = new TargetCard(Zone.OUTSIDE, filter); if (player.choose(Outcome.Benefit, filteredCards, target, game)) { Card card = player.getSideboard().get(target.getFirstTarget(), game); if (card != null) { diff --git a/Mage.Sets/src/mage/sets/judgment/LivingWish.java b/Mage.Sets/src/mage/sets/judgment/LivingWish.java index 907c97c9655..8db132bc324 100644 --- a/Mage.Sets/src/mage/sets/judgment/LivingWish.java +++ b/Mage.Sets/src/mage/sets/judgment/LivingWish.java @@ -29,16 +29,15 @@ package mage.sets.judgment; import java.util.Set; import java.util.UUID; - -import mage.constants.CardType; -import mage.constants.Rarity; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.Cards; import mage.cards.CardsImpl; +import mage.constants.CardType; import mage.constants.Outcome; +import mage.constants.Rarity; import mage.constants.Zone; import mage.filter.FilterCard; import mage.filter.predicate.Predicates; @@ -119,7 +118,7 @@ class LivingWishEffect extends OneShotEffect { filteredCards.add(card.getId()); } - TargetCard target = new TargetCard(Zone.PICK, filter); + TargetCard target = new TargetCard(Zone.OUTSIDE, filter); if (player.choose(Outcome.Benefit, filteredCards, target, game)) { Card card = player.getSideboard().get(target.getFirstTarget(), game); if (card != null) { diff --git a/Mage.Sets/src/mage/sets/khansoftarkir/BitterRevelation.java b/Mage.Sets/src/mage/sets/khansoftarkir/BitterRevelation.java index ee3fad23826..ac9dd2ce9e2 100644 --- a/Mage.Sets/src/mage/sets/khansoftarkir/BitterRevelation.java +++ b/Mage.Sets/src/mage/sets/khansoftarkir/BitterRevelation.java @@ -101,7 +101,7 @@ class BitterRevelationEffect extends OneShotEffect { if (cards.size() > 0) { Cards cardsToHand = new CardsImpl(); player.lookAtCards("Bitter Revelation", cards, game); - TargetCard target = new TargetCard(Math.min(2, cards.size()), Zone.PICK, new FilterCard("two cards to put in your hand")); + TargetCard target = new TargetCard(Math.min(2, cards.size()), Zone.LIBRARY, new FilterCard("two cards to put in your hand")); if (player.choose(Outcome.DrawCard, cards, target, game)) { for (UUID targetId : target.getTargets()) { Card card = cards.get(targetId, game); diff --git a/Mage.Sets/src/mage/sets/limitedalpha/NaturalSelection.java b/Mage.Sets/src/mage/sets/limitedalpha/NaturalSelection.java index 659fd8c3e48..160c4130168 100644 --- a/Mage.Sets/src/mage/sets/limitedalpha/NaturalSelection.java +++ b/Mage.Sets/src/mage/sets/limitedalpha/NaturalSelection.java @@ -100,13 +100,12 @@ class NaturalSelectionEffect extends OneShotEffect { Card card = player.getLibrary().removeFromTop(game); if (card != null) { cards.add(card); - game.setZone(card.getId(), Zone.PICK); } } you.lookAtCards("Natural Selection", cards, game); - TargetCard target = new TargetCard(Zone.PICK, new FilterCard("card to put on the top of target player's library")); + TargetCard target = new TargetCard(Zone.LIBRARY, new FilterCard("card to put on the top of target player's library")); while (player.canRespond() && cards.size() > 1) { you.choose(Outcome.Neutral, cards, target, game); Card card = cards.get(target.getFirstTarget(), game); diff --git a/Mage.Sets/src/mage/sets/lorwyn/AmoeboidChangeling.java b/Mage.Sets/src/mage/sets/lorwyn/AmoeboidChangeling.java index 5141b2e47a0..6d29eed8e10 100644 --- a/Mage.Sets/src/mage/sets/lorwyn/AmoeboidChangeling.java +++ b/Mage.Sets/src/mage/sets/lorwyn/AmoeboidChangeling.java @@ -28,7 +28,6 @@ package mage.sets.lorwyn; import java.util.UUID; - import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; @@ -39,7 +38,9 @@ import mage.abilities.keyword.ChangelingAbility; import mage.cards.CardImpl; import mage.constants.CardType; import mage.constants.Duration; +import mage.constants.Layer; import mage.constants.Rarity; +import mage.constants.SubLayer; import mage.constants.Zone; import mage.target.common.TargetCreaturePermanent; @@ -58,17 +59,18 @@ public class AmoeboidChangeling extends CardImpl { // Changeling this.addAbility(ChangelingAbility.getInstance()); - + // {tap}: Target creature gains all creature types until end of turn. - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new GainAbilityTargetEffect(ChangelingAbility.getInstance(), Duration.EndOfTurn), new TapSourceCost()); + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, + new GainAbilityTargetEffect(ChangelingAbility.getInstance(), Duration.EndOfTurn, null, false, Layer.TypeChangingEffects_4, SubLayer.NA), new TapSourceCost()); ability.addTarget(new TargetCreaturePermanent()); - + this.addAbility(ability); - + // {tap}: Target creature loses all creature types until end of turn. ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new LoseAllCreatureTypesTargetEffect(Duration.EndOfTurn), new TapSourceCost()); ability.addTarget(new TargetCreaturePermanent()); - + this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/sets/lorwyn/WingsOfVelisVel.java b/Mage.Sets/src/mage/sets/lorwyn/WingsOfVelisVel.java index c6288c24a5d..ffe50cb4db3 100644 --- a/Mage.Sets/src/mage/sets/lorwyn/WingsOfVelisVel.java +++ b/Mage.Sets/src/mage/sets/lorwyn/WingsOfVelisVel.java @@ -36,7 +36,9 @@ import mage.abilities.keyword.FlyingAbility; import mage.cards.CardImpl; import mage.constants.CardType; import mage.constants.Duration; +import mage.constants.Layer; import mage.constants.Rarity; +import mage.constants.SubLayer; import mage.target.common.TargetCreaturePermanent; /** @@ -52,20 +54,20 @@ public class WingsOfVelisVel extends CardImpl { // Changeling this.addAbility(ChangelingAbility.getInstance()); - + // Target creature becomes 4/4, gains all creature types, and gains flying until end of turn. this.getSpellAbility().addTarget(new TargetCreaturePermanent()); Effect effect = new SetPowerToughnessTargetEffect(4, 4, Duration.EndOfTurn); effect.setText("Target creature becomes 4/4"); - this.getSpellAbility().addEffect(effect); - - effect = new GainAbilityTargetEffect(ChangelingAbility.getInstance(), Duration.EndOfTurn); + this.getSpellAbility().addEffect(effect); + + effect = new GainAbilityTargetEffect(ChangelingAbility.getInstance(), Duration.EndOfTurn, null, false, Layer.TypeChangingEffects_4, SubLayer.NA); effect.setText(", gains all creature types"); - this.getSpellAbility().addEffect(effect); + this.getSpellAbility().addEffect(effect); effect = new GainAbilityTargetEffect(FlyingAbility.getInstance(), Duration.EndOfTurn); effect.setText(", and gains flying until end of turn"); - this.getSpellAbility().addEffect(effect); + this.getSpellAbility().addEffect(effect); } public WingsOfVelisVel(final WingsOfVelisVel card) { diff --git a/Mage.Sets/src/mage/sets/magic2010/JackalFamiliar.java b/Mage.Sets/src/mage/sets/magic2010/JackalFamiliar.java index 3b37baf1bd1..67059c5f0fa 100644 --- a/Mage.Sets/src/mage/sets/magic2010/JackalFamiliar.java +++ b/Mage.Sets/src/mage/sets/magic2010/JackalFamiliar.java @@ -27,14 +27,13 @@ */ package mage.sets.magic2010; -import mage.constants.CardType; -import mage.constants.Rarity; +import java.util.UUID; import mage.MageInt; import mage.abilities.keyword.CantAttackAloneAbility; import mage.abilities.keyword.CantBlockAloneAbility; import mage.cards.CardImpl; - -import java.util.UUID; +import mage.constants.CardType; +import mage.constants.Rarity; /** * @author magenoxx_at_gmail.com @@ -50,7 +49,7 @@ public class JackalFamiliar extends CardImpl { this.toughness = new MageInt(2); // Jackal Familiar can't attack or block alone. - this.addAbility(CantAttackAloneAbility.getInstance()); + this.addAbility(new CantAttackAloneAbility()); this.addAbility(CantBlockAloneAbility.getInstance()); } diff --git a/Mage.Sets/src/mage/sets/magic2010/MirrorOfFate.java b/Mage.Sets/src/mage/sets/magic2010/MirrorOfFate.java index 2452f5850b2..66e1f8a8890 100644 --- a/Mage.Sets/src/mage/sets/magic2010/MirrorOfFate.java +++ b/Mage.Sets/src/mage/sets/magic2010/MirrorOfFate.java @@ -28,10 +28,6 @@ package mage.sets.magic2010; import java.util.UUID; -import mage.constants.CardType; -import mage.constants.Outcome; -import mage.constants.Rarity; -import mage.constants.Zone; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.SacrificeSourceCost; @@ -40,6 +36,10 @@ import mage.abilities.effects.OneShotEffect; import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardsImpl; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.constants.Zone; import mage.filter.FilterCard; import mage.filter.predicate.Predicate; import mage.game.ExileZone; @@ -113,7 +113,7 @@ class MirrorOfFateEffect extends OneShotEffect { card.moveToExile(null, null, source.getSourceId(), game); } - TargetCard target = new TargetCard(Zone.PICK, new FilterCard("card to put on top of your library")); + TargetCard target = new TargetCard(Zone.EXILED, new FilterCard("card to put on top of your library")); while (player.canRespond() && cards.size() > 1) { player.choose(Outcome.Neutral, cards, target, game); Card card = cards.get(target.getFirstTarget(), game); diff --git a/Mage.Sets/src/mage/sets/magic2010/Polymorph.java b/Mage.Sets/src/mage/sets/magic2010/Polymorph.java index 504714b1a9c..e3347137348 100644 --- a/Mage.Sets/src/mage/sets/magic2010/Polymorph.java +++ b/Mage.Sets/src/mage/sets/magic2010/Polymorph.java @@ -29,10 +29,6 @@ package mage.sets.magic2010; import java.util.Set; import java.util.UUID; -import mage.constants.CardType; -import mage.constants.Outcome; -import mage.constants.Rarity; -import mage.constants.Zone; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.DestroyTargetEffect; @@ -40,6 +36,10 @@ import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.Cards; import mage.cards.CardsImpl; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.constants.Zone; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Library; @@ -112,7 +112,7 @@ class PolymorphEffect extends OneShotEffect { } if (card.getCardType().contains(CardType.CREATURE)) { - card.putOntoBattlefield(game, Zone.PICK, source.getSourceId(), player.getId()); + card.putOntoBattlefield(game, Zone.LIBRARY, source.getSourceId(), player.getId()); } if (cards.size() > 0) { diff --git a/Mage.Sets/src/mage/sets/magic2012/Monomania.java b/Mage.Sets/src/mage/sets/magic2012/Monomania.java index 3af809a1c33..b4f936b023b 100644 --- a/Mage.Sets/src/mage/sets/magic2012/Monomania.java +++ b/Mage.Sets/src/mage/sets/magic2012/Monomania.java @@ -27,13 +27,14 @@ */ package mage.sets.magic2012; -import mage.constants.CardType; -import mage.constants.Rarity; +import java.util.UUID; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; import mage.cards.Card; import mage.cards.CardImpl; +import mage.constants.CardType; import mage.constants.Outcome; +import mage.constants.Rarity; import mage.constants.Zone; import mage.filter.FilterCard; import mage.game.Game; @@ -41,8 +42,6 @@ import mage.players.Player; import mage.target.TargetCard; import mage.target.TargetPlayer; -import java.util.UUID; - /** * * @author nantuko @@ -86,7 +85,7 @@ class MonomaniaEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player player = game.getPlayer(source.getFirstTarget()); if (player != null) { - TargetCard target = new TargetCard(Zone.PICK, filter); + TargetCard target = new TargetCard(Zone.HAND, filter); if (player.choose(Outcome.Detriment, player.getHand(), target, game)) { while (player.getHand().size() > 1) { for (UUID uuid : player.getHand()) { diff --git a/Mage.Sets/src/mage/sets/magic2012/SphinxOfUthuun.java b/Mage.Sets/src/mage/sets/magic2012/SphinxOfUthuun.java index 6537fddc3b9..237af470bb3 100644 --- a/Mage.Sets/src/mage/sets/magic2012/SphinxOfUthuun.java +++ b/Mage.Sets/src/mage/sets/magic2012/SphinxOfUthuun.java @@ -108,7 +108,6 @@ class SphinxOfUthuunEffect extends OneShotEffect { Card card = player.getLibrary().removeFromTop(game); if (card != null) { cards.add(card); - game.setZone(card.getId(), Zone.PICK); } } player.revealCards(sourceObject.getName(), cards, game); @@ -117,7 +116,7 @@ class SphinxOfUthuunEffect extends OneShotEffect { if (!opponents.isEmpty()) { Player opponent = game.getPlayer(opponents.iterator().next()); - TargetCard target = new TargetCard(0, cards.size(), Zone.PICK, new FilterCard("cards to put in the first pile")); + TargetCard target = new TargetCard(0, cards.size(), Zone.LIBRARY, new FilterCard("cards to put in the first pile")); target.setRequired(false); List pile1 = new ArrayList<>(); Cards pile1CardsIds = new CardsImpl(); diff --git a/Mage.Sets/src/mage/sets/magic2013/MoggFlunkies.java b/Mage.Sets/src/mage/sets/magic2013/MoggFlunkies.java index 79bd8785521..8f101217fc4 100644 --- a/Mage.Sets/src/mage/sets/magic2013/MoggFlunkies.java +++ b/Mage.Sets/src/mage/sets/magic2013/MoggFlunkies.java @@ -27,14 +27,13 @@ */ package mage.sets.magic2013; -import mage.constants.CardType; -import mage.constants.Rarity; +import java.util.UUID; import mage.MageInt; import mage.abilities.keyword.CantAttackAloneAbility; import mage.abilities.keyword.CantBlockAloneAbility; import mage.cards.CardImpl; - -import java.util.UUID; +import mage.constants.CardType; +import mage.constants.Rarity; /** * @author magenoxx_at_gmail.com @@ -50,7 +49,7 @@ public class MoggFlunkies extends CardImpl { this.toughness = new MageInt(3); // Mogg Flunkies can't attack or block alone. - this.addAbility(CantAttackAloneAbility.getInstance()); + this.addAbility(new CantAttackAloneAbility()); this.addAbility(CantBlockAloneAbility.getInstance()); } diff --git a/Mage.Sets/src/mage/sets/magic2014/GlimpseTheFuture.java b/Mage.Sets/src/mage/sets/magic2014/GlimpseTheFuture.java index a51c086bc3c..7148c510bf0 100644 --- a/Mage.Sets/src/mage/sets/magic2014/GlimpseTheFuture.java +++ b/Mage.Sets/src/mage/sets/magic2014/GlimpseTheFuture.java @@ -95,14 +95,13 @@ class GlimpseTheFutureEffect extends OneShotEffect { Card card = controller.getLibrary().removeFromTop(game); if (card != null) { cards.add(card); - game.setZone(card.getId(), Zone.PICK); } } if (cards.size() > 0) { controller.lookAtCards("Glimpse the Future", cards, game); - TargetCard target = new TargetCard(Zone.PICK, new FilterCard("card to put in your hand")); + TargetCard target = new TargetCard(Zone.LIBRARY, new FilterCard("card to put in your hand")); if (controller.choose(Outcome.Benefit, cards, target, game)) { Card card = cards.get(target.getFirstTarget(), game); if (card != null) { diff --git a/Mage.Sets/src/mage/sets/magicorigins/BondedConstruct.java b/Mage.Sets/src/mage/sets/magicorigins/BondedConstruct.java index 5f464c632ae..95f00778a4d 100644 --- a/Mage.Sets/src/mage/sets/magicorigins/BondedConstruct.java +++ b/Mage.Sets/src/mage/sets/magicorigins/BondedConstruct.java @@ -48,7 +48,7 @@ public class BondedConstruct extends CardImpl { this.toughness = new MageInt(1); // Bonded Construct can't attack alone. - this.addAbility(CantAttackAloneAbility.getInstance()); + this.addAbility(new CantAttackAloneAbility()); } public BondedConstruct(final BondedConstruct card) { diff --git a/Mage.Sets/src/mage/sets/masterseditionii/Errantry.java b/Mage.Sets/src/mage/sets/masterseditionii/Errantry.java index b9214d5aa2a..2685f464a89 100644 --- a/Mage.Sets/src/mage/sets/masterseditionii/Errantry.java +++ b/Mage.Sets/src/mage/sets/masterseditionii/Errantry.java @@ -32,12 +32,10 @@ import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.Effect; import mage.abilities.effects.common.AttachEffect; +import mage.abilities.effects.common.combat.CanAttackOnlyAloneEffect; import mage.abilities.effects.common.continuous.BoostEnchantedEffect; -import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect; -import mage.abilities.keyword.CanAttackOnlyAloneAbility; import mage.abilities.keyword.EnchantAbility; import mage.cards.CardImpl; -import mage.constants.AttachmentType; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.Outcome; @@ -49,7 +47,7 @@ import mage.target.common.TargetCreaturePermanent; /** * * @author LoneFox - + * */ public class Errantry extends CardImpl { @@ -66,8 +64,8 @@ public class Errantry extends CardImpl { this.addAbility(ability); // Enchanted creature gets +3/+0 and can only attack alone. ability = new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostEnchantedEffect(3, 0, Duration.WhileOnBattlefield)); - Effect effect = new GainAbilityAttachedEffect(CanAttackOnlyAloneAbility.getInstance(), AttachmentType.AURA); - effect.setText("and can only attack alone."); + Effect effect = new CanAttackOnlyAloneEffect(); + effect.setText("and can only attack alone"); ability.addEffect(effect); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/sets/mirage/PainfulMemories.java b/Mage.Sets/src/mage/sets/mirage/PainfulMemories.java index 590ff980988..2b4bc26a633 100644 --- a/Mage.Sets/src/mage/sets/mirage/PainfulMemories.java +++ b/Mage.Sets/src/mage/sets/mirage/PainfulMemories.java @@ -92,7 +92,7 @@ class PainfulMemoriesEffect extends OneShotEffect { targetPlayer.revealCards("Painful Memories", targetPlayer.getHand(), game); if (targetPlayer.getHand().size() > 0) { - TargetCard target = new TargetCard(Zone.PICK, new FilterCard()); + TargetCard target = new TargetCard(Zone.HAND, new FilterCard()); if (you.choose(Outcome.Benefit, targetPlayer.getHand(), target, game)) { Card card = targetPlayer.getHand().get(target.getFirstTarget(), game); if (card != null) { diff --git a/Mage.Sets/src/mage/sets/mirrodinbesieged/MitoticManipulation.java b/Mage.Sets/src/mage/sets/mirrodinbesieged/MitoticManipulation.java index 9c2a6e67099..b903d4199ae 100644 --- a/Mage.Sets/src/mage/sets/mirrodinbesieged/MitoticManipulation.java +++ b/Mage.Sets/src/mage/sets/mirrodinbesieged/MitoticManipulation.java @@ -109,7 +109,6 @@ class MitoticManipulationEffect extends OneShotEffect { Card card = player.getLibrary().removeFromTop(game); if (card != null) { cards.add(card); - game.setZone(card.getId(), Zone.PICK); if (permanentNames.contains(card.getName())) { cardsFound.add(card); } @@ -118,7 +117,7 @@ class MitoticManipulationEffect extends OneShotEffect { player.lookAtCards("Mitotic Manipulation", cards, game); if (!cardsFound.isEmpty() && player.chooseUse(Outcome.PutCardInPlay, "Do you wish to put a card on the battlefield?", source, game)) { - TargetCard target = new TargetCard(Zone.PICK, filter); + TargetCard target = new TargetCard(Zone.LIBRARY, filter); if (player.choose(Outcome.PutCardInPlay, cardsFound, target, game)) { Card card = cards.get(target.getFirstTarget(), game); @@ -128,22 +127,7 @@ class MitoticManipulationEffect extends OneShotEffect { } } } - - TargetCard target = new TargetCard(Zone.PICK, new FilterCard("card to put on the bottom of your library")); - while (player.canRespond() && cards.size() > 1) { - player.choose(Outcome.Neutral, cards, target, game); - Card card = cards.get(target.getFirstTarget(), game); - if (card != null) { - cards.remove(card); - card.moveToZone(Zone.LIBRARY, source.getSourceId(), game, false); - } - target.clearChosen(); - } - if (cards.size() == 1) { - Card card = cards.get(cards.iterator().next(), game); - card.moveToZone(Zone.LIBRARY, source.getSourceId(), game, false); - } - + player.putCardsOnBottomOfLibrary(cards, game, source, true); return true; } } diff --git a/Mage.Sets/src/mage/sets/modernmasters/ThievingSprite.java b/Mage.Sets/src/mage/sets/modernmasters/ThievingSprite.java index 1d6cdd19721..d67cc288672 100644 --- a/Mage.Sets/src/mage/sets/modernmasters/ThievingSprite.java +++ b/Mage.Sets/src/mage/sets/modernmasters/ThievingSprite.java @@ -118,7 +118,7 @@ class ThievingSpriteEffect extends OneShotEffect { Cards cardsInHand = new CardsImpl(); cardsInHand.addAll(targetPlayer.getHand()); - TargetCard target = new TargetCard(numberOfFaeries, Zone.PICK, new FilterCard()); + TargetCard target = new TargetCard(numberOfFaeries, Zone.HAND, new FilterCard()); if (targetPlayer.choose(Outcome.Discard, cardsInHand, target, game)) { List targets = target.getTargets(); @@ -133,7 +133,7 @@ class ThievingSpriteEffect extends OneShotEffect { revealedCards.addAll(targetPlayer.getHand()); } - TargetCard targetInHand = new TargetCard(Zone.PICK, new FilterCard("card to discard")); + TargetCard targetInHand = new TargetCard(Zone.HAND, new FilterCard("card to discard")); if (!revealedCards.isEmpty()) { targetPlayer.revealCards("Thieving Sprite", revealedCards, game); diff --git a/Mage.Sets/src/mage/sets/newphyrexia/EntomberExarch.java b/Mage.Sets/src/mage/sets/newphyrexia/EntomberExarch.java index 147f62f486d..50bfaeca161 100644 --- a/Mage.Sets/src/mage/sets/newphyrexia/EntomberExarch.java +++ b/Mage.Sets/src/mage/sets/newphyrexia/EntomberExarch.java @@ -28,9 +28,6 @@ package mage.sets.newphyrexia; import java.util.UUID; - -import mage.constants.CardType; -import mage.constants.Rarity; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.Mode; @@ -39,7 +36,9 @@ import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.ReturnToHandTargetEffect; import mage.cards.Card; import mage.cards.CardImpl; +import mage.constants.CardType; import mage.constants.Outcome; +import mage.constants.Rarity; import mage.constants.Zone; import mage.filter.FilterCard; import mage.filter.common.FilterCreatureCard; @@ -108,7 +107,7 @@ class EntomberExarchEffect extends OneShotEffect { player.revealCards("Entomber Exarch", player.getHand(), game); Player you = game.getPlayer(source.getControllerId()); if (you != null) { - TargetCard target = new TargetCard(Zone.PICK, filter); + TargetCard target = new TargetCard(Zone.HAND, filter); if (you.choose(Outcome.Benefit, player.getHand(), target, game)) { Card card = player.getHand().get(target.getFirstTarget(), game); if (card != null) { diff --git a/Mage.Sets/src/mage/sets/newphyrexia/PsychicSurgery.java b/Mage.Sets/src/mage/sets/newphyrexia/PsychicSurgery.java index 960184d8448..ba3ed78b01d 100644 --- a/Mage.Sets/src/mage/sets/newphyrexia/PsychicSurgery.java +++ b/Mage.Sets/src/mage/sets/newphyrexia/PsychicSurgery.java @@ -139,7 +139,7 @@ class PsychicSurgeryEffect extends OneShotEffect { player.lookAtCards("Psychic Surgery", cards, game); if (!cards.isEmpty() && player.chooseUse(Outcome.Exile, "Do you wish to exile a card?", source, game)) { - TargetCard target = new TargetCard(Zone.PICK, new FilterCard("card to exile")); + TargetCard target = new TargetCard(Zone.LIBRARY, new FilterCard("card to exile")); if (player.choose(Outcome.Exile, cards, target, game)) { Card card = cards.get(target.getFirstTarget(), game); if (card != null) { @@ -148,22 +148,7 @@ class PsychicSurgeryEffect extends OneShotEffect { } } } - - TargetCard target = new TargetCard(Zone.PICK, new FilterCard("card to put on top of his library")); - while (player.canRespond() && cards.size() > 1) { - player.choose(Outcome.Neutral, cards, target, game); - Card card = cards.get(target.getFirstTarget(), game); - if (card != null) { - cards.remove(card); - card.moveToZone(Zone.LIBRARY, source.getSourceId(), game, true); - } - target.clearChosen(); - } - if (cards.size() == 1) { - Card card = cards.get(cards.iterator().next(), game); - card.moveToZone(Zone.LIBRARY, source.getSourceId(), game, true); - } - + player.putCardsOnBottomOfLibrary(cards, game, source, true); return true; } return false; diff --git a/Mage.Sets/src/mage/sets/newphyrexia/ShrineOfPiercingVision.java b/Mage.Sets/src/mage/sets/newphyrexia/ShrineOfPiercingVision.java index 8086c1af2f3..830b69cb6e7 100644 --- a/Mage.Sets/src/mage/sets/newphyrexia/ShrineOfPiercingVision.java +++ b/Mage.Sets/src/mage/sets/newphyrexia/ShrineOfPiercingVision.java @@ -122,13 +122,12 @@ class ShrineOfPiercingVisionEffect extends OneShotEffect { Card card = player.getLibrary().removeFromTop(game); if (card != null) { cards.add(card); - game.setZone(card.getId(), Zone.PICK); } } player.lookAtCards("Shrine of Piercing Vision", cards, game); if (!cards.isEmpty()) { - TargetCard target = new TargetCard(Zone.PICK, new FilterCard("card to put into your hand")); + TargetCard target = new TargetCard(Zone.LIBRARY, new FilterCard("card to put into your hand")); if (player.choose(Outcome.DrawCard, cards, target, game)) { Card card = cards.get(target.getFirstTarget(), game); @@ -138,22 +137,7 @@ class ShrineOfPiercingVisionEffect extends OneShotEffect { } } } - - TargetCard target = new TargetCard(Zone.PICK, new FilterCard("card to put on the bottom of your library")); - while (player.canRespond() && cards.size() > 1) { - player.choose(Outcome.Neutral, cards, target, game); - Card card = cards.get(target.getFirstTarget(), game); - if (card != null) { - cards.remove(card); - card.moveToZone(Zone.LIBRARY, source.getSourceId(), game, false); - } - target.clearChosen(); - } - if (cards.size() == 1) { - Card card = cards.get(cards.iterator().next(), game); - card.moveToZone(Zone.LIBRARY, source.getSourceId(), game, false); - } - + player.putCardsOnBottomOfLibrary(cards, game, source, true); return true; } } diff --git a/Mage.Sets/src/mage/sets/odyssey/BalshanBeguiler.java b/Mage.Sets/src/mage/sets/odyssey/BalshanBeguiler.java index 77c3aa7de3a..f1fa6de190e 100644 --- a/Mage.Sets/src/mage/sets/odyssey/BalshanBeguiler.java +++ b/Mage.Sets/src/mage/sets/odyssey/BalshanBeguiler.java @@ -97,7 +97,7 @@ class BalshanBeguilerEffect extends OneShotEffect { cards.addAll(player.getLibrary().getTopCards(game, 2)); Player you = game.getPlayer(source.getControllerId()); if (you != null) { - TargetCard target = new TargetCard(Zone.PICK, new FilterCard()); + TargetCard target = new TargetCard(Zone.LIBRARY, new FilterCard()); if (you.choose(Outcome.Benefit, cards, target, game)) { Card card = player.getLibrary().getCard(target.getFirstTarget(), game); card.moveToZone(Zone.BATTLEFIELD, source.getSourceId(), game, true); diff --git a/Mage.Sets/src/mage/sets/planechase2012/SilentBladeOni.java b/Mage.Sets/src/mage/sets/planechase2012/SilentBladeOni.java index 6295725eea2..7a91c35bc01 100644 --- a/Mage.Sets/src/mage/sets/planechase2012/SilentBladeOni.java +++ b/Mage.Sets/src/mage/sets/planechase2012/SilentBladeOni.java @@ -103,7 +103,7 @@ class SilentBladeOniEffect extends OneShotEffect { Cards cardsInHand = new CardsImpl(); cardsInHand.addAll(opponent.getHand()); if (cardsInHand.size() > 0) { - TargetCard target = new TargetCard(1, Zone.PICK, new FilterNonlandCard()); + TargetCard target = new TargetCard(1, Zone.HAND, new FilterNonlandCard()); if (controller.chooseTarget(outcome, cardsInHand, target, source, game)) { Card card = game.getCard(target.getFirstTarget()); if (card != null) { diff --git a/Mage.Sets/src/mage/sets/ravnica/CongregationAtDawn.java b/Mage.Sets/src/mage/sets/ravnica/CongregationAtDawn.java index 6ca8d911a6d..555db0e6051 100644 --- a/Mage.Sets/src/mage/sets/ravnica/CongregationAtDawn.java +++ b/Mage.Sets/src/mage/sets/ravnica/CongregationAtDawn.java @@ -105,7 +105,7 @@ class CongregationAtDawnEffect extends OneShotEffect { controller.revealCards(sourceObject.getName(), revealed, game); controller.shuffleLibrary(game); - TargetCard targetToLib = new TargetCard(Zone.PICK, new FilterCard(textTop)); + TargetCard targetToLib = new TargetCard(Zone.LIBRARY, new FilterCard(textTop)); while (revealed.size() > 1 && controller.canRespond()) { controller.choose(Outcome.Neutral, revealed, targetToLib, game); diff --git a/Mage.Sets/src/mage/sets/ravnica/MindleechMass.java b/Mage.Sets/src/mage/sets/ravnica/MindleechMass.java index 81db0ad98dc..3d83c832caa 100644 --- a/Mage.Sets/src/mage/sets/ravnica/MindleechMass.java +++ b/Mage.Sets/src/mage/sets/ravnica/MindleechMass.java @@ -103,7 +103,7 @@ class MindleechMassEffect extends OneShotEffect { opponent.revealCards("Opponents hand", cardsInHand, game); if (cardsInHand.size() > 0 && cardsInHand.getCards(new FilterNonlandCard(), game).size() > 0) { - TargetCard target = new TargetCard(1, Zone.PICK, new FilterNonlandCard()); + TargetCard target = new TargetCard(1, Zone.HAND, new FilterNonlandCard()); if (you.chooseTarget(Outcome.PlayForFree, cardsInHand, target, source, game)) { Card card = game.getCard(target.getFirstTarget()); if (card != null) { diff --git a/Mage.Sets/src/mage/sets/ravnica/Mindmoil.java b/Mage.Sets/src/mage/sets/ravnica/Mindmoil.java index f0669f79591..60133863812 100644 --- a/Mage.Sets/src/mage/sets/ravnica/Mindmoil.java +++ b/Mage.Sets/src/mage/sets/ravnica/Mindmoil.java @@ -28,22 +28,15 @@ package mage.sets.ravnica; import java.util.UUID; - -import mage.constants.CardType; -import mage.constants.Rarity; import mage.abilities.Ability; import mage.abilities.common.SpellCastControllerTriggeredAbility; import mage.abilities.effects.OneShotEffect; -import mage.cards.Card; import mage.cards.CardImpl; -import mage.cards.Cards; -import mage.cards.CardsImpl; +import mage.constants.CardType; import mage.constants.Outcome; -import mage.constants.Zone; -import mage.filter.FilterCard; +import mage.constants.Rarity; import mage.game.Game; import mage.players.Player; -import mage.target.TargetCard; /** * @@ -86,25 +79,7 @@ class MindmoilEffect extends OneShotEffect { Player you = game.getPlayer(source.getControllerId()); if (you != null) { int count = you.getHand().size(); - Cards cards = new CardsImpl(); - for (Card card : you.getHand().getCards(game)) { - cards.add(card.getId()); - } - TargetCard target = new TargetCard(Zone.PICK, new FilterCard("card to put on the bottom of your library")); - while (you.canRespond() && cards.size() > 1) { - you.choose(Outcome.Neutral, cards, target, game); - Card card = cards.get(target.getFirstTarget(), game); - if (card != null) { - cards.remove(card); - card.moveToZone(Zone.LIBRARY, source.getSourceId(), game, false); - } - target.clearChosen(); - } - if (cards.size() == 1) { - Card card = cards.get(cards.iterator().next(), game); - card.moveToZone(Zone.LIBRARY, source.getSourceId(), game, false); - } - you.getHand().clear(); + you.putCardsOnBottomOfLibrary(you.getHand(), game, source, true); you.drawCards(count, game); } return true; diff --git a/Mage.Sets/src/mage/sets/returntoravnica/JaceArchitectOfThought.java b/Mage.Sets/src/mage/sets/returntoravnica/JaceArchitectOfThought.java index 7d00e7d53ab..4d3c0b2fa75 100644 --- a/Mage.Sets/src/mage/sets/returntoravnica/JaceArchitectOfThought.java +++ b/Mage.Sets/src/mage/sets/returntoravnica/JaceArchitectOfThought.java @@ -199,7 +199,6 @@ class JaceArchitectOfThoughtEffect2 extends OneShotEffect { Card card = player.getLibrary().removeFromTop(game); if (card != null) { cards.add(card); - game.setZone(card.getId(), Zone.PICK); } } player.revealCards("Jace, Architect of Thought", cards, game); @@ -217,7 +216,7 @@ class JaceArchitectOfThoughtEffect2 extends OneShotEffect { opponent = game.getPlayer(opponents.iterator().next()); } - TargetCard target = new TargetCard(0, cards.size(), Zone.PICK, new FilterCard("cards to put in the first pile")); + TargetCard target = new TargetCard(0, cards.size(), Zone.LIBRARY, new FilterCard("cards to put in the first pile")); target.setRequired(false); Cards pile1 = new CardsImpl(); if (opponent.choose(Outcome.Neutral, cards, target, game)) { @@ -260,20 +259,7 @@ class JaceArchitectOfThoughtEffect2 extends OneShotEffect { } } - TargetCard targetCard = new TargetCard(Zone.PICK, new FilterCard("card to put on the bottom of your library")); - while (player.canRespond() && cardsToLibrary.size() > 1) { - player.choose(Outcome.Neutral, cardsToLibrary, targetCard, game); - Card card = cardsToLibrary.get(targetCard.getFirstTarget(), game); - if (card != null) { - cardsToLibrary.remove(card); - player.moveCardToLibraryWithInfo(card, source.getSourceId(), game, Zone.LIBRARY, false, false); - } - target.clearChosen(); - } - if (cardsToLibrary.size() == 1) { - Card card = cardsToLibrary.get(cardsToLibrary.iterator().next(), game); - player.moveCardToLibraryWithInfo(card, source.getSourceId(), game, Zone.LIBRARY, false, false); - } + player.putCardsOnBottomOfLibrary(cardsToLibrary, game, source, true); return true; } return false; diff --git a/Mage.Sets/src/mage/sets/returntoravnica/JaradsOrders.java b/Mage.Sets/src/mage/sets/returntoravnica/JaradsOrders.java index adc5aa137cd..89e8c945006 100644 --- a/Mage.Sets/src/mage/sets/returntoravnica/JaradsOrders.java +++ b/Mage.Sets/src/mage/sets/returntoravnica/JaradsOrders.java @@ -29,16 +29,15 @@ package mage.sets.returntoravnica; import java.util.List; import java.util.UUID; - -import mage.constants.CardType; -import mage.constants.Rarity; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.Cards; import mage.cards.CardsImpl; +import mage.constants.CardType; import mage.constants.Outcome; +import mage.constants.Rarity; import mage.constants.Zone; import mage.filter.FilterCard; import mage.filter.common.FilterCreatureCard; @@ -102,7 +101,7 @@ class JaradsOrdersEffect extends OneShotEffect { } controller.revealCards("Jarad's Orders", revealed, game); if (target.getTargets().size() == 2) { - TargetCard target2 = new TargetCard(Zone.PICK, filter); + TargetCard target2 = new TargetCard(Zone.LIBRARY, filter); controller.choose(Outcome.Benefit, revealed, target2, game); Card card = revealed.get(target2.getFirstTarget(), game); controller.moveCards(card, Zone.LIBRARY, Zone.HAND, source, game); diff --git a/Mage.Sets/src/mage/sets/riseoftheeldrazi/PerishTheThought.java b/Mage.Sets/src/mage/sets/riseoftheeldrazi/PerishTheThought.java index 90f0368c91a..998441b36f9 100644 --- a/Mage.Sets/src/mage/sets/riseoftheeldrazi/PerishTheThought.java +++ b/Mage.Sets/src/mage/sets/riseoftheeldrazi/PerishTheThought.java @@ -28,14 +28,13 @@ package mage.sets.riseoftheeldrazi; import java.util.UUID; - -import mage.constants.CardType; -import mage.constants.Rarity; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; import mage.cards.Card; import mage.cards.CardImpl; +import mage.constants.CardType; import mage.constants.Outcome; +import mage.constants.Rarity; import mage.constants.Zone; import mage.filter.FilterCard; import mage.game.Game; @@ -95,7 +94,7 @@ class PerishTheThoughtEffect extends OneShotEffect { targetOpponent.revealCards("Perish the Thought", targetOpponent.getHand(), game); Player you = game.getPlayer(source.getControllerId()); if (you != null) { - TargetCard target = new TargetCard(Zone.PICK, filter); + TargetCard target = new TargetCard(Zone.HAND, filter); target.setNotTarget(true); if (you.choose(Outcome.Neutral, targetOpponent.getHand(), target, game)) { Card chosenCard = targetOpponent.getHand().get(target.getFirstTarget(), game); diff --git a/Mage.Sets/src/mage/sets/saviorsofkamigawa/AshesOfTheFallen.java b/Mage.Sets/src/mage/sets/saviorsofkamigawa/AshesOfTheFallen.java new file mode 100644 index 00000000000..682765f4a5f --- /dev/null +++ b/Mage.Sets/src/mage/sets/saviorsofkamigawa/AshesOfTheFallen.java @@ -0,0 +1,109 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.saviorsofkamigawa; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.AsEntersBattlefieldAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.ContinuousEffectImpl; +import mage.abilities.effects.common.ChooseCreatureTypeEffect; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Layer; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.constants.SubLayer; +import mage.constants.Zone; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; + +/** + * + * @author emerald000 + */ +public class AshesOfTheFallen extends CardImpl { + + public AshesOfTheFallen(UUID ownerId) { + super(ownerId, 152, "Ashes of the Fallen", Rarity.RARE, new CardType[]{CardType.ARTIFACT}, "{2}"); + this.expansionSetCode = "SOK"; + + // As Ashes of the Fallen enters the battlefield, choose a creature type. + this.addAbility(new AsEntersBattlefieldAbility(new ChooseCreatureTypeEffect(Outcome.Benefit))); + + // Each creature card in your graveyard has the chosen creature type in addition to its other types. + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new AshesOfTheFallenEffect())); + } + + public AshesOfTheFallen(final AshesOfTheFallen card) { + super(card); + } + + @Override + public AshesOfTheFallen copy() { + return new AshesOfTheFallen(this); + } +} + +class AshesOfTheFallenEffect extends ContinuousEffectImpl { + + AshesOfTheFallenEffect() { + super(Duration.WhileOnBattlefield, Layer.TypeChangingEffects_4, SubLayer.NA, Outcome.Benefit); + staticText = "Each creature card in your graveyard has the chosen creature type in addition to its other types"; + } + + AshesOfTheFallenEffect(final AshesOfTheFallenEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + Permanent permanent = game.getPermanent(source.getSourceId()); + if (controller != null && permanent != null) { + String subtype = (String) game.getState().getValue(permanent.getId() + "_type"); + for (UUID cardId : controller.getGraveyard()) { + Card card = game.getCard(cardId); + if (card != null && card.getCardType().contains(CardType.CREATURE) && !card.getSubtype().contains(subtype)) { + card.getSubtype().add(subtype); + } + } + return true; + } + return false; + } + + @Override + public AshesOfTheFallenEffect copy() { + return new AshesOfTheFallenEffect(this); + } +} + diff --git a/Mage.Sets/src/mage/sets/scarsofmirrodin/CloneShell.java b/Mage.Sets/src/mage/sets/scarsofmirrodin/CloneShell.java index 6fb58914f1b..84665e99f4b 100644 --- a/Mage.Sets/src/mage/sets/scarsofmirrodin/CloneShell.java +++ b/Mage.Sets/src/mage/sets/scarsofmirrodin/CloneShell.java @@ -100,14 +100,13 @@ class CloneShellEffect extends OneShotEffect { for (int i = 0; i < count; i++) { Card card = player.getLibrary().removeFromTop(game); cards.add(card); - game.setZone(card.getId(), Zone.PICK); } if (cards.size() == 0) { return false; } - TargetCard target1 = new TargetCard(Zone.PICK, filter1); + TargetCard target1 = new TargetCard(Zone.LIBRARY, filter1); if (player.choose(Outcome.Detriment, cards, target1, game)) { Card card = cards.get(target1.getFirstTarget(), game); if (card != null) { @@ -123,7 +122,7 @@ class CloneShellEffect extends OneShotEffect { } if (cards.size() > 0) { - TargetCard target2 = new TargetCard(Zone.PICK, filter2); + TargetCard target2 = new TargetCard(Zone.LIBRARY, filter2); while (player.canRespond() && cards.size() > 1) { player.choose(Outcome.Benefit, cards, target2, game); Card card = cards.get(target2.getFirstTarget(), game); diff --git a/Mage.Sets/src/mage/sets/seventhedition/AgonizingMemories.java b/Mage.Sets/src/mage/sets/seventhedition/AgonizingMemories.java index b41be8998c3..aacf0ef4c18 100644 --- a/Mage.Sets/src/mage/sets/seventhedition/AgonizingMemories.java +++ b/Mage.Sets/src/mage/sets/seventhedition/AgonizingMemories.java @@ -28,7 +28,6 @@ package mage.sets.seventhedition; import java.util.UUID; -import mage.MageObject; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; import mage.cards.Card; @@ -99,7 +98,7 @@ class AgonizingMemoriesEffect extends OneShotEffect { private void chooseCardInHandAndPutOnTopOfLibrary(Game game, Ability source, Player you, Player targetPlayer) { if (targetPlayer.getHand().size() > 0) { - TargetCard target = new TargetCard(Zone.PICK, new FilterCard("card to put on the top of library (last chosen will be on top)")); + TargetCard target = new TargetCard(Zone.HAND, new FilterCard("card to put on the top of library (last chosen will be on top)")); if (you.choose(Outcome.Benefit, targetPlayer.getHand(), target, game)) { Card card = targetPlayer.getHand().get(target.getFirstTarget(), game); if (card != null) { diff --git a/Mage.Sets/src/mage/sets/seventhedition/AncestralMemories.java b/Mage.Sets/src/mage/sets/seventhedition/AncestralMemories.java index 96263a28f54..32b515cc39f 100644 --- a/Mage.Sets/src/mage/sets/seventhedition/AncestralMemories.java +++ b/Mage.Sets/src/mage/sets/seventhedition/AncestralMemories.java @@ -96,14 +96,13 @@ class AncestralMemoriesEffect extends OneShotEffect { Card card = player.getLibrary().removeFromTop(game); if (card != null) { cards.add(card); - game.setZone(card.getId(), Zone.PICK); } } if (cards.size() > 0) { player.lookAtCards("Ancestral Memories", cards, game); - TargetCard target = new TargetCard(Math.min(2, cards.size()), Zone.PICK, new FilterCard("two cards to put in your hand")); + TargetCard target = new TargetCard(Math.min(2, cards.size()), Zone.LIBRARY, new FilterCard("two cards to put in your hand")); if (player.choose(Outcome.Benefit, cards, target, game)) { for (UUID targetId : (List)target.getTargets()) { Card card = cards.get(targetId, game); diff --git a/Mage.Sets/src/mage/sets/shadowmoor/RiversGrasp.java b/Mage.Sets/src/mage/sets/shadowmoor/RiversGrasp.java index 5d6cc24269c..d266a182b81 100644 --- a/Mage.Sets/src/mage/sets/shadowmoor/RiversGrasp.java +++ b/Mage.Sets/src/mage/sets/shadowmoor/RiversGrasp.java @@ -118,7 +118,7 @@ class RiversGraspEffect extends OneShotEffect { player.revealCards("River's Grasp", player.getHand(), game); Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { - TargetCard target = new TargetCard(Zone.PICK, filter); + TargetCard target = new TargetCard(Zone.HAND, filter); if (controller.choose(Outcome.Benefit, player.getHand(), target, game)) { Card card = player.getHand().get(target.getFirstTarget(), game); if (card != null) { diff --git a/Mage.Sets/src/mage/sets/shadowmoor/SplittingHeadache.java b/Mage.Sets/src/mage/sets/shadowmoor/SplittingHeadache.java index 6aaa0734757..313afbd80da 100644 --- a/Mage.Sets/src/mage/sets/shadowmoor/SplittingHeadache.java +++ b/Mage.Sets/src/mage/sets/shadowmoor/SplittingHeadache.java @@ -98,7 +98,7 @@ class SplittingHeadacheEffect extends OneShotEffect { player.revealCards("Splitting Headache", player.getHand(), game); Player you = game.getPlayer(source.getControllerId()); if (you != null) { - TargetCard target = new TargetCard(Zone.PICK, new FilterCard()); + TargetCard target = new TargetCard(Zone.HAND, new FilterCard()); if (you.choose(Outcome.Benefit, player.getHand(), target, game)) { Card card = player.getHand().get(target.getFirstTarget(), game); if (card != null) { diff --git a/Mage.Sets/src/mage/sets/shardsofalara/GiftOfTheGargantuan.java b/Mage.Sets/src/mage/sets/shardsofalara/GiftOfTheGargantuan.java index 6eb8c586f8f..d3c0799f02f 100644 --- a/Mage.Sets/src/mage/sets/shardsofalara/GiftOfTheGargantuan.java +++ b/Mage.Sets/src/mage/sets/shardsofalara/GiftOfTheGargantuan.java @@ -38,7 +38,6 @@ import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.Rarity; import mage.constants.Zone; -import mage.filter.FilterCard; import mage.filter.common.FilterCreatureCard; import mage.filter.common.FilterLandCard; import mage.game.Game; @@ -101,7 +100,6 @@ class GiftOfTheGargantuanEffect extends OneShotEffect { Card card = player.getLibrary().removeFromTop(game); if (card != null) { cards.add(card); - game.setZone(card.getId(), Zone.PICK); if (card.getCardType().contains(CardType.CREATURE)) { creatureCardFound = true; } @@ -115,7 +113,7 @@ class GiftOfTheGargantuanEffect extends OneShotEffect { if ((creatureCardFound || landCardFound) && player.chooseUse(Outcome.DrawCard, "Do you wish to reveal a creature card and/or a land card and put them into your hand?", source, game)) { Cards revealedCards = new CardsImpl(); - TargetCard target = new TargetCard(Zone.PICK, new FilterCreatureCard("creature card to reveal and put into your hand")); + TargetCard target = new TargetCard(Zone.LIBRARY, new FilterCreatureCard("creature card to reveal and put into your hand")); if (creatureCardFound && player.choose(Outcome.DrawCard, cards, target, game)) { Card card = cards.get(target.getFirstTarget(), game); if (card != null) { @@ -125,7 +123,7 @@ class GiftOfTheGargantuanEffect extends OneShotEffect { } } - target = new TargetCard(Zone.PICK, new FilterLandCard("land card to reveal and put into your hand")); + target = new TargetCard(Zone.LIBRARY, new FilterLandCard("land card to reveal and put into your hand")); if (landCardFound && player.choose(Outcome.DrawCard, cards, target, game)) { Card card = cards.get(target.getFirstTarget(), game); if (card != null) { @@ -139,22 +137,7 @@ class GiftOfTheGargantuanEffect extends OneShotEffect { player.revealCards("Gift of the Gargantuan", revealedCards, game); } } - - TargetCard target = new TargetCard(Zone.PICK, new FilterCard("card to put on the bottom of your library")); - while (player.canRespond() && cards.size() > 1) { - player.choose(Outcome.Neutral, cards, target, game); - Card card = cards.get(target.getFirstTarget(), game); - if (card != null) { - cards.remove(card); - card.moveToZone(Zone.LIBRARY, source.getSourceId(), game, false); - } - target.clearChosen(); - } - if (cards.size() == 1) { - Card card = cards.get(cards.iterator().next(), game); - card.moveToZone(Zone.LIBRARY, source.getSourceId(), game, false); - } - + player.putCardsOnBottomOfLibrary(cards, game, source, true); return true; } } diff --git a/Mage.Sets/src/mage/sets/stronghold/HibernationSliver.java b/Mage.Sets/src/mage/sets/stronghold/HibernationSliver.java index 9421f6bcb79..11faedca0d4 100644 --- a/Mage.Sets/src/mage/sets/stronghold/HibernationSliver.java +++ b/Mage.Sets/src/mage/sets/stronghold/HibernationSliver.java @@ -61,7 +61,9 @@ public class HibernationSliver extends CardImpl { Effect effect = new ReturnToHandSourceEffect(true); effect.setText("Return this permanent to its owner's hand"); Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, effect, new PayLifeCost(2)); - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityAllEffect(ability, Duration.WhileOnBattlefield, new FilterPermanent("Sliver", "All Slivers"), "All Slivers have \"Pay 2 life: Return this permanent to its owner's hand"))); + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, + new GainAbilityAllEffect(ability, Duration.WhileOnBattlefield, + new FilterPermanent("Sliver", "All Slivers"), "All Slivers have \"Pay 2 life: Return this permanent to its owner's hand"))); } public HibernationSliver(final HibernationSliver card) { diff --git a/Mage.Sets/src/mage/sets/tempest/Intuition.java b/Mage.Sets/src/mage/sets/tempest/Intuition.java index b53b71eddcb..37c24daa36a 100644 --- a/Mage.Sets/src/mage/sets/tempest/Intuition.java +++ b/Mage.Sets/src/mage/sets/tempest/Intuition.java @@ -29,16 +29,15 @@ package mage.sets.tempest; import java.util.List; import java.util.UUID; - -import mage.constants.CardType; -import mage.constants.Outcome; -import mage.constants.Rarity; import mage.abilities.Ability; import mage.abilities.effects.SearchEffect; import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.Cards; import mage.cards.CardsImpl; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Rarity; import mage.constants.Zone; import mage.filter.FilterCard; import mage.game.Game; @@ -111,7 +110,7 @@ class IntuitionEffect extends SearchEffect { } controller.revealCards("Reveal", cards, game); - TargetCard targetCard = new TargetCard(Zone.PICK, new FilterCard()); + TargetCard targetCard = new TargetCard(Zone.LIBRARY, new FilterCard()); while(!opponent.choose(Outcome.Neutral, cards, targetCard, game)) { if (!opponent.canRespond()) { diff --git a/Mage.Sets/src/mage/sets/tenthedition/TellingTime.java b/Mage.Sets/src/mage/sets/tenthedition/TellingTime.java index 7b143838c03..74923b800d5 100644 --- a/Mage.Sets/src/mage/sets/tenthedition/TellingTime.java +++ b/Mage.Sets/src/mage/sets/tenthedition/TellingTime.java @@ -28,17 +28,16 @@ package mage.sets.tenthedition; import java.util.UUID; - -import mage.constants.CardType; -import mage.constants.Outcome; -import mage.constants.Rarity; -import mage.constants.Zone; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.Cards; import mage.cards.CardsImpl; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.constants.Zone; import mage.filter.FilterCard; import mage.game.Game; import mage.players.Library; @@ -130,7 +129,7 @@ class TellingTimeEffect extends OneShotEffect { return cards.getRandom(null); } - TargetCard target = new TargetCard(Zone.PICK, new FilterCard(message)); + TargetCard target = new TargetCard(Zone.LIBRARY, new FilterCard(message)); if (player.choose(Outcome.Benefit, cards, target, game)) { Card card = cards.get(target.getFirstTarget(), game); if (card != null) { diff --git a/Mage.Sets/src/mage/sets/tenthedition/ThrullSurgeon.java b/Mage.Sets/src/mage/sets/tenthedition/ThrullSurgeon.java index 0b1707279eb..5c789be767c 100644 --- a/Mage.Sets/src/mage/sets/tenthedition/ThrullSurgeon.java +++ b/Mage.Sets/src/mage/sets/tenthedition/ThrullSurgeon.java @@ -28,9 +28,6 @@ package mage.sets.tenthedition; import java.util.UUID; - -import mage.constants.CardType; -import mage.constants.Rarity; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.ActivateAsSorceryActivatedAbility; @@ -39,7 +36,9 @@ import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.OneShotEffect; import mage.cards.Card; import mage.cards.CardImpl; +import mage.constants.CardType; import mage.constants.Outcome; +import mage.constants.Rarity; import mage.constants.Zone; import mage.filter.FilterCard; import mage.game.Game; @@ -96,7 +95,7 @@ class ThrullSurgeonEffect extends OneShotEffect { Player you = game.getPlayer(source.getControllerId()); if (targetPlayer != null && you != null) { you.lookAtCards("Discard", targetPlayer.getHand(), game); - TargetCard target = new TargetCard(Zone.PICK, new FilterCard()); + TargetCard target = new TargetCard(Zone.HAND, new FilterCard()); target.setNotTarget(true); if (you.choose(Outcome.Benefit, targetPlayer.getHand(), target, game)) { Card card = targetPlayer.getHand().get(target.getFirstTarget(), game); diff --git a/Mage.Sets/src/mage/sets/theros/DiscipleOfPhenax.java b/Mage.Sets/src/mage/sets/theros/DiscipleOfPhenax.java index a3d7b7a62ac..d7bac0bba90 100644 --- a/Mage.Sets/src/mage/sets/theros/DiscipleOfPhenax.java +++ b/Mage.Sets/src/mage/sets/theros/DiscipleOfPhenax.java @@ -128,7 +128,7 @@ class DiscipleOfPhenaxEffect extends OneShotEffect { targetPlayer.revealCards("Disciple of Phenax", revealedCards, game); Player you = game.getPlayer(source.getControllerId()); if (you != null) { - TargetCard yourChoice = new TargetCard(Zone.PICK, new FilterCard()); + TargetCard yourChoice = new TargetCard(Zone.HAND, new FilterCard()); yourChoice.setNotTarget(true); if (you.choose(Outcome.Benefit, revealedCards, yourChoice, game)) { Card card = targetPlayer.getHand().get(yourChoice.getFirstTarget(), game); diff --git a/Mage.Sets/src/mage/sets/theros/SteamAugury.java b/Mage.Sets/src/mage/sets/theros/SteamAugury.java index f73f15876f0..6e3cf2f9958 100644 --- a/Mage.Sets/src/mage/sets/theros/SteamAugury.java +++ b/Mage.Sets/src/mage/sets/theros/SteamAugury.java @@ -115,7 +115,7 @@ class SteamAuguryEffect extends OneShotEffect { } if (opponent != null) { - TargetCard target = new TargetCard(0, cards.size(), Zone.PICK, new FilterCard("cards to put in the first pile")); + TargetCard target = new TargetCard(0, cards.size(), Zone.LIBRARY, new FilterCard("cards to put in the first pile")); List pile1 = new ArrayList<>(); Cards pile1CardsIds = new CardsImpl(); target.setRequired(false); diff --git a/Mage.Sets/src/mage/sets/urzaslegacy/HarmonicConvergence.java b/Mage.Sets/src/mage/sets/urzaslegacy/HarmonicConvergence.java index fde1f0a2527..a5c5225868a 100644 --- a/Mage.Sets/src/mage/sets/urzaslegacy/HarmonicConvergence.java +++ b/Mage.Sets/src/mage/sets/urzaslegacy/HarmonicConvergence.java @@ -104,7 +104,7 @@ class HarmonicConvergenceEffect extends OneShotEffect { list.add(permanent); } - TargetCard target = new TargetCard(Zone.PICK, new FilterCard("card to put on top of your library")); + TargetCard target = new TargetCard(Zone.BATTLEFIELD, new FilterCard("card to put on top of your library")); for (UUID playerId : moveList.keySet()) { Player player = game.getPlayer(playerId); List list = moveList.get(playerId); diff --git a/Mage.Sets/src/mage/sets/urzaslegacy/RavenFamiliar.java b/Mage.Sets/src/mage/sets/urzaslegacy/RavenFamiliar.java index 881a72a1225..ef0d1e56950 100644 --- a/Mage.Sets/src/mage/sets/urzaslegacy/RavenFamiliar.java +++ b/Mage.Sets/src/mage/sets/urzaslegacy/RavenFamiliar.java @@ -108,12 +108,11 @@ public class RavenFamiliar extends CardImpl { Card card = player.getLibrary().removeFromTop(game); if (card != null) { cards.add(card); - game.setZone(card.getId(), Zone.PICK); } } player.lookAtCards("Raven Familiar", cards, game); - TargetCard target = new TargetCard(Zone.PICK, new FilterCard("card to put into your hand")); + TargetCard target = new TargetCard(Zone.LIBRARY, new FilterCard("card to put into your hand")); if (player.choose(Outcome.DrawCard, cards, target, game)) { Card card = cards.get(target.getFirstTarget(), game); if (card != null) { @@ -121,22 +120,7 @@ public class RavenFamiliar extends CardImpl { card.moveToZone(Zone.HAND, source.getSourceId(), game, false); } } - - target = new TargetCard(Zone.PICK, new FilterCard("card to put on the bottom of your library")); - while (player.canRespond() && cards.size() > 1) { - player.choose(Outcome.Neutral, cards, target, game); - Card card = cards.get(target.getFirstTarget(), game); - if (card != null) { - cards.remove(card); - card.moveToZone(Zone.LIBRARY, source.getSourceId(), game, false); - } - target.clearChosen(); - } - if (cards.size() == 1) { - Card card = cards.get(cards.iterator().next(), game); - card.moveToZone(Zone.LIBRARY, source.getSourceId(), game, false); - } - + player.putCardsOnBottomOfLibrary(cards, game, source, true); return true; } } diff --git a/Mage.Sets/src/mage/sets/vintagemasters/KrovikanSorcerer.java b/Mage.Sets/src/mage/sets/vintagemasters/KrovikanSorcerer.java index 6d966566194..d7f14c367b1 100644 --- a/Mage.Sets/src/mage/sets/vintagemasters/KrovikanSorcerer.java +++ b/Mage.Sets/src/mage/sets/vintagemasters/KrovikanSorcerer.java @@ -123,7 +123,7 @@ class KrovikanSorcererEffect extends OneShotEffect { } } if (drawnCards.size() > 0) { - TargetCard cardToDiscard = new TargetCard(Zone.PICK, new FilterCard("card to discard")); + TargetCard cardToDiscard = new TargetCard(Zone.HAND, new FilterCard("card to discard")); cardToDiscard.setNotTarget(true); if (player.choose(Outcome.Discard, drawnCards, cardToDiscard, game)) { Card card = player.getHand().get(cardToDiscard.getFirstTarget(), game); diff --git a/Mage.Sets/src/mage/sets/weatherlight/Doomsday.java b/Mage.Sets/src/mage/sets/weatherlight/Doomsday.java index a48fff82ecd..f8fa1c6e467 100644 --- a/Mage.Sets/src/mage/sets/weatherlight/Doomsday.java +++ b/Mage.Sets/src/mage/sets/weatherlight/Doomsday.java @@ -96,7 +96,7 @@ class DoomsdayEffect extends OneShotEffect { allCards.addAll(player.getLibrary().getCardList()); allCards.addAll(player.getGraveyard()); int number = Math.min(5, allCards.size()); - TargetCard target = new TargetCard(number, number, Zone.PICK, new FilterCard()); + TargetCard target = new TargetCard(number, number, Zone.ALL, new FilterCard()); if (player.choose(Outcome.Benefit, allCards, target, game)){ // exile the rest @@ -113,7 +113,7 @@ class DoomsdayEffect extends OneShotEffect { } //Put the chosen cards on top of your library in any order - target = new TargetCard(Zone.PICK, new FilterCard("Card to put on top")); + target = new TargetCard(Zone.ALL, new FilterCard("Card to put on top")); while (cards.size() > 1 && player.canRespond()) { player.choose(Outcome.Neutral, cards, target, game); Card card = cards.get(target.getFirstTarget(), game); diff --git a/Mage.Sets/src/mage/sets/zendikar/BalaGedThief.java b/Mage.Sets/src/mage/sets/zendikar/BalaGedThief.java index c66289a522e..48274dfa013 100644 --- a/Mage.Sets/src/mage/sets/zendikar/BalaGedThief.java +++ b/Mage.Sets/src/mage/sets/zendikar/BalaGedThief.java @@ -117,7 +117,7 @@ class BalaGedThiefEffect extends OneShotEffect { int count = Math.min(cardsInHand.size(), numberOfAllies); - TargetCard target = new TargetCard(count, Zone.PICK, new FilterCard()); + TargetCard target = new TargetCard(count, Zone.HAND, new FilterCard()); Cards revealedCards = new CardsImpl(); if (targetPlayer.choose(Outcome.DrawCard, cardsInHand, target, game)) { @@ -130,7 +130,7 @@ class BalaGedThiefEffect extends OneShotEffect { } } - TargetCard targetInHand = new TargetCard(Zone.PICK, new FilterCard("card to discard")); + TargetCard targetInHand = new TargetCard(Zone.HAND, new FilterCard("card to discard")); if (!revealedCards.isEmpty()) { targetPlayer.revealCards("Bala Ged Thief", revealedCards, game); diff --git a/Mage.Sets/src/mage/sets/zendikar/MerfolkWayfinder.java b/Mage.Sets/src/mage/sets/zendikar/MerfolkWayfinder.java index 04461008f7e..f87bd296ac1 100644 --- a/Mage.Sets/src/mage/sets/zendikar/MerfolkWayfinder.java +++ b/Mage.Sets/src/mage/sets/zendikar/MerfolkWayfinder.java @@ -41,10 +41,8 @@ import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.Rarity; import mage.constants.Zone; -import mage.filter.FilterCard; import mage.game.Game; import mage.players.Player; -import mage.target.TargetCard; /** * @@ -109,27 +107,11 @@ class MerfolkWayfinderEffect extends OneShotEffect { card.moveToZone(Zone.HAND, source.getSourceId(), game, false); } else { cards.add(card); - game.setZone(card.getId(), Zone.PICK); } } } player.revealCards("Merfolk Wayfinder", cardsToReveal, game); - - TargetCard target = new TargetCard(Zone.PICK, new FilterCard("card to put on the bottom of your library")); - while (player.canRespond() && cards.size() > 1) { - player.choose(Outcome.Neutral, cards, target, game); - Card card = cards.get(target.getFirstTarget(), game); - if (card != null) { - cards.remove(card); - card.moveToZone(Zone.LIBRARY, source.getSourceId(), game, false); - } - target.clearChosen(); - } - if (cards.size() == 1) { - Card card = cards.get(cards.iterator().next(), game); - card.moveToZone(Zone.LIBRARY, source.getSourceId(), game, false); - } - + player.putCardsOnBottomOfLibrary(cards, game, source, true); return true; } } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/ChangelingTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/ChangelingTest.java index c2010548151..80ce765fa67 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/ChangelingTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/ChangelingTest.java @@ -27,8 +27,11 @@ */ package org.mage.test.cards.abilities.keywords; +import mage.abilities.Ability; import mage.constants.PhaseStep; import mage.constants.Zone; +import mage.game.permanent.Permanent; +import org.junit.Assert; import org.junit.Test; import org.mage.test.serverside.base.CardTestPlayerBase; @@ -36,18 +39,17 @@ import org.mage.test.serverside.base.CardTestPlayerBase; * * @author LevelX2 */ - public class ChangelingTest extends CardTestPlayerBase { /** - * Casting changelings with a Long-Forgotten Gohei in play reduces its casting cost by {1}. + * Casting changelings with a Long-Forgotten Gohei in play reduces its + * casting cost by {1}. */ - @Test public void testLongForgottenGohei() { addCard(Zone.BATTLEFIELD, playerA, "Forest", 1); addCard(Zone.HAND, playerA, "Woodland Changeling"); - + addCard(Zone.BATTLEFIELD, playerA, "Long-Forgotten Gohei"); castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Woodland Changeling"); @@ -58,6 +60,46 @@ public class ChangelingTest extends CardTestPlayerBase { assertPermanentCount(playerA, "Woodland Changeling", 0); // Casting cost of spell is not reduced so not on the battlefield assertHandCount(playerA, "Woodland Changeling", 1); - } + } -} \ No newline at end of file + /** + * Another bug, was playing Slivers again. I had a Amoeboid Changeling, a + * Hibernation Sliver and a Prophet of Kruphix. In response to a boardwipe, + * I tapped my Changeling, giving my Prophet Changeling. However, it didn't + * gain any Sliver abilities despite having all creature types, including + * Sliver, so I couldn't save it with my Hibernation Sliver. I clicked the + * Prophet and nothing happened at all. + */ + @Test + public void testGainingChangeling() { + addCard(Zone.BATTLEFIELD, playerA, "Forest", 2); + addCard(Zone.BATTLEFIELD, playerA, "Island", 3); + // Untap all creatures and lands you control during each other player's untap step. + // You may cast creature cards as though they had flash. + addCard(Zone.HAND, playerA, "Prophet of Kruphix");// {3}{G}{U} + // Changeling + // {T}: Target creature gains all creature types until end of turn. + // {T}: Target creature loses all creature types until end of turn. + addCard(Zone.BATTLEFIELD, playerA, "Amoeboid Changeling"); + // All Slivers have "Pay 2 life: Return this permanent to its owner's hand." + addCard(Zone.BATTLEFIELD, playerA, "Hibernation Sliver"); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Prophet of Kruphix"); + activateAbility(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "{T}: Target creature gains", "Prophet of Kruphix"); + + setStopAt(1, PhaseStep.END_TURN); + execute(); + + assertTapped("Amoeboid Changeling", true); + + Permanent prophet = getPermanent("Prophet of Kruphix", playerA); + boolean abilityFound = false; + for (Ability ability : prophet.getAbilities()) { + if (ability.getRule().startsWith("Pay 2 life")) { + abilityFound = true; + } + } + Assert.assertTrue("Prophet of Kruphix has to have the 'Pay 2 life: Return this permanent to its owner's hand.' ability, but has not.", abilityFound); + + } +} diff --git a/Mage.Tests/src/test/java/org/mage/test/combat/CantAttackOrBlockAloneTest.java b/Mage.Tests/src/test/java/org/mage/test/combat/CantAttackOrBlockAloneTest.java index a668c46beba..0a24dab7a21 100644 --- a/Mage.Tests/src/test/java/org/mage/test/combat/CantAttackOrBlockAloneTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/combat/CantAttackOrBlockAloneTest.java @@ -48,6 +48,23 @@ public class CantAttackOrBlockAloneTest extends CardTestPlayerBase { assertLife(playerA, 15); } + /** + * Try to attack with two Flunkies + */ + @Test + public void testCanAttackWithTwo() { + addCard(Zone.BATTLEFIELD, playerB, "Mogg Flunkies", 2); // 3/3 + + attack(2, playerB, "Mogg Flunkies"); + attack(2, playerB, "Mogg Flunkies"); + + setStopAt(2, PhaseStep.END_TURN); + execute(); + + assertLife(playerA, 14); + + } + /** * Try to block alone */ diff --git a/Mage/src/main/java/mage/abilities/effects/RestrictionEffect.java b/Mage/src/main/java/mage/abilities/effects/RestrictionEffect.java index 47f89ec6021..12bf04ef220 100644 --- a/Mage/src/main/java/mage/abilities/effects/RestrictionEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/RestrictionEffect.java @@ -69,6 +69,10 @@ public abstract class RestrictionEffect extends ContinuousEffectImpl { return true; } + public boolean canAttackCheckAfter(int numberOfAttackers, Ability source, Game game) { + return true; + } + public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game) { return true; } diff --git a/Mage/src/main/java/mage/abilities/effects/common/CastCardFromOutsideTheGameEffect.java b/Mage/src/main/java/mage/abilities/effects/common/CastCardFromOutsideTheGameEffect.java index 5dbef2a742b..c8e1052d3a5 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/CastCardFromOutsideTheGameEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/CastCardFromOutsideTheGameEffect.java @@ -27,6 +27,7 @@ */ package mage.abilities.effects.common; +import java.util.Set; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; import mage.cards.Card; @@ -39,8 +40,6 @@ import mage.game.Game; import mage.players.Player; import mage.target.TargetCard; -import java.util.Set; - /** * @author magenoxx_at_gmail.com */ @@ -48,7 +47,7 @@ public class CastCardFromOutsideTheGameEffect extends OneShotEffect { private static final String choiceText = "Cast a card from outside the game?"; - private FilterCard filterCard; + private final FilterCard filterCard; public CastCardFromOutsideTheGameEffect(FilterCard filter, String ruleText) { super(Outcome.Benefit); @@ -76,15 +75,17 @@ public class CastCardFromOutsideTheGameEffect extends OneShotEffect { while (player.chooseUse(Outcome.Benefit, choiceText, source, game)) { Cards cards = player.getSideboard(); if (cards.isEmpty()) { - if (!game.isSimulation()) + if (!game.isSimulation()) { game.informPlayer(player, "You have no cards outside the game."); + } return false; } Set filtered = cards.getCards(filterCard, source.getSourceId(), source.getControllerId(), game); if (filtered.isEmpty()) { - if (!game.isSimulation()) + if (!game.isSimulation()) { game.informPlayer(player, "You have no " + filterCard.getMessage() + " outside the game."); + } return false; } @@ -93,7 +94,7 @@ public class CastCardFromOutsideTheGameEffect extends OneShotEffect { filteredCards.add(card.getId()); } - TargetCard target = new TargetCard(Zone.PICK, filterCard); + TargetCard target = new TargetCard(Zone.OUTSIDE, filterCard); if (player.choose(Outcome.Benefit, filteredCards, target, game)) { Card card = player.getSideboard().get(target.getFirstTarget(), game); if (card != null) { diff --git a/Mage/src/main/java/mage/abilities/effects/common/combat/CanAttackOnlyAloneEffect.java b/Mage/src/main/java/mage/abilities/effects/common/combat/CanAttackOnlyAloneEffect.java new file mode 100644 index 00000000000..2df2b790ad6 --- /dev/null +++ b/Mage/src/main/java/mage/abilities/effects/common/combat/CanAttackOnlyAloneEffect.java @@ -0,0 +1,43 @@ +/* + * 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. + */ +package mage.abilities.effects.common.combat; + +import mage.abilities.Ability; +import mage.abilities.effects.RestrictionEffect; +import mage.constants.Duration; +import mage.game.Game; +import mage.game.permanent.Permanent; + +/** + * + * @author LevelX2 + */ +public class CanAttackOnlyAloneEffect extends RestrictionEffect { + + public CanAttackOnlyAloneEffect() { + super(Duration.WhileOnBattlefield); + staticText = "{this} can only attack alone"; + } + + public CanAttackOnlyAloneEffect(final CanAttackOnlyAloneEffect effect) { + super(effect); + } + + @Override + public CanAttackOnlyAloneEffect copy() { + return new CanAttackOnlyAloneEffect(this); + } + + @Override + public boolean canAttackCheckAfter(int numberOfAttackers, Ability source, Game game) { + return numberOfAttackers == 1; + } + + @Override + public boolean applies(Permanent permanent, Ability source, Game game) { + return source.getSourceId().equals(permanent.getId()); + } +} diff --git a/Mage/src/main/java/mage/abilities/effects/common/combat/CantAttackAloneEffect.java b/Mage/src/main/java/mage/abilities/effects/common/combat/CantAttackAloneEffect.java new file mode 100644 index 00000000000..6d8cd6d610b --- /dev/null +++ b/Mage/src/main/java/mage/abilities/effects/common/combat/CantAttackAloneEffect.java @@ -0,0 +1,43 @@ +/* + * 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. + */ +package mage.abilities.effects.common.combat; + +import mage.abilities.Ability; +import mage.abilities.effects.RestrictionEffect; +import mage.constants.Duration; +import mage.game.Game; +import mage.game.permanent.Permanent; + +/** + * + * @author LevelX2 + */ +public class CantAttackAloneEffect extends RestrictionEffect { + + public CantAttackAloneEffect() { + super(Duration.WhileOnBattlefield); + staticText = "{this} can't attack alone"; + } + + public CantAttackAloneEffect(final CantAttackAloneEffect effect) { + super(effect); + } + + @Override + public CantAttackAloneEffect copy() { + return new CantAttackAloneEffect(this); + } + + @Override + public boolean canAttackCheckAfter(int numberOfAttackers, Ability source, Game game) { + return numberOfAttackers > 1; + } + + @Override + public boolean applies(Permanent permanent, Ability source, Game game) { + return source.getSourceId().equals(permanent.getId()); + } +} diff --git a/Mage/src/main/java/mage/abilities/effects/common/continuous/GainAbilityTargetEffect.java b/Mage/src/main/java/mage/abilities/effects/common/continuous/GainAbilityTargetEffect.java index 8117823221a..2532cd38a5b 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/continuous/GainAbilityTargetEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/continuous/GainAbilityTargetEffect.java @@ -66,7 +66,11 @@ public class GainAbilityTargetEffect extends ContinuousEffectImpl { } public GainAbilityTargetEffect(Ability ability, Duration duration, String rule, boolean onCard) { - super(duration, Layer.AbilityAddingRemovingEffects_6, SubLayer.NA, + this(ability, duration, rule, onCard, Layer.AbilityAddingRemovingEffects_6, SubLayer.NA); + } + + public GainAbilityTargetEffect(Ability ability, Duration duration, String rule, boolean onCard, Layer layer, SubLayer subLayer) { + super(duration, layer, subLayer, ability.getEffects().size() > 0 ? ability.getEffects().get(0).getOutcome() : Outcome.AddAbility); this.ability = ability; staticText = rule; diff --git a/Mage/src/main/java/mage/abilities/effects/common/continuous/UntapAllDuringEachOtherPlayersUntapStepEffect.java b/Mage/src/main/java/mage/abilities/effects/common/continuous/UntapAllDuringEachOtherPlayersUntapStepEffect.java index 2513b9a9f5e..2fdb87193bf 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/continuous/UntapAllDuringEachOtherPlayersUntapStepEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/continuous/UntapAllDuringEachOtherPlayersUntapStepEffect.java @@ -70,7 +70,7 @@ public class UntapAllDuringEachOtherPlayersUntapStepEffect extends ContinuousEff applied = Boolean.FALSE; } if (!applied && layer.equals(Layer.RulesEffects)) { - if (!game.getActivePlayerId().equals(source.getControllerId()) && game.getStep().getType() == PhaseStep.UNTAP) { + if (!source.getControllerId().equals(game.getActivePlayerId()) && game.getStep().getType() == PhaseStep.UNTAP) { game.getState().setValue(source.getSourceId() + "applied", true); for (Permanent permanent : game.getBattlefield().getAllActivePermanents(filter, source.getControllerId(), game)) { boolean untap = true; diff --git a/Mage/src/main/java/mage/abilities/keyword/CanAttackOnlyAloneAbility.java b/Mage/src/main/java/mage/abilities/keyword/CanAttackOnlyAloneAbility.java index 55aa82e3905..f37cb247fed 100644 --- a/Mage/src/main/java/mage/abilities/keyword/CanAttackOnlyAloneAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/CanAttackOnlyAloneAbility.java @@ -1,65 +1,52 @@ /* -* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. -* -* Redistribution and use in source and binary forms, with or without modification, are -* permitted provided that the following conditions are met: -* -* 1. Redistributions of source code must retain the above copyright notice, this list of -* conditions and the following disclaimer. -* -* 2. Redistributions in binary form must reproduce the above copyright notice, this list -* of conditions and the following disclaimer in the documentation and/or other materials -* provided with the distribution. -* -* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED -* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND -* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR -* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF -* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -* -* The views and conclusions contained in the software and documentation are those of the -* authors and should not be interpreted as representing official policies, either expressed -* or implied, of BetaSteward_at_googlemail.com. -*/ - + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ package mage.abilities.keyword; -import java.io.ObjectStreamException; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.combat.CanAttackOnlyAloneEffect; import mage.constants.Zone; -import mage.abilities.MageSingleton; -import mage.abilities.StaticAbility; /** * @author LevelX2 */ -public class CanAttackOnlyAloneAbility extends StaticAbility implements MageSingleton { +public class CanAttackOnlyAloneAbility extends SimpleStaticAbility { - private static final CanAttackOnlyAloneAbility fINSTANCE = new CanAttackOnlyAloneAbility(); - - private Object readResolve() throws ObjectStreamException { - return fINSTANCE; + public CanAttackOnlyAloneAbility() { + super(Zone.BATTLEFIELD, new CanAttackOnlyAloneEffect()); } - public static CanAttackOnlyAloneAbility getInstance() { - return fINSTANCE; - } - - private CanAttackOnlyAloneAbility() { - super(Zone.BATTLEFIELD, null); - } - - @Override - public String getRule() { - return "{this} can only attack alone."; + private CanAttackOnlyAloneAbility(CanAttackOnlyAloneAbility ability) { + super(ability); } @Override public CanAttackOnlyAloneAbility copy() { - return fINSTANCE; + return new CanAttackOnlyAloneAbility(this); } } diff --git a/Mage/src/main/java/mage/abilities/keyword/CantAttackAloneAbility.java b/Mage/src/main/java/mage/abilities/keyword/CantAttackAloneAbility.java index a7b0d7ef72d..fecbd9dcdd6 100644 --- a/Mage/src/main/java/mage/abilities/keyword/CantAttackAloneAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/CantAttackAloneAbility.java @@ -1,66 +1,52 @@ /* -* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. -* -* Redistribution and use in source and binary forms, with or without modification, are -* permitted provided that the following conditions are met: -* -* 1. Redistributions of source code must retain the above copyright notice, this list of -* conditions and the following disclaimer. -* -* 2. Redistributions in binary form must reproduce the above copyright notice, this list -* of conditions and the following disclaimer in the documentation and/or other materials -* provided with the distribution. -* -* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED -* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND -* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR -* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF -* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -* -* The views and conclusions contained in the software and documentation are those of the -* authors and should not be interpreted as representing official policies, either expressed -* or implied, of BetaSteward_at_googlemail.com. -*/ - + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ package mage.abilities.keyword; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.combat.CantAttackAloneEffect; import mage.constants.Zone; -import mage.abilities.MageSingleton; -import mage.abilities.StaticAbility; - -import java.io.ObjectStreamException; /** * @author magenoxx_at_googlemail.com */ -public class CantAttackAloneAbility extends StaticAbility implements MageSingleton { +public class CantAttackAloneAbility extends SimpleStaticAbility { - private static final CantAttackAloneAbility fINSTANCE = new CantAttackAloneAbility(); - - private Object readResolve() throws ObjectStreamException { - return fINSTANCE; + public CantAttackAloneAbility() { + super(Zone.BATTLEFIELD, new CantAttackAloneEffect()); } - public static CantAttackAloneAbility getInstance() { - return fINSTANCE; - } - - private CantAttackAloneAbility() { - super(Zone.BATTLEFIELD, null); - } - - @Override - public String getRule() { - return "{this} can't attack alone."; + private CantAttackAloneAbility(CantAttackAloneAbility ability) { + super(ability); } @Override public CantAttackAloneAbility copy() { - return fINSTANCE; + return new CantAttackAloneAbility(this); } } diff --git a/Mage/src/main/java/mage/cards/CardImpl.java b/Mage/src/main/java/mage/cards/CardImpl.java index c57a99b9a5d..055b21c318c 100644 --- a/Mage/src/main/java/mage/cards/CardImpl.java +++ b/Mage/src/main/java/mage/cards/CardImpl.java @@ -546,8 +546,6 @@ public abstract class CardImpl extends MageObjectImpl implements Card { removed = true; } break; - - case PICK: // Pick should no longer be used case BATTLEFIELD: // for sacrificing permanents or putting to library removed = true; break; diff --git a/Mage/src/main/java/mage/cards/decks/DeckCardLists.java b/Mage/src/main/java/mage/cards/decks/DeckCardLists.java index cb752cfafb5..7079d8996bc 100644 --- a/Mage/src/main/java/mage/cards/decks/DeckCardLists.java +++ b/Mage/src/main/java/mage/cards/decks/DeckCardLists.java @@ -1,31 +1,30 @@ /* -* 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. -*/ - + * 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.decks; import java.io.Serializable; @@ -40,8 +39,8 @@ public class DeckCardLists implements Serializable { private String name; private String author; - private List cards = new ArrayList(); - private List sideboard = new ArrayList(); + private List cards = new ArrayList<>(); + private List sideboard = new ArrayList<>(); /** * @return the cards diff --git a/Mage/src/main/java/mage/constants/Zone.java b/Mage/src/main/java/mage/constants/Zone.java index b5318c939ac..8114afa9e7b 100644 --- a/Mage/src/main/java/mage/constants/Zone.java +++ b/Mage/src/main/java/mage/constants/Zone.java @@ -6,7 +6,7 @@ package mage.constants; */ public enum Zone { - HAND, GRAVEYARD, LIBRARY, BATTLEFIELD, STACK, EXILED, ALL, OUTSIDE, PICK, COMMAND; + HAND, GRAVEYARD, LIBRARY, BATTLEFIELD, STACK, EXILED, ALL, OUTSIDE, COMMAND; public boolean match(Zone zone) { return (this == zone || this == ALL || zone == ALL); diff --git a/Mage/src/main/java/mage/game/combat/Combat.java b/Mage/src/main/java/mage/game/combat/Combat.java index 7b041bdef57..aa6c20c20ff 100644 --- a/Mage/src/main/java/mage/game/combat/Combat.java +++ b/Mage/src/main/java/mage/game/combat/Combat.java @@ -36,11 +36,10 @@ import java.util.List; import java.util.Map; import java.util.Set; import java.util.UUID; +import mage.MageObject; import mage.abilities.Ability; import mage.abilities.effects.RequirementEffect; import mage.abilities.effects.RestrictionEffect; -import mage.abilities.keyword.CanAttackOnlyAloneAbility; -import mage.abilities.keyword.CantAttackAloneAbility; import mage.abilities.keyword.VigilanceAbility; import mage.constants.CardType; import mage.constants.Outcome; @@ -58,12 +57,15 @@ import mage.target.common.TargetDefender; import mage.util.CardUtil; import mage.util.Copyable; import mage.util.trace.TraceUtil; +import org.apache.log4j.Logger; /** * @author BetaSteward_at_googlemail.com */ public class Combat implements Serializable, Copyable { + private static final Logger logger = Logger.getLogger(Combat.class); + private static FilterPlaneswalkerPermanent filterPlaneswalker = new FilterPlaneswalkerPermanent(); private static FilterCreatureForCombatBlock filterBlockers = new FilterCreatureForCombatBlock(); // There are effects that let creatures assigns combat damage equal to its toughness rather than its power @@ -252,14 +254,18 @@ public class Combat implements Serializable, Copyable { Player player = game.getPlayer(attackerId); //20101001 - 508.1d game.getCombat().checkAttackRequirements(player, game); - if (!game.getPlayer(game.getActivePlayerId()).getAvailableAttackers(game).isEmpty()) { - player.selectAttackers(game, attackerId); - } - if (game.isPaused() || game.gameOver(null) || game.executingRollback()) { - return; - } - // because of possible undo during declare attackers it's neccassary to call here the methods with "game.getCombat()." to get the valid combat object!!! - game.getCombat().checkAttackRestrictions(player, game); + boolean firstTime = true; + do { + if (!firstTime || !game.getPlayer(game.getActivePlayerId()).getAvailableAttackers(game).isEmpty()) { + player.selectAttackers(game, attackerId); + } + firstTime = false; + if (game.isPaused() || game.gameOver(null) || game.executingRollback()) { + return; + } + // because of possible undo during declare attackers it's neccassary to call here the methods with "game.getCombat()." to get the current combat object!!! + // I don't like it too - it has to be redesigned + } while (!game.getCombat().checkAttackRestrictions(player, game)); game.getCombat().resumeSelectAttackers(game); } } @@ -337,50 +343,60 @@ public class Combat implements Serializable, Copyable { } } - protected void checkAttackRestrictions(Player player, Game game) { - int count = 0; - for (CombatGroup group : groups) { - count += group.getAttackers().size(); - } - - if (count > 1) { - List tobeRemoved = new ArrayList<>(); + /** + * + * @param player + * @param game + * @return true if the attack with that set of creatures and attacked + * players/planeswalkers is possible + */ + protected boolean checkAttackRestrictions(Player player, Game game) { + boolean check = true; + int numberOfChecks = 0; + UUID attackerToRemove = null; + Check: + while (check) { + check = false; + numberOfChecks++; + int numberAttackers = 0; for (CombatGroup group : groups) { - for (UUID attackingCreatureId : group.getAttackers()) { - Permanent attacker = game.getPermanent(attackingCreatureId); - if (count > 1 && attacker != null && attacker.getAbilities().containsKey(CanAttackOnlyAloneAbility.getInstance().getId())) { - if (!game.isSimulation()) { - game.informPlayers(attacker.getLogName() + " can only attack alone. Removing it from combat."); + numberAttackers += group.getAttackers().size(); + } + Player attackingPlayer = game.getPlayer(attackerId); + if (attackerToRemove != null) { + removeAttacker(attackerToRemove, game); + } + for (UUID attackingCreatureId : this.getAttackers()) { + Permanent attackingCreature = game.getPermanent(attackingCreatureId); + for (Map.Entry> entry : game.getContinuousEffects().getApplicableRestrictionEffects(attackingCreature, game).entrySet()) { + RestrictionEffect effect = entry.getKey(); + for (Ability ability : entry.getValue()) { + if (!effect.canAttackCheckAfter(numberAttackers, ability, game)) { + MageObject sourceObject = ability.getSourceObject(game); + if (attackingPlayer.isHuman()) { + game.informPlayer(attackingPlayer, attackingCreature.getIdName() + " can't attack this way (" + (sourceObject == null ? "null" : sourceObject.getIdName()) + ")"); + return false; + } else { + // remove attacking creatures for AI that are not allowed to attack + // can create possible not allowed attack scenarios, but not sure how to solve this + for (CombatGroup combatGroup : this.getGroups()) { + if (combatGroup.getAttackers().contains(attackingCreatureId)) { + attackerToRemove = attackingCreatureId; + } + } + check = true; // do the check again + if (numberOfChecks > 50) { + logger.error("Seems to be an AI declare attacker lock (reached 50 check iterations) " + (sourceObject == null ? "null" : sourceObject.getIdName())); + return true; // break the check + } + continue Check; + } } - tobeRemoved.add(attackingCreatureId); - count--; } } } - for (UUID attackingCreatureId : tobeRemoved) { - this.removeAttacker(attackingCreatureId, game); - } } - - if (count == 1) { - List tobeRemoved = new ArrayList<>(); - for (CombatGroup group : groups) { - for (UUID attackingCreatureId : group.getAttackers()) { - Permanent attacker = game.getPermanent(attackingCreatureId); - if (attacker != null && attacker.getAbilities().containsKey(CantAttackAloneAbility.getInstance().getId())) { - if (!game.isSimulation()) { - game.informPlayers(attacker.getLogName() + " can't attack alone. Removing it from combat."); - } - tobeRemoved.add(attackingCreatureId); - } - } - } - for (UUID attackingCreatureId : tobeRemoved) { - this.removeAttacker(attackingCreatureId, game); - } - - } - + return true; } public void selectBlockers(Game game) { diff --git a/Mage/src/main/java/mage/players/PlayerImpl.java b/Mage/src/main/java/mage/players/PlayerImpl.java index 1082a21b51a..28753d5a2ef 100644 --- a/Mage/src/main/java/mage/players/PlayerImpl.java +++ b/Mage/src/main/java/mage/players/PlayerImpl.java @@ -862,7 +862,7 @@ public abstract class PlayerImpl implements Player, Serializable { moveObjectToLibrary(objectId, source == null ? null : source.getSourceId(), game, false, false); } } else { - TargetCard target = new TargetCard(Zone.PICK, new FilterCard("card to put on the bottom of your library (last one chosen will be bottommost)")); + TargetCard target = new TargetCard(Zone.ALL, new FilterCard("card to put on the bottom of your library (last one chosen will be bottommost)")); target.setRequired(true); while (isInGame() && cards.size() > 1) { this.choose(Outcome.Neutral, cards, target, game); @@ -3344,11 +3344,7 @@ public abstract class PlayerImpl implements Player, Serializable { StringBuilder sb = new StringBuilder(this.getLogName()) .append(" puts ").append(withName ? card.getLogName() : "a card").append(" "); if (fromZone != null) { - if (fromZone.equals(Zone.PICK)) { - sb.append("a picked card "); - } else { - sb.append("from ").append(fromZone.toString().toLowerCase(Locale.ENGLISH)).append(" "); - } + sb.append("from ").append(fromZone.toString().toLowerCase(Locale.ENGLISH)).append(" "); } sb.append("to the ").append(toTop ? "top" : "bottom"); if (card.getOwnerId().equals(getId())) {