From 3e251e0ea55cae0727faab5bf31c3b7df3fd2d64 Mon Sep 17 00:00:00 2001 From: Susucre <34709007+Susucre@users.noreply.github.com> Date: Tue, 29 Aug 2023 15:41:29 +0200 Subject: [PATCH] [WOE] Implement Extraordinary Journey (#10948) --- .../mage/cards/e/ExtraordinaryJourney.java | 200 ++++++++++++++++++ Mage.Sets/src/mage/sets/WildsOfEldraine.java | 1 + 2 files changed, 201 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/e/ExtraordinaryJourney.java diff --git a/Mage.Sets/src/mage/cards/e/ExtraordinaryJourney.java b/Mage.Sets/src/mage/cards/e/ExtraordinaryJourney.java new file mode 100644 index 00000000000..83f97714ac5 --- /dev/null +++ b/Mage.Sets/src/mage/cards/e/ExtraordinaryJourney.java @@ -0,0 +1,200 @@ +package mage.cards.e; + +import mage.abilities.Ability; +import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.dynamicvalue.common.ManacostVariableValue; +import mage.abilities.effects.Effect; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.ExileTargetEffect; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.Zone; +import mage.game.ExileZone; +import mage.game.Game; +import mage.game.events.EntersTheBattlefieldEvent; +import mage.game.events.GameEvent; +import mage.game.events.ZoneChangeEvent; +import mage.game.events.ZoneChangeGroupEvent; +import mage.game.permanent.Permanent; +import mage.game.stack.Spell; +import mage.players.Player; +import mage.target.common.TargetCreaturePermanent; +import mage.target.targetadjustment.TargetAdjuster; +import mage.target.targetpointer.FixedTargets; +import mage.util.CardUtil; + +import java.util.List; +import java.util.Objects; +import java.util.Set; +import java.util.UUID; +import java.util.stream.Collectors; + +/** + * + * @author Susucr + */ +public final class ExtraordinaryJourney extends CardImpl { + + public ExtraordinaryJourney(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{X}{X}{U}{U}"); + + + // When Extraordinary Journey enters the battlefield, exile up to X target creatures. For each of those cards, its owner may play it for as long as it remains exiled. + Ability ability = new EntersBattlefieldTriggeredAbility(new ExtraordinaryJourneyEffect()); + ability.setTargetAdjuster(ExtraordinaryJourneyAdjuster.instance); + this.addAbility(ability); + + // Whenever one or more nontoken creatures enter the battlefield, if one or more of them entered from exile or was cast from exile, you draw a card. This ability triggers only once each turn. + this.addAbility(new ExtraordinaryJourneyTriggeredAbility()); + } + + private ExtraordinaryJourney(final ExtraordinaryJourney card) { + super(card); + } + + @Override + public ExtraordinaryJourney copy() { + return new ExtraordinaryJourney(this); + } +} + +enum ExtraordinaryJourneyAdjuster implements TargetAdjuster { + instance; + + @Override + public void adjustTargets(Ability ability, Game game) { + ability.getTargets().clear(); + ability.addTarget(new TargetCreaturePermanent(0, ManacostVariableValue.ETB.calculate(game, ability, null))); + } +} + +class ExtraordinaryJourneyEffect extends OneShotEffect { + + ExtraordinaryJourneyEffect() { + super(Outcome.Neutral); + this.staticText = "exile up to X target creatures. For each of those cards, " + + "its owner may play it for as long as it remains exiled"; + } + + private ExtraordinaryJourneyEffect(final ExtraordinaryJourneyEffect effect) { + super(effect); + } + + @Override + public ExtraordinaryJourneyEffect copy() { + return new ExtraordinaryJourneyEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + List permanents = source + .getTargets().get(0).getTargets() + .stream() + .map(game::getPermanent) + .filter(Objects::nonNull) + .collect(Collectors.toList()); + + // exile up to X target creatures. + Effect effect = new ExileTargetEffect().setTargetPointer(new FixedTargets(permanents, game)); + if(!effect.apply(game, source)) { + return false; + } + + Set cards = permanents + .stream() + .map(p -> p.getMainCard()) + .filter(Objects::nonNull) + .filter(card -> game.getState().getZone(card.getId()) == Zone.EXILED) + .collect(Collectors.toSet()); + + Set owners = cards + .stream() + .map(Card::getOwnerId) + .map(game::getPlayer) + .filter(Objects::nonNull) + .collect(Collectors.toSet()); + + // For each of those cards, its owner may play it for as long as it remains exiled. + for (Player owner : owners) { + String exileZoneName = "Exile — Can be played by " + owner.getName(); + UUID exileZoneId = CardUtil.getExileZoneId( + exileZoneName, + game + ); + + ExileZone zone = game.getState().getExile().createZone(exileZoneId, exileZoneName); + + for(Card card : cards) { + if (card.getOwnerId().equals(owner.getId())) { + game.getExile().moveToAnotherZone(card, game, zone); + CardUtil.makeCardPlayable( + game, source, card, Duration.Custom, + false, card.getOwnerId(), null + ); + } + } + } + + return true; + } +} + +class ExtraordinaryJourneyTriggeredAbility extends TriggeredAbilityImpl { + + ExtraordinaryJourneyTriggeredAbility() { + super(Zone.BATTLEFIELD, new DrawCardSourceControllerEffect(1), false); + setTriggerPhrase("Whenever one or more nontoken creatures enter the battlefield, " + + "if one or more of them entered from exile or was cast from exile, "); + setTriggersOnceEachTurn(true); + } + + private ExtraordinaryJourneyTriggeredAbility(final ExtraordinaryJourneyTriggeredAbility ability) { + super(ability); + } + + @Override + public ExtraordinaryJourneyTriggeredAbility copy() { + return new ExtraordinaryJourneyTriggeredAbility(this); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.ENTERS_THE_BATTLEFIELD; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + EntersTheBattlefieldEvent zEvent = (EntersTheBattlefieldEvent) event; + if(zEvent == null){ + return false; + } + + Permanent permanent = zEvent.getTarget(); + if(permanent == null || !permanent.isCreature(game)) { + return false; + } + + Zone fromZone = zEvent.getFromZone(); + if(fromZone == Zone.EXILED) { + // Directly from exile + return true; + } + + if(fromZone == Zone.STACK) { + // Get spell in the stack. + Spell spell = game.getSpellOrLKIStack(permanent.getId()); + if(spell != null && spell.getFromZone() == Zone.EXILED) { + // Creature was cast from exile + return true; + } + } + + return false; + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/sets/WildsOfEldraine.java b/Mage.Sets/src/mage/sets/WildsOfEldraine.java index 87978f9c390..b081ce15e46 100644 --- a/Mage.Sets/src/mage/sets/WildsOfEldraine.java +++ b/Mage.Sets/src/mage/sets/WildsOfEldraine.java @@ -86,6 +86,7 @@ public final class WildsOfEldraine extends ExpansionSet { cards.add(new SetCardInfo("Evolving Wilds", 256, Rarity.COMMON, mage.cards.e.EvolvingWilds.class)); cards.add(new SetCardInfo("Expel the Interlopers", 13, Rarity.RARE, mage.cards.e.ExpelTheInterlopers.class)); cards.add(new SetCardInfo("Experimental Confectioner", 314, Rarity.UNCOMMON, mage.cards.e.ExperimentalConfectioner.class)); + cards.add(new SetCardInfo("Extraordinary Journey", 48, Rarity.RARE, mage.cards.e.ExtraordinaryJourney.class)); cards.add(new SetCardInfo("Faerie Dreamthief", 89, Rarity.UNCOMMON, mage.cards.f.FaerieDreamthief.class)); cards.add(new SetCardInfo("Faerie Fencing", 90, Rarity.UNCOMMON, mage.cards.f.FaerieFencing.class)); cards.add(new SetCardInfo("Farsight Ritual", 49, Rarity.RARE, mage.cards.f.FarsightRitual.class));