diff --git a/Mage.Sets/src/mage/sets/avacynrestored/GuiseOfFire.java b/Mage.Sets/src/mage/sets/avacynrestored/GuiseOfFire.java
index d20155125a..a2177f742d 100644
--- a/Mage.Sets/src/mage/sets/avacynrestored/GuiseOfFire.java
+++ b/Mage.Sets/src/mage/sets/avacynrestored/GuiseOfFire.java
@@ -29,17 +29,17 @@ package mage.sets.avacynrestored;
import mage.constants.*;
import mage.abilities.Ability;
-import mage.abilities.common.AttacksEachTurnStaticAbility;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.effects.common.AttachEffect;
import mage.abilities.effects.common.continuous.BoostEnchantedEffect;
-import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect;
import mage.abilities.keyword.EnchantAbility;
import mage.cards.CardImpl;
import mage.target.TargetPermanent;
import mage.target.common.TargetCreaturePermanent;
import java.util.UUID;
+import mage.abilities.effects.Effect;
+import mage.abilities.effects.common.combat.AttacksIfAbleAttachedEffect;
/**
* @author noxx
@@ -51,7 +51,6 @@ public class GuiseOfFire extends CardImpl {
this.expansionSetCode = "AVR";
this.subtype.add("Aura");
-
// Enchant creature
TargetPermanent auraTarget = new TargetCreaturePermanent();
this.getSpellAbility().addTarget(auraTarget);
@@ -60,8 +59,12 @@ public class GuiseOfFire extends CardImpl {
this.addAbility(ability);
// Enchanted creature gets +1/-1 and attacks each turn if able.
- this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostEnchantedEffect(1, -1, Duration.WhileOnBattlefield)));
- this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityAttachedEffect(new AttacksEachTurnStaticAbility(), AttachmentType.AURA)));
+ ability = new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostEnchantedEffect(1, -1, Duration.WhileOnBattlefield));
+ Effect effect = new AttacksIfAbleAttachedEffect(Duration.WhileOnBattlefield, AttachmentType.AURA);
+ effect.setText("and attacks each turn if able");
+ ability.addEffect(effect);
+ this.addAbility(ability);
+
}
public GuiseOfFire(final GuiseOfFire card) {
diff --git a/Mage.Sets/src/mage/sets/championsofkamigawa/GhostlyPrison.java b/Mage.Sets/src/mage/sets/championsofkamigawa/GhostlyPrison.java
index a59826a420..120e33b61d 100644
--- a/Mage.Sets/src/mage/sets/championsofkamigawa/GhostlyPrison.java
+++ b/Mage.Sets/src/mage/sets/championsofkamigawa/GhostlyPrison.java
@@ -25,20 +25,15 @@
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
-
package mage.sets.championsofkamigawa;
import java.util.UUID;
import mage.constants.*;
-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.cards.CardImpl;
-import mage.game.Game;
-import mage.game.events.GameEvent;
-import mage.players.Player;
/**
*
@@ -46,16 +41,16 @@ import mage.players.Player;
*/
public class GhostlyPrison extends CardImpl {
- public GhostlyPrison (UUID ownerId) {
+ public GhostlyPrison(UUID ownerId) {
super(ownerId, 10, "Ghostly Prison", Rarity.UNCOMMON, new CardType[]{CardType.ENCHANTMENT}, "{2}{W}");
this.expansionSetCode = "CHK";
-
// 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 GhostlyPrisonReplacementEffect()));
+ this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new CantAttackYouUnlessPayManaAllEffect(new ManaCostsImpl("{2}"))));
+
}
- public GhostlyPrison (final GhostlyPrison card) {
+ public GhostlyPrison(final GhostlyPrison card) {
super(card);
}
@@ -65,58 +60,3 @@ public class GhostlyPrison extends CardImpl {
}
}
-
-class GhostlyPrisonReplacementEffect 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";
-
- GhostlyPrisonReplacementEffect ( ) {
- super(Duration.WhileOnBattlefield, Outcome.Neutral);
- staticText = effectText;
- }
-
- GhostlyPrisonReplacementEffect ( GhostlyPrisonReplacementEffect 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 GhostlyPrisonReplacementEffect copy() {
- return new GhostlyPrisonReplacementEffect(this);
- }
-
-}
-
diff --git a/Mage.Sets/src/mage/sets/championsofkamigawa/UncontrollableAnger.java b/Mage.Sets/src/mage/sets/championsofkamigawa/UncontrollableAnger.java
index 5da913217d..8a2b1d0863 100644
--- a/Mage.Sets/src/mage/sets/championsofkamigawa/UncontrollableAnger.java
+++ b/Mage.Sets/src/mage/sets/championsofkamigawa/UncontrollableAnger.java
@@ -25,21 +25,24 @@
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
-
package mage.sets.championsofkamigawa;
import java.util.UUID;
-
-import mage.constants.*;
import mage.abilities.Ability;
-import mage.abilities.common.AttacksEachTurnStaticAbility;
import mage.abilities.common.SimpleStaticAbility;
+import mage.abilities.effects.Effect;
import mage.abilities.effects.common.AttachEffect;
+import mage.abilities.effects.common.combat.AttacksIfAbleAttachedEffect;
import mage.abilities.effects.common.continuous.BoostEnchantedEffect;
-import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect;
import mage.abilities.keyword.EnchantAbility;
import mage.abilities.keyword.FlashAbility;
import mage.cards.CardImpl;
+import mage.constants.AttachmentType;
+import mage.constants.CardType;
+import mage.constants.Duration;
+import mage.constants.Outcome;
+import mage.constants.Rarity;
+import mage.constants.Zone;
import mage.target.TargetPermanent;
import mage.target.common.TargetCreaturePermanent;
@@ -49,22 +52,30 @@ import mage.target.common.TargetCreaturePermanent;
*/
public class UncontrollableAnger extends CardImpl {
- public UncontrollableAnger (UUID ownerId) {
+ public UncontrollableAnger(UUID ownerId) {
super(ownerId, 195, "Uncontrollable Anger", Rarity.COMMON, new CardType[]{CardType.ENCHANTMENT}, "{2}{R}{R}");
this.expansionSetCode = "CHK";
this.subtype.add("Aura");
+ // Flash (You may cast this spell any time you could cast an instant.)
+ this.addAbility(FlashAbility.getInstance());
+
+ // Enchant creature
TargetPermanent auraTarget = new TargetCreaturePermanent();
this.getSpellAbility().addTarget(auraTarget);
this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature));
Ability ability = new EnchantAbility(auraTarget.getTargetName());
this.addAbility(ability);
- this.addAbility(FlashAbility.getInstance());
- this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostEnchantedEffect(2, 2, Duration.WhileOnBattlefield)));
- this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityAttachedEffect(new AttacksEachTurnStaticAbility(), AttachmentType.AURA)));
+
+ // Enchanted creature gets +2/+2 and attacks each turn if able.
+ ability = new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostEnchantedEffect(2, 2, Duration.WhileOnBattlefield));
+ Effect effect = new AttacksIfAbleAttachedEffect(Duration.WhileOnBattlefield, AttachmentType.AURA);
+ effect.setText("and attacks each turn if able");
+ ability.addEffect(effect);
+ this.addAbility(ability);
}
- public UncontrollableAnger (final UncontrollableAnger card) {
+ public UncontrollableAnger(final UncontrollableAnger card) {
super(card);
}
diff --git a/Mage.Sets/src/mage/sets/exodus/ExaltedDragon.java b/Mage.Sets/src/mage/sets/exodus/ExaltedDragon.java
index f0aa723125..8c637213d2 100644
--- a/Mage.Sets/src/mage/sets/exodus/ExaltedDragon.java
+++ b/Mage.Sets/src/mage/sets/exodus/ExaltedDragon.java
@@ -31,9 +31,8 @@ import java.util.UUID;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.SimpleStaticAbility;
-import mage.abilities.costs.common.ReturnToHandTargetPermanentCost;
import mage.abilities.costs.common.SacrificeTargetCost;
-import mage.abilities.effects.ReplacementEffectImpl;
+import mage.abilities.effects.PayCostToAttackBlockEffectImpl;
import mage.abilities.keyword.FlyingAbility;
import mage.cards.CardImpl;
import mage.constants.CardType;
@@ -42,11 +41,8 @@ import mage.constants.Outcome;
import mage.constants.Rarity;
import mage.constants.Zone;
import mage.filter.common.FilterControlledLandPermanent;
-import mage.filter.common.FilterControlledPermanent;
-import mage.filter.predicate.mageobject.CardTypePredicate;
import mage.game.Game;
import mage.game.events.GameEvent;
-import mage.players.Player;
import mage.target.common.TargetControlledPermanent;
/**
@@ -64,9 +60,9 @@ public class ExaltedDragon extends CardImpl {
// Flying
this.addAbility(FlyingAbility.getInstance());
-
+
// Exalted Dragon can't attack unless you sacrifice a land.
- this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new ExaltedDragonReplacementEffect()));
+ this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new ExaltedDragonCostToAttackBlockEffect()));
}
public ExaltedDragon(final ExaltedDragon card) {
@@ -79,55 +75,26 @@ public class ExaltedDragon extends CardImpl {
}
}
-class ExaltedDragonReplacementEffect extends ReplacementEffectImpl {
+class ExaltedDragonCostToAttackBlockEffect extends PayCostToAttackBlockEffectImpl {
- private static final FilterControlledPermanent filter = new FilterControlledLandPermanent();
-
- ExaltedDragonReplacementEffect ( ) {
- super(Duration.WhileOnBattlefield, Outcome.Neutral);
+ ExaltedDragonCostToAttackBlockEffect() {
+ super(Duration.WhileOnBattlefield, Outcome.Detriment, RestrictType.ATTACK,
+ new SacrificeTargetCost(new TargetControlledPermanent(new FilterControlledLandPermanent("a land"))));
staticText = "{this} can't attack unless you sacrifice a land (This cost is paid as attackers are declared.)";
}
- ExaltedDragonReplacementEffect ( ExaltedDragonReplacementEffect effect ) {
+ ExaltedDragonCostToAttackBlockEffect(ExaltedDragonCostToAttackBlockEffect 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 ) {
- SacrificeTargetCost attackCost = new SacrificeTargetCost(new TargetControlledPermanent(filter));
- if ( attackCost.canPay(source, source.getSourceId(), event.getPlayerId(), game) &&
- player.chooseUse(Outcome.Neutral, "Sacrifice a land?", source, game) )
- {
- if (attackCost.pay(source, game, source.getSourceId(), event.getPlayerId(), false) ) {
- 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) {
- return event.getSourceId().equals(source.getSourceId());
+ return source.getSourceId().equals(event.getSourceId());
}
@Override
- public ExaltedDragonReplacementEffect copy() {
- return new ExaltedDragonReplacementEffect(this);
+ public ExaltedDragonCostToAttackBlockEffect copy() {
+ return new ExaltedDragonCostToAttackBlockEffect(this);
}
}
diff --git a/Mage.Sets/src/mage/sets/innistrad/FurorOfTheBitten.java b/Mage.Sets/src/mage/sets/innistrad/FurorOfTheBitten.java
index bc19111137..79252e39bd 100644
--- a/Mage.Sets/src/mage/sets/innistrad/FurorOfTheBitten.java
+++ b/Mage.Sets/src/mage/sets/innistrad/FurorOfTheBitten.java
@@ -28,19 +28,20 @@
package mage.sets.innistrad;
import java.util.UUID;
+import mage.abilities.Ability;
+import mage.abilities.common.SimpleStaticAbility;
+import mage.abilities.effects.Effect;
+import mage.abilities.effects.common.AttachEffect;
+import mage.abilities.effects.common.combat.AttacksIfAbleAttachedEffect;
+import mage.abilities.effects.common.continuous.BoostEnchantedEffect;
+import mage.abilities.keyword.EnchantAbility;
+import mage.cards.CardImpl;
import mage.constants.AttachmentType;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.Outcome;
import mage.constants.Rarity;
import mage.constants.Zone;
-import mage.abilities.common.AttacksEachTurnStaticAbility;
-import mage.abilities.common.SimpleStaticAbility;
-import mage.abilities.effects.common.AttachEffect;
-import mage.abilities.effects.common.continuous.BoostEnchantedEffect;
-import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect;
-import mage.abilities.keyword.EnchantAbility;
-import mage.cards.CardImpl;
import mage.target.TargetPermanent;
import mage.target.common.TargetCreaturePermanent;
@@ -55,15 +56,17 @@ public class FurorOfTheBitten extends CardImpl {
this.expansionSetCode = "ISD";
this.subtype.add("Aura");
-
// Enchant creature
TargetPermanent auraTarget = new TargetCreaturePermanent();
this.getSpellAbility().addTarget(auraTarget);
this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature));
this.addAbility(new EnchantAbility(auraTarget.getTargetName()));
+
// Enchanted creature gets +2/+2 and attacks each turn if able.
- SimpleStaticAbility ability = new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostEnchantedEffect(2, 2, Duration.WhileOnBattlefield));
- ability.addEffect(new GainAbilityAttachedEffect(new AttacksEachTurnStaticAbility(), AttachmentType.AURA));
+ Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostEnchantedEffect(2, 2, Duration.WhileOnBattlefield));
+ Effect effect = new AttacksIfAbleAttachedEffect(Duration.WhileOnBattlefield, AttachmentType.AURA);
+ effect.setText("and attacks each turn if able");
+ ability.addEffect(effect);
this.addAbility(ability);
}
diff --git a/Mage.Sets/src/mage/sets/riseoftheeldrazi/LustForWar.java b/Mage.Sets/src/mage/sets/riseoftheeldrazi/LustForWar.java
index a0fb89d181..403a433405 100644
--- a/Mage.Sets/src/mage/sets/riseoftheeldrazi/LustForWar.java
+++ b/Mage.Sets/src/mage/sets/riseoftheeldrazi/LustForWar.java
@@ -31,11 +31,11 @@ import java.util.UUID;
import mage.constants.*;
import mage.abilities.Ability;
-import mage.abilities.common.AttacksEachTurnStaticAbility;
import mage.abilities.common.BecomesTappedTriggeredAbility;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.effects.common.AttachEffect;
import mage.abilities.effects.common.DamageControllerEffect;
+import mage.abilities.effects.common.combat.AttacksIfAbleAttachedEffect;
import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect;
import mage.abilities.keyword.EnchantAbility;
import mage.cards.CardImpl;
@@ -53,7 +53,6 @@ public class LustForWar extends CardImpl {
this.expansionSetCode = "ROE";
this.subtype.add("Aura");
-
// Enchant creature
TargetPermanent auraTarget = new TargetCreaturePermanent();
this.getSpellAbility().addTarget(auraTarget);
@@ -66,7 +65,8 @@ public class LustForWar extends CardImpl {
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityAttachedEffect(attachedAbility, AttachmentType.AURA)));
// Enchanted creature attacks each turn if able.
- this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityAttachedEffect(new AttacksEachTurnStaticAbility(), AttachmentType.AURA)));
+ this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD,
+ new AttacksIfAbleAttachedEffect(Duration.WhileOnBattlefield, AttachmentType.AURA)));
}
public LustForWar(final LustForWar card) {
diff --git a/Mage.Sets/src/mage/sets/saviorsofkamigawa/CowedByWisdom.java b/Mage.Sets/src/mage/sets/saviorsofkamigawa/CowedByWisdom.java
index 9ad1c7827b..f112c128dc 100644
--- a/Mage.Sets/src/mage/sets/saviorsofkamigawa/CowedByWisdom.java
+++ b/Mage.Sets/src/mage/sets/saviorsofkamigawa/CowedByWisdom.java
@@ -30,8 +30,9 @@ package mage.sets.saviorsofkamigawa;
import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.common.SimpleStaticAbility;
-import mage.abilities.costs.Cost;
import mage.abilities.costs.mana.GenericManaCost;
+import mage.abilities.costs.mana.ManaCosts;
+import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.effects.PayCostToAttackBlockEffectImpl;
import mage.abilities.effects.common.AttachEffect;
import mage.abilities.keyword.EnchantAbility;
@@ -83,7 +84,7 @@ public class CowedByWisdom extends CardImpl {
class CowedByWisdomayCostToAttackBlockEffect extends PayCostToAttackBlockEffectImpl {
CowedByWisdomayCostToAttackBlockEffect() {
- super(Duration.WhileOnBattlefield, Outcome.Detriment, RestrictType.ATTACK_AND_BLOCK, null);
+ super(Duration.WhileOnBattlefield, Outcome.Detriment, RestrictType.ATTACK_AND_BLOCK);
staticText = "Enchanted creature can't attack or block unless its controller pays {1} for each card in your hand";
}
@@ -92,10 +93,12 @@ class CowedByWisdomayCostToAttackBlockEffect extends PayCostToAttackBlockEffectI
}
@Override
- public Cost getCostToPay(GameEvent event, Ability source, Game game) {
+ public ManaCosts getManaCostToPay(GameEvent event, Ability source, Game game) {
Player controller = game.getPlayer(source.getControllerId());
if (controller != null && !controller.getHand().isEmpty()) {
- return new GenericManaCost(controller.getHand().size());
+ ManaCosts manaCosts = new ManaCostsImpl();
+ manaCosts.add(new GenericManaCost(controller.getHand().size()));
+ return manaCosts;
}
return null;
}
diff --git a/Mage.Sets/src/mage/sets/shadowmoor/BloodshedFever.java b/Mage.Sets/src/mage/sets/shadowmoor/BloodshedFever.java
index af7f607476..c22140bc3f 100644
--- a/Mage.Sets/src/mage/sets/shadowmoor/BloodshedFever.java
+++ b/Mage.Sets/src/mage/sets/shadowmoor/BloodshedFever.java
@@ -29,10 +29,9 @@ package mage.sets.shadowmoor;
import java.util.UUID;
import mage.abilities.Ability;
-import mage.abilities.common.AttacksEachTurnStaticAbility;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.effects.common.AttachEffect;
-import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect;
+import mage.abilities.effects.common.combat.AttacksIfAbleAttachedEffect;
import mage.abilities.keyword.EnchantAbility;
import mage.cards.CardImpl;
import mage.constants.AttachmentType;
@@ -55,7 +54,6 @@ public class BloodshedFever extends CardImpl {
this.expansionSetCode = "SHM";
this.subtype.add("Aura");
-
// Enchant creature
TargetPermanent auraTarget = new TargetCreaturePermanent();
this.getSpellAbility().addTarget(auraTarget);
@@ -64,7 +62,8 @@ public class BloodshedFever extends CardImpl {
this.addAbility(ability);
// Enchanted creature attacks each turn if able.
- this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityAttachedEffect(new AttacksEachTurnStaticAbility(), AttachmentType.AURA, Duration.WhileOnBattlefield, "Enchanted creature attacks each turn if able")));
+ this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD,
+ new AttacksIfAbleAttachedEffect(Duration.WhileOnBattlefield, AttachmentType.AURA)));
}
public BloodshedFever(final BloodshedFever card) {
diff --git a/Mage.Sets/src/mage/sets/tempest/Propaganda.java b/Mage.Sets/src/mage/sets/tempest/Propaganda.java
index e4f36fd168..9b5f60aa26 100644
--- a/Mage.Sets/src/mage/sets/tempest/Propaganda.java
+++ b/Mage.Sets/src/mage/sets/tempest/Propaganda.java
@@ -28,19 +28,13 @@
package mage.sets.tempest;
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.replacement.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.players.Player;
/**
*
@@ -52,7 +46,8 @@ public class Propaganda extends CardImpl {
super(ownerId, 80, "Propaganda", Rarity.UNCOMMON, new CardType[]{CardType.ENCHANTMENT}, "{2}{U}");
this.expansionSetCode = "TMP";
- this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new PropagandaReplacementEffect()));
+ // 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 CantAttackYouUnlessPayManaAllEffect(new ManaCostsImpl("{2}"))));
}
public Propaganda(final Propaganda card) {
@@ -64,56 +59,3 @@ public class Propaganda extends CardImpl {
return new Propaganda(this);
}
}
-
-class PropagandaReplacementEffect 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";
-
- PropagandaReplacementEffect() {
- super(Duration.WhileOnBattlefield, Outcome.Neutral);
- staticText = effectText;
- }
-
- PropagandaReplacementEffect(PropagandaReplacementEffect 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) {
- ManaCostsImpl attackTax = new ManaCostsImpl("{2}");
- if (attackTax.canPay(source, source.getSourceId(), event.getPlayerId(), game)
- && player.chooseUse(Outcome.Neutral, "Pay {2} to attack player?", source, game)) {
- if (attackTax.payOrRollback(source, game, source.getSourceId(), event.getPlayerId())) {
- return false;
- }
- }
- return true;
- }
- return false;
- }
-
- @Override
- public PropagandaReplacementEffect copy() {
- return new PropagandaReplacementEffect(this);
- }
-
-}
diff --git a/Mage.Sets/src/mage/sets/tenthedition/WindbornMuse.java b/Mage.Sets/src/mage/sets/tenthedition/WindbornMuse.java
index e1d70ddfef..b16714da35 100644
--- a/Mage.Sets/src/mage/sets/tenthedition/WindbornMuse.java
+++ b/Mage.Sets/src/mage/sets/tenthedition/WindbornMuse.java
@@ -28,15 +28,19 @@
package mage.sets.tenthedition;
import java.util.UUID;
-
-import mage.constants.*;
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.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;
@@ -53,12 +57,13 @@ public class WindbornMuse extends CardImpl {
this.subtype.add("Spirit");
this.power = new MageInt(2);
this.toughness = new MageInt(3);
-
+
// Flying
this.addAbility(FlyingAbility.getInstance());
+
// 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 WindbornMuseReplacementEffect()));
-
+ this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new CantAttackYouUnlessPayManaAllEffect(new ManaCostsImpl("{2}"))));
+
}
public WindbornMuse(final WindbornMuse card) {
@@ -75,12 +80,12 @@ 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 ( ) {
+ WindbornMuseReplacementEffect() {
super(Duration.WhileOnBattlefield, Outcome.Benefit);
staticText = effectText;
}
- WindbornMuseReplacementEffect ( WindbornMuseReplacementEffect effect ) {
+ WindbornMuseReplacementEffect(WindbornMuseReplacementEffect effect) {
super(effect);
}
@@ -88,10 +93,10 @@ class WindbornMuseReplacementEffect extends ReplacementEffectImpl {
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()) ) {
+ 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
@@ -100,15 +105,14 @@ class WindbornMuseReplacementEffect extends ReplacementEffectImpl {
}
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())) {
+ 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.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;
}
@@ -124,4 +128,3 @@ class WindbornMuseReplacementEffect extends ReplacementEffectImpl {
}
}
-
diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/restriction/CantAttackTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/restriction/CantAttackTest.java
index 6eee906395..f88a2a0c42 100644
--- a/Mage.Tests/src/test/java/org/mage/test/cards/restriction/CantAttackTest.java
+++ b/Mage.Tests/src/test/java/org/mage/test/cards/restriction/CantAttackTest.java
@@ -118,4 +118,26 @@ public class CantAttackTest extends CardTestPlayerBase {
assertCounterCount("Ajani Goldmane", CounterType.LOYALTY, 2);
}
+ @Test
+ public void testCowedByWisdom() {
+ addCard(Zone.BATTLEFIELD, playerA, "Plains", 1);
+ // Enchant creature
+ // Enchanted creature can't attack or block unless its controller pays {1} for each card in your hand.
+ addCard(Zone.HAND, playerA, "Cowed by Wisdom"); // Planeswalker 4 loyality counter
+
+ // Bushido 2 (When this blocks or becomes blocked, it gets +2/+2 until end of turn.)
+ // Battle-Mad Ronin attacks each turn if able.
+ addCard(Zone.BATTLEFIELD, playerB, "Battle-Mad Ronin");
+ addCard(Zone.HAND, playerA, "Mountain", 4);
+ addCard(Zone.BATTLEFIELD, playerA, "Mountain", 2);
+
+ castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cowed by Wisdom", "Battle-Mad Ronin");
+
+ setStopAt(2, PhaseStep.POSTCOMBAT_MAIN);
+ execute();
+
+ assertLife(playerA, 20);
+
+ assertTapped("Battle-Mad Ronin", false);
+ }
}
diff --git a/Mage/src/mage/abilities/costs/mana/ManaCosts.java b/Mage/src/mage/abilities/costs/mana/ManaCosts.java
index 49e4989b36..e21c8fa2ac 100644
--- a/Mage/src/mage/abilities/costs/mana/ManaCosts.java
+++ b/Mage/src/mage/abilities/costs/mana/ManaCosts.java
@@ -1,36 +1,38 @@
/*
-* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
-*
-* Redistribution and use in source and binary forms, with or without modification, are
-* permitted provided that the following conditions are met:
-*
-* 1. Redistributions of source code must retain the above copyright notice, this list of
-* conditions and the following disclaimer.
-*
-* 2. Redistributions in binary form must reproduce the above copyright notice, this list
-* of conditions and the following disclaimer in the documentation and/or other materials
-* provided with the distribution.
-*
-* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
-* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
-* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
-* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
-* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
-* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
-* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-*
-* The views and conclusions contained in the software and documentation are those of the
-* authors and should not be interpreted as representing official policies, either expressed
-* or implied, of BetaSteward_at_googlemail.com.
-*/
-
+ * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and should not be interpreted as representing official policies, either expressed
+ * or implied, of BetaSteward_at_googlemail.com.
+ */
package mage.abilities.costs.mana;
import java.util.List;
+import java.util.UUID;
import mage.Mana;
+import mage.abilities.Ability;
import mage.abilities.costs.VariableCost;
+import mage.game.Game;
/**
*
@@ -40,12 +42,18 @@ import mage.abilities.costs.VariableCost;
public interface ManaCosts extends List, ManaCost {
ManaCosts getUnpaidVariableCosts();
+
List getVariableCosts();
+
int getX();
+
void setX(int x);
+
void load(String mana);
+
List getSymbols();
+ boolean payOrRollback(Ability ability, Game game, UUID sourceId, UUID payingPlayerId);
@Override
Mana getMana();
diff --git a/Mage/src/mage/abilities/costs/mana/ManaCostsImpl.java b/Mage/src/mage/abilities/costs/mana/ManaCostsImpl.java
index aca1bd6b37..4b610c2af3 100644
--- a/Mage/src/mage/abilities/costs/mana/ManaCostsImpl.java
+++ b/Mage/src/mage/abilities/costs/mana/ManaCostsImpl.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.abilities.costs.mana;
import java.util.ArrayList;
@@ -134,14 +133,16 @@ public class ManaCostsImpl extends ArrayList implements M
}
/**
- * bookmarks the current state and restores it if player doesn't pay the mana cost
- *
+ * bookmarks the current state and restores it if player doesn't pay the
+ * mana cost
+ *
* @param ability
* @param game
* @param sourceId
* @param payingPlayerId
* @return true if the cost was paid
*/
+ @Override
public boolean payOrRollback(Ability ability, Game game, UUID sourceId, UUID payingPlayerId) {
int bookmark = game.bookmarkState();
if (pay(ability, game, sourceId, payingPlayerId, false)) {
@@ -174,7 +175,6 @@ public class ManaCostsImpl extends ArrayList implements M
return unpaid;
}
-
@Override
public List getVariableCosts() {
List variableCosts = new ArrayList<>();
@@ -216,7 +216,6 @@ public class ManaCostsImpl extends ArrayList implements M
}
//attempt to pay colored costs first
-
for (ManaCost cost : this) {
if (!cost.isPaid() && cost instanceof ColoredManaCost) {
cost.assignPayment(game, ability, pool);
@@ -234,15 +233,13 @@ public class ManaCostsImpl extends ArrayList implements M
cost.assignPayment(game, ability, pool);
}
}
-
-
+
for (ManaCost cost : this) {
if (!cost.isPaid() && cost instanceof SnowManaCost) {
cost.assignPayment(game, ability, pool);
}
}
-
for (ManaCost cost : this) {
if (!cost.isPaid() && cost instanceof GenericManaCost) {
cost.assignPayment(game, ability, pool);
@@ -280,8 +277,7 @@ public class ManaCostsImpl extends ArrayList implements M
} else {
if (!symbol.equals("X")) {
this.add((T) new ColoredManaCost(ColoredManaSymbol.lookup(symbol.charAt(0))));
- }
- else {
+ } else {
// check X wasn't added before
if (modifierForX == 0) {
// count X occurence
@@ -296,11 +292,9 @@ public class ManaCostsImpl extends ArrayList implements M
//TODO: handle multiple {X} and/or {Y} symbols
}
} else {
- if(symbol.equals("snow"))
- {
+ if (symbol.equals("snow")) {
this.add((T) new SnowManaCost());
- }
- else if (Character.isDigit(symbol.charAt(0))) {
+ } else if (Character.isDigit(symbol.charAt(0))) {
this.add((T) new MonoHybridManaCost(ColoredManaSymbol.lookup(symbol.charAt(2))));
} else if (symbol.contains("P")) {
this.add((T) new PhyrexianManaCost(ColoredManaSymbol.lookup(symbol.charAt(0))));
@@ -443,7 +437,7 @@ public class ManaCostsImpl extends ArrayList implements M
@Override
public boolean containsColor(ColoredManaSymbol coloredManaSymbol) {
- for(ManaCost manaCost: this) {
+ for (ManaCost manaCost : this) {
if (manaCost.containsColor(coloredManaSymbol)) {
return true;
}
diff --git a/Mage/src/mage/abilities/effects/ContinuousEffects.java b/Mage/src/mage/abilities/effects/ContinuousEffects.java
index b19c442092..12ae10a9fc 100644
--- a/Mage/src/mage/abilities/effects/ContinuousEffects.java
+++ b/Mage/src/mage/abilities/effects/ContinuousEffects.java
@@ -324,6 +324,30 @@ public class ContinuousEffects implements Serializable {
return effects;
}
+ public boolean checkIfThereArePayCostToAttackBlockEffects(GameEvent event, Game game) {
+ for (ReplacementEffect effect : replacementEffects) {
+ if (!effect.checksEventType(event, game)) {
+ continue;
+ }
+ if (effect instanceof PayCostToAttackBlockEffect) {
+ HashSet abilities = replacementEffects.getAbility(effect.getId());
+ for (Ability ability : abilities) {
+ // for replacment effects of static abilities do not use LKI to check if to apply
+ 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)) {
+ return true;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ return false;
+ }
+
/**
*
* @param event
diff --git a/Mage/src/mage/abilities/effects/PayCostToAttackBlockEffect.java b/Mage/src/mage/abilities/effects/PayCostToAttackBlockEffect.java
index 63920ccddd..f73af6074f 100644
--- a/Mage/src/mage/abilities/effects/PayCostToAttackBlockEffect.java
+++ b/Mage/src/mage/abilities/effects/PayCostToAttackBlockEffect.java
@@ -29,6 +29,7 @@ package mage.abilities.effects;
import mage.abilities.Ability;
import mage.abilities.costs.Cost;
+import mage.abilities.costs.mana.ManaCosts;
import mage.game.Game;
import mage.game.events.GameEvent;
@@ -38,5 +39,7 @@ import mage.game.events.GameEvent;
*/
public interface PayCostToAttackBlockEffect extends ReplacementEffect {
- Cost getCostToPay(GameEvent event, Ability source, Game game);
+ ManaCosts getManaCostToPay(GameEvent event, Ability source, Game game);
+
+ Cost getOtherCostToPay(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 917665ca82..9473fbcd9c 100644
--- a/Mage/src/mage/abilities/effects/PayCostToAttackBlockEffectImpl.java
+++ b/Mage/src/mage/abilities/effects/PayCostToAttackBlockEffectImpl.java
@@ -29,12 +29,13 @@ package mage.abilities.effects;
import mage.abilities.Ability;
import mage.abilities.costs.Cost;
-import mage.abilities.costs.mana.ManaCostImpl;
+import mage.abilities.costs.mana.ManaCosts;
import mage.abilities.costs.mana.ManaCostsImpl;
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.players.Player;
/**
@@ -49,12 +50,29 @@ public abstract class PayCostToAttackBlockEffectImpl extends ReplacementEffectIm
}
private final Cost cost;
+ private final ManaCosts manaCosts;
+
private final RestrictType restrictType;
+ public PayCostToAttackBlockEffectImpl(Duration duration, Outcome outcome, RestrictType restrictType) {
+ super(duration, outcome, false);
+ this.restrictType = restrictType;
+ this.cost = null;
+ this.manaCosts = null;
+ }
+
public PayCostToAttackBlockEffectImpl(Duration duration, Outcome outcome, RestrictType restrictType, Cost cost) {
super(duration, outcome, false);
this.restrictType = restrictType;
this.cost = cost;
+ this.manaCosts = null;
+ }
+
+ public PayCostToAttackBlockEffectImpl(Duration duration, Outcome outcome, RestrictType restrictType, ManaCosts manaCosts) {
+ super(duration, outcome, false);
+ this.restrictType = restrictType;
+ this.cost = null;
+ this.manaCosts = manaCosts;
}
public PayCostToAttackBlockEffectImpl(PayCostToAttackBlockEffectImpl effect) {
@@ -64,6 +82,11 @@ public abstract class PayCostToAttackBlockEffectImpl extends ReplacementEffectIm
} else {
this.cost = null;
}
+ if (effect.manaCosts != null) {
+ this.manaCosts = effect.manaCosts.copy();
+ } else {
+ this.manaCosts = null;
+ }
this.restrictType = effect.restrictType;
}
@@ -82,20 +105,31 @@ public abstract class PayCostToAttackBlockEffectImpl extends ReplacementEffectIm
@Override
public boolean replaceEvent(GameEvent event, Ability source, Game game) {
+ ManaCosts attackBlockManaTax = getManaCostToPay(event, source, game);
+ if (attackBlockManaTax != null) {
+ return handleManaCosts(attackBlockManaTax, event, source, game);
+ }
+ Cost attackBlockOtherTax = getOtherCostToPay(event, source, game);
+ if (attackBlockOtherTax != null) {
+ return handleOtherCosts(attackBlockOtherTax, event, source, game);
+ }
+ return false;
+ }
+
+ private boolean handleManaCosts(ManaCosts attackBlockManaTax, GameEvent event, Ability source, Game game) {
Player player = game.getPlayer(event.getPlayerId());
- Cost attackBlockTax = getCostToPay(event, source, game);
- if (player != null && attackBlockTax != null) {
+ if (player != null) {
String chooseText;
if (event.getType().equals(GameEvent.EventType.DECLARE_ATTACKER)) {
- chooseText = "Pay " + attackBlockTax.getText() + " to attack?";
+ chooseText = "Pay " + attackBlockManaTax.getText() + " to attack?";
} else {
- chooseText = "Pay " + attackBlockTax.getText() + " to block?";
+ chooseText = "Pay " + attackBlockManaTax.getText() + " to block?";
}
- if (attackBlockTax.canPay(source, source.getSourceId(), player.getId(), game)
+ attackBlockManaTax.clearPaid();
+ if (attackBlockManaTax.canPay(source, source.getSourceId(), player.getId(), game)
&& player.chooseUse(Outcome.Neutral, chooseText, source, game)) {
- if (attackBlockTax instanceof ManaCostImpl) {
- ManaCostsImpl manaCosts = new ManaCostsImpl(attackBlockTax.getText());
- if (manaCosts.payOrRollback(source, game, source.getSourceId(), event.getPlayerId())) {
+ if (attackBlockManaTax instanceof ManaCostsImpl) {
+ if (attackBlockManaTax.payOrRollback(source, game, source.getSourceId(), event.getPlayerId())) {
return false;
}
}
@@ -105,9 +139,30 @@ public abstract class PayCostToAttackBlockEffectImpl extends ReplacementEffectIm
return false;
}
+ private boolean handleOtherCosts(Cost attackBlockOtherTax, GameEvent event, Ability source, Game game) {
+ Player player = game.getPlayer(event.getPlayerId());
+ if (player != null) {
+ attackBlockOtherTax.clearPaid();
+ if (attackBlockOtherTax.canPay(source, source.getSourceId(), event.getPlayerId(), game)
+ && player.chooseUse(Outcome.Neutral,
+ attackBlockOtherTax.getText() + " to " + (event.getType().equals(EventType.DECLARE_ATTACKER) ? "attack?" : "block?"), source, game)) {
+ if (attackBlockOtherTax.pay(source, game, source.getSourceId(), event.getPlayerId(), false)) {
+ return false;
+ }
+ }
+ return true;
+ }
+ return false;
+ }
+
@Override
- public Cost getCostToPay(GameEvent event, Ability source, Game game) {
+ public Cost getOtherCostToPay(GameEvent event, Ability source, Game game) {
return cost;
}
+ @Override
+ public ManaCosts getManaCostToPay(GameEvent event, Ability source, Game game) {
+ return manaCosts;
+ }
+
}
diff --git a/Mage/src/mage/abilities/effects/common/replacement/CantAttackYouUnlessPayManaAllEffect.java b/Mage/src/mage/abilities/effects/common/replacement/CantAttackYouUnlessPayManaAllEffect.java
new file mode 100644
index 0000000000..36f7be673a
--- /dev/null
+++ b/Mage/src/mage/abilities/effects/common/replacement/CantAttackYouUnlessPayManaAllEffect.java
@@ -0,0 +1,41 @@
+/*
+ * 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 e5d281763c..80caa16dba 100644
--- a/Mage/src/mage/game/combat/Combat.java
+++ b/Mage/src/mage/game/combat/Combat.java
@@ -27,6 +27,15 @@
*/
package mage.game.combat;
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.effects.RequirementEffect;
import mage.abilities.effects.RestrictionEffect;
@@ -37,6 +46,7 @@ import mage.constants.Outcome;
import mage.constants.Zone;
import mage.filter.common.FilterControlledCreaturePermanent;
import mage.filter.common.FilterCreatureForCombatBlock;
+import mage.filter.common.FilterCreaturePermanent;
import mage.filter.common.FilterPlaneswalkerPermanent;
import mage.game.Game;
import mage.game.events.GameEvent;
@@ -48,10 +58,6 @@ import mage.util.CardUtil;
import mage.util.Copyable;
import mage.util.trace.TraceUtil;
-import java.io.Serializable;
-import java.util.*;
-import mage.filter.common.FilterCreaturePermanent;
-
/**
* @author BetaSteward_at_googlemail.com
*/
@@ -92,8 +98,8 @@ public class Combat implements Serializable, Copyable {
this.useToughnessForDamage = combat.useToughnessForDamage;
for (Map.Entry> group : combat.numberCreaturesDefenderAttackedBy.entrySet()) {
this.numberCreaturesDefenderAttackedBy.put(group.getKey(), group.getValue());
- }
-
+ }
+
for (Map.Entry> group : combat.creatureMustBlockAttackers.entrySet()) {
this.creatureMustBlockAttackers.put(group.getKey(), group.getValue());
}
@@ -133,7 +139,7 @@ public class Combat implements Serializable, Copyable {
public boolean useToughnessForDamage(Permanent permanent, Game game) {
if (useToughnessForDamage) {
- for(FilterCreaturePermanent filter: useToughnessForDamageFilters) {
+ for (FilterCreaturePermanent filter : useToughnessForDamageFilters) {
if (filter.match(permanent, game)) {
return true;
}
@@ -231,7 +237,7 @@ public class Combat implements Serializable, Copyable {
}
game.fireEvent(GameEvent.getEvent(GameEvent.EventType.DECLARED_ATTACKERS, attackerId, attackerId));
if (!game.isSimulation()) {
- game.informPlayers(new StringBuilder(player.getLogName()).append(" attacks with ").append(groups.size()).append(groups.size() == 1 ? " creature":" creatures").toString());
+ game.informPlayers(new StringBuilder(player.getLogName()).append(" attacks with ").append(groups.size()).append(groups.size() == 1 ? " creature" : " creatures").toString());
}
}
@@ -256,20 +262,38 @@ public class Combat implements Serializable, Copyable {
}
}
if (mustAttack) {
- creaturesForcedToAttack.put(creature.getId(), defendersForcedToAttack);
- if (defendersForcedToAttack.isEmpty()) {
- if (defenders.size() == 1) {
- player.declareAttacker(creature.getId(), defenders.iterator().next(), game, false);
- } else {
- TargetDefender target = new TargetDefender(defenders, creature.getId());
- target.setRequired(true);
- if (player.chooseTarget(Outcome.Damage, target, null, game)) {
- player.declareAttacker(creature.getId(), target.getFirstTarget(), game, false);
- }
+ // check which defenders the forced to attck creature can attack without paying a cost
+ HashSet defendersCostlessAttackable = new HashSet<>();
+ defendersCostlessAttackable.addAll(defenders);
+ for (UUID defenderId : defenders) {
+ if (game.getContinuousEffects().checkIfThereArePayCostToAttackBlockEffects(
+ GameEvent.getEvent(GameEvent.EventType.DECLARE_ATTACKER,
+ defenderId, creature.getId(), creature.getControllerId()), game)) {
+ defendersCostlessAttackable.remove(defenderId);
+ defendersForcedToAttack.remove(defenderId);
}
- } else {
- player.declareAttacker(creature.getId(), defendersForcedToAttack.iterator().next(), game, false);
}
+ // force attack only if a defender can be attacked without paying a cost
+ if (!defendersCostlessAttackable.isEmpty()) {
+ // No need to attack a special defender
+ if (defendersForcedToAttack.isEmpty()) {
+ creaturesForcedToAttack.put(creature.getId(), defendersForcedToAttack);
+ if (defendersForcedToAttack.isEmpty()) {
+ if (defendersCostlessAttackable.size() == 1) {
+ player.declareAttacker(creature.getId(), defenders.iterator().next(), game, false);
+ }
+ } else {
+ TargetDefender target = new TargetDefender(defendersCostlessAttackable, creature.getId());
+ target.setRequired(true);
+ if (player.chooseTarget(Outcome.Damage, target, null, game)) {
+ player.declareAttacker(creature.getId(), target.getFirstTarget(), game, false);
+ }
+ }
+ } else {
+ player.declareAttacker(creature.getId(), defendersForcedToAttack.iterator().next(), game, false);
+ }
+ }
+
}
}
@@ -457,17 +481,18 @@ public class Combat implements Serializable, Copyable {
}
/**
- * Retrieves all requirements that apply and creates a Map with blockers and attackers
- * it contains only records if attackers can be retrieved
- * // Map>
- *
+ * Retrieves all requirements that apply and creates a Map with blockers and
+ * attackers it contains only records if attackers can be retrieved //
+ * Map>
+ *
* @param attackingPlayer - attacker
- * @param game
+ * @param game
*/
private void retrieveMustBlockAttackerRequirements(Player attackingPlayer, Game game) {
if (!game.getContinuousEffects().existRequirementEffects()) {
return;
- }
+ }
for (Permanent possibleBlocker : game.getBattlefield().getActivePermanents(filterBlockers, attackingPlayer.getId(), game)) {
for (Map.Entry> requirementEntry : game.getContinuousEffects().getApplicableRequirementEffects(possibleBlocker, game).entrySet()) {
if (requirementEntry.getKey().mustBlock(game)) {
@@ -582,7 +607,7 @@ public class Combat implements Serializable, Copyable {
// check if the attacker is already blocked by a max of blockers, so blocker can't block it also
if (attackingCreature.getMaxBlockedBy() != 0) { // 0 = no restriction about the number of possible blockers
int alreadyBlockingCreatures = 0;
- for(CombatGroup group :getGroups()) {
+ for (CombatGroup group : getGroups()) {
if (group.getAttackers().contains(attackingCreatureId)) {
alreadyBlockingCreatures = group.getBlockers().size();
break;
@@ -874,7 +899,7 @@ public class Combat implements Serializable, Copyable {
Permanent attacker = game.getPermanent(attackerId);
attacker.setAttacking(true);
groups.add(newGroup);
- return true;
+ return true;
}
public boolean canDefenderBeAttacked(UUID attackerId, UUID defenderId, Game game) {
@@ -999,7 +1024,6 @@ public class Combat implements Serializable, Copyable {
// }
// return total;
// }
-
public boolean attacksAlone() {
return (groups.size() == 1 && groups.get(0).getAttackers().size() == 1);
}
@@ -1106,10 +1130,9 @@ public class Combat implements Serializable, Copyable {
}
}
-
public void removeBlockerGromGroup(UUID blockerId, CombatGroup groupToUnblock, Game game) {
Permanent creature = game.getPermanent(blockerId);
- if (creature != null) {
+ if (creature != null) {
for (CombatGroup group : groups) {
if (group.equals(groupToUnblock) && group.blockers.contains(blockerId)) {
group.blockers.remove(blockerId);
@@ -1124,9 +1147,9 @@ public class Combat implements Serializable, Copyable {
}
}
}
- }
+ }
}
-
+
public void removeBlocker(UUID blockerId, Game game) {
for (CombatGroup group : groups) {
if (group.blockers.contains(blockerId)) {