From 97af948932ca2c57d5f459ad4d60d4acdae710f0 Mon Sep 17 00:00:00 2001 From: Evan Kranzler Date: Mon, 29 Mar 2021 21:35:27 -0400 Subject: [PATCH] simplified and condensed various effects which discard variable amounts of cards --- .../src/mage/cards/c/CavalierOfFlame.java | 39 +------- .../src/mage/cards/d/DarettiScrapSavant.java | 97 +++---------------- Mage.Sets/src/mage/cards/j/JayaBallard.java | 49 ++-------- Mage.Sets/src/mage/cards/k/KineticAugur.java | 47 ++------- Mage.Sets/src/mage/cards/l/LastRites.java | 12 +-- Mage.Sets/src/mage/cards/l/LeaveChance.java | 42 +------- .../mage/cards/n/NehebDreadhordeChampion.java | 22 +---- .../src/mage/cards/r/RitesOfRefusal.java | 38 ++------ Mage.Sets/src/mage/cards/r/RitesOfSpring.java | 28 ++++-- Mage.Sets/src/mage/cards/s/SacredRites.java | 8 +- .../java/org/mage/test/player/TestPlayer.java | 5 + .../java/org/mage/test/stub/PlayerStub.java | 5 + .../discard/DiscardAndDrawThatManyEffect.java | 44 +++++++++ Mage/src/main/java/mage/players/Player.java | 2 + .../main/java/mage/players/PlayerImpl.java | 89 ++++++++--------- 15 files changed, 163 insertions(+), 364 deletions(-) create mode 100644 Mage/src/main/java/mage/abilities/effects/common/discard/DiscardAndDrawThatManyEffect.java diff --git a/Mage.Sets/src/mage/cards/c/CavalierOfFlame.java b/Mage.Sets/src/mage/cards/c/CavalierOfFlame.java index cd31d66bf1..995f91e5d6 100644 --- a/Mage.Sets/src/mage/cards/c/CavalierOfFlame.java +++ b/Mage.Sets/src/mage/cards/c/CavalierOfFlame.java @@ -8,22 +8,18 @@ import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.dynamicvalue.common.CardsInControllerGraveyardCount; -import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.DamageAllEffect; import mage.abilities.effects.common.DamagePlayersEffect; import mage.abilities.effects.common.continuous.BoostControlledEffect; import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; +import mage.abilities.effects.common.discard.DiscardAndDrawThatManyEffect; import mage.abilities.keyword.HasteAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.cards.CardsImpl; import mage.constants.*; import mage.filter.FilterPermanent; import mage.filter.StaticFilters; import mage.filter.common.FilterPlaneswalkerPermanent; -import mage.game.Game; -import mage.players.Player; -import mage.target.common.TargetCardInHand; import java.util.UUID; @@ -58,7 +54,7 @@ public final class CavalierOfFlame extends CardImpl { this.addAbility(ability); // When Cavalier of Flame enters the battlefield, discard any number of cards, then draw that many cards. - this.addAbility(new EntersBattlefieldTriggeredAbility(new CavalierOfFlameEffect())); + this.addAbility(new EntersBattlefieldTriggeredAbility(new DiscardAndDrawThatManyEffect(Integer.MAX_VALUE))); // When Cavalier of Flame dies, it deals X damage to each opponent and each planeswalker they control, where X is the number of land cards in your graveyard. ability = new DiesSourceTriggeredAbility(new DamagePlayersEffect( @@ -79,34 +75,3 @@ public final class CavalierOfFlame extends CardImpl { return new CavalierOfFlame(this); } } - -class CavalierOfFlameEffect extends OneShotEffect { - - CavalierOfFlameEffect() { - super(Outcome.Benefit); - staticText = "discard any number of cards, then draw that many cards."; - } - - private CavalierOfFlameEffect(final CavalierOfFlameEffect effect) { - super(effect); - } - - @Override - public CavalierOfFlameEffect copy() { - return new CavalierOfFlameEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); - if (player == null) { - return false; - } - TargetCardInHand target = new TargetCardInHand(0, player.getHand().size(), StaticFilters.FILTER_CARD); - if (player.choose(Outcome.Discard, player.getHand(), target, game)) { - int counter = player.discard(new CardsImpl(target.getTargets()), false, source, game).size(); - player.drawCards(counter, source, game); - } - return true; - } -} diff --git a/Mage.Sets/src/mage/cards/d/DarettiScrapSavant.java b/Mage.Sets/src/mage/cards/d/DarettiScrapSavant.java index b20d29bb87..0a3f91aa63 100644 --- a/Mage.Sets/src/mage/cards/d/DarettiScrapSavant.java +++ b/Mage.Sets/src/mage/cards/d/DarettiScrapSavant.java @@ -4,17 +4,13 @@ import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; import mage.abilities.common.CanBeYourCommanderAbility; import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; -import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbility; -import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.GetEmblemEffect; -import mage.abilities.effects.common.ReturnFromGraveyardToBattlefieldTargetEffect; +import mage.abilities.effects.common.discard.DiscardAndDrawThatManyEffect; import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.cards.CardsImpl; import mage.constants.*; -import mage.filter.FilterCard; import mage.filter.common.FilterArtifactCard; import mage.filter.common.FilterControlledArtifactPermanent; import mage.game.Game; @@ -24,8 +20,6 @@ import mage.players.Player; import mage.target.Target; import mage.target.common.TargetCardInYourGraveyard; import mage.target.common.TargetControlledPermanent; -import mage.target.common.TargetDiscard; -import mage.target.targetpointer.FixedTarget; import java.util.UUID; @@ -42,7 +36,7 @@ public final class DarettiScrapSavant extends CardImpl { this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(3)); // +2: Discard up to two cards, then draw that many cards. - this.addAbility(new LoyaltyAbility(new DarettiDiscardDrawEffect(), 2)); + this.addAbility(new LoyaltyAbility(new DiscardAndDrawThatManyEffect(2), 2)); // -2: Sacrifice an artifact. If you do, return target artifact card from your graveyard to the battlefield. LoyaltyAbility loyaltyAbility = new LoyaltyAbility(new DarettiSacrificeEffect(), -2); @@ -66,44 +60,14 @@ public final class DarettiScrapSavant extends CardImpl { } } -class DarettiDiscardDrawEffect extends OneShotEffect { - - public DarettiDiscardDrawEffect() { - super(Outcome.Detriment); - this.staticText = "Discard up to two cards, then draw that many cards"; - } - - public DarettiDiscardDrawEffect(final DarettiDiscardDrawEffect effect) { - super(effect); - } - - @Override - public DarettiDiscardDrawEffect copy() { - return new DarettiDiscardDrawEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player controller = game.getPlayer(source.getControllerId()); - if (controller != null) { - TargetDiscard target = new TargetDiscard(0, 2, new FilterCard(), controller.getId()); - target.choose(outcome, controller.getId(), source.getSourceId(), game); - int count = controller.discard(new CardsImpl(target.getTargets()), false, source, game).size(); - controller.drawCards(count, source, game); - return true; - } - return false; - } -} - class DarettiSacrificeEffect extends OneShotEffect { - public DarettiSacrificeEffect() { + DarettiSacrificeEffect() { super(Outcome.PutCardInPlay); this.staticText = "Sacrifice an artifact. If you do, return target artifact card from your graveyard to the battlefield"; } - public DarettiSacrificeEffect(final DarettiSacrificeEffect effect) { + private DarettiSacrificeEffect(final DarettiSacrificeEffect effect) { super(effect); } @@ -115,50 +79,19 @@ class DarettiSacrificeEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - if (controller != null) { - Target target = new TargetControlledPermanent(1, 1, new FilterControlledArtifactPermanent(), true); - if (target.canChoose(source.getSourceId(), controller.getId(), game) - && controller.chooseTarget(outcome, target, source, game)) { - Permanent artifact = game.getPermanent(target.getFirstTarget()); - if (artifact != null && artifact.sacrifice(source, game)) { - Card card = game.getCard(getTargetPointer().getFirst(game, source)); - if (card != null) { - return controller.moveCards(card, Zone.BATTLEFIELD, source, game); - } - } - } + if (controller == null) { + return false; + } + Target target = new TargetControlledPermanent(1, 1, new FilterControlledArtifactPermanent(), true); + if (!target.canChoose(source.getSourceId(), controller.getId(), game) + || !controller.chooseTarget(outcome, target, source, game)) { + return true; + } + Permanent artifact = game.getPermanent(target.getFirstTarget()); + if (artifact == null || !artifact.sacrifice(source, game)) { return true; } - return false; - } -} - -class DarettiScrapSavantEffect extends OneShotEffect { - - DarettiScrapSavantEffect() { - super(Outcome.PutCardInPlay); - this.staticText = "return that card to the battlefield at the beginning of the next end step"; - } - - DarettiScrapSavantEffect(final DarettiScrapSavantEffect effect) { - super(effect); - } - - @Override - public DarettiScrapSavantEffect copy() { - return new DarettiScrapSavantEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { Card card = game.getCard(getTargetPointer().getFirst(game, source)); - if (card != null && game.getState().getZone(card.getId()) == Zone.GRAVEYARD) { - Effect effect = new ReturnFromGraveyardToBattlefieldTargetEffect(); - effect.setTargetPointer(new FixedTarget(card, game)); - effect.setText("return that card to the battlefield at the beginning of the next end step"); - game.addDelayedTriggeredAbility(new AtTheBeginOfNextEndStepDelayedTriggeredAbility(Zone.COMMAND, effect, TargetController.ANY), source); - return true; - } - return false; + return card == null || controller.moveCards(card, Zone.BATTLEFIELD, source, game); } } diff --git a/Mage.Sets/src/mage/cards/j/JayaBallard.java b/Mage.Sets/src/mage/cards/j/JayaBallard.java index 6f11b38555..5a1e88a84a 100644 --- a/Mage.Sets/src/mage/cards/j/JayaBallard.java +++ b/Mage.Sets/src/mage/cards/j/JayaBallard.java @@ -1,25 +1,18 @@ package mage.cards.j; import mage.Mana; -import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; -import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.GetEmblemEffect; +import mage.abilities.effects.common.discard.DiscardAndDrawThatManyEffect; import mage.abilities.effects.mana.AddConditionalManaEffect; import mage.abilities.mana.builder.common.InstantOrSorcerySpellManaBuilder; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.cards.CardsImpl; import mage.constants.CardType; -import mage.constants.Outcome; import mage.constants.SubType; import mage.constants.SuperType; -import mage.filter.FilterCard; -import mage.game.Game; import mage.game.command.emblems.JayaBallardEmblem; -import mage.players.Player; -import mage.target.common.TargetDiscard; import mage.watchers.common.CastFromGraveyardWatcher; import java.util.UUID; @@ -37,13 +30,17 @@ public final class JayaBallard extends CardImpl { this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(5)); // +1: Add {R}{R}{R}. Spend this mana only to cast instant or sorcery spells. - this.addAbility(new LoyaltyAbility(new AddConditionalManaEffect(Mana.RedMana(3), new InstantOrSorcerySpellManaBuilder()), 1)); + this.addAbility(new LoyaltyAbility(new AddConditionalManaEffect( + Mana.RedMana(3), new InstantOrSorcerySpellManaBuilder() + ), 1)); // +1: Discard up to three cards, then draw that many cards. - this.addAbility(new LoyaltyAbility(new JayaBallardDiscardDrawEffect(), 1)); + this.addAbility(new LoyaltyAbility(new DiscardAndDrawThatManyEffect(3), 1)); // −8: You get an emblem with "You may cast instant and sorcery cards from your graveyard. If a card cast this way would be put into your graveyard, exile it instead." - this.addAbility(new LoyaltyAbility(new GetEmblemEffect(new JayaBallardEmblem()), -8), new CastFromGraveyardWatcher()); + this.addAbility(new LoyaltyAbility( + new GetEmblemEffect(new JayaBallardEmblem()), -8 + ), new CastFromGraveyardWatcher()); } private JayaBallard(final JayaBallard card) { @@ -55,33 +52,3 @@ public final class JayaBallard extends CardImpl { return new JayaBallard(this); } } - -class JayaBallardDiscardDrawEffect extends OneShotEffect { - - public JayaBallardDiscardDrawEffect() { - super(Outcome.Detriment); - this.staticText = "Discard up to three cards, then draw that many cards"; - } - - public JayaBallardDiscardDrawEffect(final JayaBallardDiscardDrawEffect effect) { - super(effect); - } - - @Override - public JayaBallardDiscardDrawEffect copy() { - return new JayaBallardDiscardDrawEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player controller = game.getPlayer(source.getControllerId()); - if (controller == null) { - return false; - } - TargetDiscard target = new TargetDiscard(0, 3, new FilterCard(), controller.getId()); - target.choose(outcome, controller.getId(), source.getSourceId(), game); - int count = controller.discard(new CardsImpl(target.getTargets()), false, source, game).size(); - controller.drawCards(count, source, game); - return true; - } -} diff --git a/Mage.Sets/src/mage/cards/k/KineticAugur.java b/Mage.Sets/src/mage/cards/k/KineticAugur.java index 009a4ce500..ded12e23c6 100644 --- a/Mage.Sets/src/mage/cards/k/KineticAugur.java +++ b/Mage.Sets/src/mage/cards/k/KineticAugur.java @@ -1,24 +1,21 @@ package mage.cards.k; import mage.MageInt; -import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.dynamicvalue.common.CardsInControllerGraveyardCount; -import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.continuous.SetPowerSourceEffect; +import mage.abilities.effects.common.discard.DiscardAndDrawThatManyEffect; import mage.abilities.keyword.TrampleAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.cards.CardsImpl; -import mage.constants.*; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.constants.Zone; import mage.filter.FilterCard; -import mage.filter.StaticFilters; import mage.filter.common.FilterInstantOrSorceryCard; -import mage.game.Game; -import mage.players.Player; -import mage.target.common.TargetDiscard; import java.util.UUID; @@ -45,7 +42,7 @@ public final class KineticAugur extends CardImpl { this.addAbility(new SimpleStaticAbility(Zone.ALL, new SetPowerSourceEffect(xValue, Duration.EndOfGame))); // When Kinetic Augur enters the battlefield, discard up to two cards, then draw that many cards. - this.addAbility(new EntersBattlefieldTriggeredAbility(new KineticAugurEffect())); + this.addAbility(new EntersBattlefieldTriggeredAbility(new DiscardAndDrawThatManyEffect(2))); } private KineticAugur(final KineticAugur card) { @@ -57,35 +54,3 @@ public final class KineticAugur extends CardImpl { return new KineticAugur(this); } } - -class KineticAugurEffect extends OneShotEffect { - - KineticAugurEffect() { - super(Outcome.Benefit); - staticText = "discard up to two cards, then draw that many cards"; - } - - private KineticAugurEffect(final KineticAugurEffect effect) { - super(effect); - } - - @Override - public KineticAugurEffect copy() { - return new KineticAugurEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); - if (player == null || player.getHand().isEmpty()) { - return false; - } - TargetDiscard target = new TargetDiscard(0, 2, StaticFilters.FILTER_CARD, player.getId()); - player.choose(Outcome.AIDontUseIt, player.getHand(), target, game); - int discarded = player.discard(new CardsImpl(target.getTargets()), false, source, game).size(); - if (discarded > 0) { - player.drawCards(discarded, source, game); - } - return true; - } -} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/l/LastRites.java b/Mage.Sets/src/mage/cards/l/LastRites.java index 245ccc571a..0d06036cdb 100644 --- a/Mage.Sets/src/mage/cards/l/LastRites.java +++ b/Mage.Sets/src/mage/cards/l/LastRites.java @@ -7,19 +7,14 @@ import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.discard.DiscardCardYouChooseTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.cards.Cards; -import mage.cards.CardsImpl; import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.TargetController; import mage.filter.FilterCard; -import mage.filter.StaticFilters; import mage.filter.predicate.Predicates; import mage.game.Game; import mage.players.Player; -import mage.target.TargetCard; import mage.target.TargetPlayer; -import mage.target.common.TargetDiscard; import mage.target.targetpointer.FixedTarget; import java.util.UUID; @@ -74,12 +69,7 @@ class LastRitesEffect extends OneShotEffect { if (controller == null || targetPlayer == null) { return false; } - Cards cardsInHand = controller.getHand().copy(); - TargetCard target = new TargetDiscard( - 0, Integer.MAX_VALUE, StaticFilters.FILTER_CARD_CARDS, controller.getId() - ); - controller.chooseTarget(Outcome.AIDontUseIt, cardsInHand, target, source, game); - int discardCount = controller.discard(new CardsImpl(target.getTargets()), false, source, game).size(); + int discardCount = controller.discard(0, Integer.MAX_VALUE, false, source, game).size(); FilterCard filter = new FilterCard((discardCount > 1 ? "" : "a") + " nonland card" + (discardCount > 1 ? "s" : "")); filter.add(Predicates.not(CardType.LAND.getPredicate())); diff --git a/Mage.Sets/src/mage/cards/l/LeaveChance.java b/Mage.Sets/src/mage/cards/l/LeaveChance.java index a756848d9a..53c989c86e 100644 --- a/Mage.Sets/src/mage/cards/l/LeaveChance.java +++ b/Mage.Sets/src/mage/cards/l/LeaveChance.java @@ -1,23 +1,15 @@ package mage.cards.l; -import mage.abilities.Ability; -import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.ReturnToHandTargetEffect; +import mage.abilities.effects.common.discard.DiscardAndDrawThatManyEffect; import mage.abilities.keyword.AftermathAbility; import mage.cards.CardSetInfo; -import mage.cards.CardsImpl; import mage.cards.SplitCard; import mage.constants.CardType; -import mage.constants.Outcome; import mage.constants.SpellAbilityType; import mage.constants.TargetController; import mage.filter.FilterPermanent; -import mage.filter.StaticFilters; -import mage.game.Game; -import mage.players.Player; -import mage.target.TargetCard; import mage.target.TargetPermanent; -import mage.target.common.TargetDiscard; import java.util.UUID; @@ -45,7 +37,7 @@ public final class LeaveChance extends SplitCard { getRightHalfCard().addAbility(new AftermathAbility().setRuleAtTheTop(true)); // Discard any number of cards, then draw that many cards. - getRightHalfCard().getSpellAbility().addEffect(new ChanceEffect()); + getRightHalfCard().getSpellAbility().addEffect(new DiscardAndDrawThatManyEffect(Integer.MAX_VALUE)); } private LeaveChance(final LeaveChance card) { @@ -57,33 +49,3 @@ public final class LeaveChance extends SplitCard { return new LeaveChance(this); } } - -class ChanceEffect extends OneShotEffect { - - ChanceEffect() { - super(Outcome.DrawCard); - this.staticText = "Discard any number of cards, then draw that many cards"; - } - - private ChanceEffect(final ChanceEffect effect) { - super(effect); - } - - @Override - public ChanceEffect copy() { - return new ChanceEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player controller = game.getPlayer(source.getControllerId()); - if (controller == null) { - return false; - } - TargetCard target = new TargetDiscard(0, controller.getHand().size(), StaticFilters.FILTER_CARD_CARDS, controller.getId()); - controller.chooseTarget(outcome, controller.getHand(), target, source, game); - int amount = controller.discard(new CardsImpl(target.getTargets()), false, source, game).size(); - controller.drawCards(amount, source, game); - return true; - } -} diff --git a/Mage.Sets/src/mage/cards/n/NehebDreadhordeChampion.java b/Mage.Sets/src/mage/cards/n/NehebDreadhordeChampion.java index 69a785b7d0..ed232f0b82 100644 --- a/Mage.Sets/src/mage/cards/n/NehebDreadhordeChampion.java +++ b/Mage.Sets/src/mage/cards/n/NehebDreadhordeChampion.java @@ -8,19 +8,11 @@ import mage.abilities.effects.OneShotEffect; import mage.abilities.keyword.TrampleAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.cards.CardsImpl; -import mage.constants.CardType; -import mage.constants.Outcome; -import mage.constants.SubType; -import mage.constants.SuperType; -import mage.filter.StaticFilters; +import mage.constants.*; import mage.game.Game; import mage.players.Player; -import mage.target.TargetCard; -import mage.target.common.TargetCardInHand; import java.util.UUID; -import java.util.stream.IntStream; /** * @author TheElk801 @@ -79,18 +71,12 @@ class NehebDreadhordeChampionEffect extends OneShotEffect { if (player == null) { return false; } - TargetCard target = new TargetCardInHand(0, Integer.MAX_VALUE, StaticFilters.FILTER_CARD); - if (!player.choose(outcome, target, source.getSourceId(), game)) { - return false; - } - int counter = player.discard(new CardsImpl(target.getTargets()), false, source, game).size(); - Mana mana = new Mana(); + int counter = player.discard(0, Integer.MAX_VALUE, false, source, game).size(); if (counter < 1) { return true; } - IntStream.range(0, counter).forEach(x -> mana.increaseRed()); player.drawCards(counter, source, game); - player.getManaPool().addMana(mana, game, source, true); + player.getManaPool().addMana(new Mana(ManaType.RED, counter), game, source, true); return true; } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/cards/r/RitesOfRefusal.java b/Mage.Sets/src/mage/cards/r/RitesOfRefusal.java index 653da6bce6..401d311ecd 100644 --- a/Mage.Sets/src/mage/cards/r/RitesOfRefusal.java +++ b/Mage.Sets/src/mage/cards/r/RitesOfRefusal.java @@ -1,18 +1,16 @@ package mage.cards.r; import mage.abilities.Ability; -import mage.abilities.costs.Cost; +import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.CounterUnlessPaysEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.cards.Cards; import mage.constants.CardType; import mage.constants.Outcome; import mage.game.Game; -import mage.game.stack.Spell; import mage.players.Player; import mage.target.TargetSpell; -import mage.util.ManaUtil; import java.util.UUID; @@ -28,7 +26,6 @@ public final class RitesOfRefusal extends CardImpl { // controller pays {3} for each card discarded this way. this.getSpellAbility().addEffect(new RitesOfRefusalEffect()); this.getSpellAbility().addTarget(new TargetSpell()); - } private RitesOfRefusal(final RitesOfRefusal card) { @@ -49,7 +46,7 @@ class RitesOfRefusalEffect extends OneShotEffect { + "spell unless its controller pays {3} for each card discarded this way"; } - RitesOfRefusalEffect(final RitesOfRefusalEffect effect) { + private RitesOfRefusalEffect(final RitesOfRefusalEffect effect) { super(effect); } @@ -61,31 +58,10 @@ class RitesOfRefusalEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - Spell targetSpell = game.getStack().getSpell(source.getFirstTarget()); - if (targetSpell != null) { - Player controllerOfTargetedSpell = game.getPlayer(targetSpell.getControllerId()); - if (controller != null && controllerOfTargetedSpell != null) { - int numToDiscard = controller.getAmount(0, - controller.getHand().size(), "How many cards do you want to discard?", game); - Cards discardedCards = controller.discard(numToDiscard, false, false, source, game); - int actualNumberDiscarded = discardedCards.size(); - if (actualNumberDiscarded > 0) { - Cost cost = ManaUtil.createManaCost(actualNumberDiscarded * 3, false); - if (controllerOfTargetedSpell.chooseUse(Outcome.Benefit, - "Do you want to pay " - + cost.getText() - + " to prevent " - + targetSpell.getName() - + " from gettting countered?", source, game) - && cost.pay(source, game, source, - controllerOfTargetedSpell.getId(), false)) { - return true; - } - game.getStack().counter(targetSpell.getId(), source, game); - return true; - } - } + if (controller == null) { + return false; } - return false; + int count = controller.discard(0, Integer.MAX_VALUE, false, source, game).size(); + return new CounterUnlessPaysEffect(new GenericManaCost(3 * count)).apply(game, source); } } diff --git a/Mage.Sets/src/mage/cards/r/RitesOfSpring.java b/Mage.Sets/src/mage/cards/r/RitesOfSpring.java index 2f04978334..ccacca53d6 100644 --- a/Mage.Sets/src/mage/cards/r/RitesOfSpring.java +++ b/Mage.Sets/src/mage/cards/r/RitesOfSpring.java @@ -1,20 +1,21 @@ package mage.cards.r; +import mage.MageItem; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; -import mage.abilities.effects.common.search.SearchLibraryPutInHandEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.Cards; import mage.cards.CardsImpl; import mage.constants.CardType; import mage.constants.Outcome; +import mage.constants.Zone; import mage.filter.StaticFilters; import mage.game.Game; import mage.players.Player; -import mage.target.TargetCard; import mage.target.common.TargetCardInLibrary; -import mage.target.common.TargetDiscard; +import java.util.Objects; import java.util.UUID; /** @@ -62,12 +63,23 @@ class RitesOfSpringEffect extends OneShotEffect { if (controller == null) { return false; } - TargetCard target = new TargetDiscard(0, Integer.MAX_VALUE, StaticFilters.FILTER_CARD, controller.getId()); - controller.choose(Outcome.AIDontUseIt, controller.getHand(), target, game); - int numDiscarded = controller.discard(new CardsImpl(target.getTargets()), false, source, game).size(); - new SearchLibraryPutInHandEffect(new TargetCardInLibrary( + int numDiscarded = controller.discard(0, Integer.MAX_VALUE, false, source, game).size(); + TargetCardInLibrary target = new TargetCardInLibrary( 0, numDiscarded, StaticFilters.FILTER_CARD_BASIC_LAND - ), true, true).apply(game, source); + ); + controller.searchLibrary(target, source, game); + Cards cards = new CardsImpl(); + controller + .getLibrary() + .getCards(game) + .stream() + .filter(Objects::nonNull) + .map(MageItem::getId) + .filter(target.getTargets()::contains) + .forEach(cards::add); + controller.revealCards(source, cards, game); + controller.moveCards(cards, Zone.HAND, source, game); + controller.shuffleLibrary(source, game); return true; } } diff --git a/Mage.Sets/src/mage/cards/s/SacredRites.java b/Mage.Sets/src/mage/cards/s/SacredRites.java index 4c302b9f2c..aded1d3446 100644 --- a/Mage.Sets/src/mage/cards/s/SacredRites.java +++ b/Mage.Sets/src/mage/cards/s/SacredRites.java @@ -5,15 +5,11 @@ import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.continuous.BoostControlledEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.cards.CardsImpl; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.Outcome; -import mage.filter.StaticFilters; import mage.game.Game; import mage.players.Player; -import mage.target.Target; -import mage.target.common.TargetDiscard; import java.util.UUID; @@ -61,9 +57,7 @@ class SacredRitesEffect extends OneShotEffect { if (controller == null) { return false; } - Target target = new TargetDiscard(0, Integer.MAX_VALUE, StaticFilters.FILTER_CARD, controller.getId()); - target.choose(outcome, controller.getId(), source.getSourceId(), game); - int numDiscarded = controller.discard(new CardsImpl(target.getTargets()), false, source, game).size(); + int numDiscarded = controller.discard(0, Integer.MAX_VALUE, false, source, game).size(); if (numDiscarded > 0) { game.addEffect(new BoostControlledEffect(0, numDiscarded, Duration.EndOfTurn), source); } diff --git a/Mage.Tests/src/test/java/org/mage/test/player/TestPlayer.java b/Mage.Tests/src/test/java/org/mage/test/player/TestPlayer.java index cf72df155a..c04aad5af6 100644 --- a/Mage.Tests/src/test/java/org/mage/test/player/TestPlayer.java +++ b/Mage.Tests/src/test/java/org/mage/test/player/TestPlayer.java @@ -2841,6 +2841,11 @@ public class TestPlayer implements Player { return computerPlayer.discard(amount, random, payForCost, source, game); } + @Override + public Cards discard(int minAmount, int maxAmount, boolean payForCost, Ability source, Game game) { + return computerPlayer.discard(minAmount, maxAmount, payForCost, source, game); + } + @Override public Cards discard(Cards cards, boolean payForCost, Ability source, Game game) { return computerPlayer.discard(cards, payForCost, source, game); diff --git a/Mage.Tests/src/test/java/org/mage/test/stub/PlayerStub.java b/Mage.Tests/src/test/java/org/mage/test/stub/PlayerStub.java index 2bb39a3efc..4ddfb7f824 100644 --- a/Mage.Tests/src/test/java/org/mage/test/stub/PlayerStub.java +++ b/Mage.Tests/src/test/java/org/mage/test/stub/PlayerStub.java @@ -664,6 +664,11 @@ public class PlayerStub implements Player { return null; } + @Override + public Cards discard(int minAmount, int maxAmount, boolean payForCost, Ability source, Game game) { + return null; + } + @Override public void discardToMax(Game game) { diff --git a/Mage/src/main/java/mage/abilities/effects/common/discard/DiscardAndDrawThatManyEffect.java b/Mage/src/main/java/mage/abilities/effects/common/discard/DiscardAndDrawThatManyEffect.java new file mode 100644 index 0000000000..477978f249 --- /dev/null +++ b/Mage/src/main/java/mage/abilities/effects/common/discard/DiscardAndDrawThatManyEffect.java @@ -0,0 +1,44 @@ +package mage.abilities.effects.common.discard; + +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.constants.Outcome; +import mage.game.Game; +import mage.players.Player; +import mage.util.CardUtil; + +/** + * @author TheElk801 + */ +public class DiscardAndDrawThatManyEffect extends OneShotEffect { + + private final int amount; + + public DiscardAndDrawThatManyEffect(int amount) { + super(Outcome.DrawCard); + this.amount = amount; + staticText = "discard " + + (amount == Integer.MAX_VALUE ? "any number of" : "up to" + CardUtil.numberToText(amount)) + + " cards, then draw that many cards"; + } + + private DiscardAndDrawThatManyEffect(final DiscardAndDrawThatManyEffect effect) { + super(effect); + this.amount = effect.amount; + } + + @Override + public DiscardAndDrawThatManyEffect copy() { + return new DiscardAndDrawThatManyEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; + } + player.drawCards(player.discard(0, amount, false, source, game).size(), source, game); + return true; + } +} diff --git a/Mage/src/main/java/mage/players/Player.java b/Mage/src/main/java/mage/players/Player.java index 1354544cbc..2192d2bf0a 100644 --- a/Mage/src/main/java/mage/players/Player.java +++ b/Mage/src/main/java/mage/players/Player.java @@ -497,6 +497,8 @@ public interface Player extends MageItem, Copyable { Cards discard(int amount, boolean random, boolean payForCost, Ability source, Game game); + Cards discard(int minAmount, int maxAmount, boolean payForCost, Ability source, Game game); + Cards discard(Cards cards, boolean payForCost, Ability source, Game game); void discardToMax(Game game); diff --git a/Mage/src/main/java/mage/players/PlayerImpl.java b/Mage/src/main/java/mage/players/PlayerImpl.java index cfbeca1759..59ca6ed70d 100644 --- a/Mage/src/main/java/mage/players/PlayerImpl.java +++ b/Mage/src/main/java/mage/players/PlayerImpl.java @@ -720,20 +720,20 @@ public abstract class PlayerImpl implements Player, Serializable { @Override public Card discardOne(boolean random, boolean payForCost, Ability source, Game game) { - Cards cards = discard(1, random, payForCost, source, game); - if (cards.isEmpty()) { - return null; - } - return cards.getRandom(game); + return discard(1, random, payForCost, source, game).getRandom(game); } @Override public Cards discard(int amount, boolean random, boolean payForCost, Ability source, Game game) { - Cards discardedCards = doDiscardWithoutFinalEvent(amount, random, payForCost, source, game); - if (!discardedCards.isEmpty()) { - game.fireEvent(GameEvent.getEvent(GameEvent.EventType.DISCARDED_CARDS, null, source, playerId, discardedCards.size())); + if (random) { + return discard(getRandomToDiscard(amount, source, game), payForCost, source, game); } - return discardedCards; + return discard(amount, amount, payForCost, source, game); + } + + @Override + public Cards discard(int minAmount, int maxAmount, boolean payForCost, Ability source, Game game) { + return discard(getToDiscard(minAmount, maxAmount, source, game), payForCost, source, game); } @Override @@ -753,50 +753,43 @@ public abstract class PlayerImpl implements Player, Serializable { return discardedCards; } - private Cards doDiscardWithoutFinalEvent(int amount, boolean random, boolean payForCost, Ability source, Game game) { - Cards discardedCards = new CardsImpl(); - if (amount <= 0) { - return discardedCards; - } - - // all without dialogs - if (this.getHand().size() == 1 || this.getHand().size() == amount) { - List cardsToDiscard = new ArrayList<>(this.getHand()); - for (UUID id : cardsToDiscard) { - if (doDiscard(this.getHand().get(id, game), source, game, payForCost, false)) { - discardedCards.add(id); - } - } - return discardedCards; - } - - if (random) { - for (int i = 0; i < amount; i++) { - Card card = this.getHand().getRandom(game); - if (doDiscard(card, source, game, payForCost, false)) { - discardedCards.add(card); - } - } - } else { - int possibleAmount = Math.min(getHand().size(), amount); - TargetDiscard target = new TargetDiscard(possibleAmount, possibleAmount, - new FilterCard(CardUtil.numberToText(possibleAmount, "a") - + " card" + (possibleAmount > 1 ? "s" : "")), playerId); - choose(Outcome.Discard, target, source == null ? null : source.getSourceId(), game); - for (UUID cardId : target.getTargets()) { - if (doDiscard(this.getHand().get(cardId, game), source, game, payForCost, false)) { - discardedCards.add(cardId); - } - } - } - return discardedCards; - } - @Override public boolean discard(Card card, boolean payForCost, Ability source, Game game) { return doDiscard(card, source, game, payForCost, true); } + private Cards getToDiscard(int minAmount, int maxAmount, Ability source, Game game) { + Cards toDiscard = new CardsImpl(); + if (minAmount > maxAmount) { + return getToDiscard(maxAmount, minAmount, source, game); + } + if (maxAmount < 1) { + return toDiscard; + } + if (getHand().size() <= minAmount) { + toDiscard.addAll(getHand()); + return toDiscard; + } + TargetDiscard target = new TargetDiscard(minAmount, maxAmount, StaticFilters.FILTER_CARD, getId()); + choose(Outcome.Discard, target, source != null ? source.getSourceId() : null, game); + toDiscard.addAll(target.getTargets()); + return toDiscard; + } + + private Cards getRandomToDiscard(int amount, Ability source, Game game) { + Cards toDiscard = new CardsImpl(); + Cards hand = getHand().copy(); + for (int i = 0; i < amount; i++) { + if(hand.isEmpty()){ + break; + } + Card card = hand.getRandom(game); + hand.remove(card); + toDiscard.add(card); + } + return toDiscard; + } + private boolean doDiscard(Card card, Ability source, Game game, boolean payForCost, boolean fireFinalEvent) { //20100716 - 701.7 /* 701.7. Discard #