diff --git a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/effect/appender/ChooseANumber.java b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/effect/appender/ChooseANumber.java index 653e894c1..d8a2ce2d2 100644 --- a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/effect/appender/ChooseANumber.java +++ b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/effect/appender/ChooseANumber.java @@ -1,13 +1,11 @@ package com.gempukku.lotro.cards.build.field.effect.appender; -import com.gempukku.lotro.cards.build.ActionContext; -import com.gempukku.lotro.cards.build.CardGenerationEnvironment; -import com.gempukku.lotro.cards.build.InvalidCardDefinitionException; -import com.gempukku.lotro.cards.build.PlayerSource; +import com.gempukku.lotro.cards.build.*; import com.gempukku.lotro.cards.build.field.FieldUtils; import com.gempukku.lotro.cards.build.field.effect.EffectAppender; import com.gempukku.lotro.cards.build.field.effect.EffectAppenderProducer; import com.gempukku.lotro.cards.build.field.effect.appender.resolver.PlayerResolver; +import com.gempukku.lotro.cards.build.field.effect.appender.resolver.ValueResolver; import com.gempukku.lotro.logic.actions.CostToEffectAction; import com.gempukku.lotro.logic.decisions.DecisionResultInvalidException; import com.gempukku.lotro.logic.decisions.IntegerAwaitingDecision; @@ -22,8 +20,9 @@ public class ChooseANumber implements EffectAppenderProducer { final String player = FieldUtils.getString(effectObject.get("player"), "player", "you"); final String displayText = FieldUtils.getString(effectObject.get("text"), "text", "Choose a number"); - final int from = FieldUtils.getInteger(effectObject.get("from"), "from", 0); - final int to = FieldUtils.getInteger(effectObject.get("to"), "to", 1); + final ValueSource fromSource = ValueResolver.resolveEvaluator(effectObject.get("from"), 0, environment); + final ValueSource toSource = ValueResolver.resolveEvaluator(effectObject.get("to"), 1, environment); + final String memorize = FieldUtils.getString(effectObject.get("memorize"), "memorize"); final PlayerSource playerSource = PlayerResolver.resolvePlayer(player, environment); @@ -35,7 +34,10 @@ public class ChooseANumber implements EffectAppenderProducer { @Override protected Effect createEffect(boolean cost, CostToEffectAction action, ActionContext actionContext) { return new PlayoutDecisionEffect(actionContext.getPerformingPlayer(), - new IntegerAwaitingDecision(1, displayText, from, to) { + new IntegerAwaitingDecision(1, displayText, + fromSource.getEvaluator(actionContext).evaluateExpression(actionContext.getGame(), null), + toSource.getEvaluator(actionContext).evaluateExpression(actionContext.getGame(), null)) + { @Override public void decisionMade(String result) throws DecisionResultInvalidException { actionContext.setValueToMemory(memorize, String.valueOf(getValidatedResult(result))); diff --git a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/effect/appender/resolver/CardResolver.java b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/effect/appender/resolver/CardResolver.java index e835e2da1..e9b15405e 100644 --- a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/effect/appender/resolver/CardResolver.java +++ b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/effect/appender/resolver/CardResolver.java @@ -46,7 +46,8 @@ public class CardResolver { if (type.startsWith("memory(") && type.endsWith(")")) { return resolveMemoryCards(type, choiceFilter, playabilityFilter, countSource, memory, cardSource); - } else if (type.startsWith("choose(") && type.endsWith(")")) { + } + else if (type.startsWith("choose(") && type.endsWith(")")) { final PlayerSource playerSource = PlayerResolver.resolvePlayer(choicePlayer, environment); ChoiceEffectSource effectSource = (possibleCards, action, actionContext, min, max) -> { String choicePlayerId = playerSource.getPlayer(actionContext); diff --git a/gemp-lotr/gemp-lotr-server/src/test/java/com/gempukku/lotro/cards/GenericCardTestHelper.java b/gemp-lotr/gemp-lotr-server/src/test/java/com/gempukku/lotro/cards/GenericCardTestHelper.java index e3db99dfc..d6ec7b3ba 100644 --- a/gemp-lotr/gemp-lotr-server/src/test/java/com/gempukku/lotro/cards/GenericCardTestHelper.java +++ b/gemp-lotr/gemp-lotr-server/src/test/java/com/gempukku/lotro/cards/GenericCardTestHelper.java @@ -55,13 +55,15 @@ public class GenericCardTestHelper extends AbstractAtTest { // Player key, then name/card public Map> Cards = new HashMap<>(); - public GenericCardTestHelper(Map cardIDs) throws CardNotFoundException, DecisionResultInvalidException { + public GenericCardTestHelper(HashMap cardIDs) throws CardNotFoundException, DecisionResultInvalidException { this(cardIDs, null, null, null); } - public GenericCardTestHelper(Map cardIDs, Map siteIDs, String ringBearerID, String ringID) throws CardNotFoundException, DecisionResultInvalidException { + public GenericCardTestHelper(HashMap cardIDs, HashMap siteIDs, String ringBearerID, String ringID) throws CardNotFoundException, DecisionResultInvalidException { super(); + + if(siteIDs == null || ringBearerID == null || ringID == null) { initializeSimplestGame(); } @@ -91,20 +93,17 @@ public class GenericCardTestHelper extends AbstractAtTest { if(cardIDs != null) { for(String name : cardIDs.keySet()) { String id = cardIDs.get(name); - PhysicalCardImpl card = CreateCard(P1, id); + PhysicalCardImpl card = createCard(P1, id); Cards.get(P1).put(name, card); FreepsMoveCardsToTopOfDeck(card); - card = CreateCard(P2, id); + card = createCard(P2, id); Cards.get(P2).put(name, card); FreepsMoveCardsToTopOfDeck(card); } } } - public PhysicalCardImpl CreateCard(String playerID, String cardID) throws CardNotFoundException { - return new PhysicalCardImpl(LastCardID++, cardID, playerID, _library.getLotroCardBlueprint(cardID)); - } public void StartGame() throws DecisionResultInvalidException { skipMulligans(); @@ -256,10 +255,9 @@ public class GenericCardTestHelper extends AbstractAtTest { public int GetFreepsDiscardCount() { return GetPlayerDiscardCount(P1); } public int GetShadowDiscardCount() { return GetPlayerDiscardCount(P2); } - public int GetPlayerDiscardCount(String player) - { - return _game.getGameState().getDiscard(player).size(); - } + public int GetPlayerDiscardCount(String player) { return _game.getGameState().getDiscard(player).size(); } + + public int GetFreepsDeadCount() { return _game.getGameState().getDeadPile(P1).size(); } public Phase GetCurrentPhase() { return _game.getGameState().getCurrentPhase(); } @@ -360,6 +358,8 @@ public class GenericCardTestHelper extends AbstractAtTest { RemoveCardZone(card.getOwner(), card); _game.getGameState().putCardOnTopOfDeck(card); }); + + ShuffleFreepsDeck(); } public void ShadowShuffleCardsInDeck(String...cardNames) { Arrays.stream(cardNames).forEach(cardName -> ShadowShuffleCardsInDeck(GetShadowCard(cardName))); @@ -369,6 +369,14 @@ public class GenericCardTestHelper extends AbstractAtTest { RemoveCardZone(card.getOwner(), card); _game.getGameState().putCardOnTopOfDeck(card); }); + + ShuffleShadowDeck(); + } + + public void ShuffleFreepsDeck() { ShuffleDeck(P1); } + public void ShuffleShadowDeck() { ShuffleDeck(P2); } + public void ShuffleDeck(String player) { + _game.getGameState().shuffleDeck(player); } public void FreepsMoveCharToTable(String...names) { @@ -385,22 +393,43 @@ public class GenericCardTestHelper extends AbstractAtTest { } - public void FreepsMoveCardToSupportArea(String cardName) { FreepsMoveCardToSupportArea(GetFreepsCard(cardName)); } + public void FreepsMoveCardToSupportArea(String...names) { + Arrays.stream(names).forEach(name -> FreepsMoveCardToSupportArea(GetFreepsCard(name))); + } public void FreepsMoveCardToSupportArea(PhysicalCardImpl...cards) { Arrays.stream(cards).forEach(card -> MoveCardToZone(P1, card, Zone.SUPPORT)); } - public void ShadowMoveCardToSupportArea(String cardName) { ShadowMoveCardToSupportArea(GetShadowCard(cardName)); } - public void ShadowMoveCardToSupportArea(PhysicalCardImpl...cards) { - Arrays.stream(cards).forEach(card -> MoveCardToZone(P1, card, Zone.SUPPORT)); + public void ShadowMoveCardToSupportArea(String...names) { + Arrays.stream(names).forEach(name -> ShadowMoveCardToSupportArea(GetFreepsCard(name))); + } + public void ShadowMoveCardToSupportArea(PhysicalCardImpl...cards) { + Arrays.stream(cards).forEach(card -> MoveCardToZone(P2, card, Zone.SUPPORT)); + } + public void FreepsMoveCardToDiscard(String...names) { + Arrays.stream(names).forEach(name -> FreepsMoveCardToDiscard(GetFreepsCard(name))); } - - public void FreepsMoveCardToDiscard(String cardName) { FreepsMoveCardToDiscard(GetFreepsCard(cardName)); } public void FreepsMoveCardToDiscard(PhysicalCardImpl...cards) { Arrays.stream(cards).forEach(card -> MoveCardToZone(P1, card, Zone.DISCARD)); } - public void ShadowMoveCardToDiscard(String cardName) { ShadowMoveCardToDiscard(GetShadowCard(cardName)); } + public void ShadowMoveCardToDiscard(String...names) { + Arrays.stream(names).forEach(name -> ShadowMoveCardToDiscard(GetFreepsCard(name))); + } public void ShadowMoveCardToDiscard(PhysicalCardImpl...cards) { - Arrays.stream(cards).forEach(card -> MoveCardToZone(P1, card, Zone.DISCARD)); + Arrays.stream(cards).forEach(card -> MoveCardToZone(P2, card, Zone.DISCARD)); + } + + + public void FreepsMoveCardToDeadPile(String...names) { + Arrays.stream(names).forEach(name -> FreepsMoveCardToDeadPile(GetFreepsCard(name))); + } + public void FreepsMoveCardToDeadPile(PhysicalCardImpl...cards) { + Arrays.stream(cards).forEach(card -> MoveCardToZone(P1, card, Zone.DEAD)); + } + public void ShadowMoveCardToDeadPile(String...names) { + Arrays.stream(names).forEach(name -> ShadowMoveCardToDeadPile(GetFreepsCard(name))); + } + public void ShadowMoveCardToDeadPile(PhysicalCardImpl...cards) { + Arrays.stream(cards).forEach(card -> MoveCardToZone(P2, card, Zone.DEAD)); } @@ -557,25 +586,27 @@ public class GenericCardTestHelper extends AbstractAtTest { public int GetFreepsCardChoiceCount() { return FreepsGetCardChoices().size(); } public int GetShadowCardChoiceCount() { return ShadowGetCardChoices().size(); } - public void FreepsChooseCardBPFromSelection(PhysicalCardImpl card) throws DecisionResultInvalidException { ChooseCardBPFromSelection(P1, card);} - public void ShadowChooseCardBPFromSelection(PhysicalCardImpl card) throws DecisionResultInvalidException { ChooseCardBPFromSelection(P2, card);} + public void FreepsChooseCardBPFromSelection(PhysicalCardImpl...cards) throws DecisionResultInvalidException { ChooseCardBPFromSelection(P1, cards);} + public void ShadowChooseCardBPFromSelection(PhysicalCardImpl...cards) throws DecisionResultInvalidException { ChooseCardBPFromSelection(P2, cards);} - public void ChooseCardBPFromSelection(String player, PhysicalCardImpl card) throws DecisionResultInvalidException { - AwaitingDecision decision = _userFeedback.getAwaitingDecision(player); + public void ChooseCardBPFromSelection(String player, PhysicalCardImpl...cards) throws DecisionResultInvalidException { + String[] choices = GetAwaitingDecisionParam(player,"blueprintId"); + ArrayList bps = new ArrayList(); - String[] ids = GetAwaitingDecisionParam(player,"blueprintId"); - for(int i = 0; i < ids.length; i++) + for(int i = 0; i < choices.length; i++) { - String id = ids[i]; - if(id == card.getBlueprintId()) + for(PhysicalCardImpl card : cards) { - // I have no idea why the spacing is required, but the BP parser skips to the fourth position - playerDecided(player, " " + i); - return; + if(card.getBlueprintId() == choices[i]) + { + // I have no idea why the spacing is required, but the BP parser skips to the fourth position + bps.add(" " + i); + break; + } } } - playerDecided(player, card.getBlueprintId()); + playerDecided(player, String.join(",", bps)); } public void FreepsChooseCardIDFromSelection(PhysicalCardImpl card) throws DecisionResultInvalidException { ChooseCardIDFromSelection(P1, card);} diff --git a/gemp-lotr/gemp-lotr-server/src/test/java/com/gempukku/lotro/cards/official/set09/Card_09_039_Tests.java b/gemp-lotr/gemp-lotr-server/src/test/java/com/gempukku/lotro/cards/official/set09/Card_09_039_Tests.java index c0a9c2c25..25d41262d 100644 --- a/gemp-lotr/gemp-lotr-server/src/test/java/com/gempukku/lotro/cards/official/set09/Card_09_039_Tests.java +++ b/gemp-lotr/gemp-lotr-server/src/test/java/com/gempukku/lotro/cards/official/set09/Card_09_039_Tests.java @@ -112,19 +112,18 @@ public class Card_09_039_Tests PhysicalCardImpl library = scn.GetShadowCard("library"); PhysicalCardImpl troop1 = scn.GetShadowCard("troop1"); + PhysicalCardImpl troop2 = scn.GetShadowCard("troop2"); PhysicalCardImpl axe1 = scn.GetShadowCard("axe1"); - scn.ShadowMoveCardToHand(library, troop1); + scn.ShadowMoveCardToSupportArea(library); + scn.ShadowMoveCharToTable(troop1); + scn.StackCardsOn(library, axe1, troop2); scn.StartGame(); scn.SetTwilight(20); scn.FreepsSkipCurrentPhaseAction(); - scn.ShadowPlayCard(library); - scn.ShadowUseCardAction(library); - assertEquals(library, axe1.getStackedOn()); - scn.SkipToPhase(Phase.ASSIGNMENT); scn.SkipCurrentPhaseActions(); scn.FreepsAssignToMinions(scn.GetRingBearer(), troop1); @@ -132,17 +131,54 @@ public class Card_09_039_Tests scn.FreepsSkipCurrentPhaseAction(); assertTrue(scn.ShadowCardActionAvailable(library)); - // 20 initially, +2 from move, -2 from library, -5 for troop, -2 for roaming - assertEquals(13, scn.GetTwilight()); + // 20 initially, +2 from move, the rest were all cheated in + assertEquals(22, scn.GetTwilight()); assertEquals(9, scn.GetStrength(troop1)); - assertEquals(1, scn.GetStackedCards(library).size()); + assertEquals(2, scn.GetStackedCards(library).size()); + scn.ShadowUseCardAction(library); - assertEquals(13, scn.GetTwilight()); - assertEquals(9, scn.GetStrength(troop1)); - assertEquals(0, scn.GetStackedCards(library).size()); + assertFalse(scn.ShadowAnyDecisionsAvailable()); // only 1 valid choice even with 2 stacked, so should have no decision + assertEquals(21, scn.GetTwilight()); + assertEquals(10, scn.GetStrength(troop1)); + assertEquals(1, scn.GetStackedCards(library).size()); assertEquals(Zone.DISCARD, axe1.getZone()); } + @Test + public void RegroupAbilityRemoves1AndTakesStackedIsengardCardIntoHand() throws DecisionResultInvalidException, CardNotFoundException { + //Pre-game setup + GenericCardTestHelper scn = GetScenario(); + + PhysicalCardImpl library = scn.GetShadowCard("library"); + PhysicalCardImpl troop1 = scn.GetShadowCard("troop1"); + PhysicalCardImpl runner = scn.GetShadowCard("runner"); + PhysicalCardImpl axe1 = scn.GetShadowCard("axe1"); + + scn.ShadowMoveCardToSupportArea(library); + scn.StackCardsOn(library, axe1, runner, troop1); + + scn.StartGame(); + scn.SetTwilight(20); + + scn.FreepsSkipCurrentPhaseAction(); + + scn.SkipToPhase(Phase.REGROUP); + scn.FreepsSkipCurrentPhaseAction(); + + assertTrue(scn.ShadowCardActionAvailable(library)); + // 20 initially, +2 from move, the rest were all cheated in + assertEquals(22, scn.GetTwilight()); + assertEquals(0, scn.GetShadowHandCount()); + assertEquals(3, scn.GetStackedCards(library).size()); + + scn.ShadowUseCardAction(library); + assertFalse(scn.ShadowAnyDecisionsAvailable()); // only 1 valid choice even with 3 stacked, so should have no decision + assertEquals(21, scn.GetTwilight()); + assertEquals(1, scn.GetShadowHandCount()); + assertEquals(2, scn.GetStackedCards(library).size()); + assertEquals(Zone.HAND, troop1.getZone()); + } +