Cost reduction effects - refactor, removed redundant custom effects, added card hints;

This commit is contained in:
Oleg Agafonov 2020-06-29 12:52:14 +04:00
parent e4ebf50d42
commit cf3feff76a
35 changed files with 506 additions and 643 deletions

View file

@ -1,31 +1,25 @@
package mage.cards.a;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.SpellAbility;
import mage.abilities.common.DiesTriggeredAbility;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.dynamicvalue.DynamicValue;
import mage.abilities.dynamicvalue.common.AttackingCreatureCount;
import mage.abilities.effects.common.CreateTokenEffect;
import mage.abilities.effects.common.cost.CostModificationEffectImpl;
import mage.constants.SubType;
import mage.abilities.effects.common.cost.SpellCostReductionForEachSourceEffect;
import mage.abilities.hint.ValueHint;
import mage.abilities.keyword.FlashAbility;
import mage.abilities.keyword.TrampleAbility;
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.common.FilterCreaturePermanent;
import mage.filter.predicate.permanent.AttackingPredicate;
import mage.game.Game;
import mage.game.permanent.token.StoneTrapIdolToken;
import mage.util.CardUtil;
import java.util.UUID;
/**
*
* @author TheElk801
*/
public final class AncientStoneIdol extends CardImpl {
@ -41,7 +35,10 @@ public final class AncientStoneIdol extends CardImpl {
this.addAbility(FlashAbility.getInstance());
// This spell costs {1} less to cast for each attacking creature.
this.addAbility(new SimpleStaticAbility(Zone.ALL, new AncientStoneIdolCostReductionEffect()));
DynamicValue xValue = new AttackingCreatureCount();
this.addAbility(new SimpleStaticAbility(Zone.ALL, new SpellCostReductionForEachSourceEffect(1, xValue))
.addHint(new ValueHint("Attacking creatures", xValue))
);
// Trample
this.addAbility(TrampleAbility.getInstance());
@ -59,41 +56,3 @@ public final class AncientStoneIdol extends CardImpl {
return new AncientStoneIdol(this);
}
}
class AncientStoneIdolCostReductionEffect extends CostModificationEffectImpl {
private static final FilterCreaturePermanent filter = new FilterCreaturePermanent();
static {
filter.add(AttackingPredicate.instance);
}
public AncientStoneIdolCostReductionEffect() {
super(Duration.WhileOnStack, Outcome.Benefit, CostModificationType.REDUCE_COST);
staticText = "This spell costs {1} less to cast for each attacking creature";
}
protected AncientStoneIdolCostReductionEffect(AncientStoneIdolCostReductionEffect effect) {
super(effect);
}
@Override
public boolean apply(Game game, Ability source, Ability abilityToModify) {
int reductionAmount = game.getBattlefield().count(filter, source.getSourceId(), source.getControllerId(), game);
CardUtil.reduceCost(abilityToModify, reductionAmount);
return true;
}
@Override
public boolean applies(Ability abilityToModify, Ability source, Game game) {
if ((abilityToModify instanceof SpellAbility) && abilityToModify.getSourceId().equals(source.getSourceId())) {
return game.getCard(abilityToModify.getSourceId()) != null;
}
return false;
}
@Override
public AncientStoneIdolCostReductionEffect copy() {
return new AncientStoneIdolCostReductionEffect(this);
}
}

View file

@ -4,8 +4,9 @@ import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.dynamicvalue.common.OpponentsCount;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.cost.SpellCostReductionSourceForOpponentsEffect;
import mage.abilities.effects.common.cost.SpellCostReductionForEachSourceEffect;
import mage.abilities.keyword.TrampleAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
@ -35,7 +36,8 @@ public final class AvatarOfGrowth extends CardImpl {
this.toughness = new MageInt(4);
// This spell costs {1} less to cast for each opponent you have.
this.addAbility(new SimpleStaticAbility(Zone.ALL, new SpellCostReductionSourceForOpponentsEffect("This spell costs {1} less to cast for each opponent you have")));
this.addAbility(new SimpleStaticAbility(Zone.ALL, new SpellCostReductionForEachSourceEffect(1, OpponentsCount.instance)
.setText("This spell costs {1} less to cast for each opponent you have")));
// Trample
this.addAbility(TrampleAbility.getInstance());

View file

@ -1,4 +1,3 @@
package mage.cards.b;
import mage.MageInt;
@ -8,7 +7,7 @@ import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.dynamicvalue.DynamicValue;
import mage.abilities.dynamicvalue.common.CardsInControllerGraveyardCount;
import mage.abilities.effects.common.DrawCardSourceControllerEffect;
import mage.abilities.effects.common.cost.SourceCostReductionForEachCardInGraveyardEffect;
import mage.abilities.effects.common.cost.SpellCostReductionForEachSourceEffect;
import mage.abilities.effects.common.discard.DiscardHandControllerEffect;
import mage.abilities.hint.ValueHint;
import mage.abilities.keyword.ProwessAbility;
@ -26,27 +25,25 @@ import java.util.UUID;
*/
public final class BedlamReveler extends CardImpl {
private static final DynamicValue cardsCount = new CardsInControllerGraveyardCount(StaticFilters.FILTER_CARD_INSTANT_OR_SORCERY);
public BedlamReveler(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{6}{R}{R}");
this.subtype.add(SubType.DEVIL, SubType.HORROR);
this.power = new MageInt(3);
this.toughness = new MageInt(4);
// Bedlam Reveler costs {1} less to cast for each instant or sorcery card in your graveyard.
this.addAbility(new SimpleStaticAbility(
Zone.ALL, new SourceCostReductionForEachCardInGraveyardEffect(StaticFilters.FILTER_CARD_INSTANT_AND_SORCERY)
).addHint(new ValueHint("Instant and sorcery cards in your graveyard", cardsCount)));
// This spell costs {1} less to cast for each instant and sorcery card in your graveyard.
DynamicValue xValue = new CardsInControllerGraveyardCount(StaticFilters.FILTER_CARD_INSTANT_OR_SORCERY);
Ability ability = new SimpleStaticAbility(Zone.ALL, new SpellCostReductionForEachSourceEffect(1, xValue));
ability.setRuleAtTheTop(true);
ability.addHint(new ValueHint("Instant or sourcery card in your graveyard", xValue));
this.addAbility(ability);
// Prowess
this.addAbility(new ProwessAbility());
// When Bedlam Reveler enters the battlefield, discard your hand, then draw three cards.
Ability ability = new EntersBattlefieldTriggeredAbility(
new DiscardHandControllerEffect().setText("discard your hand,")
);
ability.addEffect(new DrawCardSourceControllerEffect(3).setText("then draw three cards"));
ability = new EntersBattlefieldTriggeredAbility(new DiscardHandControllerEffect());
ability.addEffect(new DrawCardSourceControllerEffect(3).concatBy(", then"));
this.addAbility(ability);
}

View file

@ -1,18 +1,17 @@
package mage.cards.b;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.dynamicvalue.DynamicValue;
import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount;
import mage.abilities.effects.common.cost.CostModificationEffectImpl;
import mage.abilities.effects.common.cost.SpellCostReductionForEachSourceEffect;
import mage.abilities.hint.ValueHint;
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.filter.common.FilterControlledPermanent;
import mage.game.Game;
import mage.util.CardUtil;
import java.util.UUID;
@ -21,8 +20,13 @@ import java.util.UUID;
*/
public final class BrineGiant extends CardImpl {
private static final DynamicValue xValue
= new PermanentsOnBattlefieldCount(BrineGiantCostReductionEffect.filter);
static final FilterControlledPermanent filter = new FilterControlledPermanent("enchantment you control");
static {
filter.add(CardType.ENCHANTMENT.getPredicate());
}
private static final DynamicValue xValue = new PermanentsOnBattlefieldCount(filter);
public BrineGiant(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{6}{U}");
@ -33,7 +37,7 @@ public final class BrineGiant extends CardImpl {
// This spell costs {1} less to cast for each enchantment you control.
this.addAbility(new SimpleStaticAbility(
Zone.ALL, new BrineGiantCostReductionEffect()
Zone.ALL, new SpellCostReductionForEachSourceEffect(1, xValue)
).addHint(new ValueHint("Enchantments you control", xValue)));
}
@ -45,39 +49,4 @@ public final class BrineGiant extends CardImpl {
public BrineGiant copy() {
return new BrineGiant(this);
}
}
class BrineGiantCostReductionEffect extends CostModificationEffectImpl {
static final FilterControlledPermanent filter = new FilterControlledPermanent();
static {
filter.add(CardType.ENCHANTMENT.getPredicate());
}
BrineGiantCostReductionEffect() {
super(Duration.WhileOnStack, Outcome.Benefit, CostModificationType.REDUCE_COST);
staticText = "This spell costs {1} less to cast for each enchantment you control";
}
private BrineGiantCostReductionEffect(final BrineGiantCostReductionEffect effect) {
super(effect);
}
@Override
public boolean apply(Game game, Ability source, Ability abilityToModify) {
int count = game.getBattlefield().getAllActivePermanents(filter, source.getControllerId(), game).size();
CardUtil.reduceCost(abilityToModify, count);
return true;
}
@Override
public boolean applies(Ability abilityToModify, Ability source, Game game) {
return abilityToModify.getSourceId().equals(source.getSourceId());
}
@Override
public BrineGiantCostReductionEffect copy() {
return new BrineGiantCostReductionEffect(this);
}
}

View file

@ -1,10 +1,11 @@
package mage.cards.c;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.dynamicvalue.DynamicValue;
import mage.abilities.dynamicvalue.common.CardsInControllerGraveyardCount;
import mage.abilities.effects.common.cost.SourceCostReductionForEachCardInGraveyardEffect;
import mage.abilities.effects.common.cost.SpellCostReductionForEachSourceEffect;
import mage.abilities.hint.ValueHint;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
@ -12,7 +13,6 @@ import mage.constants.CardType;
import mage.constants.SubType;
import mage.constants.Zone;
import mage.filter.StaticFilters;
import mage.filter.common.FilterInstantOrSorceryCard;
import java.util.UUID;
@ -21,8 +21,6 @@ import java.util.UUID;
*/
public final class CrypticSerpent extends CardImpl {
private static final DynamicValue cardsCount = new CardsInControllerGraveyardCount(StaticFilters.FILTER_CARD_INSTANT_OR_SORCERY);
public CrypticSerpent(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{5}{U}{U}");
@ -31,8 +29,11 @@ public final class CrypticSerpent extends CardImpl {
this.toughness = new MageInt(5);
// Cryptic Serpent costs {1} less to cast for each instant and sorcery card in your graveyard.
this.addAbility(new SimpleStaticAbility(Zone.ALL, new SourceCostReductionForEachCardInGraveyardEffect(new FilterInstantOrSorceryCard()))
.addHint(new ValueHint("Instant and sorcery card in your graveyard", cardsCount)));
DynamicValue xValue = new CardsInControllerGraveyardCount(StaticFilters.FILTER_CARD_INSTANT_AND_SORCERY);
Ability ability = new SimpleStaticAbility(Zone.ALL, new SpellCostReductionForEachSourceEffect(1, xValue));
ability.setRuleAtTheTop(true);
ability.addHint(new ValueHint("Instant and sorcery card in your graveyard", xValue));
this.addAbility(ability);
}
public CrypticSerpent(final CrypticSerpent card) {

View file

@ -1,7 +1,5 @@
package mage.cards.d;
import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.effects.common.AttachEffect;
@ -10,21 +8,22 @@ import mage.abilities.keyword.EnchantAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.constants.Outcome;
import mage.constants.SubType;
import mage.constants.Zone;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.target.TargetPermanent;
import java.util.UUID;
/**
*
* @author maxlebedev
*/
public final class DreamLeash extends CardImpl {
public DreamLeash(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{3}{U}{U}");
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{3}{U}{U}");
this.subtype.add(SubType.AURA);
// Enchant permanent
@ -55,7 +54,7 @@ class DreamLeashTarget extends TargetPermanent {
@Override
public boolean canTarget(UUID controllerId, UUID id, Ability source, Game game) {
if(super.canTarget(controllerId, id, source, game)){
if (super.canTarget(controllerId, id, source, game)) {
Permanent permanent = game.getPermanent(id);
return permanent.isTapped();
}

View file

@ -1,13 +1,15 @@
package mage.cards.e;
import mage.abilities.Ability;
import mage.abilities.SpellAbility;
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.dynamicvalue.DynamicValue;
import mage.abilities.dynamicvalue.common.AttackingCreatureCount;
import mage.abilities.effects.common.AttachEffect;
import mage.abilities.effects.common.continuous.BoostEquippedEffect;
import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect;
import mage.abilities.effects.common.cost.CostModificationEffectImpl;
import mage.abilities.effects.common.cost.SpellCostReductionForEachSourceEffect;
import mage.abilities.hint.ValueHint;
import mage.abilities.keyword.DoubleStrikeAbility;
import mage.abilities.keyword.EquipAbility;
import mage.abilities.keyword.FlashAbility;
@ -15,12 +17,8 @@ import mage.abilities.keyword.TrampleAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.*;
import mage.filter.FilterPermanent;
import mage.filter.common.FilterControlledCreaturePermanent;
import mage.filter.predicate.permanent.AttackingPredicate;
import mage.game.Game;
import mage.filter.StaticFilters;
import mage.target.common.TargetControlledCreaturePermanent;
import mage.util.CardUtil;
import java.util.UUID;
@ -39,7 +37,10 @@ public final class Embercleave extends CardImpl {
this.addAbility(FlashAbility.getInstance());
// This spell costs {1} less to cast for each attacking creature you control.
this.addAbility(new SimpleStaticAbility(Zone.ALL, new EmbercleaveCostReductionEffect()));
DynamicValue xValue = new AttackingCreatureCount(StaticFilters.FILTER_PERMANENT_CREATURE_CONTROLLED);
this.addAbility(new SimpleStaticAbility(Zone.ALL,
new SpellCostReductionForEachSourceEffect(1, xValue)
).addHint(new ValueHint("Attacking creature you control", xValue)));
// When Embercleave enters the battlefield, attach it to target creature you control.
Ability ability = new EntersBattlefieldTriggeredAbility(new AttachEffect(
@ -71,41 +72,3 @@ public final class Embercleave extends CardImpl {
return new Embercleave(this);
}
}
class EmbercleaveCostReductionEffect extends CostModificationEffectImpl {
private static final FilterPermanent filter = new FilterControlledCreaturePermanent();
static {
filter.add(AttackingPredicate.instance);
}
EmbercleaveCostReductionEffect() {
super(Duration.WhileOnStack, Outcome.Benefit, CostModificationType.REDUCE_COST);
staticText = "This spell costs {1} less to cast for each attacking creature you control";
}
private EmbercleaveCostReductionEffect(EmbercleaveCostReductionEffect effect) {
super(effect);
}
@Override
public boolean apply(Game game, Ability source, Ability abilityToModify) {
int reductionAmount = game.getBattlefield().count(filter, source.getSourceId(), source.getControllerId(), game);
CardUtil.reduceCost(abilityToModify, reductionAmount);
return true;
}
@Override
public boolean applies(Ability abilityToModify, Ability source, Game game) {
if ((abilityToModify instanceof SpellAbility) && abilityToModify.getSourceId().equals(source.getSourceId())) {
return game.getCard(abilityToModify.getSourceId()) != null;
}
return false;
}
@Override
public EmbercleaveCostReductionEffect copy() {
return new EmbercleaveCostReductionEffect(this);
}
}

View file

@ -2,21 +2,21 @@ package mage.cards.e;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.SpellAbility;
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.dynamicvalue.common.ArtifactYouControlCount;
import mage.abilities.effects.AsThoughEffectImpl;
import mage.abilities.effects.common.PutTopCardOfLibraryIntoGraveControllerEffect;
import mage.abilities.effects.common.cost.CostModificationEffectImpl;
import mage.abilities.effects.common.cost.SpellCostReductionForEachSourceEffect;
import mage.abilities.hint.common.ArtifactYouControlHint;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.*;
import mage.filter.StaticFilters;
import mage.game.Game;
import mage.target.common.TargetCardInYourGraveyard;
import mage.util.CardUtil;
import java.util.UUID;
@ -35,7 +35,9 @@ public final class EmryLurkerOfTheLoch extends CardImpl {
this.toughness = new MageInt(2);
// This spell costs {1} less to cast for each artifact you control.
this.addAbility(new SimpleStaticAbility(Zone.ALL, new EmryLurkerOfTheLochCostReductionEffect()));
this.addAbility(new SimpleStaticAbility(Zone.ALL,
new SpellCostReductionForEachSourceEffect(1, ArtifactYouControlCount.instance)
).addHint(ArtifactYouControlHint.instance));
// When Emry, Lurker of the Loch enters the battlefield, put the top four cards of your library into your graveyard.
this.addAbility(new EntersBattlefieldTriggeredAbility(
@ -58,40 +60,6 @@ public final class EmryLurkerOfTheLoch extends CardImpl {
}
}
class EmryLurkerOfTheLochCostReductionEffect extends CostModificationEffectImpl {
EmryLurkerOfTheLochCostReductionEffect() {
super(Duration.WhileOnStack, Outcome.Benefit, CostModificationType.REDUCE_COST);
staticText = "This spell costs {1} less to cast for each artifact you control";
}
private EmryLurkerOfTheLochCostReductionEffect(final EmryLurkerOfTheLochCostReductionEffect effect) {
super(effect);
}
@Override
public boolean apply(Game game, Ability source, Ability abilityToModify) {
int reductionAmount = game.getBattlefield().count(
StaticFilters.FILTER_CONTROLLED_PERMANENT_ARTIFACT,
source.getSourceId(), source.getControllerId(), game
);
CardUtil.reduceCost(abilityToModify, reductionAmount);
return true;
}
@Override
public boolean applies(Ability abilityToModify, Ability source, Game game) {
return abilityToModify instanceof SpellAbility
&& abilityToModify.getSourceId().equals(source.getSourceId())
&& game.getCard(abilityToModify.getSourceId()) != null;
}
@Override
public EmryLurkerOfTheLochCostReductionEffect copy() {
return new EmryLurkerOfTheLochCostReductionEffect(this);
}
}
class EmryLurkerOfTheLochPlayEffect extends AsThoughEffectImpl {
EmryLurkerOfTheLochPlayEffect() {

View file

@ -1,28 +1,26 @@
package mage.cards.f;
import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.dynamicvalue.common.AttackingFilterCreatureCount;
import mage.abilities.dynamicvalue.common.AttackingCreatureCount;
import mage.abilities.effects.OneShotEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Outcome;
import mage.constants.TargetController;
import mage.filter.common.FilterCreaturePermanent;
import mage.filter.StaticFilters;
import mage.game.Game;
import mage.players.Player;
import mage.target.common.TargetOpponent;
import java.util.UUID;
/**
*
* @author LevelX2
*/
public final class FoulTongueShriek extends CardImpl {
public FoulTongueShriek(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{B}");
super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{B}");
// Target opponent loses 1 life for each attacking creature you control. You gain that much life.
this.getSpellAbility().addEffect(new FoulTongueShriekEffect());
@ -41,12 +39,7 @@ public final class FoulTongueShriek extends CardImpl {
}
class FoulTongueShriekEffect extends OneShotEffect {
private static final FilterCreaturePermanent filter = new FilterCreaturePermanent();
static {
filter.add(TargetController.YOU.getControllerPredicate());
}
public FoulTongueShriekEffect() {
super(Outcome.Benefit);
this.staticText = "Target opponent loses 1 life for each attacking creature you control. You gain that much life";
@ -66,7 +59,7 @@ class FoulTongueShriekEffect extends OneShotEffect {
Player controller = game.getPlayer(source.getControllerId());
Player targetOpponent = game.getPlayer(getTargetPointer().getFirst(game, source));
if (controller != null && targetOpponent != null) {
int amount = new AttackingFilterCreatureCount(filter).calculate(game, source, this);
int amount = new AttackingCreatureCount(StaticFilters.FILTER_PERMANENT_CREATURES_CONTROLLED).calculate(game, source, this);
if (amount > 0) {
targetOpponent.loseLife(amount, game, false);
controller.gainLife(amount, game, source);

View file

@ -5,9 +5,11 @@ import mage.abilities.Ability;
import mage.abilities.common.EntersBattlefieldAllTriggeredAbility;
import mage.abilities.common.SimpleEvasionAbility;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.dynamicvalue.common.GateYouControlCount;
import mage.abilities.effects.common.PutOnLibrarySourceEffect;
import mage.abilities.effects.common.combat.CantBeBlockedByCreaturesSourceEffect;
import mage.abilities.effects.common.cost.CostModificationEffectImpl;
import mage.abilities.effects.common.cost.SpellCostReductionForEachSourceEffect;
import mage.abilities.hint.common.GateYouControlHint;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
@ -39,8 +41,10 @@ public final class GateColossus extends CardImpl {
this.toughness = new MageInt(8);
// This spell costs {1} less to cast for each Gate you control.
this.addAbility(new SimpleStaticAbility(Zone.ALL, new GateColossusCostReductionEffect())
.addHint(GateYouControlHint.instance));
this.addAbility(new SimpleStaticAbility(Zone.ALL,
new SpellCostReductionForEachSourceEffect(1, GateYouControlCount.instance))
.addHint(GateYouControlHint.instance)
);
// Gate Colossus can't be blocked by creatures with power 2 or less.
this.addAbility(new SimpleEvasionAbility(new CantBeBlockedByCreaturesSourceEffect(filter, Duration.WhileOnBattlefield)));

View file

@ -29,7 +29,7 @@ public final class GatekeeperGargoyle extends CardImpl {
// Flying
this.addAbility(FlyingAbility.getInstance());
// Gargoyle Guardian enters the battlefield with a +1/+1 counter on it for each Gate you control.
// Gatekeeper Gargoyle enters the battlefield with a +1/+1 counter on it for each Gate you control.
this.addAbility(new EntersBattlefieldAbility(
new AddCountersSourceEffect(
CounterType.P1P1.createInstance(),

View file

@ -1,18 +1,19 @@
package mage.cards.g;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.dynamicvalue.common.ArtifactYouControlCount;
import mage.abilities.effects.common.combat.CantBeBlockedSourceEffect;
import mage.abilities.effects.common.cost.CostModificationEffectImpl;
import mage.abilities.effects.common.cost.SpellCostReductionForEachSourceEffect;
import mage.abilities.hint.common.ArtifactYouControlHint;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.*;
import mage.filter.common.FilterControlledPermanent;
import mage.game.Game;
import mage.util.CardUtil;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.SubType;
import mage.constants.Zone;
import java.util.UUID;
@ -28,7 +29,9 @@ public final class GearseekerSerpent extends CardImpl {
this.toughness = new MageInt(6);
// Gearseeker Serpent costs {1} less to cast for each artifact you control
this.addAbility(new SimpleStaticAbility(Zone.ALL, new GearseekerSerpentCostReductionEffect()));
this.addAbility(new SimpleStaticAbility(Zone.ALL,
new SpellCostReductionForEachSourceEffect(1, ArtifactYouControlCount.instance)
).addHint(ArtifactYouControlHint.instance));
// 5U: Gearseeker Serpent can't be blocked this turn.
this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD,
@ -45,38 +48,3 @@ public final class GearseekerSerpent extends CardImpl {
return new GearseekerSerpent(this);
}
}
class GearseekerSerpentCostReductionEffect extends CostModificationEffectImpl {
private static final FilterControlledPermanent filter = new FilterControlledPermanent();
static {
filter.add(CardType.ARTIFACT.getPredicate());
}
public GearseekerSerpentCostReductionEffect() {
super(Duration.WhileOnStack, Outcome.Benefit, CostModificationType.REDUCE_COST);
staticText = "This spell costs {1} less to cast for each artifact you control";
}
protected GearseekerSerpentCostReductionEffect(final GearseekerSerpentCostReductionEffect effect) {
super(effect);
}
@Override
public boolean apply(Game game, Ability source, Ability abilityToModify) {
int count = game.getBattlefield().getAllActivePermanents(filter, source.getControllerId(), game).size();
CardUtil.reduceCost(abilityToModify, count);
return true;
}
@Override
public boolean applies(Ability abilityToModify, Ability source, Game game) {
return abilityToModify.getSourceId().equals(source.getSourceId());
}
@Override
public GearseekerSerpentCostReductionEffect copy() {
return new GearseekerSerpentCostReductionEffect(this);
}
}

View file

@ -1,9 +1,12 @@
package mage.cards.g;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.effects.common.cost.SourceCostReductionForEachCardInGraveyardEffect;
import mage.abilities.dynamicvalue.DynamicValue;
import mage.abilities.dynamicvalue.common.CardsInControllerGraveyardCount;
import mage.abilities.effects.common.cost.SpellCostReductionForEachSourceEffect;
import mage.abilities.hint.ValueHint;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
@ -11,8 +14,9 @@ import mage.constants.SubType;
import mage.constants.Zone;
import mage.filter.StaticFilters;
import java.util.UUID;
/**
*
* @author North
*/
public final class Ghoultree extends CardImpl {
@ -26,7 +30,11 @@ public final class Ghoultree extends CardImpl {
this.toughness = new MageInt(10);
// Ghoultree costs {1} less to cast for each creature card in your graveyard.
this.addAbility(new SimpleStaticAbility(Zone.ALL, new SourceCostReductionForEachCardInGraveyardEffect(StaticFilters.FILTER_CARD_CREATURE)));
DynamicValue xValue = new CardsInControllerGraveyardCount(StaticFilters.FILTER_CARD_CREATURE);
Ability ability = new SimpleStaticAbility(Zone.ALL, new SpellCostReductionForEachSourceEffect(1, xValue));
ability.setRuleAtTheTop(true);
ability.addHint(new ValueHint("Creature card in your graveyard", xValue));
this.addAbility(ability);
}
public Ghoultree(final Ghoultree card) {

View file

@ -29,10 +29,7 @@ public final class GlaiveOfTheGuildpact extends CardImpl {
this.subtype.add(SubType.EQUIPMENT);
// Equipped creature gets +1/+0 for each Gate you control and has vigilance and menace.
Ability ability = new SimpleStaticAbility(new BoostEquippedEffect(
GateYouControlCount.instance,
StaticValue.get(0)
).setText("Equipped creature gets +1/+0 for each Gate you control"));
Ability ability = new SimpleStaticAbility(new BoostEquippedEffect(GateYouControlCount.instance, StaticValue.get(0)));
ability.addEffect(new GainAbilityAttachedEffect(
VigilanceAbility.getInstance(), AttachmentType.EQUIPMENT
).setText("and has vigilance"));

View file

@ -13,7 +13,7 @@ import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.Zone;
import mage.filter.common.FilterControlledCreaturePermanent;
import mage.filter.StaticFilters;
import java.util.UUID;
@ -25,13 +25,14 @@ public final class HoldTheGates extends CardImpl {
public HoldTheGates(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{W}");
// Creatures you control get +0/+1 for each Gate you control and have vigilance.
Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD,
new BoostControlledEffect(StaticValue.get(0), GateYouControlCount.instance, Duration.WhileOnBattlefield)
.setText("Creatures you control get +0/+1 for each Gate you control "));
ability.addEffect(new GainAbilityControlledEffect(VigilanceAbility.getInstance(), Duration.WhileOnBattlefield, new FilterControlledCreaturePermanent("Creatures"))
.setText("and have vigilance"));
);
ability.addEffect(
new GainAbilityControlledEffect(VigilanceAbility.getInstance(), Duration.WhileOnBattlefield, StaticFilters.FILTER_PERMANENT_CREATURES_CONTROLLED)
.setText("and have vigilance")
);
ability.addHint(GateYouControlHint.instance);
this.addAbility(ability);
}

View file

@ -1,48 +1,52 @@
package mage.cards.k;
import java.util.Iterator;
import java.util.UUID;
import mage.MageInt;
import mage.ObjectColor;
import mage.abilities.Ability;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.costs.mana.ManaCost;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.costs.mana.ManaCosts;
import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.dynamicvalue.DynamicValue;
import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount;
import mage.abilities.effects.common.cost.SpellCostReductionForEachSourceEffect;
import mage.abilities.hint.ValueHint;
import mage.abilities.keyword.TrampleAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.constants.Outcome;
import mage.constants.Zone;
import mage.filter.common.FilterControlledCreaturePermanent;
import mage.filter.predicate.mageobject.ColorPredicate;
import mage.game.Game;
import java.util.UUID;
/**
*
* @author maurer.it_at_gmail.com
*/
public final class KhalniHydra extends CardImpl {
private static final FilterControlledCreaturePermanent filter;
private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("green creature you control");
static {
filter = new FilterControlledCreaturePermanent();
filter.add(new ColorPredicate(ObjectColor.GREEN));
}
public KhalniHydra(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{G}{G}{G}{G}{G}{G}{G}{G}");
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{G}{G}{G}{G}{G}{G}{G}{G}");
this.subtype.add(SubType.HYDRA);
this.power = new MageInt(8);
this.toughness = new MageInt(8);
// This spell costs {G} less to cast for each green creature you control.
this.addAbility(new SimpleStaticAbility(Zone.ALL, new KhalniHydraCostReductionEffect()));
ManaCosts<ManaCost> manaReduce = new ManaCostsImpl<>("{G}");
DynamicValue xValue = new PermanentsOnBattlefieldCount(filter);
this.addAbility(new SimpleStaticAbility(Zone.ALL,
new SpellCostReductionForEachSourceEffect(manaReduce, xValue))
.addHint(new ValueHint("Green creature you control", xValue))
);
// Trample
this.addAbility(TrampleAbility.getInstance());
}
@ -51,47 +55,8 @@ public final class KhalniHydra extends CardImpl {
super(card);
}
@Override
public void adjustCosts(Ability ability, Game game) {
super.adjustCosts(ability, game);
int reductionAmount = game.getBattlefield().count(filter, ability.getSourceId(), ability.getControllerId(), game);
Iterator<ManaCost> iter = ability.getManaCostsToPay().iterator();
while ( reductionAmount > 0 && iter.hasNext() ) {
ManaCost manaCostEntry = iter.next();
if (manaCostEntry.getMana().getGreen() > 0) { // in case another effect adds additional mana cost
iter.remove();
reductionAmount--;
}
}
}
@Override
public KhalniHydra copy() {
return new KhalniHydra(this);
}
}
class KhalniHydraCostReductionEffect extends OneShotEffect {
private static final String effectText = "{this} costs {G} less to cast for each green creature you control";
KhalniHydraCostReductionEffect ( ) {
super(Outcome.Benefit);
this.staticText = effectText;
}
KhalniHydraCostReductionEffect ( KhalniHydraCostReductionEffect effect ) {
super(effect);
}
@Override
public boolean apply(Game game, Ability source) {
return false;
}
@Override
public KhalniHydraCostReductionEffect copy() {
return new KhalniHydraCostReductionEffect(this);
}
}

View file

@ -1,25 +1,28 @@
package mage.cards.m;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.dynamicvalue.DynamicValue;
import mage.abilities.dynamicvalue.common.CardsInControllerGraveyardCount;
import mage.abilities.effects.common.ReturnFromGraveyardToBattlefieldTargetEffect;
import mage.abilities.effects.common.cost.SourceCostReductionForEachCardInGraveyardEffect;
import mage.constants.SubType;
import mage.abilities.effects.common.cost.SpellCostReductionForEachSourceEffect;
import mage.abilities.hint.ValueHint;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.AbilityWord;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.constants.Zone;
import mage.filter.FilterCard;
import mage.filter.StaticFilters;
import mage.filter.common.FilterLandCard;
import mage.target.common.TargetCardInYourGraveyard;
import java.util.UUID;
/**
*
* @author TheElk801
*/
public final class Molderhulk extends CardImpl {
@ -36,8 +39,11 @@ public final class Molderhulk extends CardImpl {
this.toughness = new MageInt(6);
// Undergrowth This spell costs {1} less to cast for each creature card in your graveyard.
Ability ability = new SimpleStaticAbility(Zone.ALL, new SourceCostReductionForEachCardInGraveyardEffect(StaticFilters.FILTER_CARD_CREATURE));
DynamicValue xValue = new CardsInControllerGraveyardCount(StaticFilters.FILTER_CARD_CREATURE);
Ability ability = new SimpleStaticAbility(Zone.ALL, new SpellCostReductionForEachSourceEffect(1, xValue));
ability.setAbilityWord(AbilityWord.UNDERGROWTH);
ability.setRuleAtTheTop(true);
ability.addHint(new ValueHint("Creature card in your graveyard", xValue));
this.addAbility(ability);
// When Molderhulk enters the battlefield, return target land card from your graveyard to the battlefield.

View file

@ -1,12 +1,14 @@
package mage.cards.n;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.dynamicvalue.DynamicValue;
import mage.abilities.dynamicvalue.common.CardsInControllerGraveyardCount;
import mage.abilities.effects.Effect;
import mage.abilities.effects.common.cost.CostModificationEffectImpl;
import mage.abilities.effects.common.cost.SourceCostReductionForEachCardInGraveyardEffect;
import mage.abilities.effects.common.cost.SpellCostReductionForEachSourceEffect;
import mage.abilities.hint.ValueHint;
import mage.abilities.keyword.MonstrosityAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
@ -16,6 +18,8 @@ import mage.game.Game;
import mage.players.Player;
import mage.util.CardUtil;
import java.util.UUID;
/**
* @author LevelX2
*/
@ -29,8 +33,10 @@ public final class NemesisOfMortals extends CardImpl {
this.toughness = new MageInt(5);
// Nemesis of Mortals costs {1} less to cast for each creature card in your graveyard.
Ability ability = new SimpleStaticAbility(Zone.ALL, new SourceCostReductionForEachCardInGraveyardEffect(StaticFilters.FILTER_CARD_CREATURE));
DynamicValue xValue = new CardsInControllerGraveyardCount(StaticFilters.FILTER_CARD_CREATURE);
Ability ability = new SimpleStaticAbility(Zone.ALL, new SpellCostReductionForEachSourceEffect(1, xValue));
ability.setRuleAtTheTop(true);
ability.addHint(new ValueHint("Creature card in your graveyard", xValue));
this.addAbility(ability);
// {7}{G}{G}: Monstrosity 5. This ability costs {1} less to activate for each creature card in your graveyard.

View file

@ -3,7 +3,10 @@ package mage.cards.o;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.effects.common.cost.SourceCostReductionForEachCardInGraveyardEffect;
import mage.abilities.dynamicvalue.DynamicValue;
import mage.abilities.dynamicvalue.common.CardsInControllerGraveyardCount;
import mage.abilities.effects.common.cost.SpellCostReductionForEachSourceEffect;
import mage.abilities.hint.ValueHint;
import mage.abilities.keyword.FlyingAbility;
import mage.abilities.keyword.HasteAbility;
import mage.cards.CardImpl;
@ -28,10 +31,10 @@ public final class OreScaleGuardian extends CardImpl {
this.toughness = new MageInt(4);
// This spell costs {1} less to cast for each land card in your graveyard.
Ability ability = new SimpleStaticAbility(
Zone.ALL, new SourceCostReductionForEachCardInGraveyardEffect(StaticFilters.FILTER_CARD_LAND)
);
DynamicValue xValue = new CardsInControllerGraveyardCount(StaticFilters.FILTER_CARD_LAND);
Ability ability = new SimpleStaticAbility(Zone.ALL, new SpellCostReductionForEachSourceEffect(1, xValue));
ability.setRuleAtTheTop(true);
ability.addHint(new ValueHint("Land card in your graveyard", xValue));
this.addAbility(ability);
// Flying

View file

@ -1,25 +1,25 @@
package mage.cards.t;
import mage.MageObject;
import mage.abilities.Ability;
import mage.abilities.SpellAbility;
import mage.abilities.common.ActivateAsSorceryActivatedAbility;
import mage.abilities.common.DiesCreatureTriggeredAbility;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.costs.common.PayLifeCost;
import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.dynamicvalue.DynamicValue;
import mage.abilities.dynamicvalue.common.CardsInControllerGraveyardCount;
import mage.abilities.effects.common.PutOnLibraryTargetEffect;
import mage.abilities.effects.common.ReturnFromGraveyardToBattlefieldTargetEffect;
import mage.abilities.effects.common.cost.CostModificationEffectImpl;
import mage.abilities.effects.common.cost.SpellCostReductionForEachSourceEffect;
import mage.abilities.hint.ValueHint;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.*;
import mage.constants.CardType;
import mage.constants.SuperType;
import mage.constants.Zone;
import mage.filter.StaticFilters;
import mage.game.Game;
import mage.players.Player;
import mage.target.common.TargetCardInYourGraveyard;
import mage.util.CardUtil;
import java.util.UUID;
@ -34,7 +34,11 @@ public final class TheCauldronOfEternity extends CardImpl {
this.addSuperType(SuperType.LEGENDARY);
// This spell costs {2} less to cast for each creature card in your graveyard.
this.addAbility(new SimpleStaticAbility(Zone.ALL, new TheCauldronOfEternityCostReductionEffect()));
DynamicValue xValue = new CardsInControllerGraveyardCount(StaticFilters.FILTER_CARD_CREATURE);
Ability ability = new SimpleStaticAbility(Zone.ALL, new SpellCostReductionForEachSourceEffect(2, xValue));
ability.setRuleAtTheTop(true);
ability.addHint(new ValueHint("Creature card in your graveyard", xValue));
this.addAbility(ability);
// Whenever a creature you control dies, put it on the bottom of its owner's library.
this.addAbility(new DiesCreatureTriggeredAbility(
@ -43,7 +47,7 @@ public final class TheCauldronOfEternity extends CardImpl {
));
// {2}{B}, {T}, Pay 2 life: Return target creature card from your graveyard to the battlefield. Activate this ability only any time you could cast a sorcery.
Ability ability = new ActivateAsSorceryActivatedAbility(
ability = new ActivateAsSorceryActivatedAbility(
Zone.BATTLEFIELD, new ReturnFromGraveyardToBattlefieldTargetEffect(), new ManaCostsImpl("{2}{B}")
);
ability.addCost(new TapSourceCost());
@ -61,44 +65,3 @@ public final class TheCauldronOfEternity extends CardImpl {
return new TheCauldronOfEternity(this);
}
}
class TheCauldronOfEternityCostReductionEffect extends CostModificationEffectImpl {
TheCauldronOfEternityCostReductionEffect() {
super(Duration.WhileOnStack, Outcome.Benefit, CostModificationType.REDUCE_COST);
staticText = "This spell costs {2} less to cast for each creature card in your graveyard";
}
private TheCauldronOfEternityCostReductionEffect(final TheCauldronOfEternityCostReductionEffect effect) {
super(effect);
}
@Override
public boolean apply(Game game, Ability source, Ability abilityToModify) {
Player player = game.getPlayer(source.getControllerId());
if (player == null) {
return false;
}
int reductionAmount = player
.getGraveyard()
.getCards(game)
.stream()
.filter(MageObject::isCreature)
.mapToInt(card -> 2)
.sum();
CardUtil.reduceCost(abilityToModify, reductionAmount);
return true;
}
@Override
public boolean applies(Ability abilityToModify, Ability source, Game game) {
return abilityToModify instanceof SpellAbility
&& abilityToModify.getSourceId().equals(source.getSourceId())
&& game.getCard(abilityToModify.getSourceId()) != null;
}
@Override
public TheCauldronOfEternityCostReductionEffect copy() {
return new TheCauldronOfEternityCostReductionEffect(this);
}
}

View file

@ -1,24 +1,23 @@
package mage.cards.t;
import mage.abilities.Ability;
import mage.abilities.SpellAbility;
import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.common.SpellCastControllerTriggeredAbility;
import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.dynamicvalue.DynamicValue;
import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount;
import mage.abilities.effects.common.CreateTokenEffect;
import mage.abilities.effects.common.continuous.BoostControlledEffect;
import mage.abilities.effects.common.cost.CostModificationEffectImpl;
import mage.abilities.effects.common.cost.SpellCostReductionForEachSourceEffect;
import mage.abilities.hint.ValueHint;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.*;
import mage.filter.FilterPermanent;
import mage.filter.FilterSpell;
import mage.filter.common.FilterControlledPermanent;
import mage.game.Game;
import mage.game.permanent.token.KnightToken;
import mage.util.CardUtil;
import java.util.UUID;
@ -27,10 +26,16 @@ import java.util.UUID;
*/
public final class TheCircleOfLoyalty extends CardImpl {
private static final FilterSpell filter = new FilterSpell("a legendary spell");
private static final FilterSpell filterLegendary = new FilterSpell("a legendary spell");
static {
filter.add(SuperType.LEGENDARY.getPredicate());
filterLegendary.add(SuperType.LEGENDARY.getPredicate());
}
static final FilterControlledPermanent filterKnight = new FilterControlledPermanent("Knight you control");
static {
filterKnight.add(SubType.KNIGHT.getPredicate());
}
public TheCircleOfLoyalty(UUID ownerId, CardSetInfo setInfo) {
@ -39,7 +44,10 @@ public final class TheCircleOfLoyalty extends CardImpl {
this.addSuperType(SuperType.LEGENDARY);
// This spell costs {1} less to cast for each Knight you control.
this.addAbility(new SimpleStaticAbility(Zone.ALL, new TheCircleOfLoyaltyCostReductionEffect()));
DynamicValue xValue = new PermanentsOnBattlefieldCount(filterKnight);
this.addAbility(new SimpleStaticAbility(
Zone.ALL, new SpellCostReductionForEachSourceEffect(1, xValue)
).addHint(new ValueHint("Knight you control", xValue)));
// Creatures you control get +1/+1.
this.addAbility(new SimpleStaticAbility(
@ -48,7 +56,7 @@ public final class TheCircleOfLoyalty extends CardImpl {
// Whenever you cast a legendary spell, create a 2/2 white Knight creature token with vigilance.
this.addAbility(new SpellCastControllerTriggeredAbility(
new CreateTokenEffect(new KnightToken()), filter, false
new CreateTokenEffect(new KnightToken()), filterLegendary, false
));
// {3}{W}, {T}: Create a 2/2 white Knight creature token with vigilance.
@ -67,37 +75,4 @@ public final class TheCircleOfLoyalty extends CardImpl {
public TheCircleOfLoyalty copy() {
return new TheCircleOfLoyalty(this);
}
}
class TheCircleOfLoyaltyCostReductionEffect extends CostModificationEffectImpl {
private static final FilterPermanent filter = new FilterControlledPermanent(SubType.KNIGHT);
TheCircleOfLoyaltyCostReductionEffect() {
super(Duration.WhileOnStack, Outcome.Benefit, CostModificationType.REDUCE_COST);
staticText = "This spell costs {1} less to cast for each Knight you control";
}
private TheCircleOfLoyaltyCostReductionEffect(final TheCircleOfLoyaltyCostReductionEffect effect) {
super(effect);
}
@Override
public boolean apply(Game game, Ability source, Ability abilityToModify) {
int reductionAmount = game.getBattlefield().count(filter, source.getSourceId(), source.getControllerId(), game);
CardUtil.reduceCost(abilityToModify, reductionAmount);
return true;
}
@Override
public boolean applies(Ability abilityToModify, Ability source, Game game) {
return abilityToModify instanceof SpellAbility
&& abilityToModify.getSourceId().equals(source.getSourceId())
&& game.getCard(abilityToModify.getSourceId()) != null;
}
@Override
public TheCircleOfLoyaltyCostReductionEffect copy() {
return new TheCircleOfLoyaltyCostReductionEffect(this);
}
}
}

View file

@ -4,11 +4,13 @@ import mage.abilities.Ability;
import mage.abilities.common.BeginningOfUpkeepTriggeredAbility;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.dynamicvalue.DynamicValue;
import mage.abilities.dynamicvalue.common.CardsInControllerGraveyardCount;
import mage.abilities.dynamicvalue.common.CountersSourceCount;
import mage.abilities.effects.common.DrawCardSourceControllerEffect;
import mage.abilities.effects.common.continuous.MaximumHandSizeControllerEffect;
import mage.abilities.effects.common.cost.SourceCostReductionForEachCardInGraveyardEffect;
import mage.abilities.effects.common.cost.SpellCostReductionForEachSourceEffect;
import mage.abilities.effects.common.counter.AddCountersSourceEffect;
import mage.abilities.hint.ValueHint;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.*;
@ -30,10 +32,11 @@ public final class TheMagicMirror extends CardImpl {
this.addSuperType(SuperType.LEGENDARY);
// This spell costs {1} less to cast for each instant and sorcery card in your graveyard.
this.addAbility(new SimpleStaticAbility(
Zone.ALL, new SourceCostReductionForEachCardInGraveyardEffect(
StaticFilters.FILTER_CARD_INSTANT_AND_SORCERY
)).setRuleAtTheTop(true));
DynamicValue xValue = new CardsInControllerGraveyardCount(StaticFilters.FILTER_CARD_INSTANT_AND_SORCERY);
Ability ability = new SimpleStaticAbility(Zone.ALL, new SpellCostReductionForEachSourceEffect(1, xValue));
ability.setRuleAtTheTop(true);
ability.addHint(new ValueHint("Instant and sorcery card in your graveyard", xValue));
this.addAbility(ability);
// You have no maximum hand size.
this.addAbility(new SimpleStaticAbility(new MaximumHandSizeControllerEffect(
@ -42,7 +45,7 @@ public final class TheMagicMirror extends CardImpl {
)));
// At the beginning of your upkeep, put a knowledge counter on The Magic Mirror, then draw a card for each knowledge counter on The Magic Mirror.
Ability ability = new BeginningOfUpkeepTriggeredAbility(
ability = new BeginningOfUpkeepTriggeredAbility(
new AddCountersSourceEffect(CounterType.KNOWLEDGE.createInstance())
.setText("put a knowledge counter on {this},"),
TargetController.YOU, false

View file

@ -1,7 +1,5 @@
package mage.cards.t;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.SpellAbility;
@ -13,21 +11,16 @@ import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.cost.CostModificationEffectImpl;
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.SuperType;
import mage.constants.Zone;
import mage.constants.*;
import mage.filter.StaticFilters;
import mage.game.Game;
import mage.players.Player;
import mage.target.TargetPlayer;
import mage.util.CardUtil;
import java.util.UUID;
/**
*
* @author LevelX2
*/
public final class TorgaarFamineIncarnate extends CardImpl {
@ -107,8 +100,16 @@ class TorgaarFamineIncarnateEffectCostReductionEffect extends CostModificationEf
SpellAbility spellAbility = (SpellAbility) abilityToModify;
for (Cost cost : spellAbility.getCosts()) {
if (cost instanceof SacrificeXTargetCost) {
int reduction = ((SacrificeXTargetCost) cost).getAmount();
CardUtil.adjustCost(spellAbility, reduction * 2);
if (game.inCheckPlayableState()) {
// allows to cast in getPlayable
int reduction = ((SacrificeXTargetCost) cost).getMaxValue(spellAbility, game);
CardUtil.adjustCost(spellAbility, reduction * 2);
} else {
// real cast
int reduction = ((SacrificeXTargetCost) cost).getAmount();
CardUtil.adjustCost(spellAbility, reduction * 2);
}
break;
}
}

View file

@ -0,0 +1,140 @@
package org.mage.test.cards.cost.modification;
import mage.constants.PhaseStep;
import mage.constants.Zone;
import org.junit.Test;
import org.mage.test.serverside.base.CardTestPlayerBaseWithAIHelps;
/**
* @author JayDi85
*/
public class CostReduceForEachTest extends CardTestPlayerBaseWithAIHelps {
@Test
public void test_AncientStoneIdol_Attacking() {
// {10}
// Flash
// This spell costs {1} less to cast for each attacking creature.
addCard(Zone.HAND, playerA, "Ancient Stone Idol", 1);
addCard(Zone.BATTLEFIELD, playerA, "Swamp", 10 - 2);
addCard(Zone.BATTLEFIELD, playerA, "Balduvian Bears", 2); // give 2 cost reduction
// before
checkPlayableAbility("before attack", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Ancient Stone Idol", false);
// prepare for attack
attack(1, playerA, "Balduvian Bears");
attack(1, playerA, "Balduvian Bears");
// on attack
checkPlayableAbility("on attack", 1, PhaseStep.DECLARE_BLOCKERS, playerA, "Cast Ancient Stone Idol", true);
castSpell(1, PhaseStep.DECLARE_BLOCKERS, playerA, "Ancient Stone Idol");
setStrictChooseMode(true);
setStopAt(1, PhaseStep.END_TURN);
execute();
assertAllCommandsUsed();
assertPermanentCount(playerA, "Ancient Stone Idol", 1);
}
@Test
public void test_AncientStoneIdol_AttackingWithSacrifice() {
// The total cost to cast a spell is locked in before you pay that cost. For example, if you control five attacking
// creatures, including one you can sacrifice to add {C} to your mana pool, Ancient Stone Idol costs {5} to cast.
// Then you can sacrifice the creature when you activate mana abilities just before paying the cost, and it still
// costs only {5} to cast.
// (2018-07-13)
// {10}
// Flash
// This spell costs {1} less to cast for each attacking creature.
addCard(Zone.HAND, playerA, "Ancient Stone Idol", 1);
addCard(Zone.BATTLEFIELD, playerA, "Swamp", 10 - 4);
//
// Sacrifice Blood Pet: Add {B}.
addCard(Zone.BATTLEFIELD, playerA, "Blood Pet", 2); // give 2 cost reduction + can be sacrificed as 2 mana
// before
checkPlayableAbility("before attack", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Ancient Stone Idol", false);
// prepare for attack
attack(1, playerA, "Blood Pet");
attack(1, playerA, "Blood Pet");
// on attack (must automaticly sacrifice creatures as mana pay)
checkPlayableAbility("on attack", 1, PhaseStep.DECLARE_BLOCKERS, playerA, "Cast Ancient Stone Idol", true);
castSpell(1, PhaseStep.DECLARE_BLOCKERS, playerA, "Ancient Stone Idol");
setStrictChooseMode(true);
setStopAt(1, PhaseStep.END_TURN);
execute();
assertAllCommandsUsed();
assertPermanentCount(playerA, "Ancient Stone Idol", 1);
assertGraveyardCount(playerA, "Blood Pet", 2);
}
@Test
public void test_KhalniHydra_ColorReduce() {
// {G}{G}{G}{G}{G}{G}{G}{G}
// This spell costs {G} less to cast for each green creature you control.
addCard(Zone.HAND, playerA, "Khalni Hydra", 1);
addCard(Zone.BATTLEFIELD, playerA, "Forest", 8 - 2);
addCard(Zone.HAND, playerA, "Balduvian Bears", 2); // give 2 cost reduction
checkPlayableAbility("no cost reduction 1", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Khalni Hydra", false);
// prepare creatures for reduce
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Balduvian Bears");
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Balduvian Bears");
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN, playerA);
checkPlayableAbility("no cost reduction 2", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Khalni Hydra", false);
// can cast on next turn
castSpell(3, PhaseStep.PRECOMBAT_MAIN, playerA, "Khalni Hydra");
setStrictChooseMode(true);
setStopAt(3, PhaseStep.END_TURN);
execute();
assertAllCommandsUsed();
assertPermanentCount(playerA, "Khalni Hydra", 1);
}
@Test
public void test_TorgaarFamineIncarnate_SacrificeXTargets() {
// {6}{B}{B}
// As an additional cost to cast this spell, you may sacrifice any number of creatures.
// This spell costs {2} less to cast for each creature sacrificed this way.
// When Torgaar, Famine Incarnate enters the battlefield, up to one target player's life total becomes half their starting life total, rounded down.
addCard(Zone.HAND, playerA, "Torgaar, Famine Incarnate", 1);
addCard(Zone.BATTLEFIELD, playerA, "Swamp", 8 - 4 - 2);
addCard(Zone.BATTLEFIELD, playerA, "Forest", 2);
addCard(Zone.HAND, playerA, "Balduvian Bears", 2); // give 4 cost reduction on sacrifice
checkPlayableAbility("no cost reduction 1", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Torgaar, Famine Incarnate", false);
// prepare creatures for reduce
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Balduvian Bears");
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Balduvian Bears");
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN, playerA);
checkPlayableAbility("no cost reduction 2", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Torgaar, Famine Incarnate", false);
// can cast on next turn
checkPlayableAbility("must reduce", 3, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Torgaar, Famine Incarnate", true);
castSpell(3, PhaseStep.PRECOMBAT_MAIN, playerA, "Torgaar, Famine Incarnate");
setChoice(playerA, "X=2"); // two creatures sacrifice
setChoice(playerA, "Balduvian Bears");
setChoice(playerA, "Balduvian Bears");
addTarget(playerA, playerB); // target player for half life
setStrictChooseMode(true);
setStopAt(3, PhaseStep.END_TURN);
execute();
assertAllCommandsUsed();
assertPermanentCount(playerA, "Torgaar, Famine Incarnate", 1);
assertLife(playerB, 20 / 2);
}
}

View file

@ -1663,16 +1663,20 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement
public void attack(int turnNum, TestPlayer player, String attacker) {
//Assert.assertNotEquals("", attacker);
assertAliaseSupportInActivateCommand(attacker, false); // it uses old special notation like card_name:index
player.addAction(turnNum, PhaseStep.DECLARE_ATTACKERS, "attack:" + attacker);
}
public void attack(int turnNum, TestPlayer player, String attacker, TestPlayer defendingPlayer) {
//Assert.assertNotEquals("", attacker);
assertAliaseSupportInActivateCommand(attacker, false); // it uses old special notation like card_name:index
player.addAction(turnNum, PhaseStep.DECLARE_ATTACKERS, "attack:" + attacker + "$defendingPlayer=" + defendingPlayer.getName());
}
public void attack(int turnNum, TestPlayer player, String attacker, String planeswalker) {
//Assert.assertNotEquals("", attacker);
assertAliaseSupportInActivateCommand(attacker, false); // it uses old special notation like card_name:index
assertAliaseSupportInActivateCommand(planeswalker, false);
player.addAction(turnNum, PhaseStep.DECLARE_ATTACKERS, new StringBuilder("attack:").append(attacker).append("$planeswalker=").append(planeswalker).toString());
}
@ -1683,6 +1687,8 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement
public void block(int turnNum, TestPlayer player, String blocker, String attacker) {
//Assert.assertNotEquals("", blocker);
//Assert.assertNotEquals("", attacker);
assertAliaseSupportInActivateCommand(blocker, false); // it uses old special notation like card_name:index
assertAliaseSupportInActivateCommand(attacker, false);
player.addAction(turnNum, PhaseStep.DECLARE_BLOCKERS, "block:" + blocker + '$' + attacker);
}

View file

@ -1,38 +1,60 @@
package mage.abilities.dynamicvalue.common;
import mage.abilities.Ability;
import mage.abilities.dynamicvalue.DynamicValue;
import mage.abilities.effects.Effect;
import mage.filter.common.FilterCreaturePermanent;
import mage.game.Game;
import mage.game.combat.CombatGroup;
import mage.game.permanent.Permanent;
import java.util.UUID;
/**
*
* @author LevelX2
*/
public class AttackingCreatureCount implements DynamicValue {
private String message;
private FilterCreaturePermanent filter;
public AttackingCreatureCount() {
this("attacking creature");
}
public AttackingCreatureCount(FilterCreaturePermanent filter) {
this(filter, "attacking " + filter.getMessage());
}
public AttackingCreatureCount(String message) {
this(null, message);
}
public AttackingCreatureCount(FilterCreaturePermanent filter, String message) {
this.message = message;
this.filter = filter;
}
public AttackingCreatureCount(final AttackingCreatureCount dynamicValue) {
super();
this.message = dynamicValue.message;
this.filter = dynamicValue.filter;
}
@Override
public int calculate(Game game, Ability sourceAbility, Effect effect) {
int count = 0;
for (CombatGroup combatGroup : game.getCombat().getGroups()) {
count += combatGroup.getAttackers().size();
for (UUID permId : combatGroup.getAttackers()) {
if (filter != null) {
Permanent attacker = game.getPermanent(permId);
if (attacker != null && filter.match(attacker, sourceAbility.getSourceId(), sourceAbility.getControllerId(), game)) {
count++;
}
} else {
count++;
}
}
}
return count;
}

View file

@ -1,65 +0,0 @@
package mage.abilities.dynamicvalue.common;
import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.dynamicvalue.DynamicValue;
import mage.abilities.effects.Effect;
import mage.filter.common.FilterCreaturePermanent;
import mage.game.Game;
import mage.game.combat.CombatGroup;
import mage.game.permanent.Permanent;
/**
*
* @author escplan9 (Derek Monturo - dmontur1 at gmail dot com)
*/
public class AttackingFilterCreatureCount implements DynamicValue {
private FilterCreaturePermanent filter;
private String message;
public AttackingFilterCreatureCount(FilterCreaturePermanent filter) {
this(filter, "attacking creature");
}
public AttackingFilterCreatureCount(FilterCreaturePermanent filter, String message) {
this.filter = filter;
this.message = message;
}
public AttackingFilterCreatureCount(final AttackingFilterCreatureCount dynamicValue) {
super();
this.message = dynamicValue.message;
this.filter = dynamicValue.filter;
}
@Override
public int calculate(Game game, Ability sourceAbility, Effect effect) {
int count = 0;
for (CombatGroup combatGroup : game.getCombat().getGroups()) {
for (UUID permId : combatGroup.getAttackers()) {
Permanent attacker = game.getPermanent(permId);
if (filter.match(attacker, sourceAbility.getSourceId(), sourceAbility.getControllerId(), game)) {
count++;
}
}
}
return count;
}
@Override
public AttackingFilterCreatureCount copy() {
return new AttackingFilterCreatureCount(this);
}
@Override
public String getMessage() {
return message;
}
@Override
public String toString() {
return "X";
}
}

View file

@ -32,11 +32,11 @@ public enum GateYouControlCount implements DynamicValue {
@Override
public String toString() {
return "X";
return "1"; // uses "for each" effects, so must be 1, not X
}
@Override
public String getMessage() {
return "gate you control";
return "Gate you control";
}
}

View file

@ -1,7 +1,5 @@
package mage.abilities.effects.common.continuous;
import java.util.Iterator;
import mage.MageObjectReference;
import mage.abilities.Ability;
import mage.abilities.dynamicvalue.DynamicValue;
@ -16,8 +14,9 @@ import mage.filter.common.FilterCreaturePermanent;
import mage.game.Game;
import mage.game.permanent.Permanent;
import java.util.Iterator;
/**
*
* @author BetaSteward_at_googlemail.com
*/
public class BoostControlledEffect extends ContinuousEffectImpl {
@ -56,10 +55,10 @@ public class BoostControlledEffect extends ContinuousEffectImpl {
* @param power
* @param toughness
* @param duration
* @param filter AnotherPredicate is not working, you need to use the
* excludeSource option
* @param lockedIn if true, power and toughness will be calculated only
* once, when the ability resolves
* @param filter AnotherPredicate is not working, you need to use the
* excludeSource option
* @param lockedIn if true, power and toughness will be calculated only
* once, when the ability resolves
* @param excludeSource
*/
public BoostControlledEffect(DynamicValue power, DynamicValue toughness, Duration duration, FilterCreaturePermanent filter, boolean excludeSource, boolean lockedIn) {
@ -105,7 +104,7 @@ public class BoostControlledEffect extends ContinuousEffectImpl {
@Override
public boolean apply(Game game, Ability source) {
if (this.affectedObjectsSet) {
for (Iterator<MageObjectReference> it = affectedObjectList.iterator(); it.hasNext();) {
for (Iterator<MageObjectReference> it = affectedObjectList.iterator(); it.hasNext(); ) {
Permanent permanent = it.next().getPermanent(game);
if (permanent != null) {
permanent.addPower(power.calculate(game, source, this));
@ -126,7 +125,6 @@ public class BoostControlledEffect extends ContinuousEffectImpl {
}
private void setText() {
String message = null;
StringBuilder sb = new StringBuilder();
if (excludeSource) {
sb.append("other ");
@ -150,6 +148,9 @@ public class BoostControlledEffect extends ContinuousEffectImpl {
sb.append(t);
sb.append((duration == Duration.EndOfTurn ? " until end of turn" : ""));
// where X
String message = null;
if (t.equals("X")) {
message = toughness.getMessage();
} else if (p.equals("X")) {
@ -158,6 +159,17 @@ public class BoostControlledEffect extends ContinuousEffectImpl {
if (message != null && !message.isEmpty()) {
sb.append(", where X is ").append(message);
}
// for each
if (message == null) {
message = toughness.getMessage();
if (message.isEmpty()) {
message = power.getMessage();
}
if (!message.isEmpty()) {
sb.append(" for each " + message);
}
}
staticText = sb.toString();
}

View file

@ -12,6 +12,12 @@ import mage.game.Game;
/**
* Simple implementation of a {@link CostModificationEffect} offering simplified
* construction to setup the object for use by the mage framework.
* <p>
* WARNING, if you implement custom effect and it can works on stack only (e.g. it need spell's targets to check) then
* use different apply code:
* - one for get playable mode before spell puts on stack (apply maximum possible cost reduction, use game.inCheckPlayableState()).
* - one for normal mode after spell puts on stack (apply real cost reduction)
* Example: TorgaarFamineIncarnate
*
* @author maurer.it_at_gmail.com
*/

View file

@ -1,59 +0,0 @@
package mage.abilities.effects.common.cost;
import mage.abilities.Ability;
import mage.abilities.SpellAbility;
import mage.constants.CostModificationType;
import mage.constants.Duration;
import mage.constants.Outcome;
import mage.filter.FilterCard;
import mage.filter.StaticFilters;
import mage.game.Game;
import mage.players.Player;
import mage.util.CardUtil;
/**
* @author Styxo
*/
public class SourceCostReductionForEachCardInGraveyardEffect extends CostModificationEffectImpl {
private FilterCard filter;
public SourceCostReductionForEachCardInGraveyardEffect() {
this(StaticFilters.FILTER_CARD);
}
public SourceCostReductionForEachCardInGraveyardEffect(FilterCard filter) {
super(Duration.WhileOnStack, Outcome.Benefit, CostModificationType.REDUCE_COST);
this.filter = filter;
staticText = "{this} costs {1} less to cast for each " + filter.getMessage() + " in your graveyard";
}
private SourceCostReductionForEachCardInGraveyardEffect(SourceCostReductionForEachCardInGraveyardEffect effect) {
super(effect);
this.filter = effect.filter.copy();
}
@Override
public boolean apply(Game game, Ability source, Ability abilityToModify) {
Player player = game.getPlayer(source.getControllerId());
if (player != null) {
int reductionAmount = player.getGraveyard().count(filter, game);
CardUtil.reduceCost(abilityToModify, reductionAmount);
return true;
}
return false;
}
@Override
public boolean applies(Ability abilityToModify, Ability source, Game game) {
if ((abilityToModify instanceof SpellAbility) && abilityToModify.getSourceId().equals(source.getSourceId())) {
return game.getCard(abilityToModify.getSourceId()) != null;
}
return false;
}
@Override
public SourceCostReductionForEachCardInGraveyardEffect copy() {
return new SourceCostReductionForEachCardInGraveyardEffect(this);
}
}

View file

@ -0,0 +1,93 @@
package mage.abilities.effects.common.cost;
import mage.abilities.Ability;
import mage.abilities.SpellAbility;
import mage.abilities.costs.mana.ManaCost;
import mage.abilities.costs.mana.ManaCosts;
import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.dynamicvalue.DynamicValue;
import mage.constants.CostModificationType;
import mage.constants.Duration;
import mage.constants.Outcome;
import mage.game.Game;
import mage.util.CardUtil;
/**
* @author JayDi85
*/
public class SpellCostReductionForEachSourceEffect extends CostModificationEffectImpl {
private final DynamicValue eachAmount;
private ManaCosts<ManaCost> reduceManaCosts;
private final int reduceGenericMana;
public SpellCostReductionForEachSourceEffect(int reduceGenericMana, DynamicValue eachAmount) {
super(Duration.WhileOnBattlefield, Outcome.Benefit, CostModificationType.REDUCE_COST);
this.eachAmount = eachAmount;
this.reduceManaCosts = null;
this.reduceGenericMana = reduceGenericMana;
StringBuilder sb = new StringBuilder();
sb.append("this spell costs {")
.append(this.reduceGenericMana)
.append("} less to cast for each ")
.append(this.eachAmount.getMessage());
this.staticText = sb.toString();
}
public SpellCostReductionForEachSourceEffect(ManaCosts<ManaCost> reduceManaCosts, DynamicValue eachAmount) {
super(Duration.WhileOnBattlefield, Outcome.Benefit, CostModificationType.REDUCE_COST);
this.eachAmount = eachAmount;
this.reduceManaCosts = reduceManaCosts;
this.reduceGenericMana = 0;
StringBuilder sb = new StringBuilder();
sb.append("this spell costs ");
for (String manaSymbol : reduceManaCosts.getSymbols()) {
sb.append(manaSymbol);
}
sb.append(" less to cast for each ").append(this.eachAmount.getMessage());
this.staticText = sb.toString();
}
protected SpellCostReductionForEachSourceEffect(final SpellCostReductionForEachSourceEffect effect) {
super(effect);
this.eachAmount = effect.eachAmount;
this.reduceManaCosts = effect.reduceManaCosts;
this.reduceGenericMana = effect.reduceGenericMana;
}
@Override
public boolean apply(Game game, Ability source, Ability abilityToModify) {
int needReduceAmount = eachAmount.calculate(game, source, this);
if (needReduceAmount > 0) {
if (reduceManaCosts != null) {
// color reduce
ManaCosts<ManaCost> needReduceMana = new ManaCostsImpl<>();
for (int i = 0; i <= needReduceAmount; i++) {
needReduceMana.add(reduceManaCosts.copy());
}
CardUtil.adjustCost((SpellAbility) abilityToModify, needReduceMana, false);
} else {
// generic reduce
CardUtil.reduceCost(abilityToModify, needReduceAmount * this.reduceGenericMana);
}
}
return true;
}
@Override
public boolean applies(Ability abilityToModify, Ability source, Game game) {
if (abilityToModify.getSourceId().equals(source.getSourceId()) && (abilityToModify instanceof SpellAbility)) {
return true;
}
return false;
}
@Override
public SpellCostReductionForEachSourceEffect copy() {
return new SpellCostReductionForEachSourceEffect(this);
}
}

View file

@ -37,11 +37,10 @@ public class SpellCostReductionSourceEffect extends CostModificationEffectImpl {
for (String manaSymbol : manaCostsToReduce.getSymbols()) {
sb.append(manaSymbol);
}
sb.append(" less");
sb.append(" less to cast");
if (this.condition != null) {
sb.append(" to if ").append(this.condition.toString());
sb.append(" if ").append(this.condition.toString());
}
this.staticText = sb.toString();
}

View file

@ -1,42 +0,0 @@
package mage.abilities.effects.common.cost;
import mage.abilities.Ability;
import mage.abilities.SpellAbility;
import mage.constants.CostModificationType;
import mage.constants.Duration;
import mage.constants.Outcome;
import mage.game.Game;
import mage.util.CardUtil;
public class SpellCostReductionSourceForOpponentsEffect extends CostModificationEffectImpl {
public SpellCostReductionSourceForOpponentsEffect() {
this("undaunted <i>(This spell costs {1} less to cast for each opponent.)</i>");
}
public SpellCostReductionSourceForOpponentsEffect(String newStaticText) {
super(Duration.Custom, Outcome.Benefit, CostModificationType.REDUCE_COST);
staticText = newStaticText;
}
public SpellCostReductionSourceForOpponentsEffect(final SpellCostReductionSourceForOpponentsEffect effect) {
super(effect);
}
@Override
public boolean apply(Game game, Ability source, Ability abilityToModify) {
int count = game.getOpponents(source.getControllerId()).size();
CardUtil.reduceCost(abilityToModify, count);
return true;
}
@Override
public boolean applies(Ability abilityToModify, Ability source, Game game) {
return abilityToModify instanceof SpellAbility && abilityToModify.getSourceId().equals(source.getSourceId());
}
@Override
public SpellCostReductionSourceForOpponentsEffect copy() {
return new SpellCostReductionSourceForOpponentsEffect(this);
}
}

View file

@ -1,12 +1,8 @@
/*
* 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.keyword;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.effects.common.cost.SpellCostReductionSourceForOpponentsEffect;
import mage.abilities.dynamicvalue.common.OpponentsCount;
import mage.abilities.effects.common.cost.SpellCostReductionForEachSourceEffect;
import mage.constants.Zone;
/**
@ -15,7 +11,7 @@ import mage.constants.Zone;
public class UndauntedAbility extends SimpleStaticAbility {
public UndauntedAbility() {
super(Zone.ALL, new SpellCostReductionSourceForOpponentsEffect("undaunted <i>(This spell costs {1} less to cast for each opponent.)</i>"));
super(Zone.ALL, new SpellCostReductionForEachSourceEffect(1, OpponentsCount.instance));
setRuleAtTheTop(true);
}
@ -28,4 +24,8 @@ public class UndauntedAbility extends SimpleStaticAbility {
return new UndauntedAbility(this);
}
@Override
public String getRule() {
return "undaunted <i>(This spell costs {1} less to cast for each opponent.)</i>";
}
}