diff --git a/Mage.Sets/src/mage/cards/a/AccursedWitch.java b/Mage.Sets/src/mage/cards/a/AccursedWitch.java index 497724b2b63..0bc6e8d72a2 100644 --- a/Mage.Sets/src/mage/cards/a/AccursedWitch.java +++ b/Mage.Sets/src/mage/cards/a/AccursedWitch.java @@ -1,25 +1,20 @@ - package mage.cards.a; import mage.MageInt; import mage.abilities.Ability; -import mage.abilities.Mode; -import mage.abilities.SpellAbility; import mage.abilities.common.DiesSourceTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.OneShotEffect; -import mage.abilities.effects.common.cost.CostModificationEffectImpl; +import mage.abilities.effects.common.cost.SpellsCostModificationThatTargetSourceEffect; import mage.abilities.keyword.TransformAbility; import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.*; +import mage.filter.FilterCard; import mage.game.Game; -import mage.game.permanent.Permanent; import mage.players.Player; -import mage.target.Target; import mage.target.common.TargetOpponent; -import mage.util.CardUtil; import java.util.UUID; @@ -39,7 +34,10 @@ public final class AccursedWitch extends CardImpl { this.secondSideCardClazz = mage.cards.i.InfectiousCurse.class; // Spells your opponents cast that target Accursed Witch cost {1} less to cast. - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new AccursedWitchSpellsCostReductionEffect())); + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, + new SpellsCostModificationThatTargetSourceEffect(-1, new FilterCard("Spells"), TargetController.OPPONENT)) + ); + // When Accursed Witch dies, return it to the battlefield transformed under your control attached to target opponent. this.addAbility(new TransformAbility()); Ability ability = new DiesSourceTriggeredAbility(new AccursedWitchReturnTransformedEffect()); @@ -93,45 +91,3 @@ class AccursedWitchReturnTransformedEffect extends OneShotEffect { return true; } } - -class AccursedWitchSpellsCostReductionEffect extends CostModificationEffectImpl { - - AccursedWitchSpellsCostReductionEffect() { - super(Duration.WhileOnBattlefield, Outcome.Detriment, CostModificationType.REDUCE_COST); - this.staticText = "Spells your opponents cast that target {this} cost {1} less to cast"; - } - - private AccursedWitchSpellsCostReductionEffect(AccursedWitchSpellsCostReductionEffect effect) { - super(effect); - } - - @Override - public boolean apply(Game game, Ability source, Ability abilityToModify) { - CardUtil.reduceCost(abilityToModify, 1); - return true; - } - - @Override - public boolean applies(Ability abilityToModify, Ability source, Game game) { - if (!(abilityToModify instanceof SpellAbility) || !game.getOpponents(source.getControllerId()).contains(abilityToModify.getControllerId())) { - return false; - } - for (UUID modeId : abilityToModify.getModes().getSelectedModes()) { - Mode mode = abilityToModify.getModes().get(modeId); - for (Target target : mode.getTargets()) { - for (UUID targetUUID : target.getTargets()) { - Permanent permanent = game.getPermanent(targetUUID); - if (permanent != null && permanent.getId().equals(source.getSourceId())) { - return true; - } - } - } - } - return false; - } - - @Override - public AccursedWitchSpellsCostReductionEffect copy() { - return new AccursedWitchSpellsCostReductionEffect(this); - } -} diff --git a/Mage.Sets/src/mage/cards/a/AnimarSoulOfElements.java b/Mage.Sets/src/mage/cards/a/AnimarSoulOfElements.java index e47b01a4681..1ac2052194d 100644 --- a/Mage.Sets/src/mage/cards/a/AnimarSoulOfElements.java +++ b/Mage.Sets/src/mage/cards/a/AnimarSoulOfElements.java @@ -82,9 +82,9 @@ class AnimarCostReductionEffect extends CostModificationEffectImpl { public boolean applies(Ability abilityToModify, Ability source, Game game) { if (abilityToModify instanceof SpellAbility) { if (abilityToModify.isControlledBy(source.getControllerId())) { - Card spell = ((SpellAbility) abilityToModify).getCharacteristics(game); - if (spell != null) { - return spell.isCreature(); + Card card = ((SpellAbility) abilityToModify).getCharacteristics(game); + if (card != null) { + return card.isCreature(); } } } diff --git a/Mage.Sets/src/mage/cards/a/ArcaneMelee.java b/Mage.Sets/src/mage/cards/a/ArcaneMelee.java index 9e45b06db79..2657238404a 100644 --- a/Mage.Sets/src/mage/cards/a/ArcaneMelee.java +++ b/Mage.Sets/src/mage/cards/a/ArcaneMelee.java @@ -1,17 +1,14 @@ - package mage.cards.a; -import java.util.UUID; -import mage.abilities.Ability; -import mage.abilities.SpellAbility; import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.effects.common.cost.CostModificationEffectImpl; -import mage.cards.Card; +import mage.abilities.effects.common.cost.SpellsCostReductionAllEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.*; -import mage.game.Game; -import mage.util.CardUtil; +import mage.constants.CardType; +import mage.constants.Zone; +import mage.filter.common.FilterInstantOrSorceryCard; + +import java.util.UUID; /** * @author noxx @@ -22,7 +19,9 @@ public final class ArcaneMelee extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{4}{U}"); // Instant and sorcery spells cost {2} less to cast. - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new ArcaneMeleeCostReductionEffect())); + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, + new SpellsCostReductionAllEffect(new FilterInstantOrSorceryCard("Instant and sorcery spells"), 2)) + ); } public ArcaneMelee(final ArcaneMelee card) { @@ -34,39 +33,3 @@ public final class ArcaneMelee extends CardImpl { return new ArcaneMelee(this); } } - -class ArcaneMeleeCostReductionEffect extends CostModificationEffectImpl { - - ArcaneMeleeCostReductionEffect() { - super(Duration.WhileOnBattlefield, Outcome.Benefit, CostModificationType.REDUCE_COST); - staticText = "Instant and sorcery spells cost {2} less to cast"; - } - - ArcaneMeleeCostReductionEffect(ArcaneMeleeCostReductionEffect effect) { - super(effect); - } - - @Override - public boolean apply(Game game, Ability source, Ability abilityToModify) { - SpellAbility spellAbility = (SpellAbility) abilityToModify; - CardUtil.adjustCost(spellAbility, 2); - return true; - } - - @Override - public boolean applies(Ability abilityToModify, Ability source, Game game) { - if (abilityToModify instanceof SpellAbility) { - Card sourceCard = game.getCard((abilityToModify).getSourceId()); - if (sourceCard != null && (sourceCard.isInstant() || sourceCard.isSorcery())) { - return true; - } - } - return false; - } - - @Override - public ArcaneMeleeCostReductionEffect copy() { - return new ArcaneMeleeCostReductionEffect(this); - } - -} diff --git a/Mage.Sets/src/mage/cards/a/AvatarOfFury.java b/Mage.Sets/src/mage/cards/a/AvatarOfFury.java index 9153c0a4f99..6489605608b 100644 --- a/Mage.Sets/src/mage/cards/a/AvatarOfFury.java +++ b/Mage.Sets/src/mage/cards/a/AvatarOfFury.java @@ -1,33 +1,41 @@ package mage.cards.a; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; -import mage.abilities.SpellAbility; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.Condition; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.common.continuous.BoostSourceEffect; -import mage.abilities.effects.common.cost.CostModificationEffectImpl; +import mage.abilities.effects.common.cost.SpellCostReductionSourceEffect; +import mage.abilities.hint.ConditionHint; import mage.abilities.keyword.FlyingAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.CostModificationType; import mage.constants.Duration; -import mage.constants.Outcome; import mage.constants.SubType; import mage.constants.Zone; +import mage.filter.FilterPermanent; import mage.filter.StaticFilters; +import mage.filter.predicate.Predicates; import mage.game.Game; -import mage.util.CardUtil; + +import java.util.UUID; /** - * * @author LevelX2 */ public final class AvatarOfFury extends CardImpl { + private static final FilterPermanent filter = new FilterPermanent("artifact, creature, or enchantment"); + + static { + filter.add(Predicates.or(CardType.ARTIFACT.getPredicate(), + CardType.CREATURE.getPredicate(), + CardType.ENCHANTMENT.getPredicate())); + } + public AvatarOfFury(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{6}{R}{R}"); this.subtype.add(SubType.AVATAR); @@ -36,9 +44,14 @@ public final class AvatarOfFury extends CardImpl { this.toughness = new MageInt(6); // If an opponent controls seven or more lands, Avatar of Fury costs {6} less to cast. - this.addAbility(new SimpleStaticAbility(Zone.ALL, new AvatarOfFuryAdjustingCostsEffect())); + this.addAbility(new SimpleStaticAbility(Zone.ALL, new SpellCostReductionSourceEffect(6, AvatarOfFuryCondition.instance) + .setText("if an opponent controls seven or more lands, Avatar of Fury costs {6} less to cast")) + .addHint(new ConditionHint(AvatarOfFuryCondition.instance, "Opponent controls seven or more lands")) + ); + // Flying this.addAbility(FlyingAbility.getInstance()); + // {R}: Avatar of Fury gets +1/+0 until end of turn. this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new BoostSourceEffect(1, 0, Duration.EndOfTurn), new ManaCostsImpl("{R}"))); } @@ -53,39 +66,22 @@ public final class AvatarOfFury extends CardImpl { } } -class AvatarOfFuryAdjustingCostsEffect extends CostModificationEffectImpl { +enum AvatarOfFuryCondition implements Condition { - AvatarOfFuryAdjustingCostsEffect() { - super(Duration.EndOfGame, Outcome.Benefit, CostModificationType.REDUCE_COST); - staticText = "If an opponent controls seven or more lands, {this} costs {6} less to cast"; - } - - AvatarOfFuryAdjustingCostsEffect(AvatarOfFuryAdjustingCostsEffect effect) { - super(effect); - } + instance; @Override - public boolean apply(Game game, Ability source, Ability abilityToModify) { - CardUtil.reduceCost(abilityToModify, 6); - return true; - } - - @Override - public boolean applies(Ability abilityToModify, Ability source, Game game) { - if (abilityToModify.getSourceId().equals(source.getSourceId()) - && (abilityToModify instanceof SpellAbility)) { - for (UUID playerId : game.getOpponents(abilityToModify.getControllerId())) { - if (game.getBattlefield().countAll(StaticFilters.FILTER_LAND, playerId, game) > 6) { - return true; - } + public boolean apply(Game game, Ability source) { + for (UUID playerId : game.getOpponents(source.getControllerId())) { + if (game.getBattlefield().countAll(StaticFilters.FILTER_LAND, playerId, game) > 6) { + return true; } } return false; } @Override - public AvatarOfFuryAdjustingCostsEffect copy() { - return new AvatarOfFuryAdjustingCostsEffect(this); + public String toString() { + return "an opponent controls seven or more lands"; } - } diff --git a/Mage.Sets/src/mage/cards/a/AvatarOfHope.java b/Mage.Sets/src/mage/cards/a/AvatarOfHope.java index d1e82950fe5..08957746eec 100644 --- a/Mage.Sets/src/mage/cards/a/AvatarOfHope.java +++ b/Mage.Sets/src/mage/cards/a/AvatarOfHope.java @@ -1,22 +1,24 @@ package mage.cards.a; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; -import mage.abilities.SpellAbility; import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.Condition; import mage.abilities.effects.common.combat.CanBlockAdditionalCreatureEffect; -import mage.abilities.effects.common.cost.CostModificationEffectImpl; +import mage.abilities.effects.common.cost.SpellCostReductionSourceEffect; +import mage.abilities.hint.ConditionHint; import mage.abilities.keyword.FlyingAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.*; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.Zone; import mage.game.Game; import mage.players.Player; -import mage.util.CardUtil; + +import java.util.UUID; /** - * * @author Plopman */ public final class AvatarOfHope extends CardImpl { @@ -29,9 +31,14 @@ public final class AvatarOfHope extends CardImpl { this.toughness = new MageInt(9); // If you have 3 or less life, Avatar of Hope costs {6} less to cast. - this.addAbility(new SimpleStaticAbility(Zone.ALL, new AvatarOfHopeAdjustingCostsEffect())); + this.addAbility(new SimpleStaticAbility(Zone.ALL, new SpellCostReductionSourceEffect(6, AvatarOfHopeCondition.instance) + .setText("if you have 3 or less life, Avatar of Hope costs {6} less to cast")) + .addHint(new ConditionHint(AvatarOfHopeCondition.instance)) + ); + // Flying this.addAbility(FlyingAbility.getInstance()); + // Avatar of Hope can block any number of creatures. this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new CanBlockAdditionalCreatureEffect(0))); } @@ -46,39 +53,21 @@ public final class AvatarOfHope extends CardImpl { } } -class AvatarOfHopeAdjustingCostsEffect extends CostModificationEffectImpl { +enum AvatarOfHopeCondition implements Condition { - AvatarOfHopeAdjustingCostsEffect() { - super(Duration.EndOfGame, Outcome.Benefit, CostModificationType.REDUCE_COST); - staticText = "If you have 3 or less life, {this} costs {6} less to cast"; - } - - AvatarOfHopeAdjustingCostsEffect(AvatarOfHopeAdjustingCostsEffect effect) { - super(effect); - } + instance; @Override - public boolean apply(Game game, Ability source, Ability abilityToModify) { - CardUtil.reduceCost(abilityToModify, 6); - return true; - } - - @Override - public boolean applies(Ability abilityToModify, Ability source, Game game) { - if (abilityToModify.getSourceId().equals(source.getSourceId()) - && (abilityToModify instanceof SpellAbility)) { - Player player = game.getPlayer(abilityToModify.getControllerId()); - if (player != null && player.getLife() < 4) { - return true; - } + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player != null && player.getLife() <= 3) { + return true; } - return false; } @Override - public AvatarOfHopeAdjustingCostsEffect copy() { - return new AvatarOfHopeAdjustingCostsEffect(this); + public String toString() { + return "you have 3 or less life"; } - } diff --git a/Mage.Sets/src/mage/cards/b/BorealElemental.java b/Mage.Sets/src/mage/cards/b/BorealElemental.java index bd0f8fcadaf..df54bda0db4 100644 --- a/Mage.Sets/src/mage/cards/b/BorealElemental.java +++ b/Mage.Sets/src/mage/cards/b/BorealElemental.java @@ -1,20 +1,17 @@ package mage.cards.b; import mage.MageInt; -import mage.abilities.Ability; -import mage.abilities.Mode; -import mage.abilities.SpellAbility; import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.effects.common.cost.CostModificationEffectImpl; +import mage.abilities.effects.common.cost.SpellsCostModificationThatTargetSourceEffect; import mage.abilities.keyword.FlyingAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.*; -import mage.game.Game; -import mage.target.Target; -import mage.util.CardUtil; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.TargetController; +import mage.constants.Zone; +import mage.filter.FilterCard; -import java.util.Collection; import java.util.UUID; /** @@ -33,7 +30,9 @@ public final class BorealElemental extends CardImpl { this.addAbility(FlyingAbility.getInstance()); // Spells your opponents cast that target Boreal Elemental cost {2} more to cast. - this.addAbility(new SimpleStaticAbility(new BorealElementalCostIncreaseEffect())); + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, + new SpellsCostModificationThatTargetSourceEffect(2, new FilterCard("Spells"), TargetController.OPPONENT)) + ); } private BorealElemental(final BorealElemental card) { @@ -45,46 +44,3 @@ public final class BorealElemental extends CardImpl { return new BorealElemental(this); } } - -class BorealElementalCostIncreaseEffect extends CostModificationEffectImpl { - - BorealElementalCostIncreaseEffect() { - super(Duration.WhileOnBattlefield, Outcome.Benefit, CostModificationType.INCREASE_COST); - staticText = "Spells your opponents cast that target {this} cost {2} more to cast"; - } - - private BorealElementalCostIncreaseEffect(BorealElementalCostIncreaseEffect effect) { - super(effect); - } - - @Override - public boolean apply(Game game, Ability source, Ability abilityToModify) { - SpellAbility spellAbility = (SpellAbility) abilityToModify; - CardUtil.adjustCost(spellAbility, -2); - return true; - } - - @Override - public boolean applies(Ability abilityToModify, Ability source, Game game) { - if (!(abilityToModify instanceof SpellAbility) - || !game.getOpponents(source.getControllerId()).contains(abilityToModify.getControllerId())) { - return false; - } - return abilityToModify - .getModes() - .getSelectedModes() - .stream() - .map(uuid -> abilityToModify.getModes().get(uuid)) - .map(Mode::getTargets) - .flatMap(Collection::stream) - .map(Target::getTargets) - .flatMap(Collection::stream) - .anyMatch(uuid -> uuid.equals(source.getSourceId())); - } - - @Override - public BorealElementalCostIncreaseEffect copy() { - return new BorealElementalCostIncreaseEffect(this); - } - -} diff --git a/Mage.Sets/src/mage/cards/c/CallapheBelovedOfTheSea.java b/Mage.Sets/src/mage/cards/c/CallapheBelovedOfTheSea.java index 4e245e095f1..1baa9de971d 100644 --- a/Mage.Sets/src/mage/cards/c/CallapheBelovedOfTheSea.java +++ b/Mage.Sets/src/mage/cards/c/CallapheBelovedOfTheSea.java @@ -2,23 +2,18 @@ package mage.cards.c; import mage.MageInt; import mage.abilities.Ability; -import mage.abilities.Mode; -import mage.abilities.SpellAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.dynamicvalue.common.DevotionCount; import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; import mage.abilities.effects.common.continuous.SetPowerSourceEffect; -import mage.abilities.effects.common.cost.CostModificationEffectImpl; +import mage.abilities.effects.common.cost.SpellsCostModificationThatTargetSourceEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.*; +import mage.filter.FilterCard; import mage.filter.FilterPermanent; import mage.filter.predicate.Predicates; -import mage.game.Game; -import mage.target.Target; -import mage.util.CardUtil; -import java.util.Collection; import java.util.UUID; /** @@ -51,11 +46,12 @@ public final class CallapheBelovedOfTheSea extends CardImpl { ).addHint(DevotionCount.U.getHint())); // Creatures and enchantments you control have "Spells your opponents cast that target this permanent cost {1} more to cast". - this.addAbility(new SimpleStaticAbility(new GainAbilityControlledEffect( - new SimpleStaticAbility( - new CallapheBelovedOfTheSeaEffect() - ), Duration.WhileOnBattlefield, filter) - .withForceQuotes() + Ability gainAbility = new SimpleStaticAbility(Zone.BATTLEFIELD, + new SpellsCostModificationThatTargetSourceEffect(1, new FilterCard("Spells"), TargetController.OPPONENT) + .withTargetName("this permanent") + ); + this.addAbility(new SimpleStaticAbility( + new GainAbilityControlledEffect(gainAbility, Duration.WhileOnBattlefield, filter).withForceQuotes() )); } @@ -68,45 +64,3 @@ public final class CallapheBelovedOfTheSea extends CardImpl { return new CallapheBelovedOfTheSea(this); } } - -class CallapheBelovedOfTheSeaEffect extends CostModificationEffectImpl { - - CallapheBelovedOfTheSeaEffect() { - super(Duration.WhileOnBattlefield, Outcome.Benefit, CostModificationType.INCREASE_COST); - staticText = "Spells your opponents cast that target this permanent cost {1} more to cast"; - } - - private CallapheBelovedOfTheSeaEffect(CallapheBelovedOfTheSeaEffect effect) { - super(effect); - } - - @Override - public boolean apply(Game game, Ability source, Ability abilityToModify) { - SpellAbility spellAbility = (SpellAbility) abilityToModify; - CardUtil.adjustCost(spellAbility, -1); - return true; - } - - @Override - public boolean applies(Ability abilityToModify, Ability source, Game game) { - if (!(abilityToModify instanceof SpellAbility) - || !game.getOpponents(source.getControllerId()).contains(abilityToModify.getControllerId())) { - return false; - } - return abilityToModify - .getModes() - .getSelectedModes() - .stream() - .map(uuid -> abilityToModify.getModes().get(uuid)) - .map(Mode::getTargets) - .flatMap(Collection::stream) - .map(Target::getTargets) - .flatMap(Collection::stream) - .anyMatch(uuid -> uuid.equals(source.getSourceId())); - } - - @Override - public CallapheBelovedOfTheSeaEffect copy() { - return new CallapheBelovedOfTheSeaEffect(this); - } -} diff --git a/Mage.Sets/src/mage/cards/e/ElderwoodScion.java b/Mage.Sets/src/mage/cards/e/ElderwoodScion.java index 778ffb55e52..eceff73b4f2 100644 --- a/Mage.Sets/src/mage/cards/e/ElderwoodScion.java +++ b/Mage.Sets/src/mage/cards/e/ElderwoodScion.java @@ -1,24 +1,21 @@ - package mage.cards.e; -import java.util.UUID; import mage.MageInt; -import mage.abilities.Ability; -import mage.abilities.Mode; -import mage.abilities.SpellAbility; import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.effects.common.cost.CostModificationEffectImpl; +import mage.abilities.effects.common.cost.SpellsCostModificationThatTargetSourceEffect; import mage.abilities.keyword.LifelinkAbility; import mage.abilities.keyword.TrampleAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.*; -import mage.game.Game; -import mage.target.Target; -import mage.util.CardUtil; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.TargetController; +import mage.constants.Zone; +import mage.filter.FilterCard; + +import java.util.UUID; /** - * * @author LevelX2 */ public final class ElderwoodScion extends CardImpl { @@ -32,12 +29,19 @@ public final class ElderwoodScion extends CardImpl { // Trample this.addAbility(TrampleAbility.getInstance()); + // Lifelink this.addAbility(LifelinkAbility.getInstance()); + // Spells you cast that target Elderwood Scion cost {2} less to cast. - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new ElderwoodScionCostReductionEffect())); + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, + new SpellsCostModificationThatTargetSourceEffect(-2, new FilterCard("Spells"), TargetController.YOU)) + ); + // Spells your opponents cast that target Elderwood Scion cost {2} more to cast. - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new ElderwoodScionCostReductionEffect2())); + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, + new SpellsCostModificationThatTargetSourceEffect(2, new FilterCard("Spells"), TargetController.OPPONENT)) + ); } public ElderwoodScion(final ElderwoodScion card) { @@ -49,92 +53,3 @@ public final class ElderwoodScion extends CardImpl { return new ElderwoodScion(this); } } - -class ElderwoodScionCostReductionEffect extends CostModificationEffectImpl { - - private static final String effectText = "Spells you cast that target {this} cost {2} less to cast"; - - ElderwoodScionCostReductionEffect() { - super(Duration.WhileOnBattlefield, Outcome.Benefit, CostModificationType.REDUCE_COST); - staticText = effectText; - } - - ElderwoodScionCostReductionEffect(ElderwoodScionCostReductionEffect effect) { - super(effect); - } - - @Override - public boolean apply(Game game, Ability source, Ability abilityToModify) { - SpellAbility spellAbility = (SpellAbility) abilityToModify; - CardUtil.adjustCost(spellAbility, 2); - return true; - } - - @Override - public boolean applies(Ability abilityToModify, Ability source, Game game) { - if (abilityToModify instanceof SpellAbility) { - if (abilityToModify.isControlledBy(source.getControllerId())) { - for (UUID modeId : abilityToModify.getModes().getSelectedModes()) { - Mode mode = abilityToModify.getModes().get(modeId); - for (Target target : mode.getTargets()) { - for (UUID targetUUID : target.getTargets()) { - if (targetUUID.equals(source.getSourceId())) { - return true; - } - } - } - } - } - } - return false; - } - - @Override - public ElderwoodScionCostReductionEffect copy() { - return new ElderwoodScionCostReductionEffect(this); - } - -} - -class ElderwoodScionCostReductionEffect2 extends CostModificationEffectImpl { - - private static final String effectText = "Spells your opponents cast that target {this} cost {2} more to cast"; - - ElderwoodScionCostReductionEffect2() { - super(Duration.WhileOnBattlefield, Outcome.Benefit, CostModificationType.INCREASE_COST); - staticText = effectText; - } - - ElderwoodScionCostReductionEffect2(ElderwoodScionCostReductionEffect2 effect) { - super(effect); - } - - @Override - public boolean apply(Game game, Ability source, Ability abilityToModify) { - SpellAbility spellAbility = (SpellAbility) abilityToModify; - CardUtil.increaseCost(spellAbility, 2); - return true; - } - - @Override - public boolean applies(Ability abilityToModify, Ability source, Game game) { - if (abilityToModify instanceof SpellAbility) { - if (game.getOpponents(source.getControllerId()).contains(abilityToModify.getControllerId())) { - for (Target target : abilityToModify.getTargets()) { - for (UUID targetUUID : target.getTargets()) { - if (targetUUID.equals(source.getSourceId())) { - return true; - } - } - } - } - } - return false; - } - - @Override - public ElderwoodScionCostReductionEffect2 copy() { - return new ElderwoodScionCostReductionEffect2(this); - } - -} diff --git a/Mage.Sets/src/mage/cards/g/Grapeshot.java b/Mage.Sets/src/mage/cards/g/Grapeshot.java index 82a6a8b5c67..5101aaa10fd 100644 --- a/Mage.Sets/src/mage/cards/g/Grapeshot.java +++ b/Mage.Sets/src/mage/cards/g/Grapeshot.java @@ -1,7 +1,5 @@ - package mage.cards.g; -import java.util.UUID; import mage.abilities.effects.common.DamageTargetEffect; import mage.abilities.keyword.StormAbility; import mage.cards.CardImpl; @@ -9,19 +7,20 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.target.common.TargetAnyTarget; +import java.util.UUID; + /** - * * @author Plopman */ public final class Grapeshot extends CardImpl { public Grapeshot(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{1}{R}"); - + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{1}{R}"); // Grapeshot deals 1 damage to any target. this.getSpellAbility().addTarget(new TargetAnyTarget()); this.getSpellAbility().addEffect(new DamageTargetEffect(1)); + // Storm this.addAbility(new StormAbility()); } diff --git a/Mage.Sets/src/mage/cards/i/IcefallRegent.java b/Mage.Sets/src/mage/cards/i/IcefallRegent.java index 71e5d8e2670..582882559a8 100644 --- a/Mage.Sets/src/mage/cards/i/IcefallRegent.java +++ b/Mage.Sets/src/mage/cards/i/IcefallRegent.java @@ -2,17 +2,16 @@ package mage.cards.i; import mage.MageInt; import mage.abilities.Ability; -import mage.abilities.Mode; -import mage.abilities.SpellAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.ContinuousRuleModifyingEffectImpl; import mage.abilities.effects.common.TapTargetEffect; -import mage.abilities.effects.common.cost.CostModificationEffectImpl; +import mage.abilities.effects.common.cost.SpellsCostModificationThatTargetSourceEffect; import mage.abilities.keyword.FlyingAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.*; +import mage.filter.FilterCard; import mage.filter.common.FilterCreaturePermanent; import mage.game.Game; import mage.game.events.GameEvent; @@ -20,7 +19,6 @@ import mage.game.events.ZoneChangeEvent; import mage.game.permanent.Permanent; import mage.target.Target; import mage.target.common.TargetCreaturePermanent; -import mage.util.CardUtil; import mage.watchers.Watcher; import java.util.UUID; @@ -53,8 +51,9 @@ public final class IcefallRegent extends CardImpl { this.addAbility(ability, new IcefallRegentWatcher()); // Spells your opponents cast that target Icefall Regent cost {2} more to cast. - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new IcefallRegentCostIncreaseEffect())); - + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, + new SpellsCostModificationThatTargetSourceEffect(2, new FilterCard("Spells"), TargetController.OPPONENT)) + ); } public IcefallRegent(final IcefallRegent card) { @@ -157,48 +156,3 @@ class IcefallRegentWatcher extends Watcher { //don't reset condition each turn - only when this leaves the battlefield } } - -class IcefallRegentCostIncreaseEffect extends CostModificationEffectImpl { - - - IcefallRegentCostIncreaseEffect() { - super(Duration.WhileOnBattlefield, Outcome.Benefit, CostModificationType.INCREASE_COST); - staticText = "Spells your opponents cast that target {this} cost {2} more to cast"; - } - - private IcefallRegentCostIncreaseEffect(IcefallRegentCostIncreaseEffect effect) { - super(effect); - } - - @Override - public boolean apply(Game game, Ability source, Ability abilityToModify) { - SpellAbility spellAbility = (SpellAbility) abilityToModify; - CardUtil.adjustCost(spellAbility, -2); - return true; - } - - @Override - public boolean applies(Ability abilityToModify, Ability source, Game game) { - if (abilityToModify instanceof SpellAbility) { - if (game.getOpponents(source.getControllerId()).contains(abilityToModify.getControllerId())) { - for (UUID modeId : abilityToModify.getModes().getSelectedModes()) { - Mode mode = abilityToModify.getModes().get(modeId); - for (Target target : mode.getTargets()) { - for (UUID targetUUID : target.getTargets()) { - if (targetUUID.equals(source.getSourceId())) { - return true; - } - } - } - } - } - } - return false; - } - - @Override - public IcefallRegentCostIncreaseEffect copy() { - return new IcefallRegentCostIncreaseEffect(this); - } - -} diff --git a/Mage.Sets/src/mage/cards/j/JubilantSkybonder.java b/Mage.Sets/src/mage/cards/j/JubilantSkybonder.java index 3c82fe7b3eb..ee0d7622b27 100644 --- a/Mage.Sets/src/mage/cards/j/JubilantSkybonder.java +++ b/Mage.Sets/src/mage/cards/j/JubilantSkybonder.java @@ -2,24 +2,19 @@ package mage.cards.j; import mage.MageInt; import mage.abilities.Ability; -import mage.abilities.Mode; -import mage.abilities.SpellAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.ContinuousEffect; import mage.abilities.effects.common.continuous.GainAbilityAllEffect; -import mage.abilities.effects.common.cost.CostModificationEffectImpl; +import mage.abilities.effects.common.cost.SpellsCostModificationThatTargetSourceEffect; import mage.abilities.keyword.FlyingAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.*; +import mage.filter.FilterCard; import mage.filter.FilterPermanent; import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.predicate.mageobject.AbilityPredicate; -import mage.game.Game; -import mage.target.Target; -import mage.util.CardUtil; -import java.util.Collection; import java.util.UUID; /** @@ -46,10 +41,12 @@ public final class JubilantSkybonder extends CardImpl { this.addAbility(FlyingAbility.getInstance()); // Creatures you control with flying have "Spells your opponents cast that target this creature cost {2} more to cast." - ContinuousEffect effect = new GainAbilityAllEffect( - new SimpleStaticAbility(new JubilantSkybonderEffect()), - Duration.WhileOnBattlefield, filter - ).withForceQuotes(); + Ability gainAbility = new SimpleStaticAbility(Zone.BATTLEFIELD, + new SpellsCostModificationThatTargetSourceEffect(2, new FilterCard("Spells"), TargetController.OPPONENT) + .withTargetName("this creature") + ); + + ContinuousEffect effect = new GainAbilityAllEffect(gainAbility, Duration.WhileOnBattlefield, filter).withForceQuotes(); effect.setDependedToType(DependencyType.AddingAbility); this.addAbility(new SimpleStaticAbility(effect)); } @@ -63,45 +60,3 @@ public final class JubilantSkybonder extends CardImpl { return new JubilantSkybonder(this); } } - -class JubilantSkybonderEffect extends CostModificationEffectImpl { - - JubilantSkybonderEffect() { - super(Duration.WhileOnBattlefield, Outcome.Benefit, CostModificationType.INCREASE_COST); - staticText = "Spells your opponents cast that target this creature cost {2} more to cast"; - } - - private JubilantSkybonderEffect(JubilantSkybonderEffect effect) { - super(effect); - } - - @Override - public boolean apply(Game game, Ability source, Ability abilityToModify) { - SpellAbility spellAbility = (SpellAbility) abilityToModify; - CardUtil.adjustCost(spellAbility, -2); - return true; - } - - @Override - public boolean applies(Ability abilityToModify, Ability source, Game game) { - if (!(abilityToModify instanceof SpellAbility) - || !game.getOpponents(source.getControllerId()).contains(abilityToModify.getControllerId())) { - return false; - } - return abilityToModify - .getModes() - .getSelectedModes() - .stream() - .map(abilityToModify.getModes()::get) - .map(Mode::getTargets) - .flatMap(Collection::stream) - .map(Target::getTargets) - .flatMap(Collection::stream) - .anyMatch(source.getSourceId()::equals); - } - - @Override - public JubilantSkybonderEffect copy() { - return new JubilantSkybonderEffect(this); - } -} diff --git a/Mage.Sets/src/mage/cards/p/PursuedWhale.java b/Mage.Sets/src/mage/cards/p/PursuedWhale.java index fd9ca15ab87..d26a8f02d8c 100644 --- a/Mage.Sets/src/mage/cards/p/PursuedWhale.java +++ b/Mage.Sets/src/mage/cards/p/PursuedWhale.java @@ -2,22 +2,18 @@ package mage.cards.p; import mage.MageInt; import mage.abilities.Ability; -import mage.abilities.Mode; -import mage.abilities.SpellAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.OneShotEffect; -import mage.abilities.effects.common.cost.CostModificationEffectImpl; +import mage.abilities.effects.common.cost.SpellsCostModificationThatTargetSourceEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.*; +import mage.filter.FilterCard; import mage.game.Game; import mage.game.permanent.token.PursuedWhaleToken; import mage.game.permanent.token.Token; -import mage.target.Target; -import mage.util.CardUtil; -import java.util.Collection; import java.util.UUID; /** @@ -36,7 +32,9 @@ public final class PursuedWhale extends CardImpl { this.addAbility(new EntersBattlefieldTriggeredAbility(new PursuedWhaleTokenEffect())); // Spells your opponents cast that target Pursued Whale cost {3} more to cast. - this.addAbility(new SimpleStaticAbility(new PursuedWhaleCostIncreaseEffect())); + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, + new SpellsCostModificationThatTargetSourceEffect(3, new FilterCard("Spells"), TargetController.OPPONENT)) + ); } private PursuedWhale(final PursuedWhale card) { @@ -76,45 +74,3 @@ class PursuedWhaleTokenEffect extends OneShotEffect { return true; } } - -class PursuedWhaleCostIncreaseEffect extends CostModificationEffectImpl { - - PursuedWhaleCostIncreaseEffect() { - super(Duration.WhileOnBattlefield, Outcome.Benefit, CostModificationType.INCREASE_COST); - staticText = "Spells your opponents cast that target {this} cost {3} more to cast"; - } - - private PursuedWhaleCostIncreaseEffect(PursuedWhaleCostIncreaseEffect effect) { - super(effect); - } - - @Override - public boolean apply(Game game, Ability source, Ability abilityToModify) { - SpellAbility spellAbility = (SpellAbility) abilityToModify; - CardUtil.adjustCost(spellAbility, -3); - return true; - } - - @Override - public boolean applies(Ability abilityToModify, Ability source, Game game) { - if (!(abilityToModify instanceof SpellAbility) - || !game.getOpponents(source.getControllerId()).contains(abilityToModify.getControllerId())) { - return false; - } - return abilityToModify - .getModes() - .getSelectedModes() - .stream() - .map(uuid -> abilityToModify.getModes().get(uuid)) - .map(Mode::getTargets) - .flatMap(Collection::stream) - .map(Target::getTargets) - .flatMap(Collection::stream) - .anyMatch(uuid -> uuid.equals(source.getSourceId())); - } - - @Override - public PursuedWhaleCostIncreaseEffect copy() { - return new PursuedWhaleCostIncreaseEffect(this); - } -} diff --git a/Mage.Sets/src/mage/cards/s/SphinxOfNewPrahv.java b/Mage.Sets/src/mage/cards/s/SphinxOfNewPrahv.java index 690a8c7f3b9..102695ce817 100644 --- a/Mage.Sets/src/mage/cards/s/SphinxOfNewPrahv.java +++ b/Mage.Sets/src/mage/cards/s/SphinxOfNewPrahv.java @@ -1,20 +1,17 @@ package mage.cards.s; import mage.MageInt; -import mage.abilities.Ability; -import mage.abilities.Mode; -import mage.abilities.SpellAbility; import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.effects.common.cost.CostModificationEffectImpl; +import mage.abilities.effects.common.cost.SpellsCostModificationThatTargetSourceEffect; import mage.abilities.keyword.FlyingAbility; import mage.abilities.keyword.VigilanceAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.*; -import mage.game.Game; -import mage.players.Player; -import mage.target.Target; -import mage.util.CardUtil; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.TargetController; +import mage.constants.Zone; +import mage.filter.FilterCard; import java.util.UUID; @@ -37,7 +34,9 @@ public final class SphinxOfNewPrahv extends CardImpl { this.addAbility(VigilanceAbility.getInstance()); // Spells your opponents cast that target Sphinx of New Prahv cost {2} more to cast. - this.addAbility(new SimpleStaticAbility(new SphinxOfNewPrahvCostIncreaseEffect())); + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, + new SpellsCostModificationThatTargetSourceEffect(2, new FilterCard("Spells"), TargetController.OPPONENT)) + ); } private SphinxOfNewPrahv(final SphinxOfNewPrahv card) { @@ -49,49 +48,3 @@ public final class SphinxOfNewPrahv extends CardImpl { return new SphinxOfNewPrahv(this); } } - -class SphinxOfNewPrahvCostIncreaseEffect extends CostModificationEffectImpl { - - SphinxOfNewPrahvCostIncreaseEffect() { - super(Duration.WhileOnBattlefield, Outcome.Benefit, CostModificationType.INCREASE_COST); - staticText = "Spells your opponents cast that target {this} cost {2} more to cast"; - } - - private SphinxOfNewPrahvCostIncreaseEffect(SphinxOfNewPrahvCostIncreaseEffect effect) { - super(effect); - } - - @Override - public boolean apply(Game game, Ability source, Ability abilityToModify) { - SpellAbility spellAbility = (SpellAbility) abilityToModify; - CardUtil.adjustCost(spellAbility, -2); - return true; - } - - @Override - public boolean applies(Ability abilityToModify, Ability source, Game game) { - Player controller = game.getPlayer(source.getControllerId()); - if (controller == null - || !(abilityToModify instanceof SpellAbility) - || !controller.hasOpponent(abilityToModify.getControllerId(), game)) { - return false; - } - for (UUID modeId : abilityToModify.getModes().getSelectedModes()) { - Mode mode = abilityToModify.getModes().get(modeId); - for (Target target : mode.getTargets()) { - for (UUID targetUUID : target.getTargets()) { - if (targetUUID.equals(source.getSourceId())) { - return true; - } - } - } - } - return false; - } - - @Override - public SphinxOfNewPrahvCostIncreaseEffect copy() { - return new SphinxOfNewPrahvCostIncreaseEffect(this); - } - -} diff --git a/Mage.Sets/src/mage/cards/s/SyrElenoraTheDiscerning.java b/Mage.Sets/src/mage/cards/s/SyrElenoraTheDiscerning.java index 0be67605193..558ccfb9096 100644 --- a/Mage.Sets/src/mage/cards/s/SyrElenoraTheDiscerning.java +++ b/Mage.Sets/src/mage/cards/s/SyrElenoraTheDiscerning.java @@ -1,23 +1,17 @@ package mage.cards.s; import mage.MageInt; -import mage.abilities.Ability; -import mage.abilities.Mode; -import mage.abilities.SpellAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.dynamicvalue.common.CardsInControllerHandCount; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.continuous.SetPowerSourceEffect; -import mage.abilities.effects.common.cost.CostModificationEffectImpl; +import mage.abilities.effects.common.cost.SpellsCostModificationThatTargetSourceEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.*; -import mage.game.Game; -import mage.target.Target; -import mage.util.CardUtil; +import mage.filter.FilterCard; -import java.util.Collection; import java.util.UUID; /** @@ -43,7 +37,9 @@ public final class SyrElenoraTheDiscerning extends CardImpl { this.addAbility(new EntersBattlefieldTriggeredAbility(new DrawCardSourceControllerEffect(1))); // Spells your opponents cast that target Syr Elenora cost {2} more to cast. - this.addAbility(new SimpleStaticAbility(new SyrElenoraTheDiscerningCostIncreaseEffect())); + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, + new SpellsCostModificationThatTargetSourceEffect(2, new FilterCard("Spells"), TargetController.OPPONENT)) + ); } private SyrElenoraTheDiscerning(final SyrElenoraTheDiscerning card) { @@ -55,46 +51,3 @@ public final class SyrElenoraTheDiscerning extends CardImpl { return new SyrElenoraTheDiscerning(this); } } - -class SyrElenoraTheDiscerningCostIncreaseEffect extends CostModificationEffectImpl { - - SyrElenoraTheDiscerningCostIncreaseEffect() { - super(Duration.WhileOnBattlefield, Outcome.Benefit, CostModificationType.INCREASE_COST); - staticText = "Spells your opponents cast that target {this} cost {2} more to cast"; - } - - private SyrElenoraTheDiscerningCostIncreaseEffect(SyrElenoraTheDiscerningCostIncreaseEffect effect) { - super(effect); - } - - @Override - public boolean apply(Game game, Ability source, Ability abilityToModify) { - SpellAbility spellAbility = (SpellAbility) abilityToModify; - CardUtil.adjustCost(spellAbility, -2); - return true; - } - - @Override - public boolean applies(Ability abilityToModify, Ability source, Game game) { - if (!(abilityToModify instanceof SpellAbility) - || !game.getOpponents(source.getControllerId()).contains(abilityToModify.getControllerId())) { - return false; - } - return abilityToModify - .getModes() - .getSelectedModes() - .stream() - .map(uuid -> abilityToModify.getModes().get(uuid)) - .map(Mode::getTargets) - .flatMap(Collection::stream) - .map(Target::getTargets) - .flatMap(Collection::stream) - .anyMatch(uuid -> uuid.equals(source.getSourceId())); - } - - @Override - public SyrElenoraTheDiscerningCostIncreaseEffect copy() { - return new SyrElenoraTheDiscerningCostIncreaseEffect(this); - } - -} diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/cost/modification/CostModificationTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/cost/modification/CostModificationTest.java index 40ffdc079f8..e7a6d7232de 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/cost/modification/CostModificationTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/cost/modification/CostModificationTest.java @@ -7,10 +7,7 @@ import org.junit.Test; import org.mage.test.serverside.base.CardTestPlayerBase; /** - * - * also tests cost reduction effects - * - * @author BetaSteward + * @author BetaSteward, JayDi85 */ public class CostModificationTest extends CardTestPlayerBase { @@ -71,7 +68,7 @@ public class CostModificationTest extends CardTestPlayerBase { /** * Test that cost reduction also works with mana source restriction Myr * Superion Spend only mana produced by creatures to cast Myr Superion - * + *
* Etherium Sculptor {1}{U} Artifact Creature - Vedalken Artificer 1/2
* Artifact spells you cast cost {1} less to cast.
*/
@@ -143,7 +140,7 @@ public class CostModificationTest extends CardTestPlayerBase {
}
/*
- * Reported bug: Grand Arbiter Augustin IV makes moth spells you cast and your opponent cast {1} more. Should only affect opponent's spells costs.
+ * Reported bug: Grand Arbiter Augustin IV makes moth spells you cast and your opponent cast {1} more. Should only affect opponent's spells costs.
*/
@Test
public void testArbiterIncreasingCostBothPlayers() {
@@ -244,6 +241,106 @@ public class CostModificationTest extends CardTestPlayerBase {
assertCounterCount(playerA, "Animar, Soul of Elements", CounterType.P1P1, 2);
assertTappedCount("Plains", true, 3);
+ }
+ @Test
+ public void test_ThatTargetSourceEffect_AccursedWitch_CanPlayWithReduction() {
+ // creature 4/2
+ // Spells your opponents cast that target Accursed Witch cost {1} less to cast.
+ addCard(Zone.BATTLEFIELD, playerB, "Accursed Witch");
+ //
+ // {1}{R} SORCERY
+ // Grapeshot deals 1 damage to any target.
+ addCard(Zone.HAND, playerA, "Grapeshot");
+ addCard(Zone.HAND, playerA, "Mountain", 1); // play to add mana
+
+ checkPlayableAbility("0 mana, can't", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Grapeshot", false);
+
+ // add 1 mana, can cast by target
+ playLand(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Mountain");
+ checkPlayableAbility("1 mana, can play", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Grapeshot", true);
+
+ // cast with target
+ castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Grapeshot", "Accursed Witch");
+
+ setStrictChooseMode(true);
+ setStopAt(1, PhaseStep.END_TURN);
+ execute();
+ assertAllCommandsUsed();
+
+ assertGraveyardCount(playerA, "Grapeshot", 1);
+ }
+
+ @Test
+ public void test_ThatTargetSourceEffect_AccursedWitch_CantPlayOnProtection() {
+ // creature 4/2
+ // Spells your opponents cast that target Accursed Witch cost {1} less to cast.
+ addCard(Zone.BATTLEFIELD, playerB, "Accursed Witch");
+ //
+ // {1}{R} SORCERY
+ // Grapeshot deals 1 damage to any target.
+ addCard(Zone.HAND, playerA, "Grapeshot");
+ addCard(Zone.BATTLEFIELD, playerA, "Mountain", 1);
+ //
+ // Artifact — Equipment
+ // Equip {2}
+ // Equipped creature gets +2/+2 and has protection from red and from white.
+ addCard(Zone.BATTLEFIELD, playerB, "Sword of War and Peace");
+ addCard(Zone.BATTLEFIELD, playerB, "Plains", 2);
+
+ // 1 mana, can cast by target
+ checkPlayableAbility("1 mana, can play", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Grapeshot", true);
+
+ // add protection from red
+ activateAbility(2, PhaseStep.PRECOMBAT_MAIN, playerB, "Equip {2}", "Accursed Witch");
+
+ // can't cast cause can't target to red
+ checkPlayableAbility("can't cast cause protection", 3, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Grapeshot", false);
+
+ setStrictChooseMode(true);
+ setStopAt(3, PhaseStep.END_TURN);
+ execute();
+ assertAllCommandsUsed();
+ }
+
+ @Test
+ public void test_ThatTargetSourceEffect_BorealElemental() {
+ // use case: cost increase for getPlayable works only for no other targets available
+ // so if you can targets another target then allows to cast (don't apply cost increase)
+
+ // creature 3/4
+ // Spells your opponents cast that target Boreal Elemental cost {2} more to cast.
+ addCard(Zone.BATTLEFIELD, playerB, "Boreal Elemental");
+ //
+ // {R} instant
+ // Engulfing Flames deals 1 damage to target creature. It can't be regenerated this turn.
+ addCard(Zone.HAND, playerA, "Engulfing Flames");
+ addCard(Zone.BATTLEFIELD, playerA, "Mountain", 1);
+ //
+ addCard(Zone.HAND, playerA, "Grizzly Bears"); // {1}{G}
+ addCard(Zone.HAND, playerA, "Forest", 1);
+ addCard(Zone.BATTLEFIELD, playerA, "Forest", 1);
+
+ // no second target, so must cost increase
+ checkPlayableAbility("one target, can't play", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Engulfing Flames", false);
+
+ // prepare second target
+ playLand(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Forest");
+ activateManaAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}: Add {G}", 2);
+ castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Grizzly Bears");
+ waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
+ checkPlayableAbility("two targets, can play", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Engulfing Flames", true);
+
+ // try to cast (only one target possible to targets/play)
+ castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Engulfing Flames");
+ //addTarget(playerA, "Boreal Elemental"); // you can't target Boreal Elemental cause it will increase cost
+ addTarget(playerA, "Grizzly Bears");
+
+ setStrictChooseMode(true);
+ setStopAt(1, PhaseStep.END_TURN);
+ execute();
+ assertAllCommandsUsed();
+
+ assertGraveyardCount(playerA, "Engulfing Flames", 1);
}
}
diff --git a/Mage.Tests/src/test/java/org/mage/test/player/TestPlayer.java b/Mage.Tests/src/test/java/org/mage/test/player/TestPlayer.java
index 7e424803a8c..f8d33b3ffbb 100644
--- a/Mage.Tests/src/test/java/org/mage/test/player/TestPlayer.java
+++ b/Mage.Tests/src/test/java/org/mage/test/player/TestPlayer.java
@@ -1181,6 +1181,8 @@ public class TestPlayer implements Player {
}
if (mustHave && !founded) {
+ printStart("Available mana for " + computerPlayer.getName());
+ printMana(game, computerPlayer.getManaAvailable(game));
printStart(action.getActionName());
printAbilities(game, computerPlayer.getPlayable(game, true));
printEnd();
@@ -1188,6 +1190,8 @@ public class TestPlayer implements Player {
}
if (!mustHave && founded) {
+ printStart("Available mana for " + computerPlayer.getName());
+ printMana(game, computerPlayer.getManaAvailable(game));
printStart(action.getActionName());
printAbilities(game, computerPlayer.getPlayable(game, true));
printEnd();
diff --git a/Mage/src/main/java/mage/abilities/AbilityImpl.java b/Mage/src/main/java/mage/abilities/AbilityImpl.java
index 5f1512e321f..fe26af024e6 100644
--- a/Mage/src/main/java/mage/abilities/AbilityImpl.java
+++ b/Mage/src/main/java/mage/abilities/AbilityImpl.java
@@ -769,7 +769,7 @@ public abstract class AbilityImpl implements Ability {
if (ruleStart.length() > 1) {
String end = ruleStart.substring(ruleStart.length() - 2).trim();
if (end.isEmpty() || end.equals(":") || end.equals(".")) {
- rule = ruleStart + Character.toUpperCase(text.charAt(0)) + text.substring(1);
+ rule = ruleStart + CardUtil.getTextWithFirstCharUpperCase(text);
} else {
rule = ruleStart + text;
}
diff --git a/Mage/src/main/java/mage/abilities/effects/Effects.java b/Mage/src/main/java/mage/abilities/effects/Effects.java
index 38c798b30fd..42698bba846 100644
--- a/Mage/src/main/java/mage/abilities/effects/Effects.java
+++ b/Mage/src/main/java/mage/abilities/effects/Effects.java
@@ -4,6 +4,7 @@ import mage.abilities.Ability;
import mage.abilities.Mode;
import mage.constants.Outcome;
import mage.target.targetpointer.TargetPointer;
+import mage.util.CardUtil;
import java.util.ArrayList;
@@ -31,7 +32,7 @@ public class Effects extends ArrayList