diff --git a/Mage.Sets/src/mage/cards/c/CaseOfTheBurningMasks.java b/Mage.Sets/src/mage/cards/c/CaseOfTheBurningMasks.java index 68067b1c2cc..7c6fad69706 100644 --- a/Mage.Sets/src/mage/cards/c/CaseOfTheBurningMasks.java +++ b/Mage.Sets/src/mage/cards/c/CaseOfTheBurningMasks.java @@ -8,19 +8,18 @@ import mage.abilities.condition.Condition; import mage.abilities.condition.common.SolvedSourceCondition; import mage.abilities.costs.common.SacrificeSourceCost; import mage.abilities.decorator.ConditionalActivatedAbility; -import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.effects.common.ExileTopXMayPlayUntilEffect; import mage.abilities.hint.common.CaseSolvedHint; -import mage.cards.*; -import mage.constants.*; -import mage.filter.StaticFilters; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.constants.WatcherScope; import mage.game.Game; import mage.game.events.GameEvent; -import mage.players.Player; -import mage.target.TargetCard; -import mage.target.common.TargetCardInExile; import mage.target.common.TargetOpponentsCreaturePermanent; -import mage.util.CardUtil; import mage.watchers.Watcher; import java.util.*; @@ -46,12 +45,14 @@ public final class CaseOfTheBurningMasks extends CardImpl { initialAbility.addTarget(new TargetOpponentsCreaturePermanent()); // To solve -- Three or more sources you controlled dealt damage this turn. // Solved -- Sacrifice this Case: Exile the top three cards of your library. Choose one of them. You may play that card this turn. - Ability solvedAbility = new ConditionalActivatedAbility(new CaseOfTheBurningMasksEffect(), - new SacrificeSourceCost().setText("sacrifice this Case"), SolvedSourceCondition.SOLVED); + Ability solvedAbility = new ConditionalActivatedAbility( + new ExileTopXMayPlayUntilEffect(3, true, Duration.EndOfTurn), + new SacrificeSourceCost().setText("sacrifice this Case"), SolvedSourceCondition.SOLVED + ); - this.addAbility(new CaseAbility(initialAbility, CaseOfTheBurningMasksCondition.instance, solvedAbility) - .addHint(new CaseOfTheBurningMasksHint()), - new CaseOfTheBurningMasksWatcher()); + this.addAbility(new CaseAbility( + initialAbility, CaseOfTheBurningMasksCondition.instance, solvedAbility + ).addHint(new CaseOfTheBurningMasksHint()), new CaseOfTheBurningMasksWatcher()); } private CaseOfTheBurningMasks(final CaseOfTheBurningMasks card) { @@ -134,49 +135,3 @@ class CaseOfTheBurningMasksWatcher extends Watcher { return damagingObjects.getOrDefault(controllerId, Collections.emptySet()).size(); } } - -class CaseOfTheBurningMasksEffect extends OneShotEffect { - - CaseOfTheBurningMasksEffect() { - super(Outcome.Benefit); - staticText = "Exile the top three cards of your library. Choose one of them. You may play that card this turn."; - } - - private CaseOfTheBurningMasksEffect(final CaseOfTheBurningMasksEffect effect) { - super(effect); - } - - @Override - public CaseOfTheBurningMasksEffect copy() { - return new CaseOfTheBurningMasksEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); - if (player == null) { - return false; - } - Cards cards = new CardsImpl(player.getLibrary().getTopCards(game, 3)); - player.moveCards(cards, Zone.EXILED, source, game); - cards.retainZone(Zone.EXILED, game); - - Card card; - switch (cards.size()) { - case 0: - return false; - case 1: - card = cards.getRandom(game); - break; - default: - TargetCard target = new TargetCardInExile(StaticFilters.FILTER_CARD); - target.withNotTarget(true); - player.choose(outcome, cards, target, source, game); - card = game.getCard(target.getFirstTarget()); - } - if (card != null) { - CardUtil.makeCardPlayable(game, source, card, false, Duration.EndOfTurn, false); - } - return true; - } -} diff --git a/Mage.Sets/src/mage/cards/d/DragonhawkFatesTempest.java b/Mage.Sets/src/mage/cards/d/DragonhawkFatesTempest.java index 23c594dd194..6cfe84e869b 100644 --- a/Mage.Sets/src/mage/cards/d/DragonhawkFatesTempest.java +++ b/Mage.Sets/src/mage/cards/d/DragonhawkFatesTempest.java @@ -64,7 +64,7 @@ public final class DragonhawkFatesTempest extends CardImpl { class DragonhawkExileEffect extends ExileTopXMayPlayUntilEffect { DragonhawkExileEffect(DynamicValue amount, Duration duration) { - super(amount, duration); + super(amount, false, duration); this.withTextOptions("those cards", true); staticText += ". At the beginning of your next end step, " + DragonhawkFatesTempestDamageEffect.STATIC_TEXT; } diff --git a/Mage.Sets/src/mage/cards/f/FireglassMentor.java b/Mage.Sets/src/mage/cards/f/FireglassMentor.java index 50451c81b45..a12f5a5bc9e 100644 --- a/Mage.Sets/src/mage/cards/f/FireglassMentor.java +++ b/Mage.Sets/src/mage/cards/f/FireglassMentor.java @@ -1,18 +1,14 @@ package mage.cards.f; import mage.MageInt; -import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfSecondMainTriggeredAbility; import mage.abilities.condition.common.OpponentsLostLifeCondition; -import mage.abilities.effects.OneShotEffect; -import mage.cards.*; -import mage.constants.*; -import mage.filter.StaticFilters; -import mage.game.Game; -import mage.players.Player; -import mage.target.TargetCard; -import mage.target.common.TargetCardInExile; -import mage.util.CardUtil; +import mage.abilities.effects.common.ExileTopXMayPlayUntilEffect; +import mage.abilities.triggers.BeginningOfSecondMainTriggeredAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; import java.util.UUID; @@ -30,8 +26,9 @@ public final class FireglassMentor extends CardImpl { this.toughness = new MageInt(1); // At the beginning of your second main phase, if an opponent lost life this turn, exile the top two cards of your library. Choose one of them. Until end of turn, you may play that card. - this.addAbility(new BeginningOfSecondMainTriggeredAbility(new FireglassMentorEffect(), false) - .withInterveningIf(OpponentsLostLifeCondition.instance)); + this.addAbility(new BeginningOfSecondMainTriggeredAbility( + new ExileTopXMayPlayUntilEffect(2, true, Duration.EndOfTurn), false + ).withInterveningIf(OpponentsLostLifeCondition.instance)); } private FireglassMentor(final FireglassMentor card) { @@ -43,50 +40,3 @@ public final class FireglassMentor extends CardImpl { return new FireglassMentor(this); } } - -//Based on CaseOfTheBurningMasksEffect -class FireglassMentorEffect extends OneShotEffect { - - FireglassMentorEffect() { - super(Outcome.Benefit); - staticText = "exile the top two cards of your library. Choose one of them. Until end of turn, you may play that card"; - } - - private FireglassMentorEffect(final FireglassMentorEffect effect) { - super(effect); - } - - @Override - public FireglassMentorEffect copy() { - return new FireglassMentorEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); - if (player == null) { - return false; - } - Cards cards = new CardsImpl(player.getLibrary().getTopCards(game, 2)); - player.moveCards(cards, Zone.EXILED, source, game); - cards.retainZone(Zone.EXILED, game); - - Card card; - switch (cards.size()) { - case 0: - return false; - case 1: - card = cards.getRandom(game); - break; - default: - TargetCard target = new TargetCardInExile(StaticFilters.FILTER_CARD); - target.withNotTarget(true); - player.choose(outcome, cards, target, source, game); - card = game.getCard(target.getFirstTarget()); - } - if (card != null) { - CardUtil.makeCardPlayable(game, source, card, false, Duration.EndOfTurn, false); - } - return true; - } -} diff --git a/Mage.Sets/src/mage/cards/h/HugsGrislyGuardian.java b/Mage.Sets/src/mage/cards/h/HugsGrislyGuardian.java index ec184354541..7aad68ca2e3 100644 --- a/Mage.Sets/src/mage/cards/h/HugsGrislyGuardian.java +++ b/Mage.Sets/src/mage/cards/h/HugsGrislyGuardian.java @@ -35,7 +35,7 @@ public final class HugsGrislyGuardian extends CardImpl { // When Hugs, Grisly Guardian enters, exile the top X cards of your library. Until the end of your next turn, you may play those cards. this.addAbility(new EntersBattlefieldTriggeredAbility(new ExileTopXMayPlayUntilEffect( - GetXValue.instance, Duration.UntilEndOfYourNextTurn + GetXValue.instance, false, Duration.UntilEndOfYourNextTurn ))); // You may play an additional land on each of your turns. diff --git a/Mage.Sets/src/mage/cards/j/JayaFieryNegotiator.java b/Mage.Sets/src/mage/cards/j/JayaFieryNegotiator.java index 26fa932b8e9..ded7c8c9f7c 100644 --- a/Mage.Sets/src/mage/cards/j/JayaFieryNegotiator.java +++ b/Mage.Sets/src/mage/cards/j/JayaFieryNegotiator.java @@ -5,23 +5,22 @@ import mage.abilities.DelayedTriggeredAbility; import mage.abilities.LoyaltyAbility; import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.dynamicvalue.common.AttackingCreatureCount; -import mage.abilities.effects.OneShotEffect; -import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect; -import mage.abilities.effects.common.CreateTokenEffect; -import mage.abilities.effects.common.DamageTargetEffect; -import mage.abilities.effects.common.GetEmblemEffect; -import mage.cards.*; -import mage.constants.*; +import mage.abilities.effects.common.*; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.constants.SuperType; import mage.game.Controllable; import mage.game.Game; import mage.game.command.emblems.JayaFieryNegotiatorEmblem; import mage.game.events.GameEvent; import mage.game.permanent.token.MonkRedToken; -import mage.players.Player; import mage.target.common.TargetOpponentsCreaturePermanent; -import mage.util.CardUtil; -import java.util.*; +import java.util.Objects; +import java.util.UUID; /** * @author TheElk801 @@ -39,7 +38,7 @@ public final class JayaFieryNegotiator extends CardImpl { this.addAbility(new LoyaltyAbility(new CreateTokenEffect(new MonkRedToken()), 1)); // −1: Exile the top two cards of your library. Choose one of them. You may play that card this turn. - this.addAbility(new LoyaltyAbility(new JayaFieryNegotiatorExileEffect(), -1)); + this.addAbility(new LoyaltyAbility(new ExileTopXMayPlayUntilEffect(2, true, Duration.EndOfTurn), -1)); // −2: Choose target creature an opponent controls. Whenever you attack this turn, Jaya, Fiery Negotiator deals damage equal to the number of attacking creatures to that creature. Ability ability = new LoyaltyAbility(new CreateDelayedTriggeredAbilityEffect( @@ -63,57 +62,6 @@ public final class JayaFieryNegotiator extends CardImpl { } } -class JayaFieryNegotiatorExileEffect extends OneShotEffect { - - JayaFieryNegotiatorExileEffect() { - super(Outcome.Benefit); - staticText = "exile the top two cards of your library. Choose one of them. You may play that card this turn"; - } - - private JayaFieryNegotiatorExileEffect(final JayaFieryNegotiatorExileEffect effect) { - super(effect); - } - - @Override - public JayaFieryNegotiatorExileEffect copy() { - return new JayaFieryNegotiatorExileEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); - if (player == null) { - return false; - } - Cards cards = new CardsImpl(player.getLibrary().getTopCards(game, 2)); - Card card; - - if (cards.size() == 0) { - return false; - } else if (cards.size() == 1) { - card = cards.getRandom(game); - player.moveCardsToExile(card, source, game, true, CardUtil.getExileZoneId(game, source), "Jaya, Fiery Negotiator"); - } else { - Iterator iterator = cards.getCards(game).iterator(); - Card card1 = iterator.next(); - Card card2 = iterator.next(); - card = player.chooseUse( - outcome, "Choose a card to play this turn", null, - card1.getName(), card2.getName(), source, game - ) ? card1 : card2; - - Set exileCards = new HashSet<>(2); - exileCards.add(card1); - exileCards.add(card2); - player.moveCardsToExile(exileCards, source, game, true, CardUtil.getExileZoneId(game, source), "Jaya, Fiery Negotiator"); - } - if (card != null) { - CardUtil.makeCardPlayable(game, source, card, false, Duration.EndOfTurn, false); - } - return true; - } -} - class JayaFieryNegotiatorTriggeredAbility extends DelayedTriggeredAbility { private static final DynamicValue xValue = new AttackingCreatureCount(); diff --git a/Mage.Sets/src/mage/cards/l/LootTheKeyToEverything.java b/Mage.Sets/src/mage/cards/l/LootTheKeyToEverything.java index 208066315f7..b0c6a86df7f 100644 --- a/Mage.Sets/src/mage/cards/l/LootTheKeyToEverything.java +++ b/Mage.Sets/src/mage/cards/l/LootTheKeyToEverything.java @@ -2,12 +2,12 @@ package mage.cards.l; import mage.MageInt; import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.effects.Effect; import mage.abilities.effects.common.ExileTopXMayPlayUntilEffect; import mage.abilities.keyword.WardAbility; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.*; @@ -38,7 +38,7 @@ public final class LootTheKeyToEverything extends CardImpl { // At the beginning of your upkeep, exile the top X cards of your library, where X is the number of card types among other nonland permanents you control. You may play those cards this turn. this.addAbility(new BeginningOfUpkeepTriggeredAbility( - new ExileTopXMayPlayUntilEffect(LootTheKeyToEverythingValue.instance, Duration.EndOfTurn) + new ExileTopXMayPlayUntilEffect(LootTheKeyToEverythingValue.instance, false, Duration.EndOfTurn) .setText("exile the top X cards of your library, where X is the number of card types " + "among other nonland permanents you control. You may play those cards this turn") )); diff --git a/Mage.Sets/src/mage/cards/m/MagmaticChanneler.java b/Mage.Sets/src/mage/cards/m/MagmaticChanneler.java index 005118cd2af..afec31ce020 100644 --- a/Mage.Sets/src/mage/cards/m/MagmaticChanneler.java +++ b/Mage.Sets/src/mage/cards/m/MagmaticChanneler.java @@ -1,7 +1,6 @@ package mage.cards.m; import mage.MageInt; -import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.common.SimpleStaticAbility; @@ -12,18 +11,16 @@ import mage.abilities.costs.common.TapSourceCost; import mage.abilities.decorator.ConditionalContinuousEffect; import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.dynamicvalue.common.CardsInControllerGraveyardCount; -import mage.abilities.effects.AsThoughEffectImpl; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.ExileTopXMayPlayUntilEffect; import mage.abilities.effects.common.continuous.BoostSourceEffect; import mage.abilities.hint.Hint; import mage.abilities.hint.ValueHint; -import mage.cards.*; -import mage.constants.*; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; import mage.filter.StaticFilters; -import mage.game.Game; -import mage.players.Player; -import mage.target.TargetCard; -import mage.target.common.TargetCardInExile; import java.util.UUID; @@ -54,7 +51,7 @@ public final class MagmaticChanneler extends CardImpl { )).addHint(hint)); // {T}, Discard a card: Exile the top two cards of your library, then choose one of them. You may play that card this turn. - Ability ability = new SimpleActivatedAbility(new MagmaticChannelerExileEffect(), new TapSourceCost()); + Ability ability = new SimpleActivatedAbility(new ExileTopXMayPlayUntilEffect(2, true, Duration.EndOfTurn), new TapSourceCost()); ability.addCost(new DiscardCardCost()); this.addAbility(ability); } @@ -68,83 +65,3 @@ public final class MagmaticChanneler extends CardImpl { return new MagmaticChanneler(this); } } - -class MagmaticChannelerExileEffect extends OneShotEffect { - - MagmaticChannelerExileEffect() { - super(Outcome.Benefit); - staticText = "Exile the top two cards of your library, then choose one of them. You may play that card this turn."; - } - - private MagmaticChannelerExileEffect(final MagmaticChannelerExileEffect effect) { - super(effect); - } - - @Override - public MagmaticChannelerExileEffect copy() { - return new MagmaticChannelerExileEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); - if (player == null) { - return false; - } - Cards cards = new CardsImpl(player.getLibrary().getTopCards(game, 2)); - player.moveCards(cards, Zone.EXILED, source, game); - cards.removeIf(uuid -> game.getState().getZone(uuid) != Zone.EXILED); - Card card = null; - if (cards.isEmpty()) { - return false; - } else if (cards.size() == 1) { - card = cards.getRandom(game); - } else { - TargetCard targetCard = new TargetCardInExile(StaticFilters.FILTER_CARD); - player.choose(outcome, cards, targetCard, source, game); - card = game.getCard(targetCard.getFirstTarget()); - } - if (card == null) { - return false; - } - game.addEffect(new MagmaticChannelerCastFromExileEffect(new MageObjectReference(card, game)), source); - return true; - } -} - -class MagmaticChannelerCastFromExileEffect extends AsThoughEffectImpl { - - private final MageObjectReference mor; - - MagmaticChannelerCastFromExileEffect(MageObjectReference mor) { - super(AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, Duration.EndOfTurn, Outcome.Benefit); - this.mor = mor; - } - - private MagmaticChannelerCastFromExileEffect(final MagmaticChannelerCastFromExileEffect effect) { - super(effect); - this.mor = effect.mor; - } - - @Override - public boolean apply(Game game, Ability source) { - return true; - } - - @Override - public MagmaticChannelerCastFromExileEffect copy() { - return new MagmaticChannelerCastFromExileEffect(this); - } - - @Override - public boolean applies(UUID objectId, Ability source, UUID affectedControllerId, Game game) { - Card theCard = game.getCard(objectId); - if (theCard == null) { - return false; - } - objectId = theCard.getMainCard().getId(); // for split cards/MDFC/Adventure cards - - return source.isControlledBy(affectedControllerId) - && mor.refersTo(objectId, game); - } -} diff --git a/Mage.Sets/src/mage/cards/m/MishrasResearchDesk.java b/Mage.Sets/src/mage/cards/m/MishrasResearchDesk.java index f8375d8ec3e..96fe4afcf6b 100644 --- a/Mage.Sets/src/mage/cards/m/MishrasResearchDesk.java +++ b/Mage.Sets/src/mage/cards/m/MishrasResearchDesk.java @@ -6,19 +6,12 @@ import mage.abilities.costs.common.SacrificeSourceCost; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.ExileTopXMayPlayUntilEffect; import mage.abilities.keyword.UnearthAbility; -import mage.cards.*; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; -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.TargetCardInExile; -import mage.util.CardUtil; import java.util.UUID; @@ -31,7 +24,9 @@ public final class MishrasResearchDesk extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{1}"); // {1}, {T}, Sacrifice Mishra's Research Desk: Exile the top two cards of your library. Choose one of them. Until the end of your next turn, you may play that card. - Ability ability = new SimpleActivatedAbility(new MishrasResearchDeskEffect(), new GenericManaCost(1)); + Ability ability = new SimpleActivatedAbility(new ExileTopXMayPlayUntilEffect( + 2, true, Duration.UntilEndOfYourNextTurn + ), new GenericManaCost(1)); ability.addCost(new TapSourceCost()); ability.addCost(new SacrificeSourceCost()); this.addAbility(ability); @@ -49,50 +44,3 @@ public final class MishrasResearchDesk extends CardImpl { return new MishrasResearchDesk(this); } } - -class MishrasResearchDeskEffect extends OneShotEffect { - - MishrasResearchDeskEffect() { - super(Outcome.Benefit); - staticText = "exile the top two cards of your library. Choose one of them. " + - "Until the end of your next turn, you may play that card"; - } - - private MishrasResearchDeskEffect(final MishrasResearchDeskEffect effect) { - super(effect); - } - - @Override - public MishrasResearchDeskEffect copy() { - return new MishrasResearchDeskEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); - if (player == null) { - return false; - } - Cards cards = new CardsImpl(player.getLibrary().getTopCards(game, 2)); - player.moveCards(cards, Zone.EXILED, source, game); - cards.retainZone(Zone.EXILED, game); - Card card; - switch (cards.size()) { - case 0: - return false; - case 1: - card = cards.getRandom(game); - break; - default: - TargetCard target = new TargetCardInExile(StaticFilters.FILTER_CARD); - target.withNotTarget(true); - player.choose(outcome, cards, target, source, game); - card = game.getCard(target.getFirstTarget()); - } - if (card == null) { - return false; - } - CardUtil.makeCardPlayable(game, source, card, false, Duration.UntilEndOfYourNextTurn, false); - return true; - } -} diff --git a/Mage.Sets/src/mage/cards/p/PartyThrasher.java b/Mage.Sets/src/mage/cards/p/PartyThrasher.java index db789dbb755..db0d5088dff 100644 --- a/Mage.Sets/src/mage/cards/p/PartyThrasher.java +++ b/Mage.Sets/src/mage/cards/p/PartyThrasher.java @@ -1,28 +1,23 @@ package mage.cards.p; import mage.MageInt; -import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfFirstMainTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.costs.common.DiscardCardCost; -import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.DoIfCostPaid; -import mage.abilities.effects.common.asthought.PlayFromNotOwnHandZoneTargetEffect; +import mage.abilities.effects.common.ExileTopXMayPlayUntilEffect; import mage.abilities.effects.common.continuous.GainAbilityControlledSpellsEffect; import mage.abilities.keyword.ConvokeAbility; -import mage.cards.*; -import mage.constants.*; -import mage.filter.StaticFilters; +import mage.abilities.triggers.BeginningOfFirstMainTriggeredAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.constants.Zone; import mage.filter.common.FilterNonlandCard; import mage.filter.predicate.Predicates; import mage.filter.predicate.card.CastFromZonePredicate; import mage.filter.predicate.mageobject.AbilityPredicate; -import mage.game.ExileZone; -import mage.game.Game; -import mage.players.Player; -import mage.target.TargetCard; -import mage.target.targetpointer.FixedTarget; -import mage.util.CardUtil; import java.util.UUID; @@ -53,12 +48,9 @@ public final class PartyThrasher extends CardImpl { )); // At the beginning of your precombat main phase, you may discard a card. If you do, exile the top two cards of your library, then choose one of them. You may play that card this turn. - this.addAbility(new BeginningOfFirstMainTriggeredAbility( - new DoIfCostPaid( - new PartyThrasherEffect(), - new DiscardCardCost() - ) - )); + this.addAbility(new BeginningOfFirstMainTriggeredAbility(new DoIfCostPaid( + new ExileTopXMayPlayUntilEffect(2, true, Duration.EndOfTurn), new DiscardCardCost() + ))); } private PartyThrasher(final PartyThrasher card) { @@ -70,56 +62,3 @@ public final class PartyThrasher extends CardImpl { return new PartyThrasher(this); } } - -class PartyThrasherEffect extends OneShotEffect { - - PartyThrasherEffect() { - super(Outcome.DrawCard); - staticText = "exile the top two cards of your library, then choose one of them. You may play that card this turn"; - } - - private PartyThrasherEffect(final PartyThrasherEffect effect) { - super(effect); - } - - @Override - public PartyThrasherEffect copy() { - return new PartyThrasherEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player controller = game.getPlayer(source.getControllerId()); - if (controller == null) { - return false; - } - Cards cards = new CardsImpl(controller.getLibrary().getTopCards(game, 2)); - if (cards.isEmpty()) { - return false; - } - controller.moveCardsToExile(cards.getCards(game), source, game, true, null, ""); - game.processAction(); - cards.retainZone(Zone.EXILED, game); - if (cards.isEmpty()) { - return true; - } - TargetCard target = new TargetCard(Zone.EXILED, StaticFilters.FILTER_CARD_A); - target.withNotTarget(true); - if (!controller.choose(Outcome.DrawCard, cards, target, source, game)) { - return true; - } - Card card = game.getCard(target.getFirstTarget()); - if (card == null) { - return true; - } - String exileName = CardUtil.getSourceIdName(game, source); - UUID exileId = CardUtil.getExileZoneId(game, source); - ExileZone exileZone = game.getExile().createZone(exileId, exileName); - exileZone.setCleanupOnEndTurn(true); - game.getExile().moveToAnotherZone(card, game, exileZone); - game.addEffect(new PlayFromNotOwnHandZoneTargetEffect(Zone.EXILED, Duration.EndOfTurn) - .setTargetPointer(new FixedTarget(card, game)), source); - return true; - } - -} diff --git a/Mage.Sets/src/mage/cards/r/RotisserieElemental.java b/Mage.Sets/src/mage/cards/r/RotisserieElemental.java index a7a4403ca1e..dc49f708789 100644 --- a/Mage.Sets/src/mage/cards/r/RotisserieElemental.java +++ b/Mage.Sets/src/mage/cards/r/RotisserieElemental.java @@ -42,7 +42,7 @@ public final class RotisserieElemental extends CardImpl { false ).withRuleTextReplacement(false); ability.addEffect(new DoIfCostPaid( - new ExileTopXMayPlayUntilEffect(xValue, Duration.EndOfTurn) + new ExileTopXMayPlayUntilEffect(xValue, false, Duration.EndOfTurn) .setText("exile the top X cards of your library, where X is the number of skewer counters " + "on {this}. You may play those cards this turn"), new SacrificeSourceCost().setText("sacrifice it") diff --git a/Mage.Sets/src/mage/cards/s/StrongboxRaider.java b/Mage.Sets/src/mage/cards/s/StrongboxRaider.java new file mode 100644 index 00000000000..9dafb06a0cf --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/StrongboxRaider.java @@ -0,0 +1,45 @@ +package mage.cards.s; + +import mage.MageInt; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.condition.common.RaidCondition; +import mage.abilities.effects.common.ExileTopXMayPlayUntilEffect; +import mage.abilities.hint.common.RaidHint; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.AbilityWord; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.watchers.common.PlayerAttackedWatcher; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class StrongboxRaider extends CardImpl { + + public StrongboxRaider(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{R}{R}"); + + this.subtype.add(SubType.ORC); + this.subtype.add(SubType.PIRATE); + this.power = new MageInt(5); + this.toughness = new MageInt(2); + + // Raid -- When this creature enters, if you attacked this turn, exile the top two cards of your library. Choose one of them. Until the end of your next turn, you may play that card. + this.addAbility(new EntersBattlefieldTriggeredAbility( + new ExileTopXMayPlayUntilEffect(2, true, Duration.UntilEndOfYourNextTurn) + ).withInterveningIf(RaidCondition.instance).setAbilityWord(AbilityWord.RAID).addHint(RaidHint.instance), new PlayerAttackedWatcher()); + } + + private StrongboxRaider(final StrongboxRaider card) { + super(card); + } + + @Override + public StrongboxRaider copy() { + return new StrongboxRaider(this); + } +} diff --git a/Mage.Sets/src/mage/cards/t/TectonicGiant.java b/Mage.Sets/src/mage/cards/t/TectonicGiant.java index 3b521f8dc3e..a6905f129ae 100644 --- a/Mage.Sets/src/mage/cards/t/TectonicGiant.java +++ b/Mage.Sets/src/mage/cards/t/TectonicGiant.java @@ -1,25 +1,17 @@ package mage.cards.t; import mage.MageInt; -import mage.abilities.Ability; import mage.abilities.Mode; import mage.abilities.TriggeredAbility; import mage.abilities.common.AttacksTriggeredAbility; import mage.abilities.common.BecomesTargetSourceTriggeredAbility; -import mage.abilities.effects.AsThoughEffectImpl; -import mage.abilities.effects.ContinuousEffect; -import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.DamagePlayersEffect; +import mage.abilities.effects.common.ExileTopXMayPlayUntilEffect; import mage.abilities.meta.OrTriggeredAbility; -import mage.cards.*; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; import mage.constants.*; import mage.filter.FilterSpell; -import mage.filter.StaticFilters; -import mage.game.Game; -import mage.players.Player; -import mage.target.TargetCard; -import mage.target.common.TargetCardInExile; -import mage.target.targetpointer.FixedTarget; import java.util.UUID; @@ -29,6 +21,7 @@ import java.util.UUID; public final class TectonicGiant extends CardImpl { private static final FilterSpell filter = new FilterSpell("a spell an opponent controls"); + static { filter.add(TargetController.OPPONENT.getControllerPredicate()); } @@ -44,11 +37,13 @@ public final class TectonicGiant extends CardImpl { // Whenever Tectonic Giant attacks or becomes the target of a spell an opponent controls, choose one — // • Tectonic Giant deals 3 damage to each opponent. // • Exile the top two cards of your library. Choose one of them. Until the end of your next turn, you may play that card. - TriggeredAbility ability = new OrTriggeredAbility(Zone.BATTLEFIELD, new DamagePlayersEffect(3, TargetController.OPPONENT), false, + TriggeredAbility ability = new OrTriggeredAbility( + Zone.BATTLEFIELD, new DamagePlayersEffect(3, TargetController.OPPONENT), false, "Whenever {this} attacks or becomes the target of a spell an opponent controls, ", new AttacksTriggeredAbility(null), - new BecomesTargetSourceTriggeredAbility(null, filter)); - ability.addMode(new Mode(new TectonicGiantEffect())); + new BecomesTargetSourceTriggeredAbility(null, filter) + ); + ability.addMode(new Mode(new ExileTopXMayPlayUntilEffect(2, true, Duration.UntilEndOfYourNextTurn))); this.addAbility(ability); } @@ -61,87 +56,3 @@ public final class TectonicGiant extends CardImpl { return new TectonicGiant(this); } } - -class TectonicGiantEffect extends OneShotEffect { - - TectonicGiantEffect() { - super(Outcome.Benefit); - staticText = "exile the top two cards of your library. Choose one of them. " - + "Until the end of your next turn, you may play that card"; - } - - private TectonicGiantEffect(final TectonicGiantEffect effect) { - super(effect); - } - - @Override - public TectonicGiantEffect copy() { - return new TectonicGiantEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player controller = game.getPlayer(source.getControllerId()); - if (controller == null) { - return false; - } - Cards cards = new CardsImpl(controller.getLibrary().getTopCards(game, 2)); - controller.moveCards(cards, Zone.EXILED, source, game); - TargetCard targetCard = new TargetCardInExile(StaticFilters.FILTER_CARD); - controller.choose(outcome, cards, targetCard, source, game); - - Card card = game.getCard(targetCard.getFirstTarget()); - if (card == null) { - return true; - } - ContinuousEffect effect = new TectonicGiantMayPlayEffect(); - effect.setTargetPointer(new FixedTarget(card.getId())); - game.addEffect(effect, source); - - return true; - } -} - -class TectonicGiantMayPlayEffect extends AsThoughEffectImpl { - - private int castOnTurn = 0; - - TectonicGiantMayPlayEffect() { - super(AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, Duration.Custom, Outcome.Benefit); - this.staticText = "Until the end of your next turn, you may play that card."; - } - - private TectonicGiantMayPlayEffect(final TectonicGiantMayPlayEffect effect) { - super(effect); - castOnTurn = effect.castOnTurn; - } - - @Override - public TectonicGiantMayPlayEffect copy() { - return new TectonicGiantMayPlayEffect(this); - } - - @Override - public void init(Ability source, Game game) { - super.init(source, game); - castOnTurn = game.getTurnNum(); - } - - @Override - public boolean isInactive(Ability source, Game game) { - return castOnTurn != game.getTurnNum() - && game.getPhase().getStep().getType() == PhaseStep.END_TURN - && game.isActivePlayer(source.getControllerId()); - } - - @Override - public boolean apply(Game game, Ability source) { - return true; - } - - @Override - public boolean applies(UUID sourceId, Ability source, UUID affectedControllerId, Game game) { - return source.isControlledBy(affectedControllerId) - && getTargetPointer().getTargets(game, source).contains(sourceId); - } -} diff --git a/Mage.Sets/src/mage/cards/w/WitchKingSkyScourge.java b/Mage.Sets/src/mage/cards/w/WitchKingSkyScourge.java index 0104c279c7a..1020ed8b8a9 100644 --- a/Mage.Sets/src/mage/cards/w/WitchKingSkyScourge.java +++ b/Mage.Sets/src/mage/cards/w/WitchKingSkyScourge.java @@ -20,7 +20,6 @@ import mage.game.permanent.Permanent; import java.util.UUID; /** - * * @author notgreat */ public final class WitchKingSkyScourge extends CardImpl { @@ -31,6 +30,7 @@ public final class WitchKingSkyScourge extends CardImpl { filter.add(TargetController.YOU.getControllerPredicate()); filter.add(SubType.WRAITH.getPredicate()); } + public WitchKingSkyScourge(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{5}{B}{R}"); @@ -45,7 +45,7 @@ public final class WitchKingSkyScourge extends CardImpl { // Whenever you attack with one or more Wraiths, exile the top X cards of your library, where X is their total power. You may play those cards this turn. this.addAbility(new AttacksWithCreaturesTriggeredAbility(Zone.BATTLEFIELD, - new ExileTopXMayPlayUntilEffect(TotalTargetsPowerValue.instance, Duration.EndOfTurn) + new ExileTopXMayPlayUntilEffect(TotalTargetsPowerValue.instance, false, Duration.EndOfTurn) .setText("exile the top X cards of your library, where X is their total power. You may play those cards this turn.") , 1, filter, true)); diff --git a/Mage.Sets/src/mage/sets/Foundations.java b/Mage.Sets/src/mage/sets/Foundations.java index 2ac8a55861b..e543b015531 100644 --- a/Mage.Sets/src/mage/sets/Foundations.java +++ b/Mage.Sets/src/mage/sets/Foundations.java @@ -273,6 +273,7 @@ public final class Foundations extends ExpansionSet { cards.add(new SetCardInfo("Stroke of Midnight", 148, Rarity.UNCOMMON, mage.cards.s.StrokeOfMidnight.class)); cards.add(new SetCardInfo("Stromkirk Bloodthief", 185, Rarity.UNCOMMON, mage.cards.s.StromkirkBloodthief.class)); cards.add(new SetCardInfo("Stromkirk Noble", 632, Rarity.RARE, mage.cards.s.StromkirkNoble.class)); + cards.add(new SetCardInfo("Strongbox Raider", 96, Rarity.UNCOMMON, mage.cards.s.StrongboxRaider.class)); cards.add(new SetCardInfo("Surrak, the Hunt Caller", 647, Rarity.RARE, mage.cards.s.SurrakTheHuntCaller.class)); cards.add(new SetCardInfo("Swamp", 276, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Swiftblade Vindicator", 246, Rarity.RARE, mage.cards.s.SwiftbladeVindicator.class)); diff --git a/Mage/src/main/java/mage/abilities/effects/common/ExileTopXMayPlayUntilEffect.java b/Mage/src/main/java/mage/abilities/effects/common/ExileTopXMayPlayUntilEffect.java index 36a01e5595e..f55338e73c7 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/ExileTopXMayPlayUntilEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/ExileTopXMayPlayUntilEffect.java @@ -6,11 +6,16 @@ import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.asthought.PlayFromNotOwnHandZoneTargetEffect; import mage.cards.Card; +import mage.cards.Cards; +import mage.cards.CardsImpl; import mage.constants.Duration; 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.TargetCardInExile; import mage.target.targetpointer.FixedTargets; import mage.util.CardUtil; @@ -19,22 +24,29 @@ import java.util.Set; public class ExileTopXMayPlayUntilEffect extends OneShotEffect { private final DynamicValue amount; + private final boolean chooseOne; private final Duration duration; public ExileTopXMayPlayUntilEffect(int amount, Duration duration) { - this(StaticValue.get(amount), duration); + this(amount, false, duration); } - public ExileTopXMayPlayUntilEffect(DynamicValue amount, Duration duration) { + public ExileTopXMayPlayUntilEffect(int amount, boolean chooseOne, Duration duration) { + this(StaticValue.get(amount), chooseOne, duration); + } + + public ExileTopXMayPlayUntilEffect(DynamicValue amount, boolean chooseOne, Duration duration) { super(Outcome.Benefit); this.amount = amount.copy(); + this.chooseOne = chooseOne; this.duration = duration; - makeText(amount.toString().equals("1") ? "that card" : "those cards", duration == Duration.EndOfTurn); + makeText(amount.toString().equals("1") || chooseOne ? "that card" : "those cards", duration == Duration.EndOfTurn); } protected ExileTopXMayPlayUntilEffect(final ExileTopXMayPlayUntilEffect effect) { super(effect); this.amount = effect.amount.copy(); + this.chooseOne = effect.chooseOne; this.duration = effect.duration; } @@ -50,18 +62,29 @@ public class ExileTopXMayPlayUntilEffect extends OneShotEffect { return false; } int resolvedAmount = amount.calculate(game, source, this); - Set cards = controller.getLibrary().getTopCards(game, resolvedAmount); + Cards cards = new CardsImpl(controller.getLibrary().getTopCards(game, resolvedAmount)); if (cards.isEmpty()) { return true; } - controller.moveCardsToExile(cards, source, game, true, CardUtil.getExileZoneId(game, source), CardUtil.getSourceName(game, source)); + controller.moveCardsToExile( + cards.getCards(game), source, game, true, + CardUtil.getExileZoneId(game, source), + CardUtil.getSourceName(game, source) + ); // remove cards that could not be moved to exile - cards.removeIf(card -> !Zone.EXILED.equals(game.getState().getZone(card.getId()))); - if (!cards.isEmpty()) { - game.addEffect(new PlayFromNotOwnHandZoneTargetEffect(Zone.EXILED, duration) - .setTargetPointer(new FixedTargets(cards, game)), source); - effectCards(game, source, cards); + cards.retainZone(Zone.EXILED, game); + if (chooseOne && cards.size() > 1) { + TargetCard target = new TargetCardInExile(StaticFilters.FILTER_CARD); + target.withNotTarget(true); + controller.choose(outcome, cards, target, source, game); + cards.removeIf(uuid -> !uuid.equals(target.getFirstTarget())); } + if (cards.isEmpty()) { + return true; + } + game.addEffect(new PlayFromNotOwnHandZoneTargetEffect(Zone.EXILED, duration) + .setTargetPointer(new FixedTargets(cards, game)), source); + effectCards(game, source, cards.getCards(game)); return true; } @@ -86,6 +109,9 @@ public class ExileTopXMayPlayUntilEffect extends OneShotEffect { } else { text += " of your library. "; } + if (chooseOne) { + text += "Choose one of them. "; + } if (durationRuleAtEnd) { text += "You may play " + refCardText + ' ' + (duration == Duration.EndOfTurn ? "this turn" : duration.toString()); } else {