From d98b9bc18a8afd98b787f5a4085cce082087450b Mon Sep 17 00:00:00 2001 From: theelk801 Date: Tue, 6 Jan 2026 09:13:29 -0500 Subject: [PATCH] [ECL] Implement Sanar, Innovative First-Year --- .../cards/s/SanarInnovativeFirstYear.java | 150 ++++++++++++++++++ Mage.Sets/src/mage/sets/LorwynEclipsed.java | 2 + 2 files changed, 152 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/s/SanarInnovativeFirstYear.java diff --git a/Mage.Sets/src/mage/cards/s/SanarInnovativeFirstYear.java b/Mage.Sets/src/mage/cards/s/SanarInnovativeFirstYear.java new file mode 100644 index 00000000000..864ca3d15a3 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SanarInnovativeFirstYear.java @@ -0,0 +1,150 @@ +package mage.cards.s; + +import mage.MageInt; +import mage.ObjectColor; +import mage.abilities.Ability; +import mage.abilities.assignment.common.ColorAssignment; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.dynamicvalue.common.ColorsAmongControlledPermanentsCount; +import mage.abilities.effects.OneShotEffect; +import mage.cards.*; +import mage.constants.*; +import mage.filter.FilterCard; +import mage.filter.StaticFilters; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.ColorlessPredicate; +import mage.game.Game; +import mage.players.Player; +import mage.target.TargetCard; +import mage.target.common.TargetCardInLibrary; +import mage.util.CardUtil; + +import java.util.UUID; +import java.util.stream.Collectors; + +/** + * @author TheElk801 + */ +public final class SanarInnovativeFirstYear extends CardImpl { + + public SanarInnovativeFirstYear(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{U/R}{U/R}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.GOBLIN); + this.subtype.add(SubType.SORCERER); + this.power = new MageInt(2); + this.toughness = new MageInt(4); + + // Vivid -- At the beginning of your first main phase, reveal cards from the top of your library until you reveal X nonland cards, where X is the number of colors among permanents you control. For each of those colors, you may exile a card of that color from among the revealed cards. Then shuffle. You may cast the exiled cards this turn. + this.addAbility(new EntersBattlefieldTriggeredAbility(new SanarInnovativeFirstYearEffect()) + .setAbilityWord(AbilityWord.VIVID) + .addHint(ColorsAmongControlledPermanentsCount.ALL_PERMANENTS.getHint())); + } + + private SanarInnovativeFirstYear(final SanarInnovativeFirstYear card) { + super(card); + } + + @Override + public SanarInnovativeFirstYear copy() { + return new SanarInnovativeFirstYear(this); + } +} + +class SanarInnovativeFirstYearEffect extends OneShotEffect { + + SanarInnovativeFirstYearEffect() { + super(Outcome.Benefit); + staticText = "reveal cards from the top of your library until you reveal X nonland cards, " + + "where X is the number of colors among permanents you control. For each of those colors, " + + "you may exile a card of that color from among the revealed cards. Then shuffle. " + + "You may cast the exiled cards this turn"; + } + + private SanarInnovativeFirstYearEffect(final SanarInnovativeFirstYearEffect effect) { + super(effect); + } + + @Override + public SanarInnovativeFirstYearEffect copy() { + return new SanarInnovativeFirstYearEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + ObjectColor color = ColorsAmongControlledPermanentsCount.ALL_PERMANENTS.getAllControlledColors(game, source); + int count = color.getColorCount(); + if (player == null || count < 1) { + return false; + } + Cards cards = new CardsImpl(); + for (Card card : player.getLibrary().getCards(game)) { + cards.add(card); + if (cards.count(StaticFilters.FILTER_CARD_NON_LAND, game) >= count) { + break; + } + } + player.revealCards(source, cards, game); + TargetCard target = new SanarInnovativeFirstYearTarget(color); + player.choose(outcome, cards, target, source, game); + Cards toExile = new CardsImpl(target.getTargets()); + player.moveCards(toExile, Zone.EXILED, source, game); + toExile.retainZone(Zone.EXILED, game); + player.shuffleLibrary(source, game); + for (Card card : toExile.getCards(game)) { + CardUtil.makeCardPlayable(game, source, card, true, Duration.EndOfTurn, false); + } + return true; + } +} + +class SanarInnovativeFirstYearTarget extends TargetCardInLibrary { + + private final ColorAssignment colorAssigner; + + private static FilterCard makeFilter(ObjectColor color) { + FilterCard filterCard = new FilterCard(CardUtil.concatWithAnd( + color.getColors() + .stream() + .map(ObjectColor::getDescription) + .map(s -> "a " + s + " card") + .collect(Collectors.toList()) + )); + filterCard.add(Predicates.not(ColorlessPredicate.instance)); + return filterCard; + } + + SanarInnovativeFirstYearTarget(ObjectColor color) { + super(0, color.getColorCount(), makeFilter(color)); + this.colorAssigner = new ColorAssignment(color.toString().split("")); + } + + private SanarInnovativeFirstYearTarget(final SanarInnovativeFirstYearTarget target) { + super(target); + this.colorAssigner = target.colorAssigner; + } + + @Override + public SanarInnovativeFirstYearTarget copy() { + return new SanarInnovativeFirstYearTarget(this); + } + + @Override + public boolean canTarget(UUID playerId, UUID id, Ability source, Game game) { + if (!super.canTarget(playerId, id, source, game)) { + return false; + } + Card card = game.getCard(id); + if (card == null) { + return false; + } + if (this.getTargets().isEmpty()) { + return true; + } + Cards cards = new CardsImpl(this.getTargets()); + cards.add(card); + return colorAssigner.getRoleCount(cards, game) >= cards.size(); + } +} diff --git a/Mage.Sets/src/mage/sets/LorwynEclipsed.java b/Mage.Sets/src/mage/sets/LorwynEclipsed.java index fd992dcbfa3..81b31f0625b 100644 --- a/Mage.Sets/src/mage/sets/LorwynEclipsed.java +++ b/Mage.Sets/src/mage/sets/LorwynEclipsed.java @@ -84,6 +84,8 @@ public final class LorwynEclipsed extends ExpansionSet { cards.add(new SetCardInfo("Plains", 269, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Plains", 274, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Plains", 279, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Sanar, Innovative First-Year", 241, Rarity.RARE, mage.cards.s.SanarInnovativeFirstYear.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Sanar, Innovative First-Year", 378, Rarity.RARE, mage.cards.s.SanarInnovativeFirstYear.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Sear", 154, Rarity.UNCOMMON, mage.cards.s.Sear.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Sear", 405, Rarity.UNCOMMON, mage.cards.s.Sear.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Silvergill Mentor", 403, Rarity.UNCOMMON, mage.cards.s.SilvergillMentor.class));