From 0ce1f507340358f70a2641b11150bbcedc461d7b Mon Sep 17 00:00:00 2001 From: BetaSteward Date: Sun, 19 Dec 2010 00:56:45 -0500 Subject: [PATCH] redesigned evasion abilities and added restriction and requirement effects --- .../mage/sets/conflux/InkwellLeviathan.java | 2 +- .../mage/sets/magic2010/AlluringSiren.java | 15 +- .../src/mage/sets/magic2010/BogWraith.java | 2 +- .../src/mage/sets/magic2010/EmeraldOryx.java | 2 +- .../mage/sets/magic2010/PrizedUnicorn.java | 1 + .../src/mage/sets/magic2011/BogRaiders.java | 2 +- .../src/mage/sets/magic2011/DryadsFavor.java | 2 +- .../mage/sets/magic2011/HarborSerpent.java | 2 +- Mage.Sets/src/mage/sets/magic2011/Incite.java | 6 +- .../src/mage/sets/magic2011/MerfolkSpy.java | 2 +- .../sets/magic2011/StormtideLeviathan.java | 6 +- .../mage/sets/magic2011/VolcanicStrength.java | 2 +- .../mage/sets/ravnika/GrayscaledGharial.java | 2 +- .../sets/riseoftheeldrazi/GideonJura.java | 45 +++--- .../sets/shardsofalara/GoblinMountaineer.java | 2 +- Mage.Sets/src/mage/sets/tenth/Juggernaut.java | 38 +++-- Mage.Sets/src/mage/sets/tenth/Pacifism.java | 51 +++---- .../src/mage/sets/zendikar/CliffThreader.java | 2 +- .../src/mage/sets/zendikar/RiverBoa.java | 2 +- Mage/src/mage/Constants.java | 7 +- Mage/src/mage/abilities/Abilities.java | 1 + Mage/src/mage/abilities/AbilitiesImpl.java | 19 +-- Mage/src/mage/abilities/EvasionAbility.java | 15 +- .../mage/abilities/EvasionAbilityImpl.java | 48 ------- .../common/AttacksEachTurnStaticAbility.java | 48 +------ .../abilities/effects/ContinuousEffect.java | 1 + .../effects/ContinuousEffectImpl.java | 5 + .../abilities/effects/ContinuousEffects.java | 134 ++++++++++++++---- .../abilities/effects/RequirementEffect.java | 73 ++++++++++ ...tackEffect.java => RestrictionEffect.java} | 30 ++-- .../common/AttacksIfAbleSourceEffect.java | 82 +++++++++++ .../common/AttacksIfAbleTargetEffect.java | 43 +++--- .../common/CantAttackSourceEffect.java | 69 +++++++++ .../effects/common/CantBlockSourceEffect.java | 69 +++++++++ .../effects/common/MustBlockSourceEffect.java | 50 +++---- .../mage/abilities/keyword/FlyingAbility.java | 48 +++++-- .../abilities/keyword/ForestwalkAbility.java | 25 ++-- .../abilities/keyword/IslandwalkAbility.java | 25 ++-- .../abilities/keyword/LandwalkAbility.java | 47 ++++-- .../keyword/MountainwalkAbility.java | 25 ++-- .../abilities/keyword/SwampwalkAbility.java | 25 ++-- .../abilities/keyword/UnblockableAbility.java | 44 +++++- Mage/src/mage/game/combat/Combat.java | 61 +++++++- .../mage/game/permanent/PermanentImpl.java | 15 +- 44 files changed, 839 insertions(+), 356 deletions(-) delete mode 100644 Mage/src/mage/abilities/EvasionAbilityImpl.java create mode 100644 Mage/src/mage/abilities/effects/RequirementEffect.java rename Mage/src/mage/abilities/effects/{RequirementAttackEffect.java => RestrictionEffect.java} (74%) create mode 100644 Mage/src/mage/abilities/effects/common/AttacksIfAbleSourceEffect.java create mode 100644 Mage/src/mage/abilities/effects/common/CantAttackSourceEffect.java create mode 100644 Mage/src/mage/abilities/effects/common/CantBlockSourceEffect.java diff --git a/Mage.Sets/src/mage/sets/conflux/InkwellLeviathan.java b/Mage.Sets/src/mage/sets/conflux/InkwellLeviathan.java index e6fbf5db2c8..b7104382297 100644 --- a/Mage.Sets/src/mage/sets/conflux/InkwellLeviathan.java +++ b/Mage.Sets/src/mage/sets/conflux/InkwellLeviathan.java @@ -51,7 +51,7 @@ public class InkwellLeviathan extends CardImpl { this.power = new MageInt(7); this.toughness = new MageInt(11); - this.addAbility(IslandwalkAbility.getInstance()); + this.addAbility(new IslandwalkAbility()); this.addAbility(TrampleAbility.getInstance()); this.addAbility(ShroudAbility.getInstance()); } diff --git a/Mage.Sets/src/mage/sets/magic2010/AlluringSiren.java b/Mage.Sets/src/mage/sets/magic2010/AlluringSiren.java index 3f91805e453..219171a4c8e 100644 --- a/Mage.Sets/src/mage/sets/magic2010/AlluringSiren.java +++ b/Mage.Sets/src/mage/sets/magic2010/AlluringSiren.java @@ -38,7 +38,8 @@ import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.TapSourceCost; -import mage.abilities.effects.RequirementAttackEffect; +import mage.abilities.effects.RequirementEffect; +import mage.abilities.effects.common.AttacksIfAbleTargetEffect; import mage.cards.CardImpl; import mage.filter.common.FilterCreaturePermanent; import mage.game.Game; @@ -85,7 +86,7 @@ public class AlluringSiren extends CardImpl { } -class AlluringSirenEffect extends RequirementAttackEffect { +class AlluringSirenEffect extends AttacksIfAbleTargetEffect { public AlluringSirenEffect() { super(Duration.EndOfTurn); @@ -101,14 +102,8 @@ class AlluringSirenEffect extends RequirementAttackEffect { } @Override - public boolean apply(Game game, Ability source) { - Permanent creature = game.getPermanent(source.getFirstTarget()); - if (creature != null) { - if (creature.canAttack(game)) { - game.getCombat().declareAttacker(creature.getId(), source.getControllerId(), game); - } - } - return false; + public UUID mustAttackDefender(Ability source, Game game) { + return source.getControllerId(); } @Override diff --git a/Mage.Sets/src/mage/sets/magic2010/BogWraith.java b/Mage.Sets/src/mage/sets/magic2010/BogWraith.java index 85cfdfea80c..d752f453dff 100644 --- a/Mage.Sets/src/mage/sets/magic2010/BogWraith.java +++ b/Mage.Sets/src/mage/sets/magic2010/BogWraith.java @@ -48,7 +48,7 @@ public class BogWraith extends CardImpl { this.subtype.add("Wraith"); this.power = new MageInt(3); this.toughness = new MageInt(3); - this.addAbility(SwampwalkAbility.getInstance()); + this.addAbility(new SwampwalkAbility()); } public BogWraith(final BogWraith card) { diff --git a/Mage.Sets/src/mage/sets/magic2010/EmeraldOryx.java b/Mage.Sets/src/mage/sets/magic2010/EmeraldOryx.java index fb545b42df7..d25730fe84d 100644 --- a/Mage.Sets/src/mage/sets/magic2010/EmeraldOryx.java +++ b/Mage.Sets/src/mage/sets/magic2010/EmeraldOryx.java @@ -48,7 +48,7 @@ public class EmeraldOryx extends CardImpl { this.subtype.add("Antelope"); this.power = new MageInt(2); this.toughness = new MageInt(3); - this.addAbility(ForestwalkAbility.getInstance()); + this.addAbility(new ForestwalkAbility()); } public EmeraldOryx(final EmeraldOryx card) { diff --git a/Mage.Sets/src/mage/sets/magic2010/PrizedUnicorn.java b/Mage.Sets/src/mage/sets/magic2010/PrizedUnicorn.java index efb65e65825..95117d54e22 100644 --- a/Mage.Sets/src/mage/sets/magic2010/PrizedUnicorn.java +++ b/Mage.Sets/src/mage/sets/magic2010/PrizedUnicorn.java @@ -30,6 +30,7 @@ package mage.sets.magic2010; import java.util.UUID; import mage.Constants.CardType; +import mage.Constants.Duration; import mage.Constants.Rarity; import mage.Constants.Zone; import mage.MageInt; diff --git a/Mage.Sets/src/mage/sets/magic2011/BogRaiders.java b/Mage.Sets/src/mage/sets/magic2011/BogRaiders.java index ae58237b2c6..ff40ca1e8f6 100644 --- a/Mage.Sets/src/mage/sets/magic2011/BogRaiders.java +++ b/Mage.Sets/src/mage/sets/magic2011/BogRaiders.java @@ -48,7 +48,7 @@ public class BogRaiders extends CardImpl { this.subtype.add("Zombie"); this.power = new MageInt(2); this.toughness = new MageInt(2); - this.addAbility(SwampwalkAbility.getInstance()); + this.addAbility(new SwampwalkAbility()); } public BogRaiders(final BogRaiders card) { diff --git a/Mage.Sets/src/mage/sets/magic2011/DryadsFavor.java b/Mage.Sets/src/mage/sets/magic2011/DryadsFavor.java index fe3cd04397c..c2517cb32d4 100644 --- a/Mage.Sets/src/mage/sets/magic2011/DryadsFavor.java +++ b/Mage.Sets/src/mage/sets/magic2011/DryadsFavor.java @@ -108,7 +108,7 @@ class DryadsFavorEffect extends ContinuousEffectImpl { switch (layer) { case AbilityAddingRemovingEffects_6: if (sublayer == SubLayer.NA) { - creature.addAbility(ForestwalkAbility.getInstance()); + creature.addAbility(new ForestwalkAbility()); } break; } diff --git a/Mage.Sets/src/mage/sets/magic2011/HarborSerpent.java b/Mage.Sets/src/mage/sets/magic2011/HarborSerpent.java index 2fd9aadedbc..20a7791643c 100644 --- a/Mage.Sets/src/mage/sets/magic2011/HarborSerpent.java +++ b/Mage.Sets/src/mage/sets/magic2011/HarborSerpent.java @@ -60,7 +60,7 @@ public class HarborSerpent extends CardImpl { this.power = new MageInt(5); this.toughness = new MageInt(5); - this.addAbility(IslandwalkAbility.getInstance()); + this.addAbility(new IslandwalkAbility()); this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new HarborSerpentEffect())); } diff --git a/Mage.Sets/src/mage/sets/magic2011/Incite.java b/Mage.Sets/src/mage/sets/magic2011/Incite.java index 773bf16c8ba..f6a08f1fdaf 100644 --- a/Mage.Sets/src/mage/sets/magic2011/Incite.java +++ b/Mage.Sets/src/mage/sets/magic2011/Incite.java @@ -55,7 +55,7 @@ public class Incite extends CardImpl { this.color.setRed(true); this.getSpellAbility().addTarget(new TargetCreaturePermanent()); this.getSpellAbility().addEffect(new InciteEffect()); - this.getSpellAbility().addEffect(new AttacksIfAbleTargetEffect()); + this.getSpellAbility().addEffect(new AttacksIfAbleTargetEffect(Duration.EndOfTurn)); } public Incite(final Incite card) { @@ -93,6 +93,10 @@ class InciteEffect extends ContinuousEffectImpl { Permanent permanent = game.getPermanent(source.getFirstTarget()); if (permanent != null) { permanent.getColor().setRed(true); + permanent.getColor().setWhite(false); + permanent.getColor().setGreen(false); + permanent.getColor().setBlue(false); + permanent.getColor().setBlack(false); return true; } return false; diff --git a/Mage.Sets/src/mage/sets/magic2011/MerfolkSpy.java b/Mage.Sets/src/mage/sets/magic2011/MerfolkSpy.java index 41d47a7f27d..ac8a9161808 100644 --- a/Mage.Sets/src/mage/sets/magic2011/MerfolkSpy.java +++ b/Mage.Sets/src/mage/sets/magic2011/MerfolkSpy.java @@ -58,7 +58,7 @@ public class MerfolkSpy extends CardImpl { this.power = new MageInt(1); this.toughness = new MageInt(1); - this.addAbility(IslandwalkAbility.getInstance()); + this.addAbility(new IslandwalkAbility()); this.addAbility(new DealsCombatDamageToAPlayerTriggeredAbility(new MerfolkSpyEffect(), false)); } diff --git a/Mage.Sets/src/mage/sets/magic2011/StormtideLeviathan.java b/Mage.Sets/src/mage/sets/magic2011/StormtideLeviathan.java index e7b9fc0c2d9..172c8b9d756 100644 --- a/Mage.Sets/src/mage/sets/magic2011/StormtideLeviathan.java +++ b/Mage.Sets/src/mage/sets/magic2011/StormtideLeviathan.java @@ -65,7 +65,7 @@ public class StormtideLeviathan extends CardImpl { this.power = new MageInt(8); this.toughness = new MageInt(8); - this.addAbility(IslandwalkAbility.getInstance()); + this.addAbility(new IslandwalkAbility()); this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new StormtideLeviathanEffect())); this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new StormtideLeviathanEffect2())); @@ -119,6 +119,8 @@ class StormtideLeviathanEffect extends ContinuousEffectImpl { + private static IslandwalkAbility islandwalk = new IslandwalkAbility(); + public StormtideLeviathanEffect2() { super(Duration.WhileOnBattlefield, Outcome.Detriment); } @@ -150,7 +152,7 @@ class StormtideLeviathanEffect2 extends ReplacementEffectImpl { this.color.setBlue(true); this.power = new MageInt(1); this.toughness = new MageInt(1); - this.addAbility(IslandwalkAbility.getInstance()); + this.addAbility(new IslandwalkAbility()); } public GrayscaledGharial (final GrayscaledGharial card) { diff --git a/Mage.Sets/src/mage/sets/riseoftheeldrazi/GideonJura.java b/Mage.Sets/src/mage/sets/riseoftheeldrazi/GideonJura.java index bf8d67c5da4..8804ff9b158 100644 --- a/Mage.Sets/src/mage/sets/riseoftheeldrazi/GideonJura.java +++ b/Mage.Sets/src/mage/sets/riseoftheeldrazi/GideonJura.java @@ -32,10 +32,11 @@ import java.util.UUID; import mage.Constants.CardType; import mage.Constants.Duration; import mage.Constants.Rarity; +import mage.Constants.TurnPhase; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.effects.RequirementAttackEffect; +import mage.abilities.effects.RequirementEffect; import mage.abilities.effects.common.BecomesCreatureSourceEOTEffect; import mage.abilities.effects.common.DestroyTargetEffect; import mage.abilities.effects.common.PreventAllDamageSourceEffect; @@ -112,10 +113,10 @@ class GideonJuraToken extends Token { } -class GideonJuraEffect extends RequirementAttackEffect { +class GideonJuraEffect extends RequirementEffect { public GideonJuraEffect() { - super(Duration.OneUse); + super(Duration.Custom); } public GideonJuraEffect(final GideonJuraEffect effect) { @@ -128,30 +129,32 @@ class GideonJuraEffect extends RequirementAttackEffect { } @Override - public boolean applies(GameEvent event, Ability source, Game game) { - if (event.getType().equals(EventType.DECLARE_ATTACKERS_STEP_PRE) && event.getPlayerId().equals(source.getFirstTarget())) - return true; - if (event.getType().equals(EventType.END_PHASE_POST) && event.getPlayerId().equals(source.getFirstTarget())) - used = true; - return false; + public boolean applies(Permanent permanent, Ability source, Game game) { + return permanent.getControllerId().equals(source.getFirstTarget()); } @Override - public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getFirstTarget()); - if (player != null) { - for (Permanent creature: game.getBattlefield().getAllActivePermanents(new FilterCreatureForCombat(), player.getId())) { - if (creature.canAttack(game)) { - game.getCombat().declareAttacker(creature.getId(), source.getSourceId(), game); - } - } - return true; - } - return false; + public boolean isInactive(Ability source, Game game) { + return (game.getPhase().getType() == TurnPhase.END && game.getActivePlayerId().equals(source.getFirstTarget())); } @Override public String getText(Ability source) { - return "During target opponent's next turn, creatures that player controls attack {this} if able"; + return "During target opponent's next turn, creatures that player controls attack Gideon Jura if able"; + } + + @Override + public UUID mustAttackDefender(Ability source, Game game) { + return source.getSourceId(); + } + + @Override + public boolean mustAttack(Game game) { + return true; + } + + @Override + public boolean mustBlock(Game game) { + return false; } } \ No newline at end of file diff --git a/Mage.Sets/src/mage/sets/shardsofalara/GoblinMountaineer.java b/Mage.Sets/src/mage/sets/shardsofalara/GoblinMountaineer.java index 38792195c74..c763ca4f076 100644 --- a/Mage.Sets/src/mage/sets/shardsofalara/GoblinMountaineer.java +++ b/Mage.Sets/src/mage/sets/shardsofalara/GoblinMountaineer.java @@ -49,7 +49,7 @@ public class GoblinMountaineer extends CardImpl { this.color.setRed(true); this.power = new MageInt(1); this.toughness = new MageInt(1); - this.addAbility(MountainwalkAbility.getInstance()); + this.addAbility(new MountainwalkAbility()); } public GoblinMountaineer (final GoblinMountaineer card) { diff --git a/Mage.Sets/src/mage/sets/tenth/Juggernaut.java b/Mage.Sets/src/mage/sets/tenth/Juggernaut.java index 9f37b2116c5..ff15f86842a 100644 --- a/Mage.Sets/src/mage/sets/tenth/Juggernaut.java +++ b/Mage.Sets/src/mage/sets/tenth/Juggernaut.java @@ -30,11 +30,12 @@ package mage.sets.tenth; import java.util.UUID; import mage.Constants.CardType; +import mage.Constants.Duration; import mage.Constants.Rarity; import mage.MageInt; -import mage.abilities.EvasionAbilityImpl; +import mage.abilities.EvasionAbility; import mage.abilities.common.AttacksEachTurnStaticAbility; -import mage.abilities.keyword.DefenderAbility; +import mage.abilities.effects.common.CantBlockSourceEffect; import mage.cards.CardImpl; import mage.game.Game; import mage.game.permanent.Permanent; @@ -72,19 +73,16 @@ public class Juggernaut extends CardImpl { } -class JuggernautAbility extends EvasionAbilityImpl { +class JuggernautAbility extends EvasionAbility { - public JuggernautAbility() {} + public JuggernautAbility() { + this.addEffect(new JuggernautEffect()); + } public JuggernautAbility(final JuggernautAbility ability) { super(ability); } - @Override - public boolean canBlock(Permanent blocker, Game game) { - return !blocker.getSubtype().contains("Wall"); - } - @Override public String getRule() { return "Juggernaut can't be blocked by Walls."; @@ -96,3 +94,25 @@ class JuggernautAbility extends EvasionAbilityImpl { } } + +class JuggernautEffect extends CantBlockSourceEffect { + + public JuggernautEffect() { + super(Duration.WhileOnBattlefield); + } + + public JuggernautEffect(final JuggernautEffect effect) { + super(effect); + } + + @Override + public boolean canBlock(Permanent blocker, Game game) { + return !blocker.getSubtype().contains("Wall"); + } + + @Override + public JuggernautEffect copy() { + return new JuggernautEffect(this); + } + +} diff --git a/Mage.Sets/src/mage/sets/tenth/Pacifism.java b/Mage.Sets/src/mage/sets/tenth/Pacifism.java index 336a37a3830..66b5c25661f 100644 --- a/Mage.Sets/src/mage/sets/tenth/Pacifism.java +++ b/Mage.Sets/src/mage/sets/tenth/Pacifism.java @@ -36,13 +36,11 @@ import mage.Constants.Rarity; import mage.Constants.Zone; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.effects.ReplacementEffectImpl; +import mage.abilities.effects.RestrictionEffect; import mage.abilities.effects.common.AttachEffect; import mage.abilities.keyword.EnchantAbility; import mage.cards.CardImpl; import mage.game.Game; -import mage.game.events.GameEvent; -import mage.game.events.GameEvent.EventType; import mage.game.permanent.Permanent; import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; @@ -83,47 +81,42 @@ public class Pacifism extends CardImpl { } } -class PacifismEffect extends ReplacementEffectImpl { +class PacifismEffect extends RestrictionEffect { public PacifismEffect() { - super(Duration.WhileOnBattlefield, Outcome.Detriment); + super(Duration.WhileOnBattlefield); } public PacifismEffect(final PacifismEffect effect) { super(effect); } + @Override + public boolean applies(Permanent permanent, Ability source, Game game) { + if (permanent.getAttachments().contains((source.getSourceId()))) { + return true; + } + return false; + } + + @Override + public boolean canAttack(Game game) { + return false; + } + + @Override + public boolean canBlock(Permanent blocker, Game game) { + return false; + } + @Override public PacifismEffect copy() { return new PacifismEffect(this); } - @Override - public boolean apply(Game game, Ability source) { - return true; - } - - @Override - public boolean replaceEvent(GameEvent event, Ability source, Game game) { - return true; - } - - @Override - public boolean applies(GameEvent event, Ability source, Game game) { - if (event.getType() == EventType.DECLARE_ATTACKER || event.getType() == EventType.DECLARE_BLOCKER) { - Permanent enchantment = game.getPermanent(source.getSourceId()); - if (enchantment != null && enchantment.getAttachedTo() != null) { - if (event.getSourceId().equals(enchantment.getAttachedTo())) { - return true; - } - } - } - return false; - } - @Override public String getText(Ability source) { return "Enchanted creature can't attack or block"; } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/sets/zendikar/CliffThreader.java b/Mage.Sets/src/mage/sets/zendikar/CliffThreader.java index 1c9581caf98..c8e97d500a7 100644 --- a/Mage.Sets/src/mage/sets/zendikar/CliffThreader.java +++ b/Mage.Sets/src/mage/sets/zendikar/CliffThreader.java @@ -49,7 +49,7 @@ public class CliffThreader extends CardImpl { this.color.setWhite(true); this.power = new MageInt(2); this.toughness = new MageInt(1); - this.addAbility(MountainwalkAbility.getInstance()); + this.addAbility(new MountainwalkAbility()); } public CliffThreader (final CliffThreader card) { diff --git a/Mage.Sets/src/mage/sets/zendikar/RiverBoa.java b/Mage.Sets/src/mage/sets/zendikar/RiverBoa.java index f77b4e289bd..9c757ed241d 100644 --- a/Mage.Sets/src/mage/sets/zendikar/RiverBoa.java +++ b/Mage.Sets/src/mage/sets/zendikar/RiverBoa.java @@ -52,7 +52,7 @@ public class RiverBoa extends CardImpl { this.subtype.add("Snake"); this.power = new MageInt(2); this.toughness = new MageInt(1); - this.addAbility(IslandwalkAbility.getInstance()); + this.addAbility(new IslandwalkAbility()); this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new RegenerateSourceEffect(), new ManaCostsImpl("{G}"))); } diff --git a/Mage/src/mage/Constants.java b/Mage/src/mage/Constants.java index 572feb24ffd..292fcbc3abc 100644 --- a/Mage/src/mage/Constants.java +++ b/Mage/src/mage/Constants.java @@ -146,7 +146,9 @@ public final class Constants { REPLACEMENT("Replacement Effect"), PREVENTION("Prevention Effect"), REDIRECTION("Redirection Effect"), - ASTHOUGH("As Though Effect"); + ASTHOUGH("As Though Effect"), + RESTRICTION("Restriction Effect"), + REQUIREMENT("Requirement Effect"); private String text; @@ -176,7 +178,8 @@ public final class Constants { WhileOnBattlefield(""), WhileOnStack(""), EndOfTurn("until end of turn"), - EndOfCombat("until end of combat"); + EndOfCombat("until end of combat"), + Custom(""); private String text; diff --git a/Mage/src/mage/abilities/Abilities.java b/Mage/src/mage/abilities/Abilities.java index 78af1b21b69..84fa54f9061 100644 --- a/Mage/src/mage/abilities/Abilities.java +++ b/Mage/src/mage/abilities/Abilities.java @@ -55,6 +55,7 @@ public interface Abilities extends List, Serializable { public boolean containsKey(UUID abilityId); public T get(UUID abilityId); + public boolean contains(T ability); public boolean containsAll(Abilities abilities); public Abilities copy(); diff --git a/Mage/src/mage/abilities/AbilitiesImpl.java b/Mage/src/mage/abilities/AbilitiesImpl.java index 661a3b77b98..ae40e84139e 100644 --- a/Mage/src/mage/abilities/AbilitiesImpl.java +++ b/Mage/src/mage/abilities/AbilitiesImpl.java @@ -177,19 +177,22 @@ public class AbilitiesImpl extends ArrayList implements Ab } } + @Override + public boolean contains(T ability) { + for (T test: this) { + if (ability.getId().equals(test.getId()) || ability.getRule().equals(test.getRule())) { + return true; + } + } + return false; + } + @Override public boolean containsAll(Abilities abilities) { if (this.size() < abilities.size()) return false; for (T ability: abilities) { - boolean found = false; - for (T test: this) { - if (ability.getId().equals(test.getId()) || ability.getRule().equals(test.getRule())) { - found = true; - break; - } - } - if (!found) + if (!contains(ability)) return false; } return true; diff --git a/Mage/src/mage/abilities/EvasionAbility.java b/Mage/src/mage/abilities/EvasionAbility.java index a8a2c0b19b0..097e1bcacda 100644 --- a/Mage/src/mage/abilities/EvasionAbility.java +++ b/Mage/src/mage/abilities/EvasionAbility.java @@ -28,16 +28,21 @@ package mage.abilities; -import java.util.UUID; -import mage.game.Game; -import mage.game.permanent.Permanent; +import mage.Constants.AbilityType; +import mage.Constants.Zone; /** * * @author BetaSteward_at_googlemail.com */ -public interface EvasionAbility extends Ability { +public abstract class EvasionAbility> extends StaticAbility { - public boolean canBlock(Permanent blocker, Game game); + public EvasionAbility() { + super(AbilityType.EVASION, Zone.BATTLEFIELD); + } + + public EvasionAbility(final EvasionAbility ability) { + super(ability); + } } diff --git a/Mage/src/mage/abilities/EvasionAbilityImpl.java b/Mage/src/mage/abilities/EvasionAbilityImpl.java deleted file mode 100644 index 9f89cacf323..00000000000 --- a/Mage/src/mage/abilities/EvasionAbilityImpl.java +++ /dev/null @@ -1,48 +0,0 @@ -/* -* 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; - -import mage.Constants.AbilityType; -import mage.Constants.Zone; - -/** - * - * @author BetaSteward_at_googlemail.com - */ -public abstract class EvasionAbilityImpl> extends StaticAbility implements EvasionAbility { - - public EvasionAbilityImpl() { - super(AbilityType.EVASION, Zone.BATTLEFIELD); - } - - public EvasionAbilityImpl(final EvasionAbilityImpl ability) { - super(ability); - } - -} diff --git a/Mage/src/mage/abilities/common/AttacksEachTurnStaticAbility.java b/Mage/src/mage/abilities/common/AttacksEachTurnStaticAbility.java index 2a8febd54b5..de981703717 100644 --- a/Mage/src/mage/abilities/common/AttacksEachTurnStaticAbility.java +++ b/Mage/src/mage/abilities/common/AttacksEachTurnStaticAbility.java @@ -29,15 +29,9 @@ package mage.abilities.common; import mage.Constants.Duration; -import mage.Constants.Outcome; import mage.Constants.Zone; -import mage.abilities.Ability; import mage.abilities.StaticAbility; -import mage.abilities.effects.RequirementAttackEffect; -import mage.game.Game; -import mage.game.permanent.Permanent; -import mage.players.Player; -import mage.target.common.TargetDefender; +import mage.abilities.effects.common.AttacksIfAbleSourceEffect; /** * @@ -46,7 +40,7 @@ import mage.target.common.TargetDefender; public class AttacksEachTurnStaticAbility extends StaticAbility { public AttacksEachTurnStaticAbility() { - super(Zone.BATTLEFIELD, new AttacksEachTurnEffect()); + super(Zone.BATTLEFIELD, new AttacksIfAbleSourceEffect(Duration.WhileOnBattlefield)); } public AttacksEachTurnStaticAbility(AttacksEachTurnStaticAbility ability) { @@ -59,41 +53,3 @@ public class AttacksEachTurnStaticAbility extends StaticAbility { - - public AttacksEachTurnEffect() { - super(Duration.WhileOnBattlefield); - } - - public AttacksEachTurnEffect(final AttacksEachTurnEffect effect) { - super(effect); - } - - @Override - public boolean apply(Game game, Ability source) { - Permanent creature = game.getPermanent(source.getSourceId()); - if (creature != null) { - if (creature.canAttack(game)) { - TargetDefender target = new TargetDefender(game.getCombat().getDefenders(), creature.getControllerId()); - target.setRequired(true); - Player controller = game.getPlayer(creature.getControllerId()); - while (!target.isChosen()) - controller.chooseTarget(Outcome.Damage, target, source, game); - game.getCombat().declareAttacker(creature.getId(), target.getFirstTarget(), game); - return true; - } - } - return false; - } - - @Override - public String getText(Ability source) { - return "{this} attacks each turn if able."; - } - - @Override - public AttacksEachTurnEffect copy() { - return new AttacksEachTurnEffect(this); - } -} \ No newline at end of file diff --git a/Mage/src/mage/abilities/effects/ContinuousEffect.java b/Mage/src/mage/abilities/effects/ContinuousEffect.java index 29be96c7be0..2ec838aec36 100644 --- a/Mage/src/mage/abilities/effects/ContinuousEffect.java +++ b/Mage/src/mage/abilities/effects/ContinuousEffect.java @@ -48,6 +48,7 @@ public interface ContinuousEffect> extends Effect< public void newId(); public boolean apply(Layer layer, SubLayer sublayer, Ability source, Game game); public boolean hasLayer(Layer layer); + public boolean isInactive(Ability source, Game game); public void init(Ability source, Game game); } diff --git a/Mage/src/mage/abilities/effects/ContinuousEffectImpl.java b/Mage/src/mage/abilities/effects/ContinuousEffectImpl.java index a6d4f75a4a9..f477df87e85 100644 --- a/Mage/src/mage/abilities/effects/ContinuousEffectImpl.java +++ b/Mage/src/mage/abilities/effects/ContinuousEffectImpl.java @@ -145,4 +145,9 @@ public abstract class ContinuousEffectImpl> ex } } + @Override + public boolean isInactive(Ability source, Game game) { + return false; + } + } diff --git a/Mage/src/mage/abilities/effects/ContinuousEffects.java b/Mage/src/mage/abilities/effects/ContinuousEffects.java index 34b04ac49d9..08f44cbc2f3 100644 --- a/Mage/src/mage/abilities/effects/ContinuousEffects.java +++ b/Mage/src/mage/abilities/effects/ContinuousEffects.java @@ -45,6 +45,7 @@ import mage.Constants.Layer; import mage.Constants.SubLayer; import mage.Constants.Zone; import mage.abilities.Ability; +import mage.abilities.StaticAbility; import mage.cards.Card; import mage.game.Game; import mage.game.events.GameEvent; @@ -61,6 +62,8 @@ public class ContinuousEffects implements Serializable { private final List layeredEffects = new ArrayList(); private final List replacementEffects = new ArrayList(); private final List preventionEffects = new ArrayList(); + private final List requirementEffects = new ArrayList(); + private final List restrictionEffects = new ArrayList(); private final List asThoughEffects = new ArrayList(); //map Abilities to Continuous effects @@ -86,6 +89,12 @@ public class ContinuousEffects implements Serializable { for (PreventionEffect entry: effect.preventionEffects) { preventionEffects.add((PreventionEffect)entry.copy()); } + for (RequirementEffect entry: effect.requirementEffects) { + requirementEffects.add((RequirementEffect)entry.copy()); + } + for (RestrictionEffect entry: effect.restrictionEffects) { + restrictionEffects.add((RestrictionEffect)entry.copy()); + } for (AsThoughEffect entry: effect.asThoughEffects) { asThoughEffects.add((AsThoughEffect)entry.copy()); } @@ -98,6 +107,18 @@ public class ContinuousEffects implements Serializable { return new ContinuousEffects(this); } + public List getRequirementEffects() { + return requirementEffects; + } + + public List getRestrictionEffects() { + return restrictionEffects; + } + + public Ability getAbility(UUID effectId) { + return abilityMap.get(effectId); + } + public void removeEndOfTurnEffects() { for (Iterator i = layeredEffects.iterator(); i.hasNext();) { ContinuousEffect entry = i.next(); @@ -114,6 +135,16 @@ public class ContinuousEffects implements Serializable { if (entry.getDuration() == Duration.EndOfTurn) i.remove(); } + for (Iterator i = requirementEffects.iterator(); i.hasNext();) { + ContinuousEffect entry = i.next(); + if (entry.getDuration() == Duration.EndOfTurn) + i.remove(); + } + for (Iterator i = restrictionEffects.iterator(); i.hasNext();) { + ContinuousEffect entry = i.next(); + if (entry.getDuration() == Duration.EndOfTurn) + i.remove(); + } for (Iterator i = asThoughEffects.iterator(); i.hasNext();) { ContinuousEffect entry = i.next(); if (entry.getDuration() == Duration.EndOfTurn) @@ -123,47 +154,44 @@ public class ContinuousEffects implements Serializable { public void removeInactiveEffects(Game game) { for (Iterator i = layeredEffects.iterator(); i.hasNext();) { - ContinuousEffect entry = i.next(); - if (entry.getDuration() == Duration.WhileOnBattlefield) { - Permanent permanent = game.getPermanent(abilityMap.get(entry.getId()).getSourceId()); - if (permanent == null || !permanent.isPhasedIn()) - i.remove(); - } - else if (entry.getDuration() == Duration.OneUse && entry.isUsed()) + if (isInactive(i.next(), game)) i.remove(); } for (Iterator i = replacementEffects.iterator(); i.hasNext();) { - ReplacementEffect entry = i.next(); - if (entry.getDuration() == Duration.WhileOnBattlefield) { - Permanent permanent = game.getPermanent(abilityMap.get(entry.getId()).getSourceId()); - if (permanent == null || !permanent.isPhasedIn()) - i.remove(); - } - else if (entry.getDuration() == Duration.OneUse && entry.isUsed()) + if (isInactive(i.next(), game)) i.remove(); } for (Iterator i = preventionEffects.iterator(); i.hasNext();) { - PreventionEffect entry = i.next(); - if (entry.getDuration() == Duration.WhileOnBattlefield) { - Permanent permanent = game.getPermanent(abilityMap.get(entry.getId()).getSourceId()); - if (permanent == null || !permanent.isPhasedIn()) - i.remove(); - } - else if (entry.getDuration() == Duration.OneUse && entry.isUsed()) + if (isInactive(i.next(), game)) + i.remove(); + } + for (Iterator i = requirementEffects.iterator(); i.hasNext();) { + if (isInactive(i.next(), game)) + i.remove(); + } + for (Iterator i = restrictionEffects.iterator(); i.hasNext();) { + if (isInactive(i.next(), game)) i.remove(); } for (Iterator i = asThoughEffects.iterator(); i.hasNext();) { - AsThoughEffect entry = i.next(); - if (entry.getDuration() == Duration.WhileOnBattlefield) { - Permanent permanent = game.getPermanent(abilityMap.get(entry.getId()).getSourceId()); - if (permanent == null || !permanent.isPhasedIn()) - i.remove(); - } - else if (entry.getDuration() == Duration.OneUse && entry.isUsed()) + if (isInactive(i.next(), game)) i.remove(); } } + private boolean isInactive(ContinuousEffect effect, Game game) { + switch(effect.getDuration()) { + case WhileOnBattlefield: + Permanent permanent = game.getPermanent(abilityMap.get(effect.getId()).getSourceId()); + return (permanent == null || !permanent.isPhasedIn()); + case OneUse: + return effect.isUsed(); + case Custom: + return effect.isInactive(abilityMap.get(effect.getId()), game); + } + return false; + } + private List getLayeredEffects(Game game) { List layerEffects = new ArrayList(layeredEffects); for (Card card: game.getCards()) { @@ -197,6 +225,46 @@ public class ContinuousEffects implements Serializable { return layerEffects; } + public List getApplicableRequirementEffects(Permanent permanent, Game game) { + List effects = new ArrayList(); + //get all applicable Requirement effects on the battlefield + for (Permanent perm: game.getBattlefield().getActivePermanents(permanent.getControllerId(), game)) { + for (StaticAbility ability: perm.getAbilities().getStaticAbilities(Zone.BATTLEFIELD)) { + for (Effect effect: ability.getEffects(EffectType.REQUIREMENT)) { + if (((RequirementEffect)effect).applies(permanent, ability, game)) { + effects.add((RequirementEffect) effect); + abilityMap.put(effect.getId(), ability); + } + } + } + } + for (RequirementEffect effect: requirementEffects) { + if (effect.applies(permanent, abilityMap.get(effect.getId()), game)) + effects.add(effect); + } + return effects; + } + + public List getApplicableRestrictionEffects(Permanent permanent, Game game) { + List effects = new ArrayList(); + //get all applicable Restriction effects on the battlefield + for (Permanent perm: game.getBattlefield().getActivePermanents(permanent.getControllerId(), game)) { + for (StaticAbility ability: perm.getAbilities().getStaticAbilities(Zone.BATTLEFIELD)) { + for (Effect effect: ability.getEffects(EffectType.RESTRICTION)) { + if (((RestrictionEffect)effect).applies(permanent, ability, game)) { + effects.add((RestrictionEffect) effect); + abilityMap.put(effect.getId(), ability); + } + } + } + } + for (RestrictionEffect effect: restrictionEffects) { + if (effect.applies(permanent, abilityMap.get(effect.getId()), game)) + effects.add(effect); + } + return effects; + } + /** * * @param event @@ -391,6 +459,16 @@ public class ContinuousEffects implements Serializable { preventionEffects.add(newPreventionEffect); abilityMap.put(newPreventionEffect.getId(), source); break; + case RESTRICTION: + RestrictionEffect newRestrictionEffect = (RestrictionEffect)effect; + restrictionEffects.add(newRestrictionEffect); + abilityMap.put(newRestrictionEffect.getId(), source); + break; + case REQUIREMENT: + RequirementEffect newRequirementEffect = (RequirementEffect)effect; + requirementEffects.add(newRequirementEffect); + abilityMap.put(newRequirementEffect.getId(), source); + break; case ASTHOUGH: AsThoughEffect newAsThoughEffect = (AsThoughEffect)effect; asThoughEffects.add(newAsThoughEffect); diff --git a/Mage/src/mage/abilities/effects/RequirementEffect.java b/Mage/src/mage/abilities/effects/RequirementEffect.java new file mode 100644 index 00000000000..925e388339b --- /dev/null +++ b/Mage/src/mage/abilities/effects/RequirementEffect.java @@ -0,0 +1,73 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ + +package mage.abilities.effects; + +import java.util.UUID; +import mage.Constants.Duration; +import mage.Constants.EffectType; +import mage.Constants.Outcome; +import mage.abilities.Ability; +import mage.game.Game; +import mage.game.permanent.Permanent; + +/** + * + * @author BetaSteward_at_googlemail.com + */ +public abstract class RequirementEffect> extends ContinuousEffectImpl { + + public RequirementEffect(Duration duration) { + super(duration, Outcome.Detriment); + this.effectType = EffectType.REQUIREMENT; + } + + public RequirementEffect(final RequirementEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source) { + throw new UnsupportedOperationException("Not supported."); + } + + public abstract boolean applies(Permanent permanent, Ability source, Game game); + + public abstract boolean mustAttack(Game game); + + public abstract boolean mustBlock(Game game); + + public UUID mustAttackDefender(Ability source, Game game) { + return null; + } + + public UUID mustBlockAttacker(Ability source, Game game) { + return null; + } + +} diff --git a/Mage/src/mage/abilities/effects/RequirementAttackEffect.java b/Mage/src/mage/abilities/effects/RestrictionEffect.java similarity index 74% rename from Mage/src/mage/abilities/effects/RequirementAttackEffect.java rename to Mage/src/mage/abilities/effects/RestrictionEffect.java index 9ac98e8685e..10bb3d49caa 100644 --- a/Mage/src/mage/abilities/effects/RequirementAttackEffect.java +++ b/Mage/src/mage/abilities/effects/RestrictionEffect.java @@ -29,38 +29,40 @@ package mage.abilities.effects; import mage.Constants.Duration; +import mage.Constants.EffectType; import mage.Constants.Outcome; import mage.abilities.Ability; import mage.game.Game; -import mage.game.events.GameEvent; -import mage.game.events.GameEvent.EventType; +import mage.game.permanent.Permanent; /** * * @author BetaSteward_at_googlemail.com */ -public abstract class RequirementAttackEffect> extends ReplacementEffectImpl { +public abstract class RestrictionEffect> extends ContinuousEffectImpl { - public RequirementAttackEffect(Duration duration) { + public RestrictionEffect(Duration duration) { super(duration, Outcome.Detriment); + this.effectType = EffectType.RESTRICTION; } - public RequirementAttackEffect(final RequirementAttackEffect effect) { + public RestrictionEffect(final RestrictionEffect effect) { super(effect); } @Override - public boolean replaceEvent(GameEvent event, Ability source, Game game) { - apply(game, source); - return false; + public boolean apply(Game game, Ability source) { + throw new UnsupportedOperationException("Not supported."); } - @Override - public boolean applies(GameEvent event, Ability source, Game game) { - if (event.getType().equals(EventType.DECLARE_ATTACKERS_STEP_PRE)) - return true; - return false; + public abstract boolean applies(Permanent permanent, Ability source, Game game); + + public boolean canAttack(Game game) { + return true; } - + public boolean canBlock(Permanent blocker, Game game) { + return true; + } + } diff --git a/Mage/src/mage/abilities/effects/common/AttacksIfAbleSourceEffect.java b/Mage/src/mage/abilities/effects/common/AttacksIfAbleSourceEffect.java new file mode 100644 index 00000000000..492762444a5 --- /dev/null +++ b/Mage/src/mage/abilities/effects/common/AttacksIfAbleSourceEffect.java @@ -0,0 +1,82 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ + +package mage.abilities.effects.common; + +import mage.Constants.Duration; +import mage.abilities.Ability; +import mage.abilities.effects.RequirementEffect; +import mage.game.Game; +import mage.game.permanent.Permanent; + +/** + * + * @author BetaSteward_at_googlemail.com + */ +public class AttacksIfAbleSourceEffect extends RequirementEffect { + + public AttacksIfAbleSourceEffect(Duration duration) { + super(duration); + } + + public AttacksIfAbleSourceEffect(final AttacksIfAbleSourceEffect effect) { + super(effect); + } + + @Override + public AttacksIfAbleSourceEffect copy() { + return new AttacksIfAbleSourceEffect(this); + } + + @Override + public boolean applies(Permanent permanent, Ability source, Game game) { + if (permanent.getId().equals(source.getSourceId())) { + return true; + } + return false; + } + + @Override + public boolean mustAttack(Game game) { + return true; + } + + @Override + public boolean mustBlock(Game game) { + return false; + } + + @Override + public String getText(Ability source) { + if (this.duration == Duration.EndOfTurn) + return "{this} attacks this turn if able"; + else + return "{this} attacks each turn if able"; + } + +} \ No newline at end of file diff --git a/Mage/src/mage/abilities/effects/common/AttacksIfAbleTargetEffect.java b/Mage/src/mage/abilities/effects/common/AttacksIfAbleTargetEffect.java index fc4d80593e4..250324e1bd9 100644 --- a/Mage/src/mage/abilities/effects/common/AttacksIfAbleTargetEffect.java +++ b/Mage/src/mage/abilities/effects/common/AttacksIfAbleTargetEffect.java @@ -29,22 +29,19 @@ package mage.abilities.effects.common; import mage.Constants.Duration; -import mage.Constants.Outcome; import mage.abilities.Ability; -import mage.abilities.effects.RequirementAttackEffect; +import mage.abilities.effects.RequirementEffect; import mage.game.Game; import mage.game.permanent.Permanent; -import mage.players.Player; -import mage.target.common.TargetDefender; /** * * @author BetaSteward_at_googlemail.com */ -public class AttacksIfAbleTargetEffect extends RequirementAttackEffect { +public class AttacksIfAbleTargetEffect extends RequirementEffect { - public AttacksIfAbleTargetEffect() { - super(Duration.EndOfTurn); + public AttacksIfAbleTargetEffect(Duration duration) { + super(duration); } public AttacksIfAbleTargetEffect(final AttacksIfAbleTargetEffect effect) { @@ -57,24 +54,30 @@ public class AttacksIfAbleTargetEffect extends RequirementAttackEffect { + + public CantAttackSourceEffect(Duration duration) { + super(duration); + } + + public CantAttackSourceEffect(final CantAttackSourceEffect effect) { + super(effect); + } + + @Override + public boolean applies(Permanent permanent, Ability source, Game game) { + if (permanent.getId().equals(source.getSourceId())) { + return true; + } + return false; + } + + @Override + public boolean canAttack(Game game) { + return false; + } + + @Override + public CantAttackSourceEffect copy() { + return new CantAttackSourceEffect(this); + } + +} diff --git a/Mage/src/mage/abilities/effects/common/CantBlockSourceEffect.java b/Mage/src/mage/abilities/effects/common/CantBlockSourceEffect.java new file mode 100644 index 00000000000..cb11c1114a3 --- /dev/null +++ b/Mage/src/mage/abilities/effects/common/CantBlockSourceEffect.java @@ -0,0 +1,69 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ + +package mage.abilities.effects.common; + +import mage.Constants.Duration; +import mage.abilities.Ability; +import mage.abilities.effects.RestrictionEffect; +import mage.game.Game; +import mage.game.permanent.Permanent; + +/** + * + * @author BetaSteward_at_googlemail.com + */ +public class CantBlockSourceEffect extends RestrictionEffect { + + public CantBlockSourceEffect(Duration duration) { + super(duration); + } + + public CantBlockSourceEffect(final CantBlockSourceEffect effect) { + super(effect); + } + + @Override + public boolean applies(Permanent permanent, Ability source, Game game) { + if (permanent.getId().equals(source.getSourceId())) { + return true; + } + return false; + } + + @Override + public boolean canBlock(Permanent blocker, Game game) { + return false; + } + + @Override + public CantBlockSourceEffect copy() { + return new CantBlockSourceEffect(this); + } + +} diff --git a/Mage/src/mage/abilities/effects/common/MustBlockSourceEffect.java b/Mage/src/mage/abilities/effects/common/MustBlockSourceEffect.java index e50b8e23193..2842abbc8b6 100644 --- a/Mage/src/mage/abilities/effects/common/MustBlockSourceEffect.java +++ b/Mage/src/mage/abilities/effects/common/MustBlockSourceEffect.java @@ -28,55 +28,51 @@ package mage.abilities.effects.common; +import java.util.UUID; import mage.Constants.Duration; import mage.abilities.Ability; -import mage.abilities.effects.RequirementBlockEffect; -import mage.filter.common.FilterCreaturePermanent; +import mage.abilities.effects.RequirementEffect; import mage.game.Game; -import mage.game.combat.CombatGroup; import mage.game.permanent.Permanent; -import mage.players.Player; /** * * @author BetaSteward_at_googlemail.com */ -public class MustBlockSourceEffect extends RequirementBlockEffect { +public class MustBlockSourceEffect extends RequirementEffect { public MustBlockSourceEffect() { super(Duration.WhileOnBattlefield); } + public MustBlockSourceEffect(Duration duration) { + super(duration); + } + public MustBlockSourceEffect(final MustBlockSourceEffect effect) { super(effect); } @Override - public boolean apply(Game game, Ability source) { - CombatGroup group = game.getCombat().findGroup(source.getSourceId()); - if (group != null) { - Player defender = null; - if (group.isDefenderIsPlaneswalker()) { - Permanent planeswalker = game.getPermanent(group.getDefenderId()); - if (planeswalker != null) { - defender = game.getPlayer(planeswalker.getControllerId()); - } - } - else { - defender = game.getPlayer(group.getDefenderId()); - } - if (defender != null) { - for (Permanent creature: game.getBattlefield().getAllActivePermanents(FilterCreaturePermanent.getDefault(), defender.getId())) { - if (group.canBlock(creature, game)) { - group.addBlocker(creature.getId(), creature.getControllerId(), game); - } - } - return true; - } - } + public boolean applies(Permanent permanent, Ability source, Game game) { + return true; + } + + @Override + public boolean mustAttack(Game game) { return false; } + @Override + public boolean mustBlock(Game game) { + return true; + } + + @Override + public UUID mustBlockAttacker(Ability source, Game game) { + return source.getSourceId(); + } + @Override public MustBlockSourceEffect copy() { return new MustBlockSourceEffect(this); diff --git a/Mage/src/mage/abilities/keyword/FlyingAbility.java b/Mage/src/mage/abilities/keyword/FlyingAbility.java index 0d2df53ea0a..f91dfc72f1c 100644 --- a/Mage/src/mage/abilities/keyword/FlyingAbility.java +++ b/Mage/src/mage/abilities/keyword/FlyingAbility.java @@ -29,7 +29,10 @@ package mage.abilities.keyword; import java.io.ObjectStreamException; -import mage.abilities.EvasionAbilityImpl; +import mage.Constants.Duration; +import mage.abilities.Ability; +import mage.abilities.EvasionAbility; +import mage.abilities.effects.RestrictionEffect; import mage.game.Game; import mage.game.permanent.Permanent; @@ -37,7 +40,7 @@ import mage.game.permanent.Permanent; * * @author BetaSteward_at_googlemail.com */ -public class FlyingAbility extends EvasionAbilityImpl { +public class FlyingAbility extends EvasionAbility { private static final FlyingAbility fINSTANCE = new FlyingAbility(); @@ -49,13 +52,8 @@ public class FlyingAbility extends EvasionAbilityImpl { return fINSTANCE; } - private FlyingAbility() {} - - @Override - public boolean canBlock(Permanent blocker, Game game) { - if (blocker.getAbilities().containsKey(id) || blocker.getAbilities().containsKey(ReachAbility.getInstance().getId())) - return true; - return false; + private FlyingAbility() { + this.addEffect(new FlyingEffect()); } @Override @@ -69,3 +67,35 @@ public class FlyingAbility extends EvasionAbilityImpl { } } + +class FlyingEffect extends RestrictionEffect { + + public FlyingEffect() { + super(Duration.WhileOnBattlefield); + } + + public FlyingEffect(final FlyingEffect effect) { + super(effect); + } + + @Override + public boolean applies(Permanent permanent, Ability source, Game game) { + if (permanent.getAbilities().containsKey(FlyingAbility.getInstance().getId())) { + return true; + } + return false; + } + + @Override + public boolean canBlock(Permanent blocker, Game game) { + if (blocker.getAbilities().containsKey(FlyingAbility.getInstance().getId()) || blocker.getAbilities().containsKey(ReachAbility.getInstance().getId())) + return true; + return false; + } + + @Override + public FlyingEffect copy() { + return new FlyingEffect(this); + } + +} \ No newline at end of file diff --git a/Mage/src/mage/abilities/keyword/ForestwalkAbility.java b/Mage/src/mage/abilities/keyword/ForestwalkAbility.java index bdfe38d6934..88b52a2b8d9 100644 --- a/Mage/src/mage/abilities/keyword/ForestwalkAbility.java +++ b/Mage/src/mage/abilities/keyword/ForestwalkAbility.java @@ -38,20 +38,23 @@ import mage.filter.common.FilterLandPermanent; */ public class ForestwalkAbility extends LandwalkAbility { - private static final ForestwalkAbility fINSTANCE = new ForestwalkAbility(); + private static FilterLandPermanent filter = new FilterLandPermanent("Forest"); - private Object readResolve() throws ObjectStreamException { - return fINSTANCE; - } - - public static ForestwalkAbility getInstance() { - return fINSTANCE; - } - - private ForestwalkAbility() { - filter = new FilterLandPermanent("Forest"); + static { filter.getSubtype().add("Forest"); filter.setScopeSubtype(ComparisonScope.Any); } + public ForestwalkAbility() { + super(filter); + } + + public ForestwalkAbility(final ForestwalkAbility ability) { + super(ability); + } + + @Override + public ForestwalkAbility copy() { + return new ForestwalkAbility(this); + } } \ No newline at end of file diff --git a/Mage/src/mage/abilities/keyword/IslandwalkAbility.java b/Mage/src/mage/abilities/keyword/IslandwalkAbility.java index fdd834c5874..efd97cff739 100644 --- a/Mage/src/mage/abilities/keyword/IslandwalkAbility.java +++ b/Mage/src/mage/abilities/keyword/IslandwalkAbility.java @@ -38,20 +38,23 @@ import mage.filter.common.FilterLandPermanent; */ public class IslandwalkAbility extends LandwalkAbility { - private static final IslandwalkAbility fINSTANCE = new IslandwalkAbility(); + private static final IslandwalkAbility fINSTANCE = new IslandwalkAbility(); private static FilterLandPermanent filter = new FilterLandPermanent("Island"); - private Object readResolve() throws ObjectStreamException { - return fINSTANCE; - } - - public static IslandwalkAbility getInstance() { - return fINSTANCE; - } - - private IslandwalkAbility() { - filter = new FilterLandPermanent("Island"); + static { filter.getSubtype().add("Island"); filter.setScopeSubtype(ComparisonScope.Any); } + public IslandwalkAbility() { + super(filter); + } + + public IslandwalkAbility(final IslandwalkAbility ability) { + super(ability); + } + + @Override + public IslandwalkAbility copy() { + return new IslandwalkAbility(this); + } } diff --git a/Mage/src/mage/abilities/keyword/LandwalkAbility.java b/Mage/src/mage/abilities/keyword/LandwalkAbility.java index 6cb8379d9fe..6a812899905 100644 --- a/Mage/src/mage/abilities/keyword/LandwalkAbility.java +++ b/Mage/src/mage/abilities/keyword/LandwalkAbility.java @@ -28,7 +28,10 @@ package mage.abilities.keyword; -import mage.abilities.EvasionAbilityImpl; +import mage.Constants.Duration; +import mage.abilities.Ability; +import mage.abilities.EvasionAbility; +import mage.abilities.effects.RestrictionEffect; import mage.filter.common.FilterLandPermanent; import mage.game.Game; import mage.game.permanent.Permanent; @@ -37,19 +40,14 @@ import mage.game.permanent.Permanent; * * @author BetaSteward_at_googlemail.com */ -public class LandwalkAbility extends EvasionAbilityImpl { - - protected FilterLandPermanent filter; - - protected LandwalkAbility() {} +public class LandwalkAbility extends EvasionAbility { public LandwalkAbility(FilterLandPermanent filter) { - this.filter = filter; + this.addEffect(new LandwalkEffect(filter)); } public LandwalkAbility(final LandwalkAbility ability) { super(ability); - this.filter = ability.filter.copy(); } @Override @@ -57,14 +55,43 @@ public class LandwalkAbility extends EvasionAbilityImpl { return new LandwalkAbility(this); } +} + +class LandwalkEffect extends RestrictionEffect { + + protected FilterLandPermanent filter; + + public LandwalkEffect(FilterLandPermanent filter) { + super(Duration.WhileOnBattlefield); + this.filter = filter; + } + + public LandwalkEffect(final LandwalkEffect effect) { + super(effect); + this.filter = effect.filter.copy(); + } + @Override public boolean canBlock(Permanent blocker, Game game) { return game.getBattlefield().countAll(filter, blocker.getControllerId()) == 0; } @Override - public String getRule() { + public boolean applies(Permanent permanent, Ability source, Game game) { + if (permanent.getId().equals(source.getSourceId())) { + return true; + } + return false; + } + + @Override + public LandwalkEffect copy() { + return new LandwalkEffect(this); + } + + @Override + public String getText(Ability source) { return filter.getMessage() + "walk"; } -} +} \ No newline at end of file diff --git a/Mage/src/mage/abilities/keyword/MountainwalkAbility.java b/Mage/src/mage/abilities/keyword/MountainwalkAbility.java index 19b2f306b75..d24945e80e4 100644 --- a/Mage/src/mage/abilities/keyword/MountainwalkAbility.java +++ b/Mage/src/mage/abilities/keyword/MountainwalkAbility.java @@ -38,20 +38,23 @@ import mage.filter.common.FilterLandPermanent; */ public class MountainwalkAbility extends LandwalkAbility { - private static final MountainwalkAbility fINSTANCE = new MountainwalkAbility(); + private static FilterLandPermanent filter = new FilterLandPermanent("Mountain"); - private Object readResolve() throws ObjectStreamException { - return fINSTANCE; - } - - public static MountainwalkAbility getInstance() { - return fINSTANCE; - } - - private MountainwalkAbility() { - filter = new FilterLandPermanent("Mountain"); + static { filter.getSubtype().add("Mountain"); filter.setScopeSubtype(ComparisonScope.Any); } + public MountainwalkAbility() { + super(filter); + } + + public MountainwalkAbility(final MountainwalkAbility ability) { + super(ability); + } + + @Override + public MountainwalkAbility copy() { + return new MountainwalkAbility(this); + } } \ No newline at end of file diff --git a/Mage/src/mage/abilities/keyword/SwampwalkAbility.java b/Mage/src/mage/abilities/keyword/SwampwalkAbility.java index 306d2188e38..994b71b8e29 100644 --- a/Mage/src/mage/abilities/keyword/SwampwalkAbility.java +++ b/Mage/src/mage/abilities/keyword/SwampwalkAbility.java @@ -38,20 +38,23 @@ import mage.filter.common.FilterLandPermanent; */ public class SwampwalkAbility extends LandwalkAbility { - private static final SwampwalkAbility fINSTANCE = new SwampwalkAbility(); + private static FilterLandPermanent filter = new FilterLandPermanent("Swamp"); - private Object readResolve() throws ObjectStreamException { - return fINSTANCE; - } - - public static SwampwalkAbility getInstance() { - return fINSTANCE; - } - - private SwampwalkAbility() { - filter = new FilterLandPermanent("Swamp"); + static { filter.getSubtype().add("Swamp"); filter.setScopeSubtype(ComparisonScope.Any); } + public SwampwalkAbility() { + super(filter); + } + + public SwampwalkAbility(final SwampwalkAbility ability) { + super(ability); + } + + @Override + public SwampwalkAbility copy() { + return new SwampwalkAbility(this); + } } \ No newline at end of file diff --git a/Mage/src/mage/abilities/keyword/UnblockableAbility.java b/Mage/src/mage/abilities/keyword/UnblockableAbility.java index 03ad6323211..a9fb7edea46 100644 --- a/Mage/src/mage/abilities/keyword/UnblockableAbility.java +++ b/Mage/src/mage/abilities/keyword/UnblockableAbility.java @@ -29,7 +29,10 @@ package mage.abilities.keyword; import java.io.ObjectStreamException; -import mage.abilities.EvasionAbilityImpl; +import mage.Constants.Duration; +import mage.abilities.Ability; +import mage.abilities.EvasionAbility; +import mage.abilities.effects.RestrictionEffect; import mage.game.Game; import mage.game.permanent.Permanent; @@ -37,7 +40,7 @@ import mage.game.permanent.Permanent; * * @author BetaSteward_at_googlemail.com */ -public class UnblockableAbility extends EvasionAbilityImpl { +public class UnblockableAbility extends EvasionAbility { private static final UnblockableAbility fINSTANCE = new UnblockableAbility(); @@ -49,11 +52,8 @@ public class UnblockableAbility extends EvasionAbilityImpl { return fINSTANCE; } - private UnblockableAbility() {} - - @Override - public boolean canBlock(Permanent blocker, Game game) { - return false; + private UnblockableAbility() { + this.addEffect(new UnblockableEffect()); } @Override @@ -67,3 +67,33 @@ public class UnblockableAbility extends EvasionAbilityImpl { } } + +class UnblockableEffect extends RestrictionEffect { + + public UnblockableEffect() { + super(Duration.WhileOnBattlefield); + } + + public UnblockableEffect(final UnblockableEffect effect) { + super(effect); + } + + @Override + public boolean applies(Permanent permanent, Ability source, Game game) { + if (permanent.getId().equals(source.getSourceId())) { + return true; + } + return false; + } + + @Override + public boolean canBlock(Permanent blocker, Game game) { + return false; + } + + @Override + public UnblockableEffect copy() { + return new UnblockableEffect(this); + } + +} \ No newline at end of file diff --git a/Mage/src/mage/game/combat/Combat.java b/Mage/src/mage/game/combat/Combat.java index 08720fdc7e8..a359f776486 100644 --- a/Mage/src/mage/game/combat/Combat.java +++ b/Mage/src/mage/game/combat/Combat.java @@ -34,13 +34,18 @@ import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.UUID; +import mage.Constants.Outcome; +import mage.abilities.effects.RequirementEffect; import mage.abilities.keyword.VigilanceAbility; +import mage.filter.common.FilterCreatureForAttack; +import mage.filter.common.FilterCreatureForCombat; import mage.filter.common.FilterPlaneswalkerPermanent; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.permanent.Permanent; import mage.players.Player; import mage.players.PlayerList; +import mage.target.common.TargetDefender; import mage.util.Copyable; @@ -51,6 +56,8 @@ import mage.util.Copyable; public class Combat implements Serializable, Copyable { private static FilterPlaneswalkerPermanent filterPlaneswalker = new FilterPlaneswalkerPermanent(); + private static FilterCreatureForAttack filterAttackers = new FilterCreatureForAttack(); + private static FilterCreatureForCombat filterBlockers = new FilterCreatureForCombat(); protected List groups = new ArrayList(); protected Set defenders = new HashSet(); @@ -113,14 +120,46 @@ public class Combat implements Serializable, Copyable { public void selectAttackers(Game game) { if (!game.replaceEvent(GameEvent.getEvent(GameEvent.EventType.DECLARING_ATTACKERS, attackerId, attackerId))) { - game.getPlayer(attackerId).selectAttackers(game); + Player player = game.getPlayer(attackerId); + //20101001 - 508.1d + checkAttackRequirements(player, game); + player.selectAttackers(game); game.fireEvent(GameEvent.getEvent(GameEvent.EventType.DECLARED_ATTACKERS, attackerId, attackerId)); - game.fireInformEvent(game.getPlayer(attackerId).getName() + " attacks with " + groups.size() + " creatures"); + game.fireInformEvent(player.getName() + " attacks with " + groups.size() + " creatures"); + } + } + + protected void checkAttackRequirements(Player player, Game game) { + //20101001 - 508.1d + for (Permanent creature: game.getBattlefield().getAllActivePermanents(filterAttackers, player.getId())) { + for (RequirementEffect effect: game.getContinuousEffects().getApplicableRequirementEffects(creature, game)) { + if (effect.mustAttack(game)) { + UUID defenderId = effect.mustAttackDefender(game.getContinuousEffects().getAbility(effect.getId()), game); + if (defenderId == null) { + if (defenders.size() == 1) { + player.declareAttacker(creature.getId(), defenders.iterator().next(), game); + } + else { + TargetDefender target = new TargetDefender(defenders, creature.getId()); + target.setRequired(true); + if (player.chooseTarget(Outcome.Damage, target, null, game)) { + player.declareAttacker(creature.getId(), target.getFirstTarget(), game); + } + } + } + else { + player.declareAttacker(creature.getId(), defenderId, game); + } + } + } } } public void selectBlockers(Game game) { if (!game.replaceEvent(GameEvent.getEvent(GameEvent.EventType.DECLARING_BLOCKERS, attackerId, attackerId))) { + Player player = game.getPlayer(attackerId); + //20101001 - 509.1c + checkBlockRequirements(player, game); for (UUID defenderId: getPlayerDefenders(game)) { game.getPlayer(defenderId).selectBlockers(game); game.fireEvent(GameEvent.getEvent(GameEvent.EventType.DECLARED_BLOCKERS, defenderId, defenderId)); @@ -128,6 +167,24 @@ public class Combat implements Serializable, Copyable { } } + protected void checkBlockRequirements(Player player, Game game) { + //20101001 - 509.1c + //TODO: handle case where more than one attacker must be blocked + for (Permanent creature: game.getBattlefield().getActivePermanents(filterBlockers, player.getId(), game)) { + if (game.getOpponents(attackerId).contains(creature.getControllerId())) { + for (RequirementEffect effect: game.getContinuousEffects().getApplicableRequirementEffects(creature, game)) { + if (effect.mustBlock(game)) { + UUID attackId = effect.mustBlockAttacker(game.getContinuousEffects().getAbility(effect.getId()), game); + Player defender = game.getPlayer(creature.getControllerId()); + if (attackId != null && defender != null) { + defender.declareBlocker(creature.getId(), attackId, game); + } + } + } + } + } + } + public void setDefenders(Game game) { Set opponents = game.getOpponents(attackerId); PlayerList players; diff --git a/Mage/src/mage/game/permanent/PermanentImpl.java b/Mage/src/mage/game/permanent/PermanentImpl.java index e23455db40c..75b419c1a5b 100644 --- a/Mage/src/mage/game/permanent/PermanentImpl.java +++ b/Mage/src/mage/game/permanent/PermanentImpl.java @@ -37,6 +37,7 @@ import mage.MageObject; import mage.abilities.Ability; import mage.abilities.EvasionAbility; import mage.abilities.TriggeredAbility; +import mage.abilities.effects.RestrictionEffect; import mage.abilities.keyword.DeathtouchAbility; import mage.abilities.keyword.DefenderAbility; import mage.abilities.keyword.HasteAbility; @@ -558,6 +559,11 @@ public abstract class PermanentImpl> extends CardImpl return false; if (hasSummoningSickness()) return false; + //20101001 - 508.1c + for (RestrictionEffect effect: game.getContinuousEffects().getApplicableRestrictionEffects(this, game)) { + if (!effect.canAttack(game)) + return false; + } if (abilities.containsKey(DefenderAbility.getInstance().getId())) return false; return true; @@ -568,10 +574,15 @@ public abstract class PermanentImpl> extends CardImpl if (tapped) return false; Permanent attacker = game.getPermanent(attackerId); - for (EvasionAbility ability: attacker.getAbilities().getEvasionAbilities()) { - if (!ability.canBlock(this, game)) + //20101001 - 509.1b + for (RestrictionEffect effect: game.getContinuousEffects().getApplicableRestrictionEffects(this, game)) { + if (!effect.canBlock(attacker, game)) return false; } +// for (EvasionAbility ability: attacker.getAbilities().getEvasionAbilities()) { +// if (!ability.canBlock(this, game)) +// return false; +// } if (attacker.hasProtectionFrom(this)) return false; return true;