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 1c1c800262..178b626e4f 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 @@ -1701,7 +1701,7 @@ public class ComputerPlayer> extends PlayerImpl i } protected List getOpponentBlockers(UUID opponentId, Game game) { - FilterCreatureForCombat blockFilter = new FilterCreatureForCombat(); + FilterCreatureForCombatBlock blockFilter = new FilterCreatureForCombatBlock(); List blockers = game.getBattlefield().getAllActivePermanents(blockFilter, opponentId, game); return blockers; } diff --git a/Mage.Server.Plugins/Mage.Player.Human/src/mage/player/human/HumanPlayer.java b/Mage.Server.Plugins/Mage.Player.Human/src/mage/player/human/HumanPlayer.java index 851564a7a9..ff526bc26a 100644 --- a/Mage.Server.Plugins/Mage.Player.Human/src/mage/player/human/HumanPlayer.java +++ b/Mage.Server.Plugins/Mage.Player.Human/src/mage/player/human/HumanPlayer.java @@ -28,8 +28,22 @@ package mage.player.human; +import java.io.Serializable; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.UUID; import mage.MageObject; -import mage.abilities.*; +import mage.abilities.Ability; +import mage.abilities.ActivatedAbility; +import mage.abilities.Mode; +import mage.abilities.Modes; +import mage.abilities.SpecialAction; +import mage.abilities.SpellAbility; +import mage.abilities.TriggeredAbility; import mage.abilities.costs.common.SacrificeSourceCost; import mage.abilities.costs.mana.ManaCost; import mage.abilities.costs.mana.ManaCostsImpl; @@ -41,12 +55,15 @@ import mage.cards.Cards; import mage.cards.decks.Deck; import mage.choices.Choice; import mage.choices.ChoiceImpl; +import mage.constants.AsThoughEffectType; import mage.constants.Outcome; import mage.constants.RangeOfInfluence; import mage.constants.Zone; import mage.filter.common.FilterAttackingCreature; import mage.filter.common.FilterBlockingCreature; import mage.filter.common.FilterCreatureForCombat; +import mage.filter.common.FilterCreatureForCombatBase; +import mage.filter.common.FilterCreatureForCombatBlock; import mage.filter.predicate.permanent.ControllerIdPredicate; import mage.game.Game; import mage.game.draft.Draft; @@ -65,9 +82,6 @@ import mage.target.common.TargetDefender; import mage.util.ManaUtil; import org.apache.log4j.Logger; -import java.io.Serializable; -import java.util.*; - /** * @@ -77,6 +91,7 @@ public class HumanPlayer extends PlayerImpl { private final transient PlayerResponse response = new PlayerResponse(); + protected static FilterCreatureForCombatBlock filterCreatureForCombatBlock = new FilterCreatureForCombatBlock(); protected static FilterCreatureForCombat filterCreatureForCombat = new FilterCreatureForCombat(); protected static FilterAttackingCreature filterAttack = new FilterAttackingCreature(); protected static FilterBlockingCreature filterBlock = new FilterBlockingCreature(); @@ -593,7 +608,7 @@ public class HumanPlayer extends PlayerImpl { @Override public void selectBlockers(Game game, UUID defendingPlayerId) { updateGameStatePriority("selectBlockers", game); - FilterCreatureForCombat filter = filterCreatureForCombat.copy(); + FilterCreatureForCombatBlock filter = filterCreatureForCombatBlock.copy(); filter.add(new ControllerIdPredicate(defendingPlayerId)); while (!abort) { game.fireSelectEvent(playerId, "Select blockers"); @@ -601,10 +616,6 @@ public class HumanPlayer extends PlayerImpl { if (response.getBoolean() != null) { return; } else if (response.getInteger() != null) { - //if (response.getInteger() == -9999) { - // passedAllTurns = true; - //} - //passedTurn = true; return; } else if (response.getUUID() != null) { Permanent blocker = game.getPermanent(response.getUUID()); @@ -613,8 +624,7 @@ public class HumanPlayer extends PlayerImpl { selectCombatGroup(blocker.getId(), game); } else if (filterBlock.match(blocker, null, playerId, game) && game.getStack().isEmpty()) { -// if (game.getState().getTriggered().isEmpty() && game.getState().getDelayed().isEmpty()) - game.getCombat().removeBlocker(blocker.getId(), game); + game.getCombat().removeBlocker(blocker.getId(), game); } } } diff --git a/Mage.Tests/src/test/java/org/mage/test/player/TestPlayer.java b/Mage.Tests/src/test/java/org/mage/test/player/TestPlayer.java index 81ebd28f32..5b8abac74c 100644 --- a/Mage.Tests/src/test/java/org/mage/test/player/TestPlayer.java +++ b/Mage.Tests/src/test/java/org/mage/test/player/TestPlayer.java @@ -54,6 +54,7 @@ import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.UUID; +import mage.filter.common.FilterCreatureForCombatBlock; /** * @@ -154,7 +155,7 @@ public class TestPlayer extends ComputerPlayer { String command = action.getAction(); command = command.substring(command.indexOf("block:") + 6); String[] groups = command.split(";"); - FilterCreatureForCombat filterBlocker = new FilterCreatureForCombat(); + FilterCreatureForCombatBlock filterBlocker = new FilterCreatureForCombatBlock(); filterBlocker.add(new NamePredicate(groups[0])); Permanent blocker = findPermanent(filterBlocker, playerId, game); if (blocker != null) { diff --git a/Mage/src/mage/constants/AsThoughEffectType.java b/Mage/src/mage/constants/AsThoughEffectType.java index d8f0e8070d..48fca425dd 100644 --- a/Mage/src/mage/constants/AsThoughEffectType.java +++ b/Mage/src/mage/constants/AsThoughEffectType.java @@ -5,7 +5,7 @@ package mage.constants; * @author North */ public enum AsThoughEffectType { - BLOCK, + BLOCK_TAPPED, BE_BLOCKED, ATTACK, CAST, diff --git a/Mage/src/mage/filter/common/FilterCreatureForCombat.java b/Mage/src/mage/filter/common/FilterCreatureForCombat.java index c9a5f90250..d909f39654 100644 --- a/Mage/src/mage/filter/common/FilterCreatureForCombat.java +++ b/Mage/src/mage/filter/common/FilterCreatureForCombat.java @@ -28,19 +28,15 @@ package mage.filter.common; -import mage.filter.predicate.Predicate; import mage.filter.predicate.Predicates; -import mage.filter.predicate.permanent.AttackingPredicate; import mage.filter.predicate.permanent.TappedPredicate; -import mage.game.Game; -import mage.game.permanent.Permanent; /** * * @author BetaSteward_at_googlemail.com * @author North */ -public class FilterCreatureForCombat extends FilterCreaturePermanent { +public class FilterCreatureForCombat extends FilterCreatureForCombatBase { public FilterCreatureForCombat() { this(""); @@ -48,10 +44,7 @@ public class FilterCreatureForCombat extends FilterCreaturePermanent { public FilterCreatureForCombat(String name) { super(name); - this.add(Predicates.not(new AttackingPredicate())); this.add(Predicates.not(new TappedPredicate())); - this.add(new PhasedInPredicate()); - this.add(new CanBlockPredicate()); } public FilterCreatureForCombat(final FilterCreatureForCombat filter) { @@ -63,29 +56,3 @@ public class FilterCreatureForCombat extends FilterCreaturePermanent { return new FilterCreatureForCombat(this); } } - -class PhasedInPredicate implements Predicate { - - @Override - public boolean apply(Permanent input, Game game) { - return input.isPhasedIn(); - } - - @Override - public String toString() { - return "PhasedIn"; - } -} - -class CanBlockPredicate implements Predicate { - - @Override - public boolean apply(Permanent input, Game game) { - return input.getMaxBlocks() == 0 || input.getBlocking() < input.getMaxBlocks(); - } - - @Override - public String toString() { - return "CanBlock"; - } -} diff --git a/Mage/src/mage/filter/common/FilterCreatureForCombatBase.java b/Mage/src/mage/filter/common/FilterCreatureForCombatBase.java new file mode 100644 index 0000000000..a7a14999f6 --- /dev/null +++ b/Mage/src/mage/filter/common/FilterCreatureForCombatBase.java @@ -0,0 +1,91 @@ +/* +* 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.filter.common; + +import mage.filter.predicate.Predicate; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.permanent.AttackingPredicate; +import mage.filter.predicate.permanent.TappedPredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; + + +/** + * + * @author BetaSteward_at_googlemail.com + * @author North + */ +public class FilterCreatureForCombatBase extends FilterCreaturePermanent { + + public FilterCreatureForCombatBase() { + this(""); + } + + public FilterCreatureForCombatBase(String name) { + super(name); + this.add(Predicates.not(new AttackingPredicate())); + this.add(new PhasedInPredicate()); + this.add(new CanBlockPredicate()); + } + + public FilterCreatureForCombatBase(final FilterCreatureForCombatBase filter) { + super(filter); + } + + @Override + public FilterCreatureForCombatBase copy() { + return new FilterCreatureForCombatBase(this); + } +} + +class PhasedInPredicate implements Predicate { + + @Override + public boolean apply(Permanent input, Game game) { + return input.isPhasedIn(); + } + + @Override + public String toString() { + return "PhasedIn"; + } +} + +class CanBlockPredicate implements Predicate { + + @Override + public boolean apply(Permanent input, Game game) { + return input.getMaxBlocks() == 0 || input.getBlocking() < input.getMaxBlocks(); + } + + @Override + public String toString() { + return "CanBlock"; + } +} diff --git a/Mage/src/mage/filter/common/FilterCreatureForCombatBlock.java b/Mage/src/mage/filter/common/FilterCreatureForCombatBlock.java new file mode 100644 index 0000000000..db405b4bbe --- /dev/null +++ b/Mage/src/mage/filter/common/FilterCreatureForCombatBlock.java @@ -0,0 +1,72 @@ +/* +* 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.filter.common; + +import mage.constants.AsThoughEffectType; +import mage.filter.predicate.Predicate; +import mage.game.Game; +import mage.game.permanent.Permanent; + +/** + * + * @author LevelX2 + */ +public class FilterCreatureForCombatBlock extends FilterCreatureForCombatBase { + + public FilterCreatureForCombatBlock() { + this(""); + } + + public FilterCreatureForCombatBlock(String name) { + super(name); + this.add(new BlockTappedPredicate()); + } + + public FilterCreatureForCombatBlock(final FilterCreatureForCombatBlock filter) { + super(filter); + } + + @Override + public FilterCreatureForCombatBlock copy() { + return new FilterCreatureForCombatBlock(this); + } +} + +class BlockTappedPredicate implements Predicate { + + @Override + public boolean apply(Permanent input, Game game) { + return !input.isTapped() || game.getState().getContinuousEffects().asThough(input.getId(), AsThoughEffectType.BLOCK_TAPPED, game); + } + + @Override + public String toString() { + return "untapped or can block tapped"; + } +} diff --git a/Mage/src/mage/game/combat/Combat.java b/Mage/src/mage/game/combat/Combat.java index c28631fc45..d4e287f0dd 100644 --- a/Mage/src/mage/game/combat/Combat.java +++ b/Mage/src/mage/game/combat/Combat.java @@ -37,7 +37,7 @@ import mage.abilities.keyword.CanAttackOnlyAloneAbility; import mage.abilities.keyword.CantAttackAloneAbility; import mage.abilities.keyword.VigilanceAbility; import mage.filter.common.FilterControlledCreaturePermanent; -import mage.filter.common.FilterCreatureForCombat; +import mage.filter.common.FilterCreatureForCombatBlock; import mage.filter.common.FilterPlaneswalkerPermanent; import mage.game.Game; import mage.game.events.GameEvent; @@ -55,7 +55,7 @@ import mage.util.trace.TraceUtil; public class Combat implements Serializable, Copyable { private static FilterPlaneswalkerPermanent filterPlaneswalker = new FilterPlaneswalkerPermanent(); - private static FilterCreatureForCombat filterBlockers = new FilterCreatureForCombat(); + private static FilterCreatureForCombatBlock filterBlockers = new FilterCreatureForCombatBlock(); protected List groups = new ArrayList(); protected Map blockingGroups = new HashMap(); diff --git a/Mage/src/mage/game/permanent/PermanentImpl.java b/Mage/src/mage/game/permanent/PermanentImpl.java index 086f7ec0b9..ec09f63d44 100644 --- a/Mage/src/mage/game/permanent/PermanentImpl.java +++ b/Mage/src/mage/game/permanent/PermanentImpl.java @@ -863,7 +863,7 @@ public abstract class PermanentImpl> extends CardImpl @Override public boolean canBlock(UUID attackerId, Game game) { - if (tapped) { + if (tapped && !game.getState().getContinuousEffects().asThough(this.getId(), AsThoughEffectType.BLOCK_TAPPED, game)) { return false; } Permanent attacker = game.getPermanent(attackerId); diff --git a/Mage/src/mage/players/PlayerImpl.java b/Mage/src/mage/players/PlayerImpl.java index f8f45afed4..a68b5bac22 100644 --- a/Mage/src/mage/players/PlayerImpl.java +++ b/Mage/src/mage/players/PlayerImpl.java @@ -83,6 +83,7 @@ import mage.counters.CounterType; import mage.counters.Counters; import mage.filter.FilterCard; import mage.filter.common.FilterCreatureForCombat; +import mage.filter.common.FilterCreatureForCombatBlock; import mage.game.ExileZone; import mage.game.Game; import mage.game.combat.CombatGroup; @@ -1468,7 +1469,7 @@ public abstract class PlayerImpl> implements Player, Ser @Override public List getAvailableBlockers(Game game) { - FilterCreatureForCombat blockFilter = new FilterCreatureForCombat(); + FilterCreatureForCombatBlock blockFilter = new FilterCreatureForCombatBlock(); List blockers = game.getBattlefield().getAllActivePermanents(blockFilter, playerId, game); return blockers; }