From be7e936fc133ed2204358b66e6966e3ac59bd3a4 Mon Sep 17 00:00:00 2001 From: Evan Kranzler Date: Sat, 5 Feb 2022 16:43:45 -0500 Subject: [PATCH] [NEO] Implemented Inventive Iteration / Living Breakthrough --- .../src/mage/cards/i/InventiveIteration.java | 104 +++++++++++++++++ .../src/mage/cards/l/LivingBreakthrough.java | 107 ++++++++++++++++++ .../src/mage/sets/KamigawaNeonDynasty.java | 2 + .../SpellCastControllerTriggeredAbility.java | 2 +- 4 files changed, 214 insertions(+), 1 deletion(-) create mode 100644 Mage.Sets/src/mage/cards/i/InventiveIteration.java create mode 100644 Mage.Sets/src/mage/cards/l/LivingBreakthrough.java diff --git a/Mage.Sets/src/mage/cards/i/InventiveIteration.java b/Mage.Sets/src/mage/cards/i/InventiveIteration.java new file mode 100644 index 0000000000..dcbcf504cd --- /dev/null +++ b/Mage.Sets/src/mage/cards/i/InventiveIteration.java @@ -0,0 +1,104 @@ +package mage.cards.i; + +import mage.abilities.Ability; +import mage.abilities.common.SagaAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.ExileSagaAndReturnTransformedEffect; +import mage.abilities.effects.common.ReturnToHandTargetEffect; +import mage.abilities.keyword.TransformAbility; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.players.Player; +import mage.target.TargetCard; +import mage.target.common.TargetCardInYourGraveyard; +import mage.target.common.TargetCreatureOrPlaneswalker; +import mage.util.RandomUtil; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class InventiveIteration extends CardImpl { + + public InventiveIteration(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{3}{U}"); + + this.subtype.add(SubType.SAGA); + this.secondSideCardClazz = mage.cards.l.LivingBreakthrough.class; + + // (As this Saga enters and after your draw step, add a lore counter.) + SagaAbility sagaAbility = new SagaAbility(this); + + // I — Return up to one target creature or planeswalker to its owner's hand. + sagaAbility.addChapterEffect( + this, SagaChapter.CHAPTER_I, SagaChapter.CHAPTER_I, + new ReturnToHandTargetEffect(), new TargetCreatureOrPlaneswalker(0, 1) + ); + + // II — Return an artifact card from your graveyard to your hand. If you can't, draw a card. + sagaAbility.addChapterEffect(this, SagaChapter.CHAPTER_II, new InventiveIterationEffect()); + + // 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 InventiveIteration(final InventiveIteration card) { + super(card); + } + + @Override + public InventiveIteration copy() { + return new InventiveIteration(this); + } +} + +class InventiveIterationEffect extends OneShotEffect { + + InventiveIterationEffect() { + super(Outcome.Benefit); + staticText = "return an artifact card from your graveyard to your hand. If you can't, draw a card"; + } + + private InventiveIterationEffect(final InventiveIterationEffect effect) { + super(effect); + } + + @Override + public InventiveIterationEffect copy() { + return new InventiveIterationEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; + } + Card card; + switch (player.getGraveyard().count(StaticFilters.FILTER_CARD_ARTIFACT, game)) { + case 0: + player.drawCards(1, source, game); + return true; + case 1: + card = RandomUtil.randomFromCollection( + player.getGraveyard().getCards(StaticFilters.FILTER_CARD_ARTIFACT, game) + ); + break; + default: + TargetCard target = new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_ARTIFACT); + target.setNotTarget(true); + player.choose(outcome, player.getGraveyard(), target, game); + card = game.getCard(target.getFirstTarget()); + } + player.moveCards(card, Zone.HAND, source, game); + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/l/LivingBreakthrough.java b/Mage.Sets/src/mage/cards/l/LivingBreakthrough.java new file mode 100644 index 0000000000..ada98c582e --- /dev/null +++ b/Mage.Sets/src/mage/cards/l/LivingBreakthrough.java @@ -0,0 +1,107 @@ +package mage.cards.l; + +import mage.MageInt; +import mage.MageObject; +import mage.abilities.Ability; +import mage.abilities.common.SpellCastControllerTriggeredAbility; +import mage.abilities.effects.ContinuousRuleModifyingEffectImpl; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.stack.Spell; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class LivingBreakthrough extends CardImpl { + + public LivingBreakthrough(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT, CardType.CREATURE}, ""); + + this.subtype.add(SubType.MOONFOLK); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + this.color.setBlue(true); + this.nightCard = true; + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // Whenever you cast a spell, your opponents can't cast spells with the same mana value as that spell until your next turn. + this.addAbility(new SpellCastControllerTriggeredAbility(new LivingBreakthroughEffect(), false)); + } + + private LivingBreakthrough(final LivingBreakthrough card) { + super(card); + } + + @Override + public LivingBreakthrough copy() { + return new LivingBreakthrough(this); + } +} + +class LivingBreakthroughEffect extends ContinuousRuleModifyingEffectImpl { + + private int manaValue = -1; + + LivingBreakthroughEffect() { + super(Duration.UntilYourNextTurn, Outcome.Benefit); + staticText = "your opponents can't cast spells with the same mana value as that spell until your next turn"; + } + + private LivingBreakthroughEffect(final LivingBreakthroughEffect effect) { + super(effect); + } + + @Override + public LivingBreakthroughEffect copy() { + return new LivingBreakthroughEffect(this); + } + + @Override + public void init(Ability source, Game game) { + super.init(source, game); + Spell spell = (Spell) getValue("spellCast"); + if (spell != null) { + this.manaValue = spell.getManaValue(); + } + } + + @Override + public String getInfoMessage(Ability source, GameEvent event, Game game) { + MageObject mageObject = game.getObject(source.getSourceId()); + if (mageObject != null) { + return "You can't cast spells with mana value " + manaValue + + " this turn (" + mageObject.getIdName() + ")."; + } + return null; + } + + @Override + public boolean checksEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.CAST_SPELL_LATE; + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + if (!game.getOpponents(source.getControllerId()).contains(event.getPlayerId())) { + return false; + } + Spell spell = game.getStack().getSpell(event.getTargetId()); + return spell != null && spell.getManaValue() == this.manaValue; + } + + @Override + public boolean apply(Game game, Ability source) { + return true; + } +} diff --git a/Mage.Sets/src/mage/sets/KamigawaNeonDynasty.java b/Mage.Sets/src/mage/sets/KamigawaNeonDynasty.java index d3af523a07..09219c65d2 100644 --- a/Mage.Sets/src/mage/sets/KamigawaNeonDynasty.java +++ b/Mage.Sets/src/mage/sets/KamigawaNeonDynasty.java @@ -122,6 +122,7 @@ public final class KamigawaNeonDynasty extends ExpansionSet { cards.add(new SetCardInfo("Imperial Recovery Unit", 18, Rarity.UNCOMMON, mage.cards.i.ImperialRecoveryUnit.class)); cards.add(new SetCardInfo("Imperial Subduer", 19, Rarity.COMMON, mage.cards.i.ImperialSubduer.class)); cards.add(new SetCardInfo("Inkrise Infiltrator", 100, Rarity.COMMON, mage.cards.i.InkriseInfiltrator.class)); + cards.add(new SetCardInfo("Inventive Iteration", 57, Rarity.RARE, mage.cards.i.InventiveIteration.class)); cards.add(new SetCardInfo("Invoke the Ancients", 193, Rarity.RARE, mage.cards.i.InvokeTheAncients.class)); cards.add(new SetCardInfo("Invoke the Winds", 58, Rarity.RARE, mage.cards.i.InvokeTheWinds.class)); cards.add(new SetCardInfo("Ironhoof Boar", 148, Rarity.COMMON, mage.cards.i.IronhoofBoar.class)); @@ -147,6 +148,7 @@ public final class KamigawaNeonDynasty extends ExpansionSet { cards.add(new SetCardInfo("Light the Way", 24, Rarity.COMMON, mage.cards.l.LightTheWay.class)); cards.add(new SetCardInfo("Likeness of the Seeker", 172, Rarity.UNCOMMON, mage.cards.l.LikenessOfTheSeeker.class)); cards.add(new SetCardInfo("Lion Sash", 26, Rarity.RARE, mage.cards.l.LionSash.class)); + cards.add(new SetCardInfo("Living Breakthrough", 57, Rarity.RARE, mage.cards.l.LivingBreakthrough.class)); cards.add(new SetCardInfo("Lizard Blades", 153, Rarity.RARE, mage.cards.l.LizardBlades.class)); cards.add(new SetCardInfo("Lucky Offering", 27, Rarity.COMMON, mage.cards.l.LuckyOffering.class)); cards.add(new SetCardInfo("Malicious Malfunction", 110, Rarity.UNCOMMON, mage.cards.m.MaliciousMalfunction.class)); diff --git a/Mage/src/main/java/mage/abilities/common/SpellCastControllerTriggeredAbility.java b/Mage/src/main/java/mage/abilities/common/SpellCastControllerTriggeredAbility.java index 911ead8e71..775efe507a 100644 --- a/Mage/src/main/java/mage/abilities/common/SpellCastControllerTriggeredAbility.java +++ b/Mage/src/main/java/mage/abilities/common/SpellCastControllerTriggeredAbility.java @@ -69,8 +69,8 @@ public class SpellCastControllerTriggeredAbility extends TriggeredAbilityImpl { if (event.getPlayerId().equals(this.getControllerId())) { Spell spell = game.getStack().getSpell(event.getTargetId()); if (filter.match(spell, getSourceId(), getControllerId(), game)) { + this.getEffects().setValue("spellCast", spell); if (rememberSource) { - this.getEffects().setValue("spellCast", spell); if (rememberSourceAsCard) { this.getEffects().setTargetPointer(new FixedTarget(spell.getCard().getId(), game)); } else {