From b1abddbce5d3c938cc74e63fe9986c73a893bb3f Mon Sep 17 00:00:00 2001 From: Christian 'ketura' McCarty Date: Tue, 1 Apr 2025 08:06:37 -0500 Subject: [PATCH] printedTwilightCostFromMemory change - Reverted printedTwilightCostFromMemory filter to use card memory reference. - Added MatchesTwilight for an exact numeric match of the twilight cost of a card - Altered Gathering Wind to use MatchesTwilight, since it is having the player choose an arbitrary number - Fixed Catapult crashing the game due to the card reference --- .../cards/official/set10/set10-Gandalf.hjson | 2 +- .../appender/RevealTopCardsOfDrawDeck.java | 3 +- .../field/effect/filter/FilterFactory.java | 33 ++++++--- .../RevealTopCardsOfDrawDeckEffect.java | 2 +- .../lotro/cards/GenericCardTestHelper.java | 26 +++++++ .../official/set08/Card_08_032_Tests.java | 70 ++++++++++++++++--- 6 files changed, 113 insertions(+), 23 deletions(-) diff --git a/gemp-lotr/gemp-lotr-cards/src/main/resources/cards/official/set10/set10-Gandalf.hjson b/gemp-lotr/gemp-lotr-cards/src/main/resources/cards/official/set10/set10-Gandalf.hjson index b3fd74156..b9316d6bc 100644 --- a/gemp-lotr/gemp-lotr-cards/src/main/resources/cards/official/set10/set10-Gandalf.hjson +++ b/gemp-lotr/gemp-lotr-cards/src/main/resources/cards/official/set10/set10-Gandalf.hjson @@ -132,7 +132,7 @@ } { type: modifyStrength - select: all(minion,printedTwilightCostFromMemory(chosenNumber)) + select: all(minion,matchesTwilight(memory(chosenNumber))) amount: -2 until: regroup } diff --git a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/effect/appender/RevealTopCardsOfDrawDeck.java b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/effect/appender/RevealTopCardsOfDrawDeck.java index 6cbd3ac5d..2c826f3a8 100644 --- a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/effect/appender/RevealTopCardsOfDrawDeck.java +++ b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/effect/appender/RevealTopCardsOfDrawDeck.java @@ -45,8 +45,7 @@ public class RevealTopCardsOfDrawDeck implements EffectAppenderProducer { return new RevealTopCardsOfDrawDeckEffect(actionContext.getSource(), deckId, count) { @Override protected void cardsRevealed(List revealedCards) { - if (memorize != null) - actionContext.setCardMemory(memorize, revealedCards); + actionContext.setCardMemory(memorize, revealedCards); } }; } diff --git a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/effect/filter/FilterFactory.java b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/effect/filter/FilterFactory.java index 238c5598c..930725692 100644 --- a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/effect/filter/FilterFactory.java +++ b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/effect/filter/FilterFactory.java @@ -427,6 +427,26 @@ public class FilterFactory { return Filters.filter(game, game.getGameState().getSkirmish().getShadowCharacters(), filterable).size() >= count; }); }); + parameterFilters.put("matchestwilight", + (parameter, environment) -> { + if (parameter.startsWith("memory(") && parameter.endsWith(")")) { + String memory = parameter.substring(parameter.indexOf("(") + 1, parameter.lastIndexOf(")")); + return actionContext -> { + try { + final int value = Integer.parseInt(actionContext.getValueFromMemory(memory)); + return Filters.printedTwilightCost(value); + } catch (IllegalArgumentException ex) { + return Filters.minPrintedTwilightCost(0); + } + }; + } else { + final ValueSource valueSource = ValueResolver.resolveEvaluator(parameter, environment); + return actionContext -> { + final int value = valueSource.getEvaluator(actionContext).evaluateExpression(actionContext.getGame(), null); + return Filters.printedTwilightCost(value); + }; + } + }); parameterFilters.put("maxtwilight", (parameter, environment) -> { if (parameter.startsWith("memory(") && parameter.endsWith(")")) { @@ -467,6 +487,7 @@ public class FilterFactory { }; } }); + parameterFilters.put("maxresistance", (parameter, environment) -> { final ValueSource valueSource = ValueResolver.resolveEvaluator(parameter, environment); @@ -568,17 +589,11 @@ public class FilterFactory { }); parameterFilters.put("printedtwilightcostfrommemory", (parameter, environment) -> actionContext -> { - String valueStr = actionContext.getValueFromMemory(parameter); - if (valueStr == null) + var card = actionContext.getCardFromMemory(parameter).getBlueprint(); + if (card.getCardType() == CardType.THE_ONE_RING || card.getCardType() == CardType.MAP) return Filters.none; - try { - int twilight = Integer.parseInt(valueStr); - return Filters.printedTwilightCost(twilight); - } - catch (NumberFormatException ex) { - return Filters.none; - } + return Filters.printedTwilightCost(card.getTwilightCost()); }); parameterFilters.put("race", (parameter, environment) -> { diff --git a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/logic/effects/RevealTopCardsOfDrawDeckEffect.java b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/logic/effects/RevealTopCardsOfDrawDeckEffect.java index 51cb1e151..f74e109d0 100644 --- a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/logic/effects/RevealTopCardsOfDrawDeckEffect.java +++ b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/logic/effects/RevealTopCardsOfDrawDeckEffect.java @@ -44,7 +44,7 @@ public abstract class RevealTopCardsOfDrawDeckEffect extends AbstractEffect { List deck = game.getGameState().getDeck(_playerId); int count = Math.min(deck.size(), _count); LinkedList topCards = new LinkedList<>(deck.subList(0, count)); - if (topCards.size() > 0) { + if (!topCards.isEmpty()) { final PlayOrder playerOrder = game.getGameState().getPlayerOrder().getCounterClockwisePlayOrder(_source.getOwner(), false); String nextPlayer; 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 b8280c150..5c9bc0dc8 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 @@ -965,6 +965,32 @@ public class GenericCardTestHelper extends AbstractAtTest { playerDecided(player, String.join(",", bps)); } + public boolean FreepsHasCardChoiceAvailable(PhysicalCardImpl card) throws DecisionResultInvalidException { return HasCardChoiceAvailable(P1, card);} + public boolean ShadowHasCardChoiceAvailable(PhysicalCardImpl card) throws DecisionResultInvalidException { return HasCardChoiceAvailable(P2, card);} + + public boolean HasCardChoiceAvailable(String player, PhysicalCardImpl card) throws DecisionResultInvalidException { + String[] choices = GetAwaitingDecisionParam(player,"blueprintId"); + if(choices != null) { + for (String choice : choices) { + if (card.getBlueprintId().equals(choice)) + return true; + } + return false; + } + + choices = GetAwaitingDecisionParam(player,"cardId"); + if(choices != null) { + for (String choice : choices) { + if (card.getCardId() == Integer.parseInt(choice)) + return true; + } + return false; + } + + + return false; + } + public void FreepsChooseCardIDFromSelection(PhysicalCardImpl...cards) throws DecisionResultInvalidException { ChooseCardIDFromSelection(P1, cards);} public void ShadowChooseCardIDFromSelection(PhysicalCardImpl...cards) throws DecisionResultInvalidException { ChooseCardIDFromSelection(P2, cards);} diff --git a/gemp-lotr/gemp-lotr-server/src/test/java/com/gempukku/lotro/cards/official/set08/Card_08_032_Tests.java b/gemp-lotr/gemp-lotr-server/src/test/java/com/gempukku/lotro/cards/official/set08/Card_08_032_Tests.java index 16d875d57..5b1d537c8 100644 --- a/gemp-lotr/gemp-lotr-server/src/test/java/com/gempukku/lotro/cards/official/set08/Card_08_032_Tests.java +++ b/gemp-lotr/gemp-lotr-server/src/test/java/com/gempukku/lotro/cards/official/set08/Card_08_032_Tests.java @@ -17,8 +17,13 @@ public class Card_08_032_Tests return new GenericCardTestHelper( new HashMap<>() {{ - put("card", "8_32"); - // put other cards in here as needed for the test case + put("catapult", "8_32"); + put("fodder1", "8_33"); + put("fodder2", "8_34"); + + put("runner", "1_178"); + put("shelob", "8_25"); + put("larder", "8_23"); }}, GenericCardTestHelper.FellowshipSites, GenericCardTestHelper.FOTRFrodo, @@ -43,7 +48,7 @@ public class Card_08_032_Tests var scn = GetScenario(); - var card = scn.GetFreepsCard("card"); + var card = scn.GetFreepsCard("catapult"); assertEquals("Catapult", card.getBlueprint().getTitle()); assertNull(card.getBlueprint().getSubtitle()); @@ -55,18 +60,63 @@ public class Card_08_032_Tests assertEquals(1, card.getBlueprint().getTwilightCost()); } - // Uncomment any @Test markers below once this is ready to be used - //@Test - public void CatapultTest1() throws DecisionResultInvalidException, CardNotFoundException { + @Test + public void CatapultCantBeUsedWithLessThanTwoCardsInHand() throws DecisionResultInvalidException, CardNotFoundException { //Pre-game setup var scn = GetScenario(); - var card = scn.GetFreepsCard("card"); - scn.FreepsMoveCardToHand(card); + var catapult = scn.GetFreepsCard("catapult"); + scn.FreepsMoveCardToHand("fodder1"); + scn.FreepsMoveCardToSupportArea(catapult); + + scn.ShadowMoveCharToTable("runner"); scn.StartGame(); - scn.FreepsPlayCard(card); + scn.SkipToPhase(Phase.MANEUVER); - assertEquals(1, scn.GetTwilight()); + assertEquals(1, scn.GetFreepsHandCount()); + assertFalse(scn.FreepsActionAvailable(catapult)); + } + + @Test + public void CatapultRevealsTopOfOpponentDeckAndDiscardsShadowCardOfSameCost() throws DecisionResultInvalidException, CardNotFoundException { + //Pre-game setup + var scn = GetScenario(); + + var catapult = scn.GetFreepsCard("catapult"); + scn.FreepsMoveCardToHand("fodder1", "fodder2"); + scn.FreepsMoveCardToSupportArea(catapult); + + var runner = scn.GetShadowCard("runner"); + var shelob = scn.GetShadowCard("shelob"); + var larder = scn.GetShadowCard("larder"); + var evilcatapult = scn.GetShadowCard("catapult"); + scn.ShadowMoveCharToTable(runner, shelob); + scn.ShadowMoveCardToSupportArea(larder); + scn.ShadowMoveCardsToTopOfDeck(evilcatapult); + + scn.StartGame(); + scn.SkipToPhase(Phase.MANEUVER); + + assertEquals(2, scn.GetFreepsHandCount()); + assertEquals(0, scn.GetFreepsDiscardCount()); + assertTrue(scn.FreepsActionAvailable(catapult)); + + scn.FreepsUseCardAction(catapult); + assertEquals(0, scn.GetFreepsHandCount()); + assertEquals(2, scn.GetFreepsDiscardCount()); + assertTrue(scn.FreepsHasCardChoiceAvailable(evilcatapult)); + scn.DismissRevealedCards(); + + assertEquals(2, scn.ShadowGetCardChoiceCount()); + assertTrue(scn.ShadowHasCardChoiceAvailable(runner)); + assertTrue(scn.ShadowHasCardChoiceAvailable(larder)); + assertFalse(scn.ShadowHasCardChoiceAvailable(shelob)); + + assertEquals(Zone.SUPPORT, larder.getZone()); + assertEquals(Zone.SHADOW_CHARACTERS, runner.getZone()); + scn.ShadowChooseCard(larder); + assertEquals(Zone.DISCARD, larder.getZone()); + assertEquals(Zone.SHADOW_CHARACTERS, runner.getZone()); } }