From 4c9f31d862ad35d38b512e7b68409a897d041965 Mon Sep 17 00:00:00 2001 From: Christian 'ketura' McCarty Date: Sat, 11 Mar 2023 00:50:23 -0600 Subject: [PATCH] Hopefully fixing the Terrible as the Dawn errata --- .../pc/errata/set03/set03-Sauron-errata.hjson | 117 ++++--- .../field/effect/EventEffectProcessor.java | 4 +- .../errata/set03/Card_03_103_ErrataTests.java | 286 ++++++++++++++++++ 3 files changed, 345 insertions(+), 62 deletions(-) create mode 100644 gemp-lotr/gemp-lotr-server/src/test/java/com/gempukku/lotro/cards/unofficial/pc/errata/set03/Card_03_103_ErrataTests.java diff --git a/gemp-lotr/gemp-lotr-cards/src/main/resources/cards/unofficial/pc/errata/set03/set03-Sauron-errata.hjson b/gemp-lotr/gemp-lotr-cards/src/main/resources/cards/unofficial/pc/errata/set03/set03-Sauron-errata.hjson index 6b92e23aa..d4ea260b9 100644 --- a/gemp-lotr/gemp-lotr-cards/src/main/resources/cards/unofficial/pc/errata/set03/set03-Sauron-errata.hjson +++ b/gemp-lotr/gemp-lotr-cards/src/main/resources/cards/unofficial/pc/errata/set03/set03-Sauron-errata.hjson @@ -493,74 +493,71 @@ ] effects: { type: event - effect: { - type: conditional - effect: { - type: choice - texts: [ - Ring-bound Galadriel - Unbound/Ally Galadriel - ] - effects: [ - { - type: conditional - requires: { - type: CanSpot - filter: title(Galadriel),Ring-bound + effect: { + type: choice + texts: [ + Ring-bound Galadriel + Unbound/Ally Galadriel + ] + effects: [ + { + type: conditional + requires: { + type: CanSpot + filter: title(Galadriel),Ring-bound + } + effect: { + type: preventable + player: freeps + cost: { + type: choice + texts: [ + Discard 2 Elves + Add 2 burdens + ] + effects: [ + { + type: discard + filter: choose(Elf) + count: 2 + } + { + type: AddBurdens + amount: 2 + } + ] } + text: Discard 2 Elves or add 2 burdens to prevent wounding Galadriel 3 times effect: { - type: preventable - player: freeps - cost: { - type: choice - texts: [ - Discard 2 Elves - Add 2 burdens - ] - effects: [ - { - type: discard - filter: choose(Elf) - count: 2 - } - { - type: AddBurdens - amount: 2 - } - ] - } - text: Discard 2 Elves or add 2 burdens to prevent wounding Galadriel 3 times - effect: { - type: wound - times: 3 - filter: choose(title(Galadriel)) - } + type: wound + times: 3 + filter: choose(title(Galadriel)) } } - { - type: conditional - requires: { - type: CantSpot - filter: title(Galadriel),Ring-bound + } + { + type: conditional + requires: { + type: CantSpot + filter: title(Galadriel),Ring-bound + } + effect: { + type: preventable + player: freeps + cost: { + type: discard + filter: choose(Elf) + count: 2 } + text: Discard 2 Elves to prevent wounding Galadriel 3 times effect: { - type: preventable - player: freeps - cost: { - type: discard - filter: choose(Elf) - count: 2 - } - text: Discard 2 Elves to prevent wounding Galadriel 3 times - effect: { - type: wound - times: 3 - filter: choose(title(Galadriel)) - } + type: wound + times: 3 + filter: choose(title(Galadriel)) } } - ] - } + } + ] } } gametext: Maneuver: Spot a [sauron] minion to wound Galadriel 3 times. The Free Peoples player may discard 2 Elves to prevent this. If Galadriel is Ring-bound, 2 burdens may be added instead. diff --git a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/effect/EventEffectProcessor.java b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/effect/EventEffectProcessor.java index 40a2a2845..4883cb369 100644 --- a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/effect/EventEffectProcessor.java +++ b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/effect/EventEffectProcessor.java @@ -10,14 +10,14 @@ import org.json.simple.JSONObject; public class EventEffectProcessor implements EffectProcessor { @Override public void processEffect(JSONObject value, BuiltLotroCardBlueprint blueprint, CardGenerationEnvironment environment) throws InvalidCardDefinitionException { - FieldUtils.validateAllowedFields(value, "cost", "effect", "requiresRanger"); + FieldUtils.validateAllowedFields(value, "cost", "effect", "requires", "requiresRanger"); final boolean requiresRanger = FieldUtils.getBoolean(value.get("requiresRanger"), "requiresRanger", false); DefaultActionSource actionSource = new DefaultActionSource(); actionSource.setRequiresRanger(requiresRanger); - EffectUtils.processCostsAndEffects(value, environment, actionSource); + EffectUtils.processRequirementsCostsAndEffects(value, environment, actionSource); blueprint.setPlayEventAction(actionSource); } diff --git a/gemp-lotr/gemp-lotr-server/src/test/java/com/gempukku/lotro/cards/unofficial/pc/errata/set03/Card_03_103_ErrataTests.java b/gemp-lotr/gemp-lotr-server/src/test/java/com/gempukku/lotro/cards/unofficial/pc/errata/set03/Card_03_103_ErrataTests.java new file mode 100644 index 000000000..df42465dd --- /dev/null +++ b/gemp-lotr/gemp-lotr-server/src/test/java/com/gempukku/lotro/cards/unofficial/pc/errata/set03/Card_03_103_ErrataTests.java @@ -0,0 +1,286 @@ +package com.gempukku.lotro.cards.unofficial.pc.errata.set03; + +import com.gempukku.lotro.cards.GenericCardTestHelper; +import com.gempukku.lotro.common.*; +import com.gempukku.lotro.game.CardNotFoundException; +import com.gempukku.lotro.logic.decisions.DecisionResultInvalidException; +import org.junit.Test; + +import java.util.HashMap; + +import static org.junit.Assert.*; + +public class Card_03_103_ErrataTests +{ + + protected GenericCardTestHelper GetUnboundScenario() throws CardNotFoundException, DecisionResultInvalidException { + return new GenericCardTestHelper( + new HashMap<>() + {{ + put("terrible", "53_103"); + put("troll", "6_106"); + put("din", "7_267"); + put("runner", "1_178"); + + put("galadriel", "1_45"); + put("greenleaf", "1_50"); + put("arwen", "1_30"); + put("hosts", "2_18"); + }}, + GenericCardTestHelper.FellowshipSites, + GenericCardTestHelper.FOTRFrodo, + GenericCardTestHelper.FOTRRing + ); + } + + protected GenericCardTestHelper GetRBScenario() throws CardNotFoundException, DecisionResultInvalidException { + return new GenericCardTestHelper( + new HashMap<>() + {{ + put("terrible", "53_103"); + put("troll", "6_106"); + put("din", "7_267"); + put("runner", "1_178"); + + put("galadriel", "1_45"); + put("greenleaf", "1_50"); + put("arwen", "1_30"); + put("hosts", "2_18"); + }}, + GenericCardTestHelper.FellowshipSites, + GenericCardTestHelper.GaladrielRB, + GenericCardTestHelper.FOTRRing + ); + } + + @Test + public void TerribleastheDawnStatsAndKeywordsAreCorrect() throws DecisionResultInvalidException, CardNotFoundException { + + /** + * Set: 3 + * Title: Terrible as the Dawn + * Unique: False + * Side: SHADOW + * Culture: Sauron + * Twilight Cost: 0 + * Type: event + * Subtype: + * Game Text: Maneuver: Spot a [sauron] minion to wound Galadriel 3 times. The Free Peoples player may discard 2 Elves to prevent this. If Galadriel is Ring-bound, 2 burdens may be added instead. + */ + + //Pre-game setup + var scn = GetUnboundScenario(); + + var terrible = scn.GetFreepsCard("terrible"); + + assertFalse(terrible.getBlueprint().isUnique()); + assertEquals(Side.SHADOW, terrible.getBlueprint().getSide()); + assertEquals(Culture.SAURON, terrible.getBlueprint().getCulture()); + assertEquals(CardType.EVENT, terrible.getBlueprint().getCardType()); + assertTrue(scn.HasKeyword(terrible, Keyword.MANEUVER)); + assertEquals(0, terrible.getBlueprint().getTwilightCost()); + } + + @Test + public void TerribleastheDawnRequiresSauronMinion() throws DecisionResultInvalidException, CardNotFoundException { + //Pre-game setup + var scn = GetUnboundScenario(); + + var terrible = scn.GetShadowCard("terrible"); + var din = scn.GetShadowCard("din"); + var troll = scn.GetShadowCard("troll"); + scn.ShadowMoveCardToHand(terrible, din, troll); + scn.ShadowMoveCharToTable("runner"); //needed so that the maneuver phase is accessible + + var galadriel = scn.GetFreepsCard("galadriel"); + scn.FreepsMoveCharToTable(galadriel); + + scn.StartGame(); + scn.SetTwilight(20); + + scn.SkipToPhase(Phase.MANEUVER); + scn.FreepsPassCurrentPhaseAction(); + assertFalse(scn.ShadowPlayAvailable(terrible)); + scn.ShadowMoveCharToTable(troll); + + scn.ShadowPlayCard(din); // we only do this to perform a maneuver action and refresh what actions are available + scn.FreepsPassCurrentPhaseAction(); + assertEquals(Zone.FREE_CHARACTERS, galadriel.getZone()); + assertTrue(scn.ShadowPlayAvailable(terrible)); + scn.ShadowPlayCard(terrible); + assertEquals(Zone.DEAD, galadriel.getZone()); + } + + @Test + public void UnboundGaladrielIsWounded3Times() throws DecisionResultInvalidException, CardNotFoundException { + //Pre-game setup + var scn = GetUnboundScenario(); + + var terrible = scn.GetShadowCard("terrible"); + var troll = scn.GetShadowCard("troll"); + scn.ShadowMoveCardToHand(terrible); + scn.ShadowMoveCharToTable(troll); + + var galadriel = scn.GetFreepsCard("galadriel"); + scn.FreepsMoveCharToTable(galadriel); + scn.FreepsMoveCardToSupportArea("hosts"); + + scn.StartGame(); + + scn.SkipToPhase(Phase.MANEUVER); + scn.FreepsPassCurrentPhaseAction(); + scn.ShadowPlayCard(terrible); + + assertEquals(Zone.FREE_CHARACTERS, galadriel.getZone()); + assertEquals(0, scn.GetWoundsOn(galadriel)); + scn.FreepsDeclineOptionalTrigger(); + assertEquals(1, scn.GetWoundsOn(galadriel)); + scn.FreepsDeclineOptionalTrigger(); + assertEquals(2, scn.GetWoundsOn(galadriel)); + scn.FreepsDeclineOptionalTrigger(); + assertEquals(Zone.DEAD, galadriel.getZone()); + } + + @Test + public void UnboundGaladrielCanDiscard2ElvesToSaveGaladriel() throws DecisionResultInvalidException, CardNotFoundException { + //Pre-game setup + var scn = GetUnboundScenario(); + + var terrible = scn.GetShadowCard("terrible"); + scn.ShadowMoveCardToHand(terrible); + scn.ShadowMoveCharToTable("troll"); + + var galadriel = scn.GetFreepsCard("galadriel"); + var greenleaf = scn.GetFreepsCard("greenleaf"); + var arwen = scn.GetFreepsCard("arwen"); + scn.FreepsMoveCharToTable(galadriel, greenleaf, arwen); + scn.FreepsMoveCardToSupportArea("hosts"); + + scn.StartGame(); + + scn.SkipToPhase(Phase.MANEUVER); + scn.FreepsPassCurrentPhaseAction(); + scn.ShadowPlayCard(terrible); + + assertEquals(Zone.FREE_CHARACTERS, galadriel.getZone()); + assertEquals(Zone.FREE_CHARACTERS, greenleaf.getZone()); + assertEquals(Zone.FREE_CHARACTERS, arwen.getZone()); + + assertTrue(scn.FreepsDecisionAvailable("Discard 2 Elves to prevent wounding Galadriel")); + scn.FreepsChooseYes(); + scn.FreepsChooseCards(greenleaf, arwen); + + assertEquals(Zone.FREE_CHARACTERS, galadriel.getZone()); + assertEquals(Zone.DISCARD, greenleaf.getZone()); + assertEquals(Zone.DISCARD, arwen.getZone()); + } + + @Test + public void RBGaladrielIsWounded3Times() throws DecisionResultInvalidException, CardNotFoundException { + //Pre-game setup + var scn = GetRBScenario(); + + var terrible = scn.GetShadowCard("terrible"); + var troll = scn.GetShadowCard("troll"); + scn.ShadowMoveCardToHand(terrible); + scn.ShadowMoveCharToTable(troll); + + var galadriel = scn.GetRingBearer(); + scn.FreepsMoveCardToSupportArea("hosts"); + + scn.StartGame(); + + scn.SkipToPhase(Phase.MANEUVER); + scn.FreepsPassCurrentPhaseAction(); + scn.ShadowPlayCard(terrible); + + scn.FreepsChooseNo(); + + assertEquals(Zone.FREE_CHARACTERS, galadriel.getZone()); + assertEquals(0, scn.GetWoundsOn(galadriel)); + scn.FreepsDeclineOptionalTrigger(); + assertEquals(1, scn.GetWoundsOn(galadriel)); + scn.FreepsDeclineOptionalTrigger(); + assertEquals(2, scn.GetWoundsOn(galadriel)); + scn.FreepsDeclineOptionalTrigger(); + assertEquals(Zone.DEAD, galadriel.getZone()); + } + + @Test + public void RBGaladrielCanDiscard2ElvesToSaveGaladriel() throws DecisionResultInvalidException, CardNotFoundException { + //Pre-game setup + var scn = GetRBScenario(); + + var terrible = scn.GetShadowCard("terrible"); + scn.ShadowMoveCardToHand(terrible); + scn.ShadowMoveCharToTable("troll"); + + var galadriel = scn.GetRingBearer(); + var greenleaf = scn.GetFreepsCard("greenleaf"); + var arwen = scn.GetFreepsCard("arwen"); + scn.FreepsMoveCharToTable(greenleaf, arwen); + scn.FreepsMoveCardToSupportArea("hosts"); + + scn.StartGame(); + + scn.SkipToPhase(Phase.MANEUVER); + scn.FreepsPassCurrentPhaseAction(); + scn.ShadowPlayCard(terrible); + + assertEquals(0, scn.GetWoundsOn(galadriel)); + assertEquals(Zone.FREE_CHARACTERS, galadriel.getZone()); + assertEquals(Zone.FREE_CHARACTERS, greenleaf.getZone()); + assertEquals(Zone.FREE_CHARACTERS, arwen.getZone()); + + assertTrue(scn.FreepsDecisionAvailable("Discard 2 Elves or add 2 burdens to prevent wounding Galadriel 3 times")); + scn.FreepsChooseYes(); + assertTrue(scn.FreepsChoiceAvailable("Discard 2 Elves")); + assertTrue(scn.FreepsChoiceAvailable("Add 2 burdens")); + scn.FreepsChooseMultipleChoiceOption("Discard"); + + assertEquals(0, scn.GetWoundsOn(galadriel)); + assertEquals(Zone.FREE_CHARACTERS, galadriel.getZone()); + assertEquals(Zone.DISCARD, greenleaf.getZone()); + assertEquals(Zone.DISCARD, arwen.getZone()); + } + + @Test + public void RBGaladrielCanAdd2BurdensToSaveGaladriel() throws DecisionResultInvalidException, CardNotFoundException { + //Pre-game setup + var scn = GetRBScenario(); + + var terrible = scn.GetShadowCard("terrible"); + scn.ShadowMoveCardToHand(terrible); + scn.ShadowMoveCharToTable("troll"); + + var galadriel = scn.GetRingBearer(); + var greenleaf = scn.GetFreepsCard("greenleaf"); + var arwen = scn.GetFreepsCard("arwen"); + scn.FreepsMoveCharToTable(greenleaf, arwen); + scn.FreepsMoveCardToSupportArea("hosts"); + + scn.StartGame(); + + scn.SkipToPhase(Phase.MANEUVER); + scn.FreepsPassCurrentPhaseAction(); + scn.ShadowPlayCard(terrible); + + assertEquals(0, scn.GetWoundsOn(galadriel)); + assertEquals(1, scn.GetBurdens()); + assertEquals(Zone.FREE_CHARACTERS, galadriel.getZone()); + assertEquals(Zone.FREE_CHARACTERS, greenleaf.getZone()); + assertEquals(Zone.FREE_CHARACTERS, arwen.getZone()); + + assertTrue(scn.FreepsDecisionAvailable("Discard 2 Elves or add 2 burdens to prevent wounding Galadriel 3 times")); + scn.FreepsChooseYes(); + assertTrue(scn.FreepsChoiceAvailable("Discard 2 Elves")); + assertTrue(scn.FreepsChoiceAvailable("Add 2 burdens")); + scn.FreepsChooseMultipleChoiceOption("Burdens"); + + assertEquals(0, scn.GetWoundsOn(galadriel)); + assertEquals(3, scn.GetBurdens()); + assertEquals(Zone.FREE_CHARACTERS, galadriel.getZone()); + assertEquals(Zone.FREE_CHARACTERS, greenleaf.getZone()); + assertEquals(Zone.FREE_CHARACTERS, arwen.getZone()); + } +}