From 6f5d789057a44d3e31d6cfa83033a735b2465c78 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Sun, 23 Feb 2014 12:19:59 +0100 Subject: [PATCH] * Chained to the Rocks - Fixed that target was also exiled if Chained to the Rocks was no more on the battlefield as the exile effect resolves. --- .../mage/sets/theros/ChainedToTheRocks.java | 83 +++++++++++++++---- 1 file changed, 66 insertions(+), 17 deletions(-) diff --git a/Mage.Sets/src/mage/sets/theros/ChainedToTheRocks.java b/Mage.Sets/src/mage/sets/theros/ChainedToTheRocks.java index 36a6c62103..d0358433f4 100644 --- a/Mage.Sets/src/mage/sets/theros/ChainedToTheRocks.java +++ b/Mage.Sets/src/mage/sets/theros/ChainedToTheRocks.java @@ -29,18 +29,18 @@ package mage.sets.theros; import java.util.LinkedList; import java.util.UUID; - -import mage.constants.CardType; -import mage.constants.Rarity; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.effects.Effect; +import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.AttachEffect; import mage.abilities.effects.common.ExileTargetEffect; import mage.abilities.keyword.EnchantAbility; import mage.cards.Card; import mage.cards.CardImpl; +import mage.constants.CardType; import mage.constants.Outcome; +import mage.constants.Rarity; import mage.constants.TargetController; import mage.constants.WatcherScope; import mage.constants.Zone; @@ -52,11 +52,39 @@ import mage.game.ExileZone; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.events.ZoneChangeEvent; +import mage.game.permanent.Permanent; import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import mage.watchers.WatcherImpl; /** + * If the land Chained to the Rocks is enchanting stops being a Mountain or another player + * gains control of it, Chained to the Rocks will be put into its owner's graveyard when + * state-based actions are performed. + * + * Chained to the Rocks's ability causes a zone change with a duration, a style of ability + * introduced in Magic 2014 that's somewhat reminiscent of older cards like Oblivion Ring. + * However, unlike Oblivion Ring, cards like Chained to the Rocks have a single ability + * that creates two one-shot effects: one that exiles the creature when the ability resolves, + * and another that returns the exiled card to the battlefield immediately after Chained to + * the Rocks leaves the battlefield. + * + * If Chained to the Rocks leaves the battlefield before its triggered ability resolves, + * the target creature won't be exiled. + * + * Auras attached to the exiled creature will be put into their owners' graveyards (unless + * they have bestow). Equipment attached to the exiled creature will become unattached and + * remain on the battlefield. Any counters on the exiled creature will cease to exist. + * + * If a creature token is exiled, it ceases to exist. It won't be returned to the battlefield. + * + * The exiled card returns to the battlefield immediately after Chained to the Rocks leaves + * the battlefield. Nothing happens between the two events, including state-based actions. + * + * In a multiplayer game, if Chained to the Rocks's owner leaves the game, the exiled card + * will return to the battlefield. Because the one-shot effect that returns the card isn't + * an ability that goes on the stack, it won't cease to exist along with the leaving player's + * spells and abilities on the stack. * * @author LevelX2 */ @@ -68,7 +96,6 @@ public class ChainedToTheRocks extends CardImpl { filter.add(new SubtypePredicate("Mountain")); filterTarget.add(new ControllerPredicate(TargetController.OPPONENT)); } - private UUID exileId = UUID.randomUUID(); public ChainedToTheRocks(UUID ownerId) { super(ownerId, 4, "Chained to the Rocks", Rarity.RARE, new CardType[]{CardType.ENCHANTMENT}, "{W}"); @@ -84,14 +111,11 @@ public class ChainedToTheRocks extends CardImpl { Ability ability = new EnchantAbility(auraTarget.getTargetName()); this.addAbility(ability); - // When Chained to the Rocks enters the battlefield, exile target creature an opponent controls until Chained to the Rocks leaves the battlefield. (That creature returns under its owner's control.) - Effect effect = new ExileTargetEffect(exileId, this.getName()); - effect.setText("exile target creature an opponent controls until {this} leaves the battlefield. (That creature returns under its owner's control.)"); - ability = new EntersBattlefieldTriggeredAbility(effect); + ability = new EntersBattlefieldTriggeredAbility(new ChainedToTheRocksEffect()); ability.addTarget(new TargetCreaturePermanent(filterTarget)); this.addAbility(ability); - this.addWatcher(new ChainedToTheRocksWatcher(exileId)); + this.addWatcher(new ChainedToTheRocksWatcher(this.getId())); } @@ -105,32 +129,57 @@ public class ChainedToTheRocks extends CardImpl { } } +class ChainedToTheRocksEffect extends OneShotEffect { + + public ChainedToTheRocksEffect() { + super(Outcome.Benefit); + this.staticText = "exile target creature an opponent controls until {this} leaves the battlefield. (That creature returns under its owner's control.)"; + } + + public ChainedToTheRocksEffect(final ChainedToTheRocksEffect effect) { + super(effect); + } + + @Override + public ChainedToTheRocksEffect copy() { + return new ChainedToTheRocksEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent permanent = game.getPermanent(source.getSourceId()); + // If Chained to the Rocks leaves the battlefield before its triggered ability resolves, + // the target creature won't be exiled. + if (permanent != null) { + new ExileTargetEffect(source.getSourceId(), permanent.getName()).apply(game, source); + } + return false; + } +} class ChainedToTheRocksWatcher extends WatcherImpl { - private UUID exileId; - ChainedToTheRocksWatcher (UUID exileId) { super("BattlefieldLeft", WatcherScope.CARD); - this.exileId = exileId; } ChainedToTheRocksWatcher(final ChainedToTheRocksWatcher watcher) { super(watcher); - this.exileId = watcher.exileId; } @Override public void watch(GameEvent event, Game game) { - if (event.getType() == GameEvent.EventType.ZONE_CHANGE && event.getTargetId().equals(sourceId)) { + if (event.getType() == GameEvent.EventType.ZONE_CHANGE && event.getTargetId().equals(this.getSourceId())) { ZoneChangeEvent zEvent = (ZoneChangeEvent)event; if (zEvent.getFromZone() == Zone.BATTLEFIELD) { - ExileZone exile = game.getExile().getExileZone(exileId); - if (exile != null) { - LinkedList cards = new LinkedList(exile); + ExileZone exile = game.getExile().getExileZone(this.getSourceId()); + Card sourceCard = game.getCard(this.getSourceId()); + if (exile != null && sourceCard != null) { + LinkedList cards = new LinkedList<>(exile); for (UUID cardId: cards) { Card card = game.getCard(cardId); card.moveToZone(Zone.BATTLEFIELD, this.getSourceId(), game, false); + game.informPlayers(new StringBuilder(sourceCard.getName()).append(": ").append(card.getName()).append(" was returned to battlefield from exile").toString()); } exile.clear(); }