From ba05bc13c4635d8a349cca3b425580d427108eb5 Mon Sep 17 00:00:00 2001 From: Evan Kranzler Date: Wed, 2 Feb 2022 19:41:47 -0500 Subject: [PATCH] [NEO] Implemented Behold the Unspeakable / Vision of the Unspeakable --- .../mage/cards/b/BeholdTheUnspeakable.java | 63 +++++++++++++++++++ .../mage/cards/v/VisionOfTheUnspeakable.java | 53 ++++++++++++++++ .../src/mage/sets/KamigawaNeonDynasty.java | 2 + .../decorator/ConditionalOneShotEffect.java | 54 +++++++++------- .../main/java/mage/filter/StaticFilters.java | 7 +++ 5 files changed, 157 insertions(+), 22 deletions(-) create mode 100644 Mage.Sets/src/mage/cards/b/BeholdTheUnspeakable.java create mode 100644 Mage.Sets/src/mage/cards/v/VisionOfTheUnspeakable.java diff --git a/Mage.Sets/src/mage/cards/b/BeholdTheUnspeakable.java b/Mage.Sets/src/mage/cards/b/BeholdTheUnspeakable.java new file mode 100644 index 00000000000..c42d0c20e54 --- /dev/null +++ b/Mage.Sets/src/mage/cards/b/BeholdTheUnspeakable.java @@ -0,0 +1,63 @@ +package mage.cards.b; + +import mage.abilities.common.SagaAbility; +import mage.abilities.condition.common.HeckbentCondition; +import mage.abilities.decorator.ConditionalOneShotEffect; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.ExileSagaAndReturnTransformedEffect; +import mage.abilities.effects.common.continuous.BoostAllEffect; +import mage.abilities.effects.keyword.ScryEffect; +import mage.abilities.keyword.TransformAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SagaChapter; +import mage.constants.SubType; +import mage.filter.StaticFilters; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class BeholdTheUnspeakable extends CardImpl { + + public BeholdTheUnspeakable(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{3}{U}{U}"); + + this.subtype.add(SubType.SAGA); + this.secondSideCardClazz = mage.cards.v.VisionOfTheUnspeakable.class; + + // (As this Saga enters and after your draw step, add a lore counter.) + SagaAbility sagaAbility = new SagaAbility(this); + + // I — Creatures you don't control get -2/-0 until your next turn. + sagaAbility.addChapterEffect(this, SagaChapter.CHAPTER_I, new BoostAllEffect( + -2, 0, Duration.UntilYourNextTurn, + StaticFilters.FILTER_CREATURES_YOU_DONT_CONTROL, false + )); + + // II — If you have one or fewer cards in hand, draw four cards. Otherwise, scry 2, then draw two cards. + sagaAbility.addChapterEffect(this, SagaChapter.CHAPTER_II, new ConditionalOneShotEffect( + new DrawCardSourceControllerEffect(4), new ScryEffect(2), + HeckbentCondition.instance, "if you have one or fewer cards in hand, " + + "draw four cards. Otherwise, scry 2, then draw two cards" + ).addOtherwiseEffect(new DrawCardSourceControllerEffect(2))); + + // 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 BeholdTheUnspeakable(final BeholdTheUnspeakable card) { + super(card); + } + + @Override + public BeholdTheUnspeakable copy() { + return new BeholdTheUnspeakable(this); + } +} diff --git a/Mage.Sets/src/mage/cards/v/VisionOfTheUnspeakable.java b/Mage.Sets/src/mage/cards/v/VisionOfTheUnspeakable.java new file mode 100644 index 00000000000..4d8752569c1 --- /dev/null +++ b/Mage.Sets/src/mage/cards/v/VisionOfTheUnspeakable.java @@ -0,0 +1,53 @@ +package mage.cards.v; + +import mage.MageInt; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.dynamicvalue.common.CardsInControllerHandCount; +import mage.abilities.effects.common.continuous.BoostSourceEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.abilities.keyword.TrampleAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class VisionOfTheUnspeakable extends CardImpl { + + public VisionOfTheUnspeakable(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(0); + this.color.setBlue(true); + this.nightCard = true; + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // Trample + this.addAbility(TrampleAbility.getInstance()); + + // Vision of the Unspeakable gets +1/+1 for each card in your hand. + this.addAbility(new SimpleStaticAbility(new BoostSourceEffect( + CardsInControllerHandCount.instance, + CardsInControllerHandCount.instance, + Duration.WhileOnBattlefield + ))); + } + + private VisionOfTheUnspeakable(final VisionOfTheUnspeakable card) { + super(card); + } + + @Override + public VisionOfTheUnspeakable copy() { + return new VisionOfTheUnspeakable(this); + } +} diff --git a/Mage.Sets/src/mage/sets/KamigawaNeonDynasty.java b/Mage.Sets/src/mage/sets/KamigawaNeonDynasty.java index 4efdd026421..339bc93a858 100644 --- a/Mage.Sets/src/mage/sets/KamigawaNeonDynasty.java +++ b/Mage.Sets/src/mage/sets/KamigawaNeonDynasty.java @@ -40,6 +40,7 @@ public final class KamigawaNeonDynasty extends ExpansionSet { cards.add(new SetCardInfo("Bamboo Grove Archer", 173, Rarity.COMMON, mage.cards.b.BambooGroveArcher.class)); cards.add(new SetCardInfo("Banishing Slash", 3, Rarity.UNCOMMON, mage.cards.b.BanishingSlash.class)); cards.add(new SetCardInfo("Befriending the Moths", 4, Rarity.COMMON, mage.cards.b.BefriendingTheMoths.class)); + cards.add(new SetCardInfo("Behold the Unspeakable", 48, Rarity.UNCOMMON, mage.cards.b.BeholdTheUnspeakable.class)); cards.add(new SetCardInfo("Biting-Palm Ninja", 88, Rarity.RARE, mage.cards.b.BitingPalmNinja.class)); cards.add(new SetCardInfo("Boseiju Reaches Skyward", 177, Rarity.UNCOMMON, mage.cards.b.BoseijuReachesSkyward.class)); cards.add(new SetCardInfo("Branch of Boseiju", 177, Rarity.UNCOMMON, mage.cards.b.BranchOfBoseiju.class)); @@ -128,6 +129,7 @@ public final class KamigawaNeonDynasty extends ExpansionSet { cards.add(new SetCardInfo("Unstoppable Ogre", 169, Rarity.COMMON, mage.cards.u.UnstoppableOgre.class)); cards.add(new SetCardInfo("Upriser Renegade", 170, Rarity.UNCOMMON, mage.cards.u.UpriserRenegade.class)); cards.add(new SetCardInfo("Vector Glider", 66, Rarity.COMMON, mage.cards.v.VectorGlider.class)); + cards.add(new SetCardInfo("Vision of the Unspeakable", 48, Rarity.UNCOMMON, mage.cards.v.VisionOfTheUnspeakable.class)); cards.add(new SetCardInfo("You Are Already Dead", 129, Rarity.COMMON, mage.cards.y.YouAreAlreadyDead.class)); cards.removeIf(setCardInfo -> unfinished.contains(setCardInfo.getName())); // remove when mechanic is fully implemented diff --git a/Mage/src/main/java/mage/abilities/decorator/ConditionalOneShotEffect.java b/Mage/src/main/java/mage/abilities/decorator/ConditionalOneShotEffect.java index 3dd4de8e89d..1bad5b3e2e8 100644 --- a/Mage/src/main/java/mage/abilities/decorator/ConditionalOneShotEffect.java +++ b/Mage/src/main/java/mage/abilities/decorator/ConditionalOneShotEffect.java @@ -1,10 +1,9 @@ - - package mage.abilities.decorator; import mage.abilities.Ability; import mage.abilities.Mode; import mage.abilities.condition.Condition; +import mage.abilities.effects.Effects; import mage.abilities.effects.OneShotEffect; import mage.game.Game; @@ -15,9 +14,9 @@ import mage.game.Game; */ public class ConditionalOneShotEffect extends OneShotEffect { - private OneShotEffect effect; - private OneShotEffect otherwiseEffect; - private Condition condition; + private final Effects effects = new Effects(); + private final Effects otherwiseEffects = new Effects(); + private final Condition condition; public ConditionalOneShotEffect(OneShotEffect effect, Condition condition) { this(effect, null, condition, null); @@ -29,31 +28,43 @@ public class ConditionalOneShotEffect extends OneShotEffect { public ConditionalOneShotEffect(OneShotEffect effect, OneShotEffect otherwiseEffect, Condition condition, String text) { super(effect.getOutcome()); - this.effect = effect; - this.otherwiseEffect = otherwiseEffect; + if (effect != null) { + this.effects.add(effect); + } + if (otherwiseEffect != null) { + this.otherwiseEffects.add(otherwiseEffect); + } this.condition = condition; this.staticText = text; } public ConditionalOneShotEffect(ConditionalOneShotEffect effect) { super(effect); - this.effect = (OneShotEffect) effect.effect.copy(); - if (effect.otherwiseEffect != null) { - this.otherwiseEffect = (OneShotEffect) effect.otherwiseEffect.copy(); - } + this.effects.addAll(effect.effects.copy()); + this.otherwiseEffects.addAll(effect.otherwiseEffects.copy()); this.condition = effect.condition; } @Override public boolean apply(Game game, Ability source) { - if (condition.apply(game, source)) { - effect.setTargetPointer(this.targetPointer); - return effect.apply(game, source); - } else if (otherwiseEffect == null) { - return true; // nothing to do - no problem + // nothing to do - no problem + Effects toApply = condition.apply(game, source) ? effects : otherwiseEffects; + if (toApply.isEmpty()) { + return false; } - otherwiseEffect.setTargetPointer(this.targetPointer); - return otherwiseEffect.apply(game, source); + toApply.setTargetPointer(this.targetPointer); + toApply.stream().forEach(effect -> effect.apply(game, source)); + return true; + } + + public ConditionalOneShotEffect addEffect(OneShotEffect effect) { + this.effects.add(effect); + return this; + } + + public ConditionalOneShotEffect addOtherwiseEffect(OneShotEffect effect) { + this.effects.add(effect); + return this; } @Override @@ -66,10 +77,9 @@ public class ConditionalOneShotEffect extends OneShotEffect { if (staticText != null && !staticText.isEmpty()) { return staticText; } - if (otherwiseEffect == null) { - return "if " + condition.toString() + ", " + effect.getText(mode); + if (otherwiseEffects.isEmpty()) { + return "if " + condition.toString() + ", " + effects.getText(mode); } - return effect.getText(mode) + ". If " + condition.toString() + ", " + otherwiseEffect.getText(mode); + return effects.getText(mode) + ". If " + condition.toString() + ", " + otherwiseEffects.getText(mode); } - } diff --git a/Mage/src/main/java/mage/filter/StaticFilters.java b/Mage/src/main/java/mage/filter/StaticFilters.java index 01ecbb370ed..1134e7fa465 100644 --- a/Mage/src/main/java/mage/filter/StaticFilters.java +++ b/Mage/src/main/java/mage/filter/StaticFilters.java @@ -455,6 +455,13 @@ public final class StaticFilters { FILTER_CREATURE_YOU_DONT_CONTROL.setLockedFilter(true); } + public static final FilterCreaturePermanent FILTER_CREATURES_YOU_DONT_CONTROL = new FilterCreaturePermanent("creatures you don't control"); + + static { + FILTER_CREATURES_YOU_DONT_CONTROL.add(TargetController.NOT_YOU.getControllerPredicate()); + FILTER_CREATURES_YOU_DONT_CONTROL.setLockedFilter(true); + } + public static final FilterControlledCreaturePermanent FILTER_CONTROLLED_CREATURE = new FilterControlledCreaturePermanent(); static {