* Some fixes to the exile effects with duration. Fixed that exiled cards/permanets did not come back if causing card was put into play and exiled by Whip of Erebos.

This commit is contained in:
LevelX2 2014-12-14 22:56:37 +01:00
parent 9ba6f74bf6
commit 7b738474a9
15 changed files with 187 additions and 542 deletions

View file

@ -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<UUID> 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;
}

View file

@ -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

View file

@ -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;

View file

@ -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<UUID> 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;
}

View file

@ -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<UUID> 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;
}

View file

@ -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<UUID> 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;
}

View file

@ -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<UUID> 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;
}

View file

@ -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;

View file

@ -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<UUID> 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;
}

View file

@ -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;
}