[MID] Implemented Bloodthirsty Adversary

This commit is contained in:
Daniel Bomar 2021-09-08 13:02:04 -05:00
parent 43b3f12b56
commit d829094f90
No known key found for this signature in database
GPG key ID: C86C8658F4023918
5 changed files with 248 additions and 43 deletions

View file

@ -0,0 +1,155 @@
package mage.cards.b;
import java.util.LinkedHashSet;
import java.util.Set;
import java.util.UUID;
import mage.ApprovingObject;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
import mage.abilities.common.delayed.ReflexiveTriggeredAbility;
import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.DoIfAnyNumberCostPaid;
import mage.abilities.effects.common.counter.AddCountersSourceEffect;
import mage.cards.Card;
import mage.constants.*;
import mage.abilities.keyword.HasteAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.counters.CounterType;
import mage.filter.common.FilterInstantOrSorceryCard;
import mage.filter.predicate.mageobject.ManaValuePredicate;
import mage.game.Game;
import mage.players.Player;
import mage.target.common.TargetCardInYourGraveyard;
/**
*
* @author weirddan455
*/
public final class BloodthirstyAdversary extends CardImpl {
public BloodthirstyAdversary(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{R}");
this.subtype.add(SubType.VAMPIRE);
this.power = new MageInt(2);
this.toughness = new MageInt(2);
// Haste
this.addAbility(HasteAbility.getInstance());
// When Bloodthirsty Adversary enters the battlefield, you may pay {2}{R} any number of times.
// When you pay this cost one or more times, put that many +1/+1 counters on Bloodthirsty Adversary,
// then exile up to that many target instant and/or sorcery cards with mana value 3 or less from your graveyard and copy them.
// You may cast any number of the copies without paying their mana costs.
this.addAbility(new EntersBattlefieldTriggeredAbility(new DoIfAnyNumberCostPaid(
new BloodthirstyAdversaryEffect(), new ManaCostsImpl<>("{2}{R}")
)));
}
private BloodthirstyAdversary(final BloodthirstyAdversary card) {
super(card);
}
@Override
public BloodthirstyAdversary copy() {
return new BloodthirstyAdversary(this);
}
}
class BloodthirstyAdversaryEffect extends OneShotEffect {
private static final FilterInstantOrSorceryCard filter =
new FilterInstantOrSorceryCard("instant and/or sorcery cards with mana value 3 or less from your graveyard");
static {
filter.add(new ManaValuePredicate(ComparisonType.FEWER_THAN, 4));
}
public BloodthirstyAdversaryEffect() {
super(Outcome.Benefit);
staticText = "put that many +1/+1 counters on {this}, " +
"then exile up to that many target instant and/or sorcery cards with mana value 3 or less from your graveyard and copy them. " +
"You may cast any number of the copies without paying their mana costs";
}
private BloodthirstyAdversaryEffect(final BloodthirstyAdversaryEffect effect) {
super(effect);
}
@Override
public BloodthirstyAdversaryEffect copy() {
return new BloodthirstyAdversaryEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
if (controller == null) {
return false;
}
Integer timesPaid = (Integer) getValue("timesPaid");
if (timesPaid == null || timesPaid <= 0) {
return false;
}
ReflexiveTriggeredAbility ability = new ReflexiveTriggeredAbility(
new AddCountersSourceEffect(CounterType.P1P1.createInstance(timesPaid)),
false, staticText
);
ability.addEffect(new BloodthirstyAdversaryCopyEffect());
ability.addTarget(new TargetCardInYourGraveyard(0, timesPaid, filter));
game.fireReflexiveTriggeredAbility(ability, source);
return true;
}
}
class BloodthirstyAdversaryCopyEffect extends OneShotEffect {
public BloodthirstyAdversaryCopyEffect() {
super(Outcome.PlayForFree);
}
private BloodthirstyAdversaryCopyEffect(final BloodthirstyAdversaryCopyEffect effect) {
super(effect);
}
@Override
public BloodthirstyAdversaryCopyEffect copy() {
return new BloodthirstyAdversaryCopyEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
if (controller == null) {
return false;
}
Set<Card> cardsToExile = new LinkedHashSet<>();
for (UUID cardId : targetPointer.getTargets(game, source)) {
Card card = game.getCard(cardId);
if (card != null) {
cardsToExile.add(card);
}
}
if (cardsToExile.isEmpty()) {
return false;
}
controller.moveCards(cardsToExile, Zone.EXILED, source, game);
ApprovingObject approvingObject = new ApprovingObject(source, game);
for (Card card : cardsToExile) {
Card copiedCard = game.copyCard(card, source, controller.getId());
if (copiedCard != null && controller.chooseUse(outcome, "Cast " + copiedCard.getName() + " for free?", source, game)) {
game.getState().setValue("PlayFromNotOwnHandZone" + copiedCard.getId(), Boolean.TRUE);
controller.cast(
controller.chooseAbilityForCast(copiedCard, game, true),
game, true, approvingObject
);
game.getState().setValue("PlayFromNotOwnHandZone" + copiedCard.getId(), null);
}
}
return true;
}
}

View file

@ -7,6 +7,7 @@ import mage.abilities.common.delayed.ReflexiveTriggeredAbility;
import mage.abilities.costs.Cost;
import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.DoIfAnyNumberCostPaid;
import mage.abilities.effects.common.PhaseOutTargetEffect;
import mage.abilities.effects.common.counter.AddCountersSourceEffect;
import mage.abilities.keyword.FlashAbility;
@ -19,6 +20,7 @@ import mage.constants.SubType;
import mage.counters.CounterType;
import mage.filter.FilterPermanent;
import mage.filter.predicate.Predicates;
import mage.filter.predicate.mageobject.AnotherPredicate;
import mage.game.Game;
import mage.players.Player;
import mage.target.TargetPermanent;
@ -44,7 +46,9 @@ public final class SpectralAdversary extends CardImpl {
this.addAbility(FlyingAbility.getInstance());
// When Spectral Adversary enters the battlefield, you may pay {1}{U} any number of times. When you pay this cost one or more times, put that many +1/+1 counters on Spectral Adversary, then up to that many other target artifacts, creatures, and/or enchantments phase out.
this.addAbility(new EntersBattlefieldTriggeredAbility(new SpectralAdversaryEffect()));
this.addAbility(new EntersBattlefieldTriggeredAbility(new DoIfAnyNumberCostPaid(
new SpectralAdversaryEffect(), new ManaCostsImpl<>("{1}{U}")
)));
}
private SpectralAdversary(final SpectralAdversary card) {
@ -60,7 +64,7 @@ public final class SpectralAdversary extends CardImpl {
class SpectralAdversaryEffect extends OneShotEffect {
private static final FilterPermanent filter
= new FilterPermanent("artifacts, creatures, and/or enchantments");
= new FilterPermanent("other artifacts, creatures, and/or enchantments");
static {
filter.add(Predicates.or(
@ -68,12 +72,12 @@ class SpectralAdversaryEffect extends OneShotEffect {
CardType.CREATURE.getPredicate(),
CardType.ENCHANTMENT.getPredicate()
));
filter.add(AnotherPredicate.instance);
}
SpectralAdversaryEffect() {
super(Outcome.Benefit);
staticText = "you may pay {1}{U} any number of times. When you pay this cost one or more times, " +
"put that many +1/+1 counters on {this}, then up to that many other target " +
staticText = "put that many +1/+1 counters on {this}, then up to that many other target " +
"artifacts, creatures, and/or enchantments phase out";
}
@ -92,29 +96,16 @@ class SpectralAdversaryEffect extends OneShotEffect {
if (player == null) {
return false;
}
Cost cost = new ManaCostsImpl<>("{1}{U}");
int amount = 0;
while (player.canRespond()) {
cost.clearPaid();
if (cost.canPay(source, source, source.getControllerId(), game)
&& player.chooseUse(
outcome, "Pay {1}{U}? You have paid this cost " +
amount + " time" + (amount != 1 ? "s" : ""), source, game
) && cost.pay(source, game, source, source.getControllerId(), false)) {
amount++;
}
break;
}
if (amount == 0) {
Integer timesPaid = (Integer) getValue("timesPaid");
if (timesPaid == null || timesPaid <= 0) {
return false;
}
ReflexiveTriggeredAbility ability = new ReflexiveTriggeredAbility(
new AddCountersSourceEffect(CounterType.P1P1.createInstance(amount)),
false, "put that many +1/+1 counters on {this}, then " +
"up to that many other target artifacts, creatures, and/or enchantments phase out"
new AddCountersSourceEffect(CounterType.P1P1.createInstance(timesPaid)),
false, staticText
);
ability.addEffect(new PhaseOutTargetEffect());
ability.addTarget(new TargetPermanent(0, amount, filter));
ability.addTarget(new TargetPermanent(0, timesPaid, filter));
game.fireReflexiveTriggeredAbility(ability, source);
return true;
}

View file

@ -8,6 +8,7 @@ import mage.abilities.costs.Cost;
import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.CreateTokenEffect;
import mage.abilities.effects.common.DoIfAnyNumberCostPaid;
import mage.abilities.effects.common.counter.AddCountersSourceEffect;
import mage.abilities.keyword.DeathtouchAbility;
import mage.cards.CardImpl;
@ -38,7 +39,9 @@ public final class TaintedAdversary extends CardImpl {
this.addAbility(DeathtouchAbility.getInstance());
// When Tainted Adversary enters the battlefield, you may pay {2}{B} any number of times. When you pay this cost one or more times, put that many +1/+1 counters on Tainted Adversary, then create twice that many black 2/2 Zombie creature tokens with decayed.
this.addAbility(new EntersBattlefieldTriggeredAbility(new TaintedAdversaryEffect()));
this.addAbility(new EntersBattlefieldTriggeredAbility(new DoIfAnyNumberCostPaid(
new TaintedAdversaryEffect(), new ManaCostsImpl<>("{2}{B}")
)));
}
private TaintedAdversary(final TaintedAdversary card) {
@ -55,8 +58,7 @@ class TaintedAdversaryEffect extends OneShotEffect {
TaintedAdversaryEffect() {
super(Outcome.Benefit);
staticText = "you may pay {2}{B} any number of times. When you pay this cost " +
"one or more times, put that many +1/+1 counters on {this}, " +
staticText = "put that many +1/+1 counters on {this}, " +
"then create twice that many black 2/2 Zombie creature tokens with decayed";
}
@ -75,28 +77,15 @@ class TaintedAdversaryEffect extends OneShotEffect {
if (player == null) {
return false;
}
Cost cost = new ManaCostsImpl<>("{2}{B}");
int amount = 0;
while (player.canRespond()) {
cost.clearPaid();
if (cost.canPay(source, source, source.getControllerId(), game)
&& player.chooseUse(
outcome, "Pay {2}{B}? You have paid this cost " +
amount + " time" + (amount != 1 ? "s" : ""), source, game
) && cost.pay(source, game, source, source.getControllerId(), false)) {
amount++;
}
break;
}
if (amount == 0) {
Integer timesPaid = (Integer) getValue("timesPaid");
if (timesPaid == null || timesPaid <= 0) {
return false;
}
ReflexiveTriggeredAbility ability = new ReflexiveTriggeredAbility(
new AddCountersSourceEffect(CounterType.P1P1.createInstance(amount)),
false, "put that many +1/+1 counters on {this}, then create " +
"twice that many black 2/2 Zombie creature tokens with decayed"
new AddCountersSourceEffect(CounterType.P1P1.createInstance(timesPaid)),
false, staticText
);
ability.addEffect(new CreateTokenEffect(new ZombieDecayedToken(), 2 * amount));
ability.addEffect(new CreateTokenEffect(new ZombieDecayedToken(), 2 * timesPaid));
game.fireReflexiveTriggeredAbility(ability, source);
return true;
}

View file

@ -35,6 +35,7 @@ public final class InnistradMidnightHunt extends ExpansionSet {
cards.add(new SetCardInfo("Arrogant Outlaw", 84, Rarity.COMMON, mage.cards.a.ArrogantOutlaw.class));
cards.add(new SetCardInfo("Augur of Autumn", 168, Rarity.RARE, mage.cards.a.AugurOfAutumn.class));
cards.add(new SetCardInfo("Bladestitched Skaab", 212, Rarity.UNCOMMON, mage.cards.b.BladestitchedSkaab.class));
cards.add(new SetCardInfo("Bloodthirsty Adversary", 129, Rarity.MYTHIC, mage.cards.b.BloodthirstyAdversary.class));
cards.add(new SetCardInfo("Briarbridge Tracker", 172, Rarity.RARE, mage.cards.b.BriarbridgeTracker.class));
cards.add(new SetCardInfo("Brimstone Vandal", 130, Rarity.COMMON, mage.cards.b.BrimstoneVandal.class));
cards.add(new SetCardInfo("Burly Breaker", 174, Rarity.UNCOMMON, mage.cards.b.BurlyBreaker.class));

View file

@ -0,0 +1,69 @@
package mage.abilities.effects.common;
import mage.abilities.Ability;
import mage.abilities.Mode;
import mage.abilities.costs.Cost;
import mage.abilities.effects.Effect;
import mage.abilities.effects.OneShotEffect;
import mage.constants.Outcome;
import mage.game.Game;
import mage.players.Player;
public class DoIfAnyNumberCostPaid extends OneShotEffect {
private final Effect executingEffect;
private final Cost cost;
public DoIfAnyNumberCostPaid(OneShotEffect effect, Cost cost) {
super(Outcome.Benefit);
this.executingEffect = effect;
this.cost = cost;
}
private DoIfAnyNumberCostPaid(final DoIfAnyNumberCostPaid effect) {
super(effect);
this.executingEffect = effect.executingEffect.copy();
this.cost = effect.cost.copy();
}
@Override
public DoIfAnyNumberCostPaid copy() {
return new DoIfAnyNumberCostPaid(this);
}
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
if (controller == null) {
return false;
}
String costText = cost.getText();
int timesPaid = 0;
while (controller.canRespond()) {
cost.clearPaid();
if (cost.canPay(source, source, source.getControllerId(), game)
&& controller.chooseUse(
outcome, "Pay " + costText + "? You have paid this cost " +
timesPaid + " time" + (timesPaid != 1 ? "s" : ""), source, game
) && cost.pay(source, game, source, source.getControllerId(), false)) {
timesPaid++;
continue;
}
break;
}
if (timesPaid > 0) {
executingEffect.setValue("timesPaid", timesPaid);
return executingEffect.apply(game, source);
}
return false;
}
@Override
public String getText(Mode mode) {
if (staticText != null && !staticText.isEmpty()) {
return staticText;
}
return "you may pay " + cost.getText() + " any number of times. When you pay this cost one or more times, "
+ executingEffect.getText(mode);
}
}