From 51afccfa73acd3e4eace7e0c400305c4d35bc8c9 Mon Sep 17 00:00:00 2001 From: Evan Kranzler Date: Fri, 22 Apr 2022 09:36:43 -0400 Subject: [PATCH] [SNC] Implemented Arcane Bombardment --- .../src/mage/cards/a/ArcaneBombardment.java | 158 ++++++++++++++++++ .../src/mage/sets/StreetsOfNewCapenna.java | 1 + 2 files changed, 159 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/a/ArcaneBombardment.java diff --git a/Mage.Sets/src/mage/cards/a/ArcaneBombardment.java b/Mage.Sets/src/mage/cards/a/ArcaneBombardment.java new file mode 100644 index 00000000000..b20f51a8923 --- /dev/null +++ b/Mage.Sets/src/mage/cards/a/ArcaneBombardment.java @@ -0,0 +1,158 @@ +package mage.cards.a; + +import mage.ApprovingObject; +import mage.abilities.Ability; +import mage.abilities.common.SpellCastControllerTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.cards.*; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.WatcherScope; +import mage.constants.Zone; +import mage.filter.FilterSpell; +import mage.filter.StaticFilters; +import mage.filter.common.FilterInstantOrSorcerySpell; +import mage.game.ExileZone; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.stack.Spell; +import mage.game.stack.StackObject; +import mage.players.Player; +import mage.util.CardUtil; +import mage.util.RandomUtil; +import mage.watchers.Watcher; +import org.apache.log4j.Logger; + +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ArcaneBombardment extends CardImpl { + + private static final FilterSpell filter + = new FilterInstantOrSorcerySpell("your first instant or sorcery spell each turn"); + + static { + filter.add(ArcaneBombardmentWatcher::checkSpell); + } + + public ArcaneBombardment(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{4}{R}{R}"); + + // Whenever you cast your first instant or sorcery spell each turn, exile an instant or sorcery card at random from your graveyard. Then copy each card exiled with Arcane Bombardment. You may cast any number of the copies without paying their mana costs. + this.addAbility(new SpellCastControllerTriggeredAbility( + new ArcaneBombardmentEffect(), filter, false + ), new ArcaneBombardmentWatcher()); + } + + private ArcaneBombardment(final ArcaneBombardment card) { + super(card); + } + + @Override + public ArcaneBombardment copy() { + return new ArcaneBombardment(this); + } +} + +class ArcaneBombardmentEffect extends OneShotEffect { + + ArcaneBombardmentEffect() { + super(Outcome.Benefit); + staticText = "exile an instant or sorcery card at random from your graveyard. Then copy each " + + "card exiled with {this}. You may cast any number of the copies without paying their mana costs"; + } + + private ArcaneBombardmentEffect(final ArcaneBombardmentEffect effect) { + super(effect); + } + + @Override + public ArcaneBombardmentEffect copy() { + return new ArcaneBombardmentEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; + } + UUID exileId = CardUtil.getExileZoneId(game, source); + Card toExile = RandomUtil.randomFromCollection( + player.getGraveyard().getCards(StaticFilters.FILTER_CARD_INSTANT_OR_SORCERY, game) + ); + if (toExile != null) { + player.moveCardsToExile( + toExile, source, game, true, + exileId, CardUtil.getSourceName(game, source) + ); + } + ExileZone exileZone = game.getExile().getExileZone(exileId); + if (exileZone == null || exileZone.isEmpty()) { + return false; + } + + Cards copies = new CardsImpl(); + for (Card card : exileZone.getCards(game)) { + Card copiedCard = game.copyCard(card, source, source.getControllerId()); + game.getExile().add(source.getSourceId(), "", copiedCard); + game.getState().setZone(copiedCard.getId(), Zone.EXILED); + copies.add(copiedCard); + } + for (Card copiedCard : copies.getCards(game)) { + if (!player.chooseUse(outcome, "Cast the copied card?", source, game)) { + continue; + } + if (copiedCard.getSpellAbility() != null) { + game.getState().setValue("PlayFromNotOwnHandZone" + copiedCard.getId(), Boolean.TRUE); + player.cast( + player.chooseAbilityForCast(copiedCard, game, true), + game, true, new ApprovingObject(source, game) + ); + game.getState().setValue("PlayFromNotOwnHandZone" + copiedCard.getId(), null); + } else { + Logger.getLogger(ArcaneBombardmentEffect.class).error("Arcane Bombardment: " + + "spell ability == null " + copiedCard.getName()); + } + } + return true; + } +} + +class ArcaneBombardmentWatcher extends Watcher { + + private final Map playerMap = new HashMap<>(); + + ArcaneBombardmentWatcher() { + super(WatcherScope.GAME); + } + + @Override + public void watch(GameEvent event, Game game) { + if (event.getType() != GameEvent.EventType.SPELL_CAST) { + return; + } + Spell spell = game.getSpell(event.getTargetId()); + if (spell != null && spell.isInstantOrSorcery(game)) { + playerMap.compute(spell.getControllerId(), CardUtil::setOrIncrementValue); + } + } + + @Override + public void reset() { + super.reset(); + playerMap.clear(); + } + + static boolean checkSpell(StackObject input, Game game) { + return game + .getState() + .getWatcher(ArcaneBombardmentWatcher.class) + .playerMap + .getOrDefault(input.getControllerId(), 0) < 2; + } +} diff --git a/Mage.Sets/src/mage/sets/StreetsOfNewCapenna.java b/Mage.Sets/src/mage/sets/StreetsOfNewCapenna.java index 42e728cc529..fb032a5ccd4 100644 --- a/Mage.Sets/src/mage/sets/StreetsOfNewCapenna.java +++ b/Mage.Sets/src/mage/sets/StreetsOfNewCapenna.java @@ -33,6 +33,7 @@ public final class StreetsOfNewCapenna extends ExpansionSet { cards.add(new SetCardInfo("Angelic Observer", 1, Rarity.UNCOMMON, mage.cards.a.AngelicObserver.class)); cards.add(new SetCardInfo("Antagonize", 100, Rarity.COMMON, mage.cards.a.Antagonize.class)); cards.add(new SetCardInfo("Arc Spitter", 233, Rarity.UNCOMMON, mage.cards.a.ArcSpitter.class)); + cards.add(new SetCardInfo("Arcane Bombardment", 101, Rarity.MYTHIC, mage.cards.a.ArcaneBombardment.class)); cards.add(new SetCardInfo("Attended Socialite", 133, Rarity.COMMON, mage.cards.a.AttendedSocialite.class)); cards.add(new SetCardInfo("Aven Heartstabber", 166, Rarity.RARE, mage.cards.a.AvenHeartstabber.class)); cards.add(new SetCardInfo("Backstreet Bruiser", 35, Rarity.COMMON, mage.cards.b.BackstreetBruiser.class));