diff --git a/Mage.Client/serverlist.txt b/Mage.Client/serverlist.txt index 33df5c541a6..b7f106d4c97 100644 --- a/Mage.Client/serverlist.txt +++ b/Mage.Client/serverlist.txt @@ -1,5 +1,5 @@ woogerworks (Version 1.3.0 dev 2014-10-29V2) :xmage.woogerworks.com:17171 XMage.info 1 (Version 1.3.0 dev 2014-11-29v3) :176.31.186.181:17171 -XMage.info 2 (Version 1.3.0 dev 2014-11-29V3) :176.31.186.181:17000 +XMage.info 2 (Version 1.3.0 dev 2014-11-29V4) :176.31.186.181:17000 Seedds Server (Version 1.3.0 dev 2014-11-29v2) :115.29.203.80:17171 localhost -> connect to your local server (must be started):localhost:17171 diff --git a/Mage.Sets/src/mage/sets/journeyintonyx/BanishingLight.java b/Mage.Sets/src/mage/sets/journeyintonyx/BanishingLight.java index 6cf75ce9f15..63346de0752 100644 --- a/Mage.Sets/src/mage/sets/journeyintonyx/BanishingLight.java +++ b/Mage.Sets/src/mage/sets/journeyintonyx/BanishingLight.java @@ -27,29 +27,24 @@ */ package mage.sets.journeyintonyx; -import java.util.LinkedList; import java.util.UUID; import mage.abilities.Ability; -import mage.abilities.TriggeredAbilityImpl; import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.delayed.OnLeaveReturnExiledToBattlefieldAbility; import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect; import mage.abilities.effects.common.ExileTargetEffect; -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.Zone; import mage.filter.common.FilterNonlandPermanent; import mage.filter.predicate.permanent.ControllerPredicate; -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.players.Player; import mage.target.TargetPermanent; +import mage.util.CardUtil; /** * @@ -72,10 +67,8 @@ public class BanishingLight extends CardImpl { // When Banishing Light enters the battlefield, exile target nonland permanent an opponent controls until Banishing Light leaves the battlefield. Ability ability = new EntersBattlefieldTriggeredAbility(new BanishingLightExileEffect()); ability.addTarget(new TargetPermanent(filter)); + ability.addEffect(new CreateDelayedTriggeredAbilityEffect(new OnLeaveReturnExiledToBattlefieldAbility())); this.addAbility(ability); - // Implemented as triggered effect that doesn't uses the stack (implementation with watcher does not work correctly because if the returned creature - // has a DiesTriggeredAll ability it triggers for the dying / battlefield leaving source object, what shouldn't happen) - this.addAbility(new BanishingLightReturnExiledAbility()); } public BanishingLight(final BanishingLight card) { @@ -110,79 +103,7 @@ class BanishingLightExileEffect extends OneShotEffect { // If Banishing Light leaves the battlefield before its triggered ability resolves, // the target won't be exiled. if (permanent != null) { - return new ExileTargetEffect(source.getSourceId(), permanent.getName()).apply(game, source); - } - return false; - } -} - -/** - * Returns the exiled card as source permanent leaves battlefield - * Uses no stack - * @author LevelX2 - */ - -class BanishingLightReturnExiledAbility extends TriggeredAbilityImpl { - - public BanishingLightReturnExiledAbility() { - super(Zone.BATTLEFIELD, new ReturnExiledCreatureEffect()); - this.usesStack = false; - this.setRuleVisible(false); - } - - public BanishingLightReturnExiledAbility(final BanishingLightReturnExiledAbility ability) { - super(ability); - } - - @Override - public BanishingLightReturnExiledAbility copy() { - return new BanishingLightReturnExiledAbility(this); - } - - @Override - public boolean checkTrigger(GameEvent event, Game game) { - if (event.getType() == GameEvent.EventType.ZONE_CHANGE && event.getTargetId().equals(this.getSourceId())) { - ZoneChangeEvent zEvent = (ZoneChangeEvent) event; - if (zEvent.getFromZone() == Zone.BATTLEFIELD) { - return true; - } - } - return false; - } -} - -class ReturnExiledCreatureEffect extends OneShotEffect { - - public ReturnExiledCreatureEffect() { - super(Outcome.Benefit); - this.staticText = "Return exiled permanent"; - } - - public ReturnExiledCreatureEffect(final ReturnExiledCreatureEffect effect) { - super(effect); - } - - @Override - public ReturnExiledCreatureEffect copy() { - return new ReturnExiledCreatureEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player controller = game.getPlayer(source.getControllerId()); - if (controller != null) { - ExileZone exile = game.getExile().getExileZone(source.getSourceId()); - Card sourceCard = game.getCard(source.getSourceId()); - if (exile != null && sourceCard != null) { - LinkedList cards = new LinkedList<>(exile); - for (UUID cardId : cards) { - Card card = game.getCard(cardId); - card.moveToZone(Zone.BATTLEFIELD, source.getSourceId(), game, false); - game.informPlayers(new StringBuilder(sourceCard.getName()).append(": ").append(card.getName()).append(" returns to battlefield from exile").toString()); - } - exile.clear(); - return true; - } + return new ExileTargetEffect(CardUtil.getCardExileZoneId(game, source), permanent.getName()).apply(game, source); } return false; } diff --git a/Mage.Sets/src/mage/sets/journeyintonyx/BrainMaggot.java b/Mage.Sets/src/mage/sets/journeyintonyx/BrainMaggot.java index 6f49d77ef8c..46c455db424 100644 --- a/Mage.Sets/src/mage/sets/journeyintonyx/BrainMaggot.java +++ b/Mage.Sets/src/mage/sets/journeyintonyx/BrainMaggot.java @@ -31,12 +31,14 @@ import java.util.LinkedList; import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; -import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.DelayedTriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect; import mage.cards.Card; import mage.cards.CardImpl; import mage.constants.CardType; +import mage.constants.Duration; import mage.constants.Outcome; import mage.constants.Rarity; import mage.constants.Zone; @@ -70,10 +72,8 @@ public class BrainMaggot extends CardImpl { // When Brain Maggot enters the battlefield, target opponent reveals his or her hand and you choose a nonland card from it. Exile that card until Brain Maggot leaves the battlefield. Ability ability = new EntersBattlefieldTriggeredAbility(new BrainMaggotExileEffect()); ability.addTarget(new TargetOpponent()); + ability.addEffect(new CreateDelayedTriggeredAbilityEffect(new BrainMaggotReturnExiledCreatureAbility())); this.addAbility(ability); - // Implemented as triggered effect that doesn't uses the stack (implementation with watcher does not work correctly because if the returned creature - // has a DiesTriggeredAll ability it triggers for the dying / battlefield leaving source object, what shouldn't happen) - this.addAbility(new BrainMaggotReturnExiledAbility()); } public BrainMaggot(final BrainMaggot card) { @@ -108,15 +108,17 @@ class BrainMaggotExileEffect extends OneShotEffect { Player opponent = game.getPlayer(this.getTargetPointer().getFirst(game, source)); Permanent sourcePermanent = game.getPermanentOrLKIBattlefield(source.getSourceId()); if (controller != null && opponent != null && sourcePermanent != null) { - opponent.revealCards(sourcePermanent.getLogName(), opponent.getHand(), game); + if (!opponent.getHand().isEmpty()) { + opponent.revealCards(sourcePermanent.getLogName(), opponent.getHand(), game); - FilterCard filter = new FilterNonlandCard("nonland card to exile"); - TargetCard target = new TargetCard(Zone.HAND, filter); - if (opponent.getHand().count(filter, game) > 0 && controller.choose(Outcome.Exile, opponent.getHand(), target, game)) { - Card card = opponent.getHand().get(target.getFirstTarget(), game); - // If source permanent leaves the battlefield before its triggered ability resolves, the target card won't be exiled. - if (card != null && game.getState().getZone(source.getSourceId()) == Zone.BATTLEFIELD) { - controller.moveCardToExileWithInfo(card, CardUtil.getCardExileZoneId(game, source), sourcePermanent.getName(), source.getSourceId(), game, Zone.HAND); + FilterCard filter = new FilterNonlandCard("nonland card to exile"); + TargetCard target = new TargetCard(Zone.HAND, filter); + if (opponent.getHand().count(filter, game) > 0 && controller.choose(Outcome.Exile, opponent.getHand(), target, game)) { + Card card = opponent.getHand().get(target.getFirstTarget(), game); + // If source permanent leaves the battlefield before its triggered ability resolves, the target card won't be exiled. + if (card != null && game.getState().getZone(source.getSourceId()) == Zone.BATTLEFIELD) { + controller.moveCardToExileWithInfo(card, CardUtil.getCardExileZoneId(game, source), sourcePermanent.getName(), source.getSourceId(), game, Zone.HAND); + } } } return true; @@ -132,21 +134,21 @@ class BrainMaggotExileEffect extends OneShotEffect { * @author LevelX2 */ -class BrainMaggotReturnExiledAbility extends TriggeredAbilityImpl { +class BrainMaggotReturnExiledCreatureAbility extends DelayedTriggeredAbility { - public BrainMaggotReturnExiledAbility() { - super(Zone.BATTLEFIELD, new BrainMaggotReturnExiledCreatureEffect()); + public BrainMaggotReturnExiledCreatureAbility() { + super(new BrainMaggotReturnExiledCreatureEffect(), Duration.OneUse); this.usesStack = false; this.setRuleVisible(false); } - public BrainMaggotReturnExiledAbility(final BrainMaggotReturnExiledAbility ability) { + public BrainMaggotReturnExiledCreatureAbility(final BrainMaggotReturnExiledCreatureAbility ability) { super(ability); } @Override - public BrainMaggotReturnExiledAbility copy() { - return new BrainMaggotReturnExiledAbility(this); + public BrainMaggotReturnExiledCreatureAbility copy() { + return new BrainMaggotReturnExiledCreatureAbility(this); } @Override diff --git a/Mage.Sets/src/mage/sets/khansoftarkir/KheruLichLord.java b/Mage.Sets/src/mage/sets/khansoftarkir/KheruLichLord.java index 371372235be..bcbd847eb3b 100644 --- a/Mage.Sets/src/mage/sets/khansoftarkir/KheruLichLord.java +++ b/Mage.Sets/src/mage/sets/khansoftarkir/KheruLichLord.java @@ -179,7 +179,7 @@ class KheruLichLordReplacementEffect extends ReplacementEffectImpl { if (controller != null) { Card card = game.getCard(getTargetPointer().getFirst(game, source)); if (card != null) { - controller.moveCardToExileWithInfo(card, null, "", source.getSourceId(), game, null); + controller.moveCardToExileWithInfo(card, null, "", source.getSourceId(), game, game.getState().getZone(card.getId())); } } return true; diff --git a/Mage.Sets/src/mage/sets/khansoftarkir/SuspensionField.java b/Mage.Sets/src/mage/sets/khansoftarkir/SuspensionField.java index 78ce0e25c6d..0eb6fe8efb7 100644 --- a/Mage.Sets/src/mage/sets/khansoftarkir/SuspensionField.java +++ b/Mage.Sets/src/mage/sets/khansoftarkir/SuspensionField.java @@ -27,29 +27,24 @@ */ package mage.sets.khansoftarkir; -import java.util.LinkedList; import java.util.UUID; import mage.abilities.Ability; -import mage.abilities.TriggeredAbilityImpl; import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.delayed.OnLeaveReturnExiledToBattlefieldAbility; import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect; import mage.abilities.effects.common.ExileTargetEffect; -import mage.cards.Card; import mage.cards.CardImpl; import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.Rarity; -import mage.constants.Zone; import mage.filter.Filter.ComparisonType; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.ToughnessPredicate; -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.players.Player; import mage.target.common.TargetCreaturePermanent; +import mage.util.CardUtil; /** * @@ -71,10 +66,9 @@ public class SuspensionField extends CardImpl { // When Suspension Field enters the battlefield, you may exile target creature with toughness 3 or greater until Suspension Field leaves the battlefield. Ability ability = new EntersBattlefieldTriggeredAbility(new SuspensionFieldExileEffect(), true); ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addEffect(new CreateDelayedTriggeredAbilityEffect(new OnLeaveReturnExiledToBattlefieldAbility())); this.addAbility(ability); - // Implemented as triggered effect that doesn't uses the stack (implementation with watcher does not work correctly because if the returned creature - // has a DiesTriggeredAll ability it triggers for the dying / battlefield leaving source object, what shouldn't happen) - this.addAbility(new SuspensionFieldReturnExiledAbility()); + } public SuspensionField(final SuspensionField card) { @@ -108,73 +102,7 @@ class SuspensionFieldExileEffect extends OneShotEffect { Permanent sourcePermanent = game.getPermanent(source.getSourceId()); // If Suspension Field leaves the battlefield before its triggered ability resolves, the target won't be exiled. if (sourcePermanent != null) { - return new ExileTargetEffect(source.getSourceId(), sourcePermanent.getName()).apply(game, source); - } - return false; - } -} - -class SuspensionFieldReturnExiledAbility extends TriggeredAbilityImpl { - - SuspensionFieldReturnExiledAbility() { - super(Zone.BATTLEFIELD, new SuspensionFieldReturnExiledCreatureEffect()); - this.usesStack = false; - this.setRuleVisible(false); - } - - SuspensionFieldReturnExiledAbility(final SuspensionFieldReturnExiledAbility ability) { - super(ability); - } - - @Override - public SuspensionFieldReturnExiledAbility copy() { - return new SuspensionFieldReturnExiledAbility(this); - } - - @Override - public boolean checkTrigger(GameEvent event, Game game) { - if (event.getType() == GameEvent.EventType.ZONE_CHANGE && event.getTargetId().equals(this.getSourceId())) { - ZoneChangeEvent zEvent = (ZoneChangeEvent) event; - if (zEvent.getFromZone() == Zone.BATTLEFIELD) { - return true; - } - } - return false; - } -} - -class SuspensionFieldReturnExiledCreatureEffect extends OneShotEffect { - - SuspensionFieldReturnExiledCreatureEffect() { - super(Outcome.Benefit); - this.staticText = "Return exiled permanent"; - } - - SuspensionFieldReturnExiledCreatureEffect(final SuspensionFieldReturnExiledCreatureEffect effect) { - super(effect); - } - - @Override - public SuspensionFieldReturnExiledCreatureEffect copy() { - return new SuspensionFieldReturnExiledCreatureEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player controller = game.getPlayer(source.getControllerId()); - if (controller != null) { - ExileZone exile = game.getExile().getExileZone(source.getSourceId()); - Card sourceCard = game.getCard(source.getSourceId()); - if (exile != null && sourceCard != null) { - LinkedList cards = new LinkedList<>(exile); - for (UUID cardId : cards) { - Card card = game.getCard(cardId); - card.moveToZone(Zone.BATTLEFIELD, source.getSourceId(), game, false); - game.informPlayers(new StringBuilder(sourceCard.getName()).append(": ").append(card.getName()).append(" returns to battlefield from exile").toString()); - } - exile.clear(); - return true; - } + return new ExileTargetEffect(CardUtil.getCardExileZoneId(game, source), sourcePermanent.getName()).apply(game, source); } return false; } diff --git a/Mage.Sets/src/mage/sets/magic2014/BanisherPriest.java b/Mage.Sets/src/mage/sets/magic2014/BanisherPriest.java index c084ce87811..e420e96e847 100644 --- a/Mage.Sets/src/mage/sets/magic2014/BanisherPriest.java +++ b/Mage.Sets/src/mage/sets/magic2014/BanisherPriest.java @@ -27,30 +27,25 @@ */ package mage.sets.magic2014; -import java.util.LinkedList; import java.util.UUID; import mage.MageInt; -import mage.MageObject; import mage.abilities.Ability; -import mage.abilities.TriggeredAbilityImpl; import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.delayed.OnLeaveReturnExiledToBattlefieldAbility; import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect; import mage.abilities.effects.common.ExileTargetEffect; -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.Zone; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.permanent.ControllerPredicate; -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.common.TargetCreaturePermanent; +import mage.util.CardUtil; /** * @@ -76,13 +71,8 @@ public class BanisherPriest extends CardImpl { // When Banisher Priest enters the battlefield, exile target creature an opponent controls until Banisher Priest leaves the battlefield. Ability ability = new EntersBattlefieldTriggeredAbility(new BanisherPriestExileEffect()); ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addEffect(new CreateDelayedTriggeredAbilityEffect(new OnLeaveReturnExiledToBattlefieldAbility())); this.addAbility(ability); - // Implemented as triggered effect that doesn't uses the stack (implementation with watcher does not work correctly because if the returned creature - // has a DiesTriggeredAll ability it triggers for the dying Banish Priest, what shouldn't happen) - this.addAbility(new BanisherPriestReturnExiledAbility()); - - - } public BanisherPriest(final BanisherPriest card) { @@ -117,76 +107,7 @@ class BanisherPriestExileEffect extends OneShotEffect { // If Banisher Priest leaves the battlefield before its triggered ability resolves, // the target creature won't be exiled. if (permanent != null) { - return new ExileTargetEffect(source.getSourceId(), permanent.getName()).apply(game, source); - } - return false; - } -} - -/** - * Returns the exiled card as Banisher Priest leaves battlefield - * Uses no stack - * @author LevelX2 - */ - -class BanisherPriestReturnExiledAbility extends TriggeredAbilityImpl { - - public BanisherPriestReturnExiledAbility() { - super(Zone.BATTLEFIELD, new ReturnExiledCreatureEffect()); - this.usesStack = false; - this.setRuleVisible(false); - } - - public BanisherPriestReturnExiledAbility(final BanisherPriestReturnExiledAbility ability) { - super(ability); - } - - @Override - public BanisherPriestReturnExiledAbility copy() { - return new BanisherPriestReturnExiledAbility(this); - } - - @Override - public boolean checkTrigger(GameEvent event, Game game) { - if (event.getType() == GameEvent.EventType.ZONE_CHANGE && event.getTargetId().equals(this.getSourceId())) { - ZoneChangeEvent zEvent = (ZoneChangeEvent) event; - if (zEvent.getFromZone() == Zone.BATTLEFIELD) { - return true; - } - } - return false; - } -} - -class ReturnExiledCreatureEffect extends OneShotEffect { - - public ReturnExiledCreatureEffect() { - super(Outcome.Benefit); - this.staticText = "Return exiled creature"; - } - - public ReturnExiledCreatureEffect(final ReturnExiledCreatureEffect effect) { - super(effect); - } - - @Override - public ReturnExiledCreatureEffect copy() { - return new ReturnExiledCreatureEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - ExileZone exile = game.getExile().getExileZone(source.getSourceId()); - MageObject sourceObject = game.getObject(source.getSourceId()); - if (exile != null && sourceObject != null) { - LinkedList cards = new LinkedList<>(exile); - for (UUID cardId : cards) { - Card card = game.getCard(cardId); - card.moveToZone(Zone.BATTLEFIELD, source.getSourceId(), game, false); - game.informPlayers(new StringBuilder(sourceObject.getLogName()).append(": ").append(card.getName()).append(" returns to battlefield from exile").toString()); - } - exile.clear(); - return true; + return new ExileTargetEffect(CardUtil.getCardExileZoneId(game, source), permanent.getName()).apply(game, source); } return false; } diff --git a/Mage.Sets/src/mage/sets/magic2014/ColossalWhale.java b/Mage.Sets/src/mage/sets/magic2014/ColossalWhale.java index 7cd032a54f8..28dc2a17166 100644 --- a/Mage.Sets/src/mage/sets/magic2014/ColossalWhale.java +++ b/Mage.Sets/src/mage/sets/magic2014/ColossalWhale.java @@ -27,15 +27,15 @@ */ package mage.sets.magic2014; -import java.util.LinkedList; import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.common.delayed.OnLeaveReturnExiledToBattlefieldAbility; import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect; import mage.abilities.effects.common.ExileTargetEffect; import mage.abilities.keyword.IslandwalkAbility; -import mage.cards.Card; import mage.cards.CardImpl; import mage.constants.CardType; import mage.constants.Outcome; @@ -43,12 +43,11 @@ import mage.constants.Rarity; import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.permanent.ControllerIdPredicate; -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.common.TargetCreaturePermanent; +import mage.util.CardUtil; /** * @@ -69,9 +68,6 @@ public class ColossalWhale extends CardImpl { this.addAbility(new IslandwalkAbility()); // Whenever Colossal Whale attacks, you may exile target creature defending player controls until Colossal Whale leaves the battlefield. this.addAbility(new ColossalWhaleAbility()); - // Implemented as triggered effect that doesn't uses the stack (implementation with watcher does not work correctly because if the returned creature - // has a DiesTriggeredAll ability it triggers for the dying Banish Priest, what shouldn't happen) - this.addAbility(new ColossalWhaleReturnExiledAbility()); } @@ -90,6 +86,7 @@ class ColossalWhaleAbility extends TriggeredAbilityImpl { public ColossalWhaleAbility() { super(Zone.BATTLEFIELD, null); this.addEffect(new ColossalWhaleExileEffect()); + this.addEffect(new CreateDelayedTriggeredAbilityEffect(new OnLeaveReturnExiledToBattlefieldAbility())); } public ColossalWhaleAbility(final ColossalWhaleAbility ability) { @@ -144,76 +141,7 @@ class ColossalWhaleExileEffect extends OneShotEffect { // If Whale leaves the battlefield before its triggered ability resolves, // the target creature won't be exiled. if (permanent != null) { - return new ExileTargetEffect(source.getSourceId(), permanent.getName()).apply(game, source); - } - return false; - } -} - -/** - * Returns the exiled card as Banisher Priest leaves battlefield - * Uses no stack - * @author LevelX2 - */ - -class ColossalWhaleReturnExiledAbility extends TriggeredAbilityImpl { - - public ColossalWhaleReturnExiledAbility() { - super(Zone.BATTLEFIELD, new ReturnExiledCreatureColossalWhaleEffect()); - this.usesStack = false; - this.setRuleVisible(false); - } - - public ColossalWhaleReturnExiledAbility(final ColossalWhaleReturnExiledAbility ability) { - super(ability); - } - - @Override - public ColossalWhaleReturnExiledAbility copy() { - return new ColossalWhaleReturnExiledAbility(this); - } - - @Override - public boolean checkTrigger(GameEvent event, Game game) { - if (event.getType() == GameEvent.EventType.ZONE_CHANGE && event.getTargetId().equals(this.getSourceId())) { - ZoneChangeEvent zEvent = (ZoneChangeEvent) event; - if (zEvent.getFromZone() == Zone.BATTLEFIELD) { - return true; - } - } - return false; - } -} - -class ReturnExiledCreatureColossalWhaleEffect extends OneShotEffect { - - public ReturnExiledCreatureColossalWhaleEffect() { - super(Outcome.Benefit); - this.staticText = "Return exiled creatures"; - } - - public ReturnExiledCreatureColossalWhaleEffect(final ReturnExiledCreatureColossalWhaleEffect effect) { - super(effect); - } - - @Override - public ReturnExiledCreatureColossalWhaleEffect copy() { - return new ReturnExiledCreatureColossalWhaleEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - ExileZone exile = game.getExile().getExileZone(source.getSourceId()); - Card sourceCard = game.getCard(source.getSourceId()); - if (exile != null && sourceCard != null) { - LinkedList cards = new LinkedList<>(exile); - for (UUID cardId : cards) { - Card card = game.getCard(cardId); - card.moveToZone(Zone.BATTLEFIELD, source.getSourceId(), game, false); - game.informPlayers(new StringBuilder(sourceCard.getName()).append(": ").append(card.getName()).append(" returns to battlefield from exile").toString()); - } - exile.clear(); - return true; + return new ExileTargetEffect(CardUtil.getCardExileZoneId(game, source), permanent.getName()).apply(game, source); } return false; } diff --git a/Mage.Sets/src/mage/sets/magic2015/ConstrictingSliver.java b/Mage.Sets/src/mage/sets/magic2015/ConstrictingSliver.java index bf13c13e21a..22f31040e9a 100644 --- a/Mage.Sets/src/mage/sets/magic2015/ConstrictingSliver.java +++ b/Mage.Sets/src/mage/sets/magic2015/ConstrictingSliver.java @@ -27,18 +27,16 @@ */ package mage.sets.magic2015; -import java.util.LinkedList; import java.util.UUID; import mage.MageInt; -import mage.MageObject; import mage.abilities.Ability; -import mage.abilities.DelayedTriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.common.delayed.OnLeaveReturnExiledToBattlefieldAbility; import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect; import mage.abilities.effects.common.ExileTargetEffect; import mage.abilities.effects.common.continious.GainAbilityAllEffect; -import mage.cards.Card; import mage.cards.CardImpl; import mage.constants.CardType; import mage.constants.Duration; @@ -49,13 +47,10 @@ import mage.constants.Zone; import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.permanent.ControllerPredicate; -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.players.Player; import mage.target.common.TargetCreaturePermanent; +import mage.util.CardUtil; /** * @@ -83,7 +78,7 @@ public class ConstrictingSliver extends CardImpl { // until this creature leaves the battlefield." Ability ability = new EntersBattlefieldTriggeredAbility(new ConstrictingSliverExileEffect(), true); ability.addTarget(new TargetCreaturePermanent(filterTarget)); - ability.addEffect(new ConstrictingSliverAddDelayedReturnEffect()); + ability.addEffect(new CreateDelayedTriggeredAbilityEffect(new OnLeaveReturnExiledToBattlefieldAbility())); this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityAllEffect(ability, Duration.WhileOnBattlefield, new FilterControlledCreaturePermanent("Sliver","Sliver creatures"), @@ -123,107 +118,7 @@ class ConstrictingSliverExileEffect extends OneShotEffect { // If the creature leaves the battlefield before its triggered ability resolves, // the target creature won't be exiled. if (permanent != null) { - return new ExileTargetEffect(source.getSourceId(), permanent.getLogName()).apply(game, source); - } - return false; - } -} - -class ConstrictingSliverAddDelayedReturnEffect extends OneShotEffect { - - public ConstrictingSliverAddDelayedReturnEffect() { - super(Outcome.Benefit); - this.staticText = ""; - } - - public ConstrictingSliverAddDelayedReturnEffect(final ConstrictingSliverAddDelayedReturnEffect effect) { - super(effect); - } - - @Override - public ConstrictingSliverAddDelayedReturnEffect copy() { - return new ConstrictingSliverAddDelayedReturnEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - DelayedTriggeredAbility delayedAbility = new ConstrictingSliverReturnExiledCreatureAbility(); - delayedAbility.setSourceId(source.getSourceId()); - delayedAbility.setControllerId(source.getControllerId()); - game.addDelayedTriggeredAbility(delayedAbility); - return true; - } -} - - -/** - * Returns the exiled card as creature leaves battlefield - * Uses no stack - * @author LevelX2 - */ - -class ConstrictingSliverReturnExiledCreatureAbility extends DelayedTriggeredAbility { - - public ConstrictingSliverReturnExiledCreatureAbility() { - super(new ConstrictingSliverReturnExiledCreatureEffect(), Duration.OneUse); - this.usesStack = false; - this.setRuleVisible(false); - } - - public ConstrictingSliverReturnExiledCreatureAbility(final ConstrictingSliverReturnExiledCreatureAbility ability) { - super(ability); - } - - @Override - public ConstrictingSliverReturnExiledCreatureAbility copy() { - return new ConstrictingSliverReturnExiledCreatureAbility(this); - } - - @Override - public boolean checkTrigger(GameEvent event, Game game) { - if (event.getType() == GameEvent.EventType.ZONE_CHANGE && event.getTargetId().equals(this.getSourceId())) { - ZoneChangeEvent zEvent = (ZoneChangeEvent) event; - if (zEvent.getFromZone() == Zone.BATTLEFIELD) { - return true; - } - } - return false; - } -} - -class ConstrictingSliverReturnExiledCreatureEffect extends OneShotEffect { - - public ConstrictingSliverReturnExiledCreatureEffect() { - super(Outcome.Benefit); - this.staticText = "Return exiled creatures"; - } - - public ConstrictingSliverReturnExiledCreatureEffect(final ConstrictingSliverReturnExiledCreatureEffect effect) { - super(effect); - } - - @Override - public ConstrictingSliverReturnExiledCreatureEffect copy() { - return new ConstrictingSliverReturnExiledCreatureEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player controller = game.getPlayer(source.getControllerId()); - if (controller != null) { - ExileZone exile = game.getExile().getExileZone(source.getSourceId()); - MageObject sourceObject = game.getObject(source.getSourceId()); - if (exile != null && sourceObject != null) { - LinkedList cards = new LinkedList<>(exile); - for (UUID cardId : cards) { - Card card = game.getCard(cardId); - card.moveToZone(Zone.BATTLEFIELD, source.getSourceId(), game, false); - game.informPlayers(new StringBuilder(sourceObject.getName()).append(": ").append(card.getName()).append(" returns to battlefield from exile").toString()); - } - exile.clear(); - return true; - } - + return new ExileTargetEffect(CardUtil.getCardExileZoneId(game, source), permanent.getLogName()).apply(game, source); } return false; } diff --git a/Mage.Sets/src/mage/sets/returntoravnica/DryadMilitant.java b/Mage.Sets/src/mage/sets/returntoravnica/DryadMilitant.java index e59ca858343..0649915a4aa 100644 --- a/Mage.Sets/src/mage/sets/returntoravnica/DryadMilitant.java +++ b/Mage.Sets/src/mage/sets/returntoravnica/DryadMilitant.java @@ -102,7 +102,7 @@ class DryadMilitantReplacementEffect extends ReplacementEffectImpl { if (controller != null) { Card card = game.getCard(event.getTargetId()); if (card != null) { - return controller.moveCardToExileWithInfo(card, null, "", source.getSourceId(), game, null); + return controller.moveCardToExileWithInfo(card, null, "", source.getSourceId(), game, game.getState().getZone(card.getId())); } } return false; diff --git a/Mage.Sets/src/mage/sets/theros/ChainedToTheRocks.java b/Mage.Sets/src/mage/sets/theros/ChainedToTheRocks.java index 832d37d6e66..a3bb45fe774 100644 --- a/Mage.Sets/src/mage/sets/theros/ChainedToTheRocks.java +++ b/Mage.Sets/src/mage/sets/theros/ChainedToTheRocks.java @@ -27,33 +27,29 @@ */ package mage.sets.theros; -import java.util.LinkedList; import java.util.UUID; import mage.abilities.Ability; -import mage.abilities.TriggeredAbilityImpl; import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.delayed.OnLeaveReturnExiledToBattlefieldAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.AttachEffect; +import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect; 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.Zone; import mage.filter.common.FilterControlledLandPermanent; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.SubtypePredicate; import mage.filter.predicate.permanent.ControllerPredicate; -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.util.CardUtil; /** * If the land Chained to the Rocks is enchanting stops being a Mountain or another player @@ -112,10 +108,8 @@ public class ChainedToTheRocks extends CardImpl { // 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.) ability = new EntersBattlefieldTriggeredAbility(new ChainedToTheRocksEffect()); ability.addTarget(new TargetCreaturePermanent(filterTarget)); + ability.addEffect(new CreateDelayedTriggeredAbilityEffect(new OnLeaveReturnExiledToBattlefieldAbility())); this.addAbility(ability); - // Implemented as triggered effect that doesn't uses the stack (implementation with watcher does not work correctly because if the returned creature - // has a DiesTriggeredAll ability it triggers for the battlefield leaving Chained to the Rocks, what shouldn't happen) - this.addAbility(new ChainedToTheRocksReturnExiledAbility()); } @@ -151,77 +145,7 @@ class ChainedToTheRocksEffect extends OneShotEffect { // If Chained to the Rocks leaves the battlefield before its triggered ability resolves, // the target creature won't be exiled. if (permanent != null) { - return new ExileTargetEffect(source.getSourceId(), permanent.getLogName()).apply(game, source); - } - return false; - } -} - - -/** - * Returns the exiled card as Chained to the Rocks leaves battlefield - * Uses no stack - * @author LevelX2 - */ - -class ChainedToTheRocksReturnExiledAbility extends TriggeredAbilityImpl { - - public ChainedToTheRocksReturnExiledAbility() { - super(Zone.BATTLEFIELD, new ReturnExiledCreatureChainedToTheRocksEffect()); - this.usesStack = false; - this.setRuleVisible(false); - } - - public ChainedToTheRocksReturnExiledAbility(final ChainedToTheRocksReturnExiledAbility ability) { - super(ability); - } - - @Override - public ChainedToTheRocksReturnExiledAbility copy() { - return new ChainedToTheRocksReturnExiledAbility(this); - } - - @Override - public boolean checkTrigger(GameEvent event, Game game) { - if (event.getType() == GameEvent.EventType.ZONE_CHANGE && event.getTargetId().equals(this.getSourceId())) { - ZoneChangeEvent zEvent = (ZoneChangeEvent) event; - if (zEvent.getFromZone() == Zone.BATTLEFIELD) { - return true; - } - } - return false; - } -} - -class ReturnExiledCreatureChainedToTheRocksEffect extends OneShotEffect { - - public ReturnExiledCreatureChainedToTheRocksEffect() { - super(Outcome.Benefit); - this.staticText = "Return exiled creatures"; - } - - public ReturnExiledCreatureChainedToTheRocksEffect(final ReturnExiledCreatureChainedToTheRocksEffect effect) { - super(effect); - } - - @Override - public ReturnExiledCreatureChainedToTheRocksEffect copy() { - return new ReturnExiledCreatureChainedToTheRocksEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - ExileZone exile = game.getExile().getExileZone(source.getSourceId()); - Card sourceCard = game.getCard(source.getSourceId()); - if (exile != null && sourceCard != null) { - LinkedList cards = new LinkedList<>(exile); - for (UUID cardId : cards) { - Card card = game.getCard(cardId); - card.moveToZone(Zone.BATTLEFIELD, source.getSourceId(), game, false); - game.informPlayers(new StringBuilder(sourceCard.getName()).append(": ").append(card.getName()).append(" returns to battlefield from exile").toString()); - } - exile.clear(); - return true; + return new ExileTargetEffect(CardUtil.getCardExileZoneId(game, source), permanent.getLogName()).apply(game, source); } return false; } diff --git a/Mage.Sets/src/mage/sets/theros/WhipOfErebos.java b/Mage.Sets/src/mage/sets/theros/WhipOfErebos.java index ef7c1e92a2c..bcf0cebff6d 100644 --- a/Mage.Sets/src/mage/sets/theros/WhipOfErebos.java +++ b/Mage.Sets/src/mage/sets/theros/WhipOfErebos.java @@ -156,8 +156,8 @@ class WhipOfErebosReplacementEffect extends ReplacementEffectImpl { public boolean replaceEvent(GameEvent event, Ability source, Game game) { Card card = game.getCard(source.getFirstTarget()); Player controller = game.getPlayer(source.getControllerId()); - if (card != null && controller != null) { - controller.moveCardToExileWithInfo(card, null, null, source.getSourceId(), game, null); + if (card != null && controller != null) { + controller.moveCardToExileWithInfo(card, null, null, source.getSourceId(), game, Zone.BATTLEFIELD); } return true; } diff --git a/Mage/src/mage/abilities/TriggeredAbilities.java b/Mage/src/mage/abilities/TriggeredAbilities.java index 2cb04a6ee79..731f82686bf 100644 --- a/Mage/src/mage/abilities/TriggeredAbilities.java +++ b/Mage/src/mage/abilities/TriggeredAbilities.java @@ -85,7 +85,7 @@ public class TriggeredAbilities extends ConcurrentHashMap cards = new LinkedList<>(exile); + for (UUID cardId : cards) { + Card card = game.getCard(cardId); + if (card != null) { + Player owner = game.getPlayer(card.getOwnerId()); + if (owner != null && owner.isInGame()) { + owner.putOntoBattlefieldWithInfo(card, game, Zone.EXILED, source.getSourceId()); + } + } + } + exile.clear(); + return true; + } + } + return false; + } +} diff --git a/Mage/src/mage/abilities/effects/common/CreateDelayedTriggeredAbilityEffect.java b/Mage/src/mage/abilities/effects/common/CreateDelayedTriggeredAbilityEffect.java index 2e9227ddad9..d22210f53d3 100644 --- a/Mage/src/mage/abilities/effects/common/CreateDelayedTriggeredAbilityEffect.java +++ b/Mage/src/mage/abilities/effects/common/CreateDelayedTriggeredAbilityEffect.java @@ -85,7 +85,11 @@ public class CreateDelayedTriggeredAbilityEffect extends OneShotEffect { if (staticText != null && !staticText.isEmpty()){ return staticText; } - return ability.getRule(); + if (ability.getRuleVisible()) { + return ability.getRule(); + } else { + return ""; + } } } diff --git a/Mage/src/mage/abilities/effects/common/ExileSourceEffect.java b/Mage/src/mage/abilities/effects/common/ExileSourceEffect.java index 279bbb07948..1f047fdfca8 100644 --- a/Mage/src/mage/abilities/effects/common/ExileSourceEffect.java +++ b/Mage/src/mage/abilities/effects/common/ExileSourceEffect.java @@ -67,17 +67,18 @@ public class ExileSourceEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - if (!game.getState().getZone(source.getSourceId()).match(onlyfromZone)) { + Zone zone = game.getState().getZone(source.getSourceId()); + if (!zone.match(onlyfromZone)) { return false; } Permanent permanent = game.getPermanent(source.getSourceId()); Player controller = game.getPlayer(source.getControllerId()); if (permanent != null) { - return controller.moveCardToExileWithInfo(permanent, null, null, source.getSourceId(), game, null); + return controller.moveCardToExileWithInfo(permanent, null, null, source.getSourceId(), game, zone); } else { Card card = game.getCard(source.getSourceId()); if (card != null) { - return controller.moveCardToExileWithInfo(card, null, null, source.getSourceId(), game, null); + return controller.moveCardToExileWithInfo(card, null, null, source.getSourceId(), game, zone); } } return false;