diff --git a/Mage.Client/src/main/java/mage/client/deck/generator/DeckGeneratorDialog.java b/Mage.Client/src/main/java/mage/client/deck/generator/DeckGeneratorDialog.java index d58a0942a22..189923c6c10 100644 --- a/Mage.Client/src/main/java/mage/client/deck/generator/DeckGeneratorDialog.java +++ b/Mage.Client/src/main/java/mage/client/deck/generator/DeckGeneratorDialog.java @@ -108,16 +108,16 @@ public class DeckGeneratorDialog { mainPanel.add(formatSetText, c); // Format/set dropdown with search button - JPanel setPanel = new JPanel(); + JPanel setPanel = new JPanel(); setPanel.setLayout(new javax.swing.BoxLayout(setPanel, javax.swing.BoxLayout.LINE_AXIS)); c.fill = GridBagConstraints.HORIZONTAL; c.gridx = 1; c.gridy = 1; c.ipadx = 30; c.insets = new Insets(5, 10, 0, 10); - c.weightx = 0.80; + c.weightx = 0.80; mainPanel.add(setPanel, c); - + cbSets = new JComboBox<>(ConstructedFormats.getTypes()); cbSets.setSelectedIndex(0); cbSets.setAlignmentX(0.0F); @@ -127,13 +127,14 @@ public class DeckGeneratorDialog { if (prefSet != null) { cbSets.setSelectedItem(prefSet); } - + JButton btn = new JButton(); btn.setIcon(new javax.swing.ImageIcon(getClass().getResource("/buttons/search_32.png"))); btn.setToolTipText(FastSearchUtil.DEFAULT_EXPANSION_TOOLTIP_MESSAGE); - btn.setAlignmentX(1.0F); - btn.setPreferredSize(new java.awt.Dimension(32, 32)); + btn.setAlignmentX(1.0F); + btn.setPreferredSize(new java.awt.Dimension(32, 32)); btn.addActionListener(new java.awt.event.ActionListener() { + @Override public void actionPerformed(java.awt.event.ActionEvent evt) { FastSearchUtil.showFastSearchForStringComboBox(cbSets, FastSearchUtil.DEFAULT_EXPANSION_SEARCH_MESSAGE); } diff --git a/Mage.Server.Plugins/Mage.Player.AI/src/main/java/mage/player/ai/ComputerPlayer.java b/Mage.Server.Plugins/Mage.Player.AI/src/main/java/mage/player/ai/ComputerPlayer.java index 3c435e85241..1c73c9e190d 100644 --- a/Mage.Server.Plugins/Mage.Player.AI/src/main/java/mage/player/ai/ComputerPlayer.java +++ b/Mage.Server.Plugins/Mage.Player.AI/src/main/java/mage/player/ai/ComputerPlayer.java @@ -1243,7 +1243,7 @@ public class ComputerPlayer extends PlayerImpl implements Player { protected boolean playManaHandling(Ability ability, ManaCost unpaid, Game game) { // log.info("paying for " + unpaid.getText()); - boolean spendAnyMana = game.getContinuousEffects().asThough(ability.getSourceId(), AsThoughEffectType.SPEND_OTHER_MANA, ability, ability.getControllerId(), game); + UUID spendAnyManaId = game.getContinuousEffects().asThough(ability.getSourceId(), AsThoughEffectType.SPEND_OTHER_MANA, ability, ability.getControllerId(), game); ManaCost cost; List producers; if (unpaid instanceof ManaCosts) { @@ -1285,7 +1285,7 @@ public class ComputerPlayer extends PlayerImpl implements Player { for (ActivatedManaAbilityImpl manaAbility : mageObject.getAbilities().getAvailableActivatedManaAbilities(Zone.BATTLEFIELD, game)) { if (cost instanceof ColoredManaCost) { for (Mana netMana : manaAbility.getNetMana(game)) { - if (cost.testPay(netMana) || spendAnyMana) { + if (cost.testPay(netMana) || spendAnyManaId != null) { if (activateAbility(manaAbility, game)) { return true; } @@ -1297,7 +1297,7 @@ public class ComputerPlayer extends PlayerImpl implements Player { for (ActivatedManaAbilityImpl manaAbility : mageObject.getAbilities().getAvailableActivatedManaAbilities(Zone.BATTLEFIELD, game)) { if (cost instanceof SnowManaCost) { for (Mana netMana : manaAbility.getNetMana(game)) { - if (cost.testPay(netMana) || spendAnyMana) { + if (cost.testPay(netMana) || spendAnyManaId != null) { if (activateAbility(manaAbility, game)) { return true; } @@ -1309,7 +1309,7 @@ public class ComputerPlayer extends PlayerImpl implements Player { for (ActivatedManaAbilityImpl manaAbility : mageObject.getAbilities().getAvailableActivatedManaAbilities(Zone.BATTLEFIELD, game)) { if (cost instanceof HybridManaCost) { for (Mana netMana : manaAbility.getNetMana(game)) { - if (cost.testPay(netMana) || spendAnyMana) { + if (cost.testPay(netMana) || spendAnyManaId != null) { if (activateAbility(manaAbility, game)) { return true; } @@ -1321,7 +1321,7 @@ public class ComputerPlayer extends PlayerImpl implements Player { for (ActivatedManaAbilityImpl manaAbility : mageObject.getAbilities().getAvailableActivatedManaAbilities(Zone.BATTLEFIELD, game)) { if (cost instanceof MonoHybridManaCost) { for (Mana netMana : manaAbility.getNetMana(game)) { - if (cost.testPay(netMana) || spendAnyMana) { + if (cost.testPay(netMana) || spendAnyManaId != null) { if (activateAbility(manaAbility, game)) { return true; } @@ -1333,7 +1333,7 @@ public class ComputerPlayer extends PlayerImpl implements Player { for (ActivatedManaAbilityImpl manaAbility : mageObject.getAbilities().getAvailableActivatedManaAbilities(Zone.BATTLEFIELD, game)) { if (cost instanceof ColorlessManaCost) { for (Mana netMana : manaAbility.getNetMana(game)) { - if (cost.testPay(netMana) || spendAnyMana) { + if (cost.testPay(netMana) || spendAnyManaId != null) { if (activateAbility(manaAbility, game)) { return true; } @@ -1345,7 +1345,7 @@ public class ComputerPlayer extends PlayerImpl implements Player { for (ActivatedManaAbilityImpl manaAbility : mageObject.getAbilities().getAvailableActivatedManaAbilities(Zone.BATTLEFIELD, game)) { if (cost instanceof GenericManaCost) { for (Mana netMana : manaAbility.getNetMana(game)) { - if (cost.testPay(netMana) || spendAnyMana) { + if (cost.testPay(netMana) || spendAnyManaId != null) { if (activateAbility(manaAbility, game)) { return true; } @@ -1356,7 +1356,7 @@ public class ComputerPlayer extends PlayerImpl implements Player { } // pay phyrexian life costs if (cost instanceof PhyrexianManaCost) { - if (cost.pay(null, game, null, playerId, false, null) || spendAnyMana) { + if (cost.pay(null, game, null, playerId, false, null) || spendAnyManaId != null) { return true; } } diff --git a/Mage.Sets/src/mage/cards/a/AdarkarValkyrie.java b/Mage.Sets/src/mage/cards/a/AdarkarValkyrie.java index 0fccaadd0dd..09e8beec3c2 100644 --- a/Mage.Sets/src/mage/cards/a/AdarkarValkyrie.java +++ b/Mage.Sets/src/mage/cards/a/AdarkarValkyrie.java @@ -29,6 +29,7 @@ package mage.cards.a; import java.util.UUID; import mage.MageInt; +import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.DelayedTriggeredAbility; import mage.abilities.common.SimpleActivatedAbility; @@ -46,7 +47,7 @@ import mage.game.Game; import mage.game.events.GameEvent; import mage.game.events.GameEvent.EventType; import mage.game.events.ZoneChangeEvent; -import mage.target.Target; +import mage.game.permanent.Permanent; import mage.target.common.TargetCreaturePermanent; import mage.target.targetpointer.FixedTarget; @@ -76,8 +77,8 @@ public class AdarkarValkyrie extends CardImpl { this.addAbility(VigilanceAbility.getInstance()); // {T}: When target creature other than Adarkar Valkyrie dies this turn, return that card to the battlefield under your control. Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new AdarkarValkyrieEffect(), new TapSourceCost()); - Target target = new TargetCreaturePermanent(filter); - ability.addTarget(target); + + ability.addTarget(new TargetCreaturePermanent(filter)); this.addAbility(ability); } @@ -109,25 +110,28 @@ class AdarkarValkyrieEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - DelayedTriggeredAbility delayedAbility = new AdarkarValkyrieDelayedTriggeredAbility(getTargetPointer().getFixedTarget(game, source)); - game.addDelayedTriggeredAbility(delayedAbility, source); + Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source)); + if (permanent != null) { + DelayedTriggeredAbility delayedAbility = new AdarkarValkyrieDelayedTriggeredAbility(new MageObjectReference(permanent, game)); + game.addDelayedTriggeredAbility(delayedAbility, source); + return true; + } return false; } } class AdarkarValkyrieDelayedTriggeredAbility extends DelayedTriggeredAbility { - protected FixedTarget fixedTarget; + protected MageObjectReference mor; - public AdarkarValkyrieDelayedTriggeredAbility(FixedTarget fixedTarget) { + public AdarkarValkyrieDelayedTriggeredAbility(MageObjectReference mor) { super(new ReturnToBattlefieldUnderYourControlTargetEffect(), Duration.EndOfTurn); - this.getEffects().get(0).setTargetPointer(fixedTarget); - this.fixedTarget = fixedTarget; + this.mor = mor; } public AdarkarValkyrieDelayedTriggeredAbility(final AdarkarValkyrieDelayedTriggeredAbility ability) { super(ability); - this.fixedTarget = ability.fixedTarget; + this.mor = ability.mor; } @Override @@ -142,10 +146,11 @@ class AdarkarValkyrieDelayedTriggeredAbility extends DelayedTriggeredAbility { @Override public boolean checkTrigger(GameEvent event, Game game) { - if (((ZoneChangeEvent) event).isDiesEvent()) { - if (fixedTarget.getFirst(game, this).equals(event.getTargetId())) { - return true; - } + if (((ZoneChangeEvent) event).isDiesEvent() + && mor.refersTo(((ZoneChangeEvent) event).getTarget(), game)) { + getEffects().setTargetPointer(new FixedTarget(event.getTargetId(), game)); + return true; + } return false; } diff --git a/Mage.Sets/src/mage/cards/m/MuldrothaTheGravetide.java b/Mage.Sets/src/mage/cards/m/MuldrothaTheGravetide.java index d10fa039b42..ac5e1e3b16b 100644 --- a/Mage.Sets/src/mage/cards/m/MuldrothaTheGravetide.java +++ b/Mage.Sets/src/mage/cards/m/MuldrothaTheGravetide.java @@ -1,230 +1,240 @@ -/* - * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, are - * permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this list of - * conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list - * of conditions and the following disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND - * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * The views and conclusions contained in the software and documentation are those of the - * authors and should not be interpreted as representing official policies, either expressed - * or implied, of BetaSteward_at_googlemail.com. - */ -package mage.cards.m; - -import java.util.EnumSet; -import java.util.HashMap; -import java.util.Set; -import java.util.UUID; -import mage.MageInt; -import mage.MageObject; -import mage.abilities.Ability; -import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.effects.AsThoughEffectImpl; -import mage.cards.Card; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.choices.Choice; -import mage.choices.ChoiceImpl; -import mage.constants.AsThoughEffectType; -import mage.constants.CardType; -import mage.constants.Duration; -import mage.constants.Outcome; -import mage.constants.SubType; -import mage.constants.SuperType; -import mage.constants.WatcherScope; -import mage.constants.Zone; -import mage.game.Game; -import mage.game.events.GameEvent; -import mage.game.permanent.Permanent; -import mage.game.stack.Spell; -import mage.players.Player; -import mage.watchers.Watcher; - -/** - * - * @author LevelX2 - */ -public class MuldrothaTheGravetide extends CardImpl { - - public MuldrothaTheGravetide(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{B}{G}{U}"); - - this.addSuperType(SuperType.LEGENDARY); - this.subtype.add(SubType.ELEMENTAL); - this.subtype.add(SubType.AVATAR); - this.power = new MageInt(6); - this.toughness = new MageInt(6); - - // During each of your turns, you may play up to one permanent card of each permanent type from your graveyard. - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new MuldrothaTheGravetideCastFromGraveyardEffect()), new MuldrothaTheGravetideWatcher()); - } - - public MuldrothaTheGravetide(final MuldrothaTheGravetide card) { - super(card); - } - - @Override - public MuldrothaTheGravetide copy() { - return new MuldrothaTheGravetide(this); - } -} - -class MuldrothaTheGravetideCastFromGraveyardEffect extends AsThoughEffectImpl { - - public MuldrothaTheGravetideCastFromGraveyardEffect() { - super(AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, Duration.WhileOnBattlefield, Outcome.Benefit); - staticText = "During each of your turns, you may play up to one permanent card of each permanent type from your graveyard. " - + "(If a card has multiple permanent types, choose one as you play it.)"; - } - - public MuldrothaTheGravetideCastFromGraveyardEffect(final MuldrothaTheGravetideCastFromGraveyardEffect effect) { - super(effect); - } - - @Override - public boolean apply(Game game, Ability source) { - return true; - } - - @Override - public MuldrothaTheGravetideCastFromGraveyardEffect copy() { - return new MuldrothaTheGravetideCastFromGraveyardEffect(this); - } - - @Override - public boolean applies(UUID objectId, Ability source, UUID affectedControllerId, Game game) { - if (source.getControllerId().equals(affectedControllerId) && Zone.GRAVEYARD.equals(game.getState().getZone(objectId))) { - MuldrothaTheGravetideWatcher watcher = (MuldrothaTheGravetideWatcher) game.getState().getWatchers().get(MuldrothaTheGravetideWatcher.class.getSimpleName()); - MageObject mageObject = game.getObject(objectId); - if (mageObject != null && watcher != null) { - for (CardType cardType : mageObject.getCardType()) { - if (cardType.isPermanentType()) { - if (!watcher.permanentTypePlayedFromGraveyard(affectedControllerId, cardType)) { - return true; - } - } - } - } - } - return false; - } -} - -class MuldrothaTheGravetideWatcher extends Watcher { - - final HashMap> playerPlayedPermanentTypes = new HashMap<>(); // player that played permanent types from graveyard - private Zone fromZone; - - public MuldrothaTheGravetideWatcher() { - super(MuldrothaTheGravetideWatcher.class.getSimpleName(), WatcherScope.GAME); - } - - public MuldrothaTheGravetideWatcher(final MuldrothaTheGravetideWatcher watcher) { - super(watcher); - playerPlayedPermanentTypes.putAll(watcher.playerPlayedPermanentTypes); - } - - @Override - public MuldrothaTheGravetideWatcher copy() { - return new MuldrothaTheGravetideWatcher(this); - } - - @Override - public void watch(GameEvent event, Game game) { - if (event.getType() == GameEvent.EventType.PLAY_LAND) { - fromZone = game.getState().getZone(event.getTargetId()); // Remember the Zone the land came from - } - if (event.getType() == GameEvent.EventType.LAND_PLAYED && fromZone.equals(Zone.GRAVEYARD)) { - addPermanentTypes(game.getPermanentOrLKIBattlefield(event.getTargetId()), game); - } - - if (event.getType() == GameEvent.EventType.SPELL_CAST) { - Spell spell = (Spell) game.getObject(event.getTargetId()); - if (spell.getFromZone().equals(Zone.GRAVEYARD)) { - addPermanentTypes(spell, game); - } - } - } - - private void addPermanentTypes(Card mageObject, Game game) { - if (mageObject != null) { - UUID playerId = null; - if (mageObject instanceof Spell) { - playerId = ((Spell) mageObject).getControllerId(); - } else if (mageObject instanceof Permanent) { - playerId = ((Permanent) mageObject).getControllerId(); - } - if (playerId != null) { - Set permanentTypes = playerPlayedPermanentTypes.get(playerId); - if (permanentTypes == null) { - permanentTypes = EnumSet.noneOf(CardType.class); - playerPlayedPermanentTypes.put(playerId, permanentTypes); - } - Set typesNotCast = EnumSet.noneOf(CardType.class); - for (CardType cardType : mageObject.getCardType()) { - if (cardType.isPermanentType()) { - if (!permanentTypes.contains(cardType)) { - typesNotCast.add(cardType); - } - } - } - if (typesNotCast.size() <= 1) { - permanentTypes.addAll(typesNotCast); - } else { - Player player = game.getPlayer(playerId); - if (player != null) { - Choice typeChoice = new ChoiceImpl(true); - typeChoice.setMessage("Choose permanent type you consume for casting from graveyard."); - for (CardType cardType : typesNotCast) { - typeChoice.getChoices().add(cardType.toString()); - } - if (player.choose(Outcome.Detriment, typeChoice, game)) { - String typeName = typeChoice.getChoice(); - CardType chosenType = null; - for (CardType cardType : CardType.values()) { - if (cardType.toString().equals(typeName)) { - chosenType = cardType; - break; - } - } - if (chosenType != null) { - permanentTypes.add(chosenType); - } - } - } - } - } - } - } - - @Override - public void reset() { - playerPlayedPermanentTypes.clear(); - super.reset(); - } - - public boolean permanentTypePlayedFromGraveyard(UUID playerId, CardType cardType) { - Set permanentTypes = playerPlayedPermanentTypes.get(playerId); - if (permanentTypes != null) { - return permanentTypes.contains(cardType); - } - return false; - } - -} +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.cards.m; + +import java.util.EnumSet; +import java.util.HashMap; +import java.util.Set; +import java.util.UUID; +import mage.MageInt; +import mage.MageObject; +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.AsThoughEffectImpl; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.choices.Choice; +import mage.choices.ChoiceImpl; +import mage.constants.AsThoughEffectType; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.constants.WatcherScope; +import mage.constants.Zone; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; +import mage.game.stack.Spell; +import mage.players.Player; +import mage.watchers.Watcher; + +/** + * + * @author LevelX2 + */ +public class MuldrothaTheGravetide extends CardImpl { + + public MuldrothaTheGravetide(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{B}{G}{U}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.ELEMENTAL); + this.subtype.add(SubType.AVATAR); + this.power = new MageInt(6); + this.toughness = new MageInt(6); + + // During each of your turns, you may play up to one permanent card of each permanent type from your graveyard. + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new MuldrothaTheGravetideCastFromGraveyardEffect()), new MuldrothaTheGravetideWatcher()); + } + + public MuldrothaTheGravetide(final MuldrothaTheGravetide card) { + super(card); + } + + @Override + public MuldrothaTheGravetide copy() { + return new MuldrothaTheGravetide(this); + } +} + +class MuldrothaTheGravetideCastFromGraveyardEffect extends AsThoughEffectImpl { + + public MuldrothaTheGravetideCastFromGraveyardEffect() { + super(AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, Duration.WhileOnBattlefield, Outcome.Benefit); + staticText = "During each of your turns, you may play up to one permanent card of each permanent type from your graveyard. " + + "(If a card has multiple permanent types, choose one as you play it.)"; + } + + public MuldrothaTheGravetideCastFromGraveyardEffect(final MuldrothaTheGravetideCastFromGraveyardEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source) { + return true; + } + + @Override + public MuldrothaTheGravetideCastFromGraveyardEffect copy() { + return new MuldrothaTheGravetideCastFromGraveyardEffect(this); + } + + @Override + public boolean applies(UUID objectId, Ability source, UUID affectedControllerId, Game game) { + if (source.getControllerId().equals(affectedControllerId) + && affectedControllerId.equals(game.getActivePlayerId()) // only during your turns (e.g. prevent flash creatures) + && Zone.GRAVEYARD.equals(game.getState().getZone(objectId))) { + MuldrothaTheGravetideWatcher watcher = (MuldrothaTheGravetideWatcher) game.getState().getWatchers().get(MuldrothaTheGravetideWatcher.class.getSimpleName()); + MageObject mageObject = game.getObject(objectId); + if (mageObject != null && watcher != null) { + for (CardType cardType : mageObject.getCardType()) { + if (cardType.isPermanentType()) { + if (!watcher.permanentTypePlayedFromGraveyard(affectedControllerId, cardType)) { + return true; + } + } + } + } + } + return false; + } +} + +/** + * Holds track of the consumed types of each permission giving source + * + * @author LevelX2 + */ +class MuldrothaTheGravetideWatcher extends Watcher { + + // final HashMap> playerPlayedPermanentTypes = new HashMap<>(); // source that played permanent types from graveyard + final HashMap> playerPlayedPermanentTypes = new HashMap<>(); // player that played permanent types from graveyard + // 4/27/2018 If multiple effects allow you to play a card from your graveyard, such as those of Gisa and Geralf and Karador, + // Ghost Chieftain, you must announce which permission you’re using as you begin to play the card. + private Zone fromZone; + + public MuldrothaTheGravetideWatcher() { + super(MuldrothaTheGravetideWatcher.class.getSimpleName(), WatcherScope.GAME); + } + + public MuldrothaTheGravetideWatcher(final MuldrothaTheGravetideWatcher watcher) { + super(watcher); + playerPlayedPermanentTypes.putAll(watcher.playerPlayedPermanentTypes); + } + + @Override + public MuldrothaTheGravetideWatcher copy() { + return new MuldrothaTheGravetideWatcher(this); + } + + @Override + public void watch(GameEvent event, Game game) { + if (event.getType() == GameEvent.EventType.PLAY_LAND) { + fromZone = game.getState().getZone(event.getTargetId()); // Remember the Zone the land came from + } + if (event.getType() == GameEvent.EventType.LAND_PLAYED && fromZone.equals(Zone.GRAVEYARD)) { + addPermanentTypes(event, game.getPermanentOrLKIBattlefield(event.getTargetId()), game); + } + + if (event.getType() == GameEvent.EventType.SPELL_CAST) { + Spell spell = (Spell) game.getObject(event.getTargetId()); + if (spell.getFromZone().equals(Zone.GRAVEYARD)) { + addPermanentTypes(event, spell, game); + } + } + } + + private void addPermanentTypes(GameEvent event, Card mageObject, Game game) { + if (mageObject != null) { + UUID playerId = null; + if (mageObject instanceof Spell) { + playerId = ((Spell) mageObject).getControllerId(); + } else if (mageObject instanceof Permanent) { + playerId = ((Permanent) mageObject).getControllerId(); + } + if (playerId != null) { + Set permanentTypes = playerPlayedPermanentTypes.get(playerId); + if (permanentTypes == null) { + permanentTypes = EnumSet.noneOf(CardType.class); + playerPlayedPermanentTypes.put(playerId, permanentTypes); + } + Set typesNotCast = EnumSet.noneOf(CardType.class); + for (CardType cardType : mageObject.getCardType()) { + if (cardType.isPermanentType()) { + if (!permanentTypes.contains(cardType)) { + typesNotCast.add(cardType); + } + } + } + if (typesNotCast.size() <= 1) { + permanentTypes.addAll(typesNotCast); + } else { + Player player = game.getPlayer(playerId); + if (player != null) { + Choice typeChoice = new ChoiceImpl(true); + typeChoice.setMessage("Choose permanent type you consume for casting from graveyard."); + for (CardType cardType : typesNotCast) { + typeChoice.getChoices().add(cardType.toString()); + } + if (player.choose(Outcome.Detriment, typeChoice, game)) { + String typeName = typeChoice.getChoice(); + CardType chosenType = null; + for (CardType cardType : CardType.values()) { + if (cardType.toString().equals(typeName)) { + chosenType = cardType; + break; + } + } + if (chosenType != null) { + permanentTypes.add(chosenType); + } + } + } + } + } + } + } + + @Override + public void reset() { + playerPlayedPermanentTypes.clear(); + super.reset(); + } + + public boolean permanentTypePlayedFromGraveyard(UUID playerId, CardType cardType) { + Set permanentTypes = playerPlayedPermanentTypes.get(playerId); + if (permanentTypes != null) { + return permanentTypes.contains(cardType); + } + return false; + } + +} diff --git a/Mage.Sets/src/mage/cards/t/Tromokratis.java b/Mage.Sets/src/mage/cards/t/Tromokratis.java index 833ef6ae32f..27ae856c36b 100644 --- a/Mage.Sets/src/mage/cards/t/Tromokratis.java +++ b/Mage.Sets/src/mage/cards/t/Tromokratis.java @@ -108,7 +108,7 @@ class CantBeBlockedUnlessAllEffect extends RestrictionEffect { // check if all creatures of defender are able to block this permanent // permanent.canBlock() can't be used because causing recursive call for (Permanent permanent : game.getBattlefield().getAllActivePermanents(filter, blocker.getControllerId(), game)) { - if (permanent.isTapped() && !game.getState().getContinuousEffects().asThough(this.getId(), AsThoughEffectType.BLOCK_TAPPED, source, blocker.getControllerId(), game)) { + if (permanent.isTapped() && null == game.getState().getContinuousEffects().asThough(this.getId(), AsThoughEffectType.BLOCK_TAPPED, source, blocker.getControllerId(), game)) { return false; } // check blocker restrictions diff --git a/Mage/src/main/java/mage/abilities/ActivatedAbilityImpl.java b/Mage/src/main/java/mage/abilities/ActivatedAbilityImpl.java index 6ffde97b56e..5ef80ab0f1e 100644 --- a/Mage/src/main/java/mage/abilities/ActivatedAbilityImpl.java +++ b/Mage/src/main/java/mage/abilities/ActivatedAbilityImpl.java @@ -220,7 +220,7 @@ public abstract class ActivatedAbilityImpl extends AbilityImpl implements Activa } //20091005 - 602.5d/602.5e if (timing == TimingRule.INSTANT || game.canPlaySorcery(playerId) - || game.getContinuousEffects().asThough(sourceId, AsThoughEffectType.ACTIVATE_AS_INSTANT, this, controllerId, game)) { + || null != game.getContinuousEffects().asThough(sourceId, AsThoughEffectType.ACTIVATE_AS_INSTANT, this, controllerId, game)) { if (costs.canPay(this, sourceId, playerId, game) && canChooseTarget(game)) { this.activatorId = playerId; return true; diff --git a/Mage/src/main/java/mage/abilities/PlayLandAbility.java b/Mage/src/main/java/mage/abilities/PlayLandAbility.java index 31fd0702bcb..5aa10fb6cd9 100644 --- a/Mage/src/main/java/mage/abilities/PlayLandAbility.java +++ b/Mage/src/main/java/mage/abilities/PlayLandAbility.java @@ -52,7 +52,7 @@ public class PlayLandAbility extends ActivatedAbilityImpl { @Override public boolean canActivate(UUID playerId, Game game) { if (!controlsAbility(playerId, game) - && !game.getContinuousEffects().asThough(getSourceId(), AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, playerId, game)) { + && null == game.getContinuousEffects().asThough(getSourceId(), AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, playerId, game)) { return false; } //20091005 - 114.2a diff --git a/Mage/src/main/java/mage/abilities/SpellAbility.java b/Mage/src/main/java/mage/abilities/SpellAbility.java index dc723dad6c6..84491fb0096 100644 --- a/Mage/src/main/java/mage/abilities/SpellAbility.java +++ b/Mage/src/main/java/mage/abilities/SpellAbility.java @@ -92,13 +92,13 @@ public class SpellAbility extends ActivatedAbilityImpl { @Override public boolean canActivate(UUID playerId, Game game) { - if (game.getContinuousEffects().asThough(sourceId, AsThoughEffectType.CAST_AS_INSTANT, this, playerId, game) // check this first to allow Offering in main phase + if (null != game.getContinuousEffects().asThough(sourceId, AsThoughEffectType.CAST_AS_INSTANT, this, playerId, game) // check this first to allow Offering in main phase || this.spellCanBeActivatedRegularlyNow(playerId, game)) { if (spellAbilityType == SpellAbilityType.SPLIT || spellAbilityType == SpellAbilityType.SPLIT_AFTERMATH) { return false; } // fix for Gitaxian Probe and casting opponent's spells - if (!game.getContinuousEffects().asThough(getSourceId(), AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, playerId, game)) { + if (null == game.getContinuousEffects().asThough(getSourceId(), AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, playerId, game)) { Card card = game.getCard(sourceId); if (!(card != null && card.getOwnerId().equals(playerId))) { return false; diff --git a/Mage/src/main/java/mage/abilities/costs/common/TapSourceCost.java b/Mage/src/main/java/mage/abilities/costs/common/TapSourceCost.java index e53a75282b3..d127b664918 100644 --- a/Mage/src/main/java/mage/abilities/costs/common/TapSourceCost.java +++ b/Mage/src/main/java/mage/abilities/costs/common/TapSourceCost.java @@ -24,8 +24,7 @@ * The views and conclusions contained in the software and documentation are those of the * authors and should not be interpreted as representing official policies, either expressed * or implied, of BetaSteward_at_googlemail.com. -*/ - + */ package mage.abilities.costs.common; import java.util.UUID; @@ -63,8 +62,8 @@ public class TapSourceCost extends CostImpl { public boolean canPay(Ability ability, UUID sourceId, UUID controllerId, Game game) { Permanent permanent = game.getPermanent(sourceId); if (permanent != null) { - return !permanent.isTapped() && - (permanent.canTap() || game.getContinuousEffects().asThough(sourceId, AsThoughEffectType.ACTIVATE_HASTE, controllerId, game)); + return !permanent.isTapped() + && (permanent.canTap() || null != game.getContinuousEffects().asThough(sourceId, AsThoughEffectType.ACTIVATE_HASTE, controllerId, game)); } return false; } diff --git a/Mage/src/main/java/mage/abilities/costs/common/UntapSourceCost.java b/Mage/src/main/java/mage/abilities/costs/common/UntapSourceCost.java index 9781fdece42..15af412080f 100644 --- a/Mage/src/main/java/mage/abilities/costs/common/UntapSourceCost.java +++ b/Mage/src/main/java/mage/abilities/costs/common/UntapSourceCost.java @@ -62,7 +62,7 @@ public class UntapSourceCost extends CostImpl { public boolean canPay(Ability ability, UUID sourceId, UUID controllerId, Game game) { Permanent permanent = game.getPermanent(sourceId); if (permanent != null) { - return permanent.isTapped() && (permanent.canTap() || game.getContinuousEffects().asThough(sourceId, AsThoughEffectType.ACTIVATE_HASTE, controllerId, game)); + return permanent.isTapped() && (permanent.canTap() || null != game.getContinuousEffects().asThough(sourceId, AsThoughEffectType.ACTIVATE_HASTE, controllerId, game)); } return false; } diff --git a/Mage/src/main/java/mage/abilities/effects/ContinuousEffects.java b/Mage/src/main/java/mage/abilities/effects/ContinuousEffects.java index 09ee4020053..db908e4a289 100644 --- a/Mage/src/main/java/mage/abilities/effects/ContinuousEffects.java +++ b/Mage/src/main/java/mage/abilities/effects/ContinuousEffects.java @@ -500,25 +500,44 @@ public class ContinuousEffects implements Serializable { return spliceEffects; } - public boolean asThough(UUID objectId, AsThoughEffectType type, UUID controllerId, Game game) { + /** + * + * @param objectId + * @param type + * @param controllerId + * @param game + * @return sourceId of the permitting effect if any exists otherwise returns + * null + */ + public UUID asThough(UUID objectId, AsThoughEffectType type, UUID controllerId, Game game) { return asThough(objectId, type, null, controllerId, game); } - public boolean asThough(UUID objectId, AsThoughEffectType type, Ability affectedAbility, UUID controllerId, Game game) { + /** + * + * @param objectId + * @param type + * @param affectedAbility + * @param controllerId + * @param game + * @return sourceId of the permitting effect if any exists otherwise returns + * null + */ + public UUID asThough(UUID objectId, AsThoughEffectType type, Ability affectedAbility, UUID controllerId, Game game) { List asThoughEffectsList = getApplicableAsThoughEffects(type, game); for (AsThoughEffect effect : asThoughEffectsList) { Set abilities = asThoughEffectsMap.get(type).getAbility(effect.getId()); for (Ability ability : abilities) { if (affectedAbility == null) { if (effect.applies(objectId, ability, controllerId, game)) { - return true; + return ability.getSourceId(); } } else if (effect.applies(objectId, affectedAbility, ability, game)) { - return true; + return ability.getSourceId(); } } } - return false; + return null; } @@ -754,7 +773,7 @@ public class ContinuousEffects implements Serializable { // Remove all consumed effects (ability dependant) for (Iterator it1 = rEffects.keySet().iterator(); it1.hasNext();) { ReplacementEffect entry = it1.next(); - if (consumed.containsKey(entry.getId()) /*&& !(entry instanceof CommanderReplacementEffect) */) { // 903.9. + if (consumed.containsKey(entry.getId()) /*&& !(entry instanceof CommanderReplacementEffect) */) { // 903.9. Set consumedAbilitiesIds = consumed.get(entry.getId()); if (rEffects.get(entry) == null || consumedAbilitiesIds.size() == rEffects.get(entry).size()) { it1.remove(); diff --git a/Mage/src/main/java/mage/abilities/keyword/FlyingAbility.java b/Mage/src/main/java/mage/abilities/keyword/FlyingAbility.java index 1e0bf34cb13..da7d4dddbd4 100644 --- a/Mage/src/main/java/mage/abilities/keyword/FlyingAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/FlyingAbility.java @@ -27,6 +27,7 @@ */ package mage.abilities.keyword; +import java.io.ObjectStreamException; import mage.abilities.Ability; import mage.abilities.EvasionAbility; import mage.abilities.MageSingleton; @@ -37,8 +38,6 @@ import mage.constants.SubType; import mage.game.Game; import mage.game.permanent.Permanent; -import java.io.ObjectStreamException; - /** * * @author BetaSteward_at_googlemail.com @@ -90,7 +89,8 @@ class FlyingEffect extends RestrictionEffect implements MageSingleton { public boolean canBeBlocked(Permanent attacker, Permanent blocker, Ability source, Game game) { return blocker.getAbilities().containsKey(FlyingAbility.getInstance().getId()) || blocker.getAbilities().containsKey(ReachAbility.getInstance().getId()) - || (game.getContinuousEffects().asThough(blocker.getId(), AsThoughEffectType.BLOCK_DRAGON, source, blocker.getControllerId(), game) && attacker.hasSubtype(SubType.DRAGON, game)); + || (null != game.getContinuousEffects().asThough(blocker.getId(), AsThoughEffectType.BLOCK_DRAGON, source, blocker.getControllerId(), game) + && attacker.hasSubtype(SubType.DRAGON, game)); } @Override diff --git a/Mage/src/main/java/mage/abilities/keyword/LandwalkAbility.java b/Mage/src/main/java/mage/abilities/keyword/LandwalkAbility.java index bf382c72799..3330e8ffd3b 100644 --- a/Mage/src/main/java/mage/abilities/keyword/LandwalkAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/LandwalkAbility.java @@ -88,21 +88,21 @@ class LandwalkEffect extends RestrictionEffect { @Override public boolean canBeBlocked(Permanent attacker, Permanent blocker, Ability source, Game game) { if (game.getBattlefield().contains(filter, blocker.getControllerId(), 1, game) - && !game.getContinuousEffects().asThough(blocker.getId(), AsThoughEffectType.BLOCK_LANDWALK, source, blocker.getControllerId(), game)) { + && null == game.getContinuousEffects().asThough(blocker.getId(), AsThoughEffectType.BLOCK_LANDWALK, source, blocker.getControllerId(), game)) { switch (filter.getMessage()) { case "plains": - return game.getContinuousEffects().asThough(blocker.getId(), AsThoughEffectType.BLOCK_PLAINSWALK, source, blocker.getControllerId(), game); + return null != game.getContinuousEffects().asThough(blocker.getId(), AsThoughEffectType.BLOCK_PLAINSWALK, source, blocker.getControllerId(), game); case "island": - return game.getContinuousEffects().asThough(blocker.getId(), AsThoughEffectType.BLOCK_ISLANDWALK, source, blocker.getControllerId(), game); + return null != game.getContinuousEffects().asThough(blocker.getId(), AsThoughEffectType.BLOCK_ISLANDWALK, source, blocker.getControllerId(), game); case "swamp": - return game.getContinuousEffects().asThough(blocker.getId(), AsThoughEffectType.BLOCK_SWAMPWALK, source, blocker.getControllerId(), game); + return null != game.getContinuousEffects().asThough(blocker.getId(), AsThoughEffectType.BLOCK_SWAMPWALK, source, blocker.getControllerId(), game); case "mountain": - return game.getContinuousEffects().asThough(blocker.getId(), AsThoughEffectType.BLOCK_MOUNTAINWALK, source, blocker.getControllerId(), game); + return null != game.getContinuousEffects().asThough(blocker.getId(), AsThoughEffectType.BLOCK_MOUNTAINWALK, source, blocker.getControllerId(), game); case "forest": - return game.getContinuousEffects().asThough(blocker.getId(), AsThoughEffectType.BLOCK_FORESTWALK, source, blocker.getControllerId(), game); + return null != game.getContinuousEffects().asThough(blocker.getId(), AsThoughEffectType.BLOCK_FORESTWALK, source, blocker.getControllerId(), game); default: return false; - + } } return true; diff --git a/Mage/src/main/java/mage/abilities/keyword/ShadowAbility.java b/Mage/src/main/java/mage/abilities/keyword/ShadowAbility.java index 2573570731c..6188b91b59e 100644 --- a/Mage/src/main/java/mage/abilities/keyword/ShadowAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/ShadowAbility.java @@ -66,7 +66,7 @@ class ShadowEffect extends RestrictionEffect implements MageSingleton { @Override public boolean canBeBlocked(Permanent attacker, Permanent blocker, Ability source, Game game) { return blocker.getAbilities().containsKey(ShadowAbility.getInstance().getId()) - || game.getContinuousEffects().asThough(blocker.getId(), AsThoughEffectType.BLOCK_SHADOW, source, blocker.getControllerId(), game); + || null != game.getContinuousEffects().asThough(blocker.getId(), AsThoughEffectType.BLOCK_SHADOW, source, blocker.getControllerId(), game); } @Override diff --git a/Mage/src/main/java/mage/abilities/keyword/SuspendAbility.java b/Mage/src/main/java/mage/abilities/keyword/SuspendAbility.java index 8e05b879c08..b19ca7db21c 100644 --- a/Mage/src/main/java/mage/abilities/keyword/SuspendAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/SuspendAbility.java @@ -27,6 +27,9 @@ */ package mage.abilities.keyword; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; import mage.MageObject; import mage.abilities.Ability; import mage.abilities.SpecialAction; @@ -50,10 +53,6 @@ import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.targetpointer.FixedTarget; -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; - /** * * 502.59. Suspend @@ -120,10 +119,10 @@ import java.util.UUID; * card involves an additional cost, the card's owner must pay that cost if * able. If he or she can't, the card remains removed from the game. If the * additional cost includes mana, the situation is more complex. If the player - * has enough mana in their mana pool to pay the cost, that player must do - * so. If the player can't possibly pay the cost, the card remains removed from - * the game. However, if the player has the means to produce enough mana to pay - * the cost, then he or she has a choice: The player may play the spell, produce + * has enough mana in their mana pool to pay the cost, that player must do so. + * If the player can't possibly pay the cost, the card remains removed from the + * game. However, if the player has the means to produce enough mana to pay the + * cost, then he or she has a choice: The player may play the spell, produce * mana, and pay the cost. Or the player may choose to play no mana abilities, * thus making the card impossible to play because the additional mana can't be * paid. @@ -237,7 +236,7 @@ public class SuspendAbility extends SpecialAction { MageObject object = game.getObject(sourceId); return (object.isInstant() || object.hasAbility(FlashAbility.getInstance().getId(), game) - || game.getContinuousEffects().asThough(sourceId, AsThoughEffectType.CAST_AS_INSTANT, this, playerId, game) + || null != game.getContinuousEffects().asThough(sourceId, AsThoughEffectType.CAST_AS_INSTANT, this, playerId, game) || game.canPlaySorcery(playerId)); } diff --git a/Mage/src/main/java/mage/abilities/mana/ActivatedManaAbilityImpl.java b/Mage/src/main/java/mage/abilities/mana/ActivatedManaAbilityImpl.java index 61da85343ac..e25aadbe696 100644 --- a/Mage/src/main/java/mage/abilities/mana/ActivatedManaAbilityImpl.java +++ b/Mage/src/main/java/mage/abilities/mana/ActivatedManaAbilityImpl.java @@ -77,7 +77,7 @@ public abstract class ActivatedManaAbilityImpl extends ActivatedAbilityImpl impl } if (timing == TimingRule.SORCERY && !game.canPlaySorcery(playerId) - && !game.getContinuousEffects().asThough(sourceId, AsThoughEffectType.ACTIVATE_AS_INSTANT, this, controllerId, game)) { + && null == game.getContinuousEffects().asThough(sourceId, AsThoughEffectType.ACTIVATE_AS_INSTANT, this, controllerId, game)) { return false; } // check if player is in the process of playing spell costs and he is no longer allowed to use activated mana abilities (e.g. because he started to use improvise) diff --git a/Mage/src/main/java/mage/filter/common/FilterCreatureForCombatBlock.java b/Mage/src/main/java/mage/filter/common/FilterCreatureForCombatBlock.java index fc9bb9edbfc..f4e35180ca2 100644 --- a/Mage/src/main/java/mage/filter/common/FilterCreatureForCombatBlock.java +++ b/Mage/src/main/java/mage/filter/common/FilterCreatureForCombatBlock.java @@ -24,8 +24,7 @@ * The views and conclusions contained in the software and documentation are those of the * authors and should not be interpreted as representing official policies, either expressed * or implied, of BetaSteward_at_googlemail.com. -*/ - + */ package mage.filter.common; import mage.constants.AsThoughEffectType; @@ -61,8 +60,8 @@ public class FilterCreatureForCombatBlock extends FilterCreatureForCombatBase { class BlockTappedPredicate implements Predicate { @Override - public boolean apply(Permanent input, Game game) { - return !input.isTapped() || game.getState().getContinuousEffects().asThough(input.getId(), AsThoughEffectType.BLOCK_TAPPED, input.getControllerId(), game); + public boolean apply(Permanent input, Game game) { + return !input.isTapped() || null != game.getState().getContinuousEffects().asThough(input.getId(), AsThoughEffectType.BLOCK_TAPPED, input.getControllerId(), game); } @Override diff --git a/Mage/src/main/java/mage/game/permanent/PermanentImpl.java b/Mage/src/main/java/mage/game/permanent/PermanentImpl.java index 117dd2b88b5..427b46ef05c 100644 --- a/Mage/src/main/java/mage/game/permanent/PermanentImpl.java +++ b/Mage/src/main/java/mage/game/permanent/PermanentImpl.java @@ -935,20 +935,20 @@ public abstract class PermanentImpl extends CardImpl implements Permanent { public boolean canBeTargetedBy(MageObject source, UUID sourceControllerId, Game game) { if (source != null) { if (abilities.containsKey(ShroudAbility.getInstance().getId())) { - if (!game.getContinuousEffects().asThough(this.getId(), AsThoughEffectType.SHROUD, sourceControllerId, game)) { + if (null == game.getContinuousEffects().asThough(this.getId(), AsThoughEffectType.SHROUD, sourceControllerId, game)) { return false; } } if (abilities.containsKey(HexproofAbility.getInstance().getId())) { if (game.getPlayer(this.getControllerId()).hasOpponent(sourceControllerId, game) - && !game.getContinuousEffects().asThough(this.getId(), AsThoughEffectType.HEXPROOF, sourceControllerId, game)) { + && null == game.getContinuousEffects().asThough(this.getId(), AsThoughEffectType.HEXPROOF, sourceControllerId, game)) { return false; } } if (abilities.containsKey(HexproofFromBlackAbility.getInstance().getId())) { if (game.getPlayer(this.getControllerId()).hasOpponent(sourceControllerId, game) - && !game.getContinuousEffects().asThough(this.getId(), AsThoughEffectType.HEXPROOF, sourceControllerId, game) + && null == game.getContinuousEffects().asThough(this.getId(), AsThoughEffectType.HEXPROOF, sourceControllerId, game) && source.getColor(game).isBlack()) { return false; } @@ -956,7 +956,7 @@ public abstract class PermanentImpl extends CardImpl implements Permanent { if (abilities.containsKey(HexproofFromWhiteAbility.getInstance().getId())) { if (game.getPlayer(this.getControllerId()).hasOpponent(sourceControllerId, game) - && !game.getContinuousEffects().asThough(this.getId(), AsThoughEffectType.HEXPROOF, sourceControllerId, game) + && null == game.getContinuousEffects().asThough(this.getId(), AsThoughEffectType.HEXPROOF, sourceControllerId, game) && source.getColor(game).isWhite()) { return false; } @@ -1095,7 +1095,8 @@ public abstract class PermanentImpl extends CardImpl implements Permanent { @Override public boolean canAttackInPrinciple(UUID defenderId, Game game) { - if (hasSummoningSickness() && !game.getContinuousEffects().asThough(this.objectId, AsThoughEffectType.ATTACK_AS_HASTE, this.getControllerId(), game)) { + if (hasSummoningSickness() + && null == game.getContinuousEffects().asThough(this.objectId, AsThoughEffectType.ATTACK_AS_HASTE, this.getControllerId(), game)) { return false; } //20101001 - 508.1c @@ -1115,7 +1116,7 @@ public abstract class PermanentImpl extends CardImpl implements Permanent { } return !abilities.containsKey(DefenderAbility.getInstance().getId()) - || game.getContinuousEffects().asThough(this.objectId, AsThoughEffectType.ATTACK, this.getControllerId(), game); + || null != game.getContinuousEffects().asThough(this.objectId, AsThoughEffectType.ATTACK, this.getControllerId(), game); } private boolean canAttackCheckRestrictionEffects(UUID defenderId, Game game) { @@ -1135,7 +1136,7 @@ public abstract class PermanentImpl extends CardImpl implements Permanent { @Override public boolean canBlock(UUID attackerId, Game game) { - if (tapped && !game.getState().getContinuousEffects().asThough(this.getId(), AsThoughEffectType.BLOCK_TAPPED, this.getControllerId(), game)) { + if (tapped && null == game.getState().getContinuousEffects().asThough(this.getId(), AsThoughEffectType.BLOCK_TAPPED, this.getControllerId(), game)) { return false; } Permanent attacker = game.getPermanent(attackerId); @@ -1168,7 +1169,7 @@ public abstract class PermanentImpl extends CardImpl implements Permanent { @Override public boolean canBlockAny(Game game) { - if (tapped && !game.getState().getContinuousEffects().asThough(this.getId(), AsThoughEffectType.BLOCK_TAPPED, this.getControllerId(), game)) { + if (tapped && null == game.getState().getContinuousEffects().asThough(this.getId(), AsThoughEffectType.BLOCK_TAPPED, this.getControllerId(), game)) { return false; } diff --git a/Mage/src/main/java/mage/players/PlayerImpl.java b/Mage/src/main/java/mage/players/PlayerImpl.java index c237718ee64..e3c2e66df17 100644 --- a/Mage/src/main/java/mage/players/PlayerImpl.java +++ b/Mage/src/main/java/mage/players/PlayerImpl.java @@ -31,7 +31,6 @@ import java.io.Serializable; import java.text.SimpleDateFormat; import java.util.*; import java.util.Map.Entry; -import static jdk.nashorn.internal.objects.NativeRegExp.source; import mage.ConditionalMana; import mage.MageObject; import mage.Mana; @@ -610,7 +609,7 @@ public abstract class PlayerImpl implements Player, Serializable { } if (abilities.containsKey(HexproofAbility.getInstance().getId())) { if (sourceControllerId != null && this.hasOpponent(sourceControllerId, game) - && !game.getContinuousEffects().asThough(this.getId(), AsThoughEffectType.HEXPROOF, this.getId(), game)) { + && null == game.getContinuousEffects().asThough(this.getId(), AsThoughEffectType.HEXPROOF, this.getId(), game)) { return false; } } @@ -1356,7 +1355,8 @@ public abstract class PlayerImpl implements Player, Serializable { } } } - if (zone != Zone.BATTLEFIELD && game.getContinuousEffects().asThough(object.getId(), AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, this.getId(), game)) { + if (zone != Zone.BATTLEFIELD + && null != game.getContinuousEffects().asThough(object.getId(), AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, this.getId(), game)) { for (Ability ability : candidateAbilites) { if (canUse || ability.getAbilityType() == AbilityType.SPECIAL_ACTION) { ability.setControllerId(this.getId()); @@ -2706,10 +2706,10 @@ public abstract class PlayerImpl implements Player, Serializable { if (available == null) { return true; } - boolean spendAnyMana = game.getContinuousEffects().asThough(ability.getSourceId(), AsThoughEffectType.SPEND_OTHER_MANA, ability, ability.getControllerId(), game); + UUID spendAnyManaSourceId = game.getContinuousEffects().asThough(ability.getSourceId(), AsThoughEffectType.SPEND_OTHER_MANA, ability, ability.getControllerId(), game); for (Mana mana : abilityOptions) { for (Mana avail : available) { - if (spendAnyMana && mana.count() <= avail.count()) { + if (spendAnyManaSourceId != null && mana.count() <= avail.count()) { return true; } if (mana.enough(avail)) { // here we need to check if spend mana as though allow to pay the mana cost @@ -2834,13 +2834,13 @@ public abstract class PlayerImpl implements Player, Serializable { } private void getPlayableFromGraveyardCard(Game game, Card card, Abilities candidateAbilities, ManaOptions availableMana, List output) { - boolean asThoughtCast = game.getContinuousEffects().asThough(card.getId(), AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, this.getId(), game); + UUID asThoughtCastSourceId = game.getContinuousEffects().asThough(card.getId(), AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, this.getId(), game); for (ActivatedAbility ability : candidateAbilities.getActivatedAbilities(Zone.ALL)) { boolean possible = false; if (ability.getZone().match(Zone.GRAVEYARD)) { possible = true; } else if (ability.getZone().match(Zone.HAND) && (ability instanceof SpellAbility || ability instanceof PlayLandAbility)) { - if (asThoughtCast || canPlayCardsFromGraveyard()) { + if (asThoughtCastSourceId != null || canPlayCardsFromGraveyard()) { possible = true; } } @@ -2909,7 +2909,7 @@ public abstract class PlayerImpl implements Player, Serializable { } for (ExileZone exile : game.getExile().getExileZones()) { for (Card card : exile.getCards(game)) { - if (game.getContinuousEffects().asThough(card.getId(), AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, this.getId(), game)) { + if (null != game.getContinuousEffects().asThough(card.getId(), AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, this.getId(), game)) { for (Ability ability : card.getAbilities()) { if (ability.getZone().match(Zone.HAND)) { ability.setControllerId(this.getId()); // controller must be set for case owner != caster @@ -2927,7 +2927,7 @@ public abstract class PlayerImpl implements Player, Serializable { // Check to play revealed cards for (Cards cards : game.getState().getRevealed().values()) { for (Card card : cards.getCards(game)) { - if (game.getContinuousEffects().asThough(card.getId(), AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, this.getId(), game)) { + if (null != game.getContinuousEffects().asThough(card.getId(), AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, this.getId(), game)) { for (ActivatedAbility ability : card.getAbilities().getActivatedAbilities(Zone.HAND)) { if (ability instanceof SpellAbility || ability instanceof PlayLandAbility) { playable.add(ability); @@ -2942,7 +2942,7 @@ public abstract class PlayerImpl implements Player, Serializable { if (player != null) { if (/*player.isTopCardRevealed() &&*/player.getLibrary().hasCards()) { Card card = player.getLibrary().getFromTop(game); - if (game.getContinuousEffects().asThough(card.getId(), AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, getId(), game)) { + if (null != game.getContinuousEffects().asThough(card.getId(), AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, getId(), game)) { for (ActivatedAbility ability : card.getAbilities().getActivatedAbilities(Zone.HAND)) { if (ability instanceof SpellAbility || ability instanceof PlayLandAbility) { playable.add(ability); @@ -3295,7 +3295,7 @@ public abstract class PlayerImpl implements Player, Serializable { @Override public boolean lookAtFaceDownCard(Card card, Game game ) { - if (game.getContinuousEffects().asThough(card.getId(), AsThoughEffectType.LOOK_AT_FACE_DOWN, this.getId(), game)) { + if (null != game.getContinuousEffects().asThough(card.getId(), AsThoughEffectType.LOOK_AT_FACE_DOWN, this.getId(), game)) { if (chooseUse(Outcome.Benefit, "Look at that card?", null, game)) { Cards cards = new CardsImpl(card); this.lookAtCards(getName() + " - " + sdf.format(System.currentTimeMillis()), cards, game);