From ec1fccbb80499aac02629620a4fb9839b2e46b0a Mon Sep 17 00:00:00 2001 From: Christian 'ketura' McCarty Date: Sat, 7 Sep 2024 16:52:14 -0500 Subject: [PATCH] Fixed From Deepest Dungeon crashing at the start of the Shadow phase --- .../pc/setV02/setv02-Moria-playtest.hjson | 47 ++-- .../pc/vsets/set_v02/Card_V2_039_Tests.java | 248 +++++++++++++++++- 2 files changed, 267 insertions(+), 28 deletions(-) diff --git a/gemp-lotr/gemp-lotr-cards/src/main/resources/cards/unofficial/pc/setV02/setv02-Moria-playtest.hjson b/gemp-lotr/gemp-lotr-cards/src/main/resources/cards/unofficial/pc/setV02/setv02-Moria-playtest.hjson index 1aa40d908..e593b1f3a 100644 --- a/gemp-lotr/gemp-lotr-cards/src/main/resources/cards/unofficial/pc/setV02/setv02-Moria-playtest.hjson +++ b/gemp-lotr/gemp-lotr-cards/src/main/resources/cards/unofficial/pc/setV02/setv02-Moria-playtest.hjson @@ -113,35 +113,44 @@ { type: CanPlayFromDiscard filter: name(The Balrog) - } - { - type: CanSpotThreats + discount: { + type: ForEachThreat + multiplier: -1 + } } ] - cost: [ - { + effect: { + type: CostToEffect + cost: { type: ChooseANumber text: Choose how many threats to remove - from: 1 + from: 0 to: { type: ForEachThreat } memorize: removedThreats } - { - type: RemoveThreats - amount: memory(removedThreats) + effect: { + type: CostToEffect + cost: { + type: RemoveThreats + amount: memory(removedThreats) + } + effect: { + type: PlayCardFromDiscard + select: choose(name(The Balrog)) + maxDiscount: { + type: ForEachThreat + multiplier: -1 + } + discount: { + type: FromMemory + memory: removedThreats + multiplier: -1 + } + } } - ] - effect: { - type: PlayCardFromDiscard - select: choose(name(The Balrog)) - discount: { - type: FromMemory - memory: removedThreats - multiplier: -1 - } - } + } } ] gametext: Each time the fellowship moves, you may reveal The Balrog from your hand to add a threat.
Shadow: Remove X threats to play the Balrog from your discard pile, its twilight cost is -1 for each threat removed. diff --git a/gemp-lotr/gemp-lotr-server/src/test/java/com/gempukku/lotro/cards/unofficial/pc/vsets/set_v02/Card_V2_039_Tests.java b/gemp-lotr/gemp-lotr-server/src/test/java/com/gempukku/lotro/cards/unofficial/pc/vsets/set_v02/Card_V2_039_Tests.java index e8cbf87a4..480ccdfb8 100644 --- a/gemp-lotr/gemp-lotr-server/src/test/java/com/gempukku/lotro/cards/unofficial/pc/vsets/set_v02/Card_V2_039_Tests.java +++ b/gemp-lotr/gemp-lotr-server/src/test/java/com/gempukku/lotro/cards/unofficial/pc/vsets/set_v02/Card_V2_039_Tests.java @@ -18,8 +18,19 @@ public class Card_V2_039_Tests return new GenericCardTestHelper( new HashMap<>() {{ - put("card", "102_39"); - // put other cards in here as needed for the test case + put("dungeon", "102_39"); + put("balrog1", "6_76"); + put("balrog2", "19_18"); + + //Dwarf guards for threat limit + put("fodder1", "1_7"); + put("fodder2", "1_7"); + put("fodder3", "1_7"); + put("fodder4", "1_7"); + put("fodder5", "1_7"); + put("fodder6", "1_7"); + put("fodder7", "1_7"); + put("fodder8", "1_7"); }}, GenericCardTestHelper.FellowshipSites, GenericCardTestHelper.FOTRFrodo, @@ -45,7 +56,7 @@ public class Card_V2_039_Tests var scn = GetScenario(); - var card = scn.GetFreepsCard("card"); + var card = scn.GetFreepsCard("dungeon"); assertEquals("From Deepest Dungeon", card.getBlueprint().getTitle()); assertNull(card.getBlueprint().getSubtitle()); @@ -57,18 +68,237 @@ public class Card_V2_039_Tests assertEquals(0, card.getBlueprint().getTwilightCost()); } - // Uncomment any @Test markers below once this is ready to be used - //@Test - public void FromDeepestDungeonTest1() throws DecisionResultInvalidException, CardNotFoundException { + @Test + public void FromDeepestDungeonRevealsBalrogFromHandOnMoveToAddThreat() throws DecisionResultInvalidException, CardNotFoundException { //Pre-game setup var scn = GetScenario(); - var card = scn.GetFreepsCard("card"); - scn.FreepsMoveCardToHand(card); + var dungeon = scn.GetShadowCard("dungeon"); + var balrog1 = scn.GetShadowCard("balrog1"); + scn.ShadowMoveCardToSupportArea(dungeon); + scn.ShadowMoveCardToHand(balrog1); + scn.ShadowMoveCardToDiscard("balrog2"); // So we don't draw it later + + scn.FreepsMoveCharToTable("fodder1"); scn.StartGame(); - scn.FreepsPlayCard(card); + assertEquals(0, scn.GetThreats()); + scn.FreepsPassCurrentPhaseAction(); + + assertTrue(scn.ShadowHasOptionalTriggerAvailable()); + scn.ShadowAcceptOptionalTrigger(); + scn.AcknowledgeReveal(); + assertEquals(1, scn.GetThreats()); + + scn.SkipToPhase(Phase.REGROUP); + scn.SkipToMovementDecision(); + scn.FreepsChooseToMove(); + + assertTrue(scn.ShadowHasOptionalTriggerAvailable()); + scn.ShadowAcceptOptionalTrigger(); + scn.AcknowledgeReveal(); + assertEquals(2, scn.GetThreats()); + } + + @Test + public void FromDeepestDungeonMoveRevealIsOptional() throws DecisionResultInvalidException, CardNotFoundException { + //Pre-game setup + var scn = GetScenario(); + + var dungeon = scn.GetShadowCard("dungeon"); + var balrog1 = scn.GetShadowCard("balrog1"); + scn.ShadowMoveCardToSupportArea(dungeon); + scn.ShadowMoveCardToHand(balrog1); + + scn.StartGame(); + + assertEquals(0, scn.GetThreats()); + scn.FreepsPassCurrentPhaseAction(); + + assertTrue(scn.ShadowHasOptionalTriggerAvailable()); + scn.ShadowDeclineOptionalTrigger(); + assertEquals(0, scn.GetThreats()); + assertEquals(Phase.SHADOW, scn.GetCurrentPhase()); + } + + @Test + public void FromDeepestDungeonRevealsNothingIfNoBalrogInHand() throws DecisionResultInvalidException, CardNotFoundException { + //Pre-game setup + var scn = GetScenario(); + + var dungeon = scn.GetShadowCard("dungeon"); + scn.ShadowMoveCardToSupportArea(dungeon); + scn.ShadowMoveCardToDiscard("balrog1", "balrog2"); + + scn.StartGame(); + + assertEquals(0, scn.GetThreats()); + scn.FreepsPassCurrentPhaseAction(); + + assertFalse(scn.ShadowHasOptionalTriggerAvailable()); + + + } + + + @Test + public void FromDeepestDungeonShadowCanDiscount0ByRemoving0Threats() throws DecisionResultInvalidException, CardNotFoundException { + //Pre-game setup + var scn = GetScenario(); + + var dungeon = scn.GetShadowCard("dungeon"); + var balrog1 = scn.GetShadowCard("balrog1"); + scn.ShadowMoveCardToSupportArea(dungeon); + scn.ShadowMoveCardToDiscard(balrog1); + + scn.FreepsMoveCharToTable("fodder1", "fodder2", "fodder3", "fodder4", "fodder5", "fodder6", "fodder7", "fodder8"); + + scn.StartGame(); + + scn.SetTwilight(39); + scn.AddThreats(9); + + scn.FreepsPassCurrentPhaseAction(); + + assertEquals(9, scn.GetThreats()); + assertEquals(50, scn.GetTwilight()); + assertEquals(Zone.DISCARD, balrog1.getZone()); + assertTrue(scn.ShadowActionAvailable(dungeon)); + + scn.ShadowUseCardAction(dungeon); + assertTrue(scn.ShadowDecisionAvailable("remove")); + scn.ShadowChoose("0"); + + assertEquals(Zone.SHADOW_CHARACTERS, balrog1.getZone()); + //Balrog costs 14 + 2 for roaming, with a -0 discount = 16 + assertEquals(34, scn.GetTwilight()); + assertEquals(9, scn.GetThreats()); + } + + @Test + public void FromDeepestDungeonShadowCanDiscount1ByRemoving1Threat() throws DecisionResultInvalidException, CardNotFoundException { + //Pre-game setup + var scn = GetScenario(); + + var dungeon = scn.GetShadowCard("dungeon"); + var balrog1 = scn.GetShadowCard("balrog1"); + scn.ShadowMoveCardToSupportArea(dungeon); + scn.ShadowMoveCardToDiscard(balrog1); + + scn.FreepsMoveCharToTable("fodder1", "fodder2", "fodder3", "fodder4", "fodder5", "fodder6", "fodder7", "fodder8"); + + scn.StartGame(); + + scn.SetTwilight(39); + scn.AddThreats(9); + + scn.FreepsPassCurrentPhaseAction(); + + assertEquals(9, scn.GetThreats()); + assertEquals(50, scn.GetTwilight()); + assertEquals(Zone.DISCARD, balrog1.getZone()); + assertTrue(scn.ShadowActionAvailable(dungeon)); + + scn.ShadowUseCardAction(dungeon); + assertTrue(scn.ShadowDecisionAvailable("remove")); + scn.ShadowChoose("1"); + + assertEquals(Zone.SHADOW_CHARACTERS, balrog1.getZone()); + //Balrog costs 14 + 2 for roaming, with a -1 discount = 15 + assertEquals(35, scn.GetTwilight()); + assertEquals(8, scn.GetThreats()); + } + + @Test + public void FromDeepestDungeonShadowCanDiscount9ByRemoving9Threats() throws DecisionResultInvalidException, CardNotFoundException { + //Pre-game setup + var scn = GetScenario(); + + var dungeon = scn.GetShadowCard("dungeon"); + var balrog1 = scn.GetShadowCard("balrog1"); + scn.ShadowMoveCardToSupportArea(dungeon); + scn.ShadowMoveCardToDiscard(balrog1); + + scn.FreepsMoveCharToTable("fodder1", "fodder2", "fodder3", "fodder4", "fodder5", "fodder6", "fodder7", "fodder8"); + + scn.StartGame(); + + scn.SetTwilight(39); + scn.AddThreats(9); + + scn.FreepsPassCurrentPhaseAction(); + + assertEquals(9, scn.GetThreats()); + assertEquals(50, scn.GetTwilight()); + assertEquals(Zone.DISCARD, balrog1.getZone()); + assertTrue(scn.ShadowActionAvailable(dungeon)); + + scn.ShadowUseCardAction(dungeon); + assertTrue(scn.ShadowDecisionAvailable("remove")); + scn.ShadowChoose("9"); + + assertEquals(Zone.SHADOW_CHARACTERS, balrog1.getZone()); + //Balrog costs 14 + 2 for roaming, with a -9 discount = 7 + assertEquals(43, scn.GetTwilight()); + assertEquals(0, scn.GetThreats()); + } + + @Test + public void FromDeepestDungeonShadowCanActivateIfDiscountLessThanTwilight() throws DecisionResultInvalidException, CardNotFoundException { + //Pre-game setup + var scn = GetScenario(); + + var dungeon = scn.GetShadowCard("dungeon"); + var balrog1 = scn.GetShadowCard("balrog1"); + scn.ShadowMoveCardToSupportArea(dungeon); + scn.ShadowMoveCardToDiscard(balrog1); + + scn.FreepsMoveCharToTable("fodder1", "fodder2", "fodder3", "fodder4", "fodder5", "fodder6", "fodder7", "fodder8"); + + scn.StartGame(); + + scn.AddThreats(9); + + scn.FreepsPassCurrentPhaseAction(); + + assertEquals(9, scn.GetThreats()); + assertEquals(11, scn.GetTwilight()); + assertEquals(Zone.DISCARD, balrog1.getZone()); + assertTrue(scn.ShadowActionAvailable(dungeon)); + + scn.ShadowUseCardAction(dungeon); + assertTrue(scn.ShadowDecisionAvailable("remove")); + scn.ShadowChoose("5"); + + assertEquals(Zone.SHADOW_CHARACTERS, balrog1.getZone()); + //Balrog costs 14 + 2 for roaming, with a -5 discount = 11 assertEquals(0, scn.GetTwilight()); + assertEquals(4, scn.GetThreats()); + } + + @Test + public void FromDeepestDungeonShadowCannotActivateIfMaxDiscountMoreThanTwilight() throws DecisionResultInvalidException, CardNotFoundException { + //Pre-game setup + var scn = GetScenario(); + + var dungeon = scn.GetShadowCard("dungeon"); + var balrog1 = scn.GetShadowCard("balrog1"); + scn.ShadowMoveCardToSupportArea(dungeon); + scn.ShadowMoveCardToDiscard(balrog1); + + scn.FreepsMoveCharToTable("fodder1", "fodder2", "fodder3", "fodder4", "fodder5", "fodder6", "fodder7", "fodder8"); + + scn.StartGame(); + + scn.AddThreats(4); + + scn.FreepsPassCurrentPhaseAction(); + + assertEquals(4, scn.GetThreats()); + assertEquals(11, scn.GetTwilight()); + assertEquals(Zone.DISCARD, balrog1.getZone()); + //Balrog costs 14 + 2 for roaming, with a -4 discount = 12, more twilight than is currently in the pool. + assertFalse(scn.ShadowActionAvailable(dungeon)); } }