diff --git a/Mage.Sets/src/mage/cards/r/RowanScholarOfSparks.java b/Mage.Sets/src/mage/cards/r/RowanScholarOfSparks.java new file mode 100644 index 0000000000..6fac8997a8 --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/RowanScholarOfSparks.java @@ -0,0 +1,182 @@ +package mage.cards.r; + +import mage.MageItem; +import mage.abilities.Ability; +import mage.abilities.LoyaltyAbility; +import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.Condition; +import mage.abilities.decorator.ConditionalOneShotEffect; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.DamagePlayersEffect; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.GetEmblemEffect; +import mage.abilities.effects.common.continuous.SetPowerToughnessTargetEffect; +import mage.abilities.effects.common.cost.SpellsCostReductionControllerEffect; +import mage.abilities.hint.Hint; +import mage.cards.CardSetInfo; +import mage.cards.Cards; +import mage.cards.CardsImpl; +import mage.cards.ModalDoubleFacesCard; +import mage.constants.*; +import mage.filter.FilterCard; +import mage.filter.StaticFilters; +import mage.filter.common.FilterInstantOrSorceryCard; +import mage.game.Game; +import mage.game.command.emblems.RowanScholarOfSparksEmblem; +import mage.game.permanent.token.PrismariToken; +import mage.players.Player; +import mage.target.TargetPermanent; +import mage.target.common.TargetCreaturePermanent; +import mage.watchers.common.CardsAmountDrawnThisTurnWatcher; + +import java.util.Map; +import java.util.Objects; +import java.util.UUID; +import java.util.function.Function; +import java.util.stream.Collectors; + +/** + * @author TheElk801 + */ +public final class RowanScholarOfSparks extends ModalDoubleFacesCard { + + private static final FilterCard filter = new FilterInstantOrSorceryCard(""); + + public RowanScholarOfSparks(UUID ownerId, CardSetInfo setInfo) { + super( + ownerId, setInfo, + new CardType[]{CardType.PLANESWALKER}, new SubType[]{SubType.ROWAN}, "{2}{R}", + "Will, Scholar of Frost", + new CardType[]{CardType.PLANESWALKER}, new SubType[]{SubType.WILL}, "{4}{U}" + ); + + // 1. + // Rowan, Scholar of Sparks + // Legendary Planeswalker - Rowan + this.getLeftHalfCard().addSuperType(SuperType.LEGENDARY); + this.getLeftHalfCard().addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(2)); + + // Instant and sorcery spells you cast cost {1} less to cast. + this.getLeftHalfCard().addAbility(new SimpleStaticAbility(new SpellsCostReductionControllerEffect(filter, 1))); + + // +1: Rowan, Scholar of Sparks deals 1 damage to each opponent. If you've drawn three or more cards this turn, she deals 3 damage to each opponent instead. + Ability ability = new LoyaltyAbility(new ConditionalOneShotEffect( + new DamagePlayersEffect(3, TargetController.OPPONENT), + new DamagePlayersEffect(1, TargetController.OPPONENT), + RowanScholarOfSparksCondition.instance, "{this} deals 1 damage to each opponent. " + + "If you've drawn three or more cards this turn, she deals 3 damage to each opponent instead" + ), 1); + ability.addWatcher(new CardsAmountDrawnThisTurnWatcher()); + this.getLeftHalfCard().addAbility(ability.addHint(RowanScholarOfSparksHint.instance)); + + // −4: You get an emblem with "Whenever you cast an instant or sorcery spell, you may pay {2}. If you do, copy that spell. You may choose new targets for the copy." + this.getLeftHalfCard().addAbility(new LoyaltyAbility( + new GetEmblemEffect(new RowanScholarOfSparksEmblem()), -4 + )); + + // 2. + // Will, Scholar of Frost + // Legendary Planeswalker - Will + this.getRightHalfCard().addSuperType(SuperType.LEGENDARY); + this.getRightHalfCard().addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(4)); + + // Instant and sorcery spells you cast cost {1} less to cast. + this.getRightHalfCard().addAbility(new SimpleStaticAbility( + new SpellsCostReductionControllerEffect(filter, 1) + )); + + // +1: Up to one target creature has base power and toughness 0/2 until your next turn. + ability = new LoyaltyAbility(new SetPowerToughnessTargetEffect( + 0, 2, Duration.UntilYourNextTurn + ), 1); + ability.addTarget(new TargetCreaturePermanent(0, 1)); + this.getRightHalfCard().addAbility(ability); + + // −3: Draw two cards. + this.getRightHalfCard().addAbility(new LoyaltyAbility(new DrawCardSourceControllerEffect(2), -3)); + + // −7: Exile up to five target permanents. For each permanent exiled this way, its controller creates a 4/4 blue and red Elemental Creature token. + ability = new LoyaltyAbility(new WillScholarOfFrostEffect(), -7); + ability.addTarget(new TargetPermanent(0, 5, StaticFilters.FILTER_PERMANENTS)); + this.getRightHalfCard().addAbility(ability); + } + + private RowanScholarOfSparks(final RowanScholarOfSparks card) { + super(card); + } + + @Override + public RowanScholarOfSparks copy() { + return new RowanScholarOfSparks(this); + } +} + +enum RowanScholarOfSparksCondition implements Condition { + instance; + + @Override + public boolean apply(Game game, Ability source) { + CardsAmountDrawnThisTurnWatcher watcher = game.getState().getWatcher(CardsAmountDrawnThisTurnWatcher.class); + return watcher != null && watcher.getAmountCardsDrawn(source.getControllerId()) >= 3; + } +} + +enum RowanScholarOfSparksHint implements Hint { + instance; + + @Override + public String getText(Game game, Ability ability) { + CardsAmountDrawnThisTurnWatcher watcher = game.getState().getWatcher(CardsAmountDrawnThisTurnWatcher.class); + int drawn = watcher != null ? watcher.getAmountCardsDrawn(ability.getControllerId()) : 0; + return "Cards drawn this turn: " + drawn; + } + + @Override + public RowanScholarOfSparksHint copy() { + return instance; + } +} + +class WillScholarOfFrostEffect extends OneShotEffect { + + WillScholarOfFrostEffect() { + super(Outcome.Benefit); + staticText = "exile up to five target permanents. For each permanent exiled this way, " + + "its controller creates a 4/4 blue and red Elemental creature token"; + } + + private WillScholarOfFrostEffect(final WillScholarOfFrostEffect effect) { + super(effect); + } + + @Override + public WillScholarOfFrostEffect copy() { + return new WillScholarOfFrostEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getSourceId()); + if (player == null) { + return false; + } + Cards cards = new CardsImpl(targetPointer.getTargets(game, source)); + Map playerMap = cards + .getCards(game) + .stream() + .filter(Objects::nonNull) + .map(MageItem::getId) + .map(game::getControllerId) + .filter(Objects::nonNull) + .collect(Collectors.toMap( + Function.identity(), + x -> 1, Integer::sum + )); + player.moveCards(cards, Zone.EXILED, source, game); + for (Map.Entry entry : playerMap.entrySet()) { + new PrismariToken().putOntoBattlefield(entry.getValue(), game, source, entry.getKey()); + } + return true; + } +} diff --git a/Mage.Sets/src/mage/sets/StrixhavenSchoolOfMages.java b/Mage.Sets/src/mage/sets/StrixhavenSchoolOfMages.java index f3c631f2cd..c0e9c8cbbc 100644 --- a/Mage.Sets/src/mage/sets/StrixhavenSchoolOfMages.java +++ b/Mage.Sets/src/mage/sets/StrixhavenSchoolOfMages.java @@ -230,6 +230,7 @@ public final class StrixhavenSchoolOfMages extends ExpansionSet { cards.add(new SetCardInfo("Rip Apart", 225, Rarity.UNCOMMON, mage.cards.r.RipApart.class)); cards.add(new SetCardInfo("Rise of Extus", 226, Rarity.COMMON, mage.cards.r.RiseOfExtus.class)); cards.add(new SetCardInfo("Rootha, Mercurial Artist", 227, Rarity.UNCOMMON, mage.cards.r.RoothaMercurialArtist.class)); + cards.add(new SetCardInfo("Rowan, Scholar of Sparks", 156, Rarity.MYTHIC, mage.cards.r.RowanScholarOfSparks.class)); cards.add(new SetCardInfo("Rushed Rebirth", 228, Rarity.RARE, mage.cards.r.RushedRebirth.class)); cards.add(new SetCardInfo("Scurrid Colony", 142, Rarity.COMMON, mage.cards.s.ScurridColony.class)); cards.add(new SetCardInfo("Secret Rendezvous", 26, Rarity.UNCOMMON, mage.cards.s.SecretRendezvous.class)); diff --git a/Mage/src/main/java/mage/abilities/effects/common/continuous/SetPowerToughnessTargetEffect.java b/Mage/src/main/java/mage/abilities/effects/common/continuous/SetPowerToughnessTargetEffect.java index b8ff7c4f84..31b08e6b2d 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/continuous/SetPowerToughnessTargetEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/continuous/SetPowerToughnessTargetEffect.java @@ -12,6 +12,7 @@ import mage.constants.SubLayer; import mage.game.Game; import mage.game.permanent.Permanent; import mage.target.Target; +import mage.util.CardUtil; import java.util.UUID; @@ -68,6 +69,11 @@ public class SetPowerToughnessTargetEffect extends ContinuousEffectImpl { return staticText; } StringBuilder sb = new StringBuilder(); + if (mode.getTargets().get(0).getMinNumberOfTargets() == 0) { + sb.append("up to "); + sb.append(CardUtil.numberToText(mode.getTargets().get(0).getMaxNumberOfTargets())); + sb.append(' '); + } if (!mode.getTargets().get(0).getTargetName().contains("target")) { sb.append("target "); } diff --git a/Mage/src/main/java/mage/game/command/emblems/LukkaWaywardBonderEmblem.java b/Mage/src/main/java/mage/game/command/emblems/LukkaWaywardBonderEmblem.java index bb6180fea6..7c0b4785a7 100644 --- a/Mage/src/main/java/mage/game/command/emblems/LukkaWaywardBonderEmblem.java +++ b/Mage/src/main/java/mage/game/command/emblems/LukkaWaywardBonderEmblem.java @@ -4,6 +4,7 @@ import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldControlledTriggeredAbility; import mage.abilities.effects.OneShotEffect; import mage.constants.Outcome; +import mage.constants.Zone; import mage.filter.StaticFilters; import mage.game.Game; import mage.game.command.Emblem; @@ -21,7 +22,8 @@ public final class LukkaWaywardBonderEmblem extends Emblem { this.setName("Emblem Lukka"); this.setExpansionSetCodeForImage("STX"); Ability ability = new EntersBattlefieldControlledTriggeredAbility( - new LukkaWaywardBonderEmblemEffect(), StaticFilters.FILTER_PERMANENT_CREATURE_A + Zone.COMMAND, new LukkaWaywardBonderEmblemEffect(), + StaticFilters.FILTER_PERMANENT_CREATURE_A, false ); ability.addTarget(new TargetAnyTarget()); this.getAbilities().add(ability); diff --git a/Mage/src/main/java/mage/game/command/emblems/RowanScholarOfSparksEmblem.java b/Mage/src/main/java/mage/game/command/emblems/RowanScholarOfSparksEmblem.java new file mode 100644 index 0000000000..707e0edb36 --- /dev/null +++ b/Mage/src/main/java/mage/game/command/emblems/RowanScholarOfSparksEmblem.java @@ -0,0 +1,25 @@ +package mage.game.command.emblems; + +import mage.abilities.common.SpellCastControllerTriggeredAbility; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.effects.common.CopyTargetSpellEffect; +import mage.abilities.effects.common.DoIfCostPaid; +import mage.constants.Zone; +import mage.filter.StaticFilters; +import mage.game.command.Emblem; + +/** + * @author TheElk801 + */ +public final class RowanScholarOfSparksEmblem extends Emblem { + + // −4: You get an emblem with "Whenever you cast an instant or sorcery spell, you may pay {2}. If you do, copy that spell. You may choose new targets for the copy." + public RowanScholarOfSparksEmblem() { + this.setName("Emblem Rowan"); + this.setExpansionSetCodeForImage("STX"); + this.getAbilities().add(new SpellCastControllerTriggeredAbility( + Zone.COMMAND, new DoIfCostPaid(new CopyTargetSpellEffect(true), new GenericManaCost(2)), + StaticFilters.FILTER_SPELL_AN_INSTANT_OR_SORCERY, false, true + )); + } +} diff --git a/Mage/src/main/java/mage/target/TargetPermanent.java b/Mage/src/main/java/mage/target/TargetPermanent.java index 65a8e26e33..f7fc169675 100644 --- a/Mage/src/main/java/mage/target/TargetPermanent.java +++ b/Mage/src/main/java/mage/target/TargetPermanent.java @@ -28,7 +28,11 @@ public class TargetPermanent extends TargetObject { } public TargetPermanent(int numTargets, FilterPermanent filter) { - this(numTargets, numTargets, filter, false); + this(numTargets, numTargets, filter); + } + + public TargetPermanent(int minNumTargets, int maxNumTargets, FilterPermanent filter) { + this(minNumTargets, maxNumTargets, filter, false); } public TargetPermanent(int minNumTargets, int maxNumTargets, FilterPermanent filter, boolean notTarget) {