Merge origin/master

This commit is contained in:
fireshoes 2015-07-01 12:51:55 -05:00
commit 3868066e00
30 changed files with 865 additions and 899 deletions

View file

@ -32,7 +32,9 @@ import mage.MageInt;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.common.SimpleStaticAbility; import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.costs.common.ReturnToHandTargetPermanentCost; import mage.abilities.costs.common.ReturnToHandTargetPermanentCost;
import mage.abilities.effects.PayCostToAttackBlockEffectImpl;
import mage.abilities.effects.ReplacementEffectImpl; import mage.abilities.effects.ReplacementEffectImpl;
import mage.abilities.effects.common.combat.CantAttackBlockUnlessPaysSourceEffect;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.Duration; import mage.constants.Duration;
@ -53,6 +55,12 @@ import mage.target.common.TargetControlledPermanent;
*/ */
public class FloodtideSerpent extends CardImpl { 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) { public FloodtideSerpent(UUID ownerId) {
super(ownerId, 41, "Floodtide Serpent", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{4}{U}"); super(ownerId, 41, "Floodtide Serpent", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{4}{U}");
this.expansionSetCode = "BNG"; this.expansionSetCode = "BNG";
@ -62,8 +70,8 @@ public class FloodtideSerpent extends CardImpl {
this.toughness = new MageInt(4); this.toughness = new MageInt(4);
// Floodtide Serpent can't attack unless you return an enchantment you control to its owner's hand <i>(This cost is paid as attackers are declared.)</i> // Floodtide Serpent can't attack unless you return an enchantment you control to its owner's hand <i>(This cost is paid as attackers are declared.)</i>
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)); filter.add(new CardTypePredicate(CardType.ENCHANTMENT));
} }
FloodtideSerpentReplacementEffect ( ) { FloodtideSerpentReplacementEffect() {
super(Duration.WhileOnBattlefield, Outcome.Neutral); super(Duration.WhileOnBattlefield, Outcome.Neutral);
staticText = "{this} can't attack unless you return an enchantment you control to its owner's hand <i>(This cost is paid as attackers are declared.)</i>"; staticText = "{this} can't attack unless you return an enchantment you control to its owner's hand <i>(This cost is paid as attackers are declared.)</i>";
} }
FloodtideSerpentReplacementEffect ( FloodtideSerpentReplacementEffect effect ) { FloodtideSerpentReplacementEffect(FloodtideSerpentReplacementEffect effect) {
super(effect); super(effect);
} }
@Override @Override
public boolean replaceEvent(GameEvent event, Ability source, Game game) { public boolean replaceEvent(GameEvent event, Ability source, Game game) {
Player player = game.getPlayer(event.getPlayerId()); Player player = game.getPlayer(event.getPlayerId());
if ( player != null ) { if (player != null) {
ReturnToHandTargetPermanentCost attackCost = new ReturnToHandTargetPermanentCost(new TargetControlledPermanent(filter)); ReturnToHandTargetPermanentCost attackCost = new ReturnToHandTargetPermanentCost(new TargetControlledPermanent(filter));
if ( attackCost.canPay(source, source.getSourceId(), event.getPlayerId(), game) && if (attackCost.canPay(source, source.getSourceId(), event.getPlayerId(), game)
player.chooseUse(Outcome.Neutral, "Return an enchantment you control to hand to attack?", source, 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.pay(source, game, source.getSourceId(), event.getPlayerId(), true) ) {
return false; return false;
} }
} }
@ -116,7 +123,6 @@ class FloodtideSerpentReplacementEffect extends ReplacementEffectImpl {
return event.getType() == EventType.DECLARE_ATTACKER; return event.getType() == EventType.DECLARE_ATTACKER;
} }
@Override @Override
public boolean applies(GameEvent event, Ability source, Game game) { public boolean applies(GameEvent event, Ability source, Game game) {
return event.getSourceId().equals(source.getSourceId()); return event.getSourceId().equals(source.getSourceId());

View file

@ -32,7 +32,7 @@ import java.util.UUID;
import mage.constants.*; import mage.constants.*;
import mage.abilities.common.SimpleStaticAbility; import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.costs.mana.ManaCostsImpl; 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.cards.CardImpl;
/** /**

View file

@ -29,21 +29,14 @@ package mage.sets.dragonsoftarkir;
import java.util.UUID; import java.util.UUID;
import mage.MageInt; import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.SimpleStaticAbility; import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.costs.mana.ManaCostsImpl; 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.cards.CardImpl;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.Outcome;
import mage.constants.Rarity; import mage.constants.Rarity;
import mage.constants.Zone; 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); this.toughness = new MageInt(5);
// Qal Sisma Behemoth can't attack or block unless you pay {2}. // 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); 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);
}
}

View file

@ -33,11 +33,12 @@ import mage.abilities.ActivatedAbility;
import mage.abilities.SpellAbility; import mage.abilities.SpellAbility;
import mage.abilities.common.SimpleStaticAbility; import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.costs.mana.ManaCostsImpl; 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.AttachEffect;
import mage.abilities.effects.common.combat.CantAttackBlockUnlessPaysAttachedEffect;
import mage.abilities.effects.common.cost.CostModificationEffectImpl;
import mage.abilities.keyword.EnchantAbility; import mage.abilities.keyword.EnchantAbility;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.constants.AttachmentType;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.CostModificationType; import mage.constants.CostModificationType;
import mage.constants.Duration; import mage.constants.Duration;
@ -45,9 +46,7 @@ import mage.constants.Outcome;
import mage.constants.Rarity; import mage.constants.Rarity;
import mage.constants.Zone; import mage.constants.Zone;
import mage.game.Game; import mage.game.Game;
import mage.game.events.GameEvent;
import mage.game.permanent.Permanent; import mage.game.permanent.Permanent;
import mage.players.Player;
import mage.target.TargetPermanent; import mage.target.TargetPermanent;
import mage.target.common.TargetCreaturePermanent; import mage.target.common.TargetCreaturePermanent;
import mage.util.CardUtil; import mage.util.CardUtil;
@ -63,7 +62,6 @@ public class OppressiveRays extends CardImpl {
this.expansionSetCode = "JOU"; this.expansionSetCode = "JOU";
this.subtype.add("Aura"); this.subtype.add("Aura");
// Enchant creature // Enchant creature
TargetPermanent auraTarget = new TargetCreaturePermanent(); TargetPermanent auraTarget = new TargetCreaturePermanent();
this.getSpellAbility().addTarget(auraTarget); this.getSpellAbility().addTarget(auraTarget);
@ -72,9 +70,10 @@ public class OppressiveRays extends CardImpl {
this.addAbility(ability); this.addAbility(ability);
// Enchanted creature can't attack or block unless its controller pays 3. // 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. // 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) { 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 { class OppressiveRaysCostModificationEffect extends CostModificationEffectImpl {
OppressiveRaysCostModificationEffect ( ) { OppressiveRaysCostModificationEffect() {
super(Duration.WhileOnBattlefield, Outcome.Benefit, CostModificationType.INCREASE_COST); super(Duration.WhileOnBattlefield, Outcome.Benefit, CostModificationType.INCREASE_COST);
staticText = "Activated abilities of enchanted creature cost {3} more to activate"; staticText = "Activated abilities of enchanted creature cost {3} more to activate";
} }

View file

@ -28,20 +28,13 @@
package mage.sets.newphyrexia; package mage.sets.newphyrexia;
import java.util.UUID; import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.common.SimpleStaticAbility; import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.effects.ReplacementEffectImpl; import mage.abilities.effects.common.combat.CantAttackYouUnlessPayManaAllEffect;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.Outcome;
import mage.constants.Rarity; import mage.constants.Rarity;
import mage.constants.Zone; import mage.constants.Zone;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.game.permanent.Permanent;
import mage.players.Player;
/** /**
* @author Loki * @author Loki
@ -53,8 +46,8 @@ public class NornsAnnex extends CardImpl {
this.expansionSetCode = "NPH"; this.expansionSetCode = "NPH";
// {WP} ({WP} can be paid with either or 2 life.) // {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. // 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 NornsAnnexReplacementEffect())); this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new CantAttackYouUnlessPayManaAllEffect(new ManaCostsImpl<>("{WP}"), true)));
} }
public NornsAnnex(final NornsAnnex card) { 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);
}
}

View file

@ -29,18 +29,14 @@ package mage.sets.ravnica;
import java.util.UUID; import java.util.UUID;
import mage.MageInt; import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.SimpleStaticAbility; import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.effects.RestrictionEffect; import mage.abilities.effects.common.combat.CantAttackYouAllEffect;
import mage.abilities.keyword.FlyingAbility; import mage.abilities.keyword.FlyingAbility;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.Duration; import mage.constants.Duration;
import mage.constants.Outcome;
import mage.constants.Rarity; import mage.constants.Rarity;
import mage.constants.Zone; import mage.constants.Zone;
import mage.game.Game;
import mage.game.permanent.Permanent;
/** /**
* *
@ -59,7 +55,7 @@ public class BlazingArchon extends CardImpl {
this.addAbility(FlyingAbility.getInstance()); this.addAbility(FlyingAbility.getInstance());
// Creatures can't attack you. // Creatures can't attack you.
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BlazingArchonRestrictionEffect())); this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new CantAttackYouAllEffect(Duration.WhileOnBattlefield)));
} }
@ -72,30 +68,3 @@ public class BlazingArchon extends CardImpl {
return new BlazingArchon(this); 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);
}
}

View file

@ -25,24 +25,21 @@
* authors and should not be interpreted as representing official policies, either expressed * authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com. * or implied, of BetaSteward_at_googlemail.com.
*/ */
package mage.sets.returntoravnica; package mage.sets.returntoravnica;
import java.util.UUID; import java.util.UUID;
import mage.constants.*;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.common.SimpleStaticAbility; import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.costs.mana.ManaCosts;
import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; import mage.abilities.effects.common.combat.CantAttackYouUnlessPayManaAllEffect;
import mage.abilities.effects.ReplacementEffectImpl;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.constants.CardType;
import mage.constants.Rarity;
import mage.constants.Zone;
import mage.filter.common.FilterEnchantmentPermanent; import mage.filter.common.FilterEnchantmentPermanent;
import mage.filter.predicate.permanent.ControllerPredicate;
import mage.game.Game; import mage.game.Game;
import mage.game.events.GameEvent; 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 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}"); super(ownerId, 24, "Sphere of Safety", Rarity.UNCOMMON, new CardType[]{CardType.ENCHANTMENT}, "{4}{W}");
this.expansionSetCode = "RTR"; 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. // 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); 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"; SphereOfSafetyPayManaToAttackAllEffect() {
private static final FilterEnchantmentPermanent filter = new FilterEnchantmentPermanent("enchantment you control"); super(null, true);
static { 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.";
filter.add(new ControllerPredicate(TargetController.YOU));
}
private final PermanentsOnBattlefieldCount countEnchantments = new PermanentsOnBattlefieldCount(filter);
SphereOfSafetyReplacementEffect ( ) {
super(Duration.WhileOnBattlefield, Outcome.Benefit);
staticText = effectText;
} }
SphereOfSafetyReplacementEffect ( SphereOfSafetyReplacementEffect effect ) { SphereOfSafetyPayManaToAttackAllEffect(SphereOfSafetyPayManaToAttackAllEffect effect) {
super(effect); super(effect);
} }
@Override @Override
public boolean checksEventType(GameEvent event, Game game) { public ManaCosts getManaCostToPay(GameEvent event, Ability source, Game game) {
return event.getType() == GameEvent.EventType.DECLARE_ATTACKER; int enchantments = game.getBattlefield().countAll(new FilterEnchantmentPermanent(), source.getControllerId(), game);
if (enchantments > 0) {
return new ManaCostsImpl<>("{" + enchantments + "}");
}
return null;
} }
@Override @Override
public boolean applies(GameEvent event, Ability source, Game game) { public SphereOfSafetyPayManaToAttackAllEffect copy() {
if (event.getTargetId().equals(source.getControllerId()) ) { return new SphereOfSafetyPayManaToAttackAllEffect(this);
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);
} }
} }

View file

@ -28,20 +28,16 @@
package mage.sets.saviorsofkamigawa; package mage.sets.saviorsofkamigawa;
import java.util.UUID; import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.common.SimpleStaticAbility; import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.effects.RestrictionEffect; import mage.abilities.effects.common.combat.CantAttackYouAllEffect;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.Duration; import mage.constants.Duration;
import mage.constants.Outcome;
import mage.constants.Rarity; import mage.constants.Rarity;
import mage.constants.Zone; import mage.constants.Zone;
import mage.filter.Filter; import mage.filter.Filter;
import mage.filter.common.FilterCreaturePermanent; import mage.filter.common.FilterCreaturePermanent;
import mage.filter.predicate.mageobject.PowerPredicate; 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 { 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) { public Reverence(UUID ownerId) {
super(ownerId, 26, "Reverence", Rarity.RARE, new CardType[]{CardType.ENCHANTMENT}, "{2}{W}{W}"); super(ownerId, 26, "Reverence", Rarity.RARE, new CardType[]{CardType.ENCHANTMENT}, "{2}{W}{W}");
this.expansionSetCode = "SOK"; this.expansionSetCode = "SOK";
// Creatures with power 2 or less can't attack you. // 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) { public Reverence(final Reverence card) {
@ -66,37 +68,3 @@ public class Reverence extends CardImpl {
return new Reverence(this); 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);
}
}

View file

@ -33,8 +33,8 @@ import mage.abilities.common.BeginningOfEndStepTriggeredAbility;
import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; import mage.abilities.common.BeginningOfUpkeepTriggeredAbility;
import mage.abilities.common.SimpleStaticAbility; import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.RestrictionEffect;
import mage.abilities.effects.common.DamageTargetEffect; import mage.abilities.effects.common.DamageTargetEffect;
import mage.abilities.effects.common.combat.CantAttackYouAllEffect;
import mage.abilities.keyword.FlyingAbility; import mage.abilities.keyword.FlyingAbility;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.constants.CardType; import mage.constants.CardType;
@ -47,7 +47,6 @@ import mage.filter.common.FilterCreaturePermanent;
import mage.filter.predicate.Predicates; import mage.filter.predicate.Predicates;
import mage.filter.predicate.mageobject.AbilityPredicate; import mage.filter.predicate.mageobject.AbilityPredicate;
import mage.game.Game; import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.players.Player; import mage.players.Player;
import mage.target.common.TargetCreatureOrPlayer; import mage.target.common.TargetCreatureOrPlayer;
@ -58,6 +57,7 @@ import mage.target.common.TargetCreatureOrPlayer;
public class FormOfTheDragon extends CardImpl { public class FormOfTheDragon extends CardImpl {
private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("Creatures without flying"); private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("Creatures without flying");
static { static {
filter.add(Predicates.not(new AbilityPredicate(FlyingAbility.class))); filter.add(Predicates.not(new AbilityPredicate(FlyingAbility.class)));
} }
@ -66,7 +66,6 @@ public class FormOfTheDragon extends CardImpl {
super(ownerId, 93, "Form of the Dragon", Rarity.RARE, new CardType[]{CardType.ENCHANTMENT}, "{4}{R}{R}{R}"); super(ownerId, 93, "Form of the Dragon", Rarity.RARE, new CardType[]{CardType.ENCHANTMENT}, "{4}{R}{R}{R}");
this.expansionSetCode = "SCG"; this.expansionSetCode = "SCG";
// At the beginning of your upkeep, Form of the Dragon deals 5 damage to target creature or player. // 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 ability = new BeginningOfUpkeepTriggeredAbility(new DamageTargetEffect(5), TargetController.YOU, false);
ability.addTarget(new TargetCreatureOrPlayer()); ability.addTarget(new TargetCreatureOrPlayer());
@ -76,7 +75,7 @@ public class FormOfTheDragon extends CardImpl {
this.addAbility(new BeginningOfEndStepTriggeredAbility(new FormOfTheDragonEffect(), TargetController.ANY, false)); this.addAbility(new BeginningOfEndStepTriggeredAbility(new FormOfTheDragonEffect(), TargetController.ANY, false));
// Creatures without flying can't attack you. // 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) { public FormOfTheDragon(final FormOfTheDragon card) {
@ -115,30 +114,3 @@ class FormOfTheDragonEffect extends OneShotEffect {
return false; 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);
}
}

View file

@ -58,7 +58,6 @@ public class DreamHalls extends CardImpl {
super(ownerId, 28, "Dream Halls", Rarity.RARE, new CardType[]{CardType.ENCHANTMENT}, "{3}{U}{U}"); super(ownerId, 28, "Dream Halls", Rarity.RARE, new CardType[]{CardType.ENCHANTMENT}, "{3}{U}{U}");
this.expansionSetCode = "STH"; 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. // 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())); this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new DreamHallsEffect()));
} }
@ -102,7 +101,7 @@ class DreamHallsEffect extends ContinuousEffectImpl {
public boolean apply(Layer layer, SubLayer sublayer, Ability source, Game game) { public boolean apply(Layer layer, SubLayer sublayer, Ability source, Game game) {
Player controller = game.getPlayer(source.getControllerId()); Player controller = game.getPlayer(source.getControllerId());
if (controller != null) { if (controller != null) {
for (UUID playerId: controller.getInRange()) { for (UUID playerId : controller.getInRange()) {
Player player = game.getPlayer(playerId); Player player = game.getPlayer(playerId);
if (player != null) { if (player != null) {
player.getAlternativeSourceCosts().add(alternativeCastingCostAbility); player.getAlternativeSourceCosts().add(alternativeCastingCostAbility);

View file

@ -30,7 +30,7 @@ package mage.sets.tempest;
import java.util.UUID; import java.util.UUID;
import mage.abilities.common.SimpleStaticAbility; import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.costs.mana.ManaCostsImpl; 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.cards.CardImpl;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.Rarity; import mage.constants.Rarity;

View file

@ -29,21 +29,14 @@ package mage.sets.tenthedition;
import java.util.UUID; import java.util.UUID;
import mage.MageInt; import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.SimpleStaticAbility; import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.effects.ReplacementEffectImpl; import mage.abilities.effects.common.combat.CantAttackYouUnlessPayManaAllEffect;
import mage.abilities.effects.common.replacement.CantAttackYouUnlessPayManaAllEffect;
import mage.abilities.keyword.FlyingAbility; import mage.abilities.keyword.FlyingAbility;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.Outcome;
import mage.constants.Rarity; import mage.constants.Rarity;
import mage.constants.Zone; 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); 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);
}
}

View file

@ -34,11 +34,12 @@ import mage.abilities.condition.common.SuspendedCondition;
import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.decorator.ConditionalTriggeredAbility; import mage.abilities.decorator.ConditionalTriggeredAbility;
import mage.abilities.effects.common.counter.RemoveCounterSourceEffect; import mage.abilities.effects.common.counter.RemoveCounterSourceEffect;
import mage.abilities.keyword.SuspendAbility;
import mage.abilities.keyword.CantBeBlockedSourceAbility; import mage.abilities.keyword.CantBeBlockedSourceAbility;
import mage.abilities.keyword.SuspendAbility;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.Rarity; import mage.constants.Rarity;
import mage.constants.SetTargetPointer;
import mage.constants.TargetController; import mage.constants.TargetController;
import mage.constants.Zone; import mage.constants.Zone;
import mage.counters.CounterType; import mage.counters.CounterType;
@ -52,6 +53,7 @@ import mage.filter.predicate.permanent.ControllerPredicate;
public class DeepSeaKraken extends CardImpl { public class DeepSeaKraken extends CardImpl {
private static final FilterSpell filter = new FilterSpell("an opponent casts"); private static final FilterSpell filter = new FilterSpell("an opponent casts");
static { static {
filter.add(new ControllerPredicate(TargetController.OPPONENT)); 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)); 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. // Whenever an opponent casts a spell, if Deep-Sea Kraken is suspended, remove a time counter from it.
this.addAbility(new ConditionalTriggeredAbility( 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)); "Whenever an opponent casts a spell, if Deep-Sea Kraken is suspended, remove a time counter from it.", false));
} }

View file

@ -29,6 +29,7 @@ package mage.sets.urzassaga;
import java.util.Set; import java.util.Set;
import java.util.UUID; import java.util.UUID;
import mage.MageObject;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.OneShotEffect;
import mage.cards.Card; 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}"); super(ownerId, 146, "Persecute", Rarity.RARE, new CardType[]{CardType.SORCERY}, "{2}{B}{B}");
this.expansionSetCode = "USG"; this.expansionSetCode = "USG";
// Choose a color. Target player reveals his or her hand and discards all cards of that color. // Choose a color. Target player reveals his or her hand and discards all cards of that color.
this.getSpellAbility().addEffect(new PersecuteEffect()); this.getSpellAbility().addEffect(new PersecuteEffect());
this.getSpellAbility().addTarget(new TargetPlayer()); this.getSpellAbility().addTarget(new TargetPlayer());
@ -88,7 +88,8 @@ class PersecuteEffect extends OneShotEffect {
@Override @Override
public boolean apply(Game game, Ability source) { public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getFirstTarget()); Player controller = game.getPlayer(source.getFirstTarget());
if (controller != null) { MageObject sourceObject = game.getObject(source.getSourceId());
if (controller != null && sourceObject != null) {
ChoiceColor choice = new ChoiceColor(); ChoiceColor choice = new ChoiceColor();
while (!choice.isChosen()) { while (!choice.isChosen()) {
controller.choose(outcome, choice, game); controller.choose(outcome, choice, game);
@ -100,7 +101,7 @@ class PersecuteEffect extends OneShotEffect {
return false; return false;
} }
Cards hand = controller.getHand(); Cards hand = controller.getHand();
controller.revealCards("Persecute", hand, game); controller.revealCards(sourceObject.getIdName(), hand, game);
Set<Card> cards = hand.getCards(game); Set<Card> cards = hand.getCards(game);
for (Card card : cards) { for (Card card : cards) {
if (card != null && card.getColor(game).shares(choice.getColor())) { if (card != null && card.getColor(game).shares(choice.getColor())) {

View file

@ -28,18 +28,20 @@
package mage.sets.visions; package mage.sets.visions;
import java.util.UUID; import java.util.UUID;
import mage.ObjectColor;
import mage.constants.*;
import mage.abilities.Ability;
import mage.abilities.common.SimpleStaticAbility; import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.costs.mana.ManaCostsImpl; 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.abilities.keyword.CumulativeUpkeepAbility;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.game.Game; import mage.constants.CardType;
import mage.game.events.GameEvent; import mage.constants.Duration;
import mage.game.permanent.Permanent; import mage.constants.Rarity;
import mage.players.Player; 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 { 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) { public ElephantGrass(UUID ownerId) {
super(ownerId, 54, "Elephant Grass", Rarity.UNCOMMON, new CardType[]{CardType.ENCHANTMENT}, "{G}"); super(ownerId, 54, "Elephant Grass", Rarity.UNCOMMON, new CardType[]{CardType.ENCHANTMENT}, "{G}");
this.expansionSetCode = "VIS"; this.expansionSetCode = "VIS";
// Cumulative upkeep {1} // Cumulative upkeep {1}
this.addAbility(new CumulativeUpkeepAbility(new ManaCostsImpl("{1}"))); this.addAbility(new CumulativeUpkeepAbility(new ManaCostsImpl("{1}")));
// Black creatures can't attack you. // 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. // 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) { public ElephantGrass(final ElephantGrass card) {
@ -68,97 +80,3 @@ public class ElephantGrass extends CardImpl {
return new ElephantGrass(this); 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);
}
}

View file

@ -34,23 +34,20 @@ import mage.abilities.SpellAbility;
import mage.abilities.common.CantBlockAbility; import mage.abilities.common.CantBlockAbility;
import mage.abilities.common.EntersBattlefieldAbility; import mage.abilities.common.EntersBattlefieldAbility;
import mage.abilities.common.SimpleStaticAbility; 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.costs.mana.ManaCostsImpl;
import mage.abilities.effects.EntersBattlefieldEffect; import mage.abilities.effects.EntersBattlefieldEffect;
import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.ReplacementEffectImpl; import mage.abilities.effects.common.combat.CantAttackBlockUnlessPaysSourceEffect;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.Outcome; import mage.constants.Outcome;
import mage.constants.Rarity; import mage.constants.Rarity;
import mage.constants.Zone; import mage.constants.Zone;
import mage.counters.CounterType; import mage.counters.CounterType;
import mage.game.Game; import mage.game.Game;
import mage.game.events.GameEvent; import mage.game.events.GameEvent;
import mage.game.events.GameEvent.EventType;
import mage.game.permanent.Permanent; import mage.game.permanent.Permanent;
import mage.players.Player;
/** /**
* *
@ -72,7 +69,7 @@ public class PhyrexianMarauder extends CardImpl {
this.addAbility(new CantBlockAbility()); this.addAbility(new CantBlockAbility());
// Phyrexian Marauder can't attack unless you pay {1} for each +1/+1 counter on it. // 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) { public PhyrexianMarauder(final PhyrexianMarauder card) {
@ -116,53 +113,37 @@ class PhyrexianMarauderEntersEffect extends OneShotEffect {
} }
} }
class PhyrexianMarauderPayEffect extends ReplacementEffectImpl { class PhyrexianMarauderCantAttackUnlessYouPayEffect extends CantAttackBlockUnlessPaysSourceEffect {
PhyrexianMarauderPayEffect() { PhyrexianMarauderCantAttackUnlessYouPayEffect() {
super(Duration.WhileOnBattlefield, Outcome.Neutral); super(new ManaCostsImpl("{0}"), RestrictType.ATTACK);
staticText = "{this} can't attack unless you pay {1} for each +1/+1 counter on it"; staticText = "{this} can't attack unless you pay {1} for each +1/+1 counter on it";
} }
PhyrexianMarauderPayEffect(PhyrexianMarauderPayEffect effect) { PhyrexianMarauderCantAttackUnlessYouPayEffect(PhyrexianMarauderCantAttackUnlessYouPayEffect effect) {
super(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<ManaCost> 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 @Override
public boolean applies(GameEvent event, Ability source, Game game) { public boolean applies(GameEvent event, Ability source, Game game) {
return event.getSourceId().equals(source.getSourceId()); return source.getSourceId().equals(event.getSourceId());
} }
@Override @Override
public PhyrexianMarauderPayEffect copy() { public ManaCosts getManaCostToPay(GameEvent event, Ability source, Game game) {
return new PhyrexianMarauderPayEffect(this); 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);
}
} }

View file

@ -2,7 +2,6 @@ package org.mage.test.cards.cost.alternate;
import mage.constants.PhaseStep; import mage.constants.PhaseStep;
import mage.constants.Zone; import mage.constants.Zone;
import org.junit.Test; import org.junit.Test;
import org.mage.test.serverside.base.CardTestPlayerBase; import org.mage.test.serverside.base.CardTestPlayerBase;
@ -10,6 +9,7 @@ public class OmniscienceTest extends CardTestPlayerBase {
@Test @Test
public void testSpellNoCost() { public void testSpellNoCost() {
// You may cast nonland cards from your hand without paying their mana costs.
addCard(Zone.BATTLEFIELD, playerA, "Omniscience", 1); addCard(Zone.BATTLEFIELD, playerA, "Omniscience", 1);
addCard(Zone.HAND, playerA, "Gray Ogre", 1); addCard(Zone.HAND, playerA, "Gray Ogre", 1);
@ -25,6 +25,7 @@ public class OmniscienceTest extends CardTestPlayerBase {
@Test @Test
public void testSpellHasCostIfCastFromGraveyard() { 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, "Omniscience", 1);
addCard(Zone.BATTLEFIELD, playerA, "Haakon, Stromgald Scourge", 1); addCard(Zone.BATTLEFIELD, playerA, "Haakon, Stromgald Scourge", 1);
@ -40,6 +41,4 @@ public class OmniscienceTest extends CardTestPlayerBase {
assertPermanentCount(playerA, "Knight of the White Orchid", 0); assertPermanentCount(playerA, "Knight of the White Orchid", 0);
} }
} }

View file

@ -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);
}
}

View file

@ -48,6 +48,7 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement
protected String deckNameB; protected String deckNameB;
protected enum ExpectedType { protected enum ExpectedType {
TURN_NUMBER, TURN_NUMBER,
RESULT, RESULT,
LIFE, LIFE,
@ -62,7 +63,8 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement
} }
/** /**
* Default game initialization params for red player (that plays with Mountains) * Default game initialization params for red player (that plays with
* Mountains)
*/ */
@Override @Override
public void useRedDefault() { 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() { public void useWhiteDefault() {
// *** ComputerA *** // *** ComputerA ***
@ -120,7 +123,7 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement
stopAtStep = PhaseStep.UNTAP; stopAtStep = PhaseStep.UNTAP;
for (Player player : currentGame.getPlayers().values()) { for (Player player : currentGame.getPlayers().values()) {
TestPlayer testPlayer = (TestPlayer)player; TestPlayer testPlayer = (TestPlayer) player;
getCommands(testPlayer).clear(); getCommands(testPlayer).clear();
getLibraryCards(testPlayer).clear(); getLibraryCards(testPlayer).clear();
getHandCards(testPlayer).clear(); getHandCards(testPlayer).clear();
@ -156,7 +159,8 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement
/** /**
* Starts testing card by starting current game. * 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 { public void execute() throws IllegalStateException {
if (currentGame == null || activePlayer == null) { if (currentGame == null || activePlayer == null) {
@ -164,7 +168,7 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement
} }
for (Player player : currentGame.getPlayers().values()) { for (Player player : currentGame.getPlayers().values()) {
TestPlayer testPlayer = (TestPlayer)player; TestPlayer testPlayer = (TestPlayer) player;
currentGame.cheat(player.getId(), getCommands(testPlayer)); currentGame.cheat(player.getId(), getCommands(testPlayer));
currentGame.cheat(player.getId(), getLibraryCards(testPlayer), getHandCards(testPlayer), currentGame.cheat(player.getId(), getLibraryCards(testPlayer), getHandCards(testPlayer),
getBattlefieldCards(testPlayer), getGraveCards(testPlayer)); getBattlefieldCards(testPlayer), getGraveCards(testPlayer));
@ -183,8 +187,6 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement
} }
protected TestPlayer createNewPlayer(String playerName) { protected TestPlayer createNewPlayer(String playerName) {
return createPlayer(playerName); return createPlayer(playerName);
} }
@ -211,8 +213,9 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement
} }
/** /**
* Removes all cards from player's library from the game. * Removes all cards from player's library from the game. Usually this
* Usually this should be used once before initialization to form the library in certain order. * should be used once before initialization to form the library in certain
* order.
* *
* @param player {@link Player} to remove all library cards from. * @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. * Removes all cards from player's hand from the game. Usually this should
* Usually this should be used once before initialization to set the players hand. * be used once before initialization to set the players hand.
* *
* @param player {@link Player} to remove all cards from 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. * Add a card to specified zone of specified player.
* *
* @param gameZone {@link mage.constants.Zone} to add cards to. * @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 cardName Card name in string format.
*/ */
public void addCard(Zone gameZone, TestPlayer player, String cardName) { public void addCard(Zone gameZone, TestPlayer player, String cardName) {
@ -245,7 +249,8 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement
* Add any amount of cards to specified zone of specified player. * Add any amount of cards to specified zone of specified player.
* *
* @param gameZone {@link mage.constants.Zone} to add cards to. * @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 cardName Card name in string format.
* @param count Amount of cards to be added. * @param count Amount of cards to be added.
*/ */
@ -257,11 +262,13 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement
* Add any amount of cards to specified zone of specified player. * Add any amount of cards to specified zone of specified player.
* *
* @param gameZone {@link mage.constants.Zone} to add cards to. * @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 cardName Card name in string format.
* @param count Amount of cards to be added. * @param count Amount of cards to be added.
* @param tapped In case gameZone is Battlefield, determines whether permanent should be tapped. * @param tapped In case gameZone is Battlefield, determines whether
* In case gameZone is other than Battlefield, {@link IllegalArgumentException} is thrown * 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) { public void addCard(Zone gameZone, TestPlayer player, String cardName, int count, boolean tapped) {
@ -323,6 +330,7 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement
/** /**
* Define turn number to stop the game on. * Define turn number to stop the game on.
*
* @param turn * @param turn
*/ */
@Override @Override
@ -332,8 +340,9 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement
} }
/** /**
* Define turn number and step to stop the game on. * Define turn number and step to stop the game on. The game stops after
* The game stops after executing the step * executing the step
*
* @param turn * @param turn
* @param step * @param step
*/ */
@ -400,19 +409,20 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement
/** /**
* Assert creature's power and toughness by card name. * Assert creature's power and toughness by card name.
* <p/> * <p/>
* Throws {@link AssertionError} in the following cases: * Throws {@link AssertionError} in the following cases: 1. no such player
* 1. no such player * 2. no such creature under player's control 3. depending on comparison
* 2. no such creature under player's control * scope: 3a. any: no creature under player's control with the specified p\t
* 3. depending on comparison scope: * params 3b. all: there is at least one creature with the cardName with the
* 3a. any: no creature under player's control with the specified p\t params * different 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 player {@link Player} to get creatures for comparison.
* @param cardName Card name to compare with. * @param cardName Card name to compare with.
* @param power Expected power to compare with. * @param power Expected power to compare with.
* @param toughness Expected toughness 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" * @param scope {@link mage.filter.Filter.ComparisonScope} Use ANY, if you
* Use ALL, if you want "all creature with gived name should have specified p\t" * 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 @Override
public void assertPowerToughness(Player player, String cardName, int power, int toughness, Filter.ComparisonScope scope) public void assertPowerToughness(Player player, String cardName, int power, int toughness, Filter.ComparisonScope scope)
@ -442,17 +452,18 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement
} }
} }
Assert.assertTrue("There is no such permanent under player's control, player=" + player.getName() + Assert.assertTrue("There is no such permanent under player's control, player=" + player.getName()
", cardName=" + cardName, count > 0); + ", cardName=" + cardName, count > 0);
if (scope.equals(Filter.ComparisonScope.Any)) { if (scope.equals(Filter.ComparisonScope.Any)) {
Assert.assertTrue("There is no such creature under player's control with specified power&toughness, player=" + player.getName() + 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); + ", 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 player
* @param cardName * @param cardName
@ -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() + Assert.assertNotNull("There is no such permanent under player's control, player=" + player.getName()
", cardName=" + cardName, found); + ", cardName=" + cardName, found);
Assert.assertTrue("There is more than one such permanent under player's control, player=" + player.getName() + Assert.assertTrue("There is more than one such permanent under player's control, player=" + player.getName()
", cardName=" + cardName, count == 1); + ", cardName=" + cardName, count == 1);
for (Ability ability : abilities) { for (Ability ability : abilities) {
Assert.assertTrue("No such ability=" + ability.toString() + ", player=" + player.getName() + Assert.assertTrue("No such ability=" + ability.toString() + ", player=" + player.getName()
", cardName" + cardName, found.getAbilities().contains(ability)); + ", cardName" + cardName, found.getAbilities().contains(ability));
} }
} }
@ -495,7 +506,8 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement
* @param player * @param player
* @param cardName * @param cardName
* @param ability * @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 * @throws AssertionError
*/ */
public void assertAbility(Player player, String cardName, Ability ability, boolean flag) 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() + Assert.assertNotNull("There is no such permanent under player's control, player=" + player.getName()
", cardName=" + cardName, found); + ", cardName=" + cardName, found);
Assert.assertTrue("There is more than one such permanent under player's control, player=" + player.getName() + Assert.assertTrue("There is more than one such permanent under player's control, player=" + player.getName()
", cardName=" + cardName, count == 1); + ", cardName=" + cardName, count == 1);
if (flag) { if (flag) {
Assert.assertTrue("No such ability=" + ability.toString() + ", player=" + player.getName() + Assert.assertTrue("No such ability=" + ability.toString() + ", player=" + player.getName()
", cardName" + cardName, found.getAbilities().containsRule(ability)); + ", cardName" + cardName, found.getAbilities().containsRule(ability));
} else { } else {
Assert.assertFalse("Card shouldn't have such ability=" + ability.toString() + ", player=" + player.getName() + Assert.assertFalse("Card shouldn't have such ability=" + ability.toString() + ", player=" + player.getName()
", cardName" + cardName, found.getAbilities().containsRule(ability)); + ", cardName" + cardName, found.getAbilities().containsRule(ability));
} }
} }
@ -595,6 +607,7 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement
Assert.assertNotNull("There is no such permanent on the battlefield, cardName=" + cardName, found); 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.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
* *
@ -684,7 +697,12 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement
Permanent found = null; Permanent found = null;
for (Permanent permanent : currentGame.getBattlefield().getAllActivePermanents()) { for (Permanent permanent : currentGame.getBattlefield().getAllActivePermanents()) {
if (permanent.getName().equals(cardName)) { if (permanent.getName().equals(cardName)) {
if (found == null) {
found = permanent; found = permanent;
} else if (tapped != found.isTapped()) { // try to find a not correct permanent
found = permanent;
break;
}
} }
} }
@ -756,7 +774,7 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement
*/ */
public void assertExileCount(String cardName, int count) throws AssertionError { public void assertExileCount(String cardName, int count) throws AssertionError {
int actualCount = 0; int actualCount = 0;
for (ExileZone exile: currentGame.getExile().getExileZones()) { for (ExileZone exile : currentGame.getExile().getExileZones()) {
for (Card card : exile.getCards(currentGame)) { for (Card card : exile.getCards(currentGame)) {
if (card.getName().equals(cardName)) { if (card.getName().equals(cardName)) {
actualCount++; actualCount++;
@ -775,7 +793,7 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement
*/ */
public void assertExileCount(Player owner, int count) throws AssertionError { public void assertExileCount(Player owner, int count) throws AssertionError {
int actualCount = 0; int actualCount = 0;
for (ExileZone exile: currentGame.getExile().getExileZones()) { for (ExileZone exile : currentGame.getExile().getExileZones()) {
for (Card card : exile.getCards(currentGame)) { for (Card card : exile.getCards(currentGame)) {
if (card.getOwnerId().equals(owner.getId())) { if (card.getOwnerId().equals(owner.getId())) {
actualCount++; actualCount++;
@ -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 player
* @param count * @param count
*/ */
@ -855,19 +875,22 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement
* @param step * @param step
* @param player * @param player
* @param cardName * @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) { public void castSpell(int turnNum, PhaseStep step, TestPlayer player, String cardName, String targetName) {
player.addAction(turnNum, step, "activate:Cast " + cardName + "$target=" + targetName); player.addAction(turnNum, step, "activate:Cast " + cardName + "$target=" + targetName);
} }
public enum StackClause { public enum StackClause {
WHILE_ON_STACK, WHILE_ON_STACK,
WHILE_NOT_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 turnNum
* @param step * @param step
@ -881,7 +904,8 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement
} }
/** /**
* 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 turnNum
* @param step * @param step
@ -932,13 +956,14 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement
* @param step * @param step
* @param player * @param player
* @param ability * @param ability
* @param targetName if not target has to be defined use the constant NO_TARGET * @param targetName if not target has to be defined use the constant
* NO_TARGET
* @param spellOnStack * @param spellOnStack
*/ */
public void activateAbility(int turnNum, PhaseStep step, TestPlayer player, String ability, String targetName, String spellOnStack) { public void activateAbility(int turnNum, PhaseStep step, TestPlayer player, String ability, String targetName, String spellOnStack) {
StringBuilder sb = new StringBuilder("activate:").append(ability); StringBuilder sb = new StringBuilder("activate:").append(ability);
if (targetName != null && !targetName.isEmpty()) { if (targetName != null && !targetName.isEmpty()) {
sb.append("$target=" ).append(targetName); sb.append("$target=").append(targetName);
} }
if (spellOnStack != null && !spellOnStack.isEmpty()) { if (spellOnStack != null && !spellOnStack.isEmpty()) {
sb.append("$spellOnStack=").append(spellOnStack); 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) { 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) { 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) { public void attack(int turnNum, TestPlayer player, String attacker, String planeswalker) {
@ -963,12 +988,12 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement
} }
public void block(int turnNum, TestPlayer player, String blocker, String attacker) { 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 use choices set "Yes" or "No" the the choice string. For X values set
* For X values set "X=[xValue]" example: for X=3 set choice string to "X=3". * "X=[xValue]" example: for X=3 set choice string to "X=3".
* *
* @param player * @param player
* @param choice * @param choice
@ -981,7 +1006,8 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement
* Set the modes for modal spells * Set the modes for modal spells
* *
* @param player * @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) { public void setModeChoice(TestPlayer player, String choice) {
player.addModeChoice(choice); player.addModeChoice(choice);
@ -991,12 +1017,12 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement
* Set target permanents * Set target permanents
* *
* @param player * @param player
* @param target you can add multiple targets by seperating them by the "^" character * @param target you can add multiple targets by seperating them by the "^"
* e.g. "creatureName1^creatureName2" * character e.g. "creatureName1^creatureName2" you can qualify the target
* you can qualify the target additional by setcode * additional by setcode e.g. "creatureName-M15" you can add [no copy] to
* e.g. "creatureName-M15" * the end of the target name to prohibite targets that are copied you can
* you can add [no copy] to the end of the target name to prohibite targets that are copied * add [only copy] to the end of the target name to allow only targets that
* you can add [only copy] to the end of the target name to allow only targets that are copies * are copies
*/ */
public void addTarget(TestPlayer player, String target) { public void addTarget(TestPlayer player, String target) {
player.addTarget(target); player.addTarget(target);
@ -1009,7 +1035,7 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement
* @param targetPlayer * @param targetPlayer
*/ */
public void addTarget(TestPlayer player, TestPlayer targetPlayer) { public void addTarget(TestPlayer player, TestPlayer targetPlayer) {
player.addTarget("targetPlayer="+targetPlayer.getName()); player.addTarget("targetPlayer=" + targetPlayer.getName());
} }
public void setDecknamePlayerA(String deckname) { public void setDecknamePlayerA(String deckname) {

View file

@ -1,31 +1,30 @@
/* /*
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without modification, are * Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met: * permitted provided that the following conditions are met:
* *
* 1. Redistributions of source code must retain the above copyright notice, this list of * 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer. * conditions and the following disclaimer.
* *
* 2. Redistributions in binary form must reproduce the above copyright notice, this list * 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 * of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution. * provided with the distribution.
* *
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED * 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 * 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 * 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 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 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 * 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 * 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 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* *
* The views and conclusions contained in the software and documentation are those of the * 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 * authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com. * or implied, of BetaSteward_at_googlemail.com.
*/ */
package mage; package mage;
import java.io.Serializable; import java.io.Serializable;
@ -50,7 +49,8 @@ public class ObjectColor implements Serializable, Copyable<ObjectColor>, Compara
private boolean red; private boolean red;
private boolean green; private boolean green;
public ObjectColor() {} public ObjectColor() {
}
public ObjectColor(String color) { public ObjectColor(String color) {
for (int i = 0; i < color.length(); i++) { for (int i = 0; i < color.length(); i++) {
@ -157,30 +157,39 @@ public class ObjectColor implements Serializable, Copyable<ObjectColor>, Compara
public boolean isWhite() { public boolean isWhite() {
return white; return white;
} }
public void setWhite(boolean white) { public void setWhite(boolean white) {
this.white = white; this.white = white;
} }
public boolean isBlue() { public boolean isBlue() {
return blue; return blue;
} }
public void setBlue(boolean blue) { public void setBlue(boolean blue) {
this.blue = blue; this.blue = blue;
} }
public boolean isBlack() { public boolean isBlack() {
return black; return black;
} }
public void setBlack(boolean black) { public void setBlack(boolean black) {
this.black = black; this.black = black;
} }
public boolean isRed() { public boolean isRed() {
return red; return red;
} }
public void setRed(boolean red) { public void setRed(boolean red) {
this.red = red; this.red = red;
} }
public boolean isGreen() { public boolean isGreen() {
return green; return green;
} }
public void setGreen(boolean green) { public void setGreen(boolean green) {
this.green = green; this.green = green;
} }
@ -287,14 +296,10 @@ public class ObjectColor implements Serializable, Copyable<ObjectColor>, Compara
} }
public boolean shares(ObjectColor color) { public boolean shares(ObjectColor color) {
if (this == color) { // 105.4. [...] Multicolored is not a color. Neither is colorless.
return true; return !color.isColorless()
} && (color.white && white || color.blue && blue || color.black && black
if (!hasColor() && !color.hasColor()) { || color.red && red || color.green && green);
return true;
}
return color.white && white || color.blue && blue || color.black && black ||
color.red && red || color.green && green;
} }
@Override @Override
@ -309,32 +314,32 @@ public class ObjectColor implements Serializable, Copyable<ObjectColor>, Compara
if (this.isMulticolored()) { if (this.isMulticolored()) {
o1 = 6; o1 = 6;
} else if(this.isColorless()) { } else if (this.isColorless()) {
o1 = 0; o1 = 0;
} else if(this.isBlack()) { } else if (this.isBlack()) {
o1 = 1; o1 = 1;
} else if(this.isBlue()) { } else if (this.isBlue()) {
o1 = 2; o1 = 2;
} else if(this.isGreen()) { } else if (this.isGreen()) {
o1 = 3; o1 = 3;
} else if(this.isRed()) { } else if (this.isRed()) {
o1 = 4; o1 = 4;
} else if(this.isWhite()) { } else if (this.isWhite()) {
o1 = 5; o1 = 5;
} }
if (o.isMulticolored()) { if (o.isMulticolored()) {
o2 = 6; o2 = 6;
} else if(o.isColorless()) { } else if (o.isColorless()) {
o2 = 0; o2 = 0;
} else if(o.isBlack()) { } else if (o.isBlack()) {
o2 = 1; o2 = 1;
} else if(o.isBlue()) { } else if (o.isBlue()) {
o2 = 2; o2 = 2;
} else if(o.isGreen()) { } else if (o.isGreen()) {
o2 = 3; o2 = 3;
} else if(o.isRed()) { } else if (o.isRed()) {
o2 = 4; o2 = 4;
} else if(o.isWhite()) { } else if (o.isWhite()) {
o2 = 5; o2 = 5;
} }
return o1 - o2; return o1 - o2;

View file

@ -336,7 +336,8 @@ public class ContinuousEffects implements Serializable {
if (ability.getAbilityType() != AbilityType.STATIC || ability.isInUseableZone(game, null, event)) { if (ability.getAbilityType() != AbilityType.STATIC || ability.isInUseableZone(game, null, event)) {
if (effect.getDuration() != Duration.OneUse || !effect.isUsed()) { if (effect.getDuration() != Duration.OneUse || !effect.isUsed()) {
if (!game.getScopeRelevant() || effect.hasSelfScope() || !event.getTargetId().equals(ability.getSourceId())) { 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; return true;
} }
} }

View file

@ -42,4 +42,6 @@ public interface PayCostToAttackBlockEffect extends ReplacementEffect {
ManaCosts getManaCostToPay(GameEvent event, Ability source, Game game); ManaCosts getManaCostToPay(GameEvent event, Ability source, Game game);
Cost getOtherCostToPay(GameEvent event, Ability source, Game game); Cost getOtherCostToPay(GameEvent event, Ability source, Game game);
boolean isCostless(GameEvent event, Ability source, Game game);
} }

View file

@ -46,13 +46,26 @@ public abstract class PayCostToAttackBlockEffectImpl extends ReplacementEffectIm
public static enum RestrictType { 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;
} }
private final Cost cost; @Override
private final ManaCosts manaCosts; public String toString() {
return text;
}
}
private final RestrictType restrictType; protected final Cost cost;
protected final ManaCosts manaCosts;
protected final RestrictType restrictType;
public PayCostToAttackBlockEffectImpl(Duration duration, Outcome outcome, RestrictType restrictType) { public PayCostToAttackBlockEffectImpl(Duration duration, Outcome outcome, RestrictType restrictType) {
super(duration, outcome, false); super(duration, outcome, false);
@ -165,4 +178,13 @@ public abstract class PayCostToAttackBlockEffectImpl extends ReplacementEffectIm
return manaCosts; 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;
}
} }

View file

@ -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);
}
}

View file

@ -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) ? " <i>(This cost is paid as attackers are declared.)</i>" : "");
}
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);
}
}

View file

@ -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);
}
}

View file

@ -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);
}
}

View file

@ -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);
}
}

View file

@ -71,6 +71,7 @@ public class Combat implements Serializable, Copyable<Combat> {
protected List<CombatGroup> groups = new ArrayList<>(); protected List<CombatGroup> groups = new ArrayList<>();
protected Map<UUID, CombatGroup> blockingGroups = new HashMap<>(); protected Map<UUID, CombatGroup> blockingGroups = new HashMap<>();
// player and plainswalker ids
protected Set<UUID> defenders = new HashSet<>(); protected Set<UUID> defenders = new HashSet<>();
// how many creatures attack defending player // how many creatures attack defending player
protected Map<UUID, Set<UUID>> numberCreaturesDefenderAttackedBy = new HashMap<>(); protected Map<UUID, Set<UUID>> numberCreaturesDefenderAttackedBy = new HashMap<>();

View file

@ -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 // eliminate duplicate activated abilities
Map<String, Ability> playableActivated = new HashMap<>(); Map<String, Ability> playableActivated = new HashMap<>();
for (Permanent permanent : game.getBattlefield().getAllActivePermanents(playerId)) { for (Permanent permanent : game.getBattlefield().getAllActivePermanents(playerId)) {