diff --git a/Mage.Sets/src/mage/sets/avacynrestored/Cloudshift.java b/Mage.Sets/src/mage/sets/avacynrestored/Cloudshift.java index 72f9fb906f..67a111bba7 100644 --- a/Mage.Sets/src/mage/sets/avacynrestored/Cloudshift.java +++ b/Mage.Sets/src/mage/sets/avacynrestored/Cloudshift.java @@ -50,8 +50,8 @@ public class Cloudshift extends CardImpl { // Exile target creature you control, then return that card to the battlefield under your control. this.getSpellAbility().addTarget(new TargetControlledCreaturePermanent()); - this.getSpellAbility().addEffect(new ExileTargetForSourceEffect("Cloudshift")); - this.getSpellAbility().addEffect(new ReturnToBattlefieldUnderYourControlTargetEffect()); + this.getSpellAbility().addEffect(new ExileTargetForSourceEffect()); + this.getSpellAbility().addEffect(new ReturnToBattlefieldUnderYourControlTargetEffect(true)); } public Cloudshift(final Cloudshift card) { diff --git a/Mage.Sets/src/mage/sets/avacynrestored/ConjurersCloset.java b/Mage.Sets/src/mage/sets/avacynrestored/ConjurersCloset.java index 8ebd02418f..bd9efe6f81 100644 --- a/Mage.Sets/src/mage/sets/avacynrestored/ConjurersCloset.java +++ b/Mage.Sets/src/mage/sets/avacynrestored/ConjurersCloset.java @@ -48,8 +48,8 @@ public class ConjurersCloset extends CardImpl { this.expansionSetCode = "AVR"; // At the beginning of your end step, you may exile target creature you control, then return that card to the battlefield under your control. - Ability ability = new BeginningOfYourEndStepTriggeredAbility(new ExileTargetForSourceEffect("Conjurer's Closet Exile"), true); - ability.addEffect(new ReturnToBattlefieldUnderYourControlTargetEffect()); + Ability ability = new BeginningOfYourEndStepTriggeredAbility(new ExileTargetForSourceEffect(), true); + ability.addEffect(new ReturnToBattlefieldUnderYourControlTargetEffect(true)); ability.addTarget(new TargetControlledCreaturePermanent()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/sets/avacynrestored/NephaliaSmuggler.java b/Mage.Sets/src/mage/sets/avacynrestored/NephaliaSmuggler.java index a99bb63730..4fd8a9d678 100644 --- a/Mage.Sets/src/mage/sets/avacynrestored/NephaliaSmuggler.java +++ b/Mage.Sets/src/mage/sets/avacynrestored/NephaliaSmuggler.java @@ -58,9 +58,9 @@ public class NephaliaSmuggler extends CardImpl { this.toughness = new MageInt(1); // {3}{U}, {tap}: Exile another target creature you control, then return that card to the battlefield under your control. - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new ExileTargetForSourceEffect("Exile Nephalia Smuggler"), new ManaCostsImpl("{3}{U}")); + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new ExileTargetForSourceEffect(), new ManaCostsImpl("{3}{U}")); ability.addCost(new TapSourceCost()); - ability.addEffect(new ReturnToBattlefieldUnderYourControlTargetEffect()); + ability.addEffect(new ReturnToBattlefieldUnderYourControlTargetEffect(true)); ability.addTarget(new TargetControlledCreaturePermanent()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/sets/championsofkamigawa/EyeOfNowhere.java b/Mage.Sets/src/mage/sets/championsofkamigawa/EyeOfNowhere.java index 5d97d39171..f8eaab5b94 100644 --- a/Mage.Sets/src/mage/sets/championsofkamigawa/EyeOfNowhere.java +++ b/Mage.Sets/src/mage/sets/championsofkamigawa/EyeOfNowhere.java @@ -45,7 +45,8 @@ public class EyeOfNowhere extends CardImpl { super(ownerId, 59, "Eye of Nowhere", Rarity.COMMON, new CardType[]{CardType.SORCERY}, "{U}{U}"); this.expansionSetCode = "CHK"; this.subtype.add("Arcane"); - this.color.setBlue(true); + + // Return target permanent to its owner's hand. this.getSpellAbility().addEffect(new ReturnToHandTargetEffect()); this.getSpellAbility().addTarget(new TargetPermanent()); diff --git a/Mage.Sets/src/mage/sets/coldsnap/AdarkarValkyrie.java b/Mage.Sets/src/mage/sets/coldsnap/AdarkarValkyrie.java index ac9f547e44..edacb69093 100644 --- a/Mage.Sets/src/mage/sets/coldsnap/AdarkarValkyrie.java +++ b/Mage.Sets/src/mage/sets/coldsnap/AdarkarValkyrie.java @@ -77,7 +77,7 @@ public class AdarkarValkyrie extends CardImpl { this.addAbility(FlyingAbility.getInstance()); // Vigilance this.addAbility(VigilanceAbility.getInstance()); - // {tap}: When target creature other than Adarkar Valkyrie dies this turn, return that card to the battlefield under your control. + // {T}: When target creature other than Adarkar Valkyrie dies this turn, return that card to the battlefield under your control. Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new AdarkarValkyrieEffect(), new TapSourceCost()); Target target = new TargetCreaturePermanent(filter); ability.addTarget(target); @@ -98,7 +98,7 @@ class AdarkarValkyrieEffect extends OneShotEffect { public AdarkarValkyrieEffect() { super(Outcome.PutCreatureInPlay); - this.staticText = "When target creature other than Adarkar Valkyrie dies this turn, return that card to the battlefield under your control"; + this.staticText = "When target creature other than {this} dies this turn, return that card to the battlefield under your control"; } public AdarkarValkyrieEffect(final AdarkarValkyrieEffect effect) { diff --git a/Mage.Sets/src/mage/sets/darkascension/Helvault.java b/Mage.Sets/src/mage/sets/darkascension/Helvault.java index 727bb68a5b..955b27cf4e 100644 --- a/Mage.Sets/src/mage/sets/darkascension/Helvault.java +++ b/Mage.Sets/src/mage/sets/darkascension/Helvault.java @@ -62,12 +62,12 @@ public class Helvault extends CardImpl { this.supertype.add("Legendary"); // {1}, {tap}: Exile target creature you control. - SimpleActivatedAbility ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new ExileTargetForSourceEffect("Helvault exile"), new GenericManaCost(1)); + SimpleActivatedAbility ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new ExileTargetForSourceEffect(), new GenericManaCost(1)); ability.addCost(new TapSourceCost()); ability.addTarget(new TargetControlledCreaturePermanent()); this.addAbility(ability); // {7}, {tap}: Exile target creature you don't control. - ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new ExileTargetForSourceEffect("Helvault exile"), new GenericManaCost(7)); + ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new ExileTargetForSourceEffect(), new GenericManaCost(7)); ability.addCost(new TapSourceCost()); ability.addTarget(new TargetCreaturePermanent(filter)); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/sets/iceage/IcyPrison.java b/Mage.Sets/src/mage/sets/iceage/IcyPrison.java index a6d24ee65e..7f948ad3f0 100644 --- a/Mage.Sets/src/mage/sets/iceage/IcyPrison.java +++ b/Mage.Sets/src/mage/sets/iceage/IcyPrison.java @@ -42,8 +42,6 @@ import mage.constants.CardType; import mage.constants.Rarity; import mage.constants.TargetController; import mage.constants.Zone; -import mage.target.Target; -import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -59,7 +57,7 @@ public class IcyPrison extends CardImpl { this.color.setBlue(true); // When Icy Prison enters the battlefield, exile target creature. - Ability ability1 = new EntersBattlefieldTriggeredAbility(new ExileTargetForSourceEffect(this.getLogName()), false); + Ability ability1 = new EntersBattlefieldTriggeredAbility(new ExileTargetForSourceEffect(), false); ability1.addTarget(new TargetCreaturePermanent()); this.addAbility(ability1); diff --git a/Mage.Sets/src/mage/sets/innistrad/FiendHunter.java b/Mage.Sets/src/mage/sets/innistrad/FiendHunter.java index 1a1c9ad8f7..019c9835ca 100644 --- a/Mage.Sets/src/mage/sets/innistrad/FiendHunter.java +++ b/Mage.Sets/src/mage/sets/innistrad/FiendHunter.java @@ -65,7 +65,7 @@ public class FiendHunter extends CardImpl { this.toughness = new MageInt(3); // When Fiend Hunter enters the battlefield, you may exile another target creature. - Ability ability1 = new EntersBattlefieldTriggeredAbility(new ExileTargetForSourceEffect("Fiend Hunter Exile"), true); + Ability ability1 = new EntersBattlefieldTriggeredAbility(new ExileTargetForSourceEffect(), true); Target target = new TargetPermanent(filter); ability1.addTarget(target); this.addAbility(ability1); diff --git a/Mage.Sets/src/mage/sets/mirrodinbesieged/LeoninRelicWarder.java b/Mage.Sets/src/mage/sets/mirrodinbesieged/LeoninRelicWarder.java index 1d6f222766..7eceb4ea4f 100644 --- a/Mage.Sets/src/mage/sets/mirrodinbesieged/LeoninRelicWarder.java +++ b/Mage.Sets/src/mage/sets/mirrodinbesieged/LeoninRelicWarder.java @@ -68,7 +68,7 @@ public class LeoninRelicWarder extends CardImpl { this.power = new MageInt(2); this.toughness = new MageInt(2); - Ability ability = new EntersBattlefieldTriggeredAbility(new ExileTargetForSourceEffect("Leonin Relic-Warder exile"), true); + Ability ability = new EntersBattlefieldTriggeredAbility(new ExileTargetForSourceEffect(), true); Target target = new TargetPermanent(filter); ability.addTarget(target); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/sets/nemesis/ParallaxTide.java b/Mage.Sets/src/mage/sets/nemesis/ParallaxTide.java index 902ad75d58..cca958df92 100644 --- a/Mage.Sets/src/mage/sets/nemesis/ParallaxTide.java +++ b/Mage.Sets/src/mage/sets/nemesis/ParallaxTide.java @@ -58,7 +58,7 @@ public class ParallaxTide extends CardImpl { // Fading 5 this.addAbility(new FadingAbility(5, this)); // Remove a fade counter from Parallax Tide: Exile target land. - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new ExileTargetForSourceEffect("Parallax Tide Exile"), new RemoveCountersSourceCost(CounterType.FADE.createInstance())); + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new ExileTargetForSourceEffect(), new RemoveCountersSourceCost(CounterType.FADE.createInstance())); ability.addTarget(new TargetLandPermanent()); this.addAbility(ability); // When Parallax Tide leaves the battlefield, each player returns to the battlefield all cards he or she owns exiled with Parallax Tide. diff --git a/Mage.Sets/src/mage/sets/ravnika/GolgariBrownscale.java b/Mage.Sets/src/mage/sets/ravnika/GolgariBrownscale.java new file mode 100644 index 0000000000..fae9628674 --- /dev/null +++ b/Mage.Sets/src/mage/sets/ravnika/GolgariBrownscale.java @@ -0,0 +1,69 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.ravnika; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.ZoneChangeTriggeredAbility; +import mage.abilities.effects.common.GainLifeEffect; +import mage.abilities.keyword.DredgeAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.constants.Zone; + +/** + * + * @author LevelX2 + */ +public class GolgariBrownscale extends CardImpl { + + public GolgariBrownscale(UUID ownerId) { + super(ownerId, 166, "Golgari Brownscale", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{1}{G}{G}"); + this.expansionSetCode = "RAV"; + this.subtype.add("Lizard"); + this.power = new MageInt(2); + this.toughness = new MageInt(3); + + // When Golgari Brownscale is put into your hand from your graveyard, you gain 2 life. + this.addAbility(new ZoneChangeTriggeredAbility(Zone.ALL, Zone.GRAVEYARD, Zone.HAND, new GainLifeEffect(2), + "When {this} is put into your hand from your graveyard,", false)); + + // Dredge 2 + this.addAbility(new DredgeAbility(2)); + } + + public GolgariBrownscale(final GolgariBrownscale card) { + super(card); + } + + @Override + public GolgariBrownscale copy() { + return new GolgariBrownscale(this); + } +} diff --git a/Mage.Sets/src/mage/sets/shardsofalara/OblivionRing.java b/Mage.Sets/src/mage/sets/shardsofalara/OblivionRing.java index 1c61973c1c..c6b56c48d3 100644 --- a/Mage.Sets/src/mage/sets/shardsofalara/OblivionRing.java +++ b/Mage.Sets/src/mage/sets/shardsofalara/OblivionRing.java @@ -61,7 +61,7 @@ public class OblivionRing extends CardImpl { this.color.setWhite(true); // When Oblivion Ring enters the battlefield, exile another target nonland permanent. - Ability ability1 = new EntersBattlefieldTriggeredAbility(new ExileTargetForSourceEffect( "Oblivion Ring exile"), false); + Ability ability1 = new EntersBattlefieldTriggeredAbility(new ExileTargetForSourceEffect(), false); Target target = new TargetPermanent(anotherNonlandPermanent); ability1.addTarget(target); this.addAbility(ability1); diff --git a/Mage.Sets/src/mage/sets/stronghold/SacredGround.java b/Mage.Sets/src/mage/sets/stronghold/SacredGround.java index dcc6df53c0..f7ab63d010 100644 --- a/Mage.Sets/src/mage/sets/stronghold/SacredGround.java +++ b/Mage.Sets/src/mage/sets/stronghold/SacredGround.java @@ -30,7 +30,6 @@ package mage.sets.stronghold; import java.util.UUID; import mage.MageObject; -import mage.abilities.ActivatedAbility; import mage.abilities.TriggeredAbilityImpl; import mage.abilities.effects.common.ReturnToBattlefieldUnderYourControlTargetEffect; import mage.cards.CardImpl; @@ -41,8 +40,6 @@ import mage.game.Game; import mage.game.events.GameEvent; import mage.game.events.ZoneChangeEvent; import mage.game.permanent.Permanent; -import mage.game.stack.Spell; -import mage.game.stack.StackAbility; import mage.game.stack.StackObject; import mage.target.targetpointer.FixedTarget; diff --git a/Mage.Sets/src/mage/sets/theros/TriadOfFates.java b/Mage.Sets/src/mage/sets/theros/TriadOfFates.java index 718bc067c5..ba3e38cf3b 100644 --- a/Mage.Sets/src/mage/sets/theros/TriadOfFates.java +++ b/Mage.Sets/src/mage/sets/theros/TriadOfFates.java @@ -67,7 +67,7 @@ public class TriadOfFates extends CardImpl { } public TriadOfFates(UUID ownerId) { - super(ownerId, 206, "Triad of Fates", Rarity.RARE, new CardType[]{CardType.CREATURE}, "{2}{W}{B}"); + super(ownerId, 206, "Triad of Fates", Rarity.RARE, new CardType[]{CardType.CREATURE}, "{2}{W}{B}"); this.expansionSetCode = "THS"; this.supertype.add("Legendary"); this.subtype.add("Human"); @@ -85,7 +85,7 @@ public class TriadOfFates extends CardImpl { ability.addTarget(target); this.addAbility(ability); // {W}, {T}: Exile target creature that has a fate counter on it, then return it to the battlefield under its owner's control. - ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new ExileTargetForSourceEffect("Triad of Fates"), new ManaCostsImpl("{W}")); + ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new ExileTargetForSourceEffect(), new ManaCostsImpl("{W}")); ability.addCost(new TapSourceCost()); target = new TargetCreaturePermanent(filterCounter); ability.addTarget(target); diff --git a/Mage.Sets/src/mage/sets/timespiral/MomentaryBlink.java b/Mage.Sets/src/mage/sets/timespiral/MomentaryBlink.java index 681ea1827f..a7eacc061e 100644 --- a/Mage.Sets/src/mage/sets/timespiral/MomentaryBlink.java +++ b/Mage.Sets/src/mage/sets/timespiral/MomentaryBlink.java @@ -52,8 +52,8 @@ public class MomentaryBlink extends CardImpl { // Exile target creature you control, then return it to the battlefield under its owner's control. this.getSpellAbility().addTarget(new TargetControlledCreaturePermanent()); - this.getSpellAbility().addEffect(new ExileTargetForSourceEffect("Momentary Blink")); - this.getSpellAbility().addEffect(new ReturnToBattlefieldUnderYourControlTargetEffect()); + this.getSpellAbility().addEffect(new ExileTargetForSourceEffect()); + this.getSpellAbility().addEffect(new ReturnToBattlefieldUnderYourControlTargetEffect(true)); // Flashback {3}{U} this.addAbility(new FlashbackAbility(new ManaCostsImpl("{3}{U}"), TimingRule.INSTANT)); diff --git a/Mage.Sets/src/mage/sets/worldwake/AdmonitionAngel.java b/Mage.Sets/src/mage/sets/worldwake/AdmonitionAngel.java index ece4530e94..a6e87bccd0 100644 --- a/Mage.Sets/src/mage/sets/worldwake/AdmonitionAngel.java +++ b/Mage.Sets/src/mage/sets/worldwake/AdmonitionAngel.java @@ -73,7 +73,7 @@ public class AdmonitionAngel extends CardImpl { this.addAbility(FlyingAbility.getInstance()); // Landfall - Whenever a land enters the battlefield under your control, you may exile target nonland permanent other than Admonition Angel. - TriggeredAbility ability = new LandfallAbility(Zone.BATTLEFIELD, new ExileTargetForSourceEffect("Admonition Angel Exile"), true); + TriggeredAbility ability = new LandfallAbility(Zone.BATTLEFIELD, new ExileTargetForSourceEffect(), true); ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/sets/worldwake/RuinGhost.java b/Mage.Sets/src/mage/sets/worldwake/RuinGhost.java index 5c5cc154c2..87c20f8664 100644 --- a/Mage.Sets/src/mage/sets/worldwake/RuinGhost.java +++ b/Mage.Sets/src/mage/sets/worldwake/RuinGhost.java @@ -66,9 +66,9 @@ public class RuinGhost extends CardImpl { this.toughness = new MageInt(1); // {W}, {tap}: Exile target land you control, then return it to the battlefield under your control. - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new ExileTargetForSourceEffect("Exile Ruin Ghost"), new ManaCostsImpl("{W")); + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new ExileTargetForSourceEffect(), new ManaCostsImpl("{W")); ability.addCost(new TapSourceCost()); - ability.addEffect(new ReturnToBattlefieldUnderYourControlTargetEffect()); + ability.addEffect(new ReturnToBattlefieldUnderYourControlTargetEffect(true)); ability.addTarget(new TargetControlledPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/sets/zendikar/JourneyToNowhere.java b/Mage.Sets/src/mage/sets/zendikar/JourneyToNowhere.java index 1cc6e2e20b..886918dca7 100644 --- a/Mage.Sets/src/mage/sets/zendikar/JourneyToNowhere.java +++ b/Mage.Sets/src/mage/sets/zendikar/JourneyToNowhere.java @@ -53,12 +53,16 @@ public class JourneyToNowhere extends CardImpl { super(ownerId, 14, "Journey to Nowhere", Rarity.COMMON, new CardType[]{CardType.ENCHANTMENT}, "{1}{W}"); this.expansionSetCode = "ZEN"; this.color.setWhite(true); + + // When Journey to Nowhere enters the battlefield, exile target creature. FilterCreaturePermanent filter = new FilterCreaturePermanent(); filter.add(new AnotherPredicate()); - Ability ability1 = new EntersBattlefieldTriggeredAbility(new ExileTargetForSourceEffect("Journey to Nowhere exile"), false); + Ability ability1 = new EntersBattlefieldTriggeredAbility(new ExileTargetForSourceEffect(), false); Target target = new TargetPermanent(filter); ability1.addTarget(target); this.addAbility(ability1); + + // When Journey to Nowhere leaves the battlefield, return the exiled card to the battlefield under its owner's control. Ability ability2 = new LeavesBattlefieldTriggeredAbility(new ReturnFromExileForSourceEffect(Zone.BATTLEFIELD), false); this.addAbility(ability2); } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/triggers/JournexToNowhereTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/triggers/JournexToNowhereTest.java new file mode 100644 index 0000000000..ddb20debb0 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/triggers/JournexToNowhereTest.java @@ -0,0 +1,155 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package org.mage.test.cards.triggers; + +import mage.constants.PhaseStep; +import mage.constants.Zone; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * + * @author LeveX2 + */ + +public class JournexToNowhereTest extends CardTestPlayerBase { + + /* + Journey to Nowhere Enchantment {1}{W} + When Journey to Nowhere enters the battlefield, exile target creature. + When Journey to Nowhere leaves the battlefield, return the exiled card to the battlefield under its owner's control. + + 10/1/2009: If Journey to Nowhere leaves the battlefield before its first ability has resolved, its second ability will + trigger and do nothing. Then its first ability will resolve and exile the targeted creature forever. + */ + + @Test + public void testTargetGetsExiled() { + addCard(Zone.HAND, playerA, "Journey to Nowhere"); + addCard(Zone.BATTLEFIELD, playerA, "Plains", 2); + + addCard(Zone.BATTLEFIELD, playerB, "Silvercoat Lion", 1); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Journey to Nowhere"); + addTarget(playerA, "Silvercoat Lion"); + setStopAt(1, PhaseStep.BEGIN_COMBAT); + execute(); + + assertPermanentCount(playerA, "Journey to Nowhere", 1); + assertExileCount("Silvercoat Lion", 1); + } + + + @Test + public void testTargetGetsExiledAndReturns() { + addCard(Zone.HAND, playerA, "Journey to Nowhere"); + addCard(Zone.BATTLEFIELD, playerA, "Plains", 2); + + addCard(Zone.HAND, playerB, "Disenchant", 1); + addCard(Zone.BATTLEFIELD, playerB, "Silvercoat Lion", 1); + addCard(Zone.BATTLEFIELD, playerB, "Plains", 2); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Journey to Nowhere"); + addTarget(playerA, "Silvercoat Lion"); + + castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerB, "Disenchant", "Journey to Nowhere"); + + setStopAt(1, PhaseStep.END_TURN); + execute(); + + assertGraveyardCount(playerA, "Journey to Nowhere", 1); + assertGraveyardCount(playerB, "Disenchant", 1); + assertPermanentCount(playerB, "Silvercoat Lion", 1); + } + + /* + 10/1/2009: If Journey to Nowhere leaves the battlefield before its first ability has resolved, its second ability will + trigger and do nothing. Then its first ability will resolve and exile the targeted creature forever. + */ + @Test + public void testTargetGetsExiledAndDoesNeverReturn() { + addCard(Zone.HAND, playerA, "Journey to Nowhere"); + addCard(Zone.BATTLEFIELD, playerA, "Plains", 2); + + addCard(Zone.HAND, playerB, "Disenchant", 1); + addCard(Zone.BATTLEFIELD, playerB, "Silvercoat Lion", 1); + addCard(Zone.BATTLEFIELD, playerB, "Plains", 2); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Journey to Nowhere"); + addTarget(playerA, "Silvercoat Lion"); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerB, "Disenchant", "Journey to Nowhere"); + + setStopAt(1, PhaseStep.BEGIN_COMBAT); + execute(); + + assertGraveyardCount(playerA, "Journey to Nowhere", 1); + assertGraveyardCount(playerB, "Disenchant", 1); + assertExileCount("Silvercoat Lion", 1); + } + + /* + Journey is played and targets the creature as it enters the battlefield. + The Journey will be returned to hand before the ability reolves. + The Journey will be played again targeting another creature. + The journey will be disencahnted later, so only the second creatufre has to return to battlefield. + + */ + @Test + public void testTargetGetsExiledAndDoesNeverReturnAndJourneyPlayedAgain() { + addCard(Zone.HAND, playerA, "Journey to Nowhere"); + addCard(Zone.HAND, playerA, "Boomerang"); + addCard(Zone.BATTLEFIELD, playerA, "Plains", 4); + addCard(Zone.BATTLEFIELD, playerA, "Island", 4); + + addCard(Zone.HAND, playerB, "Disenchant", 1); + addCard(Zone.BATTLEFIELD, playerB, "Silvercoat Lion", 1); + addCard(Zone.BATTLEFIELD, playerB, "Pillarfield Ox", 1); + addCard(Zone.BATTLEFIELD, playerB, "Plains", 2); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Journey to Nowhere"); + addTarget(playerA, "Silvercoat Lion"); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Boomerang", "Journey to Nowhere"); + + castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Journey to Nowhere"); + addTarget(playerA, "Pillarfield Ox"); + + castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerB, "Disenchant", "Journey to Nowhere"); + + setStopAt(2, PhaseStep.BEGIN_COMBAT); + execute(); + + assertGraveyardCount(playerA, "Boomerang", 1); + assertGraveyardCount(playerA, "Journey to Nowhere", 1); + assertGraveyardCount(playerB, "Disenchant", 1); + assertPermanentCount(playerB, "Pillarfield Ox", 1); + + assertPermanentCount(playerB, "Silvercoat Lion", 0); + assertExileCount("Silvercoat Lion", 1); + + } +} diff --git a/Mage/src/mage/abilities/Ability.java b/Mage/src/mage/abilities/Ability.java index 887f45de75..85e3526ea9 100644 --- a/Mage/src/mage/abilities/Ability.java +++ b/Mage/src/mage/abilities/Ability.java @@ -476,5 +476,22 @@ public interface Ability extends Controllable, Serializable { void setCostModificationActive(boolean active); boolean activateAlternateOrAdditionalCosts(MageObject sourceObject, boolean noMana, Player controller, Game game); - + + /** + * Sets the object that actually existed while a ability triggerd or + * an ability was activated. + * + * @param mageObject + */ + void setSourceObject(MageObject mageObject); + + /** + * Returns the object that actually existed while a ability triggerd or + * an ability was activated. + * If not set yet, the current object will be retrieved from the game. + * + * @param game + * @return + */ + MageObject getSourceObject(Game game); } diff --git a/Mage/src/mage/abilities/AbilityImpl.java b/Mage/src/mage/abilities/AbilityImpl.java index 618fa05bca..38755cd223 100644 --- a/Mage/src/mage/abilities/AbilityImpl.java +++ b/Mage/src/mage/abilities/AbilityImpl.java @@ -106,6 +106,7 @@ public abstract class AbilityImpl implements Ability { protected boolean costModificationActive = true; protected boolean activated = false; protected boolean worksFaceDown = false; + protected MageObject sourceObject; public AbilityImpl(AbilityType abilityType, Zone zone) { this.id = UUID.randomUUID(); @@ -142,6 +143,7 @@ public abstract class AbilityImpl implements Ability { this.costModificationActive = ability.costModificationActive; this.worksFaceDown = ability.worksFaceDown; this.abilityWord = ability.abilityWord; + this.sourceObject = ability.sourceObject; } @Override @@ -230,7 +232,7 @@ public abstract class AbilityImpl implements Ability { // TODO: Because all (non targeted) choices have to be done during resolution // this has to be removed, if all using effects are changed - MageObject sourceObject = game.getObject(sourceId); + sourceObject = game.getObject(sourceId); if (sourceObject != null) { sourceObject.adjustChoices(this, game); } @@ -1024,6 +1026,19 @@ public abstract class AbilityImpl implements Ability { this.worksFaceDown = worksFaceDown; } + @Override + public MageObject getSourceObject(Game game) { + if (sourceObject != null) { + return sourceObject; + } else { + return game.getObject(sourceId); + } + } + + @Override + public void setSourceObject(MageObject sourceObject) { + this.sourceObject = sourceObject; + } } diff --git a/Mage/src/mage/abilities/TriggeredAbility.java b/Mage/src/mage/abilities/TriggeredAbility.java index 7287003a3b..0ad798a101 100644 --- a/Mage/src/mage/abilities/TriggeredAbility.java +++ b/Mage/src/mage/abilities/TriggeredAbility.java @@ -44,5 +44,5 @@ public interface TriggeredAbility extends Ability { boolean checkTrigger(GameEvent event, Game game); boolean checkInterveningIfClause(Game game); TriggeredAbility copy(); - void setSourceObject(MageObject mageObject); + } diff --git a/Mage/src/mage/abilities/TriggeredAbilityImpl.java b/Mage/src/mage/abilities/TriggeredAbilityImpl.java index 92fe31385f..1b4f2ba9c3 100644 --- a/Mage/src/mage/abilities/TriggeredAbilityImpl.java +++ b/Mage/src/mage/abilities/TriggeredAbilityImpl.java @@ -43,7 +43,6 @@ import mage.players.Player; public abstract class TriggeredAbilityImpl extends AbilityImpl implements TriggeredAbility { protected boolean optional; - protected MageObject sourceObject; public TriggeredAbilityImpl(Zone zone, Effect effect) { this(zone, effect, false); @@ -152,12 +151,4 @@ public abstract class TriggeredAbilityImpl extends AbilityImpl implements Trigge return sb.toString(); } - public MageObject getSourceObject() { - return sourceObject; - } - - @Override - public void setSourceObject(MageObject sourceObject) { - this.sourceObject = sourceObject; - } } diff --git a/Mage/src/mage/abilities/common/LeavesBattlefieldTriggeredAbility.java b/Mage/src/mage/abilities/common/LeavesBattlefieldTriggeredAbility.java index b013b4c8ad..6bc8fdad61 100644 --- a/Mage/src/mage/abilities/common/LeavesBattlefieldTriggeredAbility.java +++ b/Mage/src/mage/abilities/common/LeavesBattlefieldTriggeredAbility.java @@ -30,6 +30,8 @@ package mage.abilities.common; import mage.constants.Zone; import mage.abilities.effects.Effect; +import mage.game.Game; +import mage.game.events.GameEvent; /** * diff --git a/Mage/src/mage/abilities/common/ZoneChangeTriggeredAbility.java b/Mage/src/mage/abilities/common/ZoneChangeTriggeredAbility.java index 1183523e33..9922255cfd 100644 --- a/Mage/src/mage/abilities/common/ZoneChangeTriggeredAbility.java +++ b/Mage/src/mage/abilities/common/ZoneChangeTriggeredAbility.java @@ -49,12 +49,16 @@ public class ZoneChangeTriggeredAbility extends TriggeredAbilityImpl { protected String rule; public ZoneChangeTriggeredAbility(Zone fromZone, Zone toZone, Effect effect, String rule, boolean optional) { - super(fromZone, effect, optional); + this(fromZone, fromZone, toZone, effect, rule, optional); + } + + public ZoneChangeTriggeredAbility(Zone worksInZone, Zone fromZone, Zone toZone, Effect effect, String rule, boolean optional) { + super(worksInZone, effect, optional); this.fromZone = fromZone; this.toZone = toZone; this.rule = rule; } - + public ZoneChangeTriggeredAbility(Zone toZone, Effect effect, String rule, boolean optional) { super(toZone, effect, optional); this.fromZone = null; @@ -62,7 +66,7 @@ public class ZoneChangeTriggeredAbility extends TriggeredAbilityImpl { this.rule = rule; } - public ZoneChangeTriggeredAbility(ZoneChangeTriggeredAbility ability) { + public ZoneChangeTriggeredAbility(final ZoneChangeTriggeredAbility ability) { super(ability); this.fromZone = ability.fromZone; this.toZone = ability.toZone; diff --git a/Mage/src/mage/abilities/effects/common/CastSourceTriggeredAbility.java b/Mage/src/mage/abilities/effects/common/CastSourceTriggeredAbility.java index 0825e84864..3a951bb9ef 100644 --- a/Mage/src/mage/abilities/effects/common/CastSourceTriggeredAbility.java +++ b/Mage/src/mage/abilities/effects/common/CastSourceTriggeredAbility.java @@ -27,6 +27,7 @@ */ package mage.abilities.effects.common; +import mage.MageObject; import mage.abilities.TriggeredAbilityImpl; import mage.abilities.effects.Effect; import mage.constants.Zone; @@ -62,8 +63,9 @@ public class CastSourceTriggeredAbility extends TriggeredAbilityImpl { @Override public boolean checkTrigger(GameEvent event, Game game) { if (event.getType().equals(GameEvent.EventType.SPELL_CAST) && event.getSourceId().equals(this.getSourceId())) { - if (getSourceObject() != null && getSourceObject() instanceof Spell) { - Spell spell = (Spell)getSourceObject(); + MageObject sourceObject = getSourceObject(game); + if (sourceObject != null && (sourceObject instanceof Spell)) { + Spell spell = (Spell)sourceObject; if (spell.getSpellAbility() != null) { for (Effect effect : getEffects()) { effect.setValue(SOURCE_CAST_SPELL_ABILITY, spell.getSpellAbility()); diff --git a/Mage/src/mage/abilities/effects/common/ExileTargetForSourceEffect.java b/Mage/src/mage/abilities/effects/common/ExileTargetForSourceEffect.java index 7d37467bc2..f4da07a7af 100644 --- a/Mage/src/mage/abilities/effects/common/ExileTargetForSourceEffect.java +++ b/Mage/src/mage/abilities/effects/common/ExileTargetForSourceEffect.java @@ -29,15 +29,19 @@ package mage.abilities.effects.common; import java.util.UUID; +import mage.MageObject; import mage.abilities.Ability; import mage.abilities.Mode; +import mage.abilities.TriggeredAbilityImpl; import mage.abilities.effects.OneShotEffect; import mage.cards.Card; +import mage.constants.AbilityType; import mage.constants.Outcome; import mage.constants.Zone; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; +import mage.util.CardUtil; /** * @@ -45,12 +49,6 @@ import mage.players.Player; */ public class ExileTargetForSourceEffect extends OneShotEffect { - private String exileZone = null; - - public ExileTargetForSourceEffect(String exileZone) { - this(); - this.exileZone = exileZone; - } public ExileTargetForSourceEffect() { super(Outcome.Exile); @@ -58,7 +56,6 @@ public class ExileTargetForSourceEffect extends OneShotEffect { public ExileTargetForSourceEffect(final ExileTargetForSourceEffect effect) { super(effect); - this.exileZone = effect.exileZone; } @Override @@ -69,15 +66,16 @@ public class ExileTargetForSourceEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - if (controller != null) { - Permanent permanent = game.getPermanent(targetPointer.getFirst(game, source)); - UUID exileId = source.getSourceId(); + MageObject sourceObject = source.getSourceObject(game); + if (controller != null && sourceObject != null) { + Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source)); + UUID exileId = CardUtil.getObjectExileZoneId(game, sourceObject); if (permanent != null) { - return controller.moveCardToExileWithInfo(permanent, exileId, exileZone, source.getSourceId(), game, Zone.BATTLEFIELD); + return controller.moveCardToExileWithInfo(permanent, exileId, sourceObject.getLogName(), source.getSourceId(), game, Zone.BATTLEFIELD); } else { - Card card = game.getCard(targetPointer.getFirst(game, source)); + Card card = game.getCard(getTargetPointer().getFirst(game, source)); if (card != null) { - return controller.moveCardToExileWithInfo(card, exileId, exileZone, source.getSourceId(), game, game.getState().getZone(card.getId())); + return controller.moveCardToExileWithInfo(card, exileId, sourceObject.getLogName(), source.getSourceId(), game, game.getState().getZone(card.getId())); } } } diff --git a/Mage/src/mage/abilities/effects/common/ReturnFromExileForSourceEffect.java b/Mage/src/mage/abilities/effects/common/ReturnFromExileForSourceEffect.java index 430c84b384..26ffd2715b 100644 --- a/Mage/src/mage/abilities/effects/common/ReturnFromExileForSourceEffect.java +++ b/Mage/src/mage/abilities/effects/common/ReturnFromExileForSourceEffect.java @@ -30,9 +30,12 @@ package mage.abilities.effects.common; import java.util.LinkedList; import java.util.UUID; +import mage.MageObject; import mage.abilities.Ability; +import mage.abilities.TriggeredAbilityImpl; import mage.abilities.effects.OneShotEffect; import mage.cards.Card; +import mage.constants.AbilityType; import mage.constants.Outcome; import mage.constants.Zone; import static mage.constants.Zone.BATTLEFIELD; @@ -41,6 +44,7 @@ import static mage.constants.Zone.HAND; import mage.game.ExileZone; import mage.game.Game; import mage.players.Player; +import mage.util.CardUtil; /** * @@ -75,9 +79,10 @@ public class ReturnFromExileForSourceEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Player controller = game.getPlayer(source.getControllerId()); - if (controller != null) { - UUID exileId = source.getSourceId(); + Player controller = game.getPlayer(source.getControllerId()); + MageObject sourceObject = source.getSourceObject(game); + if (controller != null && sourceObject != null) { + UUID exileId = CardUtil.getObjectExileZoneId(game, sourceObject); ExileZone exile = game.getExile().getExileZone(exileId); if (exile != null) { // null is valid if source left battlefield before enters the battlefield effect resolved LinkedList<UUID> cards = new LinkedList<>(exile); @@ -86,7 +91,7 @@ public class ReturnFromExileForSourceEffect extends OneShotEffect { if (card == null) { return false; } - game.informPlayers(controller.getName() + " moves " + card.getLogName() + " to " + zone.toString().toLowerCase()); + game.informPlayers(controller.getName() + " moves " + card.getLogName() + " from exile to " + zone.toString().toLowerCase()); card.moveToZone(zone, source.getSourceId(), game, tapped); } exile.clear(); diff --git a/Mage/src/mage/abilities/effects/common/ReturnToBattlefieldUnderYourControlTargetEffect.java b/Mage/src/mage/abilities/effects/common/ReturnToBattlefieldUnderYourControlTargetEffect.java index c0d2522736..560e8c1c77 100644 --- a/Mage/src/mage/abilities/effects/common/ReturnToBattlefieldUnderYourControlTargetEffect.java +++ b/Mage/src/mage/abilities/effects/common/ReturnToBattlefieldUnderYourControlTargetEffect.java @@ -28,6 +28,8 @@ package mage.abilities.effects.common; +import java.util.UUID; +import mage.MageObject; import mage.constants.Outcome; import mage.constants.Zone; import mage.abilities.Ability; @@ -35,6 +37,7 @@ import mage.abilities.effects.OneShotEffect; import mage.cards.Card; import mage.game.Game; import mage.players.Player; +import mage.util.CardUtil; /** * @@ -42,13 +45,25 @@ import mage.players.Player; */ public class ReturnToBattlefieldUnderYourControlTargetEffect extends OneShotEffect { + private boolean fromExileZone; + public ReturnToBattlefieldUnderYourControlTargetEffect() { + this(false); + } + + /** + * + * @param fromExileZone - the card will only be retunred if it's still in the sour obect specific exile zone + */ + public ReturnToBattlefieldUnderYourControlTargetEffect(boolean fromExileZone) { super(Outcome.Benefit); staticText = "return that card to the battlefield under your control"; + this.fromExileZone = fromExileZone; } public ReturnToBattlefieldUnderYourControlTargetEffect(final ReturnToBattlefieldUnderYourControlTargetEffect effect) { super(effect); + this.fromExileZone = effect.fromExileZone; } @Override @@ -59,17 +74,23 @@ public class ReturnToBattlefieldUnderYourControlTargetEffect extends OneShotEffe @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - if (controller != null) { - Card card = game.getCard(targetPointer.getFirst(game, source)); + MageObject sourceObject = source.getSourceObject(game); + if (controller != null && sourceObject != null) { + Card card = null; + if (fromExileZone) { + UUID exilZoneId = CardUtil.getObjectExileZoneId(game, sourceObject); + if (exilZoneId != null) { + card = game.getExile().getExileZone(exilZoneId).get(getTargetPointer().getFirst(game, source), game); + } + } else { + card = game.getCard(targetPointer.getFirst(game, source)); + } if (card != null) { Zone currentZone = game.getState().getZone(card.getId()); - if (controller.putOntoBattlefieldWithInfo(card, game, currentZone, source.getSourceId())) { - return true; - } + controller.putOntoBattlefieldWithInfo(card, game, currentZone, source.getSourceId()); } - + return true; } return false; } - } diff --git a/Mage/src/mage/abilities/keyword/ChampionAbility.java b/Mage/src/mage/abilities/keyword/ChampionAbility.java index a3c68e4ecc..5320f39111 100644 --- a/Mage/src/mage/abilities/keyword/ChampionAbility.java +++ b/Mage/src/mage/abilities/keyword/ChampionAbility.java @@ -49,6 +49,7 @@ import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.common.TargetControlledPermanent; +import mage.util.CardUtil; /* * @author LevelX2 @@ -151,14 +152,16 @@ class ChampionExileCost extends CostImpl { @Override public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana) { Player controller = game.getPlayer(controllerId); - if (controller != null) { + MageObject sourceObject = ability.getSourceObject(game); + if (controller != null && sourceObject != null) { if (targets.choose(Outcome.Exile, controllerId, sourceId, game)) { + UUID exileId = CardUtil.getObjectExileZoneId(game, sourceObject); for (UUID targetId: targets.get(0).getTargets()) { Permanent permanent = game.getPermanent(targetId); if (permanent == null) { return false; } - paid |= controller.moveCardToExileWithInfo(permanent, sourceId, exileZone, sourceId, game, Zone.BATTLEFIELD); + paid |= controller.moveCardToExileWithInfo(permanent, exileId, sourceObject.getLogName() + " championed permanents", sourceId, game, Zone.BATTLEFIELD); } } } diff --git a/Mage/src/mage/game/stack/StackAbility.java b/Mage/src/mage/game/stack/StackAbility.java index 32484612eb..2e65c538cc 100644 --- a/Mage/src/mage/game/stack/StackAbility.java +++ b/Mage/src/mage/game/stack/StackAbility.java @@ -476,5 +476,15 @@ public class StackAbility implements StackObject, Ability { this.ability.setWorksFaceDown(worksFaceDown); } + @Override + public MageObject getSourceObject(Game game) { + throw new UnsupportedOperationException("Not supported."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public void setSourceObject(MageObject sourceObject) { + throw new UnsupportedOperationException("Not supported."); //To change body of generated methods, choose Tools | Templates. + } + } diff --git a/Mage/src/mage/util/CardUtil.java b/Mage/src/mage/util/CardUtil.java index 449275739f..7ceb6e9bac 100644 --- a/Mage/src/mage/util/CardUtil.java +++ b/Mage/src/mage/util/CardUtil.java @@ -69,6 +69,8 @@ public class CardUtil { private static final String regexGreen = ".*\\x7b.{0,2}G.{0,2}\\x7d.*"; private static final String regexWhite = ".*\\x7b.{0,2}W.{0,2}\\x7d.*"; + private static final String SOURCE_EXILE_ZONE_TEXT = "SourceExileZone"; + static String numberStrings[] = { "zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten", "eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", "eighteen", "ninteen", "twenty"}; @@ -483,13 +485,28 @@ public class CardUtil { } public static UUID getCardExileZoneId(Game game, UUID sourceId, boolean previous) { - String key = getCardZoneString("SourceExileZone", sourceId, game, previous); + return getExileZoneId(getCardZoneString(SOURCE_EXILE_ZONE_TEXT, sourceId, game, previous), game); + } + + public static UUID getObjectExileZoneId(Game game, MageObject mageObject) { + int zoneChangeCounter = 0; + if (mageObject instanceof Card) { + zoneChangeCounter = ((Card) mageObject).getZoneChangeCounter(); + } + return getExileZoneId(getObjectZoneString(SOURCE_EXILE_ZONE_TEXT,mageObject.getId(), game, zoneChangeCounter, false), game); + } + + public static UUID getExileZoneId(Game game, UUID objectId, int zoneChangeCounter) { + return getExileZoneId(getObjectZoneString(SOURCE_EXILE_ZONE_TEXT,objectId, game, zoneChangeCounter, false), game); + } + + public static UUID getExileZoneId(String key, Game game) { UUID exileId = (UUID) game.getState().getValue(key); if (exileId == null) { exileId = UUID.randomUUID(); game.getState().setValue(key, exileId); } - return exileId; + return exileId; } /** @@ -506,18 +523,23 @@ public class CardUtil { return getCardZoneString(text, cardId, game, false); } - public static String getCardZoneString(String text, UUID cardId, Game game, boolean previous) { - + public static String getCardZoneString(String text, UUID cardId, Game game, boolean previous) { + int zoneChangeCounter= 0; + Card card = game.getCard(cardId); // if called for a token, the id is enough + if (card != null) { + zoneChangeCounter = card.getZoneChangeCounter(); + } + return getObjectZoneString(text,cardId, game, zoneChangeCounter, previous); + } + + public static String getObjectZoneString(String text, UUID objectId, Game game, int zoneChangeCounter, boolean previous) { StringBuilder uniqueString = new StringBuilder(); if (text != null) { uniqueString.append(text); } - uniqueString.append(cardId); - Card card = game.getCard(cardId); // if called for a token, the id is enough - if (card != null) { - uniqueString.append(previous ? card.getZoneChangeCounter() - 1: card.getZoneChangeCounter()); - } - return uniqueString.toString(); + uniqueString.append(objectId); + uniqueString.append(previous ? zoneChangeCounter - 1: zoneChangeCounter); + return uniqueString.toString(); } /**