diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/khm/DreamDevourerTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/khm/DreamDevourerTest.java new file mode 100644 index 00000000000..304c2511873 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/khm/DreamDevourerTest.java @@ -0,0 +1,64 @@ +package org.mage.test.cards.single.khm; + +import mage.constants.PhaseStep; +import mage.constants.Zone; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * @author JayDi85 + */ + +public class DreamDevourerTest extends CardTestPlayerBase { + + @Test + public void test_GainAndReduce() { + removeAllCardsFromHand(playerA); + + // Each nonland card in your hand without foretell has foretell. Its foretell cost is equal to its mana cost reduced by 2. + // Whenever you foretell a card, Dream Devourer gets +2/+0 until end of turn. + addCard(Zone.BATTLEFIELD, playerA, "Dream Devourer"); // 0/3 + // + addCard(Zone.HAND, playerA, "Grizzly Bears", 2); // {1}{G} + addCard(Zone.BATTLEFIELD, playerA, "Forest", 2 + 2); // 2 for normal cast, 2 for exile + + // bears must have foretell and normal cast + checkPlayableAbility("normal cast", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Grizzly Bears", true); + checkPlayableAbility("foretell exile", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "{2}: Foretell", true); + checkPT("no boost", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Dream Devourer", 0, 3); + + // normal cast and no boost + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Grizzly Bears"); + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); + checkPermanentCount("after normal cast", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Grizzly Bears", 1); + checkExileCount("after normal cast", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Grizzly Bears", 0); + checkPT("after normal cast - no boost", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Dream Devourer", 0, 3); + + // foretell for {2} + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{2}: Fore"); + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); + checkPermanentCount("after foretell", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Grizzly Bears", 1); + checkExileCount("after foretell", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Grizzly Bears", 1); + checkPT("after foretell - boosted", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Dream Devourer", 0 + 2, 3 + 0); + + // boost must ends on next turn + checkPT("turn 2 - boosted end", 2, PhaseStep.PRECOMBAT_MAIN, playerA, "Dream Devourer", 0, 3); + + // turn 3 - spend mana for cost reduce test (4 green -> 1 green) + activateManaAbility(3, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}: Add {G}", 3); + + // turn 3 - can play with cost reduce for {G} + activateAbility(3, PhaseStep.POSTCOMBAT_MAIN, playerA, "Foretell {G}"); + waitStackResolved(3, PhaseStep.POSTCOMBAT_MAIN); + checkPermanentCount("after foretell cast", 3, PhaseStep.POSTCOMBAT_MAIN, playerA, "Grizzly Bears", 2); + checkExileCount("after foretell cast", 3, PhaseStep.POSTCOMBAT_MAIN, playerA, "Grizzly Bears", 0); + checkPT("after foretell cast - no boost", 3, PhaseStep.POSTCOMBAT_MAIN, playerA, "Dream Devourer", 0, 3); + + setStrictChooseMode(true); + setStopAt(3, PhaseStep.END_TURN); + execute(); + assertAllCommandsUsed(); + + assertPermanentCount(playerA, "Grizzly Bears", 2); + } +} diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/khm/KarfellHarbingerTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/khm/KarfellHarbingerTest.java index 92994e8ece7..6dc944d70f8 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/single/khm/KarfellHarbingerTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/khm/KarfellHarbingerTest.java @@ -2,7 +2,6 @@ package org.mage.test.cards.single.khm; import mage.constants.PhaseStep; import mage.constants.Zone; -import org.junit.Ignore; import org.junit.Test; import org.mage.test.serverside.base.CardTestPlayerBase; @@ -12,14 +11,13 @@ import org.mage.test.serverside.base.CardTestPlayerBase; public class KarfellHarbingerTest extends CardTestPlayerBase { - @Ignore // unignore when we find a better ability text for foretell + @Test public void testForetellMana() { addCard(Zone.BATTLEFIELD, playerA, "Island", 1); addCard(Zone.BATTLEFIELD, playerA, "Karfell Harbinger"); addCard(Zone.HAND, playerA, "Augury Raven"); - //activateAbility(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "{2}: Foretold this card."); - activateAbility(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "{2}: Foretold this card."); + activateAbility(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "{2}: Fore"); setStrictChooseMode(true); setStopAt(1, PhaseStep.END_TURN); diff --git a/Mage/src/main/java/mage/abilities/common/ForetellSourceControllerTriggeredAbility.java b/Mage/src/main/java/mage/abilities/common/ForetellSourceControllerTriggeredAbility.java index a130ae0df57..d4ae35ae4dd 100644 --- a/Mage/src/main/java/mage/abilities/common/ForetellSourceControllerTriggeredAbility.java +++ b/Mage/src/main/java/mage/abilities/common/ForetellSourceControllerTriggeredAbility.java @@ -1,14 +1,8 @@ -/* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. - */ package mage.abilities.common; -import mage.abilities.Ability; -import mage.abilities.SpecialAction; import mage.abilities.TriggeredAbilityImpl; import mage.abilities.effects.Effect; +import mage.abilities.keyword.ForetellAbility; import mage.cards.Card; import mage.constants.Zone; import mage.game.Game; @@ -16,7 +10,6 @@ import mage.game.events.GameEvent; import mage.players.Player; /** - * * @author jeffwadsworth */ public class ForetellSourceControllerTriggeredAbility extends TriggeredAbilityImpl { @@ -39,22 +32,15 @@ public class ForetellSourceControllerTriggeredAbility extends TriggeredAbilityIm //UUID specialAction = event.getTargetId(); Card card = game.getCard(event.getSourceId()); Player player = game.getPlayer(event.getPlayerId()); - for (Ability a : card.getAbilities()) { - if (player.getId() == controllerId - && (a instanceof SpecialAction) - && a.getRule().endsWith("and exile this card from your hand face down. Cast it on a later turn for its foretell cost.)")) { - return true; - } + if (card == null || player == null) { + return false; } - // if the ability is added to cards via effect - for (Ability a : game.getState().getAllOtherAbilities(card.getId())) { - if (player.getId() == controllerId - && (a instanceof SpecialAction) - && a.getRule().endsWith("and exile this card from your hand face down. Cast it on a later turn for its foretell cost.)")) { - return true; - } + + if (!isControlledBy(player.getId())) { + return false; } - return false; + + return card.getAbilities(game).containsClass(ForetellAbility.class); } @Override diff --git a/Mage/src/main/java/mage/abilities/keyword/ForetellAbility.java b/Mage/src/main/java/mage/abilities/keyword/ForetellAbility.java index 213b8607c5d..aa05561f385 100644 --- a/Mage/src/main/java/mage/abilities/keyword/ForetellAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/ForetellAbility.java @@ -1,6 +1,5 @@ package mage.abilities.keyword; -import java.util.UUID; import mage.MageObject; import mage.MageObjectReference; import mage.abilities.Ability; @@ -19,14 +18,7 @@ import mage.abilities.effects.common.ExileTargetEffect; import mage.cards.Card; import mage.cards.ModalDoubleFacesCard; import mage.cards.SplitCard; -import mage.constants.AsThoughEffectType; -import mage.constants.Duration; -import mage.constants.Layer; -import mage.constants.Outcome; -import mage.constants.SpellAbilityCastMode; -import mage.constants.SpellAbilityType; -import mage.constants.SubLayer; -import mage.constants.Zone; +import mage.constants.*; import mage.game.ExileZone; import mage.game.Game; import mage.players.Player; @@ -34,13 +26,15 @@ import mage.target.targetpointer.FixedTarget; import mage.util.CardUtil; import mage.watchers.common.ForetoldWatcher; +import java.util.UUID; + /** * @author jeffwadsworth */ public class ForetellAbility extends SpecialAction { - private String foretellCost; - private Card card; + private final String foretellCost; + private final Card card; public ForetellAbility(Card card, String foretellCost) { super(Zone.HAND); @@ -72,6 +66,7 @@ public class ForetellAbility extends SpecialAction { // activate only during the controller's turn if (game.getState().getContinuousEffects().getApplicableAsThoughEffects(AsThoughEffectType.ALLOW_FORETELL_ANYTIME, game).isEmpty() && !game.isActivePlayer(this.getControllerId())) { + // TODO: must be fixed to call super.canActivate here for additional checks someday return ActivationStatus.getFalse(); } return super.canActivate(playerId, game); @@ -80,7 +75,7 @@ public class ForetellAbility extends SpecialAction { class ForetellExileEffect extends OneShotEffect { - private Card card; + private final Card card; String foretellCost; public ForetellExileEffect(Card card, String foretellCost) { diff --git a/Mage/src/main/java/mage/constants/AsThoughEffectType.java b/Mage/src/main/java/mage/constants/AsThoughEffectType.java index 74b8a27f59f..6bd79a56580 100644 --- a/Mage/src/main/java/mage/constants/AsThoughEffectType.java +++ b/Mage/src/main/java/mage/constants/AsThoughEffectType.java @@ -18,6 +18,7 @@ public enum AsThoughEffectType { BLOCK_FORESTWALK, DAMAGE_NOT_BLOCKED, BE_BLOCKED, + // PLAY_FROM_NOT_OWN_HAND_ZONE + CAST_AS_INSTANT: // 1. Do not use dialogs in "applies" method for that type of effect (it calls multiple times and will freeze the game) // 2. All effects in "applies" must checks affectedControllerId.equals(source.getControllerId()) (if not then all players will be able to play it) @@ -25,21 +26,26 @@ public enum AsThoughEffectType { // TODO: search all PLAY_FROM_NOT_OWN_HAND_ZONE and CAST_AS_INSTANT effects and add support of mainCard and objectId PLAY_FROM_NOT_OWN_HAND_ZONE(true), CAST_AS_INSTANT(true), + ACTIVATE_AS_INSTANT, DAMAGE, SHROUD, HEXPROOF, PAY_0_ECHO, LOOK_AT_FACE_DOWN, + // SPEND_OTHER_MANA: // 1. It's uses for mana calcs at any zone, not stack only // 2. Compare zone change counter as "objectZCC <= targetZCC + 1" // 3. Compare zone with original (like exiled) and stack, not stack only // TODO: search all SPEND_ONLY_MANA effects and improve counters compare as SPEND_OTHER_MANA SPEND_OTHER_MANA, + SPEND_ONLY_MANA, TARGET, - // Cosmos Charger effect + + // ALLOW_FORETELL_ANYTIME: + // For Cosmos Charger effect ALLOW_FORETELL_ANYTIME; private final boolean needPlayCardAbility; // mark effect type as compatible with play/cast abilities