From a5d83aedc0b60d6e15a2949e7c19ef33d266447a Mon Sep 17 00:00:00 2001
From: theelk801 <theelk801@gmail.com>
Date: Tue, 25 Apr 2023 08:03:28 -0400
Subject: [PATCH] [ONC] Implement Neyali, Suns' Vanguard

---
 .../src/mage/cards/n/NeyaliSunsVanguard.java  | 176 ++++++++++++++++++
 .../sets/PhyrexiaAllWillBeOneCommander.java   |   1 +
 2 files changed, 177 insertions(+)
 create mode 100644 Mage.Sets/src/mage/cards/n/NeyaliSunsVanguard.java

diff --git a/Mage.Sets/src/mage/cards/n/NeyaliSunsVanguard.java b/Mage.Sets/src/mage/cards/n/NeyaliSunsVanguard.java
new file mode 100644
index 0000000000..37262e2102
--- /dev/null
+++ b/Mage.Sets/src/mage/cards/n/NeyaliSunsVanguard.java
@@ -0,0 +1,176 @@
+package mage.cards.n;
+
+import mage.MageInt;
+import mage.abilities.Ability;
+import mage.abilities.TriggeredAbilityImpl;
+import mage.abilities.common.SimpleStaticAbility;
+import mage.abilities.effects.OneShotEffect;
+import mage.abilities.effects.common.continuous.GainAbilityControlledEffect;
+import mage.abilities.keyword.DoubleStrikeAbility;
+import mage.cards.Card;
+import mage.cards.CardImpl;
+import mage.cards.CardSetInfo;
+import mage.constants.*;
+import mage.filter.FilterPermanent;
+import mage.filter.predicate.permanent.AttackingPredicate;
+import mage.filter.predicate.permanent.TokenPredicate;
+import mage.game.Controllable;
+import mage.game.Game;
+import mage.game.events.DefenderAttackedEvent;
+import mage.game.events.GameEvent;
+import mage.game.permanent.Permanent;
+import mage.game.permanent.PermanentToken;
+import mage.players.Player;
+import mage.util.CardUtil;
+import mage.watchers.Watcher;
+
+import java.util.HashSet;
+import java.util.Set;
+import java.util.UUID;
+
+/**
+ * @author TheElk801
+ */
+public final class NeyaliSunsVanguard extends CardImpl {
+
+    private static final FilterPermanent filter = new FilterPermanent("attacking tokens");
+
+    static {
+        filter.add(AttackingPredicate.instance);
+        filter.add(TokenPredicate.TRUE);
+    }
+
+    public NeyaliSunsVanguard(UUID ownerId, CardSetInfo setInfo) {
+        super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{R}{W}");
+
+        this.addSuperType(SuperType.LEGENDARY);
+        this.subtype.add(SubType.HUMAN);
+        this.subtype.add(SubType.REBEL);
+        this.power = new MageInt(3);
+        this.toughness = new MageInt(3);
+
+        // Attacking tokens you control have double strike.
+        this.addAbility(new SimpleStaticAbility(new GainAbilityControlledEffect(
+                DoubleStrikeAbility.getInstance(), Duration.WhileOnBattlefield, filter
+        )));
+
+        // Whenever one or more tokens you control attack a player, exile the top card of your library. During any turn you attacked with a token, you may play that card.
+        this.addAbility(new NeyaliSunsVanguardTriggeredAbility());
+    }
+
+    private NeyaliSunsVanguard(final NeyaliSunsVanguard card) {
+        super(card);
+    }
+
+    @Override
+    public NeyaliSunsVanguard copy() {
+        return new NeyaliSunsVanguard(this);
+    }
+}
+
+class NeyaliSunsVanguardTriggeredAbility extends TriggeredAbilityImpl {
+
+    NeyaliSunsVanguardTriggeredAbility() {
+        super(Zone.BATTLEFIELD, new NeyaliSunsVanguardEffect());
+        this.addWatcher(new NeyaliSunsVanguardWatcher());
+    }
+
+    private NeyaliSunsVanguardTriggeredAbility(final NeyaliSunsVanguardTriggeredAbility ability) {
+        super(ability);
+    }
+
+    @Override
+    public NeyaliSunsVanguardTriggeredAbility copy() {
+        return new NeyaliSunsVanguardTriggeredAbility(this);
+    }
+
+    @Override
+    public boolean checkEventType(GameEvent event, Game game) {
+        return event.getType() == GameEvent.EventType.DEFENDER_ATTACKED;
+    }
+
+    @Override
+    public boolean checkTrigger(GameEvent event, Game game) {
+        return game.getPlayer(event.getTargetId()) != null
+                && ((DefenderAttackedEvent) event)
+                .getAttackers(game)
+                .stream()
+                .filter(PermanentToken.class::isInstance)
+                .map(Controllable::getControllerId)
+                .anyMatch(this::isControlledBy);
+    }
+
+    @Override
+    public String getRule() {
+        return "Whenever one or more tokens you control attack a player, exile the top card of your library. " +
+                "During any turn you attacked with a token, you may play that card.";
+    }
+}
+
+class NeyaliSunsVanguardEffect extends OneShotEffect {
+
+    NeyaliSunsVanguardEffect() {
+        super(Outcome.Benefit);
+    }
+
+    private NeyaliSunsVanguardEffect(final NeyaliSunsVanguardEffect effect) {
+        super(effect);
+    }
+
+    @Override
+    public NeyaliSunsVanguardEffect copy() {
+        return new NeyaliSunsVanguardEffect(this);
+    }
+
+    @Override
+    public boolean apply(Game game, Ability source) {
+        Player player = game.getPlayer(source.getControllerId());
+        if (player == null) {
+            return false;
+        }
+        Card card = player.getLibrary().getFromTop(game);
+        if (card == null) {
+            return false;
+        }
+        player.moveCards(card, Zone.EXILED, source, game);
+        CardUtil.makeCardPlayable(
+                game, source, card, Duration.Custom, false,
+                source.getControllerId(), NeyaliSunsVanguardWatcher::checkPlayer
+        );
+        return true;
+    }
+}
+
+class NeyaliSunsVanguardWatcher extends Watcher {
+
+    private final Set<UUID> set = new HashSet<>();
+
+    NeyaliSunsVanguardWatcher() {
+        super(WatcherScope.GAME);
+    }
+
+    @Override
+    public void watch(GameEvent event, Game game) {
+        if (event.getType() != GameEvent.EventType.ATTACKER_DECLARED) {
+            return;
+        }
+        Permanent permanent = game.getPermanent(event.getSourceId());
+        if (permanent instanceof PermanentToken) {
+            set.add(permanent.getControllerId());
+        }
+    }
+
+    @Override
+    public void reset() {
+        super.reset();
+        set.clear();
+    }
+
+    static boolean checkPlayer(Game game, Ability source) {
+        return game
+                .getState()
+                .getWatcher(NeyaliSunsVanguardWatcher.class)
+                .set
+                .contains(source.getControllerId());
+    }
+}
diff --git a/Mage.Sets/src/mage/sets/PhyrexiaAllWillBeOneCommander.java b/Mage.Sets/src/mage/sets/PhyrexiaAllWillBeOneCommander.java
index 69d50db9ff..e2dbcfd4cc 100644
--- a/Mage.Sets/src/mage/sets/PhyrexiaAllWillBeOneCommander.java
+++ b/Mage.Sets/src/mage/sets/PhyrexiaAllWillBeOneCommander.java
@@ -119,6 +119,7 @@ public final class PhyrexiaAllWillBeOneCommander extends ExpansionSet {
         cards.add(new SetCardInfo("Myr Battlesphere", 138, Rarity.RARE, mage.cards.m.MyrBattlesphere.class));
         cards.add(new SetCardInfo("Myriad Landscape", 159, Rarity.UNCOMMON, mage.cards.m.MyriadLandscape.class));
         cards.add(new SetCardInfo("Necroblossom Snarl", 160, Rarity.RARE, mage.cards.n.NecroblossomSnarl.class));
+        cards.add(new SetCardInfo("Neyali, Suns' Vanguard", 2, Rarity.MYTHIC, mage.cards.n.NeyaliSunsVanguard.class));
         cards.add(new SetCardInfo("Night's Whisper", 94, Rarity.COMMON, mage.cards.n.NightsWhisper.class));
         cards.add(new SetCardInfo("Norn's Annex", 83, Rarity.RARE, mage.cards.n.NornsAnnex.class));
         cards.add(new SetCardInfo("Norn's Choirmaster", 8, Rarity.RARE, mage.cards.n.NornsChoirmaster.class, NON_FULL_USE_VARIOUS));