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