mirror of
https://github.com/magefree/mage.git
synced 2025-12-22 03:22:00 -08:00
Cost reduction effects - refactor, removed redundant custom effects, added card hints;
This commit is contained in:
parent
e4ebf50d42
commit
cf3feff76a
35 changed files with 506 additions and 643 deletions
|
|
@ -1,31 +1,25 @@
|
||||||
package mage.cards.a;
|
package mage.cards.a;
|
||||||
|
|
||||||
import java.util.UUID;
|
|
||||||
import mage.MageInt;
|
import mage.MageInt;
|
||||||
import mage.abilities.Ability;
|
|
||||||
import mage.abilities.SpellAbility;
|
|
||||||
import mage.abilities.common.DiesTriggeredAbility;
|
import mage.abilities.common.DiesTriggeredAbility;
|
||||||
import mage.abilities.common.SimpleStaticAbility;
|
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.CreateTokenEffect;
|
||||||
import mage.abilities.effects.common.cost.CostModificationEffectImpl;
|
import mage.abilities.effects.common.cost.SpellCostReductionForEachSourceEffect;
|
||||||
import mage.constants.SubType;
|
import mage.abilities.hint.ValueHint;
|
||||||
import mage.abilities.keyword.FlashAbility;
|
import mage.abilities.keyword.FlashAbility;
|
||||||
import mage.abilities.keyword.TrampleAbility;
|
import mage.abilities.keyword.TrampleAbility;
|
||||||
import mage.cards.CardImpl;
|
import mage.cards.CardImpl;
|
||||||
import mage.cards.CardSetInfo;
|
import mage.cards.CardSetInfo;
|
||||||
import mage.constants.CardType;
|
import mage.constants.CardType;
|
||||||
import mage.constants.CostModificationType;
|
import mage.constants.SubType;
|
||||||
import mage.constants.Duration;
|
|
||||||
import mage.constants.Outcome;
|
|
||||||
import mage.constants.Zone;
|
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.game.permanent.token.StoneTrapIdolToken;
|
||||||
import mage.util.CardUtil;
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
|
||||||
* @author TheElk801
|
* @author TheElk801
|
||||||
*/
|
*/
|
||||||
public final class AncientStoneIdol extends CardImpl {
|
public final class AncientStoneIdol extends CardImpl {
|
||||||
|
|
@ -41,7 +35,10 @@ public final class AncientStoneIdol extends CardImpl {
|
||||||
this.addAbility(FlashAbility.getInstance());
|
this.addAbility(FlashAbility.getInstance());
|
||||||
|
|
||||||
// This spell costs {1} less to cast for each attacking creature.
|
// 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
|
// Trample
|
||||||
this.addAbility(TrampleAbility.getInstance());
|
this.addAbility(TrampleAbility.getInstance());
|
||||||
|
|
@ -59,41 +56,3 @@ public final class AncientStoneIdol extends CardImpl {
|
||||||
return new AncientStoneIdol(this);
|
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -4,8 +4,9 @@ import mage.MageInt;
|
||||||
import mage.abilities.Ability;
|
import mage.abilities.Ability;
|
||||||
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
|
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
|
||||||
import mage.abilities.common.SimpleStaticAbility;
|
import mage.abilities.common.SimpleStaticAbility;
|
||||||
|
import mage.abilities.dynamicvalue.common.OpponentsCount;
|
||||||
import mage.abilities.effects.OneShotEffect;
|
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.abilities.keyword.TrampleAbility;
|
||||||
import mage.cards.CardImpl;
|
import mage.cards.CardImpl;
|
||||||
import mage.cards.CardSetInfo;
|
import mage.cards.CardSetInfo;
|
||||||
|
|
@ -35,7 +36,8 @@ public final class AvatarOfGrowth extends CardImpl {
|
||||||
this.toughness = new MageInt(4);
|
this.toughness = new MageInt(4);
|
||||||
|
|
||||||
// This spell costs {1} less to cast for each opponent you have.
|
// 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
|
// Trample
|
||||||
this.addAbility(TrampleAbility.getInstance());
|
this.addAbility(TrampleAbility.getInstance());
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
|
|
||||||
package mage.cards.b;
|
package mage.cards.b;
|
||||||
|
|
||||||
import mage.MageInt;
|
import mage.MageInt;
|
||||||
|
|
@ -8,7 +7,7 @@ import mage.abilities.common.SimpleStaticAbility;
|
||||||
import mage.abilities.dynamicvalue.DynamicValue;
|
import mage.abilities.dynamicvalue.DynamicValue;
|
||||||
import mage.abilities.dynamicvalue.common.CardsInControllerGraveyardCount;
|
import mage.abilities.dynamicvalue.common.CardsInControllerGraveyardCount;
|
||||||
import mage.abilities.effects.common.DrawCardSourceControllerEffect;
|
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.effects.common.discard.DiscardHandControllerEffect;
|
||||||
import mage.abilities.hint.ValueHint;
|
import mage.abilities.hint.ValueHint;
|
||||||
import mage.abilities.keyword.ProwessAbility;
|
import mage.abilities.keyword.ProwessAbility;
|
||||||
|
|
@ -26,27 +25,25 @@ import java.util.UUID;
|
||||||
*/
|
*/
|
||||||
public final class BedlamReveler extends CardImpl {
|
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) {
|
public BedlamReveler(UUID ownerId, CardSetInfo setInfo) {
|
||||||
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{6}{R}{R}");
|
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{6}{R}{R}");
|
||||||
this.subtype.add(SubType.DEVIL, SubType.HORROR);
|
this.subtype.add(SubType.DEVIL, SubType.HORROR);
|
||||||
this.power = new MageInt(3);
|
this.power = new MageInt(3);
|
||||||
this.toughness = new MageInt(4);
|
this.toughness = new MageInt(4);
|
||||||
|
|
||||||
// Bedlam Reveler costs {1} less to cast for each instant or sorcery card in your graveyard.
|
// This spell costs {1} less to cast for each instant and sorcery card in your graveyard.
|
||||||
this.addAbility(new SimpleStaticAbility(
|
DynamicValue xValue = new CardsInControllerGraveyardCount(StaticFilters.FILTER_CARD_INSTANT_OR_SORCERY);
|
||||||
Zone.ALL, new SourceCostReductionForEachCardInGraveyardEffect(StaticFilters.FILTER_CARD_INSTANT_AND_SORCERY)
|
Ability ability = new SimpleStaticAbility(Zone.ALL, new SpellCostReductionForEachSourceEffect(1, xValue));
|
||||||
).addHint(new ValueHint("Instant and sorcery cards in your graveyard", cardsCount)));
|
ability.setRuleAtTheTop(true);
|
||||||
|
ability.addHint(new ValueHint("Instant or sourcery card in your graveyard", xValue));
|
||||||
|
this.addAbility(ability);
|
||||||
|
|
||||||
// Prowess
|
// Prowess
|
||||||
this.addAbility(new ProwessAbility());
|
this.addAbility(new ProwessAbility());
|
||||||
|
|
||||||
// When Bedlam Reveler enters the battlefield, discard your hand, then draw three cards.
|
// When Bedlam Reveler enters the battlefield, discard your hand, then draw three cards.
|
||||||
Ability ability = new EntersBattlefieldTriggeredAbility(
|
ability = new EntersBattlefieldTriggeredAbility(new DiscardHandControllerEffect());
|
||||||
new DiscardHandControllerEffect().setText("discard your hand,")
|
ability.addEffect(new DrawCardSourceControllerEffect(3).concatBy(", then"));
|
||||||
);
|
|
||||||
ability.addEffect(new DrawCardSourceControllerEffect(3).setText("then draw three cards"));
|
|
||||||
this.addAbility(ability);
|
this.addAbility(ability);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,17 @@
|
||||||
package mage.cards.b;
|
package mage.cards.b;
|
||||||
|
|
||||||
import mage.MageInt;
|
import mage.MageInt;
|
||||||
import mage.abilities.Ability;
|
|
||||||
import mage.abilities.common.SimpleStaticAbility;
|
import mage.abilities.common.SimpleStaticAbility;
|
||||||
import mage.abilities.dynamicvalue.DynamicValue;
|
import mage.abilities.dynamicvalue.DynamicValue;
|
||||||
import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount;
|
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.abilities.hint.ValueHint;
|
||||||
import mage.cards.CardImpl;
|
import mage.cards.CardImpl;
|
||||||
import mage.cards.CardSetInfo;
|
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.filter.common.FilterControlledPermanent;
|
||||||
import mage.game.Game;
|
|
||||||
import mage.util.CardUtil;
|
|
||||||
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
|
|
@ -21,8 +20,13 @@ import java.util.UUID;
|
||||||
*/
|
*/
|
||||||
public final class BrineGiant extends CardImpl {
|
public final class BrineGiant extends CardImpl {
|
||||||
|
|
||||||
private static final DynamicValue xValue
|
static final FilterControlledPermanent filter = new FilterControlledPermanent("enchantment you control");
|
||||||
= new PermanentsOnBattlefieldCount(BrineGiantCostReductionEffect.filter);
|
|
||||||
|
static {
|
||||||
|
filter.add(CardType.ENCHANTMENT.getPredicate());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final DynamicValue xValue = new PermanentsOnBattlefieldCount(filter);
|
||||||
|
|
||||||
public BrineGiant(UUID ownerId, CardSetInfo setInfo) {
|
public BrineGiant(UUID ownerId, CardSetInfo setInfo) {
|
||||||
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{6}{U}");
|
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 spell costs {1} less to cast for each enchantment you control.
|
||||||
this.addAbility(new SimpleStaticAbility(
|
this.addAbility(new SimpleStaticAbility(
|
||||||
Zone.ALL, new BrineGiantCostReductionEffect()
|
Zone.ALL, new SpellCostReductionForEachSourceEffect(1, xValue)
|
||||||
).addHint(new ValueHint("Enchantments you control", xValue)));
|
).addHint(new ValueHint("Enchantments you control", xValue)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -45,39 +49,4 @@ public final class BrineGiant extends CardImpl {
|
||||||
public BrineGiant copy() {
|
public BrineGiant copy() {
|
||||||
return new BrineGiant(this);
|
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
@ -1,10 +1,11 @@
|
||||||
package mage.cards.c;
|
package mage.cards.c;
|
||||||
|
|
||||||
import mage.MageInt;
|
import mage.MageInt;
|
||||||
|
import mage.abilities.Ability;
|
||||||
import mage.abilities.common.SimpleStaticAbility;
|
import mage.abilities.common.SimpleStaticAbility;
|
||||||
import mage.abilities.dynamicvalue.DynamicValue;
|
import mage.abilities.dynamicvalue.DynamicValue;
|
||||||
import mage.abilities.dynamicvalue.common.CardsInControllerGraveyardCount;
|
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.abilities.hint.ValueHint;
|
||||||
import mage.cards.CardImpl;
|
import mage.cards.CardImpl;
|
||||||
import mage.cards.CardSetInfo;
|
import mage.cards.CardSetInfo;
|
||||||
|
|
@ -12,7 +13,6 @@ import mage.constants.CardType;
|
||||||
import mage.constants.SubType;
|
import mage.constants.SubType;
|
||||||
import mage.constants.Zone;
|
import mage.constants.Zone;
|
||||||
import mage.filter.StaticFilters;
|
import mage.filter.StaticFilters;
|
||||||
import mage.filter.common.FilterInstantOrSorceryCard;
|
|
||||||
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
|
|
@ -21,8 +21,6 @@ import java.util.UUID;
|
||||||
*/
|
*/
|
||||||
public final class CrypticSerpent extends CardImpl {
|
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) {
|
public CrypticSerpent(UUID ownerId, CardSetInfo setInfo) {
|
||||||
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{5}{U}{U}");
|
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);
|
this.toughness = new MageInt(5);
|
||||||
|
|
||||||
// Cryptic Serpent costs {1} less to cast for each instant and sorcery card in your graveyard.
|
// 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()))
|
DynamicValue xValue = new CardsInControllerGraveyardCount(StaticFilters.FILTER_CARD_INSTANT_AND_SORCERY);
|
||||||
.addHint(new ValueHint("Instant and sorcery card in your graveyard", cardsCount)));
|
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) {
|
public CrypticSerpent(final CrypticSerpent card) {
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,5 @@
|
||||||
|
|
||||||
package mage.cards.d;
|
package mage.cards.d;
|
||||||
|
|
||||||
import java.util.UUID;
|
|
||||||
import mage.abilities.Ability;
|
import mage.abilities.Ability;
|
||||||
import mage.abilities.common.SimpleStaticAbility;
|
import mage.abilities.common.SimpleStaticAbility;
|
||||||
import mage.abilities.effects.common.AttachEffect;
|
import mage.abilities.effects.common.AttachEffect;
|
||||||
|
|
@ -10,21 +8,22 @@ import mage.abilities.keyword.EnchantAbility;
|
||||||
import mage.cards.CardImpl;
|
import mage.cards.CardImpl;
|
||||||
import mage.cards.CardSetInfo;
|
import mage.cards.CardSetInfo;
|
||||||
import mage.constants.CardType;
|
import mage.constants.CardType;
|
||||||
import mage.constants.SubType;
|
|
||||||
import mage.constants.Outcome;
|
import mage.constants.Outcome;
|
||||||
|
import mage.constants.SubType;
|
||||||
import mage.constants.Zone;
|
import mage.constants.Zone;
|
||||||
import mage.game.Game;
|
import mage.game.Game;
|
||||||
import mage.game.permanent.Permanent;
|
import mage.game.permanent.Permanent;
|
||||||
import mage.target.TargetPermanent;
|
import mage.target.TargetPermanent;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
|
||||||
* @author maxlebedev
|
* @author maxlebedev
|
||||||
*/
|
*/
|
||||||
public final class DreamLeash extends CardImpl {
|
public final class DreamLeash extends CardImpl {
|
||||||
|
|
||||||
public DreamLeash(UUID ownerId, CardSetInfo setInfo) {
|
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);
|
this.subtype.add(SubType.AURA);
|
||||||
|
|
||||||
// Enchant permanent
|
// Enchant permanent
|
||||||
|
|
@ -55,7 +54,7 @@ class DreamLeashTarget extends TargetPermanent {
|
||||||
@Override
|
@Override
|
||||||
public boolean canTarget(UUID controllerId, UUID id, Ability source, Game game) {
|
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);
|
Permanent permanent = game.getPermanent(id);
|
||||||
return permanent.isTapped();
|
return permanent.isTapped();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,15 @@
|
||||||
package mage.cards.e;
|
package mage.cards.e;
|
||||||
|
|
||||||
import mage.abilities.Ability;
|
import mage.abilities.Ability;
|
||||||
import mage.abilities.SpellAbility;
|
|
||||||
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
|
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
|
||||||
import mage.abilities.common.SimpleStaticAbility;
|
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.AttachEffect;
|
||||||
import mage.abilities.effects.common.continuous.BoostEquippedEffect;
|
import mage.abilities.effects.common.continuous.BoostEquippedEffect;
|
||||||
import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect;
|
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.DoubleStrikeAbility;
|
||||||
import mage.abilities.keyword.EquipAbility;
|
import mage.abilities.keyword.EquipAbility;
|
||||||
import mage.abilities.keyword.FlashAbility;
|
import mage.abilities.keyword.FlashAbility;
|
||||||
|
|
@ -15,12 +17,8 @@ import mage.abilities.keyword.TrampleAbility;
|
||||||
import mage.cards.CardImpl;
|
import mage.cards.CardImpl;
|
||||||
import mage.cards.CardSetInfo;
|
import mage.cards.CardSetInfo;
|
||||||
import mage.constants.*;
|
import mage.constants.*;
|
||||||
import mage.filter.FilterPermanent;
|
import mage.filter.StaticFilters;
|
||||||
import mage.filter.common.FilterControlledCreaturePermanent;
|
|
||||||
import mage.filter.predicate.permanent.AttackingPredicate;
|
|
||||||
import mage.game.Game;
|
|
||||||
import mage.target.common.TargetControlledCreaturePermanent;
|
import mage.target.common.TargetControlledCreaturePermanent;
|
||||||
import mage.util.CardUtil;
|
|
||||||
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
|
|
@ -39,7 +37,10 @@ public final class Embercleave extends CardImpl {
|
||||||
this.addAbility(FlashAbility.getInstance());
|
this.addAbility(FlashAbility.getInstance());
|
||||||
|
|
||||||
// This spell costs {1} less to cast for each attacking creature you control.
|
// 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.
|
// When Embercleave enters the battlefield, attach it to target creature you control.
|
||||||
Ability ability = new EntersBattlefieldTriggeredAbility(new AttachEffect(
|
Ability ability = new EntersBattlefieldTriggeredAbility(new AttachEffect(
|
||||||
|
|
@ -71,41 +72,3 @@ public final class Embercleave extends CardImpl {
|
||||||
return new Embercleave(this);
|
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -2,21 +2,21 @@ package mage.cards.e;
|
||||||
|
|
||||||
import mage.MageInt;
|
import mage.MageInt;
|
||||||
import mage.abilities.Ability;
|
import mage.abilities.Ability;
|
||||||
import mage.abilities.SpellAbility;
|
|
||||||
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
|
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
|
||||||
import mage.abilities.common.SimpleActivatedAbility;
|
import mage.abilities.common.SimpleActivatedAbility;
|
||||||
import mage.abilities.common.SimpleStaticAbility;
|
import mage.abilities.common.SimpleStaticAbility;
|
||||||
import mage.abilities.costs.common.TapSourceCost;
|
import mage.abilities.costs.common.TapSourceCost;
|
||||||
|
import mage.abilities.dynamicvalue.common.ArtifactYouControlCount;
|
||||||
import mage.abilities.effects.AsThoughEffectImpl;
|
import mage.abilities.effects.AsThoughEffectImpl;
|
||||||
import mage.abilities.effects.common.PutTopCardOfLibraryIntoGraveControllerEffect;
|
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.CardImpl;
|
||||||
import mage.cards.CardSetInfo;
|
import mage.cards.CardSetInfo;
|
||||||
import mage.constants.*;
|
import mage.constants.*;
|
||||||
import mage.filter.StaticFilters;
|
import mage.filter.StaticFilters;
|
||||||
import mage.game.Game;
|
import mage.game.Game;
|
||||||
import mage.target.common.TargetCardInYourGraveyard;
|
import mage.target.common.TargetCardInYourGraveyard;
|
||||||
import mage.util.CardUtil;
|
|
||||||
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
|
|
@ -35,7 +35,9 @@ public final class EmryLurkerOfTheLoch extends CardImpl {
|
||||||
this.toughness = new MageInt(2);
|
this.toughness = new MageInt(2);
|
||||||
|
|
||||||
// This spell costs {1} less to cast for each artifact you control.
|
// 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.
|
// When Emry, Lurker of the Loch enters the battlefield, put the top four cards of your library into your graveyard.
|
||||||
this.addAbility(new EntersBattlefieldTriggeredAbility(
|
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 {
|
class EmryLurkerOfTheLochPlayEffect extends AsThoughEffectImpl {
|
||||||
|
|
||||||
EmryLurkerOfTheLochPlayEffect() {
|
EmryLurkerOfTheLochPlayEffect() {
|
||||||
|
|
|
||||||
|
|
@ -1,28 +1,26 @@
|
||||||
|
|
||||||
package mage.cards.f;
|
package mage.cards.f;
|
||||||
|
|
||||||
import java.util.UUID;
|
|
||||||
import mage.abilities.Ability;
|
import mage.abilities.Ability;
|
||||||
import mage.abilities.dynamicvalue.common.AttackingFilterCreatureCount;
|
import mage.abilities.dynamicvalue.common.AttackingCreatureCount;
|
||||||
import mage.abilities.effects.OneShotEffect;
|
import mage.abilities.effects.OneShotEffect;
|
||||||
import mage.cards.CardImpl;
|
import mage.cards.CardImpl;
|
||||||
import mage.cards.CardSetInfo;
|
import mage.cards.CardSetInfo;
|
||||||
import mage.constants.CardType;
|
import mage.constants.CardType;
|
||||||
import mage.constants.Outcome;
|
import mage.constants.Outcome;
|
||||||
import mage.constants.TargetController;
|
import mage.filter.StaticFilters;
|
||||||
import mage.filter.common.FilterCreaturePermanent;
|
|
||||||
import mage.game.Game;
|
import mage.game.Game;
|
||||||
import mage.players.Player;
|
import mage.players.Player;
|
||||||
import mage.target.common.TargetOpponent;
|
import mage.target.common.TargetOpponent;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
|
||||||
* @author LevelX2
|
* @author LevelX2
|
||||||
*/
|
*/
|
||||||
public final class FoulTongueShriek extends CardImpl {
|
public final class FoulTongueShriek extends CardImpl {
|
||||||
|
|
||||||
public FoulTongueShriek(UUID ownerId, CardSetInfo setInfo) {
|
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.
|
// Target opponent loses 1 life for each attacking creature you control. You gain that much life.
|
||||||
this.getSpellAbility().addEffect(new FoulTongueShriekEffect());
|
this.getSpellAbility().addEffect(new FoulTongueShriekEffect());
|
||||||
|
|
@ -41,12 +39,7 @@ public final class FoulTongueShriek extends CardImpl {
|
||||||
}
|
}
|
||||||
|
|
||||||
class FoulTongueShriekEffect extends OneShotEffect {
|
class FoulTongueShriekEffect extends OneShotEffect {
|
||||||
|
|
||||||
private static final FilterCreaturePermanent filter = new FilterCreaturePermanent();
|
|
||||||
static {
|
|
||||||
filter.add(TargetController.YOU.getControllerPredicate());
|
|
||||||
}
|
|
||||||
|
|
||||||
public FoulTongueShriekEffect() {
|
public FoulTongueShriekEffect() {
|
||||||
super(Outcome.Benefit);
|
super(Outcome.Benefit);
|
||||||
this.staticText = "Target opponent loses 1 life for each attacking creature you control. You gain that much life";
|
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 controller = game.getPlayer(source.getControllerId());
|
||||||
Player targetOpponent = game.getPlayer(getTargetPointer().getFirst(game, source));
|
Player targetOpponent = game.getPlayer(getTargetPointer().getFirst(game, source));
|
||||||
if (controller != null && targetOpponent != null) {
|
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) {
|
if (amount > 0) {
|
||||||
targetOpponent.loseLife(amount, game, false);
|
targetOpponent.loseLife(amount, game, false);
|
||||||
controller.gainLife(amount, game, source);
|
controller.gainLife(amount, game, source);
|
||||||
|
|
|
||||||
|
|
@ -5,9 +5,11 @@ import mage.abilities.Ability;
|
||||||
import mage.abilities.common.EntersBattlefieldAllTriggeredAbility;
|
import mage.abilities.common.EntersBattlefieldAllTriggeredAbility;
|
||||||
import mage.abilities.common.SimpleEvasionAbility;
|
import mage.abilities.common.SimpleEvasionAbility;
|
||||||
import mage.abilities.common.SimpleStaticAbility;
|
import mage.abilities.common.SimpleStaticAbility;
|
||||||
|
import mage.abilities.dynamicvalue.common.GateYouControlCount;
|
||||||
import mage.abilities.effects.common.PutOnLibrarySourceEffect;
|
import mage.abilities.effects.common.PutOnLibrarySourceEffect;
|
||||||
import mage.abilities.effects.common.combat.CantBeBlockedByCreaturesSourceEffect;
|
import mage.abilities.effects.common.combat.CantBeBlockedByCreaturesSourceEffect;
|
||||||
import mage.abilities.effects.common.cost.CostModificationEffectImpl;
|
import mage.abilities.effects.common.cost.CostModificationEffectImpl;
|
||||||
|
import mage.abilities.effects.common.cost.SpellCostReductionForEachSourceEffect;
|
||||||
import mage.abilities.hint.common.GateYouControlHint;
|
import mage.abilities.hint.common.GateYouControlHint;
|
||||||
import mage.cards.CardImpl;
|
import mage.cards.CardImpl;
|
||||||
import mage.cards.CardSetInfo;
|
import mage.cards.CardSetInfo;
|
||||||
|
|
@ -39,8 +41,10 @@ public final class GateColossus extends CardImpl {
|
||||||
this.toughness = new MageInt(8);
|
this.toughness = new MageInt(8);
|
||||||
|
|
||||||
// This spell costs {1} less to cast for each Gate you control.
|
// This spell costs {1} less to cast for each Gate you control.
|
||||||
this.addAbility(new SimpleStaticAbility(Zone.ALL, new GateColossusCostReductionEffect())
|
this.addAbility(new SimpleStaticAbility(Zone.ALL,
|
||||||
.addHint(GateYouControlHint.instance));
|
new SpellCostReductionForEachSourceEffect(1, GateYouControlCount.instance))
|
||||||
|
.addHint(GateYouControlHint.instance)
|
||||||
|
);
|
||||||
|
|
||||||
// Gate Colossus can't be blocked by creatures with power 2 or less.
|
// Gate Colossus can't be blocked by creatures with power 2 or less.
|
||||||
this.addAbility(new SimpleEvasionAbility(new CantBeBlockedByCreaturesSourceEffect(filter, Duration.WhileOnBattlefield)));
|
this.addAbility(new SimpleEvasionAbility(new CantBeBlockedByCreaturesSourceEffect(filter, Duration.WhileOnBattlefield)));
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@ public final class GatekeeperGargoyle extends CardImpl {
|
||||||
// Flying
|
// Flying
|
||||||
this.addAbility(FlyingAbility.getInstance());
|
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(
|
this.addAbility(new EntersBattlefieldAbility(
|
||||||
new AddCountersSourceEffect(
|
new AddCountersSourceEffect(
|
||||||
CounterType.P1P1.createInstance(),
|
CounterType.P1P1.createInstance(),
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,19 @@
|
||||||
package mage.cards.g;
|
package mage.cards.g;
|
||||||
|
|
||||||
import mage.MageInt;
|
import mage.MageInt;
|
||||||
import mage.abilities.Ability;
|
|
||||||
import mage.abilities.common.SimpleActivatedAbility;
|
import mage.abilities.common.SimpleActivatedAbility;
|
||||||
import mage.abilities.common.SimpleStaticAbility;
|
import mage.abilities.common.SimpleStaticAbility;
|
||||||
import mage.abilities.costs.mana.ManaCostsImpl;
|
import mage.abilities.costs.mana.ManaCostsImpl;
|
||||||
|
import mage.abilities.dynamicvalue.common.ArtifactYouControlCount;
|
||||||
import mage.abilities.effects.common.combat.CantBeBlockedSourceEffect;
|
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.CardImpl;
|
||||||
import mage.cards.CardSetInfo;
|
import mage.cards.CardSetInfo;
|
||||||
import mage.constants.*;
|
import mage.constants.CardType;
|
||||||
import mage.filter.common.FilterControlledPermanent;
|
import mage.constants.Duration;
|
||||||
import mage.game.Game;
|
import mage.constants.SubType;
|
||||||
import mage.util.CardUtil;
|
import mage.constants.Zone;
|
||||||
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
|
|
@ -28,7 +29,9 @@ public final class GearseekerSerpent extends CardImpl {
|
||||||
this.toughness = new MageInt(6);
|
this.toughness = new MageInt(6);
|
||||||
|
|
||||||
// Gearseeker Serpent costs {1} less to cast for each artifact you control
|
// 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.
|
// 5U: Gearseeker Serpent can't be blocked this turn.
|
||||||
this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD,
|
this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD,
|
||||||
|
|
@ -45,38 +48,3 @@ public final class GearseekerSerpent extends CardImpl {
|
||||||
return new GearseekerSerpent(this);
|
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,12 @@
|
||||||
package mage.cards.g;
|
package mage.cards.g;
|
||||||
|
|
||||||
import java.util.UUID;
|
|
||||||
import mage.MageInt;
|
import mage.MageInt;
|
||||||
|
import mage.abilities.Ability;
|
||||||
import mage.abilities.common.SimpleStaticAbility;
|
import mage.abilities.common.SimpleStaticAbility;
|
||||||
import mage.abilities.effects.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.CardImpl;
|
||||||
import mage.cards.CardSetInfo;
|
import mage.cards.CardSetInfo;
|
||||||
import mage.constants.CardType;
|
import mage.constants.CardType;
|
||||||
|
|
@ -11,8 +14,9 @@ import mage.constants.SubType;
|
||||||
import mage.constants.Zone;
|
import mage.constants.Zone;
|
||||||
import mage.filter.StaticFilters;
|
import mage.filter.StaticFilters;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
|
||||||
* @author North
|
* @author North
|
||||||
*/
|
*/
|
||||||
public final class Ghoultree extends CardImpl {
|
public final class Ghoultree extends CardImpl {
|
||||||
|
|
@ -26,7 +30,11 @@ public final class Ghoultree extends CardImpl {
|
||||||
this.toughness = new MageInt(10);
|
this.toughness = new MageInt(10);
|
||||||
|
|
||||||
// Ghoultree costs {1} less to cast for each creature card in your graveyard.
|
// 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) {
|
public Ghoultree(final Ghoultree card) {
|
||||||
|
|
|
||||||
|
|
@ -29,10 +29,7 @@ public final class GlaiveOfTheGuildpact extends CardImpl {
|
||||||
this.subtype.add(SubType.EQUIPMENT);
|
this.subtype.add(SubType.EQUIPMENT);
|
||||||
|
|
||||||
// Equipped creature gets +1/+0 for each Gate you control and has vigilance and menace.
|
// Equipped creature gets +1/+0 for each Gate you control and has vigilance and menace.
|
||||||
Ability ability = new SimpleStaticAbility(new BoostEquippedEffect(
|
Ability ability = new SimpleStaticAbility(new BoostEquippedEffect(GateYouControlCount.instance, StaticValue.get(0)));
|
||||||
GateYouControlCount.instance,
|
|
||||||
StaticValue.get(0)
|
|
||||||
).setText("Equipped creature gets +1/+0 for each Gate you control"));
|
|
||||||
ability.addEffect(new GainAbilityAttachedEffect(
|
ability.addEffect(new GainAbilityAttachedEffect(
|
||||||
VigilanceAbility.getInstance(), AttachmentType.EQUIPMENT
|
VigilanceAbility.getInstance(), AttachmentType.EQUIPMENT
|
||||||
).setText("and has vigilance"));
|
).setText("and has vigilance"));
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ import mage.cards.CardSetInfo;
|
||||||
import mage.constants.CardType;
|
import mage.constants.CardType;
|
||||||
import mage.constants.Duration;
|
import mage.constants.Duration;
|
||||||
import mage.constants.Zone;
|
import mage.constants.Zone;
|
||||||
import mage.filter.common.FilterControlledCreaturePermanent;
|
import mage.filter.StaticFilters;
|
||||||
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
|
|
@ -25,13 +25,14 @@ public final class HoldTheGates extends CardImpl {
|
||||||
public HoldTheGates(UUID ownerId, CardSetInfo setInfo) {
|
public HoldTheGates(UUID ownerId, CardSetInfo setInfo) {
|
||||||
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{W}");
|
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{W}");
|
||||||
|
|
||||||
|
|
||||||
// Creatures you control get +0/+1 for each Gate you control and have vigilance.
|
// Creatures you control get +0/+1 for each Gate you control and have vigilance.
|
||||||
Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD,
|
Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD,
|
||||||
new BoostControlledEffect(StaticValue.get(0), GateYouControlCount.instance, Duration.WhileOnBattlefield)
|
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"))
|
ability.addEffect(
|
||||||
.setText("and have vigilance"));
|
new GainAbilityControlledEffect(VigilanceAbility.getInstance(), Duration.WhileOnBattlefield, StaticFilters.FILTER_PERMANENT_CREATURES_CONTROLLED)
|
||||||
|
.setText("and have vigilance")
|
||||||
|
);
|
||||||
ability.addHint(GateYouControlHint.instance);
|
ability.addHint(GateYouControlHint.instance);
|
||||||
this.addAbility(ability);
|
this.addAbility(ability);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,48 +1,52 @@
|
||||||
|
|
||||||
package mage.cards.k;
|
package mage.cards.k;
|
||||||
|
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.UUID;
|
|
||||||
import mage.MageInt;
|
import mage.MageInt;
|
||||||
import mage.ObjectColor;
|
import mage.ObjectColor;
|
||||||
import mage.abilities.Ability;
|
|
||||||
import mage.abilities.common.SimpleStaticAbility;
|
import mage.abilities.common.SimpleStaticAbility;
|
||||||
import mage.abilities.costs.mana.ManaCost;
|
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.abilities.keyword.TrampleAbility;
|
||||||
import mage.cards.CardImpl;
|
import mage.cards.CardImpl;
|
||||||
import mage.cards.CardSetInfo;
|
import mage.cards.CardSetInfo;
|
||||||
import mage.constants.CardType;
|
import mage.constants.CardType;
|
||||||
import mage.constants.SubType;
|
import mage.constants.SubType;
|
||||||
import mage.constants.Outcome;
|
|
||||||
import mage.constants.Zone;
|
import mage.constants.Zone;
|
||||||
import mage.filter.common.FilterControlledCreaturePermanent;
|
import mage.filter.common.FilterControlledCreaturePermanent;
|
||||||
import mage.filter.predicate.mageobject.ColorPredicate;
|
import mage.filter.predicate.mageobject.ColorPredicate;
|
||||||
import mage.game.Game;
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
|
||||||
* @author maurer.it_at_gmail.com
|
* @author maurer.it_at_gmail.com
|
||||||
*/
|
*/
|
||||||
public final class KhalniHydra extends CardImpl {
|
public final class KhalniHydra extends CardImpl {
|
||||||
|
|
||||||
private static final FilterControlledCreaturePermanent filter;
|
private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("green creature you control");
|
||||||
|
|
||||||
static {
|
static {
|
||||||
filter = new FilterControlledCreaturePermanent();
|
|
||||||
filter.add(new ColorPredicate(ObjectColor.GREEN));
|
filter.add(new ColorPredicate(ObjectColor.GREEN));
|
||||||
}
|
}
|
||||||
|
|
||||||
public KhalniHydra(UUID ownerId, CardSetInfo setInfo) {
|
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.subtype.add(SubType.HYDRA);
|
||||||
|
|
||||||
this.power = new MageInt(8);
|
this.power = new MageInt(8);
|
||||||
this.toughness = new MageInt(8);
|
this.toughness = new MageInt(8);
|
||||||
|
|
||||||
// This spell costs {G} less to cast for each green creature you control.
|
// 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
|
// Trample
|
||||||
this.addAbility(TrampleAbility.getInstance());
|
this.addAbility(TrampleAbility.getInstance());
|
||||||
}
|
}
|
||||||
|
|
@ -51,47 +55,8 @@ public final class KhalniHydra extends CardImpl {
|
||||||
super(card);
|
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
|
@Override
|
||||||
public KhalniHydra copy() {
|
public KhalniHydra copy() {
|
||||||
return new KhalniHydra(this);
|
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -1,25 +1,28 @@
|
||||||
package mage.cards.m;
|
package mage.cards.m;
|
||||||
|
|
||||||
import java.util.UUID;
|
|
||||||
import mage.MageInt;
|
import mage.MageInt;
|
||||||
import mage.abilities.Ability;
|
import mage.abilities.Ability;
|
||||||
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
|
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
|
||||||
import mage.abilities.common.SimpleStaticAbility;
|
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.ReturnFromGraveyardToBattlefieldTargetEffect;
|
||||||
import mage.abilities.effects.common.cost.SourceCostReductionForEachCardInGraveyardEffect;
|
import mage.abilities.effects.common.cost.SpellCostReductionForEachSourceEffect;
|
||||||
import mage.constants.SubType;
|
import mage.abilities.hint.ValueHint;
|
||||||
import mage.cards.CardImpl;
|
import mage.cards.CardImpl;
|
||||||
import mage.cards.CardSetInfo;
|
import mage.cards.CardSetInfo;
|
||||||
import mage.constants.AbilityWord;
|
import mage.constants.AbilityWord;
|
||||||
import mage.constants.CardType;
|
import mage.constants.CardType;
|
||||||
|
import mage.constants.SubType;
|
||||||
import mage.constants.Zone;
|
import mage.constants.Zone;
|
||||||
import mage.filter.FilterCard;
|
import mage.filter.FilterCard;
|
||||||
import mage.filter.StaticFilters;
|
import mage.filter.StaticFilters;
|
||||||
import mage.filter.common.FilterLandCard;
|
import mage.filter.common.FilterLandCard;
|
||||||
import mage.target.common.TargetCardInYourGraveyard;
|
import mage.target.common.TargetCardInYourGraveyard;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
|
||||||
* @author TheElk801
|
* @author TheElk801
|
||||||
*/
|
*/
|
||||||
public final class Molderhulk extends CardImpl {
|
public final class Molderhulk extends CardImpl {
|
||||||
|
|
@ -36,8 +39,11 @@ public final class Molderhulk extends CardImpl {
|
||||||
this.toughness = new MageInt(6);
|
this.toughness = new MageInt(6);
|
||||||
|
|
||||||
// Undergrowth — This spell costs {1} less to cast for each creature card in your graveyard.
|
// 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.setAbilityWord(AbilityWord.UNDERGROWTH);
|
||||||
|
ability.setRuleAtTheTop(true);
|
||||||
|
ability.addHint(new ValueHint("Creature card in your graveyard", xValue));
|
||||||
this.addAbility(ability);
|
this.addAbility(ability);
|
||||||
|
|
||||||
// When Molderhulk enters the battlefield, return target land card from your graveyard to the battlefield.
|
// When Molderhulk enters the battlefield, return target land card from your graveyard to the battlefield.
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,14 @@
|
||||||
package mage.cards.n;
|
package mage.cards.n;
|
||||||
|
|
||||||
import java.util.UUID;
|
|
||||||
import mage.MageInt;
|
import mage.MageInt;
|
||||||
import mage.abilities.Ability;
|
import mage.abilities.Ability;
|
||||||
import mage.abilities.common.SimpleStaticAbility;
|
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.Effect;
|
||||||
import mage.abilities.effects.common.cost.CostModificationEffectImpl;
|
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.abilities.keyword.MonstrosityAbility;
|
||||||
import mage.cards.CardImpl;
|
import mage.cards.CardImpl;
|
||||||
import mage.cards.CardSetInfo;
|
import mage.cards.CardSetInfo;
|
||||||
|
|
@ -16,6 +18,8 @@ import mage.game.Game;
|
||||||
import mage.players.Player;
|
import mage.players.Player;
|
||||||
import mage.util.CardUtil;
|
import mage.util.CardUtil;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author LevelX2
|
* @author LevelX2
|
||||||
*/
|
*/
|
||||||
|
|
@ -29,8 +33,10 @@ public final class NemesisOfMortals extends CardImpl {
|
||||||
this.toughness = new MageInt(5);
|
this.toughness = new MageInt(5);
|
||||||
|
|
||||||
// Nemesis of Mortals costs {1} less to cast for each creature card in your graveyard.
|
// 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.setRuleAtTheTop(true);
|
||||||
|
ability.addHint(new ValueHint("Creature card in your graveyard", xValue));
|
||||||
this.addAbility(ability);
|
this.addAbility(ability);
|
||||||
|
|
||||||
// {7}{G}{G}: Monstrosity 5. This ability costs {1} less to activate for each creature card in your graveyard.
|
// {7}{G}{G}: Monstrosity 5. This ability costs {1} less to activate for each creature card in your graveyard.
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,10 @@ package mage.cards.o;
|
||||||
import mage.MageInt;
|
import mage.MageInt;
|
||||||
import mage.abilities.Ability;
|
import mage.abilities.Ability;
|
||||||
import mage.abilities.common.SimpleStaticAbility;
|
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.FlyingAbility;
|
||||||
import mage.abilities.keyword.HasteAbility;
|
import mage.abilities.keyword.HasteAbility;
|
||||||
import mage.cards.CardImpl;
|
import mage.cards.CardImpl;
|
||||||
|
|
@ -28,10 +31,10 @@ public final class OreScaleGuardian extends CardImpl {
|
||||||
this.toughness = new MageInt(4);
|
this.toughness = new MageInt(4);
|
||||||
|
|
||||||
// This spell costs {1} less to cast for each land card in your graveyard.
|
// This spell costs {1} less to cast for each land card in your graveyard.
|
||||||
Ability ability = new SimpleStaticAbility(
|
DynamicValue xValue = new CardsInControllerGraveyardCount(StaticFilters.FILTER_CARD_LAND);
|
||||||
Zone.ALL, new SourceCostReductionForEachCardInGraveyardEffect(StaticFilters.FILTER_CARD_LAND)
|
Ability ability = new SimpleStaticAbility(Zone.ALL, new SpellCostReductionForEachSourceEffect(1, xValue));
|
||||||
);
|
|
||||||
ability.setRuleAtTheTop(true);
|
ability.setRuleAtTheTop(true);
|
||||||
|
ability.addHint(new ValueHint("Land card in your graveyard", xValue));
|
||||||
this.addAbility(ability);
|
this.addAbility(ability);
|
||||||
|
|
||||||
// Flying
|
// Flying
|
||||||
|
|
|
||||||
|
|
@ -1,25 +1,25 @@
|
||||||
package mage.cards.t;
|
package mage.cards.t;
|
||||||
|
|
||||||
import mage.MageObject;
|
|
||||||
import mage.abilities.Ability;
|
import mage.abilities.Ability;
|
||||||
import mage.abilities.SpellAbility;
|
|
||||||
import mage.abilities.common.ActivateAsSorceryActivatedAbility;
|
import mage.abilities.common.ActivateAsSorceryActivatedAbility;
|
||||||
import mage.abilities.common.DiesCreatureTriggeredAbility;
|
import mage.abilities.common.DiesCreatureTriggeredAbility;
|
||||||
import mage.abilities.common.SimpleStaticAbility;
|
import mage.abilities.common.SimpleStaticAbility;
|
||||||
import mage.abilities.costs.common.PayLifeCost;
|
import mage.abilities.costs.common.PayLifeCost;
|
||||||
import mage.abilities.costs.common.TapSourceCost;
|
import mage.abilities.costs.common.TapSourceCost;
|
||||||
import mage.abilities.costs.mana.ManaCostsImpl;
|
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.PutOnLibraryTargetEffect;
|
||||||
import mage.abilities.effects.common.ReturnFromGraveyardToBattlefieldTargetEffect;
|
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.CardImpl;
|
||||||
import mage.cards.CardSetInfo;
|
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.filter.StaticFilters;
|
||||||
import mage.game.Game;
|
|
||||||
import mage.players.Player;
|
|
||||||
import mage.target.common.TargetCardInYourGraveyard;
|
import mage.target.common.TargetCardInYourGraveyard;
|
||||||
import mage.util.CardUtil;
|
|
||||||
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
|
|
@ -34,7 +34,11 @@ public final class TheCauldronOfEternity extends CardImpl {
|
||||||
this.addSuperType(SuperType.LEGENDARY);
|
this.addSuperType(SuperType.LEGENDARY);
|
||||||
|
|
||||||
// This spell costs {2} less to cast for each creature card in your graveyard.
|
// 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.
|
// Whenever a creature you control dies, put it on the bottom of its owner's library.
|
||||||
this.addAbility(new DiesCreatureTriggeredAbility(
|
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.
|
// {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}")
|
Zone.BATTLEFIELD, new ReturnFromGraveyardToBattlefieldTargetEffect(), new ManaCostsImpl("{2}{B}")
|
||||||
);
|
);
|
||||||
ability.addCost(new TapSourceCost());
|
ability.addCost(new TapSourceCost());
|
||||||
|
|
@ -61,44 +65,3 @@ public final class TheCauldronOfEternity extends CardImpl {
|
||||||
return new TheCauldronOfEternity(this);
|
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -1,24 +1,23 @@
|
||||||
package mage.cards.t;
|
package mage.cards.t;
|
||||||
|
|
||||||
import mage.abilities.Ability;
|
import mage.abilities.Ability;
|
||||||
import mage.abilities.SpellAbility;
|
|
||||||
import mage.abilities.common.SimpleActivatedAbility;
|
import mage.abilities.common.SimpleActivatedAbility;
|
||||||
import mage.abilities.common.SimpleStaticAbility;
|
import mage.abilities.common.SimpleStaticAbility;
|
||||||
import mage.abilities.common.SpellCastControllerTriggeredAbility;
|
import mage.abilities.common.SpellCastControllerTriggeredAbility;
|
||||||
import mage.abilities.costs.common.TapSourceCost;
|
import mage.abilities.costs.common.TapSourceCost;
|
||||||
import mage.abilities.costs.mana.ManaCostsImpl;
|
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.CreateTokenEffect;
|
||||||
import mage.abilities.effects.common.continuous.BoostControlledEffect;
|
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.CardImpl;
|
||||||
import mage.cards.CardSetInfo;
|
import mage.cards.CardSetInfo;
|
||||||
import mage.constants.*;
|
import mage.constants.*;
|
||||||
import mage.filter.FilterPermanent;
|
|
||||||
import mage.filter.FilterSpell;
|
import mage.filter.FilterSpell;
|
||||||
import mage.filter.common.FilterControlledPermanent;
|
import mage.filter.common.FilterControlledPermanent;
|
||||||
import mage.game.Game;
|
|
||||||
import mage.game.permanent.token.KnightToken;
|
import mage.game.permanent.token.KnightToken;
|
||||||
import mage.util.CardUtil;
|
|
||||||
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
|
|
@ -27,10 +26,16 @@ import java.util.UUID;
|
||||||
*/
|
*/
|
||||||
public final class TheCircleOfLoyalty extends CardImpl {
|
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 {
|
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) {
|
public TheCircleOfLoyalty(UUID ownerId, CardSetInfo setInfo) {
|
||||||
|
|
@ -39,7 +44,10 @@ public final class TheCircleOfLoyalty extends CardImpl {
|
||||||
this.addSuperType(SuperType.LEGENDARY);
|
this.addSuperType(SuperType.LEGENDARY);
|
||||||
|
|
||||||
// This spell costs {1} less to cast for each Knight you control.
|
// 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.
|
// Creatures you control get +1/+1.
|
||||||
this.addAbility(new SimpleStaticAbility(
|
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.
|
// Whenever you cast a legendary spell, create a 2/2 white Knight creature token with vigilance.
|
||||||
this.addAbility(new SpellCastControllerTriggeredAbility(
|
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.
|
// {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() {
|
public TheCircleOfLoyalty copy() {
|
||||||
return new TheCircleOfLoyalty(this);
|
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -4,11 +4,13 @@ import mage.abilities.Ability;
|
||||||
import mage.abilities.common.BeginningOfUpkeepTriggeredAbility;
|
import mage.abilities.common.BeginningOfUpkeepTriggeredAbility;
|
||||||
import mage.abilities.common.SimpleStaticAbility;
|
import mage.abilities.common.SimpleStaticAbility;
|
||||||
import mage.abilities.dynamicvalue.DynamicValue;
|
import mage.abilities.dynamicvalue.DynamicValue;
|
||||||
|
import mage.abilities.dynamicvalue.common.CardsInControllerGraveyardCount;
|
||||||
import mage.abilities.dynamicvalue.common.CountersSourceCount;
|
import mage.abilities.dynamicvalue.common.CountersSourceCount;
|
||||||
import mage.abilities.effects.common.DrawCardSourceControllerEffect;
|
import mage.abilities.effects.common.DrawCardSourceControllerEffect;
|
||||||
import mage.abilities.effects.common.continuous.MaximumHandSizeControllerEffect;
|
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.effects.common.counter.AddCountersSourceEffect;
|
||||||
|
import mage.abilities.hint.ValueHint;
|
||||||
import mage.cards.CardImpl;
|
import mage.cards.CardImpl;
|
||||||
import mage.cards.CardSetInfo;
|
import mage.cards.CardSetInfo;
|
||||||
import mage.constants.*;
|
import mage.constants.*;
|
||||||
|
|
@ -30,10 +32,11 @@ public final class TheMagicMirror extends CardImpl {
|
||||||
this.addSuperType(SuperType.LEGENDARY);
|
this.addSuperType(SuperType.LEGENDARY);
|
||||||
|
|
||||||
// This spell costs {1} less to cast for each instant and sorcery card in your graveyard.
|
// This spell costs {1} less to cast for each instant and sorcery card in your graveyard.
|
||||||
this.addAbility(new SimpleStaticAbility(
|
DynamicValue xValue = new CardsInControllerGraveyardCount(StaticFilters.FILTER_CARD_INSTANT_AND_SORCERY);
|
||||||
Zone.ALL, new SourceCostReductionForEachCardInGraveyardEffect(
|
Ability ability = new SimpleStaticAbility(Zone.ALL, new SpellCostReductionForEachSourceEffect(1, xValue));
|
||||||
StaticFilters.FILTER_CARD_INSTANT_AND_SORCERY
|
ability.setRuleAtTheTop(true);
|
||||||
)).setRuleAtTheTop(true));
|
ability.addHint(new ValueHint("Instant and sorcery card in your graveyard", xValue));
|
||||||
|
this.addAbility(ability);
|
||||||
|
|
||||||
// You have no maximum hand size.
|
// You have no maximum hand size.
|
||||||
this.addAbility(new SimpleStaticAbility(new MaximumHandSizeControllerEffect(
|
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.
|
// 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())
|
new AddCountersSourceEffect(CounterType.KNOWLEDGE.createInstance())
|
||||||
.setText("put a knowledge counter on {this},"),
|
.setText("put a knowledge counter on {this},"),
|
||||||
TargetController.YOU, false
|
TargetController.YOU, false
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,5 @@
|
||||||
|
|
||||||
package mage.cards.t;
|
package mage.cards.t;
|
||||||
|
|
||||||
import java.util.UUID;
|
|
||||||
import mage.MageInt;
|
import mage.MageInt;
|
||||||
import mage.abilities.Ability;
|
import mage.abilities.Ability;
|
||||||
import mage.abilities.SpellAbility;
|
import mage.abilities.SpellAbility;
|
||||||
|
|
@ -13,21 +11,16 @@ import mage.abilities.effects.OneShotEffect;
|
||||||
import mage.abilities.effects.common.cost.CostModificationEffectImpl;
|
import mage.abilities.effects.common.cost.CostModificationEffectImpl;
|
||||||
import mage.cards.CardImpl;
|
import mage.cards.CardImpl;
|
||||||
import mage.cards.CardSetInfo;
|
import mage.cards.CardSetInfo;
|
||||||
import mage.constants.CardType;
|
import mage.constants.*;
|
||||||
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.filter.StaticFilters;
|
import mage.filter.StaticFilters;
|
||||||
import mage.game.Game;
|
import mage.game.Game;
|
||||||
import mage.players.Player;
|
import mage.players.Player;
|
||||||
import mage.target.TargetPlayer;
|
import mage.target.TargetPlayer;
|
||||||
import mage.util.CardUtil;
|
import mage.util.CardUtil;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
|
||||||
* @author LevelX2
|
* @author LevelX2
|
||||||
*/
|
*/
|
||||||
public final class TorgaarFamineIncarnate extends CardImpl {
|
public final class TorgaarFamineIncarnate extends CardImpl {
|
||||||
|
|
@ -107,8 +100,16 @@ class TorgaarFamineIncarnateEffectCostReductionEffect extends CostModificationEf
|
||||||
SpellAbility spellAbility = (SpellAbility) abilityToModify;
|
SpellAbility spellAbility = (SpellAbility) abilityToModify;
|
||||||
for (Cost cost : spellAbility.getCosts()) {
|
for (Cost cost : spellAbility.getCosts()) {
|
||||||
if (cost instanceof SacrificeXTargetCost) {
|
if (cost instanceof SacrificeXTargetCost) {
|
||||||
int reduction = ((SacrificeXTargetCost) cost).getAmount();
|
if (game.inCheckPlayableState()) {
|
||||||
CardUtil.adjustCost(spellAbility, reduction * 2);
|
// 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;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1663,16 +1663,20 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement
|
||||||
|
|
||||||
public void attack(int turnNum, TestPlayer player, String attacker) {
|
public void attack(int turnNum, TestPlayer player, String attacker) {
|
||||||
//Assert.assertNotEquals("", attacker);
|
//Assert.assertNotEquals("", attacker);
|
||||||
|
assertAliaseSupportInActivateCommand(attacker, false); // it uses old special notation like card_name:index
|
||||||
player.addAction(turnNum, PhaseStep.DECLARE_ATTACKERS, "attack:" + attacker);
|
player.addAction(turnNum, PhaseStep.DECLARE_ATTACKERS, "attack:" + attacker);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void attack(int turnNum, TestPlayer player, String attacker, TestPlayer defendingPlayer) {
|
public void attack(int turnNum, TestPlayer player, String attacker, TestPlayer defendingPlayer) {
|
||||||
//Assert.assertNotEquals("", attacker);
|
//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());
|
player.addAction(turnNum, PhaseStep.DECLARE_ATTACKERS, "attack:" + attacker + "$defendingPlayer=" + defendingPlayer.getName());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void attack(int turnNum, TestPlayer player, String attacker, String planeswalker) {
|
public void attack(int turnNum, TestPlayer player, String attacker, String planeswalker) {
|
||||||
//Assert.assertNotEquals("", attacker);
|
//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());
|
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) {
|
public void block(int turnNum, TestPlayer player, String blocker, String attacker) {
|
||||||
//Assert.assertNotEquals("", blocker);
|
//Assert.assertNotEquals("", blocker);
|
||||||
//Assert.assertNotEquals("", attacker);
|
//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);
|
player.addAction(turnNum, PhaseStep.DECLARE_BLOCKERS, "block:" + blocker + '$' + attacker);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,38 +1,60 @@
|
||||||
|
|
||||||
package mage.abilities.dynamicvalue.common;
|
package mage.abilities.dynamicvalue.common;
|
||||||
|
|
||||||
import mage.abilities.Ability;
|
import mage.abilities.Ability;
|
||||||
import mage.abilities.dynamicvalue.DynamicValue;
|
import mage.abilities.dynamicvalue.DynamicValue;
|
||||||
import mage.abilities.effects.Effect;
|
import mage.abilities.effects.Effect;
|
||||||
|
import mage.filter.common.FilterCreaturePermanent;
|
||||||
import mage.game.Game;
|
import mage.game.Game;
|
||||||
import mage.game.combat.CombatGroup;
|
import mage.game.combat.CombatGroup;
|
||||||
|
import mage.game.permanent.Permanent;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
|
||||||
* @author LevelX2
|
* @author LevelX2
|
||||||
*/
|
*/
|
||||||
public class AttackingCreatureCount implements DynamicValue {
|
public class AttackingCreatureCount implements DynamicValue {
|
||||||
|
|
||||||
private String message;
|
private String message;
|
||||||
|
private FilterCreaturePermanent filter;
|
||||||
|
|
||||||
public AttackingCreatureCount() {
|
public AttackingCreatureCount() {
|
||||||
this("attacking creature");
|
this("attacking creature");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public AttackingCreatureCount(FilterCreaturePermanent filter) {
|
||||||
|
this(filter, "attacking " + filter.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
public AttackingCreatureCount(String message) {
|
public AttackingCreatureCount(String message) {
|
||||||
|
this(null, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public AttackingCreatureCount(FilterCreaturePermanent filter, String message) {
|
||||||
this.message = message;
|
this.message = message;
|
||||||
|
this.filter = filter;
|
||||||
}
|
}
|
||||||
|
|
||||||
public AttackingCreatureCount(final AttackingCreatureCount dynamicValue) {
|
public AttackingCreatureCount(final AttackingCreatureCount dynamicValue) {
|
||||||
super();
|
super();
|
||||||
this.message = dynamicValue.message;
|
this.message = dynamicValue.message;
|
||||||
|
this.filter = dynamicValue.filter;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int calculate(Game game, Ability sourceAbility, Effect effect) {
|
public int calculate(Game game, Ability sourceAbility, Effect effect) {
|
||||||
int count = 0;
|
int count = 0;
|
||||||
for (CombatGroup combatGroup : game.getCombat().getGroups()) {
|
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;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -32,11 +32,11 @@ public enum GateYouControlCount implements DynamicValue {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "X";
|
return "1"; // uses "for each" effects, so must be 1, not X
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getMessage() {
|
public String getMessage() {
|
||||||
return "gate you control";
|
return "Gate you control";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,5 @@
|
||||||
|
|
||||||
package mage.abilities.effects.common.continuous;
|
package mage.abilities.effects.common.continuous;
|
||||||
|
|
||||||
import java.util.Iterator;
|
|
||||||
import mage.MageObjectReference;
|
import mage.MageObjectReference;
|
||||||
import mage.abilities.Ability;
|
import mage.abilities.Ability;
|
||||||
import mage.abilities.dynamicvalue.DynamicValue;
|
import mage.abilities.dynamicvalue.DynamicValue;
|
||||||
|
|
@ -16,8 +14,9 @@ import mage.filter.common.FilterCreaturePermanent;
|
||||||
import mage.game.Game;
|
import mage.game.Game;
|
||||||
import mage.game.permanent.Permanent;
|
import mage.game.permanent.Permanent;
|
||||||
|
|
||||||
|
import java.util.Iterator;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
|
||||||
* @author BetaSteward_at_googlemail.com
|
* @author BetaSteward_at_googlemail.com
|
||||||
*/
|
*/
|
||||||
public class BoostControlledEffect extends ContinuousEffectImpl {
|
public class BoostControlledEffect extends ContinuousEffectImpl {
|
||||||
|
|
@ -56,10 +55,10 @@ public class BoostControlledEffect extends ContinuousEffectImpl {
|
||||||
* @param power
|
* @param power
|
||||||
* @param toughness
|
* @param toughness
|
||||||
* @param duration
|
* @param duration
|
||||||
* @param filter AnotherPredicate is not working, you need to use the
|
* @param filter AnotherPredicate is not working, you need to use the
|
||||||
* excludeSource option
|
* excludeSource option
|
||||||
* @param lockedIn if true, power and toughness will be calculated only
|
* @param lockedIn if true, power and toughness will be calculated only
|
||||||
* once, when the ability resolves
|
* once, when the ability resolves
|
||||||
* @param excludeSource
|
* @param excludeSource
|
||||||
*/
|
*/
|
||||||
public BoostControlledEffect(DynamicValue power, DynamicValue toughness, Duration duration, FilterCreaturePermanent filter, boolean excludeSource, boolean lockedIn) {
|
public BoostControlledEffect(DynamicValue power, DynamicValue toughness, Duration duration, FilterCreaturePermanent filter, boolean excludeSource, boolean lockedIn) {
|
||||||
|
|
@ -105,7 +104,7 @@ public class BoostControlledEffect extends ContinuousEffectImpl {
|
||||||
@Override
|
@Override
|
||||||
public boolean apply(Game game, Ability source) {
|
public boolean apply(Game game, Ability source) {
|
||||||
if (this.affectedObjectsSet) {
|
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);
|
Permanent permanent = it.next().getPermanent(game);
|
||||||
if (permanent != null) {
|
if (permanent != null) {
|
||||||
permanent.addPower(power.calculate(game, source, this));
|
permanent.addPower(power.calculate(game, source, this));
|
||||||
|
|
@ -126,7 +125,6 @@ public class BoostControlledEffect extends ContinuousEffectImpl {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setText() {
|
private void setText() {
|
||||||
String message = null;
|
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
if (excludeSource) {
|
if (excludeSource) {
|
||||||
sb.append("other ");
|
sb.append("other ");
|
||||||
|
|
@ -150,6 +148,9 @@ public class BoostControlledEffect extends ContinuousEffectImpl {
|
||||||
sb.append(t);
|
sb.append(t);
|
||||||
|
|
||||||
sb.append((duration == Duration.EndOfTurn ? " until end of turn" : ""));
|
sb.append((duration == Duration.EndOfTurn ? " until end of turn" : ""));
|
||||||
|
|
||||||
|
// where X
|
||||||
|
String message = null;
|
||||||
if (t.equals("X")) {
|
if (t.equals("X")) {
|
||||||
message = toughness.getMessage();
|
message = toughness.getMessage();
|
||||||
} else if (p.equals("X")) {
|
} else if (p.equals("X")) {
|
||||||
|
|
@ -158,6 +159,17 @@ public class BoostControlledEffect extends ContinuousEffectImpl {
|
||||||
if (message != null && !message.isEmpty()) {
|
if (message != null && !message.isEmpty()) {
|
||||||
sb.append(", where X is ").append(message);
|
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();
|
staticText = sb.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,12 @@ import mage.game.Game;
|
||||||
/**
|
/**
|
||||||
* Simple implementation of a {@link CostModificationEffect} offering simplified
|
* Simple implementation of a {@link CostModificationEffect} offering simplified
|
||||||
* construction to setup the object for use by the mage framework.
|
* 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
|
* @author maurer.it_at_gmail.com
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -37,11 +37,10 @@ public class SpellCostReductionSourceEffect extends CostModificationEffectImpl {
|
||||||
for (String manaSymbol : manaCostsToReduce.getSymbols()) {
|
for (String manaSymbol : manaCostsToReduce.getSymbols()) {
|
||||||
sb.append(manaSymbol);
|
sb.append(manaSymbol);
|
||||||
}
|
}
|
||||||
sb.append(" less");
|
sb.append(" less to cast");
|
||||||
if (this.condition != null) {
|
if (this.condition != null) {
|
||||||
sb.append(" to if ").append(this.condition.toString());
|
sb.append(" if ").append(this.condition.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
this.staticText = sb.toString();
|
this.staticText = sb.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -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;
|
package mage.abilities.keyword;
|
||||||
|
|
||||||
import mage.abilities.common.SimpleStaticAbility;
|
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;
|
import mage.constants.Zone;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -15,7 +11,7 @@ import mage.constants.Zone;
|
||||||
public class UndauntedAbility extends SimpleStaticAbility {
|
public class UndauntedAbility extends SimpleStaticAbility {
|
||||||
|
|
||||||
public UndauntedAbility() {
|
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);
|
setRuleAtTheTop(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -28,4 +24,8 @@ public class UndauntedAbility extends SimpleStaticAbility {
|
||||||
return new UndauntedAbility(this);
|
return new UndauntedAbility(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getRule() {
|
||||||
|
return "undaunted <i>(This spell costs {1} less to cast for each opponent.)</i>";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue