diff --git a/Mage.Sets/src/mage/sets/bornofthegods/FloodtideSerpent.java b/Mage.Sets/src/mage/sets/bornofthegods/FloodtideSerpent.java
index 962b63f528..0fcebf1fd7 100644
--- a/Mage.Sets/src/mage/sets/bornofthegods/FloodtideSerpent.java
+++ b/Mage.Sets/src/mage/sets/bornofthegods/FloodtideSerpent.java
@@ -32,7 +32,9 @@ import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.costs.common.ReturnToHandTargetPermanentCost;
+import mage.abilities.effects.PayCostToAttackBlockEffectImpl;
import mage.abilities.effects.ReplacementEffectImpl;
+import mage.abilities.effects.common.combat.CantAttackBlockUnlessPaysSourceEffect;
import mage.cards.CardImpl;
import mage.constants.CardType;
import mage.constants.Duration;
@@ -53,6 +55,12 @@ import mage.target.common.TargetControlledPermanent;
*/
public class FloodtideSerpent extends CardImpl {
+ private static final FilterControlledPermanent filter = new FilterControlledPermanent("an enchantment you control");
+
+ static {
+ filter.add(new CardTypePredicate(CardType.ENCHANTMENT));
+ }
+
public FloodtideSerpent(UUID ownerId) {
super(ownerId, 41, "Floodtide Serpent", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{4}{U}");
this.expansionSetCode = "BNG";
@@ -62,8 +70,8 @@ public class FloodtideSerpent extends CardImpl {
this.toughness = new MageInt(4);
// Floodtide Serpent can't attack unless you return an enchantment you control to its owner's hand (This cost is paid as attackers are declared.)
- this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new FloodtideSerpentReplacementEffect()));
-
+ this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new CantAttackBlockUnlessPaysSourceEffect(
+ new ReturnToHandTargetPermanentCost(new TargetControlledPermanent(filter)), PayCostToAttackBlockEffectImpl.RestrictType.ATTACK)));
}
@@ -85,24 +93,23 @@ class FloodtideSerpentReplacementEffect extends ReplacementEffectImpl {
filter.add(new CardTypePredicate(CardType.ENCHANTMENT));
}
- FloodtideSerpentReplacementEffect ( ) {
+ FloodtideSerpentReplacementEffect() {
super(Duration.WhileOnBattlefield, Outcome.Neutral);
staticText = "{this} can't attack unless you return an enchantment you control to its owner's hand (This cost is paid as attackers are declared.)";
}
- FloodtideSerpentReplacementEffect ( FloodtideSerpentReplacementEffect effect ) {
+ FloodtideSerpentReplacementEffect(FloodtideSerpentReplacementEffect effect) {
super(effect);
}
@Override
public boolean replaceEvent(GameEvent event, Ability source, Game game) {
Player player = game.getPlayer(event.getPlayerId());
- if ( player != null ) {
+ if (player != null) {
ReturnToHandTargetPermanentCost attackCost = new ReturnToHandTargetPermanentCost(new TargetControlledPermanent(filter));
- if ( attackCost.canPay(source, source.getSourceId(), event.getPlayerId(), game) &&
- player.chooseUse(Outcome.Neutral, "Return an enchantment you control to hand to attack?", source, game) )
- {
- if (attackCost.pay(source, game, source.getSourceId(), event.getPlayerId(), true) ) {
+ if (attackCost.canPay(source, source.getSourceId(), event.getPlayerId(), game)
+ && player.chooseUse(Outcome.Neutral, "Return an enchantment you control to hand to attack?", source, game)) {
+ if (attackCost.pay(source, game, source.getSourceId(), event.getPlayerId(), true)) {
return false;
}
}
@@ -111,11 +118,10 @@ class FloodtideSerpentReplacementEffect extends ReplacementEffectImpl {
return false;
}
- @Override
+ @Override
public boolean checksEventType(GameEvent event, Game game) {
return event.getType() == EventType.DECLARE_ATTACKER;
}
-
@Override
public boolean applies(GameEvent event, Ability source, Game game) {
diff --git a/Mage.Sets/src/mage/sets/championsofkamigawa/GhostlyPrison.java b/Mage.Sets/src/mage/sets/championsofkamigawa/GhostlyPrison.java
index 120e33b61d..fa36b4ee34 100644
--- a/Mage.Sets/src/mage/sets/championsofkamigawa/GhostlyPrison.java
+++ b/Mage.Sets/src/mage/sets/championsofkamigawa/GhostlyPrison.java
@@ -32,7 +32,7 @@ import java.util.UUID;
import mage.constants.*;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.costs.mana.ManaCostsImpl;
-import mage.abilities.effects.common.replacement.CantAttackYouUnlessPayManaAllEffect;
+import mage.abilities.effects.common.combat.CantAttackYouUnlessPayManaAllEffect;
import mage.cards.CardImpl;
/**
diff --git a/Mage.Sets/src/mage/sets/dragonsoftarkir/QalSismaBehemoth.java b/Mage.Sets/src/mage/sets/dragonsoftarkir/QalSismaBehemoth.java
index b32f307659..9f43bdd2a1 100644
--- a/Mage.Sets/src/mage/sets/dragonsoftarkir/QalSismaBehemoth.java
+++ b/Mage.Sets/src/mage/sets/dragonsoftarkir/QalSismaBehemoth.java
@@ -29,21 +29,14 @@ package mage.sets.dragonsoftarkir;
import java.util.UUID;
import mage.MageInt;
-import mage.abilities.Ability;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.costs.mana.ManaCostsImpl;
-import mage.abilities.effects.ReplacementEffectImpl;
+import mage.abilities.effects.PayCostToAttackBlockEffectImpl;
+import mage.abilities.effects.common.combat.CantAttackBlockUnlessPaysSourceEffect;
import mage.cards.CardImpl;
import mage.constants.CardType;
-import mage.constants.Duration;
-import mage.constants.Outcome;
import mage.constants.Rarity;
import mage.constants.Zone;
-import mage.game.Game;
-import mage.game.events.GameEvent;
-import static mage.game.events.GameEvent.EventType.DECLARE_ATTACKER;
-import static mage.game.events.GameEvent.EventType.DECLARE_BLOCKER;
-import mage.players.Player;
/**
*
@@ -60,7 +53,7 @@ public class QalSismaBehemoth extends CardImpl {
this.toughness = new MageInt(5);
// Qal Sisma Behemoth can't attack or block unless you pay {2}.
- this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new QalSismaBehemothEffect() ));
+ this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new CantAttackBlockUnlessPaysSourceEffect(new ManaCostsImpl("{2}"), PayCostToAttackBlockEffectImpl.RestrictType.ATTACK_AND_BLOCK)));
}
@@ -73,66 +66,3 @@ public class QalSismaBehemoth extends CardImpl {
return new QalSismaBehemoth(this);
}
}
-
-class QalSismaBehemothEffect extends ReplacementEffectImpl {
-
- private static final String effectText = "{this} can't attack or block unless you pay {2}";
-
- QalSismaBehemothEffect ( ) {
- super(Duration.WhileOnBattlefield, Outcome.Neutral);
- staticText = effectText;
- }
-
- QalSismaBehemothEffect ( QalSismaBehemothEffect effect ) {
- super(effect);
- }
-
- @Override
- public boolean apply(Game game, Ability source) {
- throw new UnsupportedOperationException("Not supported.");
- }
-
- @Override
- public boolean replaceEvent(GameEvent event, Ability source, Game game) {
- Player player = game.getPlayer(event.getPlayerId());
- if (player != null) {
- String chooseText;
- if (event.getType().equals(GameEvent.EventType.DECLARE_ATTACKER)) {
- chooseText = "Pay {2} to attack?";
- } else {
- chooseText = "Pay {2} to block?";
- }
- ManaCostsImpl attackBlockTax = new ManaCostsImpl("{2}");
- if (attackBlockTax.canPay(source, source.getSourceId(), event.getPlayerId(), game)
- && player.chooseUse(Outcome.Neutral, chooseText, source, game)) {
- if (attackBlockTax.payOrRollback(source, game, source.getSourceId(), event.getPlayerId())) {
- return false;
- }
- }
- return true;
- }
- return false;
- }
-
- @Override
- public boolean checksEventType(GameEvent event, Game game) {
- switch(event.getType()) {
- case DECLARE_ATTACKER:
- case DECLARE_BLOCKER:
- return true;
- default:
- return false;
- }
- }
-
- @Override
- public boolean applies(GameEvent event, Ability source, Game game) {
- return event.getSourceId().equals(source.getSourceId());
- }
-
- @Override
- public QalSismaBehemothEffect copy() {
- return new QalSismaBehemothEffect(this);
- }
-
-}
diff --git a/Mage.Sets/src/mage/sets/journeyintonyx/OppressiveRays.java b/Mage.Sets/src/mage/sets/journeyintonyx/OppressiveRays.java
index 22e1057471..5b4dd45644 100644
--- a/Mage.Sets/src/mage/sets/journeyintonyx/OppressiveRays.java
+++ b/Mage.Sets/src/mage/sets/journeyintonyx/OppressiveRays.java
@@ -33,11 +33,12 @@ import mage.abilities.ActivatedAbility;
import mage.abilities.SpellAbility;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.costs.mana.ManaCostsImpl;
-import mage.abilities.effects.common.cost.CostModificationEffectImpl;
-import mage.abilities.effects.ReplacementEffectImpl;
import mage.abilities.effects.common.AttachEffect;
+import mage.abilities.effects.common.combat.CantAttackBlockUnlessPaysAttachedEffect;
+import mage.abilities.effects.common.cost.CostModificationEffectImpl;
import mage.abilities.keyword.EnchantAbility;
import mage.cards.CardImpl;
+import mage.constants.AttachmentType;
import mage.constants.CardType;
import mage.constants.CostModificationType;
import mage.constants.Duration;
@@ -45,9 +46,7 @@ import mage.constants.Outcome;
import mage.constants.Rarity;
import mage.constants.Zone;
import mage.game.Game;
-import mage.game.events.GameEvent;
import mage.game.permanent.Permanent;
-import mage.players.Player;
import mage.target.TargetPermanent;
import mage.target.common.TargetCreaturePermanent;
import mage.util.CardUtil;
@@ -63,7 +62,6 @@ public class OppressiveRays extends CardImpl {
this.expansionSetCode = "JOU";
this.subtype.add("Aura");
-
// Enchant creature
TargetPermanent auraTarget = new TargetCreaturePermanent();
this.getSpellAbility().addTarget(auraTarget);
@@ -72,9 +70,10 @@ public class OppressiveRays extends CardImpl {
this.addAbility(ability);
// Enchanted creature can't attack or block unless its controller pays 3.
- this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new OppressiveRaysEffect()));
+ this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new CantAttackBlockUnlessPaysAttachedEffect(new ManaCostsImpl<>("{3}"), AttachmentType.AURA)));
+
// Activated abilities of enchanted creature cost {3} more to activate.
- this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new OppressiveRaysCostModificationEffect() ));
+ this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new OppressiveRaysCostModificationEffect()));
}
public OppressiveRays(final OppressiveRays card) {
@@ -87,81 +86,9 @@ public class OppressiveRays extends CardImpl {
}
}
-
-class OppressiveRaysEffect extends ReplacementEffectImpl {
-
- private static final String effectText = "Enchanted creature can't attack or block unless its controller pays {3}";
-
- OppressiveRaysEffect ( ) {
- super(Duration.WhileOnBattlefield, Outcome.Neutral);
- staticText = effectText;
- }
-
- OppressiveRaysEffect ( OppressiveRaysEffect effect ) {
- super(effect);
- }
-
- @Override
- public boolean apply(Game game, Ability source) {
- throw new UnsupportedOperationException("Not supported.");
- }
-
- @Override
- public boolean replaceEvent(GameEvent event, Ability source, Game game) {
- Player player = game.getPlayer(event.getPlayerId());
- if (player != null) {
- String chooseText;
- if (event.getType().equals(GameEvent.EventType.DECLARE_ATTACKER)) {
- chooseText = "Pay {3} to attack?";
- } else {
- chooseText = "Pay {3} to block?";
- }
- ManaCostsImpl attackBlockTax = new ManaCostsImpl("{3}");
- if (attackBlockTax.canPay(source, source.getSourceId(), event.getPlayerId(), game)
- && player.chooseUse(Outcome.Neutral, chooseText, source, game)) {
- if (attackBlockTax.payOrRollback(source, game, source.getSourceId(), event.getPlayerId())) {
- return false;
- }
- }
- return true;
- }
- return false;
- }
-
- @Override
- public boolean checksEventType(GameEvent event, Game game) {
- switch(event.getType()) {
- case DECLARE_ATTACKER:
- case DECLARE_BLOCKER:
- return true;
- default:
- return false;
- }
- }
-
- @Override
- public boolean applies(GameEvent event, Ability source, Game game) {
- if (event.getType().equals(GameEvent.EventType.DECLARE_ATTACKER)) {
- Permanent attacker = game.getPermanent(event.getSourceId());
- return attacker != null && attacker.getAttachments().contains(source.getSourceId());
- }
- if (event.getType().equals(GameEvent.EventType.DECLARE_BLOCKER)) {
- Permanent blocker = game.getPermanent(event.getSourceId());
- return blocker != null && blocker.getAttachments().contains(source.getSourceId());
- }
- return false;
- }
-
- @Override
- public OppressiveRaysEffect copy() {
- return new OppressiveRaysEffect(this);
- }
-
-}
-
class OppressiveRaysCostModificationEffect extends CostModificationEffectImpl {
- OppressiveRaysCostModificationEffect ( ) {
+ OppressiveRaysCostModificationEffect() {
super(Duration.WhileOnBattlefield, Outcome.Benefit, CostModificationType.INCREASE_COST);
staticText = "Activated abilities of enchanted creature cost {3} more to activate";
}
@@ -180,10 +107,10 @@ class OppressiveRaysCostModificationEffect extends CostModificationEffectImpl {
public boolean applies(Ability abilityToModify, Ability source, Game game) {
Permanent creature = game.getPermanent(abilityToModify.getSourceId());
if (creature != null && creature.getAttachments().contains(source.getSourceId())) {
- if (abilityToModify instanceof ActivatedAbility
- && !(abilityToModify instanceof SpellAbility)) {
- return true;
- }
+ if (abilityToModify instanceof ActivatedAbility
+ && !(abilityToModify instanceof SpellAbility)) {
+ return true;
+ }
}
return false;
}
diff --git a/Mage.Sets/src/mage/sets/newphyrexia/NornsAnnex.java b/Mage.Sets/src/mage/sets/newphyrexia/NornsAnnex.java
index 6c5c07386a..456f4df8a3 100644
--- a/Mage.Sets/src/mage/sets/newphyrexia/NornsAnnex.java
+++ b/Mage.Sets/src/mage/sets/newphyrexia/NornsAnnex.java
@@ -28,20 +28,13 @@
package mage.sets.newphyrexia;
import java.util.UUID;
-import mage.abilities.Ability;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.costs.mana.ManaCostsImpl;
-import mage.abilities.effects.ReplacementEffectImpl;
+import mage.abilities.effects.common.combat.CantAttackYouUnlessPayManaAllEffect;
import mage.cards.CardImpl;
import mage.constants.CardType;
-import mage.constants.Duration;
-import mage.constants.Outcome;
import mage.constants.Rarity;
import mage.constants.Zone;
-import mage.game.Game;
-import mage.game.events.GameEvent;
-import mage.game.permanent.Permanent;
-import mage.players.Player;
/**
* @author Loki
@@ -53,8 +46,8 @@ public class NornsAnnex extends CardImpl {
this.expansionSetCode = "NPH";
// {WP} ({WP} can be paid with either or 2 life.)
- // Creatures can't attack you or a planeswalker you control unless their controller pays for each of those creatures.
- this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new NornsAnnexReplacementEffect()));
+ // Creatures can't attack you or a planeswalker you control unless their controller pays {WP} for each of those creatures.
+ this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new CantAttackYouUnlessPayManaAllEffect(new ManaCostsImpl<>("{WP}"), true)));
}
public NornsAnnex(final NornsAnnex card) {
@@ -67,55 +60,3 @@ public class NornsAnnex extends CardImpl {
}
}
-
-class NornsAnnexReplacementEffect extends ReplacementEffectImpl {
-
- private static final String effectText = "Creatures can't attack you or a planeswalker you control unless their controller pays {WP} for each creature he or she controls that's attacking you";
-
- NornsAnnexReplacementEffect() {
- super(Duration.WhileOnBattlefield, Outcome.Benefit);
- staticText = effectText;
- }
-
- NornsAnnexReplacementEffect(NornsAnnexReplacementEffect effect) {
- super(effect);
- }
-
- @Override
- public boolean checksEventType(GameEvent event, Game game) {
- return event.getType() == GameEvent.EventType.DECLARE_ATTACKER;
- }
-
- @Override
- public boolean applies(GameEvent event, Ability source, Game game) {
- if (event.getTargetId().equals(source.getControllerId())) {
- return true;
- }
- // planeswalker
- Permanent permanent = game.getPermanent(event.getTargetId());
- return permanent != null && permanent.getControllerId().equals(source.getControllerId())
- && permanent.getCardType().contains(CardType.PLANESWALKER);
- }
-
- @Override
- public boolean replaceEvent(GameEvent event, Ability source, Game game) {
- Player player = game.getPlayer(event.getPlayerId());
- if (player != null) {
- ManaCostsImpl propagandaTax = new ManaCostsImpl("{WP}");
- if (propagandaTax.canPay(source, source.getSourceId(), event.getPlayerId(), game)
- && player.chooseUse(Outcome.Benefit, "Pay to declare attacker?", source, game)) {
- if (propagandaTax.payOrRollback(source, game, source.getSourceId(), event.getPlayerId())) {
- return false;
- }
- }
- return true;
- }
- return false;
- }
-
- @Override
- public NornsAnnexReplacementEffect copy() {
- return new NornsAnnexReplacementEffect(this);
- }
-
-}
diff --git a/Mage.Sets/src/mage/sets/ravnica/BlazingArchon.java b/Mage.Sets/src/mage/sets/ravnica/BlazingArchon.java
index 27a153c098..41fd4e3f54 100644
--- a/Mage.Sets/src/mage/sets/ravnica/BlazingArchon.java
+++ b/Mage.Sets/src/mage/sets/ravnica/BlazingArchon.java
@@ -29,18 +29,14 @@ package mage.sets.ravnica;
import java.util.UUID;
import mage.MageInt;
-import mage.abilities.Ability;
import mage.abilities.common.SimpleStaticAbility;
-import mage.abilities.effects.RestrictionEffect;
+import mage.abilities.effects.common.combat.CantAttackYouAllEffect;
import mage.abilities.keyword.FlyingAbility;
import mage.cards.CardImpl;
import mage.constants.CardType;
import mage.constants.Duration;
-import mage.constants.Outcome;
import mage.constants.Rarity;
import mage.constants.Zone;
-import mage.game.Game;
-import mage.game.permanent.Permanent;
/**
*
@@ -57,10 +53,10 @@ public class BlazingArchon extends CardImpl {
// Flying
this.addAbility(FlyingAbility.getInstance());
-
+
// Creatures can't attack you.
- this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BlazingArchonRestrictionEffect()));
-
+ this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new CantAttackYouAllEffect(Duration.WhileOnBattlefield)));
+
}
public BlazingArchon(final BlazingArchon card) {
@@ -72,30 +68,3 @@ public class BlazingArchon extends CardImpl {
return new BlazingArchon(this);
}
}
-
-class BlazingArchonRestrictionEffect extends RestrictionEffect {
-
- BlazingArchonRestrictionEffect() {
- super(Duration.WhileOnBattlefield, Outcome.Benefit);
- staticText = "Creatures can't attack you";
- }
-
- BlazingArchonRestrictionEffect(final BlazingArchonRestrictionEffect effect) {
- super(effect);
- }
-
- @Override
- public boolean applies(Permanent permanent, Ability source, Game game) {
- return true;
- }
-
- @Override
- public boolean canAttack(UUID defenderId, Ability source, Game game) {
- return !defenderId.equals(source.getControllerId());
- }
-
- @Override
- public BlazingArchonRestrictionEffect copy() {
- return new BlazingArchonRestrictionEffect(this);
- }
-}
diff --git a/Mage.Sets/src/mage/sets/returntoravnica/SphereOfSafety.java b/Mage.Sets/src/mage/sets/returntoravnica/SphereOfSafety.java
index fbccc1f078..d3e15931f0 100644
--- a/Mage.Sets/src/mage/sets/returntoravnica/SphereOfSafety.java
+++ b/Mage.Sets/src/mage/sets/returntoravnica/SphereOfSafety.java
@@ -25,24 +25,21 @@
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
-
package mage.sets.returntoravnica;
import java.util.UUID;
-
-import mage.constants.*;
import mage.abilities.Ability;
import mage.abilities.common.SimpleStaticAbility;
+import mage.abilities.costs.mana.ManaCosts;
import mage.abilities.costs.mana.ManaCostsImpl;
-import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount;
-import mage.abilities.effects.ReplacementEffectImpl;
+import mage.abilities.effects.common.combat.CantAttackYouUnlessPayManaAllEffect;
import mage.cards.CardImpl;
+import mage.constants.CardType;
+import mage.constants.Rarity;
+import mage.constants.Zone;
import mage.filter.common.FilterEnchantmentPermanent;
-import mage.filter.predicate.permanent.ControllerPredicate;
import mage.game.Game;
import mage.game.events.GameEvent;
-import mage.game.permanent.Permanent;
-import mage.players.Player;
/**
*
@@ -50,16 +47,16 @@ import mage.players.Player;
*/
public class SphereOfSafety extends CardImpl {
- public SphereOfSafety (UUID ownerId) {
+ public SphereOfSafety(UUID ownerId) {
super(ownerId, 24, "Sphere of Safety", Rarity.UNCOMMON, new CardType[]{CardType.ENCHANTMENT}, "{4}{W}");
this.expansionSetCode = "RTR";
// Creatures can't attack you or a planeswalker you control unless their controller pays {X} for each of those creatures, where X is the number of enchantments you control.
- this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new SphereOfSafetyReplacementEffect()));
+ this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new SphereOfSafetyPayManaToAttackAllEffect()));
}
- public SphereOfSafety (final SphereOfSafety card) {
+ public SphereOfSafety(final SphereOfSafety card) {
super(card);
}
@@ -70,64 +67,29 @@ public class SphereOfSafety extends CardImpl {
}
-class SphereOfSafetyReplacementEffect extends ReplacementEffectImpl {
+class SphereOfSafetyPayManaToAttackAllEffect extends CantAttackYouUnlessPayManaAllEffect {
- private static final String effectText = "Creatures can't attack you or a planeswalker you control unless their controller pays {X} for each of those creatures, where X is the number of enchantments you control";
- private static final FilterEnchantmentPermanent filter = new FilterEnchantmentPermanent("enchantment you control");
- static {
- filter.add(new ControllerPredicate(TargetController.YOU));
- }
- private final PermanentsOnBattlefieldCount countEnchantments = new PermanentsOnBattlefieldCount(filter);
-
-
- SphereOfSafetyReplacementEffect ( ) {
- super(Duration.WhileOnBattlefield, Outcome.Benefit);
- staticText = effectText;
+ SphereOfSafetyPayManaToAttackAllEffect() {
+ super(null, true);
+ staticText = "Creatures can't attack you or a planeswalker you control unless their controller pays {X} for each of those creatures, where X is the number of enchantments you control.";
}
- SphereOfSafetyReplacementEffect ( SphereOfSafetyReplacementEffect effect ) {
+ SphereOfSafetyPayManaToAttackAllEffect(SphereOfSafetyPayManaToAttackAllEffect effect) {
super(effect);
}
@Override
- public boolean checksEventType(GameEvent event, Game game) {
- return event.getType() == GameEvent.EventType.DECLARE_ATTACKER;
+ public ManaCosts getManaCostToPay(GameEvent event, Ability source, Game game) {
+ int enchantments = game.getBattlefield().countAll(new FilterEnchantmentPermanent(), source.getControllerId(), game);
+ if (enchantments > 0) {
+ return new ManaCostsImpl<>("{" + enchantments + "}");
+ }
+ return null;
}
@Override
- public boolean applies(GameEvent event, Ability source, Game game) {
- if (event.getTargetId().equals(source.getControllerId()) ) {
- return true;
- }
- // planeswalker
- Permanent permanent = game.getPermanent(event.getTargetId());
- if (permanent != null && permanent.getControllerId().equals(source.getControllerId())
- && permanent.getCardType().contains(CardType.PLANESWALKER)) {
- return true;
- }
- return false;
- }
-
- @Override
- public boolean replaceEvent(GameEvent event, Ability source, Game game) {
- Player player = game.getPlayer(event.getPlayerId());
- if ( player != null ) {
- int ce = countEnchantments.calculate(game, source, this);
- ManaCostsImpl safetyCosts = new ManaCostsImpl("{"+ ce +"}");
- if ( safetyCosts.canPay(source, source.getSourceId(), event.getPlayerId(), game) &&
- player.chooseUse(Outcome.Benefit, "Pay {"+ ce +"} to declare attacker?", source, game) ) {
- if (safetyCosts.payOrRollback(source, game, this.getId(), event.getPlayerId())) {
- return false;
- }
- }
- return true;
- }
- return false;
- }
-
- @Override
- public SphereOfSafetyReplacementEffect copy() {
- return new SphereOfSafetyReplacementEffect(this);
+ public SphereOfSafetyPayManaToAttackAllEffect copy() {
+ return new SphereOfSafetyPayManaToAttackAllEffect(this);
}
}
diff --git a/Mage.Sets/src/mage/sets/saviorsofkamigawa/Reverence.java b/Mage.Sets/src/mage/sets/saviorsofkamigawa/Reverence.java
index dae5b5ee48..0257d9036a 100644
--- a/Mage.Sets/src/mage/sets/saviorsofkamigawa/Reverence.java
+++ b/Mage.Sets/src/mage/sets/saviorsofkamigawa/Reverence.java
@@ -28,20 +28,16 @@
package mage.sets.saviorsofkamigawa;
import java.util.UUID;
-import mage.abilities.Ability;
import mage.abilities.common.SimpleStaticAbility;
-import mage.abilities.effects.RestrictionEffect;
+import mage.abilities.effects.common.combat.CantAttackYouAllEffect;
import mage.cards.CardImpl;
import mage.constants.CardType;
import mage.constants.Duration;
-import mage.constants.Outcome;
import mage.constants.Rarity;
import mage.constants.Zone;
import mage.filter.Filter;
import mage.filter.common.FilterCreaturePermanent;
import mage.filter.predicate.mageobject.PowerPredicate;
-import mage.game.Game;
-import mage.game.permanent.Permanent;
/**
*
@@ -49,12 +45,18 @@ import mage.game.permanent.Permanent;
*/
public class Reverence extends CardImpl {
+ private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("Creatures with power 2 or less");
+
+ static {
+ filter.add(new PowerPredicate(Filter.ComparisonType.LessThan, 3));
+ }
+
public Reverence(UUID ownerId) {
super(ownerId, 26, "Reverence", Rarity.RARE, new CardType[]{CardType.ENCHANTMENT}, "{2}{W}{W}");
this.expansionSetCode = "SOK";
// Creatures with power 2 or less can't attack you.
- this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new ReverenceRestrictionEffect()));
+ this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new CantAttackYouAllEffect(Duration.WhileOnBattlefield, filter)));
}
public Reverence(final Reverence card) {
@@ -66,37 +68,3 @@ public class Reverence extends CardImpl {
return new Reverence(this);
}
}
-
-class ReverenceRestrictionEffect extends RestrictionEffect {
-
-
- private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("Creatures with power 2 or less");
-
- static {
- filter.add(new PowerPredicate(Filter.ComparisonType.LessThan, 3));
- }
-
- ReverenceRestrictionEffect() {
- super(Duration.WhileOnBattlefield, Outcome.Benefit);
- staticText = "Creatures with power 2 or less can't attack you";
- }
-
- ReverenceRestrictionEffect(final ReverenceRestrictionEffect effect) {
- super(effect);
- }
-
- @Override
- public boolean applies(Permanent permanent, Ability source, Game game) {
- return filter.match(permanent, source.getSourceId(), source.getControllerId(), game);
- }
-
- @Override
- public boolean canAttack(UUID defenderId, Ability source, Game game) {
- return !defenderId.equals(source.getControllerId());
- }
-
- @Override
- public ReverenceRestrictionEffect copy() {
- return new ReverenceRestrictionEffect(this);
- }
-}
diff --git a/Mage.Sets/src/mage/sets/scourge/FormOfTheDragon.java b/Mage.Sets/src/mage/sets/scourge/FormOfTheDragon.java
index 255e17ceaf..ac3b132005 100644
--- a/Mage.Sets/src/mage/sets/scourge/FormOfTheDragon.java
+++ b/Mage.Sets/src/mage/sets/scourge/FormOfTheDragon.java
@@ -33,8 +33,8 @@ import mage.abilities.common.BeginningOfEndStepTriggeredAbility;
import mage.abilities.common.BeginningOfUpkeepTriggeredAbility;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.effects.OneShotEffect;
-import mage.abilities.effects.RestrictionEffect;
import mage.abilities.effects.common.DamageTargetEffect;
+import mage.abilities.effects.common.combat.CantAttackYouAllEffect;
import mage.abilities.keyword.FlyingAbility;
import mage.cards.CardImpl;
import mage.constants.CardType;
@@ -47,7 +47,6 @@ import mage.filter.common.FilterCreaturePermanent;
import mage.filter.predicate.Predicates;
import mage.filter.predicate.mageobject.AbilityPredicate;
import mage.game.Game;
-import mage.game.permanent.Permanent;
import mage.players.Player;
import mage.target.common.TargetCreatureOrPlayer;
@@ -56,8 +55,9 @@ import mage.target.common.TargetCreatureOrPlayer;
* @author emerald000
*/
public class FormOfTheDragon extends CardImpl {
-
+
private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("Creatures without flying");
+
static {
filter.add(Predicates.not(new AbilityPredicate(FlyingAbility.class)));
}
@@ -66,17 +66,16 @@ public class FormOfTheDragon extends CardImpl {
super(ownerId, 93, "Form of the Dragon", Rarity.RARE, new CardType[]{CardType.ENCHANTMENT}, "{4}{R}{R}{R}");
this.expansionSetCode = "SCG";
-
// At the beginning of your upkeep, Form of the Dragon deals 5 damage to target creature or player.
Ability ability = new BeginningOfUpkeepTriggeredAbility(new DamageTargetEffect(5), TargetController.YOU, false);
ability.addTarget(new TargetCreatureOrPlayer());
this.addAbility(ability);
-
+
// At the beginning of each end step, your life total becomes 5.
this.addAbility(new BeginningOfEndStepTriggeredAbility(new FormOfTheDragonEffect(), TargetController.ANY, false));
-
+
// Creatures without flying can't attack you.
- this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new FormOfTheDragonRestrictionEffect()));
+ this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new CantAttackYouAllEffect(Duration.WhileOnBattlefield, filter)));
}
public FormOfTheDragon(final FormOfTheDragon card) {
@@ -90,21 +89,21 @@ public class FormOfTheDragon extends CardImpl {
}
class FormOfTheDragonEffect extends OneShotEffect {
-
+
FormOfTheDragonEffect() {
super(Outcome.Neutral);
this.staticText = "your life total becomes 5";
}
-
+
FormOfTheDragonEffect(final FormOfTheDragonEffect effect) {
super(effect);
}
-
+
@Override
public FormOfTheDragonEffect copy() {
return new FormOfTheDragonEffect(this);
}
-
+
@Override
public boolean apply(Game game, Ability source) {
Player player = game.getPlayer(source.getControllerId());
@@ -115,30 +114,3 @@ class FormOfTheDragonEffect extends OneShotEffect {
return false;
}
}
-
-class FormOfTheDragonRestrictionEffect extends RestrictionEffect {
-
- FormOfTheDragonRestrictionEffect() {
- super(Duration.WhileOnBattlefield, Outcome.Benefit);
- staticText = "Creatures without flying can't attack you";
- }
-
- FormOfTheDragonRestrictionEffect(final FormOfTheDragonRestrictionEffect effect) {
- super(effect);
- }
-
- @Override
- public boolean applies(Permanent permanent, Ability source, Game game) {
- return permanent.getCardType().contains(CardType.CREATURE) && !permanent.getAbilities().contains(FlyingAbility.getInstance());
- }
-
- @Override
- public boolean canAttack(UUID defenderId, Ability source, Game game) {
- return !defenderId.equals(source.getControllerId());
- }
-
- @Override
- public FormOfTheDragonRestrictionEffect copy() {
- return new FormOfTheDragonRestrictionEffect(this);
- }
-}
diff --git a/Mage.Sets/src/mage/sets/stronghold/DreamHalls.java b/Mage.Sets/src/mage/sets/stronghold/DreamHalls.java
index 317db0e018..e0a0b4c45f 100644
--- a/Mage.Sets/src/mage/sets/stronghold/DreamHalls.java
+++ b/Mage.Sets/src/mage/sets/stronghold/DreamHalls.java
@@ -58,7 +58,6 @@ public class DreamHalls extends CardImpl {
super(ownerId, 28, "Dream Halls", Rarity.RARE, new CardType[]{CardType.ENCHANTMENT}, "{3}{U}{U}");
this.expansionSetCode = "STH";
-
// Rather than pay the mana cost for a spell, its controller may discard a card that shares a color with that spell.
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new DreamHallsEffect()));
}
@@ -102,13 +101,13 @@ class DreamHallsEffect extends ContinuousEffectImpl {
public boolean apply(Layer layer, SubLayer sublayer, Ability source, Game game) {
Player controller = game.getPlayer(source.getControllerId());
if (controller != null) {
- for (UUID playerId: controller.getInRange()) {
+ for (UUID playerId : controller.getInRange()) {
Player player = game.getPlayer(playerId);
if (player != null) {
player.getAlternativeSourceCosts().add(alternativeCastingCostAbility);
}
}
-
+
return true;
}
return false;
diff --git a/Mage.Sets/src/mage/sets/tempest/Propaganda.java b/Mage.Sets/src/mage/sets/tempest/Propaganda.java
index 9b5f60aa26..4939421251 100644
--- a/Mage.Sets/src/mage/sets/tempest/Propaganda.java
+++ b/Mage.Sets/src/mage/sets/tempest/Propaganda.java
@@ -30,7 +30,7 @@ package mage.sets.tempest;
import java.util.UUID;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.costs.mana.ManaCostsImpl;
-import mage.abilities.effects.common.replacement.CantAttackYouUnlessPayManaAllEffect;
+import mage.abilities.effects.common.combat.CantAttackYouUnlessPayManaAllEffect;
import mage.cards.CardImpl;
import mage.constants.CardType;
import mage.constants.Rarity;
diff --git a/Mage.Sets/src/mage/sets/tenthedition/WindbornMuse.java b/Mage.Sets/src/mage/sets/tenthedition/WindbornMuse.java
index b16714da35..cd938527a2 100644
--- a/Mage.Sets/src/mage/sets/tenthedition/WindbornMuse.java
+++ b/Mage.Sets/src/mage/sets/tenthedition/WindbornMuse.java
@@ -29,21 +29,14 @@ package mage.sets.tenthedition;
import java.util.UUID;
import mage.MageInt;
-import mage.abilities.Ability;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.costs.mana.ManaCostsImpl;
-import mage.abilities.effects.ReplacementEffectImpl;
-import mage.abilities.effects.common.replacement.CantAttackYouUnlessPayManaAllEffect;
+import mage.abilities.effects.common.combat.CantAttackYouUnlessPayManaAllEffect;
import mage.abilities.keyword.FlyingAbility;
import mage.cards.CardImpl;
import mage.constants.CardType;
-import mage.constants.Duration;
-import mage.constants.Outcome;
import mage.constants.Rarity;
import mage.constants.Zone;
-import mage.game.Game;
-import mage.game.events.GameEvent;
-import mage.players.Player;
/**
*
@@ -75,56 +68,3 @@ public class WindbornMuse extends CardImpl {
return new WindbornMuse(this);
}
}
-
-class WindbornMuseReplacementEffect extends ReplacementEffectImpl {
-
- private static final String effectText = "Creatures can't attack you unless their controller pays {2} for each creature he or she controls that's attacking you";
-
- WindbornMuseReplacementEffect() {
- super(Duration.WhileOnBattlefield, Outcome.Benefit);
- staticText = effectText;
- }
-
- WindbornMuseReplacementEffect(WindbornMuseReplacementEffect effect) {
- super(effect);
- }
-
- @Override
- public boolean checksEventType(GameEvent event, Game game) {
- return event.getType() == GameEvent.EventType.DECLARE_ATTACKER;
- }
-
- @Override
- public boolean applies(GameEvent event, Ability source, Game game) {
- if (event.getTargetId().equals(source.getControllerId())) {
- Player attackedPlayer = game.getPlayer(event.getTargetId());
- if (attackedPlayer != null) {
- // only if a player is attacked. Attacking a planeswalker is free
- return true;
- }
- }
- return false;
- }
-
- @Override
- public boolean replaceEvent(GameEvent event, Ability source, Game game) {
- Player player = game.getPlayer(event.getPlayerId());
- if (player != null && event.getTargetId().equals(source.getControllerId())) {
- ManaCostsImpl attackTax = new ManaCostsImpl("{2}");
- if (attackTax.canPay(source, source.getSourceId(), event.getPlayerId(), game)
- && player.chooseUse(Outcome.Benefit, "Pay {2} to attack player?", source, game)) {
- if (attackTax.payOrRollback(source, game, this.getId(), event.getPlayerId())) {
- return false;
- }
- }
- return true;
- }
- return false;
- }
-
- @Override
- public WindbornMuseReplacementEffect copy() {
- return new WindbornMuseReplacementEffect(this);
- }
-
-}
diff --git a/Mage.Sets/src/mage/sets/timespiral/DeepSeaKraken.java b/Mage.Sets/src/mage/sets/timespiral/DeepSeaKraken.java
index 5df16776da..ac50ef010e 100644
--- a/Mage.Sets/src/mage/sets/timespiral/DeepSeaKraken.java
+++ b/Mage.Sets/src/mage/sets/timespiral/DeepSeaKraken.java
@@ -34,11 +34,12 @@ import mage.abilities.condition.common.SuspendedCondition;
import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.decorator.ConditionalTriggeredAbility;
import mage.abilities.effects.common.counter.RemoveCounterSourceEffect;
-import mage.abilities.keyword.SuspendAbility;
import mage.abilities.keyword.CantBeBlockedSourceAbility;
+import mage.abilities.keyword.SuspendAbility;
import mage.cards.CardImpl;
import mage.constants.CardType;
import mage.constants.Rarity;
+import mage.constants.SetTargetPointer;
import mage.constants.TargetController;
import mage.constants.Zone;
import mage.counters.CounterType;
@@ -52,6 +53,7 @@ import mage.filter.predicate.permanent.ControllerPredicate;
public class DeepSeaKraken extends CardImpl {
private static final FilterSpell filter = new FilterSpell("an opponent casts");
+
static {
filter.add(new ControllerPredicate(TargetController.OPPONENT));
}
@@ -70,7 +72,7 @@ public class DeepSeaKraken extends CardImpl {
this.addAbility(new SuspendAbility(9, new ManaCostsImpl("{2}{U}"), this));
// Whenever an opponent casts a spell, if Deep-Sea Kraken is suspended, remove a time counter from it.
this.addAbility(new ConditionalTriggeredAbility(
- new SpellCastAllTriggeredAbility(Zone.EXILED, new RemoveCounterSourceEffect(CounterType.TIME.createInstance()), filter, false, null), SuspendedCondition.getInstance(),
+ new SpellCastAllTriggeredAbility(Zone.EXILED, new RemoveCounterSourceEffect(CounterType.TIME.createInstance()), filter, false, SetTargetPointer.NONE), SuspendedCondition.getInstance(),
"Whenever an opponent casts a spell, if Deep-Sea Kraken is suspended, remove a time counter from it.", false));
}
diff --git a/Mage.Sets/src/mage/sets/urzassaga/Persecute.java b/Mage.Sets/src/mage/sets/urzassaga/Persecute.java
index 5c83ad2eea..82d8dfe6f5 100644
--- a/Mage.Sets/src/mage/sets/urzassaga/Persecute.java
+++ b/Mage.Sets/src/mage/sets/urzassaga/Persecute.java
@@ -29,6 +29,7 @@ package mage.sets.urzassaga;
import java.util.Set;
import java.util.UUID;
+import mage.MageObject;
import mage.abilities.Ability;
import mage.abilities.effects.OneShotEffect;
import mage.cards.Card;
@@ -52,7 +53,6 @@ public class Persecute extends CardImpl {
super(ownerId, 146, "Persecute", Rarity.RARE, new CardType[]{CardType.SORCERY}, "{2}{B}{B}");
this.expansionSetCode = "USG";
-
// Choose a color. Target player reveals his or her hand and discards all cards of that color.
this.getSpellAbility().addEffect(new PersecuteEffect());
this.getSpellAbility().addTarget(new TargetPlayer());
@@ -88,19 +88,20 @@ class PersecuteEffect extends OneShotEffect {
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getFirstTarget());
- if (controller != null) {
+ MageObject sourceObject = game.getObject(source.getSourceId());
+ if (controller != null && sourceObject != null) {
ChoiceColor choice = new ChoiceColor();
while (!choice.isChosen()) {
controller.choose(outcome, choice, game);
if (!controller.isInGame()) {
return false;
}
- }
+ }
if (choice.getColor() == null) {
return false;
}
Cards hand = controller.getHand();
- controller.revealCards("Persecute", hand, game);
+ controller.revealCards(sourceObject.getIdName(), hand, game);
Set cards = hand.getCards(game);
for (Card card : cards) {
if (card != null && card.getColor(game).shares(choice.getColor())) {
diff --git a/Mage.Sets/src/mage/sets/visions/ElephantGrass.java b/Mage.Sets/src/mage/sets/visions/ElephantGrass.java
index 2c10185b73..46bbb1c09e 100644
--- a/Mage.Sets/src/mage/sets/visions/ElephantGrass.java
+++ b/Mage.Sets/src/mage/sets/visions/ElephantGrass.java
@@ -28,18 +28,20 @@
package mage.sets.visions;
import java.util.UUID;
-
-import mage.constants.*;
-import mage.abilities.Ability;
+import mage.ObjectColor;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.costs.mana.ManaCostsImpl;
-import mage.abilities.effects.ReplacementEffectImpl;
+import mage.abilities.effects.common.combat.CantAttackYouAllEffect;
+import mage.abilities.effects.common.combat.CantAttackYouUnlessPayManaAllEffect;
import mage.abilities.keyword.CumulativeUpkeepAbility;
import mage.cards.CardImpl;
-import mage.game.Game;
-import mage.game.events.GameEvent;
-import mage.game.permanent.Permanent;
-import mage.players.Player;
+import mage.constants.CardType;
+import mage.constants.Duration;
+import mage.constants.Rarity;
+import mage.constants.Zone;
+import mage.filter.common.FilterCreaturePermanent;
+import mage.filter.predicate.Predicates;
+import mage.filter.predicate.mageobject.ColorPredicate;
/**
*
@@ -47,16 +49,26 @@ import mage.players.Player;
*/
public class ElephantGrass extends CardImpl {
+ private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("Nonblack creatures");
+ private static final FilterCreaturePermanent filterBlack = new FilterCreaturePermanent("Black creatures");
+
+ static {
+ filter.add(Predicates.not(new ColorPredicate(ObjectColor.BLACK)));
+ filterBlack.add(new ColorPredicate(ObjectColor.BLACK));
+ }
+
public ElephantGrass(UUID ownerId) {
super(ownerId, 54, "Elephant Grass", Rarity.UNCOMMON, new CardType[]{CardType.ENCHANTMENT}, "{G}");
this.expansionSetCode = "VIS";
// Cumulative upkeep {1}
this.addAbility(new CumulativeUpkeepAbility(new ManaCostsImpl("{1}")));
+
// Black creatures can't attack you.
- this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new ElephantGrassReplacementEffect()));
+ this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new CantAttackYouAllEffect(Duration.WhileOnBattlefield, filterBlack)));
+
// Nonblack creatures can't attack you unless their controller pays {2} for each creature he or she controls that's attacking you.
- this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new ElephantGrassReplacementEffect2()));
+ this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new CantAttackYouUnlessPayManaAllEffect(new ManaCostsImpl<>("{2"), false, filter)));
}
public ElephantGrass(final ElephantGrass card) {
@@ -68,97 +80,3 @@ public class ElephantGrass extends CardImpl {
return new ElephantGrass(this);
}
}
-
-
-class ElephantGrassReplacementEffect extends ReplacementEffectImpl {
-
- ElephantGrassReplacementEffect ( ) {
- super(Duration.WhileOnBattlefield, Outcome.Neutral);
- staticText = "Black creatures can't attack you";
- }
-
- ElephantGrassReplacementEffect ( ElephantGrassReplacementEffect effect ) {
- super(effect);
- }
-
- @Override
- public boolean checksEventType(GameEvent event, Game game) {
- return event.getType() == GameEvent.EventType.DECLARE_ATTACKER;
- }
-
- @Override
- public boolean applies(GameEvent event, Ability source, Game game) {
- if (event.getTargetId().equals(source.getControllerId()) ) {
- Permanent creature = game.getPermanent(event.getSourceId());
- if(creature != null && creature.getColor(game).isBlack()){
- return true;
- }
- }
- return false;
- }
-
- @Override
- public boolean replaceEvent(GameEvent event, Ability source, Game game) {
- return true;
- }
-
- @Override
- public ElephantGrassReplacementEffect copy() {
- return new ElephantGrassReplacementEffect(this);
- }
-
-}
-
-class ElephantGrassReplacementEffect2 extends ReplacementEffectImpl {
-
- ElephantGrassReplacementEffect2 ( ) {
- super(Duration.WhileOnBattlefield, Outcome.Neutral);
- staticText = "Nonblack creatures can't attack you unless their controller pays {2} for each creature he or she controls that's attacking you";
- }
-
- ElephantGrassReplacementEffect2 ( ElephantGrassReplacementEffect2 effect ) {
- super(effect);
- }
-
- @Override
- public boolean replaceEvent(GameEvent event, Ability source, Game game) {
- Player player = game.getPlayer(event.getPlayerId());
- if ( player != null && event.getTargetId().equals(source.getControllerId())) {
- ManaCostsImpl attackCost = new ManaCostsImpl("{2}");
- if ( attackCost.canPay(source, source.getSourceId(), event.getPlayerId(), game) &&
- player.chooseUse(Outcome.Benefit, "Pay {2} to attack player?", source, game) ) {
- if (attackCost.payOrRollback(source, game, this.getId(), event.getPlayerId())) {
- return false;
- }
- }
- return true;
- }
- return false;
- }
-
- @Override
- public boolean checksEventType(GameEvent event, Game game) {
- return event.getType() == GameEvent.EventType.DECLARE_ATTACKER;
- }
-
- @Override
- public boolean applies(GameEvent event, Ability source, Game game) {
- if (event.getTargetId().equals(source.getControllerId()) ) {
- Permanent creature = game.getPermanent(event.getSourceId());
- if (creature != null && !creature.getColor(game).isBlack()) {
- Player attackedPlayer = game.getPlayer(event.getTargetId());
- if (attackedPlayer != null) {
- // only if a player is attacked. Attacking a planeswalker is free
- return true;
- }
- }
- }
- return false;
- }
-
- @Override
- public ElephantGrassReplacementEffect2 copy() {
- return new ElephantGrassReplacementEffect2(this);
- }
-
-}
diff --git a/Mage.Sets/src/mage/sets/visions/PhyrexianMarauder.java b/Mage.Sets/src/mage/sets/visions/PhyrexianMarauder.java
index 6d13d24901..3079b7ca4d 100644
--- a/Mage.Sets/src/mage/sets/visions/PhyrexianMarauder.java
+++ b/Mage.Sets/src/mage/sets/visions/PhyrexianMarauder.java
@@ -34,23 +34,20 @@ import mage.abilities.SpellAbility;
import mage.abilities.common.CantBlockAbility;
import mage.abilities.common.EntersBattlefieldAbility;
import mage.abilities.common.SimpleStaticAbility;
-import mage.abilities.costs.mana.ManaCost;
+import mage.abilities.costs.mana.ManaCosts;
import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.effects.EntersBattlefieldEffect;
import mage.abilities.effects.OneShotEffect;
-import mage.abilities.effects.ReplacementEffectImpl;
+import mage.abilities.effects.common.combat.CantAttackBlockUnlessPaysSourceEffect;
import mage.cards.CardImpl;
import mage.constants.CardType;
-import mage.constants.Duration;
import mage.constants.Outcome;
import mage.constants.Rarity;
import mage.constants.Zone;
import mage.counters.CounterType;
import mage.game.Game;
import mage.game.events.GameEvent;
-import mage.game.events.GameEvent.EventType;
import mage.game.permanent.Permanent;
-import mage.players.Player;
/**
*
@@ -67,12 +64,12 @@ public class PhyrexianMarauder extends CardImpl {
// Phyrexian Marauder enters the battlefield with X +1/+1 counters on it.
this.addAbility(new EntersBattlefieldAbility(new PhyrexianMarauderEntersEffect(), "with X +1/+1 counters on it"));
-
+
// Phyrexian Marauder can't block.
this.addAbility(new CantBlockAbility());
-
+
// Phyrexian Marauder can't attack unless you pay {1} for each +1/+1 counter on it.
- this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new PhyrexianMarauderPayEffect()));
+ this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new PhyrexianMarauderCantAttackUnlessYouPayEffect()));
}
public PhyrexianMarauder(final PhyrexianMarauder card) {
@@ -116,53 +113,37 @@ class PhyrexianMarauderEntersEffect extends OneShotEffect {
}
}
-class PhyrexianMarauderPayEffect extends ReplacementEffectImpl {
+class PhyrexianMarauderCantAttackUnlessYouPayEffect extends CantAttackBlockUnlessPaysSourceEffect {
- PhyrexianMarauderPayEffect() {
- super(Duration.WhileOnBattlefield, Outcome.Neutral);
+ PhyrexianMarauderCantAttackUnlessYouPayEffect() {
+ super(new ManaCostsImpl("{0}"), RestrictType.ATTACK);
staticText = "{this} can't attack unless you pay {1} for each +1/+1 counter on it";
}
- PhyrexianMarauderPayEffect(PhyrexianMarauderPayEffect effect) {
+ PhyrexianMarauderCantAttackUnlessYouPayEffect(PhyrexianMarauderCantAttackUnlessYouPayEffect effect) {
super(effect);
}
- @Override
- public boolean replaceEvent(GameEvent event, Ability source, Game game) {
- Player player = game.getPlayer(event.getPlayerId());
- Permanent permanent = game.getPermanent(source.getSourceId());
- if (player != null && permanent != null) {
- int xValue = permanent.getCounters().getCount(CounterType.P1P1);
- String chooseText;
- if (event.getType().equals(GameEvent.EventType.DECLARE_ATTACKER)) {
- chooseText = "Pay {" + xValue + "} to attack?";
- } else {
- chooseText = "Pay {" + xValue + "} to block?";
- }
- ManaCostsImpl attackTax = new ManaCostsImpl<>("{" + xValue + "}");
- if (attackTax.canPay(source, source.getSourceId(), event.getPlayerId(), game)
- && player.chooseUse(Outcome.Neutral, chooseText, source, game)) {
- if (attackTax.payOrRollback(source, game, source.getSourceId(), event.getPlayerId())) {
- return false;
- }
- }
- return true;
- }
- return false;
- }
-
- @Override
- public boolean checksEventType(GameEvent event, Game game) {
- return event.getType() == EventType.DECLARE_ATTACKER;
- }
-
@Override
public boolean applies(GameEvent event, Ability source, Game game) {
- return event.getSourceId().equals(source.getSourceId());
+ return source.getSourceId().equals(event.getSourceId());
}
@Override
- public PhyrexianMarauderPayEffect copy() {
- return new PhyrexianMarauderPayEffect(this);
+ public ManaCosts getManaCostToPay(GameEvent event, Ability source, Game game) {
+ Permanent sourceObject = game.getPermanent(source.getSourceId());
+ if (sourceObject != null) {
+ int counter = sourceObject.getCounters().getCount(CounterType.P1P1);
+ if (counter > 0) {
+ return new ManaCostsImpl<>("{" + counter + "}");
+ }
+ }
+ return null;
}
+
+ @Override
+ public PhyrexianMarauderCantAttackUnlessYouPayEffect copy() {
+ return new PhyrexianMarauderCantAttackUnlessYouPayEffect(this);
+ }
+
}
diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/cost/alternate/OmniscienceTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/cost/alternate/OmniscienceTest.java
index 941a069618..02ab0f8a23 100644
--- a/Mage.Tests/src/test/java/org/mage/test/cards/cost/alternate/OmniscienceTest.java
+++ b/Mage.Tests/src/test/java/org/mage/test/cards/cost/alternate/OmniscienceTest.java
@@ -2,44 +2,43 @@ package org.mage.test.cards.cost.alternate;
import mage.constants.PhaseStep;
import mage.constants.Zone;
-
import org.junit.Test;
import org.mage.test.serverside.base.CardTestPlayerBase;
public class OmniscienceTest extends CardTestPlayerBase {
-
- @Test
- public void testSpellNoCost() {
+
+ @Test
+ public void testSpellNoCost() {
+ // You may cast nonland cards from your hand without paying their mana costs.
addCard(Zone.BATTLEFIELD, playerA, "Omniscience", 1);
-
+
addCard(Zone.HAND, playerA, "Gray Ogre", 1);
-
+
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Gray Ogre");
setStopAt(1, PhaseStep.END_TURN);
execute();
-
+
//Gray Ogre is cast because it is free
assertPermanentCount(playerA, "Gray Ogre", 1);
- }
-
- @Test
- public void testSpellHasCostIfCastFromGraveyard() {
+ }
+
+ @Test
+ public void testSpellHasCostIfCastFromGraveyard() {
+ // You may cast nonland cards from your hand without paying their mana costs.
addCard(Zone.BATTLEFIELD, playerA, "Omniscience", 1);
-
+
addCard(Zone.BATTLEFIELD, playerA, "Haakon, Stromgald Scourge", 1);
-
+
addCard(Zone.GRAVEYARD, playerA, "Knight of the White Orchid", 1);
-
+
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Knight of the White Orchid");
setStopAt(1, PhaseStep.END_TURN);
execute();
-
+
//Knight of the White Orchid was not cast due to lack of mana
assertPermanentCount(playerA, "Knight of the White Orchid", 0);
- }
-
-
+ }
}
diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/cost/alternate/UseAlternateSourceCostsTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/cost/alternate/UseAlternateSourceCostsTest.java
new file mode 100644
index 0000000000..125f37f8fd
--- /dev/null
+++ b/Mage.Tests/src/test/java/org/mage/test/cards/cost/alternate/UseAlternateSourceCostsTest.java
@@ -0,0 +1,104 @@
+/*
+ * 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 org.mage.test.cards.cost.alternate;
+
+import mage.constants.PhaseStep;
+import mage.constants.Zone;
+import org.junit.Test;
+import org.mage.test.serverside.base.CardTestPlayerBase;
+
+/**
+ *
+ * @author LevelX2
+ */
+public class UseAlternateSourceCostsTest extends CardTestPlayerBase {
+
+ @Test
+ public void DreamHallsCastColoredSpell() {
+ // Rather than pay the mana cost for a spell, its controller may discard a card that shares a color with that spell.
+ addCard(Zone.BATTLEFIELD, playerA, "Dream Halls", 1);
+ addCard(Zone.BATTLEFIELD, playerA, "Mountain", 3); // Add the mountains so the spell is included in teh available spells
+
+ addCard(Zone.HAND, playerA, "Gray Ogre", 1); // Creature 3/1
+ addCard(Zone.HAND, playerA, "Lightning Bolt", 1);
+
+ castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Gray Ogre"); // Cast Orgre by discarding the Lightning Bolt
+
+ setStopAt(1, PhaseStep.BEGIN_COMBAT);
+ execute();
+
+ //Gray Ogre is cast with the discard
+ assertPermanentCount(playerA, "Gray Ogre", 1);
+ assertGraveyardCount(playerA, "Lightning Bolt", 1);
+ assertTapped("Mountain", false);
+ }
+
+ @Test
+ public void DreamHallsCantCastColorlessSpell() {
+ // Rather than pay the mana cost for a spell, its controller may discard a card that shares a color with that spell.
+ addCard(Zone.BATTLEFIELD, playerA, "Dream Halls", 1);
+ addCard(Zone.BATTLEFIELD, playerA, "Mountain", 4); // Add the mountains so the spell is included in teh available spells
+
+ addCard(Zone.HAND, playerA, "Juggernaut", 1); // Creature 5/3 - {4}
+ addCard(Zone.HAND, playerA, "Haunted Plate Mail", 1);
+
+ castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Juggernaut"); // Cast Juggernaut by discarding Haunted Plate Mail may not work
+
+ setStopAt(1, PhaseStep.BEGIN_COMBAT);
+ execute();
+
+ assertGraveyardCount(playerA, "Haunted Plate Mail", 0);
+ assertTapped("Mountain", true);
+ //Juggernaut is not cast by alternate casting costs
+ assertPermanentCount(playerA, "Juggernaut", 1);
+ }
+
+ @Test
+ public void DreamHallsCastWithFutureSight() {
+ // Rather than pay the mana cost for a spell, its controller may discard a card that shares a color with that spell.
+ addCard(Zone.BATTLEFIELD, playerA, "Dream Halls", 1);
+ // Play with the top card of your library revealed.
+ // You may play the top card of your library.
+ addCard(Zone.BATTLEFIELD, playerA, "Future Sight", 1);
+ addCard(Zone.BATTLEFIELD, playerA, "Mountain", 3); // Add the mountains so the spell is included in teh available spells
+
+ addCard(Zone.LIBRARY, playerA, "Gray Ogre", 1); // Creature 3/1
+ addCard(Zone.HAND, playerA, "Lightning Bolt", 1);
+ skipInitShuffling();
+
+ castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Gray Ogre"); // Cast Orgre by discarding the Lightning Bolt
+
+ setStopAt(1, PhaseStep.BEGIN_COMBAT);
+ execute();
+
+ assertTapped("Mountain", false);
+ //Gray Ogre is cast with the discard
+ assertPermanentCount(playerA, "Gray Ogre", 1);
+ assertGraveyardCount(playerA, "Lightning Bolt", 1);
+ }
+}
diff --git a/Mage.Tests/src/test/java/org/mage/test/serverside/base/impl/CardTestPlayerAPIImpl.java b/Mage.Tests/src/test/java/org/mage/test/serverside/base/impl/CardTestPlayerAPIImpl.java
index 8b910600cb..331f42e4fe 100644
--- a/Mage.Tests/src/test/java/org/mage/test/serverside/base/impl/CardTestPlayerAPIImpl.java
+++ b/Mage.Tests/src/test/java/org/mage/test/serverside/base/impl/CardTestPlayerAPIImpl.java
@@ -41,13 +41,14 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement
// Defines the constant if for activate ability is not target but a ability on the stack to define
public static final String NO_TARGET = "NO_TARGET";
-
+
protected GameOptions gameOptions;
-
+
protected String deckNameA;
protected String deckNameB;
-
+
protected enum ExpectedType {
+
TURN_NUMBER,
RESULT,
LIFE,
@@ -55,14 +56,15 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement
GRAVEYARD,
UNKNOWN
}
-
+
static {
// CardScanner.scanned = true;
CardScanner.scan();
}
/**
- * Default game initialization params for red player (that plays with Mountains)
+ * Default game initialization params for red player (that plays with
+ * Mountains)
*/
@Override
public void useRedDefault() {
@@ -88,7 +90,8 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement
}
/**
- * Default game initialization params for white player (that plays with Plains)
+ * Default game initialization params for white player (that plays with
+ * Plains)
*/
public void useWhiteDefault() {
// *** ComputerA ***
@@ -103,7 +106,7 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement
removeAllCardsFromLibrary(playerB);
addCard(Zone.LIBRARY, playerB, "Plains", 10);
}
-
+
@Before
public void reset() throws GameException, FileNotFoundException {
if (currentGame != null) {
@@ -120,7 +123,7 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement
stopAtStep = PhaseStep.UNTAP;
for (Player player : currentGame.getPlayers().values()) {
- TestPlayer testPlayer = (TestPlayer)player;
+ TestPlayer testPlayer = (TestPlayer) player;
getCommands(testPlayer).clear();
getLibraryCards(testPlayer).clear();
getHandCards(testPlayer).clear();
@@ -132,11 +135,11 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement
}
abstract protected Game createNewGameAndPlayers() throws GameException, FileNotFoundException;
-
+
protected TestPlayer createPlayer(Game game, TestPlayer player, String name) throws GameException {
return createPlayer(game, player, name, "RB Aggro.dck");
}
-
+
protected TestPlayer createPlayer(Game game, TestPlayer player, String name, String deckName) throws GameException {
player = createNewPlayer(name);
player.setTestMode(true);
@@ -147,7 +150,7 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement
throw new IllegalArgumentException("Couldn't load deck, deck size=" + deck.getCards().size());
}
game.loadCards(deck.getCards(), player.getId());
- game.loadCards(deck.getSideboard(), player.getId());
+ game.loadCards(deck.getSideboard(), player.getId());
game.addPlayer(player, deck);
return player;
@@ -156,7 +159,8 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement
/**
* Starts testing card by starting current game.
*
- * @throws IllegalStateException In case game wasn't created previously. Use {@link #load} method to initialize the game.
+ * @throws IllegalStateException In case game wasn't created previously. Use
+ * {@link #load} method to initialize the game.
*/
public void execute() throws IllegalStateException {
if (currentGame == null || activePlayer == null) {
@@ -164,7 +168,7 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement
}
for (Player player : currentGame.getPlayers().values()) {
- TestPlayer testPlayer = (TestPlayer)player;
+ TestPlayer testPlayer = (TestPlayer) player;
currentGame.cheat(player.getId(), getCommands(testPlayer));
currentGame.cheat(player.getId(), getLibraryCards(testPlayer), getHandCards(testPlayer),
getBattlefieldCards(testPlayer), getGraveCards(testPlayer));
@@ -182,13 +186,11 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement
logger.info("Test has been executed. Execution time: " + (t2 - t1) / 1000000 + " ms");
}
-
-
-
+
protected TestPlayer createNewPlayer(String playerName) {
return createPlayer(playerName);
}
-
+
protected Player getPlayerFromName(String playerName, String line) {
Player player = null;
switch (playerName) {
@@ -209,10 +211,11 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement
}
return player;
}
-
+
/**
- * Removes all cards from player's library from the game.
- * Usually this should be used once before initialization to form the library in certain order.
+ * Removes all cards from player's library from the game. Usually this
+ * should be used once before initialization to form the library in certain
+ * order.
*
* @param player {@link Player} to remove all library cards from.
*/
@@ -221,8 +224,8 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement
}
/**
- * Removes all cards from player's hand from the game.
- * Usually this should be used once before initialization to set the players hand.
+ * Removes all cards from player's hand from the game. Usually this should
+ * be used once before initialization to set the players hand.
*
* @param player {@link Player} to remove all cards from hand.
*/
@@ -234,7 +237,8 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement
* Add a card to specified zone of specified player.
*
* @param gameZone {@link mage.constants.Zone} to add cards to.
- * @param player {@link Player} to add cards for. Use either playerA or playerB.
+ * @param player {@link Player} to add cards for. Use either playerA or
+ * playerB.
* @param cardName Card name in string format.
*/
public void addCard(Zone gameZone, TestPlayer player, String cardName) {
@@ -245,9 +249,10 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement
* Add any amount of cards to specified zone of specified player.
*
* @param gameZone {@link mage.constants.Zone} to add cards to.
- * @param player {@link Player} to add cards for. Use either playerA or playerB.
+ * @param player {@link Player} to add cards for. Use either playerA or
+ * playerB.
* @param cardName Card name in string format.
- * @param count Amount of cards to be added.
+ * @param count Amount of cards to be added.
*/
public void addCard(Zone gameZone, TestPlayer player, String cardName, int count) {
addCard(gameZone, player, cardName, count, false);
@@ -257,11 +262,13 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement
* Add any amount of cards to specified zone of specified player.
*
* @param gameZone {@link mage.constants.Zone} to add cards to.
- * @param player {@link Player} to add cards for. Use either playerA or playerB.
+ * @param player {@link Player} to add cards for. Use either playerA or
+ * playerB.
* @param cardName Card name in string format.
- * @param count Amount of cards to be added.
- * @param tapped In case gameZone is Battlefield, determines whether permanent should be tapped.
- * In case gameZone is other than Battlefield, {@link IllegalArgumentException} is thrown
+ * @param count Amount of cards to be added.
+ * @param tapped In case gameZone is Battlefield, determines whether
+ * permanent should be tapped. In case gameZone is other than Battlefield,
+ * {@link IllegalArgumentException} is thrown
*/
public void addCard(Zone gameZone, TestPlayer player, String cardName, int count, boolean tapped) {
@@ -315,7 +322,7 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement
* Set player's initial life count.
*
* @param player {@link Player} to set life count for.
- * @param life Life count to set.
+ * @param life Life count to set.
*/
public void setLife(TestPlayer player, int life) {
getCommands(player).put(Zone.OUTSIDE, "life:" + String.valueOf(life));
@@ -323,6 +330,7 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement
/**
* Define turn number to stop the game on.
+ *
* @param turn
*/
@Override
@@ -332,8 +340,9 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement
}
/**
- * Define turn number and step to stop the game on.
- * The game stops after executing the step
+ * Define turn number and step to stop the game on. The game stops after
+ * executing the step
+ *
* @param turn
* @param step
*/
@@ -389,7 +398,7 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement
* Assert player's life count after test execution.
*
* @param player {@link Player} to get life for comparison.
- * @param life Expected player's life to compare with.
+ * @param life Expected player's life to compare with.
*/
@Override
public void assertLife(Player player, int life) throws AssertionError {
@@ -400,19 +409,20 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement
/**
* Assert creature's power and toughness by card name.
*
- * Throws {@link AssertionError} in the following cases:
- * 1. no such player
- * 2. no such creature under player's control
- * 3. depending on comparison scope:
- * 3a. any: no creature under player's control with the specified p\t params
- * 3b. all: there is at least one creature with the cardName with the different p\t params
+ * Throws {@link AssertionError} in the following cases: 1. no such player
+ * 2. no such creature under player's control 3. depending on comparison
+ * scope: 3a. any: no creature under player's control with the specified p\t
+ * params 3b. all: there is at least one creature with the cardName with the
+ * different p\t params
*
- * @param player {@link Player} to get creatures for comparison.
- * @param cardName Card name to compare with.
- * @param power Expected power to compare with.
+ * @param player {@link Player} to get creatures for comparison.
+ * @param cardName Card name to compare with.
+ * @param power Expected power to compare with.
* @param toughness Expected toughness to compare with.
- * @param scope {@link mage.filter.Filter.ComparisonScope} Use ANY, if you want "at least one creature with given name should have specified p\t"
- * Use ALL, if you want "all creature with gived name should have specified p\t"
+ * @param scope {@link mage.filter.Filter.ComparisonScope} Use ANY, if you
+ * want "at least one creature with given name should have specified p\t"
+ * Use ALL, if you want "all creature with gived name should have specified
+ * p\t"
*/
@Override
public void assertPowerToughness(Player player, String cardName, int power, int toughness, Filter.ComparisonScope scope)
@@ -442,18 +452,19 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement
}
}
- Assert.assertTrue("There is no such permanent under player's control, player=" + player.getName() +
- ", cardName=" + cardName, count > 0);
+ Assert.assertTrue("There is no such permanent under player's control, player=" + player.getName()
+ + ", cardName=" + cardName, count > 0);
if (scope.equals(Filter.ComparisonScope.Any)) {
- Assert.assertTrue("There is no such creature under player's control with specified power&toughness, player=" + player.getName() +
- ", cardName=" + cardName + " (found similar: " + found + ", one of them: power=" + foundPower + " toughness=" + foundToughness + ")", fit > 0);
+ Assert.assertTrue("There is no such creature under player's control with specified power&toughness, player=" + player.getName()
+ + ", cardName=" + cardName + " (found similar: " + found + ", one of them: power=" + foundPower + " toughness=" + foundToughness + ")", fit > 0);
}
}
/**
- * See {@link #assertPowerToughness(mage.players.Player, String, int, int, mage.filter.Filter.ComparisonScope)}
- *
+ * See
+ * {@link #assertPowerToughness(mage.players.Player, String, int, int, mage.filter.Filter.ComparisonScope)}
+ *
* @param player
* @param cardName
* @param power
@@ -478,15 +489,15 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement
}
}
- Assert.assertNotNull("There is no such permanent under player's control, player=" + player.getName() +
- ", cardName=" + cardName, found);
+ Assert.assertNotNull("There is no such permanent under player's control, player=" + player.getName()
+ + ", cardName=" + cardName, found);
- Assert.assertTrue("There is more than one such permanent under player's control, player=" + player.getName() +
- ", cardName=" + cardName, count == 1);
+ Assert.assertTrue("There is more than one such permanent under player's control, player=" + player.getName()
+ + ", cardName=" + cardName, count == 1);
for (Ability ability : abilities) {
- Assert.assertTrue("No such ability=" + ability.toString() + ", player=" + player.getName() +
- ", cardName" + cardName, found.getAbilities().contains(ability));
+ Assert.assertTrue("No such ability=" + ability.toString() + ", player=" + player.getName()
+ + ", cardName" + cardName, found.getAbilities().contains(ability));
}
}
@@ -495,7 +506,8 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement
* @param player
* @param cardName
* @param ability
- * @param flag true if creature should contain ability, false if it should NOT contain it instead
+ * @param flag true if creature should contain ability, false if it should
+ * NOT contain it instead
* @throws AssertionError
*/
public void assertAbility(Player player, String cardName, Ability ability, boolean flag) throws AssertionError {
@@ -508,18 +520,18 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement
}
}
- Assert.assertNotNull("There is no such permanent under player's control, player=" + player.getName() +
- ", cardName=" + cardName, found);
+ Assert.assertNotNull("There is no such permanent under player's control, player=" + player.getName()
+ + ", cardName=" + cardName, found);
- Assert.assertTrue("There is more than one such permanent under player's control, player=" + player.getName() +
- ", cardName=" + cardName, count == 1);
+ Assert.assertTrue("There is more than one such permanent under player's control, player=" + player.getName()
+ + ", cardName=" + cardName, count == 1);
if (flag) {
- Assert.assertTrue("No such ability=" + ability.toString() + ", player=" + player.getName() +
- ", cardName" + cardName, found.getAbilities().containsRule(ability));
+ Assert.assertTrue("No such ability=" + ability.toString() + ", player=" + player.getName()
+ + ", cardName" + cardName, found.getAbilities().containsRule(ability));
} else {
- Assert.assertFalse("Card shouldn't have such ability=" + ability.toString() + ", player=" + player.getName() +
- ", cardName" + cardName, found.getAbilities().containsRule(ability));
+ Assert.assertFalse("Card shouldn't have such ability=" + ability.toString() + ", player=" + player.getName()
+ + ", cardName" + cardName, found.getAbilities().containsRule(ability));
}
}
@@ -527,7 +539,7 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement
* Assert permanent count under player's control.
*
* @param player {@link Player} which permanents should be counted.
- * @param count Expected count.
+ * @param count Expected count.
*/
@Override
public void assertPermanentCount(Player player, int count) throws AssertionError {
@@ -543,9 +555,9 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement
/**
* Assert permanent count under player's control.
*
- * @param player {@link Player} which permanents should be counted.
+ * @param player {@link Player} which permanents should be counted.
* @param cardName Name of the cards that should be counted.
- * @param count Expected count.
+ * @param count Expected count.
*/
@Override
public void assertPermanentCount(Player player, String cardName, int count) throws AssertionError {
@@ -580,9 +592,9 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement
/**
* Assert counter count on a permanent
*
- * @param cardName Name of the cards that should be counted.
- * @param type Type of the counter that should be counted.
- * @param count Expected count.
+ * @param cardName Name of the cards that should be counted.
+ * @param type Type of the counter that should be counted.
+ * @param count Expected count.
*/
public void assertCounterCount(String cardName, CounterType type, int count) throws AssertionError {
Permanent found = null;
@@ -595,35 +607,36 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement
Assert.assertNotNull("There is no such permanent on the battlefield, cardName=" + cardName, found);
Assert.assertEquals("(Battlefield) Counter counts are not equal (" + cardName + ":" + type + ")", count, found.getCounters().getCount(type));
}
+
/**
- * Assert counter count on a card in exile
+ * Assert counter count on a card in exile
*
- * @param cardName Name of the cards that should be counted.
- * @param type Type of the counter that should be counted.
- * @param count Expected count.
+ * @param cardName Name of the cards that should be counted.
+ * @param type Type of the counter that should be counted.
+ * @param count Expected count.
*/
public void assertCounterOnExiledCardCount(String cardName, CounterType type, int count) throws AssertionError {
Card found = null;
if (found == null) {
- for (Card card : currentGame.getExile().getAllCards(currentGame)) {
- if (card.getName().equals(cardName)) {
- found = card;
- break;
+ for (Card card : currentGame.getExile().getAllCards(currentGame)) {
+ if (card.getName().equals(cardName)) {
+ found = card;
+ break;
+ }
}
- }
-
+
}
Assert.assertNotNull("There is no such card in the exile, cardName=" + cardName, found);
Assert.assertEquals("(Exile) Counter counts are not equal (" + cardName + ":" + type + ")", count, found.getCounters(currentGame).getCount(type));
}
-
+
/**
* Assert counter count on a player
*
- * @param player The player whos counters should be counted.
- * @param type Type of the counter that should be counted.
- * @param count Expected count.
+ * @param player The player whos counters should be counted.
+ * @param type Type of the counter that should be counted.
+ * @param count Expected count.
*/
public void assertCounterCount(Player player, CounterType type, int count) throws AssertionError {
Assert.assertEquals("(Battlefield) Counter counts are not equal (" + player.getName() + ":" + type + ")", count, player.getCounters().getCount(type));
@@ -632,9 +645,9 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement
/**
* Assert whether a permanent is a specified type or not
*
- * @param cardName Name of the permanent that should be checked.
- * @param type A type to test for
- * @param flag true if creature should have type, false if it should not
+ * @param cardName Name of the permanent that should be checked.
+ * @param type A type to test for
+ * @param flag true if creature should have type, false if it should not
*/
public void assertType(String cardName, CardType type, boolean flag) throws AssertionError {
Permanent found = null;
@@ -654,9 +667,9 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement
/**
* Assert whether a permanent is a specified type
*
- * @param cardName Name of the permanent that should be checked.
- * @param type A type to test for
- * @param subType a subtype to test for
+ * @param cardName Name of the permanent that should be checked.
+ * @param type A type to test for
+ * @param subType a subtype to test for
*/
public void assertType(String cardName, CardType type, String subType) throws AssertionError {
Permanent found = null;
@@ -677,14 +690,19 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement
/**
* Assert whether a permanent is tapped or not
*
- * @param cardName Name of the permanent that should be checked.
- * @param tapped Whether the permanent is tapped or not
+ * @param cardName Name of the permanent that should be checked.
+ * @param tapped Whether the permanent is tapped or not
*/
public void assertTapped(String cardName, boolean tapped) throws AssertionError {
Permanent found = null;
for (Permanent permanent : currentGame.getBattlefield().getAllActivePermanents()) {
if (permanent.getName().equals(cardName)) {
- found = permanent;
+ if (found == null) {
+ found = permanent;
+ } else if (tapped != found.isTapped()) { // try to find a not correct permanent
+ found = permanent;
+ break;
+ }
}
}
@@ -696,8 +714,8 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement
/**
* Assert whether a permanent is attacking or not
*
- * @param cardName Name of the permanent that should be checked.
- * @param attacking Whether the permanent is attacking or not
+ * @param cardName Name of the permanent that should be checked.
+ * @param attacking Whether the permanent is attacking or not
*/
public void assertAttacking(String cardName, boolean attacking) throws AssertionError {
Permanent found = null;
@@ -715,8 +733,8 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement
/**
* Assert card count in player's hand.
*
- * @param player {@link Player} who's hand should be counted.
- * @param count Expected count.
+ * @param player {@link Player} who's hand should be counted.
+ * @param count Expected count.
*/
public void assertHandCount(Player player, int count) throws AssertionError {
int actual = currentGame.getPlayer(player.getId()).getHand().size();
@@ -726,9 +744,9 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement
/**
* Assert card count in player's hand.
*
- * @param player {@link Player} who's hand should be counted.
- * @param cardName Name of the cards that should be counted.
- * @param count Expected count.
+ * @param player {@link Player} who's hand should be counted.
+ * @param cardName Name of the cards that should be counted.
+ * @param count Expected count.
*/
public void assertHandCount(Player player, String cardName, int count) throws AssertionError {
FilterCard filter = new FilterCard();
@@ -740,8 +758,8 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement
/**
* Assert card count in player's graveyard.
*
- * @param player {@link Player} who's graveyard should be counted.
- * @param count Expected count.
+ * @param player {@link Player} who's graveyard should be counted.
+ * @param count Expected count.
*/
public void assertGraveyardCount(Player player, int count) throws AssertionError {
int actual = currentGame.getPlayer(player.getId()).getGraveyard().size();
@@ -751,12 +769,12 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement
/**
* Assert card count in exile.
*
- * @param cardName Name of the cards that should be counted.
- * @param count Expected count.
+ * @param cardName Name of the cards that should be counted.
+ * @param count Expected count.
*/
public void assertExileCount(String cardName, int count) throws AssertionError {
int actualCount = 0;
- for (ExileZone exile: currentGame.getExile().getExileZones()) {
+ for (ExileZone exile : currentGame.getExile().getExileZones()) {
for (Card card : exile.getCards(currentGame)) {
if (card.getName().equals(cardName)) {
actualCount++;
@@ -770,12 +788,12 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement
/**
* Assert card count in exile by owner.
*
- * @param owner player that owns the cards.
- * @param count Expected count.
+ * @param owner player that owns the cards.
+ * @param count Expected count.
*/
public void assertExileCount(Player owner, int count) throws AssertionError {
int actualCount = 0;
- for (ExileZone exile: currentGame.getExile().getExileZones()) {
+ for (ExileZone exile : currentGame.getExile().getExileZones()) {
for (Card card : exile.getCards(currentGame)) {
if (card.getOwnerId().equals(owner.getId())) {
actualCount++;
@@ -789,9 +807,9 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement
/**
* Assert card count in player's graveyard.
*
- * @param player {@link Player} who's graveyard should be counted.
+ * @param player {@link Player} who's graveyard should be counted.
* @param cardName Name of the cards that should be counted.
- * @param count Expected count.
+ * @param count Expected count.
*/
public void assertGraveyardCount(Player player, String cardName, int count) throws AssertionError {
int actualCount = 0;
@@ -805,7 +823,9 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement
}
/**
- * Asserts added actions count. Usefull to make sure that all actions were executed.
+ * Asserts added actions count. Usefull to make sure that all actions were
+ * executed.
+ *
* @param player
* @param count
*/
@@ -850,38 +870,42 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement
}
/**
- *
+ *
* @param turnNum
* @param step
* @param player
* @param cardName
- * @param targetName for modes you can add "mode=3" before target name, multiple targets can be seperated by ^
+ * @param targetName for modes you can add "mode=3" before target name,
+ * multiple targets can be seperated by ^
*/
public void castSpell(int turnNum, PhaseStep step, TestPlayer player, String cardName, String targetName) {
player.addAction(turnNum, step, "activate:Cast " + cardName + "$target=" + targetName);
}
public enum StackClause {
+
WHILE_ON_STACK,
WHILE_NOT_ON_STACK;
}
/**
- * Spell will only be cast, if a spell / ability with the given name is on the stack
- *
+ * Spell will only be cast, if a spell / ability with the given name is on
+ * the stack
+ *
* @param turnNum
* @param step
* @param player
* @param cardName
* @param targetName
- * @param spellOnStack
+ * @param spellOnStack
*/
public void castSpell(int turnNum, PhaseStep step, TestPlayer player, String cardName, String targetName, String spellOnStack) {
castSpell(turnNum, step, player, cardName, targetName, spellOnStack, StackClause.WHILE_ON_STACK);
}
/**
- * Spell will only be cast, if a spell / ability with the given name IS or IS NOT on the stack
+ * Spell will only be cast, if a spell / ability with the given name IS or
+ * IS NOT on the stack
*
* @param turnNum
* @param step
@@ -927,18 +951,19 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement
}
/**
- *
+ *
* @param turnNum
* @param step
* @param player
* @param ability
- * @param targetName if not target has to be defined use the constant NO_TARGET
- * @param spellOnStack
+ * @param targetName if not target has to be defined use the constant
+ * NO_TARGET
+ * @param spellOnStack
*/
public void activateAbility(int turnNum, PhaseStep step, TestPlayer player, String ability, String targetName, String spellOnStack) {
StringBuilder sb = new StringBuilder("activate:").append(ability);
if (targetName != null && !targetName.isEmpty()) {
- sb.append("$target=" ).append(targetName);
+ sb.append("$target=").append(targetName);
}
if (spellOnStack != null && !spellOnStack.isEmpty()) {
sb.append("$spellOnStack=").append(spellOnStack);
@@ -951,11 +976,11 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement
}
public void attack(int turnNum, TestPlayer player, String attacker) {
- player.addAction(turnNum, PhaseStep.DECLARE_ATTACKERS, "attack:"+attacker);
+ player.addAction(turnNum, PhaseStep.DECLARE_ATTACKERS, "attack:" + attacker);
}
-
+
public void attack(int turnNum, TestPlayer player, String attacker, TestPlayer defendingPlayer) {
- player.addAction(turnNum, PhaseStep.DECLARE_ATTACKERS, "attack:"+attacker+"$defendingPlayer="+defendingPlayer.getName());
+ player.addAction(turnNum, PhaseStep.DECLARE_ATTACKERS, "attack:" + attacker + "$defendingPlayer=" + defendingPlayer.getName());
}
public void attack(int turnNum, TestPlayer player, String attacker, String planeswalker) {
@@ -963,13 +988,13 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement
}
public void block(int turnNum, TestPlayer player, String blocker, String attacker) {
- player.addAction(turnNum, PhaseStep.DECLARE_BLOCKERS, "block:"+blocker+"$"+attacker);
+ player.addAction(turnNum, PhaseStep.DECLARE_BLOCKERS, "block:" + blocker + "$" + attacker);
}
/**
- * For use choices set "Yes" or "No" the the choice string.
- * For X values set "X=[xValue]" example: for X=3 set choice string to "X=3".
- *
+ * For use choices set "Yes" or "No" the the choice string. For X values set
+ * "X=[xValue]" example: for X=3 set choice string to "X=3".
+ *
* @param player
* @param choice
*/
@@ -979,9 +1004,10 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement
/**
* Set the modes for modal spells
- *
+ *
* @param player
- * @param choice starting with "1" for mode 1, "2" for mode 2 and so on (to set multiple modes call the command multiple times)
+ * @param choice starting with "1" for mode 1, "2" for mode 2 and so on (to
+ * set multiple modes call the command multiple times)
*/
public void setModeChoice(TestPlayer player, String choice) {
player.addModeChoice(choice);
@@ -991,39 +1017,39 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement
* Set target permanents
*
* @param player
- * @param target you can add multiple targets by seperating them by the "^" character
- * e.g. "creatureName1^creatureName2"
- * you can qualify the target additional by setcode
- * e.g. "creatureName-M15"
- * you can add [no copy] to the end of the target name to prohibite targets that are copied
- * you can add [only copy] to the end of the target name to allow only targets that are copies
+ * @param target you can add multiple targets by seperating them by the "^"
+ * character e.g. "creatureName1^creatureName2" you can qualify the target
+ * additional by setcode e.g. "creatureName-M15" you can add [no copy] to
+ * the end of the target name to prohibite targets that are copied you can
+ * add [only copy] to the end of the target name to allow only targets that
+ * are copies
*/
public void addTarget(TestPlayer player, String target) {
player.addTarget(target);
}
-
+
/**
* Sets a player as target
- *
+ *
* @param player
- * @param targetPlayer
+ * @param targetPlayer
*/
public void addTarget(TestPlayer player, TestPlayer targetPlayer) {
- player.addTarget("targetPlayer="+targetPlayer.getName());
+ player.addTarget("targetPlayer=" + targetPlayer.getName());
}
-
+
public void setDecknamePlayerA(String deckname) {
deckNameA = deckname;
}
-
+
public void setDecknamePlayerB(String deckname) {
deckNameB = deckname;
}
-
+
protected void skipInitShuffling() {
gameOptions.skipInitShuffling = true;
}
-
+
protected ExpectedType getExpectedType(String line) {
if (line.startsWith("turn:")) {
return ExpectedType.TURN_NUMBER;
@@ -1042,7 +1068,7 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement
}
return ExpectedType.UNKNOWN;
}
-
+
protected String getStringParam(String line, int index) {
String[] params = line.split(":");
if (index > params.length - 1) {
@@ -1050,7 +1076,7 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement
}
return params[index];
}
-
+
protected void checkPermanentPT(Player player, String cardName, int power, int toughness, Filter.ComparisonScope scope) {
if (currentGame == null) {
throw new IllegalStateException("Current game is null");
@@ -1066,7 +1092,7 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement
break;
}
}
- }
+ }
protected int getIntParam(String line, int index) {
String[] params = line.split(":");
@@ -1074,6 +1100,6 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement
throw new IllegalArgumentException("Not correct line: " + line);
}
return Integer.parseInt(params[index]);
- }
-
+ }
+
}
diff --git a/Mage/src/mage/ObjectColor.java b/Mage/src/mage/ObjectColor.java
index 812e45f187..c34ea4269d 100644
--- a/Mage/src/mage/ObjectColor.java
+++ b/Mage/src/mage/ObjectColor.java
@@ -1,31 +1,30 @@
/*
-* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
-*
-* Redistribution and use in source and binary forms, with or without modification, are
-* permitted provided that the following conditions are met:
-*
-* 1. Redistributions of source code must retain the above copyright notice, this list of
-* conditions and the following disclaimer.
-*
-* 2. Redistributions in binary form must reproduce the above copyright notice, this list
-* of conditions and the following disclaimer in the documentation and/or other materials
-* provided with the distribution.
-*
-* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
-* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
-* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
-* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
-* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
-* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
-* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-*
-* The views and conclusions contained in the software and documentation are those of the
-* authors and should not be interpreted as representing official policies, either expressed
-* or implied, of BetaSteward_at_googlemail.com.
-*/
-
+ * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and should not be interpreted as representing official policies, either expressed
+ * or implied, of BetaSteward_at_googlemail.com.
+ */
package mage;
import java.io.Serializable;
@@ -50,26 +49,27 @@ public class ObjectColor implements Serializable, Copyable, Compara
private boolean red;
private boolean green;
- public ObjectColor() {}
+ public ObjectColor() {
+ }
public ObjectColor(String color) {
for (int i = 0; i < color.length(); i++) {
switch (color.charAt(i)) {
- case 'W':
- white = true;
- break;
- case 'U':
- blue = true;
- break;
- case 'B':
- black = true;
- break;
- case 'R':
- red = true;
- break;
- case 'G':
- green = true;
- break;
+ case 'W':
+ white = true;
+ break;
+ case 'U':
+ blue = true;
+ break;
+ case 'B':
+ black = true;
+ break;
+ case 'R':
+ red = true;
+ break;
+ case 'G':
+ green = true;
+ break;
}
}
}
@@ -157,30 +157,39 @@ public class ObjectColor implements Serializable, Copyable, Compara
public boolean isWhite() {
return white;
}
+
public void setWhite(boolean white) {
this.white = white;
}
+
public boolean isBlue() {
return blue;
}
+
public void setBlue(boolean blue) {
this.blue = blue;
}
+
public boolean isBlack() {
return black;
}
+
public void setBlack(boolean black) {
this.black = black;
}
+
public boolean isRed() {
return red;
}
+
public void setRed(boolean red) {
this.red = red;
}
+
public boolean isGreen() {
return green;
}
+
public void setGreen(boolean green) {
this.green = green;
}
@@ -287,14 +296,10 @@ public class ObjectColor implements Serializable, Copyable, Compara
}
public boolean shares(ObjectColor color) {
- if (this == color) {
- return true;
- }
- if (!hasColor() && !color.hasColor()) {
- return true;
- }
- return color.white && white || color.blue && blue || color.black && black ||
- color.red && red || color.green && green;
+ // 105.4. [...] “Multicolored” is not a color. Neither is “colorless.”
+ return !color.isColorless()
+ && (color.white && white || color.blue && blue || color.black && black
+ || color.red && red || color.green && green);
}
@Override
@@ -309,32 +314,32 @@ public class ObjectColor implements Serializable, Copyable, Compara
if (this.isMulticolored()) {
o1 = 6;
- } else if(this.isColorless()) {
+ } else if (this.isColorless()) {
o1 = 0;
- } else if(this.isBlack()) {
+ } else if (this.isBlack()) {
o1 = 1;
- } else if(this.isBlue()) {
+ } else if (this.isBlue()) {
o1 = 2;
- } else if(this.isGreen()) {
+ } else if (this.isGreen()) {
o1 = 3;
- } else if(this.isRed()) {
+ } else if (this.isRed()) {
o1 = 4;
- } else if(this.isWhite()) {
+ } else if (this.isWhite()) {
o1 = 5;
}
if (o.isMulticolored()) {
o2 = 6;
- } else if(o.isColorless()) {
+ } else if (o.isColorless()) {
o2 = 0;
- } else if(o.isBlack()) {
+ } else if (o.isBlack()) {
o2 = 1;
- } else if(o.isBlue()) {
+ } else if (o.isBlue()) {
o2 = 2;
- } else if(o.isGreen()) {
+ } else if (o.isGreen()) {
o2 = 3;
- } else if(o.isRed()) {
+ } else if (o.isRed()) {
o2 = 4;
- } else if(o.isWhite()) {
+ } else if (o.isWhite()) {
o2 = 5;
}
return o1 - o2;
diff --git a/Mage/src/mage/abilities/effects/ContinuousEffects.java b/Mage/src/mage/abilities/effects/ContinuousEffects.java
index 12ae10a9fc..9f8f39211e 100644
--- a/Mage/src/mage/abilities/effects/ContinuousEffects.java
+++ b/Mage/src/mage/abilities/effects/ContinuousEffects.java
@@ -336,7 +336,8 @@ public class ContinuousEffects implements Serializable {
if (ability.getAbilityType() != AbilityType.STATIC || ability.isInUseableZone(game, null, event)) {
if (effect.getDuration() != Duration.OneUse || !effect.isUsed()) {
if (!game.getScopeRelevant() || effect.hasSelfScope() || !event.getTargetId().equals(ability.getSourceId())) {
- if (effect.applies(event, ability, game)) {
+ if (effect.applies(event, ability, game)
+ && !((PayCostToAttackBlockEffect) effect).isCostless(event, ability, game)) {
return true;
}
}
diff --git a/Mage/src/mage/abilities/effects/PayCostToAttackBlockEffect.java b/Mage/src/mage/abilities/effects/PayCostToAttackBlockEffect.java
index f73af6074f..d9b9b8a150 100644
--- a/Mage/src/mage/abilities/effects/PayCostToAttackBlockEffect.java
+++ b/Mage/src/mage/abilities/effects/PayCostToAttackBlockEffect.java
@@ -42,4 +42,6 @@ public interface PayCostToAttackBlockEffect extends ReplacementEffect {
ManaCosts getManaCostToPay(GameEvent event, Ability source, Game game);
Cost getOtherCostToPay(GameEvent event, Ability source, Game game);
+
+ boolean isCostless(GameEvent event, Ability source, Game game);
}
diff --git a/Mage/src/mage/abilities/effects/PayCostToAttackBlockEffectImpl.java b/Mage/src/mage/abilities/effects/PayCostToAttackBlockEffectImpl.java
index 9473fbcd9c..d31b8e71cf 100644
--- a/Mage/src/mage/abilities/effects/PayCostToAttackBlockEffectImpl.java
+++ b/Mage/src/mage/abilities/effects/PayCostToAttackBlockEffectImpl.java
@@ -46,13 +46,26 @@ public abstract class PayCostToAttackBlockEffectImpl extends ReplacementEffectIm
public static enum RestrictType {
- ATTACK, ATTACK_AND_BLOCK, BLOCK
+ ATTACK("attack"),
+ ATTACK_AND_BLOCK("attack or block"),
+ BLOCK("block");
+
+ private final String text;
+
+ RestrictType(String text) {
+ this.text = text;
+ }
+
+ @Override
+ public String toString() {
+ return text;
+ }
}
- private final Cost cost;
- private final ManaCosts manaCosts;
+ protected final Cost cost;
+ protected final ManaCosts manaCosts;
- private final RestrictType restrictType;
+ protected final RestrictType restrictType;
public PayCostToAttackBlockEffectImpl(Duration duration, Outcome outcome, RestrictType restrictType) {
super(duration, outcome, false);
@@ -165,4 +178,13 @@ public abstract class PayCostToAttackBlockEffectImpl extends ReplacementEffectIm
return manaCosts;
}
+ @Override
+ public boolean isCostless(GameEvent event, Ability source, Game game) {
+ ManaCosts currentManaCosts = getManaCostToPay(event, source, game);
+ if (currentManaCosts != null && currentManaCosts.convertedManaCost() > 0) {
+ return false;
+ }
+ return getOtherCostToPay(event, source, game) == null;
+ }
+
}
diff --git a/Mage/src/mage/abilities/effects/common/combat/CantAttackBlockUnlessPaysAttachedEffect.java b/Mage/src/mage/abilities/effects/common/combat/CantAttackBlockUnlessPaysAttachedEffect.java
new file mode 100644
index 0000000000..3a0a9b6f10
--- /dev/null
+++ b/Mage/src/mage/abilities/effects/common/combat/CantAttackBlockUnlessPaysAttachedEffect.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and should not be interpreted as representing official policies, either expressed
+ * or implied, of BetaSteward_at_googlemail.com.
+ */
+package mage.abilities.effects.common.combat;
+
+import mage.abilities.Ability;
+import mage.abilities.costs.mana.ManaCosts;
+import mage.abilities.effects.PayCostToAttackBlockEffectImpl;
+import mage.abilities.effects.PayCostToAttackBlockEffectImpl.RestrictType;
+import mage.constants.AttachmentType;
+import mage.constants.Duration;
+import mage.constants.Outcome;
+import mage.game.Game;
+import mage.game.events.GameEvent;
+import mage.game.events.GameEvent.EventType;
+import mage.game.permanent.Permanent;
+
+/**
+ *
+ * @author LevelX2
+ */
+public class CantAttackBlockUnlessPaysAttachedEffect extends PayCostToAttackBlockEffectImpl {
+
+ public CantAttackBlockUnlessPaysAttachedEffect(ManaCosts manaCosts, AttachmentType attachmentType) {
+ super(Duration.WhileOnBattlefield, Outcome.Detriment, RestrictType.ATTACK_AND_BLOCK, manaCosts);
+ staticText = attachmentType.equals(AttachmentType.AURA) ? "Enchanted " : "Equipped "
+ + "creature can't attack or block unless its controller pays "
+ + manaCosts == null ? "" : manaCosts.getText();
+ }
+
+ public CantAttackBlockUnlessPaysAttachedEffect(CantAttackBlockUnlessPaysAttachedEffect effect) {
+ super(effect);
+ }
+
+ @Override
+ public boolean applies(GameEvent event, Ability source, Game game) {
+ Permanent enchantment = game.getPermanent(source.getSourceId());
+ if (enchantment != null && enchantment.getAttachedTo() != null) {
+ if (event.getType().equals(EventType.DECLARE_ATTACKER)) {
+ return event.getSourceId().equals(enchantment.getAttachedTo());
+ }
+ if (event.getType().equals(EventType.DECLARE_BLOCKER)) {
+ return event.getSourceId().equals(enchantment.getAttachedTo());
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public CantAttackBlockUnlessPaysAttachedEffect copy() {
+ return new CantAttackBlockUnlessPaysAttachedEffect(this);
+ }
+}
diff --git a/Mage/src/mage/abilities/effects/common/combat/CantAttackBlockUnlessPaysSourceEffect.java b/Mage/src/mage/abilities/effects/common/combat/CantAttackBlockUnlessPaysSourceEffect.java
new file mode 100644
index 0000000000..b20b50b857
--- /dev/null
+++ b/Mage/src/mage/abilities/effects/common/combat/CantAttackBlockUnlessPaysSourceEffect.java
@@ -0,0 +1,78 @@
+/*
+ * 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.combat;
+
+import mage.abilities.Ability;
+import mage.abilities.costs.Cost;
+import mage.abilities.costs.mana.ManaCosts;
+import mage.abilities.effects.PayCostToAttackBlockEffectImpl;
+import mage.constants.Duration;
+import mage.constants.Outcome;
+import mage.game.Game;
+import mage.game.events.GameEvent;
+import mage.game.events.GameEvent.EventType;
+
+/**
+ *
+ * @author LevelX2
+ */
+public class CantAttackBlockUnlessPaysSourceEffect extends PayCostToAttackBlockEffectImpl {
+
+ public CantAttackBlockUnlessPaysSourceEffect(Cost cost, RestrictType restrictType) {
+ super(Duration.WhileOnBattlefield, Outcome.Detriment, restrictType, cost);
+ staticText = "{this} can't " + restrictType.toString() + " unless you "
+ + cost == null ? "" : cost.getText()
+ + (restrictType.equals(RestrictType.ATTACK) ? " (This cost is paid as attackers are declared.)" : "");
+ }
+
+ public CantAttackBlockUnlessPaysSourceEffect(ManaCosts manaCosts, RestrictType restrictType) {
+ super(Duration.WhileOnBattlefield, Outcome.Detriment, RestrictType.ATTACK_AND_BLOCK, manaCosts);
+ staticText = "{this} can't " + restrictType.toString() + " unless you pay "
+ + manaCosts == null ? "" : manaCosts.getText();
+ }
+
+ public CantAttackBlockUnlessPaysSourceEffect(CantAttackBlockUnlessPaysSourceEffect effect) {
+ super(effect);
+ }
+
+ @Override
+ public boolean applies(GameEvent event, Ability source, Game game) {
+ if (!restrictType.equals(RestrictType.BLOCK) && event.getType().equals(EventType.DECLARE_ATTACKER)) {
+ return event.getSourceId().equals(source.getSourceId());
+ }
+ if (!restrictType.equals(RestrictType.ATTACK) && event.getType().equals(EventType.DECLARE_BLOCKER)) {
+ return event.getSourceId().equals(source.getSourceId());
+ }
+ return false;
+ }
+
+ @Override
+ public CantAttackBlockUnlessPaysSourceEffect copy() {
+ return new CantAttackBlockUnlessPaysSourceEffect(this);
+ }
+}
diff --git a/Mage/src/mage/abilities/effects/common/combat/CantAttackYouAllEffect.java b/Mage/src/mage/abilities/effects/common/combat/CantAttackYouAllEffect.java
new file mode 100644
index 0000000000..519ad93ff7
--- /dev/null
+++ b/Mage/src/mage/abilities/effects/common/combat/CantAttackYouAllEffect.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and should not be interpreted as representing official policies, either expressed
+ * or implied, of BetaSteward_at_googlemail.com.
+ */
+package mage.abilities.effects.common.combat;
+
+import java.util.UUID;
+import mage.abilities.Ability;
+import mage.abilities.effects.RestrictionEffect;
+import mage.constants.Duration;
+import mage.constants.Outcome;
+import mage.filter.common.FilterCreaturePermanent;
+import mage.game.Game;
+import mage.game.permanent.Permanent;
+
+/**
+ *
+ * @author LevelX2
+ */
+public class CantAttackYouAllEffect extends RestrictionEffect {
+
+ private final FilterCreaturePermanent filterAttacker;
+
+ public CantAttackYouAllEffect(Duration duration) {
+ this(duration, new FilterCreaturePermanent());
+ }
+
+ public CantAttackYouAllEffect(Duration duration, FilterCreaturePermanent filter) {
+ super(duration, Outcome.Benefit);
+ this.filterAttacker = filter;
+ staticText = "Creatures can't attack you";
+ }
+
+ CantAttackYouAllEffect(final CantAttackYouAllEffect effect) {
+ super(effect);
+ this.filterAttacker = effect.filterAttacker;
+ }
+
+ @Override
+ public boolean applies(Permanent permanent, Ability source, Game game) {
+ return filterAttacker.match(permanent, source.getSourceId(), source.getControllerId(), game);
+ }
+
+ @Override
+ public boolean canAttack(UUID defenderId, Ability source, Game game) {
+ return !defenderId.equals(source.getControllerId());
+ }
+
+ @Override
+ public CantAttackYouAllEffect copy() {
+ return new CantAttackYouAllEffect(this);
+ }
+}
diff --git a/Mage/src/mage/abilities/effects/common/combat/CantAttackYouUnlessPayManaAllEffect.java b/Mage/src/mage/abilities/effects/common/combat/CantAttackYouUnlessPayManaAllEffect.java
new file mode 100644
index 0000000000..1846384395
--- /dev/null
+++ b/Mage/src/mage/abilities/effects/common/combat/CantAttackYouUnlessPayManaAllEffect.java
@@ -0,0 +1,84 @@
+/*
+ * To change this license header, choose License Headers in Project Properties.
+ * To change this template file, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package mage.abilities.effects.common.combat;
+
+import mage.abilities.Ability;
+import mage.abilities.costs.mana.ManaCosts;
+import mage.abilities.effects.PayCostToAttackBlockEffectImpl;
+import mage.abilities.effects.PayCostToAttackBlockEffectImpl.RestrictType;
+import mage.constants.CardType;
+import mage.constants.Duration;
+import mage.constants.Outcome;
+import mage.filter.common.FilterCreaturePermanent;
+import mage.game.Game;
+import mage.game.events.GameEvent;
+import mage.game.permanent.Permanent;
+
+/**
+ *
+ * @author LevelX2
+ */
+public class CantAttackYouUnlessPayManaAllEffect extends PayCostToAttackBlockEffectImpl {
+
+ private final FilterCreaturePermanent filterCreaturePermanent;
+ private final boolean payAlsoForAttackingPlaneswalker;
+
+ public CantAttackYouUnlessPayManaAllEffect(ManaCosts manaCosts) {
+ this(manaCosts, false);
+ }
+
+ public CantAttackYouUnlessPayManaAllEffect(ManaCosts manaCosts, boolean payAlsoForAttackingPlaneswalker) {
+ this(manaCosts, payAlsoForAttackingPlaneswalker, null);
+ }
+
+ public CantAttackYouUnlessPayManaAllEffect(ManaCosts manaCosts, boolean payAlsoForAttackingPlaneswalker, FilterCreaturePermanent filter) {
+ super(Duration.WhileOnBattlefield, Outcome.Detriment, RestrictType.ATTACK, manaCosts);
+ this.payAlsoForAttackingPlaneswalker = payAlsoForAttackingPlaneswalker;
+ this.filterCreaturePermanent = filter;
+ staticText = (filterCreaturePermanent == null ? "Creatures" : filterCreaturePermanent.getMessage())
+ + " can't attack you "
+ + (payAlsoForAttackingPlaneswalker ? "or a planeswalker you control " : "")
+ + "unless their controller pays "
+ + (manaCosts == null ? "" : manaCosts.getText())
+ + " for each creature he or she controls that's attacking you";
+ }
+
+ public CantAttackYouUnlessPayManaAllEffect(CantAttackYouUnlessPayManaAllEffect effect) {
+ super(effect);
+ this.payAlsoForAttackingPlaneswalker = effect.payAlsoForAttackingPlaneswalker;
+ this.filterCreaturePermanent = effect.filterCreaturePermanent;
+ }
+
+ @Override
+ public boolean applies(GameEvent event, Ability source, Game game) {
+ // check if attacking creature fullfills filter criteria
+ if (filterCreaturePermanent != null) {
+ Permanent permanent = game.getPermanent(event.getSourceId());
+ if (!filterCreaturePermanent.match(permanent, source.getSourceId(), source.getControllerId(), game)) {
+ return false;
+ }
+ }
+ // attack target is controlling player
+ if (source.getControllerId().equals(event.getTargetId())) {
+ return true;
+ }
+ // or attack target is a planeswalker of the controlling player
+ if (payAlsoForAttackingPlaneswalker) {
+ Permanent permanent = game.getPermanent(event.getTargetId());
+ if (permanent != null
+ && permanent.getCardType().contains(CardType.PLANESWALKER)
+ && permanent.getControllerId().equals(source.getControllerId())) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public CantAttackYouUnlessPayManaAllEffect copy() {
+ return new CantAttackYouUnlessPayManaAllEffect(this);
+ }
+}
diff --git a/Mage/src/mage/abilities/effects/common/replacement/CantAttackYouUnlessPayManaAllEffect.java b/Mage/src/mage/abilities/effects/common/replacement/CantAttackYouUnlessPayManaAllEffect.java
deleted file mode 100644
index 36f7be673a..0000000000
--- a/Mage/src/mage/abilities/effects/common/replacement/CantAttackYouUnlessPayManaAllEffect.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * To change this license header, choose License Headers in Project Properties.
- * To change this template file, choose Tools | Templates
- * and open the template in the editor.
- */
-package mage.abilities.effects.common.replacement;
-
-import mage.abilities.Ability;
-import mage.abilities.costs.mana.ManaCosts;
-import mage.abilities.effects.PayCostToAttackBlockEffectImpl;
-import mage.abilities.effects.PayCostToAttackBlockEffectImpl.RestrictType;
-import mage.constants.Duration;
-import mage.constants.Outcome;
-import mage.game.Game;
-import mage.game.events.GameEvent;
-
-/**
- *
- * @author LevelX2
- */
-public class CantAttackYouUnlessPayManaAllEffect extends PayCostToAttackBlockEffectImpl {
-
- public CantAttackYouUnlessPayManaAllEffect(ManaCosts manaCosts) {
- super(Duration.WhileOnBattlefield, Outcome.Detriment, RestrictType.ATTACK, manaCosts);
- staticText = "Creatures can't attack you unless their controller pays " + manaCosts.getText() + " for each creature he or she controls that's attacking you";
- }
-
- CantAttackYouUnlessPayManaAllEffect(CantAttackYouUnlessPayManaAllEffect effect) {
- super(effect);
- }
-
- @Override
- public boolean applies(GameEvent event, Ability source, Game game) {
- return source.getControllerId().equals(event.getTargetId());
- }
-
- @Override
- public CantAttackYouUnlessPayManaAllEffect copy() {
- return new CantAttackYouUnlessPayManaAllEffect(this);
- }
-}
diff --git a/Mage/src/mage/game/combat/Combat.java b/Mage/src/mage/game/combat/Combat.java
index 80caa16dba..59317b4a64 100644
--- a/Mage/src/mage/game/combat/Combat.java
+++ b/Mage/src/mage/game/combat/Combat.java
@@ -71,6 +71,7 @@ public class Combat implements Serializable, Copyable {
protected List groups = new ArrayList<>();
protected Map blockingGroups = new HashMap<>();
+ // player and plainswalker ids
protected Set defenders = new HashSet<>();
// how many creatures attack defending player
protected Map> numberCreaturesDefenderAttackedBy = new HashMap<>();
diff --git a/Mage/src/mage/players/PlayerImpl.java b/Mage/src/mage/players/PlayerImpl.java
index 4fcd9df58f..6b8185d257 100644
--- a/Mage/src/mage/players/PlayerImpl.java
+++ b/Mage/src/mage/players/PlayerImpl.java
@@ -2459,6 +2459,22 @@ public abstract class PlayerImpl implements Player, Serializable {
}
}
}
+ // check if it's possible to play the top card of a library
+ for (UUID playerInRangeId : game.getState().getPlayersInRange(getId(), game)) {
+ Player player = game.getPlayer(playerInRangeId);
+ if (player != null) {
+ if (player.isTopCardRevealed() && player.getLibrary().size() > 0) {
+ Card card = player.getLibrary().getFromTop(game);
+ if (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);
+ }
+ }
+ }
+ }
+ }
+ }
// eliminate duplicate activated abilities
Map playableActivated = new HashMap<>();
for (Permanent permanent : game.getBattlefield().getAllActivePermanents(playerId)) {