Rework sacrifice effects to support "can't be sacrificed" (#11587)

* add TargetSacrifice and canBeSacrificed

* SacrificeTargetCost refactor, now uses TargetSacrifice, constructors simplified, subclasses aligned

* fix text errors introduced by refactor

* refactor SacrificeEffect, SacrificeAllEffect, SacrificeOpponentsEffect

* cleanup keyword abilities involving sacrifice

* fix a bunch of custom effect classes involving sacrifice

* fix test choices

* update Assault Suit implementation

* fix filter check arguments

* add documentation to refactored common classes

* [CLB] Implement Jon Irenicus, Shattered One

* implement "{this} can't be sacrificed"

* add tests for Assault Suit and Jon Irenicus

* refactor out PlayerToRightGainsControlOfSourceEffect

* implement [LTC] Hithlain Rope

* add choose hint to all TargetSacrifice

---------

Co-authored-by: Evan Kranzler <theelk801@gmail.com>
Co-authored-by: PurpleCrowbar <26198472+PurpleCrowbar@users.noreply.github.com>
This commit is contained in:
xenohedron 2023-12-31 14:10:37 -05:00 committed by GitHub
parent f28c5c4fc5
commit 9b3ff32a33
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
699 changed files with 1837 additions and 1619 deletions

View file

@ -192,9 +192,10 @@ public class ComputerPlayer extends PlayerImpl implements Player {
return false; return false;
} }
if (target.getOriginalTarget() instanceof TargetControlledPermanent) { if (target.getOriginalTarget() instanceof TargetControlledPermanent
|| target.getOriginalTarget() instanceof TargetSacrifice) {
List<Permanent> targets; List<Permanent> targets;
TargetControlledPermanent origTarget = (TargetControlledPermanent) target.getOriginalTarget(); TargetPermanent origTarget = (TargetPermanent) target.getOriginalTarget();
targets = threats(abilityControllerId, source, origTarget.getFilter(), game, target.getTargets()); targets = threats(abilityControllerId, source, origTarget.getFilter(), game, target.getTargets());
if (!outcome.isGood()) { if (!outcome.isGood()) {
Collections.reverse(targets); Collections.reverse(targets);
@ -689,8 +690,9 @@ public class ComputerPlayer extends PlayerImpl implements Player {
return false; return false;
} }
if (target.getOriginalTarget() instanceof TargetControlledPermanent) { if (target.getOriginalTarget() instanceof TargetControlledPermanent
TargetControlledPermanent origTarget = (TargetControlledPermanent) target.getOriginalTarget(); || target.getOriginalTarget() instanceof TargetSacrifice) {
TargetPermanent origTarget = (TargetPermanent) target.getOriginalTarget();
List<Permanent> targets; List<Permanent> targets;
targets = threats(abilityControllerId, source, origTarget.getFilter(), game, target.getTargets()); targets = threats(abilityControllerId, source, origTarget.getFilter(), game, target.getTargets());
if (!outcome.isGood()) { if (!outcome.isGood()) {

View file

@ -14,6 +14,7 @@ import mage.game.Game;
import mage.game.permanent.Permanent; import mage.game.permanent.Permanent;
import mage.game.stack.Spell; import mage.game.stack.Spell;
import mage.target.TargetPermanent; import mage.target.TargetPermanent;
import mage.target.common.TargetSacrifice;
import mage.watchers.common.SpellsCastWatcher; import mage.watchers.common.SpellsCastWatcher;
import java.util.*; import java.util.*;
@ -76,9 +77,8 @@ class AJedisFervorEffect extends OneShotEffect {
} }
//get that opponents to pick a creature or planeswalker //get that opponents to pick a creature or planeswalker
for (UUID opponentId : opponentsBlack) { for (UUID opponentId : opponentsBlack) {
TargetPermanent target = new TargetPermanent(1, 1, TargetSacrifice target = new TargetSacrifice(StaticFilters.FILTER_CONTROLLED_PERMANENT_CREATURE_OR_PLANESWALKER);
StaticFilters.FILTER_CONTROLLED_PERMANENT_CREATURE_OR_PLANESWALKER, false); game.getPlayer(opponentId).choose(Outcome.Sacrifice, target, source, game);
game.getPlayer(opponentId).chooseTarget(Outcome.Sacrifice, target, source, game);
perms.addAll(target.getTargets()); perms.addAll(target.getTargets());
} }
//sacrifices the picked cards //sacrifices the picked cards

View file

@ -29,7 +29,7 @@ public final class Abjure extends CardImpl {
super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{U}"); super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{U}");
// As an additional cost to cast Abjure, sacrifice a blue permanent. // As an additional cost to cast Abjure, sacrifice a blue permanent.
this.getSpellAbility().addCost(new SacrificeTargetCost(new TargetControlledPermanent(1,1,filter, true))); this.getSpellAbility().addCost(new SacrificeTargetCost(filter));
// Counter target spell. // Counter target spell.
this.getSpellAbility().addEffect(new CounterTargetEffect()); this.getSpellAbility().addEffect(new CounterTargetEffect());

View file

@ -16,12 +16,14 @@ import mage.constants.CardType;
import mage.constants.Outcome; import mage.constants.Outcome;
import mage.constants.SubType; import mage.constants.SubType;
import mage.constants.SuperType; import mage.constants.SuperType;
import mage.filter.StaticFilters;
import mage.game.Game; import mage.game.Game;
import mage.game.permanent.Permanent; import mage.game.permanent.Permanent;
import mage.game.permanent.token.ZombieToken; import mage.game.permanent.token.ZombieToken;
import mage.players.Player; import mage.players.Player;
import mage.target.TargetPermanent; import mage.target.TargetPermanent;
import mage.target.common.TargetControlledCreaturePermanent; import mage.target.common.TargetControlledCreaturePermanent;
import mage.target.common.TargetSacrifice;
import mage.watchers.common.CompletedDungeonWatcher; import mage.watchers.common.CompletedDungeonWatcher;
import java.util.UUID; import java.util.UUID;
@ -101,8 +103,7 @@ class AcererakTheArchlichEffect extends OneShotEffect {
if (player == null) { if (player == null) {
continue; continue;
} }
TargetPermanent target = new TargetControlledCreaturePermanent(0, 1); TargetSacrifice target = new TargetSacrifice(0, 1, StaticFilters.FILTER_PERMANENT_CREATURE);
target.withNotTarget(true);
player.choose(Outcome.Sacrifice, target, source, game); player.choose(Outcome.Sacrifice, target, source, game);
Permanent permanent = game.getPermanent(target.getFirstTarget()); Permanent permanent = game.getPermanent(target.getFirstTarget());
if (permanent != null && permanent.sacrifice(source, game)) { if (permanent != null && permanent.sacrifice(source, game)) {

View file

@ -37,7 +37,7 @@ public final class AgentOfShauku extends CardImpl {
// {1}{B}, Sacrifice a land: Target creature gets +2/+0 until end of turn. // {1}{B}, Sacrifice a land: Target creature gets +2/+0 until end of turn.
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new BoostTargetEffect(2, 0, Duration.EndOfTurn), new ManaCostsImpl<>("{1}{B}")); Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new BoostTargetEffect(2, 0, Duration.EndOfTurn), new ManaCostsImpl<>("{1}{B}"));
ability.addCost(new SacrificeTargetCost(new TargetControlledPermanent(filter))); ability.addCost(new SacrificeTargetCost(filter));
ability.addTarget(new TargetCreaturePermanent()); ability.addTarget(new TargetCreaturePermanent());
this.addAbility(ability); this.addAbility(ability);
} }
@ -50,4 +50,4 @@ public final class AgentOfShauku extends CardImpl {
public AgentOfShauku copy() { public AgentOfShauku copy() {
return new AgentOfShauku(this); return new AgentOfShauku(this);
} }
} }

View file

@ -14,6 +14,7 @@ import mage.constants.CardType;
import mage.constants.Duration; import mage.constants.Duration;
import mage.constants.Outcome; import mage.constants.Outcome;
import mage.constants.Zone; import mage.constants.Zone;
import mage.filter.StaticFilters;
import mage.filter.common.FilterControlledLandPermanent; import mage.filter.common.FilterControlledLandPermanent;
import mage.game.Game; import mage.game.Game;
import mage.game.events.GameEvent; import mage.game.events.GameEvent;
@ -35,7 +36,7 @@ public final class AggressiveMining extends CardImpl {
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new AggressiveMiningEffect())); this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new AggressiveMiningEffect()));
// Sacrifice a land: Draw two cards. Activate this ability only once each turn. // Sacrifice a land: Draw two cards. Activate this ability only once each turn.
Cost cost = new SacrificeTargetCost(new TargetControlledPermanent(new FilterControlledLandPermanent("a land"))); Cost cost = new SacrificeTargetCost(StaticFilters.FILTER_LAND);
this.addAbility(new LimitedTimesPerTurnActivatedAbility(Zone.BATTLEFIELD, new DrawCardSourceControllerEffect(2), cost)); this.addAbility(new LimitedTimesPerTurnActivatedAbility(Zone.BATTLEFIELD, new DrawCardSourceControllerEffect(2), cost));
} }

View file

@ -54,7 +54,7 @@ public final class AhnCropInvader extends CardImpl {
Ability ability = new SimpleActivatedAbility( Ability ability = new SimpleActivatedAbility(
new BoostSourceEffect(2, 0, Duration.EndOfTurn), new GenericManaCost(1) new BoostSourceEffect(2, 0, Duration.EndOfTurn), new GenericManaCost(1)
); );
ability.addCost(new SacrificeTargetCost(new TargetControlledPermanent(StaticFilters.FILTER_CONTROLLED_ANOTHER_CREATURE))); ability.addCost(new SacrificeTargetCost(StaticFilters.FILTER_CONTROLLED_ANOTHER_CREATURE));
this.addAbility(ability); this.addAbility(ability);
} }

View file

@ -43,7 +43,7 @@ public final class AirdropCondor extends CardImpl {
// {1}{R}, Sacrifice a Goblin creature: Airdrop Condor deals damage equal to the sacrificed creature's power to any target. // {1}{R}, Sacrifice a Goblin creature: Airdrop Condor deals damage equal to the sacrificed creature's power to any target.
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DamageTargetEffect(SacrificeCostCreaturesPower.instance) Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DamageTargetEffect(SacrificeCostCreaturesPower.instance)
.setText("{this} deals damage equal to the sacrificed creature's power to any target"), new ManaCostsImpl<>("{1}{R}")); .setText("{this} deals damage equal to the sacrificed creature's power to any target"), new ManaCostsImpl<>("{1}{R}"));
ability.addCost(new SacrificeTargetCost(new TargetControlledCreaturePermanent(filter))); ability.addCost(new SacrificeTargetCost(filter));
ability.addTarget(new TargetAnyTarget()); ability.addTarget(new TargetAnyTarget());
this.addAbility(ability); this.addAbility(ability);
} }

View file

@ -33,7 +33,7 @@ public final class AkkiAvalanchers extends CardImpl {
this.toughness = new MageInt(1); this.toughness = new MageInt(1);
// Sacrifice a land: Akki Avalanchers gets +2/+0 until end of turn. Activate this ability only once each turn. // Sacrifice a land: Akki Avalanchers gets +2/+0 until end of turn. Activate this ability only once each turn.
this.addAbility(new LimitedTimesPerTurnActivatedAbility(Zone.BATTLEFIELD, new BoostSourceEffect(2, 0, Duration.EndOfTurn), new SacrificeTargetCost(new TargetControlledPermanent(filter)))); this.addAbility(new LimitedTimesPerTurnActivatedAbility(Zone.BATTLEFIELD, new BoostSourceEffect(2, 0, Duration.EndOfTurn), new SacrificeTargetCost(filter)));
} }
private AkkiAvalanchers(final AkkiAvalanchers card) { private AkkiAvalanchers(final AkkiAvalanchers card) {

View file

@ -41,7 +41,7 @@ public final class AkutaBornOfAsh extends CardImpl {
// At the beginning of your upkeep, if you have more cards in hand than each opponent, you may sacrifice a Swamp. If you do, return Akuta, Born of Ash from your graveyard to the battlefield. // At the beginning of your upkeep, if you have more cards in hand than each opponent, you may sacrifice a Swamp. If you do, return Akuta, Born of Ash from your graveyard to the battlefield.
Ability ability = new ConditionalInterveningIfTriggeredAbility( Ability ability = new ConditionalInterveningIfTriggeredAbility(
new BeginningOfUpkeepTriggeredAbility(Zone.GRAVEYARD, new BeginningOfUpkeepTriggeredAbility(Zone.GRAVEYARD,
new DoIfCostPaid(new ReturnSourceFromGraveyardToBattlefieldEffect(), new SacrificeTargetCost(new TargetControlledPermanent(filterSwamp))), new DoIfCostPaid(new ReturnSourceFromGraveyardToBattlefieldEffect(), new SacrificeTargetCost(filterSwamp)),
TargetController.YOU, false), TargetController.YOU, false),
MoreCardsInHandThanOpponentsCondition.instance, MoreCardsInHandThanOpponentsCondition.instance,
"At the beginning of your upkeep, if you have more cards in hand than each opponent, you may sacrifice a Swamp. If you do, return {this} from your graveyard to the battlefield."); "At the beginning of your upkeep, if you have more cards in hand than each opponent, you may sacrifice a Swamp. If you do, return {this} from your graveyard to the battlefield.");
@ -57,4 +57,3 @@ public final class AkutaBornOfAsh extends CardImpl {
return new AkutaBornOfAsh(this); return new AkutaBornOfAsh(this);
} }
} }

View file

@ -21,7 +21,7 @@ public final class AltarsReap extends CardImpl {
// As an additional cost to cast Altar's Reap, sacrifice a creature. // As an additional cost to cast Altar's Reap, sacrifice a creature.
this.getSpellAbility().addCost(new SacrificeTargetCost(new TargetControlledCreaturePermanent(1,1, StaticFilters.FILTER_CONTROLLED_CREATURE_SHORT_TEXT, true))); this.getSpellAbility().addCost(new SacrificeTargetCost(StaticFilters.FILTER_CONTROLLED_CREATURE_SHORT_TEXT));
// Draw two cards. // Draw two cards.
this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(2)); this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(2));
} }

View file

@ -48,7 +48,7 @@ public final class AmbushCommander extends CardImpl {
// {1}{G}, Sacrifice an Elf: Target creature gets +3/+3 until end of turn. // {1}{G}, Sacrifice an Elf: Target creature gets +3/+3 until end of turn.
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new BoostTargetEffect(3, 3, Duration.EndOfTurn), Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new BoostTargetEffect(3, 3, Duration.EndOfTurn),
new ManaCostsImpl<>("{1}{G}")); new ManaCostsImpl<>("{1}{G}"));
ability.addCost(new SacrificeTargetCost(new TargetControlledPermanent(1, filter))); ability.addCost(new SacrificeTargetCost(filter));
ability.addTarget(new TargetCreaturePermanent()); ability.addTarget(new TargetCreaturePermanent());
this.addAbility(ability); this.addAbility(ability);
} }

View file

@ -45,7 +45,7 @@ public final class AnakinSkywalker extends CardImpl {
// Sacrifice another creature: Target creature gets -1/-1 until end of turn. Activate this ability only as a sorcery. // Sacrifice another creature: Target creature gets -1/-1 until end of turn. Activate this ability only as a sorcery.
Ability ability = new ActivateAsSorceryActivatedAbility(Zone.BATTLEFIELD, new BoostTargetEffect(-1, -1, Duration.EndOfTurn), Ability ability = new ActivateAsSorceryActivatedAbility(Zone.BATTLEFIELD, new BoostTargetEffect(-1, -1, Duration.EndOfTurn),
new SacrificeTargetCost(new TargetControlledCreaturePermanent(StaticFilters.FILTER_CONTROLLED_ANOTHER_CREATURE))); new SacrificeTargetCost(StaticFilters.FILTER_CONTROLLED_ANOTHER_CREATURE));
ability.addTarget(new TargetCreaturePermanent()); ability.addTarget(new TargetCreaturePermanent());
this.addAbility(ability); this.addAbility(ability);

View file

@ -7,6 +7,7 @@ import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.CardType;
import mage.filter.FilterPermanent; import mage.filter.FilterPermanent;
import mage.filter.StaticFilters;
import mage.filter.common.FilterControlledPermanent; import mage.filter.common.FilterControlledPermanent;
import mage.filter.predicate.Predicates; import mage.filter.predicate.Predicates;
import mage.target.TargetPermanent; import mage.target.TargetPermanent;
@ -30,7 +31,7 @@ public final class AngelicPurge extends CardImpl {
super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{2}{W}"); super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{2}{W}");
// As an additional cost to cast Angelic Purge, sacrifice a permanent. // As an additional cost to cast Angelic Purge, sacrifice a permanent.
this.getSpellAbility().addCost(new SacrificeTargetCost(new TargetControlledPermanent(new FilterControlledPermanent("a permanent")))); this.getSpellAbility().addCost(new SacrificeTargetCost(StaticFilters.FILTER_PERMANENT));
// Exile target artifact, creature, or enchantment. // Exile target artifact, creature, or enchantment.
this.getSpellAbility().addEffect(new ExileTargetEffect()); this.getSpellAbility().addEffect(new ExileTargetEffect());

View file

@ -14,7 +14,7 @@ import mage.constants.SubType;
import mage.filter.FilterCard; import mage.filter.FilterCard;
import mage.filter.predicate.mageobject.NamePredicate; import mage.filter.predicate.mageobject.NamePredicate;
import mage.target.common.TargetCardInLibrary; import mage.target.common.TargetCardInLibrary;
import mage.target.common.TargetControlledCreatureEachColor; import mage.target.common.TargetSacrificeCreatureEachColor;
import java.util.UUID; import java.util.UUID;
@ -43,7 +43,7 @@ public final class AngelsHerald extends CardImpl {
new TargetCardInLibrary(filter)), new ManaCostsImpl<>("{2}{W}") new TargetCardInLibrary(filter)), new ManaCostsImpl<>("{2}{W}")
); );
ability.addCost(new TapSourceCost()); ability.addCost(new TapSourceCost());
ability.addCost(new SacrificeTargetCost(new TargetControlledCreatureEachColor("GWU"))); ability.addCost(new SacrificeTargetCost(new TargetSacrificeCreatureEachColor("GWU")));
this.addAbility(ability); this.addAbility(ability);
} }

View file

@ -27,7 +27,7 @@ public final class AnnihilatingGlare extends CardImpl {
// As an additional cost to cast this spell, pay {4} or sacrifice an artifact or creature. // As an additional cost to cast this spell, pay {4} or sacrifice an artifact or creature.
this.getSpellAbility().addCost(new OrCost("pay {4} or sacrifice an artifact or creature", this.getSpellAbility().addCost(new OrCost("pay {4} or sacrifice an artifact or creature",
new GenericManaCost(4), new GenericManaCost(4),
new SacrificeTargetCost(new TargetControlledPermanent(StaticFilters.FILTER_CONTROLLED_PERMANENT_ARTIFACT_OR_CREATURE)) new SacrificeTargetCost(StaticFilters.FILTER_CONTROLLED_PERMANENT_ARTIFACT_OR_CREATURE)
)); ));
// Destroy target creature or planeswalker. // Destroy target creature or planeswalker.
this.getSpellAbility().addEffect(new DestroyTargetEffect()); this.getSpellAbility().addEffect(new DestroyTargetEffect());

View file

@ -32,7 +32,7 @@ public final class ApocalypseDemon extends CardImpl {
this.addAbility(new SimpleStaticAbility(Zone.ALL, new SetBasePowerToughnessSourceEffect(new CardsInControllerGraveyardCount()))); this.addAbility(new SimpleStaticAbility(Zone.ALL, new SetBasePowerToughnessSourceEffect(new CardsInControllerGraveyardCount())));
// At the beginning of your upkeep, tap Apocalypse Demon unless you sacrifice another creature. // At the beginning of your upkeep, tap Apocalypse Demon unless you sacrifice another creature.
TapSourceUnlessPaysEffect tapEffect = new TapSourceUnlessPaysEffect(new SacrificeTargetCost(new TargetControlledPermanent(StaticFilters.FILTER_CONTROLLED_ANOTHER_CREATURE))); TapSourceUnlessPaysEffect tapEffect = new TapSourceUnlessPaysEffect(new SacrificeTargetCost(StaticFilters.FILTER_CONTROLLED_ANOTHER_CREATURE));
tapEffect.setText("tap {this} unless you sacrifice another creature."); tapEffect.setText("tap {this} unless you sacrifice another creature.");
this.addAbility(new BeginningOfUpkeepTriggeredAbility(tapEffect, TargetController.YOU, false)); this.addAbility(new BeginningOfUpkeepTriggeredAbility(tapEffect, TargetController.YOU, false));
} }

View file

@ -34,7 +34,7 @@ public final class ArcaneSpyglass extends CardImpl {
// {2}, {T} , Sacrifice a land: Draw a card and put a charge counter on Arcane Spyglass. // {2}, {T} , Sacrifice a land: Draw a card and put a charge counter on Arcane Spyglass.
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DrawCardSourceControllerEffect(1), new GenericManaCost(2)); Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DrawCardSourceControllerEffect(1), new GenericManaCost(2));
ability.addCost(new TapSourceCost()); ability.addCost(new TapSourceCost());
ability.addCost(new SacrificeTargetCost(new TargetControlledPermanent(filter))); ability.addCost(new SacrificeTargetCost(filter));
ability.addEffect(new AddCountersSourceEffect(CounterType.CHARGE.createInstance()).concatBy("and")); ability.addEffect(new AddCountersSourceEffect(CounterType.CHARGE.createInstance()).concatBy("and"));
this.addAbility(ability); this.addAbility(ability);

View file

@ -35,7 +35,7 @@ public final class ArcboundRavager extends CardImpl {
this.toughness = new MageInt(0); this.toughness = new MageInt(0);
// Sacrifice an artifact: Put a +1/+1 counter on Arcbound Ravager. // Sacrifice an artifact: Put a +1/+1 counter on Arcbound Ravager.
this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new AddCountersSourceEffect(CounterType.P1P1.createInstance()), new SacrificeTargetCost(new TargetControlledPermanent(filter)))); this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new AddCountersSourceEffect(CounterType.P1P1.createInstance()), new SacrificeTargetCost(filter)));
// Modular 1 // Modular 1
this.addAbility(new ModularAbility(this, 1)); this.addAbility(new ModularAbility(this, 1));
} }

View file

@ -18,6 +18,7 @@ import mage.game.events.GameEvent;
import mage.game.permanent.Permanent; import mage.game.permanent.Permanent;
import mage.players.Player; import mage.players.Player;
import mage.target.common.TargetControlledPermanent; import mage.target.common.TargetControlledPermanent;
import mage.target.common.TargetSacrifice;
import java.util.UUID; import java.util.UUID;
@ -82,7 +83,7 @@ public final class ArchdemonOfGreed extends CardImpl {
// create cost for sacrificing a human // create cost for sacrificing a human
Player player = game.getPlayer(source.getControllerId()); Player player = game.getPlayer(source.getControllerId());
if (player != null) { if (player != null) {
TargetControlledPermanent target = new TargetControlledPermanent(1, 1, filter, false); TargetSacrifice target = new TargetSacrifice(filter);
// if they can pay the cost, then they must pay // if they can pay the cost, then they must pay
if (target.canChoose(player.getId(), source, game)) { if (target.canChoose(player.getId(), source, game)) {
player.choose(Outcome.Sacrifice, target, source, game); player.choose(Outcome.Sacrifice, target, source, game);

View file

@ -36,7 +36,7 @@ public final class ArensonsAura extends CardImpl {
// {W}, Sacrifice an enchantment: Destroy target enchantment. // {W}, Sacrifice an enchantment: Destroy target enchantment.
Ability ability = new SimpleActivatedAbility(new DestroyTargetEffect(), new ManaCostsImpl<>("{W}")); Ability ability = new SimpleActivatedAbility(new DestroyTargetEffect(), new ManaCostsImpl<>("{W}"));
ability.addCost(new SacrificeTargetCost(new TargetControlledPermanent(1, 1, filter, true))); ability.addCost(new SacrificeTargetCost(filter));
ability.addTarget(new TargetEnchantmentPermanent().withChooseHint("to destroy")); ability.addTarget(new TargetEnchantmentPermanent().withChooseHint("to destroy"));
this.addAbility(ability); this.addAbility(ability);
// {3}{U}{U}: Counter target enchantment spell. // {3}{U}{U}: Counter target enchantment spell.

View file

@ -14,6 +14,7 @@ import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.Outcome; import mage.constants.Outcome;
import mage.constants.SubType; import mage.constants.SubType;
import mage.filter.StaticFilters;
import mage.filter.common.FilterControlledLandPermanent; import mage.filter.common.FilterControlledLandPermanent;
import mage.game.Game; import mage.game.Game;
import mage.players.Player; import mage.players.Player;
@ -70,7 +71,7 @@ class ArgothianWurmEffect extends PutOnLibrarySourceEffect {
if (controller != null) { if (controller != null) {
boolean costPaid = false; boolean costPaid = false;
for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) {
Cost cost = new SacrificeTargetCost(new TargetControlledPermanent(new FilterControlledLandPermanent())); Cost cost = new SacrificeTargetCost(StaticFilters.FILTER_LAND);
Player player = game.getPlayer(playerId); Player player = game.getPlayer(playerId);
if (player != null if (player != null
&& cost.canPay(source, source, playerId, game) && cost.canPay(source, source, playerId, game)
@ -86,4 +87,4 @@ class ArgothianWurmEffect extends PutOnLibrarySourceEffect {
} }
return false; return false;
} }
} }

View file

@ -40,7 +40,7 @@ public final class ArmsDealer extends CardImpl {
SimpleActivatedAbility ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, SimpleActivatedAbility ability = new SimpleActivatedAbility(Zone.BATTLEFIELD,
new DamageTargetEffect(4), new DamageTargetEffect(4),
new ManaCostsImpl<>("{1}{R}")); new ManaCostsImpl<>("{1}{R}"));
ability.addCost(new SacrificeTargetCost(new TargetControlledPermanent(filter))); ability.addCost(new SacrificeTargetCost(filter));
ability.addTarget(new TargetCreaturePermanent()); ability.addTarget(new TargetCreaturePermanent());
this.addAbility(ability); this.addAbility(ability);
} }

View file

@ -33,7 +33,7 @@ public final class ArmyAnts extends CardImpl {
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD,
new DestroyTargetEffect(), new DestroyTargetEffect(),
new TapSourceCost()); new TapSourceCost());
ability.addCost(new SacrificeTargetCost(new TargetControlledPermanent(StaticFilters.FILTER_CONTROLLED_LAND_SHORT_TEXT))); ability.addCost(new SacrificeTargetCost(StaticFilters.FILTER_CONTROLLED_LAND_SHORT_TEXT));
ability.addTarget(new TargetLandPermanent()); ability.addTarget(new TargetLandPermanent());
this.addAbility(ability); this.addAbility(ability);
} }

View file

@ -20,7 +20,7 @@ public final class Artillerize extends CardImpl {
public Artillerize(UUID ownerId, CardSetInfo setInfo) { public Artillerize(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{3}{R}"); super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{3}{R}");
this.getSpellAbility().addCost(new SacrificeTargetCost(new TargetControlledPermanent(StaticFilters.FILTER_CONTROLLED_ARTIFACT_OR_CREATURE_SHORT_TEXT))); this.getSpellAbility().addCost(new SacrificeTargetCost(StaticFilters.FILTER_CONTROLLED_ARTIFACT_OR_CREATURE_SHORT_TEXT));
this.getSpellAbility().addTarget(new TargetAnyTarget()); this.getSpellAbility().addTarget(new TargetAnyTarget());
this.getSpellAbility().addEffect(new DamageTargetEffect(5)); this.getSpellAbility().addEffect(new DamageTargetEffect(5));
} }

View file

@ -43,7 +43,7 @@ public final class AshnodFleshMechanist extends CardImpl {
new DoIfCostPaid( new DoIfCostPaid(
new CreateTokenEffect( new CreateTokenEffect(
new PowerstoneToken(), 1, true, false new PowerstoneToken(), 1, true, false
), new SacrificeTargetCost(new TargetControlledPermanent(StaticFilters.FILTER_CONTROLLED_ANOTHER_CREATURE)) ), new SacrificeTargetCost(StaticFilters.FILTER_CONTROLLED_ANOTHER_CREATURE)
), false ), false
)); ));

View file

@ -66,7 +66,7 @@ public final class Asmoranomardicadaistinaculdacar extends CardImpl {
// Sacrifice two Foods: Target creature deals 6 damage to itself. // Sacrifice two Foods: Target creature deals 6 damage to itself.
Ability ability = new SimpleActivatedAbility( Ability ability = new SimpleActivatedAbility(
new AsmoranomardicadaistinaculdacarEffect(), new AsmoranomardicadaistinaculdacarEffect(),
new SacrificeTargetCost(new TargetControlledPermanent(2, filter2)) new SacrificeTargetCost(2, filter2)
); );
ability.addTarget(new TargetCreaturePermanent()); ability.addTarget(new TargetCreaturePermanent());
this.addAbility(ability); this.addAbility(ability);

View file

@ -1,13 +1,10 @@
package mage.cards.a; package mage.cards.a;
import mage.abilities.Ability; 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.costs.mana.GenericManaCost;
import mage.abilities.effects.ContinuousEffect; import mage.abilities.effects.ContinuousEffect;
import mage.abilities.effects.ContinuousRuleModifyingEffectImpl; import mage.abilities.effects.ContinuousEffectImpl;
import mage.abilities.effects.Effect;
import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.combat.CantAttackControllerAttachedEffect; import mage.abilities.effects.common.combat.CantAttackControllerAttachedEffect;
import mage.abilities.effects.common.continuous.BoostEquippedEffect; import mage.abilities.effects.common.continuous.BoostEquippedEffect;
@ -19,11 +16,11 @@ import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.*; import mage.constants.*;
import mage.game.Game; import mage.game.Game;
import mage.game.events.GameEvent;
import mage.game.permanent.Permanent; import mage.game.permanent.Permanent;
import mage.players.Player; import mage.players.Player;
import mage.target.targetpointer.FixedTarget; import mage.target.targetpointer.FixedTarget;
import java.util.Optional;
import java.util.UUID; import java.util.UUID;
/** /**
@ -36,23 +33,22 @@ public final class AssaultSuit extends CardImpl {
this.subtype.add(SubType.EQUIPMENT); this.subtype.add(SubType.EQUIPMENT);
// Equipped creature gets +2/+2, has haste, can't attack you or a planeswalker you control, and can't be sacrificed. // Equipped creature gets +2/+2, has haste, can't attack you or a planeswalker you control, and can't be sacrificed.
Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostEquippedEffect(2, 2)); Ability ability = new SimpleStaticAbility(new BoostEquippedEffect(2, 2));
Effect effect = new GainAbilityAttachedEffect(HasteAbility.getInstance(), AttachmentType.EQUIPMENT); ability.addEffect(new GainAbilityAttachedEffect(
effect.setText(", has haste"); HasteAbility.getInstance(), AttachmentType.EQUIPMENT
ability.addEffect(effect); ).setText(", has haste"));
effect = new CantAttackControllerAttachedEffect(AttachmentType.EQUIPMENT, true); ability.addEffect(new CantAttackControllerAttachedEffect(AttachmentType.EQUIPMENT, true)
effect.setText(", can't attack you or planeswalkers you control"); .setText(", can't attack you or planeswalkers you control"));
ability.addEffect(effect); ability.addEffect(new AssaultSuitCantBeSacrificed());
effect = new AssaultSuitCantBeSacrificed();
effect.setText(", and can't be sacrificed");
ability.addEffect(effect);
this.addAbility(ability); this.addAbility(ability);
// At the beginning of each opponent's upkeep, you may have that player gain control of equipped creature until end of turn. If you do, untap it. // At the beginning of each opponent's upkeep, you may have that player gain control of equipped creature until end of turn. If you do, untap it.
this.addAbility(new BeginningOfUpkeepTriggeredAbility(new AssaultSuitGainControlEffect(), TargetController.OPPONENT, false)); this.addAbility(new BeginningOfUpkeepTriggeredAbility(
new AssaultSuitGainControlEffect(), TargetController.OPPONENT, false
));
// Equip {3} // Equip {3}
this.addAbility(new EquipAbility(Outcome.Detriment, new GenericManaCost(3), false)); this.addAbility(new EquipAbility(3, false));
} }
private AssaultSuit(final AssaultSuit card) { private AssaultSuit(final AssaultSuit card) {
@ -65,14 +61,14 @@ public final class AssaultSuit extends CardImpl {
} }
} }
class AssaultSuitCantBeSacrificed extends ContinuousRuleModifyingEffectImpl { class AssaultSuitCantBeSacrificed extends ContinuousEffectImpl {
public AssaultSuitCantBeSacrificed() { public AssaultSuitCantBeSacrificed() {
super(Duration.WhileOnBattlefield, Outcome.Detriment, true, false); super(Duration.WhileOnBattlefield, Layer.RulesEffects, SubLayer.NA, Outcome.Benefit);
staticText = "and can't be sacrificed"; staticText = ", and can't be sacrificed";
} }
private AssaultSuitCantBeSacrificed(final AssaultSuitCantBeSacrificed effect) { public AssaultSuitCantBeSacrificed(final AssaultSuitCantBeSacrificed effect) {
super(effect); super(effect);
} }
@ -82,19 +78,12 @@ class AssaultSuitCantBeSacrificed extends ContinuousRuleModifyingEffectImpl {
} }
@Override @Override
public String getInfoMessage(Ability source, GameEvent event, Game game) { public boolean apply(Game game, Ability source) {
return "This creature can't be sacrificed."; Optional.ofNullable(source.getSourcePermanentIfItStillExists(game))
} .map(Permanent::getAttachedTo)
.map(game::getPermanent)
@Override .ifPresent(permanent -> permanent.setCanBeSacrificed(false));
public boolean checksEventType(GameEvent event, Game game) { return true;
return event.getType() == GameEvent.EventType.SACRIFICE_PERMANENT;
}
@Override
public boolean applies(GameEvent event, Ability source, Game game) {
Permanent equipment = game.getPermanent(source.getSourceId());
return equipment != null && equipment.isAttachedTo(event.getTargetId());
} }
} }
@ -105,7 +94,7 @@ class AssaultSuitGainControlEffect extends OneShotEffect {
this.staticText = "you may have that player gain control of equipped creature until end of turn. If you do, untap it"; this.staticText = "you may have that player gain control of equipped creature until end of turn. If you do, untap it";
} }
private AssaultSuitGainControlEffect(final AssaultSuitGainControlEffect effect) { public AssaultSuitGainControlEffect(final AssaultSuitGainControlEffect effect) {
super(effect); super(effect);
} }
@ -118,22 +107,24 @@ class AssaultSuitGainControlEffect extends OneShotEffect {
public boolean apply(Game game, Ability source) { public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId()); Player controller = game.getPlayer(source.getControllerId());
Player activePlayer = game.getPlayer(game.getActivePlayerId()); Player activePlayer = game.getPlayer(game.getActivePlayerId());
Permanent equipment = game.getPermanent(source.getSourceId()); Permanent equipment = source.getSourcePermanentIfItStillExists(game);
if (controller != null && activePlayer != null && equipment != null) { if (controller == null || activePlayer == null || equipment == null) {
if (equipment.getAttachedTo() != null) { return false;
Permanent equippedCreature = game.getPermanent(equipment.getAttachedTo()); }
if (equippedCreature != null && controller.chooseUse(outcome, if (equipment.getAttachedTo() == null) {
"Let have " + activePlayer.getLogName() + " gain control of " + equippedCreature.getLogName() + '?', source, game)) {
equippedCreature.untap(game);
ContinuousEffect effect = new GainControlTargetEffect(Duration.EndOfTurn, activePlayer.getId());
effect.setTargetPointer(new FixedTarget(equipment.getAttachedTo(), game));
game.addEffect(effect, source);
}
}
return true; return true;
} }
Permanent equippedCreature = game.getPermanent(equipment.getAttachedTo());
if (equippedCreature == null || !controller.chooseUse(outcome,
"Have " + activePlayer.getLogName() + " gain control of " + equippedCreature.getLogName() + '?', source, game)) {
return true;
}
equippedCreature.untap(game);
ContinuousEffect effect = new GainControlTargetEffect(Duration.EndOfTurn, activePlayer.getId());
effect.setTargetPointer(new FixedTarget(equipment.getAttachedTo(), game));
game.addEffect(effect, source);
return true;
return false;
} }
} }

View file

@ -27,7 +27,7 @@ public final class Atog extends CardImpl {
this.toughness = new MageInt(2); this.toughness = new MageInt(2);
this.addAbility(new SimpleActivatedAbility( this.addAbility(new SimpleActivatedAbility(
new BoostSourceEffect(2, 2, Duration.EndOfTurn), new BoostSourceEffect(2, 2, Duration.EndOfTurn),
new SacrificeTargetCost(new TargetControlledPermanent(StaticFilters.FILTER_CONTROLLED_PERMANENT_ARTIFACT_AN)) new SacrificeTargetCost(StaticFilters.FILTER_CONTROLLED_PERMANENT_ARTIFACT_AN)
)); ));
} }

View file

@ -12,6 +12,7 @@ import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.*; import mage.constants.*;
import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.common.FilterControlledCreaturePermanent;
import mage.filter.common.FilterCreaturePermanent;
import mage.target.common.TargetControlledCreaturePermanent; import mage.target.common.TargetControlledCreaturePermanent;
/** /**
@ -20,12 +21,7 @@ import mage.target.common.TargetControlledCreaturePermanent;
*/ */
public final class Atogatog extends CardImpl { public final class Atogatog extends CardImpl {
private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("an Atog creature"); private static final FilterCreaturePermanent filter = new FilterCreaturePermanent(SubType.ATOG, "an Atog creature");
static {
filter.add(TargetController.YOU.getControllerPredicate());
filter.add(SubType.ATOG.getPredicate());
}
public Atogatog(UUID ownerId, CardSetInfo setInfo) { public Atogatog(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{W}{U}{B}{R}{G}"); super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{W}{U}{B}{R}{G}");
@ -38,8 +34,8 @@ public final class Atogatog extends CardImpl {
DynamicValue xValue = SacrificeCostCreaturesPower.instance; DynamicValue xValue = SacrificeCostCreaturesPower.instance;
// Sacrifice an Atog creature: Atogatog gets +X/+X until end of turn, where X is the sacrificed creature's power. // Sacrifice an Atog creature: Atogatog gets +X/+X until end of turn, where X is the sacrificed creature's power.
this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD,
new BoostSourceEffect(xValue, xValue,Duration.EndOfTurn), new BoostSourceEffect(xValue, xValue, Duration.EndOfTurn),
new SacrificeTargetCost(new TargetControlledCreaturePermanent(1,1,new FilterControlledCreaturePermanent(SubType.ATOG, "an Atog creature"), false)))); new SacrificeTargetCost(filter)));
} }

View file

@ -24,7 +24,7 @@ public final class Attrition extends CardImpl {
//{B}, Sacrifice a creature: Destroy target nonblack creature. //{B}, Sacrifice a creature: Destroy target nonblack creature.
SimpleActivatedAbility ability = new SimpleActivatedAbility(new DestroyTargetEffect(), new ColoredManaCost(ColoredManaSymbol.B)); SimpleActivatedAbility ability = new SimpleActivatedAbility(new DestroyTargetEffect(), new ColoredManaCost(ColoredManaSymbol.B));
ability.addCost(new SacrificeTargetCost(new TargetControlledCreaturePermanent(StaticFilters.FILTER_CONTROLLED_CREATURE_SHORT_TEXT))); ability.addCost(new SacrificeTargetCost(StaticFilters.FILTER_CONTROLLED_CREATURE_SHORT_TEXT));
ability.addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_PERMANENT_CREATURE_NON_BLACK).withChooseHint("to destroy")); ability.addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_PERMANENT_CREATURE_NON_BLACK).withChooseHint("to destroy"));
this.addAbility(ability); this.addAbility(ability);
} }

View file

@ -33,9 +33,7 @@ public final class AudaciousReshapers extends CardImpl {
// {T}, Sacrifice an artifact: Reveal cards from the top of your library until you reveal an artifact card. Put that card onto the battlefield and the rest on the bottom of your library in a random order. Audacious Reshapers deals damage to you equal to the number of cards revealed this way. // {T}, Sacrifice an artifact: Reveal cards from the top of your library until you reveal an artifact card. Put that card onto the battlefield and the rest on the bottom of your library in a random order. Audacious Reshapers deals damage to you equal to the number of cards revealed this way.
Ability ability = new SimpleActivatedAbility(new AudaciousReshapersEffect(), new TapSourceCost()); Ability ability = new SimpleActivatedAbility(new AudaciousReshapersEffect(), new TapSourceCost());
ability.addCost(new SacrificeTargetCost(new TargetControlledPermanent( ability.addCost(new SacrificeTargetCost(StaticFilters.FILTER_CONTROLLED_PERMANENT_ARTIFACT_AN));
StaticFilters.FILTER_CONTROLLED_PERMANENT_ARTIFACT_AN
)));
this.addAbility(ability); this.addAbility(ability);
} }

View file

@ -10,6 +10,7 @@ import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.Zone; import mage.constants.Zone;
import mage.filter.StaticFilters;
import mage.filter.common.FilterControlledLandPermanent; import mage.filter.common.FilterControlledLandPermanent;
import mage.target.common.TargetControlledPermanent; import mage.target.common.TargetControlledPermanent;
import mage.target.common.TargetEnchantmentPermanent; import mage.target.common.TargetEnchantmentPermanent;
@ -27,7 +28,7 @@ public final class AuraFracture extends CardImpl {
Ability ability = new SimpleActivatedAbility( Ability ability = new SimpleActivatedAbility(
Zone.BATTLEFIELD, Zone.BATTLEFIELD,
new DestroyTargetEffect(), new DestroyTargetEffect(),
new SacrificeTargetCost(new TargetControlledPermanent(new FilterControlledLandPermanent("land")))); new SacrificeTargetCost(StaticFilters.FILTER_LAND));
ability.addTarget(new TargetEnchantmentPermanent()); ability.addTarget(new TargetEnchantmentPermanent());
this.addAbility(ability); this.addAbility(ability);
} }

View file

@ -33,7 +33,7 @@ public final class Auratog extends CardImpl {
this.power = new MageInt(1); this.power = new MageInt(1);
this.toughness = new MageInt(2); this.toughness = new MageInt(2);
this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new BoostSourceEffect(2, 2, Duration.EndOfTurn), new SacrificeTargetCost(new TargetControlledPermanent(filter)))); this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new BoostSourceEffect(2, 2, Duration.EndOfTurn), new SacrificeTargetCost(filter)));
} }
private Auratog(final Auratog card) { private Auratog(final Auratog card) {

View file

@ -59,7 +59,7 @@ public final class AyaraFirstOfLocthwain extends CardImpl {
// {T}, Sacrifice another black creature: Draw a card. // {T}, Sacrifice another black creature: Draw a card.
ability = new SimpleActivatedAbility(new DrawCardSourceControllerEffect(1), new TapSourceCost()); ability = new SimpleActivatedAbility(new DrawCardSourceControllerEffect(1), new TapSourceCost());
ability.addCost(new SacrificeTargetCost(new TargetControlledPermanent(filter2))); ability.addCost(new SacrificeTargetCost(filter2));
this.addAbility(ability); this.addAbility(ability);
} }

View file

@ -46,7 +46,7 @@ public final class AyliEternalPilgrim extends CardImpl {
Effect effect = new GainLifeEffect(SacrificeCostCreaturesToughness.instance); Effect effect = new GainLifeEffect(SacrificeCostCreaturesToughness.instance);
effect.setText("You gain life equal to the sacrificed creature's toughness"); effect.setText("You gain life equal to the sacrificed creature's toughness");
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, effect, new GenericManaCost(1)); Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, effect, new GenericManaCost(1));
ability.addCost(new SacrificeTargetCost(new TargetControlledPermanent(StaticFilters.FILTER_CONTROLLED_ANOTHER_CREATURE))); ability.addCost(new SacrificeTargetCost(StaticFilters.FILTER_CONTROLLED_ANOTHER_CREATURE));
this.addAbility(ability); this.addAbility(ability);
// {1}{W}{B}, Sacrifice another creature: Exile target nonland permanent. Activate only if you have at least 10 life more than your starting life total. // {1}{W}{B}, Sacrifice another creature: Exile target nonland permanent. Activate only if you have at least 10 life more than your starting life total.
@ -56,7 +56,7 @@ public final class AyliEternalPilgrim extends CardImpl {
new ManaCostsImpl<>("{1}{W}{B}"), new ManaCostsImpl<>("{1}{W}{B}"),
new AyliEternalPilgrimCondition() new AyliEternalPilgrimCondition()
); );
ability.addCost(new SacrificeTargetCost(new TargetControlledPermanent(StaticFilters.FILTER_CONTROLLED_ANOTHER_CREATURE))); ability.addCost(new SacrificeTargetCost(StaticFilters.FILTER_CONTROLLED_ANOTHER_CREATURE));
ability.addTarget(new TargetNonlandPermanent().withChooseHint("to exile")); ability.addTarget(new TargetNonlandPermanent().withChooseHint("to exile"));
this.addAbility(ability); this.addAbility(ability);
} }

View file

@ -13,7 +13,7 @@ import mage.filter.StaticFilters;
import mage.game.Game; import mage.game.Game;
import mage.game.permanent.Permanent; import mage.game.permanent.Permanent;
import mage.players.Player; import mage.players.Player;
import mage.target.common.TargetControlledPermanent; import mage.target.common.TargetSacrifice;
import mage.util.CardUtil; import mage.util.CardUtil;
import java.util.*; import java.util.*;
@ -50,10 +50,10 @@ public final class BabaLysagaNightWitch extends CardImpl {
class BabaLysagaNightWitchSacrificeCost extends SacrificeTargetCost { class BabaLysagaNightWitchSacrificeCost extends SacrificeTargetCost {
private Set<CardType> sacrificeTypes = new HashSet<>(); private final Set<CardType> sacrificeTypes = new HashSet<>();
BabaLysagaNightWitchSacrificeCost() { BabaLysagaNightWitchSacrificeCost() {
super(new TargetControlledPermanent(0, 3, StaticFilters.FILTER_CONTROLLED_PERMANENTS, true)); super(new TargetSacrifice(0, 3, StaticFilters.FILTER_CONTROLLED_PERMANENTS));
setText("Sacrifice up to three permanents"); setText("Sacrifice up to three permanents");
} }

View file

@ -64,7 +64,7 @@ public final class BagOfDevouring extends CardImpl {
// {2}, {T}, Sacrifice another artifact or creature: Draw a card. // {2}, {T}, Sacrifice another artifact or creature: Draw a card.
Ability ability = new SimpleActivatedAbility(new DrawCardSourceControllerEffect(1), new GenericManaCost(2)); Ability ability = new SimpleActivatedAbility(new DrawCardSourceControllerEffect(1), new GenericManaCost(2));
ability.addCost(new TapSourceCost()); ability.addCost(new TapSourceCost());
ability.addCost(new SacrificeTargetCost(new TargetControlledPermanent(filter2))); ability.addCost(new SacrificeTargetCost(filter2));
this.addAbility(ability); this.addAbility(ability);
// {3}, {T}, Sacrifice Bag of Devouring: Roll a d10. Return up to X cards from among cards exiled with Bag of Devouring to their owners' hands, where X is the result. // {3}, {T}, Sacrifice Bag of Devouring: Roll a d10. Return up to X cards from among cards exiled with Bag of Devouring to their owners' hands, where X is the result.

View file

@ -39,7 +39,7 @@ public final class BalduvianTradingPost extends CardImpl {
super(ownerId,setInfo,new CardType[]{CardType.LAND},""); super(ownerId,setInfo,new CardType[]{CardType.LAND},"");
// If Balduvian Trading Post would enter the battlefield, sacrifice an untapped Mountain instead. If you do, put Balduvian Trading Post onto the battlefield. If you don't, put it into its owner's graveyard. // If Balduvian Trading Post would enter the battlefield, sacrifice an untapped Mountain instead. If you do, put Balduvian Trading Post onto the battlefield. If you don't, put it into its owner's graveyard.
this.addAbility(new SimpleStaticAbility(Zone.ALL, new EnterBattlefieldPayCostOrPutGraveyardEffect(new SacrificeTargetCost(new TargetControlledPermanent(filter))))); this.addAbility(new SimpleStaticAbility(Zone.ALL, new EnterBattlefieldPayCostOrPutGraveyardEffect(new SacrificeTargetCost(filter))));
// {tap}: Add {C}{R}. // {tap}: Add {C}{R}.
this.addAbility(new SimpleManaAbility(Zone.BATTLEFIELD, new Mana(0, 0, 0, 1, 0, 0, 0, 1), new TapSourceCost())); this.addAbility(new SimpleManaAbility(Zone.BATTLEFIELD, new Mana(0, 0, 0, 1, 0, 0, 0, 1), new TapSourceCost()));

View file

@ -8,6 +8,7 @@ import mage.constants.CardType;
import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.common.FilterControlledCreaturePermanent;
import mage.filter.common.FilterControlledPermanent; import mage.filter.common.FilterControlledPermanent;
import mage.target.common.TargetControlledPermanent; import mage.target.common.TargetControlledPermanent;
import mage.target.common.TargetSacrifice;
import java.util.UUID; import java.util.UUID;
@ -23,7 +24,7 @@ public final class BankruptInBlood extends CardImpl {
super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{1}{B}"); super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{1}{B}");
// As an additional cost to cast this spell, sacrifice two creatures. // As an additional cost to cast this spell, sacrifice two creatures.
this.getSpellAbility().addCost(new SacrificeTargetCost(new TargetControlledPermanent(2, filter))); this.getSpellAbility().addCost(new SacrificeTargetCost(2, filter));
// Draw three cards. // Draw three cards.
this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(3)); this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(3));

View file

@ -63,7 +63,7 @@ public final class BanquetGuests extends CardImpl {
new GainAbilitySourceEffect(IndestructibleAbility.getInstance(), Duration.EndOfTurn), new GainAbilitySourceEffect(IndestructibleAbility.getInstance(), Duration.EndOfTurn),
new GenericManaCost(2) new GenericManaCost(2)
); );
ability.addCost(new SacrificeTargetCost(new TargetControlledPermanent(StaticFilters.FILTER_CONTROLLED_FOOD))); ability.addCost(new SacrificeTargetCost(StaticFilters.FILTER_CONTROLLED_FOOD));
this.addAbility(ability); this.addAbility(ability);
} }

View file

@ -38,7 +38,7 @@ public final class BarrageOgre extends CardImpl {
this.toughness = new MageInt(3); this.toughness = new MageInt(3);
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DamageTargetEffect(2), new TapSourceCost()); Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DamageTargetEffect(2), new TapSourceCost());
ability.addTarget(new TargetAnyTarget()); ability.addTarget(new TargetAnyTarget());
ability.addCost(new SacrificeTargetCost(new TargetControlledPermanent(filter))); ability.addCost(new SacrificeTargetCost(filter));
this.addAbility(ability); this.addAbility(ability);
} }

View file

@ -48,7 +48,7 @@ public final class BarrageTyrant extends CardImpl {
Effect effect = new DamageTargetEffect(SacrificeCostCreaturesPower.instance); Effect effect = new DamageTargetEffect(SacrificeCostCreaturesPower.instance);
effect.setText("{this} deals damage equal to the sacrificed creature's power to any target"); effect.setText("{this} deals damage equal to the sacrificed creature's power to any target");
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, effect, new ManaCostsImpl<>("{2}{R}")); Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, effect, new ManaCostsImpl<>("{2}{R}"));
ability.addCost(new SacrificeTargetCost(new TargetControlledCreaturePermanent(filter))); ability.addCost(new SacrificeTargetCost(filter));
ability.addTarget(new TargetAnyTarget()); ability.addTarget(new TargetAnyTarget());
this.addAbility(ability); this.addAbility(ability);
} }

View file

@ -28,9 +28,7 @@ public final class BayouGroff extends CardImpl {
// As an additional cost to cast this spell, sacrifice a creature or pay {3}. // As an additional cost to cast this spell, sacrifice a creature or pay {3}.
this.getSpellAbility().addCost(new OrCost( this.getSpellAbility().addCost(new OrCost(
"sacrifice a creature or pay {3}", new SacrificeTargetCost(new TargetControlledPermanent( "sacrifice a creature or pay {3}", new SacrificeTargetCost(StaticFilters.FILTER_CONTROLLED_CREATURE_SHORT_TEXT), new GenericManaCost(3)
StaticFilters.FILTER_CONTROLLED_CREATURE_SHORT_TEXT
)), new GenericManaCost(3)
)); ));
} }

View file

@ -14,7 +14,7 @@ import mage.constants.SubType;
import mage.filter.FilterCard; import mage.filter.FilterCard;
import mage.filter.predicate.mageobject.NamePredicate; import mage.filter.predicate.mageobject.NamePredicate;
import mage.target.common.TargetCardInLibrary; import mage.target.common.TargetCardInLibrary;
import mage.target.common.TargetControlledCreatureEachColor; import mage.target.common.TargetSacrificeCreatureEachColor;
import java.util.UUID; import java.util.UUID;
@ -42,7 +42,7 @@ public final class BehemothsHerald extends CardImpl {
new TargetCardInLibrary(filter)), new ManaCostsImpl<>("{2}{G}") new TargetCardInLibrary(filter)), new ManaCostsImpl<>("{2}{G}")
); );
ability.addCost(new TapSourceCost()); ability.addCost(new TapSourceCost());
ability.addCost(new SacrificeTargetCost(new TargetControlledCreatureEachColor("RGW"))); ability.addCost(new SacrificeTargetCost(new TargetSacrificeCreatureEachColor("RGW")));
this.addAbility(ability); this.addAbility(ability);
} }

View file

@ -17,6 +17,7 @@ import mage.game.Game;
import mage.game.permanent.Permanent; import mage.game.permanent.Permanent;
import mage.players.Player; import mage.players.Player;
import mage.target.TargetPermanent; import mage.target.TargetPermanent;
import mage.target.common.TargetSacrifice;
/** /**
* *
@ -68,10 +69,10 @@ class BellowingMaulerEffect extends OneShotEffect {
Player player = game.getPlayer(playerId); Player player = game.getPlayer(playerId);
if (player != null) { if (player != null) {
boolean sacrificed = false; boolean sacrificed = false;
TargetPermanent target = new TargetPermanent(1, 1, StaticFilters.FILTER_CONTROLLED_CREATURE_NON_TOKEN, true); TargetSacrifice target = new TargetSacrifice(StaticFilters.FILTER_CONTROLLED_CREATURE_NON_TOKEN);
if (target.canChoose(playerId, source, game) if (target.canChoose(playerId, source, game)
&& player.chooseUse(Outcome.Sacrifice, "Sacrifice a nontoken creature or lose 4 life?", null, "Sacrifice", "Lose 4 life", source, game)) { && player.chooseUse(Outcome.Sacrifice, "Sacrifice a nontoken creature or lose 4 life?", null, "Sacrifice", "Lose 4 life", source, game)) {
player.chooseTarget(Outcome.Sacrifice, target, source, game); player.choose(Outcome.Sacrifice, target, source, game);
Permanent permanent = game.getPermanent(target.getFirstTarget()); Permanent permanent = game.getPermanent(target.getFirstTarget());
sacrificed = permanent != null && permanent.sacrifice(source, game); sacrificed = permanent != null && permanent.sacrifice(source, game);
} }

View file

@ -37,7 +37,7 @@ public final class BetrayalOfFlesh extends CardImpl {
mode.addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD)); mode.addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD));
this.getSpellAbility().getModes().addMode(mode); this.getSpellAbility().getModes().addMode(mode);
// Entwine-Sacrifice three lands. // Entwine-Sacrifice three lands.
this.addAbility(new EntwineAbility(new SacrificeTargetCost(new TargetControlledPermanent(3, 3, new FilterControlledLandPermanent("lands"), true)))); this.addAbility(new EntwineAbility(new SacrificeTargetCost(3, StaticFilters.FILTER_LANDS)));
} }
private BetrayalOfFlesh(final BetrayalOfFlesh card) { private BetrayalOfFlesh(final BetrayalOfFlesh card) {

View file

@ -49,7 +49,7 @@ public final class BetrothedOfFire extends CardImpl {
// Sacrifice an untapped creature: Enchanted creature gets +2/+0 until end of turn. // Sacrifice an untapped creature: Enchanted creature gets +2/+0 until end of turn.
this.addAbility(new SimpleActivatedAbility( this.addAbility(new SimpleActivatedAbility(
new BoostEnchantedEffect(2, 0, Duration.EndOfTurn), new BoostEnchantedEffect(2, 0, Duration.EndOfTurn),
new SacrificeTargetCost(new TargetControlledPermanent(filter)) new SacrificeTargetCost(filter)
)); ));
// Sacrifice enchanted creature: Creatures you control get +2/+0 until end of turn. // Sacrifice enchanted creature: Creatures you control get +2/+0 until end of turn.

View file

@ -36,7 +36,7 @@ public final class BillThePony extends CardImpl {
// Sacrifice a Food: Until end of turn, target creature you control assigns combat damage equal to its toughness rather than its power. // Sacrifice a Food: Until end of turn, target creature you control assigns combat damage equal to its toughness rather than its power.
Ability ability = new SimpleActivatedAbility( Ability ability = new SimpleActivatedAbility(
new CombatDamageByToughnessTargetEffect(Duration.EndOfTurn), new CombatDamageByToughnessTargetEffect(Duration.EndOfTurn),
new SacrificeTargetCost(new TargetControlledPermanent(StaticFilters.FILTER_CONTROLLED_FOOD)) new SacrificeTargetCost(StaticFilters.FILTER_CONTROLLED_FOOD)
); );
ability.addTarget(new TargetPermanent(StaticFilters.FILTER_CONTROLLED_CREATURE)); ability.addTarget(new TargetPermanent(StaticFilters.FILTER_CONTROLLED_CREATURE));
@ -51,4 +51,4 @@ public final class BillThePony extends CardImpl {
public BillThePony copy() { public BillThePony copy() {
return new BillThePony(this); return new BillThePony(this);
} }
} }

View file

@ -11,6 +11,7 @@ import mage.constants.Duration;
import mage.constants.SubType; import mage.constants.SubType;
import mage.filter.common.FilterControlledPermanent; import mage.filter.common.FilterControlledPermanent;
import mage.target.common.TargetControlledPermanent; import mage.target.common.TargetControlledPermanent;
import mage.target.common.TargetSacrifice;
import java.util.UUID; import java.util.UUID;
@ -34,7 +35,7 @@ public final class BiolumeSerpent extends CardImpl {
// Sacrifice two Islands: Biolume Serpent can't be blocked this turn. // Sacrifice two Islands: Biolume Serpent can't be blocked this turn.
this.addAbility(new SimpleActivatedAbility( this.addAbility(new SimpleActivatedAbility(
new CantBeBlockedSourceEffect(Duration.EndOfTurn), new CantBeBlockedSourceEffect(Duration.EndOfTurn),
new SacrificeTargetCost(new TargetControlledPermanent(2, filter)) new SacrificeTargetCost(2, filter)
)); ));
} }

View file

@ -40,9 +40,7 @@ public final class BirthingPod extends CardImpl {
Zone.BATTLEFIELD, new BirthingPodEffect(), new ManaCostsImpl<>("{1}{G/P}") Zone.BATTLEFIELD, new BirthingPodEffect(), new ManaCostsImpl<>("{1}{G/P}")
); );
ability.addCost(new TapSourceCost()); ability.addCost(new TapSourceCost());
ability.addCost(new SacrificeTargetCost(new TargetControlledCreaturePermanent( ability.addCost(new SacrificeTargetCost(StaticFilters.FILTER_CONTROLLED_CREATURE_SHORT_TEXT));
StaticFilters.FILTER_CONTROLLED_CREATURE_SHORT_TEXT
)));
this.addAbility(ability); this.addAbility(ability);
} }

View file

@ -34,7 +34,7 @@ public final class BjornaNightfallAlchemist extends CardImpl {
// {T}, Sacrifice an artifact: Lucas, the Sharpshooter deals 1 damage to target creature. Goad that creature. // {T}, Sacrifice an artifact: Lucas, the Sharpshooter deals 1 damage to target creature. Goad that creature.
Ability ability = new SimpleActivatedAbility(new DamageTargetEffect(1), new TapSourceCost()); Ability ability = new SimpleActivatedAbility(new DamageTargetEffect(1), new TapSourceCost());
ability.addCost(new SacrificeTargetCost(new TargetControlledPermanent(StaticFilters.FILTER_CONTROLLED_PERMANENT_ARTIFACT_AN))); ability.addCost(new SacrificeTargetCost(StaticFilters.FILTER_CONTROLLED_PERMANENT_ARTIFACT_AN));
ability.addEffect(new GoadTargetEffect().setText("Goad that creature")); ability.addEffect(new GoadTargetEffect().setText("Goad that creature"));
ability.addTarget(new TargetCreaturePermanent()); ability.addTarget(new TargetCreaturePermanent());
this.addAbility(ability); this.addAbility(ability);

View file

@ -31,7 +31,7 @@ public final class BlazingHellhound extends CardImpl {
// {1}, Sacrifice another creature: Blazing Hellhound deals 1 damage to any target. // {1}, Sacrifice another creature: Blazing Hellhound deals 1 damage to any target.
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DamageTargetEffect(1), new ManaCostsImpl<>("{1}")); Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DamageTargetEffect(1), new ManaCostsImpl<>("{1}"));
ability.addCost(new SacrificeTargetCost(new TargetControlledPermanent(StaticFilters.FILTER_CONTROLLED_ANOTHER_CREATURE))); ability.addCost(new SacrificeTargetCost(StaticFilters.FILTER_CONTROLLED_ANOTHER_CREATURE));
ability.addTarget(new TargetAnyTarget()); ability.addTarget(new TargetAnyTarget());
this.addAbility(ability); this.addAbility(ability);
} }

View file

@ -41,7 +41,7 @@ public final class BlightedShaman extends CardImpl {
// {tap}, Sacrifice a Swamp: Target creature gets +1/+1 until end of turn. // {tap}, Sacrifice a Swamp: Target creature gets +1/+1 until end of turn.
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new BoostTargetEffect(1, 1, Duration.EndOfTurn), new TapSourceCost()); Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new BoostTargetEffect(1, 1, Duration.EndOfTurn), new TapSourceCost());
ability.addCost(new SacrificeTargetCost(new TargetControlledPermanent(filterSwamp))); ability.addCost(new SacrificeTargetCost(filterSwamp));
ability.addTarget(new TargetCreaturePermanent()); ability.addTarget(new TargetCreaturePermanent());
this.addAbility(ability); this.addAbility(ability);

View file

@ -56,7 +56,7 @@ public final class BloodAspirant extends CardImpl {
new DamageTargetEffect(1), new ManaCostsImpl<>("{1}{R}") new DamageTargetEffect(1), new ManaCostsImpl<>("{1}{R}")
); );
ability.addCost(new TapSourceCost()); ability.addCost(new TapSourceCost());
ability.addCost(new SacrificeTargetCost(new TargetControlledPermanent(filter))); ability.addCost(new SacrificeTargetCost(filter));
ability.addEffect(new CantBlockTargetEffect(Duration.EndOfTurn) ability.addEffect(new CantBlockTargetEffect(Duration.EndOfTurn)
.setText("That creature can't block this turn.")); .setText("That creature can't block this turn."));
ability.addTarget(new TargetCreaturePermanent()); ability.addTarget(new TargetCreaturePermanent());
@ -102,4 +102,4 @@ class BloodAspirantAbility extends TriggeredAbilityImpl {
public String getRule() { public String getRule() {
return "Whenever you sacrifice a permanent, put a +1/+1 counter on {this}."; return "Whenever you sacrifice a permanent, put a +1/+1 counter on {this}.";
} }
} }

View file

@ -32,7 +32,7 @@ public final class BloodBairn extends CardImpl {
this.addAbility(new SimpleActivatedAbility( this.addAbility(new SimpleActivatedAbility(
Zone.BATTLEFIELD, Zone.BATTLEFIELD,
new BoostSourceEffect(2, 2, Duration.EndOfTurn), new BoostSourceEffect(2, 2, Duration.EndOfTurn),
new SacrificeTargetCost(new TargetControlledCreaturePermanent(1, 1, StaticFilters.FILTER_CONTROLLED_ANOTHER_CREATURE, true)))); new SacrificeTargetCost(StaticFilters.FILTER_CONTROLLED_ANOTHER_CREATURE)));
} }

View file

@ -47,7 +47,7 @@ public final class BloodChinFanatic extends CardImpl {
effect2.setText("and you gain X life, where X is the sacrificed creature's power"); effect2.setText("and you gain X life, where X is the sacrificed creature's power");
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, effect, new ManaCostsImpl<>("{1}{B}")); Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, effect, new ManaCostsImpl<>("{1}{B}"));
ability.addEffect(effect2); ability.addEffect(effect2);
ability.addCost(new SacrificeTargetCost(new TargetControlledPermanent(filter))); ability.addCost(new SacrificeTargetCost(filter));
ability.addTarget(new TargetPlayer()); ability.addTarget(new TargetPlayer());
this.addAbility(ability); this.addAbility(ability);

View file

@ -36,7 +36,7 @@ public final class BloodHost extends CardImpl {
Effect effect = new AddCountersSourceEffect(CounterType.P1P1.createInstance()); Effect effect = new AddCountersSourceEffect(CounterType.P1P1.createInstance());
effect.setText("Put a +1/+1 counter on {this}"); effect.setText("Put a +1/+1 counter on {this}");
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, effect, new ManaCostsImpl<>("{1}{B}")); Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, effect, new ManaCostsImpl<>("{1}{B}"));
ability.addCost(new SacrificeTargetCost(new TargetControlledPermanent(StaticFilters.FILTER_CONTROLLED_ANOTHER_CREATURE))); ability.addCost(new SacrificeTargetCost(StaticFilters.FILTER_CONTROLLED_ANOTHER_CREATURE));
// and you gain 2 life. // and you gain 2 life.
effect = new GainLifeEffect(2); effect = new GainLifeEffect(2);
effect.setText("and you gain 2 life"); effect.setText("and you gain 2 life");

View file

@ -30,7 +30,7 @@ public final class BloodmistInfiltrator extends CardImpl {
// Whenever Bloodmist Infiltrator attacks, you may sacrifice another creature. If you do, Bloodmist Infiltrator can't be blocked this turn. // Whenever Bloodmist Infiltrator attacks, you may sacrifice another creature. If you do, Bloodmist Infiltrator can't be blocked this turn.
this.addAbility(new AttacksTriggeredAbility(new DoIfCostPaid( this.addAbility(new AttacksTriggeredAbility(new DoIfCostPaid(
new CantBeBlockedSourceEffect(Duration.EndOfTurn), new CantBeBlockedSourceEffect(Duration.EndOfTurn),
new SacrificeTargetCost(new TargetControlledPermanent(StaticFilters.FILTER_CONTROLLED_ANOTHER_CREATURE)) new SacrificeTargetCost(StaticFilters.FILTER_CONTROLLED_ANOTHER_CREATURE)
), false)); ), false));
} }

View file

@ -31,9 +31,7 @@ public final class BloodsoakedAltar extends CardImpl {
); );
ability.addCost(new PayLifeCost(2)); ability.addCost(new PayLifeCost(2));
ability.addCost(new DiscardCardCost()); ability.addCost(new DiscardCardCost());
ability.addCost(new SacrificeTargetCost(new TargetControlledPermanent( ability.addCost(new SacrificeTargetCost(StaticFilters.FILTER_CONTROLLED_CREATURE_SHORT_TEXT));
StaticFilters.FILTER_CONTROLLED_CREATURE_SHORT_TEXT
)));
this.addAbility(ability); this.addAbility(ability);
} }

View file

@ -12,6 +12,7 @@ import mage.filter.common.FilterControlledLandPermanent;
import mage.filter.common.FilterControlledPermanent; import mage.filter.common.FilterControlledPermanent;
import mage.target.TargetPlayer; import mage.target.TargetPlayer;
import mage.target.common.TargetControlledPermanent; import mage.target.common.TargetControlledPermanent;
import mage.target.common.TargetSacrifice;
import java.util.UUID; import java.util.UUID;
@ -27,7 +28,7 @@ public final class BogDown extends CardImpl {
super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{B}"); super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{B}");
// Kicker-Sacrifice two lands. // Kicker-Sacrifice two lands.
this.addAbility(new KickerAbility(new SacrificeTargetCost(new TargetControlledPermanent(2, filter)))); this.addAbility(new KickerAbility(new SacrificeTargetCost(2, filter)));
// Target player discards two cards. If Bog Down was kicked, that player discards three cards instead. // Target player discards two cards. If Bog Down was kicked, that player discards three cards instead.
this.getSpellAbility().addEffect(new ConditionalOneShotEffect(new DiscardTargetEffect(3), this.getSpellAbility().addEffect(new ConditionalOneShotEffect(new DiscardTargetEffect(3),

View file

@ -34,7 +34,7 @@ public final class BogElemental extends CardImpl {
// At the beginning of your upkeep, sacrifice Bog Elemental unless you sacrifice a land. // At the beginning of your upkeep, sacrifice Bog Elemental unless you sacrifice a land.
this.addAbility(new BeginningOfUpkeepTriggeredAbility(Zone.BATTLEFIELD, this.addAbility(new BeginningOfUpkeepTriggeredAbility(Zone.BATTLEFIELD,
new SacrificeSourceUnlessPaysEffect(new SacrificeTargetCost(new TargetControlledPermanent(StaticFilters.FILTER_CONTROLLED_LAND_SHORT_TEXT))), new SacrificeSourceUnlessPaysEffect(new SacrificeTargetCost(StaticFilters.FILTER_CONTROLLED_LAND_SHORT_TEXT)),
TargetController.YOU, TargetController.YOU,
false)); false));
} }

View file

@ -48,7 +48,7 @@ public final class BogGlider extends CardImpl {
// {T}, Sacrifice a land: Search your library for a Mercenary permanent card with converted mana cost 2 or less and put it onto the battlefield. Then shuffle your library. // {T}, Sacrifice a land: Search your library for a Mercenary permanent card with converted mana cost 2 or less and put it onto the battlefield. Then shuffle your library.
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new SearchLibraryPutInPlayEffect(new TargetCardInLibrary(filter)), new TapSourceCost()); Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new SearchLibraryPutInPlayEffect(new TargetCardInLibrary(filter)), new TapSourceCost());
ability.addCost(new SacrificeTargetCost(new TargetControlledPermanent(landFilter))); ability.addCost(new SacrificeTargetCost(landFilter));
this.addAbility(ability); this.addAbility(ability);
} }
@ -60,4 +60,4 @@ public final class BogGlider extends CardImpl {
public BogGlider copy() { public BogGlider copy() {
return new BogGlider(this); return new BogGlider(this);
} }
} }

View file

@ -37,7 +37,7 @@ public final class BogNaughty extends CardImpl {
Ability ability = new SimpleActivatedAbility( Ability ability = new SimpleActivatedAbility(
new BoostTargetEffect(-3, -3, Duration.EndOfTurn), new ManaCostsImpl<>("{2}{B}") new BoostTargetEffect(-3, -3, Duration.EndOfTurn), new ManaCostsImpl<>("{2}{B}")
); );
ability.addCost(new SacrificeTargetCost(new TargetControlledPermanent(StaticFilters.FILTER_CONTROLLED_FOOD))); ability.addCost(new SacrificeTargetCost(StaticFilters.FILTER_CONTROLLED_FOOD));
ability.addTarget(new TargetCreaturePermanent()); ability.addTarget(new TargetCreaturePermanent());
this.addAbility(ability); this.addAbility(ability);
} }

View file

@ -33,7 +33,7 @@ public final class BogardanDragonheart extends CardImpl {
// Sacrifice another creature: Until end of turn, Bogardan Dragonheart becomes a Dragon with base power and toughness 4/4, flying, and haste. // Sacrifice another creature: Until end of turn, Bogardan Dragonheart becomes a Dragon with base power and toughness 4/4, flying, and haste.
this.addAbility(new SimpleActivatedAbility(new BecomesCreatureSourceEffect( this.addAbility(new SimpleActivatedAbility(new BecomesCreatureSourceEffect(
new BogardanDragonheartToken(), CardType.CREATURE, Duration.EndOfTurn new BogardanDragonheartToken(), CardType.CREATURE, Duration.EndOfTurn
), new SacrificeTargetCost(new TargetControlledPermanent(StaticFilters.FILTER_CONTROLLED_ANOTHER_CREATURE)))); ), new SacrificeTargetCost(StaticFilters.FILTER_CONTROLLED_ANOTHER_CREATURE)));
} }
private BogardanDragonheart(final BogardanDragonheart card) { private BogardanDragonheart(final BogardanDragonheart card) {

View file

@ -49,9 +49,7 @@ public final class BolassCitadel extends CardImpl {
// {T}, Sacrifice ten nonland permanents: Each opponent loses 10 life. // {T}, Sacrifice ten nonland permanents: Each opponent loses 10 life.
Ability ability = new SimpleActivatedAbility(new LoseLifeOpponentsEffect(10), new TapSourceCost()); Ability ability = new SimpleActivatedAbility(new LoseLifeOpponentsEffect(10), new TapSourceCost());
ability.addCost(new SacrificeTargetCost(new TargetControlledPermanent( ability.addCost(new SacrificeTargetCost(10, filter));
10, 10, filter, true
)));
this.addAbility(ability); this.addAbility(ability);
} }

View file

@ -7,6 +7,7 @@ import mage.abilities.effects.common.DestroyTargetEffect;
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.filter.StaticFilters;
import mage.target.common.TargetControlledCreaturePermanent; import mage.target.common.TargetControlledCreaturePermanent;
import mage.target.common.TargetCreatureOrPlaneswalker; import mage.target.common.TargetCreatureOrPlaneswalker;
@ -22,7 +23,7 @@ public final class BoneShards extends CardImpl {
// As an additional cost to cast this spell, sacrifice a creature or discard a card. // As an additional cost to cast this spell, sacrifice a creature or discard a card.
this.getSpellAbility().addCost(new OrCost( this.getSpellAbility().addCost(new OrCost(
"sacrifice a creature or discard a card", new SacrificeTargetCost(new TargetControlledCreaturePermanent()), "sacrifice a creature or discard a card", new SacrificeTargetCost(StaticFilters.FILTER_PERMANENT_CREATURE),
new DiscardCardCost() new DiscardCardCost()
)); ));

View file

@ -58,7 +58,7 @@ public final class BontuTheGlorified extends CardImpl {
Effect effect = new GainLifeEffect(1); Effect effect = new GainLifeEffect(1);
effect.setText("and you gain 1 life"); effect.setText("and you gain 1 life");
ability.addEffect(effect); ability.addEffect(effect);
ability.addCost(new SacrificeTargetCost(new TargetControlledPermanent(StaticFilters.FILTER_CONTROLLED_ANOTHER_CREATURE))); ability.addCost(new SacrificeTargetCost(StaticFilters.FILTER_CONTROLLED_ANOTHER_CREATURE));
this.addAbility(ability); this.addAbility(ability);
} }

View file

@ -16,6 +16,7 @@ import mage.constants.CardType;
import mage.constants.SubType; import mage.constants.SubType;
import mage.constants.SuperType; import mage.constants.SuperType;
import mage.constants.Zone; import mage.constants.Zone;
import mage.filter.StaticFilters;
import mage.filter.common.FilterControlledArtifactPermanent; import mage.filter.common.FilterControlledArtifactPermanent;
import mage.target.common.TargetAnyTarget; import mage.target.common.TargetAnyTarget;
import mage.target.common.TargetControlledPermanent; import mage.target.common.TargetControlledPermanent;
@ -42,7 +43,7 @@ public final class BoshIronGolem extends CardImpl {
Effect effect = new DamageTargetEffect(SacrificeCostManaValue.ARTIFACT); Effect effect = new DamageTargetEffect(SacrificeCostManaValue.ARTIFACT);
effect.setText("{this} deals damage equal to the sacrificed artifact's mana value to any target"); effect.setText("{this} deals damage equal to the sacrificed artifact's mana value to any target");
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, effect, new ManaCostsImpl<>("{3}{R}")); Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, effect, new ManaCostsImpl<>("{3}{R}"));
ability.addCost(new SacrificeTargetCost(new TargetControlledPermanent(new FilterControlledArtifactPermanent("an artifact")))); ability.addCost(new SacrificeTargetCost(StaticFilters.FILTER_PERMANENT_ARTIFACT));
ability.addTarget(new TargetAnyTarget()); ability.addTarget(new TargetAnyTarget());
this.addAbility(ability); this.addAbility(ability);
} }

View file

@ -48,7 +48,7 @@ public final class BoundByMoonsilver extends CardImpl {
// Sacrifice another permanent: Attach Bound by Moonsilver to target creature. Activate this ability only any time you could cast a sorcery and only once each turn. // Sacrifice another permanent: Attach Bound by Moonsilver to target creature. Activate this ability only any time you could cast a sorcery and only once each turn.
LimitedTimesPerTurnActivatedAbility limitedAbility = new LimitedTimesPerTurnActivatedAbility(Zone.BATTLEFIELD, new AttachEffect(Outcome.Detriment, "Attach {this} to target creature"), LimitedTimesPerTurnActivatedAbility limitedAbility = new LimitedTimesPerTurnActivatedAbility(Zone.BATTLEFIELD, new AttachEffect(Outcome.Detriment, "Attach {this} to target creature"),
new SacrificeTargetCost(new TargetControlledPermanent(filter)), 1); new SacrificeTargetCost(filter), 1);
limitedAbility.setTiming(TimingRule.SORCERY); limitedAbility.setTiming(TimingRule.SORCERY);
limitedAbility.addTarget(new TargetCreaturePermanent()); limitedAbility.addTarget(new TargetCreaturePermanent());
this.addAbility(limitedAbility); this.addAbility(limitedAbility);

View file

@ -18,6 +18,7 @@ import mage.game.Game;
import mage.game.permanent.Permanent; import mage.game.permanent.Permanent;
import mage.players.Player; import mage.players.Player;
import mage.target.common.TargetControlledPermanent; import mage.target.common.TargetControlledPermanent;
import mage.target.common.TargetSacrifice;
import mage.util.CardUtil; import mage.util.CardUtil;
/** /**
@ -86,11 +87,11 @@ class BraidsArisenNightmareEffect extends OneShotEffect {
if (controller == null) { if (controller == null) {
return false; return false;
} }
TargetControlledPermanent target = new TargetControlledPermanent(1, 1, filter, true); TargetSacrifice target = new TargetSacrifice(filter);
if (!target.canChoose(controller.getId(), source, game)) { if (!target.canChoose(controller.getId(), source, game)) {
return false; return false;
} }
controller.chooseTarget(Outcome.Sacrifice, target, source, game); controller.choose(Outcome.Sacrifice, target, source, game);
Permanent permanent = game.getPermanent(target.getFirstTarget()); Permanent permanent = game.getPermanent(target.getFirstTarget());
if (permanent == null) { if (permanent == null) {
return false; return false;
@ -115,14 +116,14 @@ class BraidsArisenNightmareEffect extends OneShotEffect {
} }
private boolean braidsSacrifice(Player opponent, FilterControlledPermanent opponentFilter, Game game, Ability source) { private boolean braidsSacrifice(Player opponent, FilterControlledPermanent opponentFilter, Game game, Ability source) {
TargetControlledPermanent target = new TargetControlledPermanent(1, 1, opponentFilter, true); TargetSacrifice target = new TargetSacrifice(opponentFilter);
if (!target.canChoose(opponent.getId(), source, game)) { if (!target.canChoose(opponent.getId(), source, game)) {
return false; return false;
} }
if (!opponent.chooseUse(Outcome.Sacrifice, "Sacrifice " + CardUtil.addArticle(opponentFilter.getMessage()) + '?', source, game)) { if (!opponent.chooseUse(Outcome.Sacrifice, "Sacrifice " + CardUtil.addArticle(opponentFilter.getMessage()) + '?', source, game)) {
return false; return false;
} }
opponent.chooseTarget(Outcome.Sacrifice, target, source, game); opponent.choose(Outcome.Sacrifice, target, source, game);
Permanent permanent = game.getPermanent(target.getFirstTarget()); Permanent permanent = game.getPermanent(target.getFirstTarget());
return permanent != null && permanent.sacrifice(source, game); return permanent != null && permanent.sacrifice(source, game);
} }

View file

@ -36,9 +36,7 @@ public final class BrawlBashOgre extends CardImpl {
this.addAbility(new AttacksTriggeredAbility( this.addAbility(new AttacksTriggeredAbility(
new DoIfCostPaid( new DoIfCostPaid(
new BoostSourceEffect(2, 2, Duration.EndOfTurn), new BoostSourceEffect(2, 2, Duration.EndOfTurn),
new SacrificeTargetCost(new TargetControlledPermanent( new SacrificeTargetCost(StaticFilters.FILTER_CONTROLLED_ANOTHER_CREATURE)
StaticFilters.FILTER_CONTROLLED_ANOTHER_CREATURE
))
), false ), false
)); ));
} }

View file

@ -15,6 +15,7 @@ import mage.abilities.effects.common.continuous.BoostTargetEffect;
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.common.FilterControlledArtifactPermanent; import mage.filter.common.FilterControlledArtifactPermanent;
import mage.game.permanent.token.ThopterToken; import mage.game.permanent.token.ThopterToken;
import mage.target.common.TargetControlledPermanent; import mage.target.common.TargetControlledPermanent;
@ -45,7 +46,7 @@ public final class BreyaEtheriumShaper extends CardImpl {
Zone.BATTLEFIELD, Zone.BATTLEFIELD,
new DamageTargetEffect(3), new DamageTargetEffect(3),
new GenericManaCost(2)); new GenericManaCost(2));
ability.addCost(new SacrificeTargetCost(new TargetControlledPermanent(2, 2, new FilterControlledArtifactPermanent("artifacts"), true))); ability.addCost(new SacrificeTargetCost(2, StaticFilters.FILTER_PERMANENT_ARTIFACTS));
ability.addTarget(new TargetPlayerOrPlaneswalker()); ability.addTarget(new TargetPlayerOrPlaneswalker());
// Target creature gets -4/-4 until end of turn. // Target creature gets -4/-4 until end of turn.

View file

@ -45,9 +45,7 @@ public final class BreyasApprentice extends CardImpl {
// {T}, Sacrifice an artifact: Choose one // {T}, Sacrifice an artifact: Choose one
// Exile the top card of your library. Until the end of your next turn, you may play that card. // Exile the top card of your library. Until the end of your next turn, you may play that card.
Ability ability = new SimpleActivatedAbility(new BreyasApprenticeEffect(), new TapSourceCost()); Ability ability = new SimpleActivatedAbility(new BreyasApprenticeEffect(), new TapSourceCost());
ability.addCost(new SacrificeTargetCost(new TargetControlledPermanent( ability.addCost(new SacrificeTargetCost(StaticFilters.FILTER_CONTROLLED_PERMANENT_ARTIFACT_AN));
StaticFilters.FILTER_CONTROLLED_PERMANENT_ARTIFACT_AN
)));
// Target creature gets +2/+0 until end of turn. // Target creature gets +2/+0 until end of turn.
Mode mode = new Mode(new BoostTargetEffect(2, 0, Duration.EndOfTurn)); Mode mode = new Mode(new BoostTargetEffect(2, 0, Duration.EndOfTurn));

View file

@ -41,7 +41,7 @@ public final class BrionStoutarm extends CardImpl {
Ability ability = new SimpleActivatedAbility(new DamageTargetEffect(SacrificeCostCreaturesPower.instance) Ability ability = new SimpleActivatedAbility(new DamageTargetEffect(SacrificeCostCreaturesPower.instance)
.setText("{this} deals damage equal to the sacrificed creature's power to target player or planeswalker"), new ManaCostsImpl<>("{R}")); .setText("{this} deals damage equal to the sacrificed creature's power to target player or planeswalker"), new ManaCostsImpl<>("{R}"));
ability.addCost(new TapSourceCost()); ability.addCost(new TapSourceCost());
ability.addCost(new SacrificeTargetCost(new TargetControlledPermanent(StaticFilters.FILTER_CONTROLLED_ANOTHER_CREATURE))); ability.addCost(new SacrificeTargetCost(StaticFilters.FILTER_CONTROLLED_ANOTHER_CREATURE));
ability.addTarget(new TargetPlayerOrPlaneswalker()); ability.addTarget(new TargetPlayerOrPlaneswalker());
this.addAbility(ability); this.addAbility(ability);
} }

View file

@ -41,8 +41,7 @@ public final class BroadsideBombardiers extends CardImpl {
Ability ability = new BoastAbility(new DamageTargetEffect( Ability ability = new BoastAbility(new DamageTargetEffect(
new IntPlusDynamicValue(2, SacrificeCostManaValue.PERMANENT)) new IntPlusDynamicValue(2, SacrificeCostManaValue.PERMANENT))
.setText("{this} deals damage equal to 2 plus the sacrificed permanent's mana value to any target."), .setText("{this} deals damage equal to 2 plus the sacrificed permanent's mana value to any target."),
new SacrificeTargetCost(new TargetControlledPermanent( new SacrificeTargetCost(StaticFilters.FILTER_CONTROLLED_ANOTHER_CREATURE_OR_ARTIFACT_SHORT_TEXT)
StaticFilters.FILTER_CONTROLLED_ANOTHER_CREATURE_OR_ARTIFACT_SHORT_TEXT))
); );
ability.addTarget(new TargetAnyTarget()); ability.addTarget(new TargetAnyTarget());
this.addAbility(ability); this.addAbility(ability);

View file

@ -69,9 +69,7 @@ class BrutalSuppressionAdditionalCostEffect extends CostModificationEffectImpl {
@Override @Override
public boolean apply(Game game, Ability source, Ability abilityToModify) { public boolean apply(Game game, Ability source, Ability abilityToModify) {
TargetControlledPermanent target = new TargetControlledPermanent(1, 1, filter, true); abilityToModify.addCost(new SacrificeTargetCost(filter));
target.setRequired(false);
abilityToModify.addCost(new SacrificeTargetCost(target));
return true; return true;
} }

View file

@ -43,7 +43,7 @@ public final class BubblingCauldron extends CardImpl {
// {1}, {T}, Sacrifice a creature named Festering Newt: Each opponent loses 4 life. You gain life equal to the life lost this way. // {1}, {T}, Sacrifice a creature named Festering Newt: Each opponent loses 4 life. You gain life equal to the life lost this way.
Ability ability2 = new SimpleActivatedAbility(Zone.BATTLEFIELD, new BubblingCauldronEffect(), new ManaCostsImpl<>("{1}")); Ability ability2 = new SimpleActivatedAbility(Zone.BATTLEFIELD, new BubblingCauldronEffect(), new ManaCostsImpl<>("{1}"));
ability2.addCost(new TapSourceCost()); ability2.addCost(new TapSourceCost());
ability2.addCost(new SacrificeTargetCost(new TargetControlledCreaturePermanent(1, 1, filter, true))); ability2.addCost(new SacrificeTargetCost(filter));
this.addAbility(ability2); this.addAbility(ability2);
} }

View file

@ -5,17 +5,14 @@ import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.costs.mana.GenericManaCost;
import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.continuous.GainControlTargetEffect; import mage.abilities.effects.common.PlayerToRightGainsControlOfSourceEffect;
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.Duration;
import mage.constants.Outcome; import mage.constants.Outcome;
import mage.game.Game; import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.game.permanent.token.TreasureToken; import mage.game.permanent.token.TreasureToken;
import mage.players.Player; import mage.players.Player;
import mage.target.targetpointer.FixedTarget;
import java.util.UUID; import java.util.UUID;
@ -30,6 +27,7 @@ public final class BucknardsEverfullPurse extends CardImpl {
// {1}, {T}: Roll a d4 and create a number of Treasure tokens equal to the result. The player to your right gains control of Bucknard's Everfull Purse. // {1}, {T}: Roll a d4 and create a number of Treasure tokens equal to the result. The player to your right gains control of Bucknard's Everfull Purse.
Ability ability = new SimpleActivatedAbility(new BucknardsEverfullPurseEffect(), new GenericManaCost(1)); Ability ability = new SimpleActivatedAbility(new BucknardsEverfullPurseEffect(), new GenericManaCost(1));
ability.addCost(new TapSourceCost()); ability.addCost(new TapSourceCost());
ability.addEffect(new PlayerToRightGainsControlOfSourceEffect());
this.addAbility(ability); this.addAbility(ability);
} }
@ -47,8 +45,7 @@ class BucknardsEverfullPurseEffect extends OneShotEffect {
BucknardsEverfullPurseEffect() { BucknardsEverfullPurseEffect() {
super(Outcome.Benefit); super(Outcome.Benefit);
staticText = "roll a d4 and create a number of Treasure tokens equal to the result. " + staticText = "roll a d4 and create a number of Treasure tokens equal to the result";
"The player to your right gains control of {this}";
} }
private BucknardsEverfullPurseEffect(final BucknardsEverfullPurseEffect effect) { private BucknardsEverfullPurseEffect(final BucknardsEverfullPurseEffect effect) {
@ -66,26 +63,9 @@ class BucknardsEverfullPurseEffect extends OneShotEffect {
if (player == null) { if (player == null) {
return false; return false;
} }
new TreasureToken().putOntoBattlefield( return new TreasureToken().putOntoBattlefield(
player.rollDice(outcome, source, game, 4), player.rollDice(outcome, source, game, 4),
game, source, source.getControllerId() game, source, source.getControllerId()
); );
Permanent permanent = source.getSourcePermanentIfItStillExists(game);
if (permanent == null) {
return true;
}
UUID playerToRightId = game
.getState()
.getPlayersInRange(source.getControllerId(), game)
.stream()
.reduce((u1, u2) -> u2)
.orElse(null);
if (playerToRightId == null) {
return false;
}
game.addEffect(new GainControlTargetEffect(
Duration.Custom, true, playerToRightId
).setTargetPointer(new FixedTarget(permanent, game)), source);
return true;
} }
} }

View file

@ -17,6 +17,7 @@ import mage.players.Player;
import mage.target.Target; import mage.target.Target;
import mage.target.common.TargetControlledPermanent; import mage.target.common.TargetControlledPermanent;
import mage.target.common.TargetOpponent; import mage.target.common.TargetOpponent;
import mage.target.common.TargetSacrifice;
/** /**
* *
@ -81,7 +82,7 @@ class BurningOfXinyeEffect extends OneShotEffect{
int realCount = game.getBattlefield().countAll(filter, player.getId(), game); int realCount = game.getBattlefield().countAll(filter, player.getId(), game);
int amount = Math.min(4, realCount); int amount = Math.min(4, realCount);
Target target = new TargetControlledPermanent(amount, amount, filter, true); Target target = new TargetSacrifice(amount, filter);
if (amount > 0 && target.canChoose(player.getId(), source, game)) { if (amount > 0 && target.canChoose(player.getId(), source, game)) {
while (!target.isChosen() && target.canChoose(player.getId(), source, game) && player.canRespond()) { while (!target.isChosen() && target.canChoose(player.getId(), source, game) && player.canRespond()) {
player.choose(Outcome.Sacrifice, target, source, game); player.choose(Outcome.Sacrifice, target, source, game);
@ -102,4 +103,4 @@ class BurningOfXinyeEffect extends OneShotEffect{
public BurningOfXinyeEffect copy() { public BurningOfXinyeEffect copy() {
return new BurningOfXinyeEffect(this); return new BurningOfXinyeEffect(this);
} }
} }

View file

@ -36,7 +36,7 @@ public final class BushmeatPoacher extends CardImpl {
// {1}, {T}, Sacrifice another creature: You gain life equal to that creature's toughness. Draw a card. // {1}, {T}, Sacrifice another creature: You gain life equal to that creature's toughness. Draw a card.
Ability ability = new SimpleActivatedAbility(new BushmeatPoacherEffect(), new GenericManaCost(1)); Ability ability = new SimpleActivatedAbility(new BushmeatPoacherEffect(), new GenericManaCost(1));
ability.addCost(new TapSourceCost()); ability.addCost(new TapSourceCost());
ability.addCost(new SacrificeTargetCost(new TargetControlledPermanent(StaticFilters.FILTER_CONTROLLED_ANOTHER_CREATURE))); ability.addCost(new SacrificeTargetCost(StaticFilters.FILTER_CONTROLLED_ANOTHER_CREATURE));
this.addAbility(ability); this.addAbility(ability);
} }
@ -92,4 +92,4 @@ class BushmeatPoacherEffect extends OneShotEffect {
} }
return player.drawCards(1, source, game) > 0; return player.drawCards(1, source, game) > 0;
} }
} }

View file

@ -43,8 +43,7 @@ public final class ButcherOfTheHorde extends CardImpl {
this.addAbility(FlyingAbility.getInstance()); this.addAbility(FlyingAbility.getInstance());
// Sacrifice another creature: Butcher of the Horde gains your choice of vigilance, lifelink, or haste until end of turn. // Sacrifice another creature: Butcher of the Horde gains your choice of vigilance, lifelink, or haste until end of turn.
this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD,
new ButcherOfTheHordeEffect(), new SacrificeTargetCost( new ButcherOfTheHordeEffect(), new SacrificeTargetCost(StaticFilters.FILTER_CONTROLLED_ANOTHER_CREATURE)));
new TargetControlledCreaturePermanent(1, 1, StaticFilters.FILTER_CONTROLLED_ANOTHER_CREATURE, false))));
} }
private ButcherOfTheHorde(final ButcherOfTheHorde card) { private ButcherOfTheHorde(final ButcherOfTheHorde card) {

View file

@ -43,7 +43,7 @@ public final class CabalArchon extends CardImpl {
Effect effect = new GainLifeEffect(2); Effect effect = new GainLifeEffect(2);
effect.setText("and you gain 2 life"); effect.setText("and you gain 2 life");
ability.addEffect(effect); ability.addEffect(effect);
ability.addCost(new SacrificeTargetCost(new TargetControlledPermanent(1, 1, filter, false))); ability.addCost(new SacrificeTargetCost(filter));
ability.addTarget(new TargetPlayer()); ability.addTarget(new TargetPlayer());
this.addAbility(ability); this.addAbility(ability);
} }

View file

@ -51,8 +51,7 @@ public final class CabalTherapist extends CardImpl {
ability.addEffect(new CabalTherapistDiscardEffect()); ability.addEffect(new CabalTherapistDiscardEffect());
ability.addTarget(new TargetPlayer()); ability.addTarget(new TargetPlayer());
this.addAbility(new BeginningOfPreCombatMainTriggeredAbility( this.addAbility(new BeginningOfPreCombatMainTriggeredAbility(
new DoWhenCostPaid(ability, new SacrificeTargetCost( new DoWhenCostPaid(ability, new SacrificeTargetCost(StaticFilters.FILTER_CONTROLLED_CREATURE_SHORT_TEXT
new TargetControlledPermanent(StaticFilters.FILTER_CONTROLLED_CREATURE_SHORT_TEXT)
), "Sacrifice a creature?"), TargetController.YOU, false ), "Sacrifice a creature?"), TargetController.YOU, false
)); ));
} }

View file

@ -35,9 +35,7 @@ public final class CabalTherapy extends CardImpl {
this.getSpellAbility().addEffect(new CabalTherapyEffect()); this.getSpellAbility().addEffect(new CabalTherapyEffect());
// Flashback-Sacrifice a creature. // Flashback-Sacrifice a creature.
this.addAbility(new FlashbackAbility(this, new SacrificeTargetCost( this.addAbility(new FlashbackAbility(this, new SacrificeTargetCost(StaticFilters.FILTER_CONTROLLED_CREATURE_SHORT_TEXT)));
new TargetControlledCreaturePermanent(StaticFilters.FILTER_CONTROLLED_CREATURE_SHORT_TEXT)
)));
} }
private CabalTherapy(final CabalTherapy card) { private CabalTherapy(final CabalTherapy card) {

View file

@ -55,7 +55,7 @@ public final class CaribouRange extends CardImpl {
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, effect)); this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, effect));
// Sacrifice a Caribou token: You gain 1 life. // Sacrifice a Caribou token: You gain 1 life.
this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new GainLifeEffect(1), this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new GainLifeEffect(1),
new SacrificeTargetCost(new TargetControlledCreaturePermanent(filter)))); new SacrificeTargetCost(filter)));
} }
private CaribouRange(final CaribouRange card) { private CaribouRange(final CaribouRange card) {

View file

@ -33,7 +33,7 @@ public final class CartelAristocrat extends CardImpl {
// Sacrifice another creature: Cartel Aristocrat gains protection from the color of your choice until end of turn. // Sacrifice another creature: Cartel Aristocrat gains protection from the color of your choice until end of turn.
this.addAbility(new SimpleActivatedAbility( this.addAbility(new SimpleActivatedAbility(
Zone.BATTLEFIELD, new GainProtectionFromColorSourceEffect(Duration.EndOfTurn), Zone.BATTLEFIELD, new GainProtectionFromColorSourceEffect(Duration.EndOfTurn),
new SacrificeTargetCost(new TargetControlledPermanent(StaticFilters.FILTER_CONTROLLED_ANOTHER_CREATURE)))); new SacrificeTargetCost(StaticFilters.FILTER_CONTROLLED_ANOTHER_CREATURE)));
} }
private CartelAristocrat(final CartelAristocrat card) { private CartelAristocrat(final CartelAristocrat card) {

View file

@ -39,7 +39,7 @@ public final class CauldronFamiliar extends CardImpl {
this.addAbility(new SimpleActivatedAbility( this.addAbility(new SimpleActivatedAbility(
Zone.GRAVEYARD, Zone.GRAVEYARD,
new ReturnSourceFromGraveyardToBattlefieldEffect(false, false), new ReturnSourceFromGraveyardToBattlefieldEffect(false, false),
new SacrificeTargetCost(new TargetControlledPermanent(StaticFilters.FILTER_CONTROLLED_FOOD)) new SacrificeTargetCost(StaticFilters.FILTER_CONTROLLED_FOOD)
)); ));
} }

View file

@ -54,7 +54,7 @@ public final class CavalierOfNight extends CardImpl {
); );
triggeredAbility.addTarget(new TargetOpponentsCreaturePermanent()); triggeredAbility.addTarget(new TargetOpponentsCreaturePermanent());
this.addAbility(new EntersBattlefieldTriggeredAbility(new DoWhenCostPaid( this.addAbility(new EntersBattlefieldTriggeredAbility(new DoWhenCostPaid(
triggeredAbility, new SacrificeTargetCost(new TargetControlledPermanent(StaticFilters.FILTER_CONTROLLED_ANOTHER_CREATURE)), triggeredAbility, new SacrificeTargetCost(StaticFilters.FILTER_CONTROLLED_ANOTHER_CREATURE),
"Sacrifice a creature?" "Sacrifice a creature?"
))); )));

View file

@ -36,7 +36,7 @@ public final class CephalidScout extends CardImpl {
this.addAbility(FlyingAbility.getInstance()); this.addAbility(FlyingAbility.getInstance());
// {2}{U}, Sacrifice a land: Draw a card. // {2}{U}, Sacrifice a land: Draw a card.
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DrawCardSourceControllerEffect(1), new ManaCostsImpl<>("{2}{U}")); Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DrawCardSourceControllerEffect(1), new ManaCostsImpl<>("{2}{U}"));
ability.addCost(new SacrificeTargetCost(new TargetControlledPermanent(StaticFilters.FILTER_CONTROLLED_LAND_SHORT_TEXT))); ability.addCost(new SacrificeTargetCost(StaticFilters.FILTER_CONTROLLED_LAND_SHORT_TEXT));
this.addAbility(ability); this.addAbility(ability);
} }

View file

@ -19,6 +19,7 @@ import mage.game.stack.Spell;
import mage.players.Player; import mage.players.Player;
import mage.target.common.TargetControlledPermanent; import mage.target.common.TargetControlledPermanent;
import mage.target.common.TargetCreaturePermanent; import mage.target.common.TargetCreaturePermanent;
import mage.target.common.TargetSacrifice;
import java.util.UUID; import java.util.UUID;
@ -74,8 +75,8 @@ class ChainOfSilenceEffect extends OneShotEffect {
ContinuousEffect effect = new PreventDamageByTargetEffect(Duration.EndOfTurn); ContinuousEffect effect = new PreventDamageByTargetEffect(Duration.EndOfTurn);
game.addEffect(effect, source); game.addEffect(effect, source);
Player player = game.getPlayer(permanent.getControllerId()); Player player = game.getPlayer(permanent.getControllerId());
TargetControlledPermanent target = new TargetControlledPermanent(0, 1, new FilterControlledLandPermanent("a land to sacrifice (to be able to copy " + sourceObject.getName() + ')'), true); TargetSacrifice target = new TargetSacrifice(0, 1, new FilterControlledLandPermanent("a land to sacrifice (to be able to copy " + sourceObject.getName() + ')'));
if (player != null && player.chooseTarget(Outcome.Sacrifice, target, source, game)) { if (player != null && player.choose(Outcome.Sacrifice, target, source, game)) {
Permanent land = game.getPermanent(target.getFirstTarget()); Permanent land = game.getPermanent(target.getFirstTarget());
if (land != null && land.sacrifice(source, game)) { if (land != null && land.sacrifice(source, game)) {
if (player.chooseUse(outcome, "Copy the spell?", source, game)) { if (player.chooseUse(outcome, "Copy the spell?", source, game)) {

View file

@ -17,6 +17,7 @@ import mage.game.stack.Spell;
import mage.players.Player; import mage.players.Player;
import mage.target.common.TargetControlledPermanent; import mage.target.common.TargetControlledPermanent;
import mage.target.common.TargetNonlandPermanent; import mage.target.common.TargetNonlandPermanent;
import mage.target.common.TargetSacrifice;
import java.util.UUID; import java.util.UUID;
@ -70,7 +71,7 @@ class ChainOfVaporEffect extends OneShotEffect {
if (permanent != null) { if (permanent != null) {
controller.moveCards(permanent, Zone.HAND, source, game); controller.moveCards(permanent, Zone.HAND, source, game);
Player player = game.getPlayer(permanent.getControllerId()); Player player = game.getPlayer(permanent.getControllerId());
TargetControlledPermanent target = new TargetControlledPermanent(0, 1, new FilterControlledLandPermanent("a land to sacrifice (to be able to copy " + sourceObject.getName() + ')'), true); TargetSacrifice target = new TargetSacrifice(0, 1, new FilterControlledLandPermanent("a land to sacrifice (to be able to copy " + sourceObject.getName() + ')'));
if (player != null && player.chooseTarget(Outcome.Sacrifice, target, source, game)) { if (player != null && player.chooseTarget(Outcome.Sacrifice, target, source, game)) {
Permanent land = game.getPermanent(target.getFirstTarget()); Permanent land = game.getPermanent(target.getFirstTarget());
if (land != null && land.sacrifice(source, game)) { if (land != null && land.sacrifice(source, game)) {

View file

@ -39,9 +39,7 @@ public final class ChainedBrute extends CardImpl {
Zone.BATTLEFIELD, new UntapSourceEffect(), Zone.BATTLEFIELD, new UntapSourceEffect(),
new GenericManaCost(1), MyTurnCondition.instance new GenericManaCost(1), MyTurnCondition.instance
); );
ability.addCost(new SacrificeTargetCost(new TargetControlledPermanent( ability.addCost(new SacrificeTargetCost(StaticFilters.FILTER_CONTROLLED_ANOTHER_CREATURE));
StaticFilters.FILTER_CONTROLLED_ANOTHER_CREATURE
)));
this.addAbility(ability); this.addAbility(ability);
} }

View file

@ -47,7 +47,7 @@ public final class Chitterspitter extends CardImpl {
this.addAbility(new BeginningOfUpkeepTriggeredAbility( this.addAbility(new BeginningOfUpkeepTriggeredAbility(
new DoIfCostPaid( new DoIfCostPaid(
new AddCountersSourceEffect(CounterType.ACORN.createInstance()), new AddCountersSourceEffect(CounterType.ACORN.createInstance()),
new SacrificeTargetCost(new TargetControlledPermanent(filter)) new SacrificeTargetCost(filter)
), ),
TargetController.YOU, TargetController.YOU,
false false

View file

@ -8,6 +8,7 @@ import mage.constants.CardType;
import mage.constants.Outcome; import mage.constants.Outcome;
import mage.constants.SubType; import mage.constants.SubType;
import mage.filter.FilterPermanent; import mage.filter.FilterPermanent;
import mage.filter.StaticFilters;
import mage.filter.common.FilterControlledPermanent; import mage.filter.common.FilterControlledPermanent;
import mage.game.Game; import mage.game.Game;
import mage.game.permanent.Permanent; import mage.game.permanent.Permanent;
@ -15,6 +16,7 @@ import mage.players.Player;
import mage.target.Target; import mage.target.Target;
import mage.target.common.TargetControlledPermanent; import mage.target.common.TargetControlledPermanent;
import mage.target.common.TargetOpponent; import mage.target.common.TargetOpponent;
import mage.target.common.TargetSacrifice;
import java.util.UUID; import java.util.UUID;
@ -98,8 +100,8 @@ class ChoiceOfDamnationsEffect extends OneShotEffect {
// (2005-06-01) // (2005-06-01)
if (numberPermanents > amount) { if (numberPermanents > amount) {
int numberToSacrifice = numberPermanents - amount; int numberToSacrifice = numberPermanents - amount;
Target target = new TargetControlledPermanent(numberToSacrifice, numberToSacrifice, new FilterControlledPermanent("permanent you control to sacrifice"), false); Target target = new TargetSacrifice(numberToSacrifice, numberToSacrifice == 1 ? StaticFilters.FILTER_PERMANENT : StaticFilters.FILTER_PERMANENTS);
targetPlayer.chooseTarget(Outcome.Sacrifice, target, source, game); targetPlayer.choose(Outcome.Sacrifice, target, source, game);
for (UUID uuid : target.getTargets()) { for (UUID uuid : target.getTargets()) {
Permanent permanent = game.getPermanent(uuid); Permanent permanent = game.getPermanent(uuid);
if (permanent != null) { if (permanent != null) {

View file

@ -45,7 +45,7 @@ public final class Clickslither extends CardImpl {
Effect effect = new BoostSourceEffect(2,2,Duration.EndOfTurn); Effect effect = new BoostSourceEffect(2,2,Duration.EndOfTurn);
effect.setText("{this} gets +2/+2"); effect.setText("{this} gets +2/+2");
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, effect, Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, effect,
new SacrificeTargetCost(new TargetControlledCreaturePermanent(1,1,filter,true))); new SacrificeTargetCost(filter));
effect = new GainAbilitySourceEffect(TrampleAbility.getInstance(), Duration.EndOfTurn); effect = new GainAbilitySourceEffect(TrampleAbility.getInstance(), Duration.EndOfTurn);
effect.setText("and gains trample until end of turn"); effect.setText("and gains trample until end of turn");
ability.addEffect(effect); ability.addEffect(effect);

View file

@ -34,7 +34,7 @@ public final class CoastalHornclaw extends CardImpl {
this.toughness = new MageInt(3); this.toughness = new MageInt(3);
// Sacrifice a land: Coastal Hornclaw gains flying until end of turn. // Sacrifice a land: Coastal Hornclaw gains flying until end of turn.
this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new GainAbilitySourceEffect(FlyingAbility.getInstance(), Duration.EndOfTurn), new SacrificeTargetCost(new TargetControlledPermanent(filter)))); this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new GainAbilitySourceEffect(FlyingAbility.getInstance(), Duration.EndOfTurn), new SacrificeTargetCost(filter)));
} }
private CoastalHornclaw(final CoastalHornclaw card) { private CoastalHornclaw(final CoastalHornclaw card) {

View file

@ -52,9 +52,7 @@ public final class CoffinPuppets extends CardImpl {
this.addAbility(new ActivateIfConditionActivatedAbility( this.addAbility(new ActivateIfConditionActivatedAbility(
Zone.GRAVEYARD, Zone.GRAVEYARD,
new ReturnSourceFromGraveyardToBattlefieldEffect(), new ReturnSourceFromGraveyardToBattlefieldEffect(),
new SacrificeTargetCost( new SacrificeTargetCost(2, filter2), condition
new TargetControlledPermanent(2, 2, filter2, true)
), condition
)); ));
} }

View file

@ -45,7 +45,7 @@ public final class CombineChrysalis extends CardImpl {
new CreateTokenEffect(new BeastToken2()), new ManaCostsImpl<>("{2}{G}{U}") new CreateTokenEffect(new BeastToken2()), new ManaCostsImpl<>("{2}{G}{U}")
); );
ability.addCost(new TapSourceCost()); ability.addCost(new TapSourceCost());
ability.addCost(new SacrificeTargetCost(new TargetControlledPermanent(filter))); ability.addCost(new SacrificeTargetCost(filter));
this.addAbility(ability); this.addAbility(ability);
} }

View file

@ -51,7 +51,7 @@ public final class ConsecratedByBlood extends CardImpl {
effect.setText("and has flying"); effect.setText("and has flying");
ability.addEffect(effect); ability.addEffect(effect);
effect = new GainAbilityAttachedEffect(new SimpleActivatedAbility(Zone.BATTLEFIELD, new RegenerateSourceEffect(), effect = new GainAbilityAttachedEffect(new SimpleActivatedAbility(Zone.BATTLEFIELD, new RegenerateSourceEffect(),
new SacrificeTargetCost(new TargetControlledCreaturePermanent(2, 2, filter, true))), AttachmentType.AURA); new SacrificeTargetCost(2, filter)), AttachmentType.AURA);
effect.setText("and \"Sacrifice two other creatures: Regenerate this creature.\""); effect.setText("and \"Sacrifice two other creatures: Regenerate this creature.\"");
ability.addEffect(effect); ability.addEffect(effect);
this.addAbility(ability); this.addAbility(ability);

Some files were not shown because too many files have changed in this diff Show more