Replace many custom CostImpl classes with common ones. Fix some wrong text. Fix #9679

This commit is contained in:
Alex W. Jackson 2022-10-24 07:48:32 -04:00
parent 58d252876a
commit 5e10c3a279
20 changed files with 211 additions and 689 deletions

View file

@ -1,19 +1,15 @@
package mage.cards.a; package mage.cards.a;
import java.util.UUID; import java.util.UUID;
import mage.MageInt; import mage.MageInt;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.costs.Cost; import mage.abilities.costs.common.PutCountersSourceCost;
import mage.abilities.costs.CostImpl;
import mage.abilities.keyword.CumulativeUpkeepAbility; import mage.abilities.keyword.CumulativeUpkeepAbility;
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.counters.CounterType; import mage.counters.CounterType;
import mage.game.Game;
import mage.game.permanent.Permanent;
/** /**
* *
@ -29,7 +25,7 @@ public final class Aboroth extends CardImpl {
this.toughness = new MageInt(9); this.toughness = new MageInt(9);
// Cumulative upkeep-Put a -1/-1 counter on Aboroth. // Cumulative upkeep-Put a -1/-1 counter on Aboroth.
this.addAbility(new CumulativeUpkeepAbility(new AborothCost())); this.addAbility(new CumulativeUpkeepAbility(new PutCountersSourceCost(CounterType.M1M1.createInstance())));
} }
private Aboroth(final Aboroth card) { private Aboroth(final Aboroth card) {
@ -41,35 +37,3 @@ public final class Aboroth extends CardImpl {
return new Aboroth(this); return new Aboroth(this);
} }
} }
class AborothCost extends CostImpl {
public AborothCost() {
this.text = "Put a -1/-1 counter on Aboroth";
}
private AborothCost(final AborothCost cost) {
super(cost);
}
@Override
public boolean pay(Ability ability, Game game, Ability source, UUID controllerId, boolean noMana, Cost costToPay) {
Permanent permanent = game.getPermanent(source.getSourceId());
if (permanent != null) {
permanent.addCounters(CounterType.M1M1.createInstance(), controllerId, ability, game);
this.paid = true;
return true;
}
return false;
}
@Override
public boolean canPay(Ability ability, Ability source, UUID controllerId, Game game) {
return true;
}
@Override
public AborothCost copy() {
return new AborothCost(this);
}
}

View file

@ -30,7 +30,7 @@ public final class AltarOfBhaal extends AdventureCard {
new ReturnFromGraveyardToBattlefieldTargetEffect(), new ManaCostsImpl<>("{2}{B}") new ReturnFromGraveyardToBattlefieldTargetEffect(), new ManaCostsImpl<>("{2}{B}")
); );
ability.addCost(new TapSourceCost()); ability.addCost(new TapSourceCost());
ability.addCost(new ExileTargetCost(new TargetControlledPermanent(1, 1, StaticFilters.FILTER_CONTROLLED_A_CREATURE, true))); ability.addCost(new ExileTargetCost(new TargetControlledPermanent(StaticFilters.FILTER_CONTROLLED_A_CREATURE)));
ability.addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD)); ability.addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD));
this.addAbility(ability); this.addAbility(ability);

View file

@ -1,11 +1,10 @@
package mage.cards.b; package mage.cards.b;
import java.util.UUID; import java.util.UUID;
import mage.abilities.common.CastOnlyIfConditionIsTrueAbility; import mage.abilities.common.CastOnlyIfConditionIsTrueAbility;
import mage.abilities.common.SimpleStaticAbility; import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition;
import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.costs.mana.GenericManaCost;
import mage.abilities.effects.common.DontUntapInControllersUntapStepAllEffect; import mage.abilities.effects.common.DontUntapInControllersUntapStepAllEffect;
import mage.abilities.keyword.CumulativeUpkeepAbility; import mage.abilities.keyword.CumulativeUpkeepAbility;
import mage.abilities.keyword.FlyingAbility; import mage.abilities.keyword.FlyingAbility;
@ -27,7 +26,7 @@ import mage.filter.predicate.mageobject.AbilityPredicate;
*/ */
public final class Blizzard extends CardImpl { public final class Blizzard extends CardImpl {
private static final FilterControlledLandPermanent filter = new FilterControlledLandPermanent("a snow land"); private static final FilterControlledLandPermanent filter = new FilterControlledLandPermanent("if you control a snow land");
private static final FilterCreaturePermanent filter2 = new FilterCreaturePermanent("creatures with flying"); private static final FilterCreaturePermanent filter2 = new FilterCreaturePermanent("creatures with flying");
static { static {
@ -44,7 +43,7 @@ public final class Blizzard extends CardImpl {
)); ));
// Cumulative upkeep {2} // Cumulative upkeep {2}
this.addAbility(new CumulativeUpkeepAbility(new ManaCostsImpl<>("{2}"))); this.addAbility(new CumulativeUpkeepAbility(new GenericManaCost(2)));
// Creatures with flying don't untap during their controllers' untap steps. // Creatures with flying don't untap during their controllers' untap steps.
this.addAbility(new SimpleStaticAbility( this.addAbility(new SimpleStaticAbility(

View file

@ -28,12 +28,12 @@ public final class CityOfShadows extends CardImpl {
// {T}, Exile a creature you control: Put a storage counter on City of Shadows. // {T}, Exile a creature you control: Put a storage counter on City of Shadows.
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new AddCountersSourceEffect(CounterType.STORAGE.createInstance()), new TapSourceCost()); Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new AddCountersSourceEffect(CounterType.STORAGE.createInstance()), new TapSourceCost());
ability.addCost(new ExileTargetCost(new TargetControlledCreaturePermanent(1, 1, StaticFilters.FILTER_CONTROLLED_A_CREATURE, true))); ability.addCost(new ExileTargetCost(new TargetControlledCreaturePermanent(StaticFilters.FILTER_CONTROLLED_A_CREATURE)));
this.addAbility(ability); this.addAbility(ability);
// {T}: Add X mana of {C}, where X is the number of storage counters on City of Shadows. // {T}: Add {C} for each storage counter on City of Shadows.
ability = new DynamicManaAbility(Mana.ColorlessMana(1), new CountersSourceCount(CounterType.STORAGE), ability = new DynamicManaAbility(Mana.ColorlessMana(1), new CountersSourceCount(CounterType.STORAGE),
"Add X mana of {C}, where X is the number of storage counters on {this}"); "Add {C} for each storage counter on {this}");
this.addAbility(ability); this.addAbility(ability);
} }

View file

@ -36,7 +36,7 @@ public final class FoodChain extends CardImpl {
// Exile a creature you control: Add X mana of any one color, where X is the exiled creature's converted mana cost plus one. Spend this mana only to cast creature spells. // Exile a creature you control: Add X mana of any one color, where X is the exiled creature's converted mana cost plus one. Spend this mana only to cast creature spells.
Ability ability = new SimpleManaAbility(Zone.BATTLEFIELD, new FoodChainManaEffect(), Ability ability = new SimpleManaAbility(Zone.BATTLEFIELD, new FoodChainManaEffect(),
new ExileTargetCost(new TargetControlledCreaturePermanent(1, 1, StaticFilters.FILTER_CONTROLLED_A_CREATURE, true))); new ExileTargetCost(new TargetControlledCreaturePermanent(StaticFilters.FILTER_CONTROLLED_A_CREATURE)));
this.addAbility(ability); this.addAbility(ability);
} }

View file

@ -1,9 +1,9 @@
package mage.cards.g; package mage.cards.g;
import java.util.UUID; import java.util.UUID;
import mage.MageInt; import mage.MageInt;
import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; import mage.abilities.common.BeginningOfUpkeepTriggeredAbility;
import mage.abilities.condition.Condition;
import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition;
import mage.abilities.decorator.ConditionalOneShotEffect; import mage.abilities.decorator.ConditionalOneShotEffect;
import mage.abilities.effects.common.discard.DiscardControllerEffect; import mage.abilities.effects.common.discard.DiscardControllerEffect;
@ -14,8 +14,7 @@ import mage.constants.CardType;
import mage.constants.ComparisonType; import mage.constants.ComparisonType;
import mage.constants.SubType; import mage.constants.SubType;
import mage.constants.TargetController; import mage.constants.TargetController;
import mage.filter.FilterPermanent; import mage.filter.common.FilterControlledPermanent;
import mage.filter.common.FilterControlledCreaturePermanent;
/** /**
* *
@ -23,16 +22,17 @@ import mage.filter.common.FilterControlledCreaturePermanent;
*/ */
public final class GutwrencherOni extends CardImpl { public final class GutwrencherOni extends CardImpl {
private static final FilterPermanent filter = new FilterControlledCreaturePermanent("Ogre"); private static final FilterControlledPermanent filter = new FilterControlledPermanent("Ogre");
static { static {
filter.add(SubType.OGRE.getPredicate()); filter.add(SubType.OGRE.getPredicate());
} }
private static final Condition condition = new PermanentsOnTheBattlefieldCondition(filter, ComparisonType.EQUAL_TO, 0);
public GutwrencherOni(UUID ownerId, CardSetInfo setInfo) { public GutwrencherOni(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{B}{B}"); super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{B}{B}");
this.subtype.add(SubType.DEMON); this.subtype.add(SubType.DEMON, SubType.SPIRIT);
this.subtype.add(SubType.SPIRIT);
this.power = new MageInt(5); this.power = new MageInt(5);
this.toughness = new MageInt(4); this.toughness = new MageInt(4);
@ -41,11 +41,14 @@ public final class GutwrencherOni extends CardImpl {
this.addAbility(TrampleAbility.getInstance()); this.addAbility(TrampleAbility.getInstance());
// At the beginning of your upkeep, discard a card if you don't control an Ogre. // At the beginning of your upkeep, discard a card if you don't control an Ogre.
this.addAbility(new BeginningOfUpkeepTriggeredAbility(new ConditionalOneShotEffect( this.addAbility(new BeginningOfUpkeepTriggeredAbility(
new DiscardControllerEffect(1), new ConditionalOneShotEffect(
new PermanentsOnTheBattlefieldCondition(filter, ComparisonType.EQUAL_TO, 0), new DiscardControllerEffect(1),
"discard a card if you don't control an Ogre"), TargetController.YOU, false)); condition,
"discard a card if you don't control an Ogre"
),
TargetController.YOU, false
));
} }
private GutwrencherOni(final GutwrencherOni card) { private GutwrencherOni(final GutwrencherOni card) {
@ -57,4 +60,3 @@ public final class GutwrencherOni extends CardImpl {
return new GutwrencherOni(this); return new GutwrencherOni(this);
} }
} }

View file

@ -1,29 +1,24 @@
package mage.cards.h; package mage.cards.h;
import java.util.Collection;
import java.util.UUID; import java.util.UUID;
import mage.MageInt; import mage.MageInt;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.costs.Cost; import mage.abilities.costs.common.DiscardCardCost;
import mage.abilities.costs.CostImpl; import mage.abilities.costs.common.DiscardTargetCost;
import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.OneShotEffect;
import mage.cards.Card;
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.Outcome;
import mage.constants.SuperType; import mage.constants.SuperType;
import mage.constants.Zone;
import mage.filter.FilterCard;
import mage.game.Game; import mage.game.Game;
import mage.game.stack.Spell; import mage.game.stack.Spell;
import mage.players.Player;
import mage.target.TargetSpell; import mage.target.TargetSpell;
import mage.target.common.TargetCardInHand; import mage.util.CardUtil;
/** /**
* @author LevelX * @author LevelX
@ -33,17 +28,15 @@ public final class HisokaMinamoSensei extends CardImpl {
public HisokaMinamoSensei(UUID ownerId, CardSetInfo setInfo) { public HisokaMinamoSensei(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{U}{U}"); super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{U}{U}");
this.addSuperType(SuperType.LEGENDARY); this.addSuperType(SuperType.LEGENDARY);
this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.HUMAN, SubType.WIZARD);
this.subtype.add(SubType.WIZARD);
this.power = new MageInt(1); this.power = new MageInt(1);
this.toughness = new MageInt(3); this.toughness = new MageInt(3);
// {2}{U}, Discard a card: Counter target spell if it has the same converted mana cost as the discarded card. // {2}{U}, Discard a card: Counter target spell if it has the same converted mana cost as the discarded card.
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new HisokaMinamoSenseiCounterEffect(), new ManaCostsImpl<>("{2}{U}")); Ability ability = new SimpleActivatedAbility(new HisokaMinamoSenseiCounterEffect(), new ManaCostsImpl<>("{2}{U}"));
ability.addCost(new DiscardCardCost());
ability.addTarget(new TargetSpell()); ability.addTarget(new TargetSpell());
TargetCardInHand targetCard = new TargetCardInHand(new FilterCard("a card"));
ability.addCost(new HisokaMinamoSenseiDiscardTargetCost(targetCard));
this.addAbility(ability); this.addAbility(ability);
} }
@ -55,54 +48,6 @@ public final class HisokaMinamoSensei extends CardImpl {
public HisokaMinamoSensei copy() { public HisokaMinamoSensei copy() {
return new HisokaMinamoSensei(this); return new HisokaMinamoSensei(this);
} }
}
class HisokaMinamoSenseiDiscardTargetCost extends CostImpl {
protected Card card = null;
public HisokaMinamoSenseiDiscardTargetCost(TargetCardInHand target) {
this.addTarget(target);
this.text = "Discard " + target.getTargetName();
}
public HisokaMinamoSenseiDiscardTargetCost(HisokaMinamoSenseiDiscardTargetCost cost) {
super(cost);
}
@Override
public boolean pay(Ability ability, Game game, Ability source, UUID controllerId, boolean noMana, Cost costToPay) {
if (targets.choose(Outcome.Discard, controllerId, source.getSourceId(), source, game)) {
Player player = game.getPlayer(controllerId);
if(player != null) {
for (UUID targetId : targets.get(0).getTargets()) {
card = player.getHand().get(targetId, game);
if (card == null) {
return false;
}
paid |= player.discard(card, true, source, game);
}
}
}
return paid;
}
@Override
public boolean canPay(Ability ability, Ability source, UUID controllerId, Game game) {
return targets.canChoose(controllerId, source, game);
}
@Override
public HisokaMinamoSenseiDiscardTargetCost copy() {
return new HisokaMinamoSenseiDiscardTargetCost(this);
}
public Card getDiscardedCard() {
return card;
}
} }
class HisokaMinamoSenseiCounterEffect extends OneShotEffect { class HisokaMinamoSenseiCounterEffect extends OneShotEffect {
@ -118,11 +63,14 @@ class HisokaMinamoSenseiCounterEffect extends OneShotEffect {
@Override @Override
public boolean apply(Game game, Ability source) { public boolean apply(Game game, Ability source) {
Spell spell = game.getStack().getSpell(targetPointer.getFirst(game, source)); Spell spell = game.getStack().getSpell(targetPointer.getFirst(game, source));
if (spell != null) { if (spell == null) {
HisokaMinamoSenseiDiscardTargetCost cost = (HisokaMinamoSenseiDiscardTargetCost) source.getCosts().get(0); return false;
if (cost != null && cost.getDiscardedCard().getManaValue() == spell.getManaValue()) { }
return game.getStack().counter(targetPointer.getFirst(game, source), source, game); if (CardUtil.castStream(source.getCosts().stream(), DiscardTargetCost.class)
} .map(DiscardTargetCost::getCards)
.flatMap(Collection::stream)
.anyMatch(card -> card.getManaValue() == spell.getManaValue())) {
return game.getStack().counter(targetPointer.getFirst(game, source), source, game);
} }
return false; return false;
} }

View file

@ -1,24 +1,15 @@
package mage.cards.l; package mage.cards.l;
import java.util.UUID; import java.util.UUID;
import mage.MageInt; import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.costs.Cost; import mage.abilities.costs.common.PutCardFromHandOnTopOfLibraryCost;
import mage.abilities.costs.CostImpl;
import mage.abilities.effects.common.ReturnToHandSourceEffect; import mage.abilities.effects.common.ReturnToHandSourceEffect;
import mage.cards.Card;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.cards.CardsImpl;
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.game.Game;
import mage.players.Player;
import mage.target.common.TargetCardInHand;
/** /**
* *
@ -33,7 +24,7 @@ public final class Leashling extends CardImpl {
this.toughness = new MageInt(3); this.toughness = new MageInt(3);
// Put a card from your hand on top of your library: Return Leashling to its owner's hand. // Put a card from your hand on top of your library: Return Leashling to its owner's hand.
this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new ReturnToHandSourceEffect(), new PutCardFromHandOnTopOfLibrary())); this.addAbility(new SimpleActivatedAbility(new ReturnToHandSourceEffect(), new PutCardFromHandOnTopOfLibraryCost()));
} }
private Leashling(final Leashling card) { private Leashling(final Leashling card) {
@ -45,52 +36,3 @@ public final class Leashling extends CardImpl {
return new Leashling(this); return new Leashling(this);
} }
} }
class PutCardFromHandOnTopOfLibrary extends CostImpl {
protected final int amount;
public PutCardFromHandOnTopOfLibrary() {
this(1);
}
public PutCardFromHandOnTopOfLibrary(final int amount) {
this.amount = amount;
this.text = "put " + (amount == 1 ? "a card" : (amount + " cards")) + " from your hand on top of your library";
}
public PutCardFromHandOnTopOfLibrary(final PutCardFromHandOnTopOfLibrary cost) {
super(cost);
this.amount = cost.amount;
}
@Override
public Cost copy() {
return new PutCardFromHandOnTopOfLibrary(this);
}
@Override
public boolean canPay(Ability ability, Ability source, UUID controllerId, Game game) {
Player controller = game.getPlayer(controllerId);
if (controller != null) {
return !controller.getHand().isEmpty();
}
return false;
}
@Override
public boolean pay(Ability ability, Game game, Ability source, UUID controllerId, boolean noMana, Cost costToPay) {
Player controller = game.getPlayer(controllerId);
if (controller != null) {
TargetCardInHand target = new TargetCardInHand();
controller.chooseTarget(Outcome.ReturnToHand, target, ability, game);
Card card = controller.getHand().get(target.getFirstTarget(), game);
if (card != null) {
controller.putCardsOnTopOfLibrary(new CardsImpl(card), game, ability, false);
paid = true;
}
}
return paid;
}
}

View file

@ -1,29 +1,27 @@
package mage.cards.n; package mage.cards.n;
import java.util.Collection;
import java.util.UUID; import java.util.UUID;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.costs.Cost; import mage.abilities.condition.Condition;
import mage.abilities.costs.CostImpl; import mage.abilities.costs.common.DiscardTargetCost;
import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.effects.OneShotEffect; import mage.abilities.decorator.ConditionalOneShotEffect;
import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.CreateTokenEffect;
import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.DrawCardSourceControllerEffect;
import mage.cards.Card;
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.SubType; import mage.constants.SubType;
import mage.constants.Zone;
import mage.filter.StaticFilters; import mage.filter.StaticFilters;
import mage.game.Game; import mage.game.Game;
import mage.game.permanent.token.ZombieToken; import mage.game.permanent.token.ZombieToken;
import mage.players.Player;
import mage.target.common.TargetCardInHand; import mage.target.common.TargetCardInHand;
import mage.util.CardUtil;
/** /**
* @author noxx * @author awjackson
*/ */
public final class NecromancersStockpile extends CardImpl { public final class NecromancersStockpile extends CardImpl {
@ -32,9 +30,12 @@ public final class NecromancersStockpile extends CardImpl {
// {1}{B}, Discard a creature card: Draw a card. // {1}{B}, Discard a creature card: Draw a card.
// If the discarded card was a Zombie card, create a tapped 2/2 black Zombie creature token. // If the discarded card was a Zombie card, create a tapped 2/2 black Zombie creature token.
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DrawCardSourceControllerEffect(1), new ManaCostsImpl<>("{1}{B}")); Ability ability = new SimpleActivatedAbility(new DrawCardSourceControllerEffect(1), new ManaCostsImpl<>("{1}{B}"));
ability.addCost(new NecromancersStockpileDiscardTargetCost(new TargetCardInHand(StaticFilters.FILTER_CARD_CREATURE))); ability.addCost(new DiscardTargetCost(new TargetCardInHand(StaticFilters.FILTER_CARD_CREATURE_A)));
ability.addEffect(new NecromancersStockpilePutTokenEffect()); ability.addEffect(new ConditionalOneShotEffect(
new CreateTokenEffect(new ZombieToken(), 1, true, false),
NecromancersStockpileCondition.instance
));
this.addAbility(ability); this.addAbility(ability);
} }
@ -46,79 +47,21 @@ public final class NecromancersStockpile extends CardImpl {
public NecromancersStockpile copy() { public NecromancersStockpile copy() {
return new NecromancersStockpile(this); return new NecromancersStockpile(this);
} }
} }
class NecromancersStockpileDiscardTargetCost extends CostImpl { enum NecromancersStockpileCondition implements Condition {
instance;
protected boolean isZombieCard;
public NecromancersStockpileDiscardTargetCost(TargetCardInHand target) {
this.addTarget(target);
this.text = "Discard " + target.getTargetName();
}
public NecromancersStockpileDiscardTargetCost(NecromancersStockpileDiscardTargetCost cost) {
super(cost);
}
@Override
public boolean pay(Ability ability, Game game, Ability source, UUID controllerId, boolean noMana, Cost costToPay) {
if (targets.choose(Outcome.Discard, controllerId, source.getSourceId(), source, game)) {
Player player = game.getPlayer(controllerId);
if (player != null) {
for (UUID targetId : targets.get(0).getTargets()) {
Card card = player.getHand().get(targetId, game);
if (card == null) {
return false;
}
isZombieCard = card.hasSubtype(SubType.ZOMBIE, game);
paid |= player.discard(card, true, source, game);
}
}
}
return paid;
}
@Override
public boolean canPay(Ability ability, Ability source, UUID controllerId, Game game) {
return targets.canChoose(controllerId, source, game);
}
@Override
public NecromancersStockpileDiscardTargetCost copy() {
return new NecromancersStockpileDiscardTargetCost(this);
}
public boolean isZombieCard() {
return isZombieCard;
}
}
class NecromancersStockpilePutTokenEffect extends OneShotEffect {
NecromancersStockpilePutTokenEffect() {
super(Outcome.Neutral);
staticText = "If the discarded card was a Zombie card, create a tapped 2/2 black Zombie creature token";
}
NecromancersStockpilePutTokenEffect(final NecromancersStockpilePutTokenEffect effect) {
super(effect);
}
@Override @Override
public boolean apply(Game game, Ability source) { public boolean apply(Game game, Ability source) {
NecromancersStockpileDiscardTargetCost cost = (NecromancersStockpileDiscardTargetCost) source.getCosts().get(0); return CardUtil.castStream(source.getCosts().stream(), DiscardTargetCost.class)
if (cost != null && cost.isZombieCard()) { .map(DiscardTargetCost::getCards)
new CreateTokenEffect(new ZombieToken(), 1, true, false).apply(game, source); .flatMap(Collection::stream)
} .anyMatch(card -> card.hasSubtype(SubType.ZOMBIE, game));
return true;
} }
@Override @Override
public NecromancersStockpilePutTokenEffect copy() { public String toString() {
return new NecromancersStockpilePutTokenEffect(this); return "the discarded card was a Zombie card";
} }
} }

View file

@ -23,7 +23,7 @@ public final class NecroticFumes extends CardImpl {
this.subtype.add(SubType.LESSON); this.subtype.add(SubType.LESSON);
// As an additional cost to cast this spell, exile a creature you control. // As an additional cost to cast this spell, exile a creature you control.
this.getSpellAbility().addCost(new ExileTargetCost(new TargetControlledPermanent(1, 1, StaticFilters.FILTER_CONTROLLED_A_CREATURE, true))); this.getSpellAbility().addCost(new ExileTargetCost(new TargetControlledPermanent(StaticFilters.FILTER_CONTROLLED_A_CREATURE)));
// Exile target creature or planeswalker. // Exile target creature or planeswalker.
this.getSpellAbility().addEffect(new ExileTargetEffect()); this.getSpellAbility().addEffect(new ExileTargetEffect());

View file

@ -1,22 +1,21 @@
package mage.cards.p; package mage.cards.p;
import java.util.UUID; import java.util.UUID;
import mage.MageInt; import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; import mage.abilities.common.BeginningOfUpkeepTriggeredAbility;
import mage.abilities.condition.Condition;
import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition;
import mage.abilities.decorator.ConditionalOneShotEffect;
import mage.abilities.effects.common.SacrificeControllerEffect; import mage.abilities.effects.common.SacrificeControllerEffect;
import mage.abilities.keyword.FearAbility; import mage.abilities.keyword.FearAbility;
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.ComparisonType;
import mage.constants.SubType; import mage.constants.SubType;
import mage.constants.TargetController; import mage.constants.TargetController;
import mage.filter.FilterPermanent; import mage.filter.StaticFilters;
import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.common.FilterControlledPermanent;
import mage.filter.common.FilterCreaturePermanent;
import mage.game.Game;
/** /**
* *
@ -24,10 +23,17 @@ import mage.game.Game;
*/ */
public final class PainwrackerOni extends CardImpl { public final class PainwrackerOni extends CardImpl {
private static final FilterControlledPermanent filter = new FilterControlledPermanent("Ogre");
static {
filter.add(SubType.OGRE.getPredicate());
}
private static final Condition condition = new PermanentsOnTheBattlefieldCondition(filter, ComparisonType.EQUAL_TO, 0);
public PainwrackerOni (UUID ownerId, CardSetInfo setInfo) { public PainwrackerOni (UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{B}{B}"); super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{B}{B}");
this.subtype.add(SubType.DEMON); this.subtype.add(SubType.DEMON, SubType.SPIRIT);
this.subtype.add(SubType.SPIRIT);
this.power = new MageInt(5); this.power = new MageInt(5);
this.toughness = new MageInt(4); this.toughness = new MageInt(4);
@ -36,7 +42,14 @@ public final class PainwrackerOni extends CardImpl {
this.addAbility(FearAbility.getInstance()); this.addAbility(FearAbility.getInstance());
// At the beginning of your upkeep, sacrifice a creature if you don't control an Ogre. // At the beginning of your upkeep, sacrifice a creature if you don't control an Ogre.
this.addAbility(new BeginningOfUpkeepTriggeredAbility(new PainwrackerOniEffect(new FilterControlledCreaturePermanent(), 1, ""), TargetController.YOU, false)); this.addAbility(new BeginningOfUpkeepTriggeredAbility(
new ConditionalOneShotEffect(
new SacrificeControllerEffect(StaticFilters.FILTER_PERMANENT_CREATURE, 1, null),
condition,
"sacrifice a creature if you don't control an Ogre"
),
TargetController.YOU, false
));
} }
public PainwrackerOni (final PainwrackerOni card) { public PainwrackerOni (final PainwrackerOni card) {
@ -47,30 +60,4 @@ public final class PainwrackerOni extends CardImpl {
public PainwrackerOni copy() { public PainwrackerOni copy() {
return new PainwrackerOni(this); return new PainwrackerOni(this);
} }
}
class PainwrackerOniEffect extends SacrificeControllerEffect {
public PainwrackerOniEffect(FilterPermanent filter, int count, String preText) {
super(filter, count, preText);
this.staticText = "sacrifice a creature if you don't control an Ogre";
}
public PainwrackerOniEffect(final PainwrackerOniEffect effect) {
super(effect);
}
@Override
public PainwrackerOniEffect copy() {
return new PainwrackerOniEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
if (game.getBattlefield().countAll(new FilterCreaturePermanent(SubType.OGRE, "Ogre"), source.getControllerId(), game) < 1) {
return super.apply(game, source);
}
return true;
}
} }

View file

@ -1,20 +1,19 @@
package mage.cards.s; package mage.cards.s;
import java.util.UUID; import java.util.UUID;
import mage.MageInt; import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; import mage.abilities.common.BeginningOfUpkeepTriggeredAbility;
import mage.abilities.effects.OneShotEffect; import mage.abilities.condition.Condition;
import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition;
import mage.abilities.decorator.ConditionalOneShotEffect;
import mage.abilities.effects.common.LoseLifeSourceControllerEffect;
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.ComparisonType;
import mage.constants.SubType; import mage.constants.SubType;
import mage.constants.TargetController; import mage.constants.TargetController;
import mage.filter.common.FilterCreaturePermanent; import mage.filter.common.FilterControlledPermanent;
import mage.game.Game;
import mage.players.Player;
/** /**
* *
@ -22,16 +21,30 @@ import mage.players.Player;
*/ */
public final class ScourgeOfNumai extends CardImpl { public final class ScourgeOfNumai extends CardImpl {
private static final FilterControlledPermanent filter = new FilterControlledPermanent("Ogre");
static {
filter.add(SubType.OGRE.getPredicate());
}
private static final Condition condition = new PermanentsOnTheBattlefieldCondition(filter, ComparisonType.EQUAL_TO, 0);
public ScourgeOfNumai(UUID ownerId, CardSetInfo setInfo) { public ScourgeOfNumai(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{B}"); super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{B}");
this.subtype.add(SubType.DEMON); this.subtype.add(SubType.DEMON, SubType.SPIRIT);
this.subtype.add(SubType.SPIRIT);
this.power = new MageInt(4); this.power = new MageInt(4);
this.toughness = new MageInt(4); this.toughness = new MageInt(4);
// At the beginning of your upkeep, you lose 2 life if you don't control an Ogre. // At the beginning of your upkeep, you lose 2 life if you don't control an Ogre.
this.addAbility(new BeginningOfUpkeepTriggeredAbility(new ScourgeOfNumaiEffect(), TargetController.YOU, false)); this.addAbility(new BeginningOfUpkeepTriggeredAbility(
new ConditionalOneShotEffect(
new LoseLifeSourceControllerEffect(2),
condition,
"you lose 2 life if you don't control an Ogre"
),
TargetController.YOU, false
));
} }
private ScourgeOfNumai(final ScourgeOfNumai card) { private ScourgeOfNumai(final ScourgeOfNumai card) {
@ -43,32 +56,3 @@ public final class ScourgeOfNumai extends CardImpl {
return new ScourgeOfNumai(this); return new ScourgeOfNumai(this);
} }
} }
class ScourgeOfNumaiEffect extends OneShotEffect {
public ScourgeOfNumaiEffect() {
super(Outcome.LoseLife);
this.staticText = "you lose 2 life if you don't control an Ogre.";
}
public ScourgeOfNumaiEffect(final ScourgeOfNumaiEffect effect) {
super(effect);
}
@Override
public ScourgeOfNumaiEffect copy() {
return new ScourgeOfNumaiEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
if (controller != null) {
if (game.getBattlefield().countAll(new FilterCreaturePermanent(SubType.OGRE, "Ogre"), source.getControllerId(), game) < 1) {
controller.loseLife(2, game, source, false);
}
return true;
}
return false;
}
}

View file

@ -1,23 +1,17 @@
package mage.cards.s; package mage.cards.s;
import mage.MageInt; import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility;
import mage.abilities.costs.Cost; import mage.abilities.costs.OrCost;
import mage.abilities.costs.CostImpl; import mage.abilities.costs.common.RevealTargetFromHandCost;
import mage.abilities.costs.mana.GenericManaCost;
import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.DrawCardSourceControllerEffect;
import mage.cards.Card;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.cards.CardsImpl;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.Outcome;
import mage.constants.SubType; import mage.constants.SubType;
import mage.filter.FilterCard; import mage.filter.FilterCard;
import mage.game.Game;
import mage.players.Player;
import mage.target.common.TargetCardInHand; import mage.target.common.TargetCardInHand;
import mage.util.ManaUtil;
import java.util.UUID; import java.util.UUID;
@ -26,6 +20,12 @@ import java.util.UUID;
*/ */
public final class SilvergillAdept extends CardImpl { public final class SilvergillAdept extends CardImpl {
private static final FilterCard filter = new FilterCard("a Merfolk card from your hand");
static {
filter.add(SubType.MERFOLK.getPredicate());
}
public SilvergillAdept(UUID ownerId, CardSetInfo setInfo) { public SilvergillAdept(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{U}"); super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{U}");
this.subtype.add(SubType.MERFOLK); this.subtype.add(SubType.MERFOLK);
@ -35,7 +35,11 @@ public final class SilvergillAdept extends CardImpl {
this.toughness = new MageInt(1); this.toughness = new MageInt(1);
// As an additional cost to cast Silvergill Adept, reveal a Merfolk card from your hand or pay {3}. // As an additional cost to cast Silvergill Adept, reveal a Merfolk card from your hand or pay {3}.
this.getSpellAbility().addCost(new SilvergillAdeptCost()); this.getSpellAbility().addCost(new OrCost(
"reveal a Merfolk card from your hand or pay {3}", new RevealTargetFromHandCost(new TargetCardInHand(filter)),
new GenericManaCost(3)
));
// When Silvergill Adept enters the battlefield, draw a card. // When Silvergill Adept enters the battlefield, draw a card.
this.addAbility(new EntersBattlefieldTriggeredAbility(new DrawCardSourceControllerEffect(1))); this.addAbility(new EntersBattlefieldTriggeredAbility(new DrawCardSourceControllerEffect(1)));
} }
@ -49,67 +53,3 @@ public final class SilvergillAdept extends CardImpl {
return new SilvergillAdept(this); return new SilvergillAdept(this);
} }
} }
class SilvergillAdeptCost extends CostImpl {
private static final FilterCard filter = new FilterCard("Merfolk card");
private Cost mana = ManaUtil.createManaCost(3, false);
static {
filter.add(SubType.MERFOLK.getPredicate());
}
public SilvergillAdeptCost() {
this.text = "reveal a Merfolk card from your hand or pay {3}";
}
public SilvergillAdeptCost(SilvergillAdeptCost cost) {
super(cost);
this.mana = cost.mana.copy();
}
@Override
public boolean pay(Ability ability, Game game, Ability source, UUID controllerId, boolean noMana, Cost costToPay) {
Player player = game.getPlayer(controllerId);
if (player == null) {
return false;
}
paid = false;
if (player.getHand().count(filter, game) > 0
&& player.chooseUse(Outcome.Benefit, "Reveal a Merfolk card? Otherwise pay {3}.", ability, game)) {
TargetCardInHand target = new TargetCardInHand(filter);
if (player.choose(Outcome.Benefit, target, source, game)) {
Card card = player.getHand().get(target.getFirstTarget(), game);
if (card != null) {
paid = true;
player.revealCards("Revealed card", new CardsImpl(card), game);
}
}
} else {
mana.clearPaid();
if (mana.pay(ability, game, source, player.getId(), false)) {
paid = true;
}
}
return paid;
}
@Override
public boolean canPay(Ability ability, Ability source, UUID controllerId, Game game) {
Player player = game.getPlayer(controllerId);
if (player != null && player.getHand().count(filter, game) > 0) {
return true;
}
return mana.canPay(ability, source, controllerId, game);
}
@Override
public SilvergillAdeptCost copy() {
return new SilvergillAdeptCost(this);
}
}

View file

@ -27,7 +27,7 @@ public final class SoulExchange extends CardImpl {
super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{B}{B}"); super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{B}{B}");
// As an additional cost to cast Soul Exchange, exile a creature you control. // As an additional cost to cast Soul Exchange, exile a creature you control.
Cost cost = new ExileTargetCost(new TargetControlledCreaturePermanent(1, 1, StaticFilters.FILTER_CONTROLLED_A_CREATURE, true)); Cost cost = new ExileTargetCost(new TargetControlledCreaturePermanent(StaticFilters.FILTER_CONTROLLED_A_CREATURE));
this.getSpellAbility().addCost(cost); this.getSpellAbility().addCost(cost);
// Return target creature card from your graveyard to the battlefield. Put a +2/+2 counter on that creature if the exiled creature was a Thrull. // Return target creature card from your graveyard to the battlefield. Put a +2/+2 counter on that creature if the exiled creature was a Thrull.
this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD)); this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD));

View file

@ -1,16 +1,13 @@
package mage.cards.t; package mage.cards.t;
import java.util.UUID; import java.util.UUID;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.common.ActivateIfConditionActivatedAbility;
import mage.abilities.condition.Condition;
import mage.abilities.condition.common.OpponentControlsPermanentCondition; import mage.abilities.condition.common.OpponentControlsPermanentCondition;
import mage.abilities.costs.Cost;
import mage.abilities.costs.CostImpl;
import mage.abilities.costs.common.SacrificeSourceCost; import mage.abilities.costs.common.SacrificeSourceCost;
import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.costs.mana.GenericManaCost;
import mage.abilities.effects.common.DestroyTargetEffect; import mage.abilities.effects.common.DestroyTargetEffect;
import mage.abilities.mana.ColorlessManaAbility; import mage.abilities.mana.ColorlessManaAbility;
import mage.cards.CardImpl; import mage.cards.CardImpl;
@ -18,9 +15,7 @@ import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.ComparisonType; import mage.constants.ComparisonType;
import mage.constants.Zone; import mage.constants.Zone;
import mage.filter.StaticFilters;
import mage.filter.common.FilterLandPermanent; import mage.filter.common.FilterLandPermanent;
import mage.game.Game;
import mage.target.common.TargetNonBasicLandPermanent; import mage.target.common.TargetNonBasicLandPermanent;
/** /**
@ -29,20 +24,20 @@ import mage.target.common.TargetNonBasicLandPermanent;
*/ */
public final class TectonicEdge extends CardImpl { public final class TectonicEdge extends CardImpl {
private static final Condition condition = new OpponentControlsPermanentCondition(
new FilterLandPermanent("an opponent controls four or more lands"), ComparisonType.MORE_THAN, 3
);
public TectonicEdge(UUID ownerId, CardSetInfo setInfo) { public TectonicEdge(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.LAND},null); super(ownerId,setInfo,new CardType[]{CardType.LAND},null);
// Tap: Add 1. // Tap: Add 1.
this.addAbility(new ColorlessManaAbility()); this.addAbility(new ColorlessManaAbility());
// {1}, {T}, Sacrifice Tectonic Edge: Destroy target nonbasic land. Activate this ability only if an opponent controls four or more lands. // {1}, {T}, Sacrifice Tectonic Edge: Destroy target nonbasic land. Activate only if an opponent controls four or more lands.
Ability ability = new ActivateIfConditionActivatedAbility( Ability ability = new ActivateIfConditionActivatedAbility(
Zone.BATTLEFIELD, Zone.BATTLEFIELD, new DestroyTargetEffect(), new GenericManaCost(1), condition
new DestroyTargetEffect(), );
new ManaCostsImpl<>("{1}"),
new OpponentControlsPermanentCondition(
new FilterLandPermanent("an opponent controls four or more lands"),
ComparisonType.MORE_THAN, 3));
ability.addCost(new TapSourceCost()); ability.addCost(new TapSourceCost());
ability.addCost(new SacrificeSourceCost()); ability.addCost(new SacrificeSourceCost());
ability.addTarget(new TargetNonBasicLandPermanent()); ability.addTarget(new TargetNonBasicLandPermanent());
@ -57,39 +52,4 @@ public final class TectonicEdge extends CardImpl {
public TectonicEdge copy() { public TectonicEdge copy() {
return new TectonicEdge(this); return new TectonicEdge(this);
} }
}
class TectonicEdgeCost extends CostImpl {
public TectonicEdgeCost() {
this.text = "Activate only if an opponent controls four or more lands";
}
public TectonicEdgeCost(final TectonicEdgeCost cost) {
super(cost);
}
@Override
public TectonicEdgeCost copy() {
return new TectonicEdgeCost(this);
}
@Override
public boolean canPay(Ability ability, Ability source, UUID controllerId, Game game) {
for (UUID opponentId: game.getOpponents(controllerId)) {
if (game.getBattlefield().countAll(StaticFilters.FILTER_LANDS, opponentId, game) > 3) {
return true;
}
}
return false;
}
@Override
public boolean pay(Ability ability, Game game, Ability source, UUID controllerId, boolean noMana, Cost costToPay) {
this.paid = true;
return paid;
}
} }

View file

@ -1,26 +1,22 @@
package mage.cards.t; package mage.cards.t;
import mage.ObjectColor; import mage.ObjectColor;
import mage.abilities.Ability;
import mage.abilities.StateTriggeredAbility; import mage.abilities.StateTriggeredAbility;
import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; import mage.abilities.common.BeginningOfUpkeepTriggeredAbility;
import mage.abilities.common.CastOnlyIfConditionIsTrueAbility;
import mage.abilities.common.EntersBattlefieldAbility; import mage.abilities.common.EntersBattlefieldAbility;
import mage.abilities.common.SimpleStaticAbility; import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.condition.Condition;
import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition;
import mage.abilities.condition.common.SourceHasCounterCondition; import mage.abilities.condition.common.SourceHasCounterCondition;
import mage.abilities.costs.Cost;
import mage.abilities.costs.CostImpl;
import mage.abilities.decorator.ConditionalContinuousEffect; import mage.abilities.decorator.ConditionalContinuousEffect;
import mage.abilities.dynamicvalue.common.CountersSourceCount; import mage.abilities.dynamicvalue.common.CountersSourceCount;
import mage.abilities.effects.Effect;
import mage.abilities.effects.common.RemoveAllCountersSourceEffect; import mage.abilities.effects.common.RemoveAllCountersSourceEffect;
import mage.abilities.effects.common.continuous.BoostAllEffect; import mage.abilities.effects.common.continuous.BoostAllEffect;
import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.abilities.effects.common.counter.AddCountersSourceEffect;
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.Duration;
import mage.constants.TargetController;
import mage.constants.Zone;
import mage.counters.CounterType; import mage.counters.CounterType;
import mage.filter.FilterPermanent; import mage.filter.FilterPermanent;
import mage.filter.common.FilterCreaturePermanent; import mage.filter.common.FilterCreaturePermanent;
@ -32,39 +28,51 @@ import mage.game.events.GameEvent;
import java.util.UUID; import java.util.UUID;
/** /**
* @author LoneFox * @author awjackson
*/ */
public final class TidalInfluence extends CardImpl { public final class TidalInfluence extends CardImpl {
private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("blue creatures"); private static final FilterPermanent filterName = new FilterPermanent("if no permanents named Tidal Influence are on the battlefield");
private static final FilterCreaturePermanent filterBlue = new FilterCreaturePermanent("all blue creatures");
static { static {
filter.add(new ColorPredicate(ObjectColor.BLUE)); filterName.add(new NamePredicate("Tidal Influence"));
filterBlue.add(new ColorPredicate(ObjectColor.BLUE));
} }
private static final Condition conditionCast = new PermanentsOnTheBattlefieldCondition(
filterName, ComparisonType.EQUAL_TO, 0, false);
private static final Condition condition1 = new SourceHasCounterCondition(CounterType.TIDE, 1, 1);
private static final Condition condition3 = new SourceHasCounterCondition(CounterType.TIDE, 3, 3);
public TidalInfluence(UUID ownerId, CardSetInfo setInfo) { public TidalInfluence(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{U}"); super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{U}");
// Cast Tidal Influence only if no permanents named Tidal Influence are on the battlefield. // Cast this spell only if no permanents named Tidal Influence are on the battlefield.
this.getSpellAbility().addCost(new TidalInfluenceCost()); this.addAbility(new CastOnlyIfConditionIsTrueAbility(conditionCast));
// Tidal Influence enters the battlefield with a tide counter on it. // Tidal Influence enters the battlefield with a tide counter on it.
this.addAbility(new EntersBattlefieldAbility(new AddCountersSourceEffect(CounterType.TIDE.createInstance()), this.addAbility(new EntersBattlefieldAbility(new AddCountersSourceEffect(CounterType.TIDE.createInstance()),
"with a tide counter on it.")); "with a tide counter on it."));
// At the beginning of your upkeep, put a tide counter on Tidal Influence. // At the beginning of your upkeep, put a tide counter on Tidal Influence.
this.addAbility(new BeginningOfUpkeepTriggeredAbility(new AddCountersSourceEffect(CounterType.TIDE.createInstance()), this.addAbility(new BeginningOfUpkeepTriggeredAbility(new AddCountersSourceEffect(CounterType.TIDE.createInstance()),
TargetController.YOU, false)); TargetController.YOU, false));
// As long as there is exactly one tide counter on Tidal Influence, all blue creatures get -2/-0. // As long as there is exactly one tide counter on Tidal Influence, all blue creatures get -2/-0.
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new ConditionalContinuousEffect( this.addAbility(new SimpleStaticAbility(new ConditionalContinuousEffect(
new BoostAllEffect(-2, -0, Duration.WhileOnBattlefield, filter, false), new BoostAllEffect(-2, -0, Duration.WhileOnBattlefield, filterBlue, false),
new SourceHasCounterCondition(CounterType.TIDE, 1, 1), condition1,
"As long as there is exactly one tide counter on {this}, all blue creatures get -2/-0."))); "As long as there is exactly one tide counter on {this}, all blue creatures get -2/-0.")));
// As long as there are exactly three tide counters on Tidal Influence, all blue creatures get +2/+0. // As long as there are exactly three tide counters on Tidal Influence, all blue creatures get +2/+0.
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new ConditionalContinuousEffect( this.addAbility(new SimpleStaticAbility(new ConditionalContinuousEffect(
new BoostAllEffect(2, -0, Duration.WhileOnBattlefield, filter, false), new BoostAllEffect(2, 0, Duration.WhileOnBattlefield, filterBlue, false),
new SourceHasCounterCondition(CounterType.TIDE, 3, 3), condition3,
"As long as there are exactly three tide counter on {this}, all blue creatures get +2/-0."))); "As long as there are exactly three tide counter on {this}, all blue creatures get +2/+0.")));
// Whenever there are four tide counters on Tidal Influence, remove all tide counters from it. // Whenever there are four tide counters on Tidal Influence, remove all tide counters from it.
this.addAbility(new TidalInfluenceTriggeredAbility(new RemoveAllCountersSourceEffect(CounterType.TIDE))); this.addAbility(new TidalInfluenceTriggeredAbility());
} }
private TidalInfluence(final TidalInfluence card) { private TidalInfluence(final TidalInfluence card) {
@ -77,45 +85,10 @@ public final class TidalInfluence extends CardImpl {
} }
} }
class TidalInfluenceCost extends CostImpl {
private static final FilterPermanent filter = new FilterPermanent();
static {
filter.add(new NamePredicate("Tidal Influence"));
}
public TidalInfluenceCost() {
this.text = "Cast Tidal Influence only if no permanents named Tidal Influence are on the battlefield";
}
public TidalInfluenceCost(final TidalInfluenceCost cost) {
super(cost);
}
@Override
public boolean canPay(Ability ability, Ability source, UUID controllerId, Game game) {
return !game.getBattlefield().contains(filter, source, game, 1);
}
@Override
public boolean pay(Ability ability, Game game, Ability source, UUID controllerId, boolean noMana, Cost costToPay) {
this.paid = true;
return paid;
}
@Override
public TidalInfluenceCost copy() {
return new TidalInfluenceCost(this);
}
}
class TidalInfluenceTriggeredAbility extends StateTriggeredAbility { class TidalInfluenceTriggeredAbility extends StateTriggeredAbility {
public TidalInfluenceTriggeredAbility(Effect effect) { public TidalInfluenceTriggeredAbility() {
super(Zone.BATTLEFIELD, effect); super(Zone.BATTLEFIELD, new RemoveAllCountersSourceEffect(CounterType.TIDE));
setTriggerPhrase("Whenever there are four tide counters on {this}, "); setTriggerPhrase("Whenever there are four tide counters on {this}, ");
} }

View file

@ -1,24 +1,25 @@
package mage.cards.t; package mage.cards.t;
import java.util.UUID; import java.util.UUID;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.costs.Cost; import mage.abilities.condition.Condition;
import mage.abilities.costs.CostImpl; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition;
import mage.abilities.costs.common.SacrificeAllCost;
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.decorator.ConditionalOneShotEffect;
import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.CreateTokenEffect;
import mage.abilities.effects.common.DamageControllerEffect; import mage.abilities.effects.common.DamageControllerEffect;
import mage.abilities.mana.BlackManaAbility; import mage.abilities.mana.BlackManaAbility;
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.ComparisonType;
import mage.constants.SubType;
import mage.constants.SuperType; import mage.constants.SuperType;
import mage.constants.Zone; import mage.filter.common.FilterControlledPermanent;
import mage.filter.common.FilterControlledLandPermanent; import mage.filter.StaticFilters;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.game.permanent.token.UramiToken; import mage.game.permanent.token.UramiToken;
/** /**
@ -27,18 +28,31 @@ import mage.game.permanent.token.UramiToken;
*/ */
public final class TombOfUrami extends CardImpl { public final class TombOfUrami extends CardImpl {
private static final FilterControlledPermanent filter = new FilterControlledPermanent("Ogre");
static {
filter.add(SubType.OGRE.getPredicate());
}
private static final Condition condition = new PermanentsOnTheBattlefieldCondition(filter, ComparisonType.EQUAL_TO, 0);
public TombOfUrami(UUID ownerId, CardSetInfo setInfo) { public TombOfUrami(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); super(ownerId, setInfo, new CardType[]{CardType.LAND}, "");
this.addSuperType(SuperType.LEGENDARY); this.addSuperType(SuperType.LEGENDARY);
// {tap}: Add {B}. Tomb of Urami deals 1 damage to you if you don't control an Ogre. // {tap}: Add {B}. Tomb of Urami deals 1 damage to you if you don't control an Ogre.
Ability ability = new BlackManaAbility(); Ability ability = new BlackManaAbility();
ability.addEffect(new DamageControllerEffect(1)); ability.addEffect(new ConditionalOneShotEffect(
new DamageControllerEffect(1),
condition,
"{this} deals 1 damage to you if you don't control an Ogre"
));
this.addAbility(ability); this.addAbility(ability);
// {2}{B}{B}, {tap}, Sacrifice all lands you control: Create a legendary 5/5 black Demon Spirit creature token with flying named Urami. // {2}{B}{B}, {tap}, Sacrifice all lands you control: Create a legendary 5/5 black Demon Spirit creature token with flying named Urami.
Ability ability2 = new SimpleActivatedAbility(Zone.BATTLEFIELD, new CreateTokenEffect(new UramiToken()), new ManaCostsImpl<>("{2}{B}{B}")); Ability ability2 = new SimpleActivatedAbility(new CreateTokenEffect(new UramiToken()), new ManaCostsImpl<>("{2}{B}{B}"));
ability2.addCost(new TapSourceCost()); ability2.addCost(new TapSourceCost());
ability2.addCost(new SacrificeAllLandCost()); ability2.addCost(new SacrificeAllCost(StaticFilters.FILTER_CONTROLLED_PERMANENT_LANDS));
this.addAbility(ability2); this.addAbility(ability2);
} }
@ -51,38 +65,3 @@ public final class TombOfUrami extends CardImpl {
return new TombOfUrami(this); return new TombOfUrami(this);
} }
} }
class SacrificeAllLandCost extends CostImpl {
public SacrificeAllLandCost() {
this.text = "Sacrifice all lands you control";
}
public SacrificeAllLandCost(SacrificeAllLandCost cost) {
super(cost);
}
@Override
public boolean pay(Ability ability, Game game, Ability source, UUID controllerId, boolean noMana, Cost costToPay) {
for (Permanent permanent : game.getBattlefield().getActivePermanents(new FilterControlledLandPermanent(), ability.getControllerId(), game)) {
paid |= permanent.sacrifice(source, game);
}
return paid;
}
@Override
public boolean canPay(Ability ability, Ability source, UUID controllerId, Game game) {
for (Permanent permanent : game.getBattlefield().getActivePermanents(new FilterControlledLandPermanent(), ability.getControllerId(), game)) {
if (!game.getPlayer(controllerId).canPaySacrificeCost(permanent, source, controllerId, game)) {
return false;
}
}
return true;
}
@Override
public SacrificeAllLandCost copy() {
return new SacrificeAllLandCost(this);
}
}

View file

@ -4,11 +4,8 @@ import mage.abilities.Ability;
import mage.abilities.ActivatedAbility; import mage.abilities.ActivatedAbility;
import mage.abilities.common.ActivateAsSorceryActivatedAbility; import mage.abilities.common.ActivateAsSorceryActivatedAbility;
import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.costs.Cost;
import mage.abilities.costs.CostImpl;
import mage.abilities.costs.common.DiscardCardCost; import mage.abilities.costs.common.DiscardCardCost;
import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.costs.common.PayLifeCost;
import mage.abilities.dynamicvalue.common.StaticValue;
import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.DestroySourceEffect; import mage.abilities.effects.common.DestroySourceEffect;
import mage.cards.Card; import mage.cards.Card;
@ -17,7 +14,6 @@ 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.constants.TargetController;
import mage.constants.Zone;
import mage.game.Game; import mage.game.Game;
import mage.players.Player; import mage.players.Player;
import mage.target.TargetPlayer; import mage.target.TargetPlayer;
@ -36,16 +32,14 @@ public final class VolrathsDungeon extends CardImpl {
// Pay 5 life: Destroy Volrath's Dungeon. Any player may activate this ability but only during their turn. // Pay 5 life: Destroy Volrath's Dungeon. Any player may activate this ability but only during their turn.
ActivatedAbility ability = new SimpleActivatedAbility( ActivatedAbility ability = new SimpleActivatedAbility(
Zone.BATTLEFIELD,
new DestroySourceEffect().setText("Destroy {this}. Any player may activate this ability but only during their turn."), new DestroySourceEffect().setText("Destroy {this}. Any player may activate this ability but only during their turn."),
new PayLifeActivePlayerCost(5)); new PayLifeCost(5));
ability.setMayActivate(TargetController.ACTIVE); ability.setMayActivate(TargetController.ACTIVE);
this.addAbility(ability); this.addAbility(ability);
// Discard a card: Target player puts a card from their hand on top of their library. Activate this ability only any time you could cast a sorcery. // Discard a card: Target player puts a card from their hand on top of their library.
ability = new ActivateAsSorceryActivatedAbility( // Activate this ability only any time you could cast a sorcery.
Zone.BATTLEFIELD, new VolrathsDungeonEffect(), new DiscardCardCost() ability = new ActivateAsSorceryActivatedAbility(new VolrathsDungeonEffect(), new DiscardCardCost());
);
ability.addTarget(new TargetPlayer()); ability.addTarget(new TargetPlayer());
this.addAbility(ability); this.addAbility(ability);
} }
@ -60,52 +54,6 @@ public final class VolrathsDungeon extends CardImpl {
} }
} }
class PayLifeActivePlayerCost extends CostImpl {
private final DynamicValue amount;
public PayLifeActivePlayerCost(int amount) {
this.amount = StaticValue.get(amount);
this.text = "Pay " + amount + " life";
}
public PayLifeActivePlayerCost(DynamicValue amount, String text) {
this.amount = amount.copy();
this.text = "Pay " + text;
}
public PayLifeActivePlayerCost(PayLifeActivePlayerCost cost) {
super(cost);
this.amount = cost.amount.copy();
}
@Override
public boolean canPay(Ability ability, Ability source, UUID controllerId, Game game) {
int lifeToPayAmount = amount.calculate(game, ability, null);
return game.getPlayer(game.getActivePlayerId()).getLife() >= lifeToPayAmount;
}
@Override
public boolean pay(Ability ability, Game game, Ability source, UUID controllerId, boolean noMana, Cost costToPay) {
Player activatingPlayer = game.getPlayer(game.getActivePlayerId());
if (activatingPlayer == null) {
return false;
}
int lifeToPayAmount = amount.calculate(game, ability, null);
if (activatingPlayer.chooseUse(Outcome.LoseLife, "Pay " + lifeToPayAmount + " life?", ability, game)) {
this.paid = CardUtil.tryPayLife(lifeToPayAmount, activatingPlayer, source, game);
return this.paid;
}
return false;
}
@Override
public PayLifeActivePlayerCost copy() {
return new PayLifeActivePlayerCost(this);
}
}
class VolrathsDungeonEffect extends OneShotEffect { class VolrathsDungeonEffect extends OneShotEffect {
public VolrathsDungeonEffect() { public VolrathsDungeonEffect() {

View file

@ -1,14 +1,10 @@
package mage.cards.w; package mage.cards.w;
import java.util.UUID; import java.util.UUID;
import mage.MageInt; import mage.MageInt;
import mage.MageObject;
import mage.abilities.Ability;
import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility;
import mage.abilities.common.LeavesBattlefieldTriggeredAbility; import mage.abilities.common.LeavesBattlefieldTriggeredAbility;
import mage.abilities.costs.Cost; import mage.abilities.costs.common.ExileTargetCost;
import mage.abilities.costs.CostImpl;
import mage.abilities.effects.common.ReturnFromExileForSourceEffect; import mage.abilities.effects.common.ReturnFromExileForSourceEffect;
import mage.abilities.effects.common.SacrificeSourceUnlessPaysEffect; import mage.abilities.effects.common.SacrificeSourceUnlessPaysEffect;
import mage.abilities.keyword.FlyingAbility; import mage.abilities.keyword.FlyingAbility;
@ -16,15 +12,11 @@ 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.common.FilterControlledPermanent;
import mage.filter.predicate.mageobject.AnotherPredicate; import mage.filter.predicate.mageobject.AnotherPredicate;
import mage.game.Game; import mage.target.common.TargetControlledPermanent;
import mage.game.permanent.Permanent;
import mage.players.Player;
import mage.target.common.TargetControlledCreaturePermanent;
import mage.util.CardUtil;
/** /**
* *
@ -32,10 +24,15 @@ import mage.util.CardUtil;
*/ */
public final class WormfangDrake extends CardImpl { public final class WormfangDrake extends CardImpl {
private static final FilterControlledPermanent filter = new FilterControlledCreaturePermanent("a creature you control other than {this}");
static {
filter.add(AnotherPredicate.instance);
}
public WormfangDrake(UUID ownerId, CardSetInfo setInfo) { public WormfangDrake(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{U}"); super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{U}");
this.subtype.add(SubType.NIGHTMARE); this.subtype.add(SubType.NIGHTMARE, SubType.DRAKE);
this.subtype.add(SubType.DRAKE);
this.power = new MageInt(3); this.power = new MageInt(3);
this.toughness = new MageInt(4); this.toughness = new MageInt(4);
@ -44,7 +41,9 @@ public final class WormfangDrake extends CardImpl {
// When Wormfang Drake enters the battlefield, sacrifice it unless you exile a creature you control other than Wormfang Drake. // When Wormfang Drake enters the battlefield, sacrifice it unless you exile a creature you control other than Wormfang Drake.
this.addAbility(new EntersBattlefieldTriggeredAbility( this.addAbility(new EntersBattlefieldTriggeredAbility(
new SacrificeSourceUnlessPaysEffect(new WormfangDrakeExileCost()), false)); new SacrificeSourceUnlessPaysEffect(new ExileTargetCost(new TargetControlledPermanent(filter))),
false
));
// When Wormfang Drake leaves the battlefield, return the exiled card to the battlefield under its owner's control. // When Wormfang Drake leaves the battlefield, return the exiled card to the battlefield under its owner's control.
this.addAbility(new LeavesBattlefieldTriggeredAbility(new ReturnFromExileForSourceEffect(Zone.BATTLEFIELD), false)); this.addAbility(new LeavesBattlefieldTriggeredAbility(new ReturnFromExileForSourceEffect(Zone.BATTLEFIELD), false));
@ -59,50 +58,3 @@ public final class WormfangDrake extends CardImpl {
return new WormfangDrake(this); return new WormfangDrake(this);
} }
} }
class WormfangDrakeExileCost extends CostImpl {
private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent();
static {
filter.add(AnotherPredicate.instance);
}
public WormfangDrakeExileCost() {
this.addTarget(new TargetControlledCreaturePermanent(1, 1, filter, true));
this.text = "Exile a creature you control other than {this}";
}
public WormfangDrakeExileCost(WormfangDrakeExileCost cost) {
super(cost);
}
@Override
public boolean pay(Ability ability, Game game, Ability source, UUID controllerId, boolean noMana, Cost costToPay) {
Player controller = game.getPlayer(controllerId);
MageObject sourceObject = ability.getSourceObject(game);
if (controller != null && sourceObject != null) {
if (targets.choose(Outcome.Exile, controllerId, source.getSourceId(), source, game)) {
UUID exileId = CardUtil.getExileZoneId(game, ability.getSourceId(), ability.getSourceObjectZoneChangeCounter());
for (UUID targetId : targets.get(0).getTargets()) {
Permanent permanent = game.getPermanent(targetId);
if (permanent == null) {
return false;
}
paid |= controller.moveCardToExileWithInfo(permanent, exileId, sourceObject.getIdName() + " exiled permanents", source, game, Zone.BATTLEFIELD, true);
}
}
}
return paid;
}
@Override
public boolean canPay(Ability ability, Ability source, UUID controllerId, Game game) {
return targets.canChoose(controllerId, source, game);
}
@Override
public WormfangDrakeExileCost copy() {
return new WormfangDrakeExileCost(this);
}
}

View file

@ -26,8 +26,9 @@ public class ExileTargetCost extends CostImpl {
List<Permanent> permanents = new ArrayList<>(); List<Permanent> permanents = new ArrayList<>();
public ExileTargetCost(TargetControlledPermanent target) { public ExileTargetCost(TargetControlledPermanent target) {
target.setNotTarget(true);
this.addTarget(target); this.addTarget(target);
this.text = "Exile " + target.getTargetName(); this.text = "exile " + target.getTargetName();
} }
public ExileTargetCost(TargetControlledPermanent target, boolean noText) { public ExileTargetCost(TargetControlledPermanent target, boolean noText) {
@ -61,7 +62,7 @@ public class ExileTargetCost extends CostImpl {
// so return state here is not important because the user indended to exile the target anyway // so return state here is not important because the user indended to exile the target anyway
} }
player.moveCardsToExile( player.moveCardsToExile(
cards.getCards(game), source, game, false, cards.getCards(game), source, game, true,
CardUtil.getExileZoneId(game, source), CardUtil.getExileZoneId(game, source),
CardUtil.getSourceName(game, source) CardUtil.getSourceName(game, source)
); );