diff --git a/Mage.Sets/src/mage/sets/modernmasters/Epochrasite.java b/Mage.Sets/src/mage/sets/modernmasters/Epochrasite.java
index 1b08cb8bdd1..3bd59ded48a 100644
--- a/Mage.Sets/src/mage/sets/modernmasters/Epochrasite.java
+++ b/Mage.Sets/src/mage/sets/modernmasters/Epochrasite.java
@@ -32,18 +32,25 @@ import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.DiesTriggeredAbility;
import mage.abilities.common.EntersBattlefieldAbility;
-import mage.abilities.condition.common.CastFromHandCondition;
import mage.abilities.condition.InvertCondition;
-import mage.abilities.dynamicvalue.common.StaticValue;
-import mage.abilities.effects.common.ExileSourceEffect;
-import mage.abilities.effects.common.continuous.GainAbilitySourceEffect;
+import mage.abilities.condition.common.CastFromHandCondition;
+import mage.abilities.effects.ContinuousEffectImpl;
+import mage.abilities.effects.OneShotEffect;
+import mage.abilities.effects.common.continuous.SourceEffect;
import mage.abilities.effects.common.counter.AddCountersSourceEffect;
import mage.abilities.keyword.SuspendAbility;
+import mage.cards.Card;
import mage.cards.CardImpl;
import mage.constants.CardType;
import mage.constants.Duration;
+import mage.constants.Layer;
+import mage.constants.Outcome;
import mage.constants.Rarity;
+import mage.constants.SubLayer;
+import mage.constants.Zone;
import mage.counters.CounterType;
+import mage.game.Game;
+import mage.players.Player;
import mage.watchers.common.CastFromHandWatcher;
/**
@@ -68,10 +75,7 @@ public class Epochrasite extends CardImpl {
new CastFromHandWatcher());
// When Epochrasite dies, exile it with three time counters on it and it gains suspend.
- Ability ability = new DiesTriggeredAbility(new ExileSourceEffect());
- ability.addEffect(new AddCountersSourceEffect(CounterType.TIME.createInstance(3), new StaticValue(0), false, true));
- ability.addEffect(new GainAbilitySourceEffect(new SuspendAbility(3, null, this), Duration.OneUse, true));
- this.addAbility(ability);
+ this.addAbility(new DiesTriggeredAbility(new EpochrasiteEffect()));
}
public Epochrasite(final Epochrasite card) {
@@ -84,3 +88,63 @@ public class Epochrasite extends CardImpl {
}
}
+class EpochrasiteEffect extends OneShotEffect {
+
+ public EpochrasiteEffect() {
+ super(Outcome.Benefit);
+ this.staticText = "exile it with three time counters on it and it gains suspend";
+ }
+
+ public EpochrasiteEffect(final EpochrasiteEffect effect) {
+ super(effect);
+ }
+
+ @Override
+ public EpochrasiteEffect copy() {
+ return new EpochrasiteEffect(this);
+ }
+
+ @Override
+ public boolean apply(Game game, Ability source) {
+ Player controller = game.getPlayer(source.getControllerId());
+ Card card = game.getCard(source.getSourceId());
+ if (controller != null && card != null) {
+ if (game.getState().getZone(card.getId()).equals(Zone.GRAVEYARD)) {
+ UUID exileId = SuspendAbility.getSuspendExileId(controller.getId(), game);
+ controller.moveCardToExileWithInfo(card, exileId, "Suspended cards of " + controller.getName(), source.getSourceId(), game, Zone.GRAVEYARD);
+ card.addCounters(CounterType.TIME.createInstance(3), game);
+ game.addEffect(new GainSuspendEffect(), source);
+ }
+ return true;
+ }
+ return false;
+ }
+}
+
+class GainSuspendEffect extends ContinuousEffectImpl implements SourceEffect {
+
+ public GainSuspendEffect() {
+ super(Duration.Custom, Layer.AbilityAddingRemovingEffects_6, SubLayer.NA, Outcome.AddAbility);
+ staticText = "{this} gains suspend";
+ }
+
+ public GainSuspendEffect(final GainSuspendEffect effect) {
+ super(effect);
+ }
+
+ @Override
+ public GainSuspendEffect copy() {
+ return new GainSuspendEffect(this);
+ }
+
+ @Override
+ public boolean apply(Game game, Ability source) {
+ Card card = game.getCard(source.getSourceId());
+ if (card != null && game.getState().getZone(card.getId()).equals(Zone.EXILED)) {
+ SuspendAbility.addSuspendTemporaryToCard(card, source, game);
+ } else {
+ discard();
+ }
+ return true;
+ }
+}
diff --git a/Mage.Sets/src/mage/sets/modernmasters/JhoiraOfTheGhitu.java b/Mage.Sets/src/mage/sets/modernmasters/JhoiraOfTheGhitu.java
index 4670aafb5e6..e8ac5863bd5 100644
--- a/Mage.Sets/src/mage/sets/modernmasters/JhoiraOfTheGhitu.java
+++ b/Mage.Sets/src/mage/sets/modernmasters/JhoiraOfTheGhitu.java
@@ -31,19 +31,24 @@ import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import mage.MageInt;
-import mage.abilities.Abilities;
+import mage.MageObjectReference;
import mage.abilities.Ability;
import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.costs.Cost;
import mage.abilities.costs.common.ExileFromHandCost;
import mage.abilities.costs.mana.GenericManaCost;
+import mage.abilities.effects.ContinuousEffectImpl;
import mage.abilities.effects.OneShotEffect;
+import mage.abilities.effects.common.continuous.SourceEffect;
import mage.abilities.keyword.SuspendAbility;
import mage.cards.Card;
import mage.cards.CardImpl;
import mage.constants.CardType;
+import mage.constants.Duration;
+import mage.constants.Layer;
import mage.constants.Outcome;
import mage.constants.Rarity;
+import mage.constants.SubLayer;
import mage.constants.Zone;
import mage.counters.CounterType;
import mage.filter.common.FilterNonlandCard;
@@ -116,38 +121,13 @@ class JhoiraOfTheGhituSuspendEffect extends OneShotEffect {
}
if (cards != null && !cards.isEmpty()) {
Card card = game.getCard(cards.get(0).getId());
- boolean hasSuspend = false;
- for (Ability ability :card.getAbilities()) {
- if (ability instanceof SuspendAbility) {
- hasSuspend = true;
- break;
- }
- }
+ boolean hasSuspend = card.getAbilities().containsClass(SuspendAbility.class);
- UUID exileId = (UUID) game.getState().getValue("SuspendExileId" + source.getControllerId().toString());
- if (exileId == null) {
- exileId = UUID.randomUUID();
- game.getState().setValue("SuspendExileId" + source.getControllerId().toString(), exileId);
- }
- if (card.moveToExile(exileId, new StringBuilder("Suspended cards of ").append(controller.getName()).toString() , source.getSourceId(), game)) {
+ UUID exileId = SuspendAbility.getSuspendExileId(controller.getId(), game);
+ if (controller.moveCardToExileWithInfo(card, exileId, "Suspended cards of " + controller.getName(), source.getSourceId(), game, Zone.HAND)) {
card.addCounters(CounterType.TIME.createInstance(4), game);
if (!hasSuspend) {
- // add suspend ability
- // TODO: Find a better solution for giving suspend to a card.
- // If the exiled card leaves exile by another way, the abilites won't be removed from the card
- Abilities oldAbilities = card.getAbilities().copy();
- SuspendAbility suspendAbility = new SuspendAbility(4, null, card);
- card.addAbility(suspendAbility);
-
- for (Ability ability :card.getAbilities()) {
- if (!oldAbilities.contains(ability)) {
- ability.setControllerId(source.getControllerId());
- ability.setSourceId(source.getSourceId());
- ability.setSourceObject(source.getSourceObject(game));
- game.getState().addAbility(ability, card);
- }
- }
-
+ game.addEffect(new JhoiraGainSuspendEffect(new MageObjectReference(card)), source);
}
game.informPlayers(controller.getName() + " suspends 4 - " + card.getName());
return true;
@@ -156,3 +136,35 @@ class JhoiraOfTheGhituSuspendEffect extends OneShotEffect {
return false;
}
}
+
+class JhoiraGainSuspendEffect extends ContinuousEffectImpl implements SourceEffect {
+
+ MageObjectReference mor;
+
+ public JhoiraGainSuspendEffect(MageObjectReference mor) {
+ super(Duration.Custom, Layer.AbilityAddingRemovingEffects_6, SubLayer.NA, Outcome.AddAbility);
+ this.mor = mor;
+ staticText = "{this} gains suspend";
+ }
+
+ public JhoiraGainSuspendEffect(final JhoiraGainSuspendEffect effect) {
+ super(effect);
+ this.mor = effect.mor;
+ }
+
+ @Override
+ public JhoiraGainSuspendEffect copy() {
+ return new JhoiraGainSuspendEffect(this);
+ }
+
+ @Override
+ public boolean apply(Game game, Ability source) {
+ Card card = game.getCard(mor.getSourceId());
+ if (card != null && mor.refersTo(card) && game.getState().getZone(card.getId()).equals(Zone.EXILED)) {
+ SuspendAbility.addSuspendTemporaryToCard(card, source, game);
+ } else {
+ discard();
+ }
+ return true;
+ }
+}
diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/SuspendTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/SuspendTest.java
index 19cf8038145..7c9abed4356 100644
--- a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/SuspendTest.java
+++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/SuspendTest.java
@@ -62,5 +62,28 @@ public class SuspendTest extends CardTestPlayerBase {
assertPowerToughness(playerA, "Epochrasite", 4, 4);
}
+ /**
+ * Tests Jhoira of the Ghitu works (give suspend to a exiled card)
+ * {2}, Exile a nonland card from your hand: Put four time counters on the exiled card. If it doesn't have suspend, it gains suspend.
+ *
+ */
+ @Test
+ public void testJhoiraOfTheGhitu() {
+ addCard(Zone.BATTLEFIELD, playerA, "Mountain", 2);
+
+ addCard(Zone.HAND, playerA, "Silvercoat Lion",1);
+ addCard(Zone.BATTLEFIELD, playerA, "Jhoira of the Ghitu", 1);
+
+ activateAbility(3, PhaseStep.PRECOMBAT_MAIN, playerA, "{2},Exile a nonland card from your hand: Put four time counters on the exiled card. If it doesn't have suspend, it gains suspend (At the beginning of your upkeep, remove a time counter from that card. When the last is removed, cast it without paying its mana cost. If it's a creature, it has haste.).");
+ setChoice(playerA, "Silvercoat Lion");
+
+ setStopAt(11, PhaseStep.PRECOMBAT_MAIN);
+ execute();
+
+ assertPermanentCount(playerA, "Jhoira of the Ghitu", 1);
+ assertHandCount(playerA, "Silvercoat Lion", 0);
+ assertPermanentCount(playerA, "Silvercoat Lion", 1);
+
+ }
}
diff --git a/Mage/src/mage/abilities/AbilityImpl.java b/Mage/src/mage/abilities/AbilityImpl.java
index 86778a06933..ae3f30b82f3 100644
--- a/Mage/src/mage/abilities/AbilityImpl.java
+++ b/Mage/src/mage/abilities/AbilityImpl.java
@@ -846,9 +846,15 @@ public abstract class AbilityImpl implements Ability {
if (object != null && !object.getAbilities().contains(this)) {
boolean found = false;
// unfortunately we need to handle double faced cards separately and only this way
- if (object instanceof PermanentCard && ((PermanentCard)object).canTransform()) {
- PermanentCard permanent = (PermanentCard)object;
- found = permanent.getSecondCardFace().getAbilities().contains(this) || permanent.getCard().getAbilities().contains(this);
+ if (object instanceof PermanentCard) {
+ if (((PermanentCard)object).canTransform()) {
+ PermanentCard permanent = (PermanentCard)object;
+ found = permanent.getSecondCardFace().getAbilities().contains(this) || permanent.getCard().getAbilities().contains(this);
+ }
+ } else {
+ // check if it's an ability that is temporary gained to a card
+ Abilities otherAbilities = game.getState().getAllOtherAbilities(this.getSourceId());
+ found = otherAbilities != null && otherAbilities.contains(this);
}
if (!found) {
return false;
diff --git a/Mage/src/mage/abilities/TriggeredAbilities.java b/Mage/src/mage/abilities/TriggeredAbilities.java
index bf49b4f0dec..f48a5745d64 100644
--- a/Mage/src/mage/abilities/TriggeredAbilities.java
+++ b/Mage/src/mage/abilities/TriggeredAbilities.java
@@ -73,7 +73,6 @@ public class TriggeredAbilities extends ConcurrentHashMap 0) {
diff --git a/Mage/src/mage/abilities/keyword/SuspendAbility.java b/Mage/src/mage/abilities/keyword/SuspendAbility.java
index 7cff82d2a2b..56297784769 100644
--- a/Mage/src/mage/abilities/keyword/SuspendAbility.java
+++ b/Mage/src/mage/abilities/keyword/SuspendAbility.java
@@ -176,15 +176,48 @@ public class SuspendAbility extends ActivatedAbilityImpl {
.append(card.getCardType().contains(CardType.CREATURE)? " If you play it this way and it's a creature, it gains haste until you lose control of it.":"")
.append(")");
}
- } else {
- gainedTemporary = true;
+ if (card.getManaCost().isEmpty()) {
+ setRuleAtTheTop(true);
+ }
+ card.addAbility(new SuspendBeginningOfUpkeepTriggeredAbility());
+ card.addAbility(new SuspendPlayCardAbility(card.getCardType().contains(CardType.CREATURE)));
}
ruleText = sb.toString();
- if (card.getManaCost().isEmpty()) {
- setRuleAtTheTop(true);
- }
- card.addAbility(new SuspendBeginningOfUpkeepTriggeredAbility());
- card.addAbility(new SuspendPlayCardAbility(card.getCardType().contains(CardType.CREATURE)));
+ }
+
+ /**
+ * Adds suspend to a card that does not have it regularly
+ * e.g. Epochrasite or added by Jhoira of the Ghitu
+ * @param card
+ * @param source
+ * @param game
+ */
+ public static void addSuspendTemporaryToCard(Card card, Ability source, Game game) {
+ SuspendAbility ability = new SuspendAbility(0, null, card, false);
+ ability.setSourceId(card.getId());
+ ability.setControllerId(card.getOwnerId());
+ game.getState().addOtherAbility(card.getId(), ability);
+
+ SuspendBeginningOfUpkeepTriggeredAbility ability1 = new SuspendBeginningOfUpkeepTriggeredAbility();
+ ability1.setSourceId(card.getId());
+ ability1.setControllerId(card.getOwnerId());
+ game.getState().addOtherAbility(card.getId(), ability1);
+ game.getState().addAbility(ability1, source.getSourceId(), card);
+
+ SuspendPlayCardAbility ability2 = new SuspendPlayCardAbility(card.getCardType().contains(CardType.CREATURE));
+ ability2.setSourceId(card.getId());
+ ability2.setControllerId(card.getOwnerId());
+ game.getState().addOtherAbility(card.getId(), ability2);
+ game.getState().addAbility(ability2, source.getSourceId(), card);
+ }
+
+ public static UUID getSuspendExileId(UUID controllerId, Game game) {
+ UUID exileId = (UUID) game.getState().getValue("SuspendExileId" + controllerId.toString());
+ if (exileId == null) {
+ exileId = UUID.randomUUID();
+ game.getState().setValue("SuspendExileId" + controllerId.toString(), exileId);
+ }
+ return exileId;
}
public SuspendAbility(SuspendAbility ability) {
@@ -248,12 +281,8 @@ class SuspendExileEffect extends OneShotEffect {
return false;
}
}
- UUID exileId = (UUID) game.getState().getValue("SuspendExileId" + source.getControllerId().toString());
- if (exileId == null) {
- exileId = UUID.randomUUID();
- game.getState().setValue("SuspendExileId" + source.getControllerId().toString(), exileId);
- }
- if (card.moveToExile(exileId, new StringBuilder("Suspended cards of ").append(controller.getName()).toString() , source.getSourceId(), game)) {
+ UUID exileId = SuspendAbility.getSuspendExileId(controller.getId(), game);
+ if (controller.moveCardToExileWithInfo(card, exileId, "Suspended cards of " + controller.getName(), source.getSourceId(), game, Zone.HAND)) {
if (suspend == Integer.MAX_VALUE) {
suspend = source.getManaCostsToPay().getX();
}
@@ -312,7 +341,7 @@ class SuspendPlayCardEffect extends OneShotEffect {
public SuspendPlayCardEffect(boolean isCreature) {
super(Outcome.PutCardInPlay);
- this.staticText = "play it without paying its mana cost if able. If you can't, it remains removed from the game";
+ this.staticText = "play it without paying its mana cost if able. If you can't, it remains removed from the game";
}
public SuspendPlayCardEffect(final SuspendPlayCardEffect effect) {
@@ -380,7 +409,7 @@ class GainHasteEffect extends ContinuousEffectImpl {
}
Permanent permanent = game.getPermanent(source.getSourceId());
if (permanent != null) {
- if (suspendController.equals(source.getControllerId())) {
+ if (suspendController.equals(source.getControllerId())) {
permanent.addAbility(HasteAbility.getInstance(), source.getSourceId(), game);
return true;
} else {
diff --git a/Mage/src/mage/game/GameState.java b/Mage/src/mage/game/GameState.java
index 3f19d3c2526..1924a9ec3f0 100644
--- a/Mage/src/mage/game/GameState.java
+++ b/Mage/src/mage/game/GameState.java
@@ -701,6 +701,16 @@ public class GameState implements Serializable, Copyable {
}
}
+ /**
+ * Adds the ability to continuous or triggered abilities
+ * @param ability
+ * @param card
+ */
+ public void addOtherAbility(Ability ability, Card card) {
+ addOtherAbility(card.getId(), ability);
+ addAbility(ability, card.getId(), card);
+ }
+
private void resetOtherAbilities() {
otherAbilities.clear();
}