From ee03e4e862748a7c3d5b005165672e40fdeeb660 Mon Sep 17 00:00:00 2001 From: Evan Kranzler Date: Thu, 29 Oct 2020 08:12:12 -0400 Subject: [PATCH] [CMR] Implemented Averna, the Chaos Bloom --- .../src/mage/cards/a/AvernaTheChaosBloom.java | 74 +++++++++++++++++++ Mage.Sets/src/mage/sets/CommanderLegends.java | 1 + .../abilities/keyword/CascadeAbility.java | 62 ++++++++++------ .../main/java/mage/game/events/GameEvent.java | 1 + 4 files changed, 114 insertions(+), 24 deletions(-) create mode 100644 Mage.Sets/src/mage/cards/a/AvernaTheChaosBloom.java diff --git a/Mage.Sets/src/mage/cards/a/AvernaTheChaosBloom.java b/Mage.Sets/src/mage/cards/a/AvernaTheChaosBloom.java new file mode 100644 index 00000000000..c6b21b3b701 --- /dev/null +++ b/Mage.Sets/src/mage/cards/a/AvernaTheChaosBloom.java @@ -0,0 +1,74 @@ +package mage.cards.a; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.ReplacementEffectImpl; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.game.Game; +import mage.game.events.GameEvent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class AvernaTheChaosBloom extends CardImpl { + + public AvernaTheChaosBloom(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{G}{U}{R}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.ELEMENTAL); + this.subtype.add(SubType.SHAMAN); + this.power = new MageInt(4); + this.toughness = new MageInt(2); + + // As you cascade, you may put a land card from among the exiled cards onto the battlefield tapped. + this.addAbility(new SimpleStaticAbility(new AvernaTheChaosBloomReplacementEffect())); + } + + private AvernaTheChaosBloom(final AvernaTheChaosBloom card) { + super(card); + } + + @Override + public AvernaTheChaosBloom copy() { + return new AvernaTheChaosBloom(this); + } +} + +class AvernaTheChaosBloomReplacementEffect extends ReplacementEffectImpl { + + AvernaTheChaosBloomReplacementEffect() { + super(Duration.WhileOnBattlefield, Outcome.Benefit); + staticText = "As you cascade, you may put a land card from among the exiled cards onto the battlefield tapped."; + } + + private AvernaTheChaosBloomReplacementEffect(final AvernaTheChaosBloomReplacementEffect effect) { + super(effect); + } + + @Override + public AvernaTheChaosBloomReplacementEffect copy() { + return new AvernaTheChaosBloomReplacementEffect(this); + } + + @Override + public boolean checksEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.CASCADE_LAND; + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + return event.getPlayerId().equals(source.getControllerId()); + } + + @Override + public boolean replaceEvent(GameEvent event, Ability source, Game game) { + event.setAmount(event.getAmount() + 1); + return false; + } +} diff --git a/Mage.Sets/src/mage/sets/CommanderLegends.java b/Mage.Sets/src/mage/sets/CommanderLegends.java index 97b2be1391f..a2952a8692b 100644 --- a/Mage.Sets/src/mage/sets/CommanderLegends.java +++ b/Mage.Sets/src/mage/sets/CommanderLegends.java @@ -30,6 +30,7 @@ public final class CommanderLegends extends ExpansionSet { cards.add(new SetCardInfo("Acidic Slime", 421, Rarity.UNCOMMON, mage.cards.a.AcidicSlime.class)); cards.add(new SetCardInfo("Alena, Kessig Trapper", 160, Rarity.UNCOMMON, mage.cards.a.AlenaKessigTrapper.class)); cards.add(new SetCardInfo("Amareth, the Lustrous", 266, Rarity.RARE, mage.cards.a.AmarethTheLustrous.class)); + cards.add(new SetCardInfo("Averna, the Chaos Bloom", 269, Rarity.RARE, mage.cards.a.AvernaTheChaosBloom.class)); cards.add(new SetCardInfo("Bladegriff Prototype", 300, Rarity.RARE, mage.cards.b.BladegriffPrototype.class)); cards.add(new SetCardInfo("Brazen Freebooter", 164, Rarity.COMMON, mage.cards.b.BrazenFreebooter.class)); cards.add(new SetCardInfo("Briarblade Adept", 111, Rarity.COMMON, mage.cards.b.BriarbladeAdept.class)); diff --git a/Mage/src/main/java/mage/abilities/keyword/CascadeAbility.java b/Mage/src/main/java/mage/abilities/keyword/CascadeAbility.java index 410b7629792..2bcc5c8af85 100644 --- a/Mage/src/main/java/mage/abilities/keyword/CascadeAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/CascadeAbility.java @@ -5,14 +5,18 @@ import mage.abilities.Ability; import mage.abilities.TriggeredAbilityImpl; import mage.abilities.effects.OneShotEffect; import mage.cards.Card; +import mage.cards.Cards; import mage.cards.CardsImpl; import mage.constants.Outcome; import mage.constants.Zone; -import mage.game.ExileZone; +import mage.filter.FilterCard; +import mage.filter.StaticFilters; +import mage.filter.common.FilterLandCard; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.stack.Spell; import mage.players.Player; +import mage.target.common.TargetCardInExile; /** * @author BetaSteward_at_googlemail.com @@ -25,7 +29,8 @@ public class CascadeAbility extends TriggeredAbilityImpl { + "nonland card that costs less." + " You may cast it without paying its mana cost. " + "Put the exiled cards on the bottom in a random order.)"; - private boolean withReminder; + private final boolean withReminder; + private static final FilterCard filter = new FilterLandCard("land card (to put onto the battlefield)"); public CascadeAbility() { this(true); @@ -36,7 +41,7 @@ public class CascadeAbility extends TriggeredAbilityImpl { this.withReminder = withReminder; } - public CascadeAbility(final CascadeAbility ability) { + private CascadeAbility(final CascadeAbility ability) { super(ability); this.withReminder = ability.withReminder; } @@ -71,11 +76,11 @@ public class CascadeAbility extends TriggeredAbilityImpl { class CascadeEffect extends OneShotEffect { - public CascadeEffect() { + CascadeEffect() { super(Outcome.PutCardInPlay); } - public CascadeEffect(CascadeEffect effect) { + private CascadeEffect(CascadeEffect effect) { super(effect); } @@ -86,8 +91,7 @@ class CascadeEffect extends OneShotEffect { if (controller == null) { return false; } - ExileZone exile = game.getExile().createZone(source.getSourceId(), - controller.getName() + " Cascade"); + Cards cards = new CardsImpl(); card = game.getCard(source.getSourceId()); if (card == null) { return false; @@ -98,33 +102,43 @@ class CascadeEffect extends OneShotEffect { if (card == null) { break; } - controller.moveCardsToExile(card, source, game, true, exile.getId(), exile.getName()); + cards.add(card); + controller.moveCards(card, Zone.EXILED, source, game); } while (controller.canRespond() - && (card.isLand() - || !cardThatCostsLess(sourceCost, card, game))); + && (card.isLand() || card.getConvertedManaCost() >= sourceCost)); controller.getLibrary().reset(); // set back empty draw state if that caused an empty draw - if (card != null) { - if (controller.chooseUse(outcome, "Use cascade effect on " + card.getLogName() + '?', source, game)) { - game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), Boolean.TRUE); - controller.cast(controller.chooseAbilityForCast(card, game, true), - game, true, new ApprovingObject(source, game)); - game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), null); - } + GameEvent event = GameEvent.getEvent( + GameEvent.EventType.CASCADE_LAND, source.getSourceId(), + source.getSourceId(), source.getControllerId(), 0 + ); + game.replaceEvent(event); + if (event.getAmount() > 0) { + TargetCardInExile target = new TargetCardInExile( + 0, event.getAmount(), StaticFilters.FILTER_CARD_LAND, null, true + ); + controller.choose(Outcome.PutCardInPlay, cards, target, game); + controller.moveCards( + new CardsImpl(target.getTargets()).getCards(game), Zone.BATTLEFIELD, + source, game, true, false, false, null + ); + } + if (card != null && controller.chooseUse( + outcome, "Use cascade effect on " + card.getLogName() + '?', source, game + )) { + game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), Boolean.TRUE); + controller.cast(controller.chooseAbilityForCast(card, game, true), + game, true, new ApprovingObject(source, game)); + game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), null); } // Move the remaining cards to the buttom of the library in a random order - return controller.putCardsOnBottomOfLibrary(new CardsImpl(exile), game, source, false); + cards.removeIf(uuid -> game.getState().getZone(uuid) != Zone.EXILED); + return controller.putCardsOnBottomOfLibrary(cards, game, source, false); } @Override public CascadeEffect copy() { return new CascadeEffect(this); } - - private boolean cardThatCostsLess(int value, Card card, Game game) { - - return card.getConvertedManaCost() < value; - - } } diff --git a/Mage/src/main/java/mage/game/events/GameEvent.java b/Mage/src/main/java/mage/game/events/GameEvent.java index 188696f9adc..642f2996861 100644 --- a/Mage/src/main/java/mage/game/events/GameEvent.java +++ b/Mage/src/main/java/mage/game/events/GameEvent.java @@ -256,6 +256,7 @@ public class GameEvent implements Serializable { PAID_CUMULATIVE_UPKEEP, DIDNT_PAY_CUMULATIVE_UPKEEP, LIFE_PAID, + CASCADE_LAND, //permanent events ENTERS_THE_BATTLEFIELD_SELF, /* 616.1a If any of the replacement and/or prevention effects are self-replacement effects (see rule 614.15), one of them must be chosen. If not, proceed to rule 616.1b. */