diff --git a/Mage.Sets/src/mage/cards/a/AnimusOfNightsReach.java b/Mage.Sets/src/mage/cards/a/AnimusOfNightsReach.java
new file mode 100644
index 00000000000..e6126818263
--- /dev/null
+++ b/Mage.Sets/src/mage/cards/a/AnimusOfNightsReach.java
@@ -0,0 +1,92 @@
+package mage.cards.a;
+
+import mage.MageInt;
+import mage.abilities.Ability;
+import mage.abilities.common.AttacksTriggeredAbility;
+import mage.abilities.dynamicvalue.DynamicValue;
+import mage.abilities.dynamicvalue.common.CardsInAllGraveyardsCount;
+import mage.abilities.dynamicvalue.common.StaticValue;
+import mage.abilities.effects.common.continuous.BoostSourceEffect;
+import mage.abilities.hint.Hint;
+import mage.abilities.keyword.MenaceAbility;
+import mage.cards.CardImpl;
+import mage.cards.CardSetInfo;
+import mage.constants.CardType;
+import mage.constants.Duration;
+import mage.constants.SubType;
+import mage.filter.FilterCard;
+import mage.filter.StaticFilters;
+import mage.filter.common.FilterCreatureCard;
+import mage.filter.predicate.card.DefendingPlayerOwnsCardPredicate;
+import mage.game.Game;
+
+import java.util.Objects;
+import java.util.UUID;
+import java.util.stream.Collectors;
+
+/**
+ * @author TheElk801
+ */
+public final class AnimusOfNightsReach extends CardImpl {
+
+ private static final FilterCard filter
+ = new FilterCreatureCard("creature cards in defending player's graveyard");
+
+ static {
+ filter.add(DefendingPlayerOwnsCardPredicate.instance);
+ }
+
+ private static final DynamicValue xValue = new CardsInAllGraveyardsCount(filter);
+
+ public AnimusOfNightsReach(UUID ownerId, CardSetInfo setInfo) {
+ super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT, CardType.CREATURE}, "");
+
+ this.subtype.add(SubType.SPIRIT);
+ this.power = new MageInt(0);
+ this.toughness = new MageInt(4);
+ this.color.setBlack(true);
+ this.nightCard = true;
+
+ // Menace
+ this.addAbility(new MenaceAbility());
+
+ // Whenever Animus of Night's Reach attacks, it gets +X/+0 until end of turn, where X is the number of creature cards in defending player's graveyard.
+ this.addAbility(new AttacksTriggeredAbility(new BoostSourceEffect(
+ xValue, StaticValue.get(0), Duration.EndOfTurn, true)
+ ).addHint(AnimusOfNightsReachHint.instance));
+ }
+
+ private AnimusOfNightsReach(final AnimusOfNightsReach card) {
+ super(card);
+ }
+
+ @Override
+ public AnimusOfNightsReach copy() {
+ return new AnimusOfNightsReach(this);
+ }
+}
+
+enum AnimusOfNightsReachHint implements Hint {
+ instance;
+
+ @Override
+ public String getText(Game game, Ability ability) {
+ return "Cards in each opponent's graveyard:
"
+ + game
+ .getOpponents(ability.getControllerId())
+ .stream()
+ .map(game::getPlayer)
+ .filter(Objects::nonNull)
+ .map(player -> player
+ .getName()
+ + ": " + player
+ .getGraveyard()
+ .count(StaticFilters.FILTER_CARD_CREATURE, game))
+ .collect(Collectors.joining("
"));
+ }
+
+ @Override
+ public AnimusOfNightsReachHint copy() {
+ return instance;
+ }
+}
\ No newline at end of file
diff --git a/Mage.Sets/src/mage/cards/t/TheLongReachOfNight.java b/Mage.Sets/src/mage/cards/t/TheLongReachOfNight.java
new file mode 100644
index 00000000000..3606b77d03c
--- /dev/null
+++ b/Mage.Sets/src/mage/cards/t/TheLongReachOfNight.java
@@ -0,0 +1,56 @@
+package mage.cards.t;
+
+import mage.abilities.common.SagaAbility;
+import mage.abilities.costs.common.DiscardCardCost;
+import mage.abilities.effects.common.ExileSagaAndReturnTransformedEffect;
+import mage.abilities.effects.common.SacrificeOpponentsUnlessPayEffect;
+import mage.abilities.keyword.TransformAbility;
+import mage.cards.CardImpl;
+import mage.cards.CardSetInfo;
+import mage.constants.CardType;
+import mage.constants.SagaChapter;
+import mage.constants.SubType;
+import mage.filter.StaticFilters;
+
+import java.util.UUID;
+
+/**
+ * @author TheElk801
+ */
+public final class TheLongReachOfNight extends CardImpl {
+
+ public TheLongReachOfNight(UUID ownerId, CardSetInfo setInfo) {
+ super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{3}{B}");
+
+ this.subtype.add(SubType.SAGA);
+ this.secondSideCardClazz = mage.cards.a.AnimusOfNightsReach.class;
+
+ // (As this Saga enters and after your draw step, add a lore counter.)
+ SagaAbility sagaAbility = new SagaAbility(this);
+
+ // I, II — Each opponent sacrifices a creature unless they discard a card.
+ sagaAbility.addChapterEffect(
+ this, SagaChapter.CHAPTER_I, SagaChapter.CHAPTER_II,
+ new SacrificeOpponentsUnlessPayEffect(
+ new DiscardCardCost(), StaticFilters.FILTER_CONTROLLED_CREATURE_SHORT_TEXT
+ )
+ );
+
+ // III — Exile this Saga, then return it to the battlefield transformed under your control.
+ this.addAbility(new TransformAbility());
+ sagaAbility.addChapterEffect(
+ this, SagaChapter.CHAPTER_III, new ExileSagaAndReturnTransformedEffect()
+ );
+
+ this.addAbility(sagaAbility);
+ }
+
+ private TheLongReachOfNight(final TheLongReachOfNight card) {
+ super(card);
+ }
+
+ @Override
+ public TheLongReachOfNight copy() {
+ return new TheLongReachOfNight(this);
+ }
+}
diff --git a/Mage.Sets/src/mage/sets/KamigawaNeonDynasty.java b/Mage.Sets/src/mage/sets/KamigawaNeonDynasty.java
index 3e376da9fef..1648b66cc85 100644
--- a/Mage.Sets/src/mage/sets/KamigawaNeonDynasty.java
+++ b/Mage.Sets/src/mage/sets/KamigawaNeonDynasty.java
@@ -31,6 +31,7 @@ public final class KamigawaNeonDynasty extends ExpansionSet {
cards.add(new SetCardInfo("Akki War Paint", 132, Rarity.COMMON, mage.cards.a.AkkiWarPaint.class));
cards.add(new SetCardInfo("Ancestral Katana", 1, Rarity.COMMON, mage.cards.a.AncestralKatana.class));
cards.add(new SetCardInfo("Anchor to Reality", 45, Rarity.UNCOMMON, mage.cards.a.AnchorToReality.class));
+ cards.add(new SetCardInfo("Animus of Night's Reach", 109, Rarity.UNCOMMON, mage.cards.a.AnimusOfNightsReach.class));
cards.add(new SetCardInfo("Ao, the Dawn Sky", 2, Rarity.MYTHIC, mage.cards.a.AoTheDawnSky.class));
cards.add(new SetCardInfo("Architect of Restoration", 34, Rarity.RARE, mage.cards.a.ArchitectOfRestoration.class));
cards.add(new SetCardInfo("Armguard Familiar", 46, Rarity.COMMON, mage.cards.a.ArmguardFamiliar.class));
@@ -159,6 +160,7 @@ public final class KamigawaNeonDynasty extends ExpansionSet {
cards.add(new SetCardInfo("Teachings of the Kirin", 212, Rarity.RARE, mage.cards.t.TeachingsOfTheKirin.class));
cards.add(new SetCardInfo("Tempered in Solitude", 165, Rarity.UNCOMMON, mage.cards.t.TemperedInSolitude.class));
cards.add(new SetCardInfo("The Fall of Lord Konda", 12, Rarity.UNCOMMON, mage.cards.t.TheFallOfLordKonda.class));
+ cards.add(new SetCardInfo("The Long Reach of Night", 109, Rarity.UNCOMMON, mage.cards.t.TheLongReachOfNight.class));
cards.add(new SetCardInfo("The Modern Age", 66, Rarity.COMMON, mage.cards.t.TheModernAge.class));
cards.add(new SetCardInfo("The Restoration of Eiganjo", 34, Rarity.RARE, mage.cards.t.TheRestorationOfEiganjo.class));
cards.add(new SetCardInfo("The Shattered States Era", 162, Rarity.COMMON, mage.cards.t.TheShatteredStatesEra.class));
diff --git a/Mage/src/main/java/mage/abilities/dynamicvalue/common/CardsInAllGraveyardsCount.java b/Mage/src/main/java/mage/abilities/dynamicvalue/common/CardsInAllGraveyardsCount.java
index 4976affce1a..e54b7b16bfc 100644
--- a/Mage/src/main/java/mage/abilities/dynamicvalue/common/CardsInAllGraveyardsCount.java
+++ b/Mage/src/main/java/mage/abilities/dynamicvalue/common/CardsInAllGraveyardsCount.java
@@ -8,7 +8,7 @@ import mage.filter.StaticFilters;
import mage.game.Game;
import mage.players.Player;
-import java.util.UUID;
+import java.util.Objects;
/**
* @author North
@@ -25,23 +25,22 @@ public class CardsInAllGraveyardsCount implements DynamicValue {
this.filter = filter;
}
- public CardsInAllGraveyardsCount(final CardsInAllGraveyardsCount dynamicValue) {
+ private CardsInAllGraveyardsCount(final CardsInAllGraveyardsCount dynamicValue) {
this.filter = dynamicValue.filter.copy();
}
@Override
public int calculate(Game game, Ability sourceAbility, Effect effect) {
- int amount = 0;
- Player controller = game.getPlayer(sourceAbility.getControllerId());
- if (controller != null) {
- for (UUID playerUUID : game.getState().getPlayersInRange(controller.getId(), game)) {
- Player player = game.getPlayer(playerUUID);
- if (player != null) {
- amount += player.getGraveyard().count(filter, sourceAbility.getSourceId(), sourceAbility.getControllerId(), game);
- }
- }
- }
- return amount;
+ return game.getState()
+ .getPlayersInRange(sourceAbility.getControllerId(), game)
+ .stream()
+ .map(game::getPlayer)
+ .filter(Objects::nonNull)
+ .map(Player::getGraveyard)
+ .mapToInt(graveyard -> graveyard.count(
+ filter, sourceAbility.getSourceId(),
+ sourceAbility.getControllerId(), game
+ )).sum();
}
@Override