Fixed From Deepest Dungeon crashing at the start of the Shadow phase

This commit is contained in:
Christian 'ketura' McCarty
2024-09-07 16:52:14 -05:00
parent eded4f57f0
commit ec1fccbb80
2 changed files with 267 additions and 28 deletions

View File

@@ -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.<br>Shadow: Remove X threats to play the Balrog from your discard pile, its twilight cost is -1 for each threat removed.

View File

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