From 80f9fdfb7942a2199b622bc075b22a1c29d27f5e Mon Sep 17 00:00:00 2001 From: Evan Kranzler Date: Tue, 5 Apr 2022 20:27:38 -0400 Subject: [PATCH] [ALL] reworked Fatal Lore and Misfortune to use mode selection --- Mage.Sets/src/mage/cards/f/FatalLore.java | 93 +++++++++++--------- Mage.Sets/src/mage/cards/m/Misfortune.java | 69 +++++++-------- Mage/src/main/java/mage/abilities/Modes.java | 21 +++-- 3 files changed, 98 insertions(+), 85 deletions(-) diff --git a/Mage.Sets/src/mage/cards/f/FatalLore.java b/Mage.Sets/src/mage/cards/f/FatalLore.java index 8c452c49dc7..8ea2a4cb7cd 100644 --- a/Mage.Sets/src/mage/cards/f/FatalLore.java +++ b/Mage.Sets/src/mage/cards/f/FatalLore.java @@ -1,37 +1,46 @@ package mage.cards.f; -import java.util.UUID; import mage.abilities.Ability; -import mage.abilities.dynamicvalue.common.StaticValue; -import mage.abilities.effects.Effect; +import mage.abilities.Mode; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.DestroyTargetEffect; -import mage.abilities.effects.common.DrawCardTargetEffect; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Outcome; +import mage.constants.TargetController; +import mage.filter.FilterPermanent; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.permanent.ControllerIdPredicate; import mage.game.Game; import mage.players.Player; -import mage.target.common.TargetCreaturePermanent; -import mage.target.common.TargetOpponent; -import mage.target.targetpointer.FixedTarget; +import mage.target.TargetPermanent; +import mage.target.targetadjustment.TargetAdjuster; + +import java.util.Objects; +import java.util.UUID; /** - * - * @author jeffwadsworth + * @author TheElk801 */ public final class FatalLore extends CardImpl { public FatalLore(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{B}{B}"); - // An opponent chooses one - You draw three cards; or you destroy up to two target creatures that opponent controls and that player draws up to three cards. Those creatures can't be regenerated. - this.getSpellAbility().addEffect(new FatalLoreEffect()); - this.getSpellAbility().addTarget(new TargetOpponent(true)); + // An opponent chooses one — + this.getSpellAbility().getModes().setModeChooser(TargetController.OPPONENT); + // • You draw three cards. + this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(1).setText("you draw three cards")); + + // • You destroy up to two target creatures that player controls. They can't be regenerated. That player draws up to three cards. + this.getSpellAbility().addMode(new Mode(new DestroyTargetEffect( + "you destroy up to two target creatures that player controls. " + + "They can't be regenerated", true + )).addEffect(new FatalLoreEffect())); + this.getSpellAbility().setTargetAdjuster(FatalLoreAdjuster.instance); } private FatalLore(final FatalLore card) { @@ -44,14 +53,37 @@ public final class FatalLore extends CardImpl { } } +enum FatalLoreAdjuster implements TargetAdjuster { + instance; + + @Override + public void adjustTargets(Ability ability, Game game) { + Mode mode = ability.getModes().getMode(); + if (mode.getEffects().stream().noneMatch(DestroyTargetEffect.class::isInstance)) { + return; + } + UUID playerId = mode + .getEffects() + .stream() + .findFirst() + .filter(Objects::nonNull) + .map(effect -> (UUID) effect.getValue("choosingPlayer")) + .orElse(null); + FilterPermanent filter = new FilterCreaturePermanent("creatures controlled by " + game.getPlayer(playerId).getName()); + filter.add(new ControllerIdPredicate(playerId)); + mode.getTargets().clear(); + mode.addTarget(new TargetPermanent(0, 2, filter)); + } +} + class FatalLoreEffect extends OneShotEffect { - public FatalLoreEffect() { - super(Outcome.Neutral); - staticText = "An opponent chooses one - You draw three cards; or you destroy up to two target creatures that opponent controls and that player draws up to three cards. Those creatures can't be regenerated"; + FatalLoreEffect() { + super(Outcome.Benefit); + staticText = "That player draws up to three cards"; } - public FatalLoreEffect(final FatalLoreEffect effect) { + private FatalLoreEffect(final FatalLoreEffect effect) { super(effect); } @@ -62,30 +94,11 @@ class FatalLoreEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Player controller = game.getPlayer(source.getControllerId()); - Player chosenOpponent = game.getPlayer(targetPointer.getFirst(game, source)); - if (controller != null - && chosenOpponent != null) { - if (chosenOpponent.chooseUse(Outcome.Neutral, "If you choose Yes, the controller draws three cards. If no, the controller gets to destroy up to two target creatures that you control and you get to draw up to 3 cards. Those creatures can't be regenerated.", source, game)) { - controller.drawCards(3, source, game); - } else { - FilterCreaturePermanent filter = new FilterCreaturePermanent("chosen opponent's creature"); - filter.add(new ControllerIdPredicate(chosenOpponent.getId())); - TargetCreaturePermanent target = new TargetCreaturePermanent(0, 2, filter, false); - if (target.canChoose(controller.getId(), source, game) - && controller.choose(Outcome.DestroyPermanent, target, source, game)) { - for (UUID targetId : target.getTargets()) { - Effect destroyCreature = new DestroyTargetEffect(true); - destroyCreature.setTargetPointer(new FixedTarget(targetId, game)); - destroyCreature.apply(game, source); - } - Effect opponentDrawsCards = new DrawCardTargetEffect(StaticValue.get(3), false, true); - opponentDrawsCards.setTargetPointer(new FixedTarget(chosenOpponent.getId())); - opponentDrawsCards.apply(game, source); - return true; - } - } + Player player = game.getPlayer((UUID) getValue("choosingPlayer")); + if (player == null) { + return false; } - return false; + int toDraw = player.getAmount(0, 3, "Choose how many cards to draw", game); + return player.drawCards(toDraw, source, game) > 0; } } diff --git a/Mage.Sets/src/mage/cards/m/Misfortune.java b/Mage.Sets/src/mage/cards/m/Misfortune.java index 6c94dcddd06..18703b68c3e 100644 --- a/Mage.Sets/src/mage/cards/m/Misfortune.java +++ b/Mage.Sets/src/mage/cards/m/Misfortune.java @@ -1,34 +1,42 @@ package mage.cards.m; import mage.abilities.Ability; -import mage.abilities.effects.Effect; +import mage.abilities.Mode; import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.GainLifeEffect; import mage.abilities.effects.common.counter.AddCountersAllEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Outcome; +import mage.constants.TargetController; import mage.counters.CounterType; -import mage.filter.common.FilterControlledCreaturePermanent; -import mage.filter.common.FilterCreaturePermanent; -import mage.filter.predicate.permanent.ControllerIdPredicate; +import mage.filter.StaticFilters; import mage.game.Game; +import mage.game.permanent.Permanent; import mage.players.Player; -import mage.target.common.TargetOpponent; import java.util.UUID; /** - * @author jeffwadsworth + * @author TheElk801 */ public final class Misfortune extends CardImpl { public Misfortune(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{1}{B}{R}{G}"); - // An opponent chooses one - You put a +1/+1 counter on each creature you control and gain 4 life; or you put a -1/-1 counter on each creature that player controls and Misfortune deals 4 damage to that player. - this.getSpellAbility().addEffect(new MisfortuneEffect()); - this.getSpellAbility().addTarget(new TargetOpponent(true)); + // An opponent chooses one — + this.getSpellAbility().getModes().setModeChooser(TargetController.OPPONENT); + + // • You put a +1/+1 counter on each creature you control and gain 4 life. + this.getSpellAbility().addEffect(new AddCountersAllEffect( + CounterType.P1P1.createInstance(), StaticFilters.FILTER_CONTROLLED_CREATURE + ).setText("you put a +1/+1 counter on each creature you control")); + this.getSpellAbility().addEffect(new GainLifeEffect(4).setText("and gain 4 life")); + + // • You put a -1/-1 counter on each creature that player controls and Misfortune deals 4 damage to that player. + this.getSpellAbility().addMode(new Mode(new MisfortuneEffect())); } private Misfortune(final Misfortune card) { @@ -43,15 +51,13 @@ public final class Misfortune extends CardImpl { class MisfortuneEffect extends OneShotEffect { - public MisfortuneEffect() { - super(Outcome.Neutral); - staticText = "An opponent chooses one - " - + "You put a +1/+1 counter on each creature you control and gain " - + "4 life; or you put a -1/-1 counter on each creature that player " - + "controls and Misfortune deals 4 damage to that player"; + MisfortuneEffect() { + super(Outcome.Benefit); + staticText = "you put a -1/-1 counter on each creature that player controls " + + "and {this} deals 4 damage to that player"; } - public MisfortuneEffect(final MisfortuneEffect effect) { + private MisfortuneEffect(final MisfortuneEffect effect) { super(effect); } @@ -62,27 +68,16 @@ class MisfortuneEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Player controller = game.getPlayer(source.getControllerId()); - Player chosenOpponent = game.getPlayer(targetPointer.getFirst(game, source)); - if (controller != null - && chosenOpponent != null) { - if (chosenOpponent.chooseUse(Outcome.Neutral, "If you choose Yes, the controller puts a +1/+1 counter" - + "on each creature they control and they gain 4 life. If no, the controller puts a -1/-1 counter" - + "on each creature you control and {this} deals 4 damage to you.", source, game)) { - Effect putP1P1CounterOnEachControlledCreature = new AddCountersAllEffect( - CounterType.P1P1.createInstance(), new FilterControlledCreaturePermanent()); - putP1P1CounterOnEachControlledCreature.apply(game, source); - controller.gainLife(4, game, source); - } else { - FilterCreaturePermanent filterOpponentCreatures = new FilterCreaturePermanent(); - filterOpponentCreatures.add(new ControllerIdPredicate(chosenOpponent.getId())); - Effect putM1M1CounterOnEachOpponentCreature = new AddCountersAllEffect( - CounterType.M1M1.createInstance(), filterOpponentCreatures); - putM1M1CounterOnEachOpponentCreature.apply(game, source); - chosenOpponent.damage(4, source.getSourceId(), source, game); - } - return true; + Player player = game.getPlayer((UUID) getValue("choosingPlayer")); + if (player == null) { + return false; } - return false; + for (Permanent permanent : game.getBattlefield().getActivePermanents( + StaticFilters.FILTER_CONTROLLED_CREATURE, player.getId(), source, game + )) { + permanent.addCounters(CounterType.M1M1.createInstance(), source.getControllerId(), source, game); + } + player.damage(4, source, game); + return true; } } diff --git a/Mage/src/main/java/mage/abilities/Modes.java b/Mage/src/main/java/mage/abilities/Modes.java index d5722654c12..594452d7d6d 100644 --- a/Mage/src/main/java/mage/abilities/Modes.java +++ b/Mage/src/main/java/mage/abilities/Modes.java @@ -306,19 +306,18 @@ public class Modes extends LinkedHashMap { // Some spells and abilities specify that a player other than their controller chooses a mode for it. // In that case, the other player does so when the spell or ability's controller normally would do so. // If there is more than one other player who could make such a choice, the spell or ability's controller decides which of those players will make the choice. - UUID playerId = null; + UUID playerId; if (modeChooser == TargetController.OPPONENT) { TargetOpponent targetOpponent = new TargetOpponent(); - if (targetOpponent.choose(Outcome.Benefit, source.getControllerId(), source.getSourceId(), source, game)) { - playerId = targetOpponent.getFirstTarget(); - } + targetOpponent.choose(Outcome.Benefit, source.getControllerId(), source.getSourceId(), source, game); + playerId = targetOpponent.getFirstTarget(); } else { playerId = source.getControllerId(); } - if (playerId == null) { + Player player = game.getPlayer(playerId); + if (player == null) { return false; } - Player player = game.getPlayer(playerId); // player chooses modes manually this.currentMode = null; @@ -341,7 +340,13 @@ public class Modes extends LinkedHashMap { if (isEachModeOnlyOnce()) { setAlreadySelectedModes(source, game); } - return true; + if (modeChooser == TargetController.OPPONENT) { + selectedModes + .stream() + .map(this::get) + .map(Mode::getEffects) + .forEach(effects -> effects.setValue("choosingPlayer", playerId)); + } } else { // only one mode available if (currentMode == null) { @@ -350,8 +355,8 @@ public class Modes extends LinkedHashMap { this.addSelectedMode(mode.getId()); this.setActiveMode(mode); } - return true; } + return true; } /**