From dd5003e0ef3df38b0d2af5c5a803743c37157921 Mon Sep 17 00:00:00 2001 From: Christian 'ketura' McCarty Date: Sun, 12 Nov 2023 15:06:31 -0600 Subject: [PATCH] Alteration to the CopyCard json functionality - Added a trigger to CopyCard which automatically unapplies/reapplies the copier when the thing they copy is played - Added unit tests for Hobbit Farmer extensively checking each use case; in particular modifier sites vs ability sites - Various minor formatting fixes in other unit tests - Dare I say it? "These stupid site copy allies are finally fixed." --- .../lotro/cards/build/field/FieldUtils.java | 11 + .../cards/build/field/effect/CopyCard.java | 35 ++ .../field/effect/EffectAppenderFactory.java | 1 + .../field/effect/appender/RefreshSelf.java | 38 ++ .../lotro/cards/GenericCardTestHelper.java | 12 +- .../official/set01/Card_01_040_Tests.java | 7 +- .../official/set01/Card_01_295_Tests.java | 347 ++++++++++++++++++ .../errata/set03/Card_03_068_ErrataTests.java | 3 +- .../errata/set03/Card_03_090_ErrataTests.java | 4 +- .../errata/set03/Card_03_103_ErrataTests.java | 4 +- 10 files changed, 456 insertions(+), 6 deletions(-) create mode 100644 gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/effect/appender/RefreshSelf.java create mode 100644 gemp-lotr/gemp-lotr-server/src/test/java/com/gempukku/lotro/cards/official/set01/Card_01_295_Tests.java diff --git a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/FieldUtils.java b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/FieldUtils.java index 65b4dcf42..706ba7dec 100644 --- a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/FieldUtils.java +++ b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/FieldUtils.java @@ -2,9 +2,13 @@ package com.gempukku.lotro.cards.build.field; import com.gempukku.lotro.cards.build.InvalidCardDefinitionException; import com.gempukku.lotro.common.Side; +import org.hjson.JsonValue; import org.json.simple.JSONArray; import org.json.simple.JSONObject; +import org.json.simple.parser.JSONParser; +import org.json.simple.parser.ParseException; +import java.util.Map; import java.util.Set; public class FieldUtils { @@ -106,6 +110,13 @@ public class FieldUtils { } } + private static final JSONParser parser = new JSONParser(); + public static JSONObject parseSubObject(String jsonString) throws ParseException { + String json = JsonValue.readHjson(jsonString).toString(); + var subObject = (JSONObject) parser.parse(json); + return subObject; + } + private static boolean contains(String[] fields, String key) { for (String field : fields) { if (field.equals(key)) diff --git a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/effect/CopyCard.java b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/effect/CopyCard.java index 4dc0f6258..ec738dd9a 100644 --- a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/effect/CopyCard.java +++ b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/effect/CopyCard.java @@ -6,6 +6,7 @@ import com.gempukku.lotro.cards.build.FilterableSource; import com.gempukku.lotro.cards.build.InvalidCardDefinitionException; import com.gempukku.lotro.cards.build.field.EffectProcessor; import com.gempukku.lotro.cards.build.field.FieldUtils; +import com.gempukku.lotro.cards.build.field.effect.trigger.TriggerChecker; import org.json.simple.JSONObject; public class CopyCard implements EffectProcessor { @@ -15,8 +16,42 @@ public class CopyCard implements EffectProcessor { final String filter = FieldUtils.getString(value.get("filter"), "filter"); + final String autoRefreshTriggerString = """ + { + type: trigger + trigger: { + type: played + filter: """ + filter + """ + + } + effect: { + type: RefreshSelf + } + } + """; + final FilterableSource filterableSource = environment.getFilterFactory().generateFilter(filter, environment); blueprint.appendCopiedFilter(filterableSource); + + //Now we add an automatic trigger that unapplies/reapplies this card so that + // modifiers etc do not get stuck. + + try { + var action = FieldUtils.parseSubObject(autoRefreshTriggerString); + var trigger = (JSONObject) action.get("trigger"); + final var triggerChecker = environment + .getTriggerCheckerFactory().getTriggerChecker(trigger, environment); + + var triggerActionSource = new DefaultActionSource(); + triggerActionSource.addPlayRequirement(triggerChecker); + EffectUtils.processRequirementsCostsAndEffects(action, environment, triggerActionSource); + + blueprint.appendRequiredAfterTrigger(triggerActionSource); + } + catch(Exception ex) { + throw new InvalidCardDefinitionException("CopyCard could not create auto refresh trigger.", ex); + } + } } \ No newline at end of file diff --git a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/effect/EffectAppenderFactory.java b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/effect/EffectAppenderFactory.java index 636c376c9..af4f92d61 100644 --- a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/effect/EffectAppenderFactory.java +++ b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/effect/EffectAppenderFactory.java @@ -111,6 +111,7 @@ public class EffectAppenderFactory { effectAppenderProducers.put("putstackedcardsintohand", new PutStackedCardsIntoHand()); effectAppenderProducers.put("reconcilehand", new ReconcileHand()); effectAppenderProducers.put("reducearcherytotal", new ReduceArcheryTotal()); + effectAppenderProducers.put("refreshself", new RefreshSelf()); effectAppenderProducers.put("reinforcetokens", new ReinforceTokens()); effectAppenderProducers.put("removeburdens", new RemoveBurdens()); effectAppenderProducers.put("removecardsindiscardfromgame", new RemoveCardsInDiscardFromGame()); diff --git a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/effect/appender/RefreshSelf.java b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/effect/appender/RefreshSelf.java new file mode 100644 index 000000000..d7ab5efa7 --- /dev/null +++ b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/effect/appender/RefreshSelf.java @@ -0,0 +1,38 @@ +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.field.FieldUtils; +import com.gempukku.lotro.cards.build.field.effect.EffectAppender; +import com.gempukku.lotro.cards.build.field.effect.EffectAppenderProducer; +import com.gempukku.lotro.game.state.LotroGame; +import com.gempukku.lotro.logic.actions.CostToEffectAction; +import com.gempukku.lotro.logic.effects.PutOnTheOneRingEffect; +import com.gempukku.lotro.logic.timing.Effect; +import com.gempukku.lotro.logic.timing.PlayConditions; +import com.gempukku.lotro.logic.timing.UnrespondableEffect; +import org.json.simple.JSONObject; + +public class RefreshSelf implements EffectAppenderProducer { + @Override + public EffectAppender createEffectAppender(JSONObject effectObject, CardGenerationEnvironment environment) throws InvalidCardDefinitionException { + FieldUtils.validateAllowedFields(effectObject); + + //This is intended to be used with cards using CopyCard, such as Hobbit Farmer. + // This very well might have side-effects including removing modifiers applied this turn. + return new DelayedAppender() { + @Override + protected Effect createEffect(boolean cost, CostToEffectAction action, ActionContext ac) { + return new UnrespondableEffect() { + @Override + protected void doPlayEffect(LotroGame game) { + ac.getGame().getGameState().reapplyAffectingForCard(ac.getGame(), ac.getSource()); + } + }; + } + + }; + } + +} 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 e1b4020e2..8a2ceefa4 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 @@ -637,6 +637,16 @@ public class GenericCardTestHelper extends AbstractAtTest { SkipToPhase(Phase.ASSIGNMENT); PassCurrentPhaseActions(); } + public void SkipToMovementDecision() throws DecisionResultInvalidException { + SkipToPhase(Phase.REGROUP); + PassCurrentPhaseActions(); + if(ShadowDecisionAvailable("reconcile")) { + ShadowDeclineReconciliation(); + } + while(ShadowDecisionAvailable("discard down")) { + ShadowChooseCard((PhysicalCardImpl) GetShadowHand().get(0)); + } + } public void SkipToPhase(Phase target) throws DecisionResultInvalidException { for(int attempts = 1; attempts <= 20; attempts++) { @@ -1040,7 +1050,7 @@ public class GenericCardTestHelper extends AbstractAtTest { { ShadowDeclineReconciliation(); } - if(ShadowDecisionAvailable("discard down")) + while(ShadowDecisionAvailable("discard down")) { ShadowChooseCard((PhysicalCardImpl) GetShadowHand().get(0)); } diff --git a/gemp-lotr/gemp-lotr-server/src/test/java/com/gempukku/lotro/cards/official/set01/Card_01_040_Tests.java b/gemp-lotr/gemp-lotr-server/src/test/java/com/gempukku/lotro/cards/official/set01/Card_01_040_Tests.java index d8fffa28b..fa2ca472d 100644 --- a/gemp-lotr/gemp-lotr-server/src/test/java/com/gempukku/lotro/cards/official/set01/Card_01_040_Tests.java +++ b/gemp-lotr/gemp-lotr-server/src/test/java/com/gempukku/lotro/cards/official/set01/Card_01_040_Tests.java @@ -1,8 +1,7 @@ package com.gempukku.lotro.cards.official.set01; import com.gempukku.lotro.cards.GenericCardTestHelper; -import com.gempukku.lotro.common.Phase; -import com.gempukku.lotro.common.SitesBlock; +import com.gempukku.lotro.common.*; import com.gempukku.lotro.game.CardNotFoundException; import com.gempukku.lotro.game.PhysicalCardImpl; import com.gempukku.lotro.logic.decisions.DecisionResultInvalidException; @@ -72,6 +71,10 @@ public class Card_01_040_Tests PhysicalCardImpl elrond = scn.GetFreepsCard("elrond"); assertTrue(elrond.getBlueprint().isUnique()); + assertEquals(Side.FREE_PEOPLE, elrond.getBlueprint().getSide()); + assertEquals(Culture.ELVEN, elrond.getBlueprint().getCulture()); + assertEquals(CardType.ALLY, elrond.getBlueprint().getCardType()); + assertEquals(Race.ELF, elrond.getBlueprint().getRace()); assertEquals(4, elrond.getBlueprint().getTwilightCost()); assertEquals(8, elrond.getBlueprint().getStrength()); assertEquals(4, elrond.getBlueprint().getVitality()); diff --git a/gemp-lotr/gemp-lotr-server/src/test/java/com/gempukku/lotro/cards/official/set01/Card_01_295_Tests.java b/gemp-lotr/gemp-lotr-server/src/test/java/com/gempukku/lotro/cards/official/set01/Card_01_295_Tests.java new file mode 100644 index 000000000..a45e60165 --- /dev/null +++ b/gemp-lotr/gemp-lotr-server/src/test/java/com/gempukku/lotro/cards/official/set01/Card_01_295_Tests.java @@ -0,0 +1,347 @@ +package com.gempukku.lotro.cards.official.set01; + +import com.gempukku.lotro.cards.GenericCardTestHelper; +import com.gempukku.lotro.common.*; +import com.gempukku.lotro.game.CardNotFoundException; +import com.gempukku.lotro.game.PhysicalCardImpl; +import com.gempukku.lotro.logic.decisions.DecisionResultInvalidException; +import org.junit.Test; + +import java.util.HashMap; + +import static org.junit.Assert.*; + +public class Card_01_295_Tests +{ + + protected GenericCardTestHelper GetScenario() throws CardNotFoundException, DecisionResultInvalidException { + return new GenericCardTestHelper( + new HashMap<>() + {{ + put("farmer", "1_295"); + put("farmer2", "1_295"); + put("merry", "4_310"); + put("pippin", "4_314"); + + }}, + new HashMap<>() {{ + put("site1", "1_321"); + put("site2", "1_327"); + put("site3", "1_337"); + put("site4", "1_343"); + put("site5", "1_349"); + put("site6", "1_350"); + put("site7", "1_353"); + put("site8", "1_356"); + put("site9", "1_360"); + }}, + GenericCardTestHelper.FOTRFrodo, + GenericCardTestHelper.RulingRing + ); + } + + protected GenericCardTestHelper GetDiscountScenario() throws CardNotFoundException, DecisionResultInvalidException { + return new GenericCardTestHelper( + new HashMap<>() + {{ + put("farmer", "1_295"); + put("farmer2", "1_295"); + put("merry", "4_310"); + put("pippin", "4_314"); + put("sam", "1_311"); + }}, + new HashMap<>() {{ + put("site1", "1_323"); + put("site2", "1_327"); + put("site3", "1_337"); + put("site4", "1_343"); + put("site5", "1_349"); + put("site6", "1_350"); + put("site7", "1_353"); + put("site8", "1_356"); + put("site9", "1_360"); + }}, + GenericCardTestHelper.FOTRFrodo, + GenericCardTestHelper.RulingRing + ); + } + + @Test + public void FarmerStatsAndKeywordsAreCorrect() throws DecisionResultInvalidException, CardNotFoundException { + + /** + * Set: 1 + * Title: Hobbit Farmer + * Unique: false + * Side: Free Peoples + * Culture: Shire + * Twilight Cost: 1 + * Type: Ally + * Race: Hobbit + * Game Text: While you can spot your site 1, this ally has the game text of that site. + * Fellowship: Exert this ally and spot your opponent's site 1 to replace it with your site 1. + */ + + //Pre-game setup + var scn = GetScenario(); + + var farmer = scn.GetFreepsCard("farmer"); + + assertFalse(farmer.getBlueprint().isUnique()); + assertEquals(Side.FREE_PEOPLE, farmer.getBlueprint().getSide()); + assertEquals(Culture.SHIRE, farmer.getBlueprint().getCulture()); + assertEquals(CardType.ALLY, farmer.getBlueprint().getCardType()); + assertEquals(Race.HOBBIT, farmer.getBlueprint().getRace()); + assertEquals(1, farmer.getBlueprint().getTwilightCost()); + assertEquals(2, farmer.getBlueprint().getStrength()); + assertEquals(2, farmer.getBlueprint().getVitality()); + assertEquals(1, farmer.getBlueprint().getAllyHomeSiteNumbers()[0]); + assertEquals(SitesBlock.FELLOWSHIP, farmer.getBlueprint().getAllyHomeSiteBlock()); + + } + + @Test + public void FarmerCopiesAbilitiesOnOwnSite1ButNotOpponentSite1() throws DecisionResultInvalidException, CardNotFoundException { + //Pre-game setup + var scn = GetScenario(); + + //Player 1 version of the Farmer will test copying one's own site + var freepsFarmer = scn.GetFreepsCard("farmer"); + var merry = scn.GetFreepsCard("merry"); + var pippin = scn.GetFreepsCard("pippin"); + scn.FreepsMoveCardToSupportArea(freepsFarmer); + scn.AddWoundsToChar(freepsFarmer, 1); // To ensure the exert ability isn't available + scn.FreepsMoveCardsToTopOfDeck(merry, pippin); + + //Player 2 version of the Farmer will test copying the enemy site + var evilFarmer = scn.GetShadowCard("farmer"); + var evilMerry = scn.GetShadowCard("merry"); + var evilPippin = scn.GetShadowCard("pippin"); + scn.ShadowMoveCardToSupportArea(evilFarmer); + scn.AddWoundsToChar(evilFarmer, 1); // To ensure the exert ability isn't available + + scn.StartGame(); + + assertTrue(scn.FreepsActionAvailable("Farmer Maggot's Fields")); + assertTrue(scn.FreepsActionAvailable("Use Hobbit Farmer")); + + scn.SkipToMovementDecision(); + scn.ShadowMoveCardsToTopOfDeck(evilMerry, evilPippin); + scn.FreepsChooseToStay(); + + assertEquals(Phase.FELLOWSHIP, scn.GetCurrentPhase()); + assertEquals(1, scn.GetVitality(evilFarmer)); + + //Since the site is player 1's, player 2 should not have access to it via Hobbit Farmer, only natively + assertTrue(scn.ShadowActionAvailable("Farmer Maggot's Fields")); + assertFalse(scn.ShadowActionAvailable("Use Hobbit Farmer")); + } + + @Test + public void FarmerCopiesModifiersOnOwnSite1ButNotOpponentSite1() throws DecisionResultInvalidException, CardNotFoundException { + //Pre-game setup + var scn = GetDiscountScenario(); + + //Player 1 version of the Farmer will test copying one's own site + var freepsFarmer = scn.GetFreepsCard("farmer"); + var sam = scn.GetFreepsCard("sam"); + scn.FreepsMoveCardToSupportArea(freepsFarmer); + scn.FreepsMoveCardToHand(sam); + + //Player 2 version of the Farmer will test copying the enemy site + var evilFarmer = scn.GetShadowCard("farmer"); + var evilSam = scn.GetShadowCard("sam"); + scn.ShadowMoveCardToSupportArea(evilFarmer); + scn.ShadowMoveCardToHand(evilSam); + + scn.StartGame(); + + assertEquals(2, sam.getBlueprint().getTwilightCost()); + assertEquals(0, scn.GetTwilight()); + scn.FreepsPlayCard(sam); + //Both the Green Hill Country and Hobbit Farmer should have stacked to make Sam -2. + assertEquals(0, scn.GetTwilight()); + + scn.SkipToMovementDecision(); + scn.FreepsChooseToStay(); + + assertEquals(Phase.FELLOWSHIP, scn.GetCurrentPhase()); + + //Since the site is player 1's, player 2 should not have access to it via Hobbit Farmer, only natively + assertEquals(2, evilSam.getBlueprint().getTwilightCost()); + assertEquals(0, scn.GetTwilight()); + scn.ShadowPlayCard(evilSam); + assertEquals(1, scn.GetTwilight()); + } + + @Test + public void FarmerAbilityExertsToReplaceOpponentsSite1() throws DecisionResultInvalidException, CardNotFoundException { + //Pre-game setup + var scn = GetScenario(); + + var opponentSite1 = scn.GetCurrentSite(); + scn.FreepsMoveCardToSupportArea("farmer"); + + //Player 2 version of the Farmer will test replacing + var evilFarmer = scn.GetShadowCard("farmer"); + var evilMerry = scn.GetShadowCard("merry"); + var evilPippin = scn.GetShadowCard("pippin"); + var site1 = scn.GetShadowSite("site1"); + + scn.ShadowMoveCardToSupportArea(evilFarmer); + + scn.StartGame(); + + assertFalse(scn.FreepsDecisionAvailable("Use Hobbit Farmer")); + + scn.SkipToMovementDecision(); + scn.ShadowMoveCardsToTopOfDeck(evilMerry, evilPippin); + scn.FreepsChooseToStay(); + + assertEquals(Phase.FELLOWSHIP, scn.GetCurrentPhase()); + + assertSame(opponentSite1, scn.GetCurrentSite()); + assertEquals(Zone.ADVENTURE_DECK, site1.getZone()); + assertTrue(scn.ShadowActionAvailable(evilFarmer)); + assertEquals(2, scn.GetVitality(evilFarmer)); + + scn.ShadowUseCardAction(evilFarmer); + + assertSame(site1, scn.GetCurrentSite()); + assertEquals(Zone.ADVENTURE_DECK, opponentSite1.getZone()); + assertEquals(1, scn.GetVitality(evilFarmer)); + + //Now that we have replaced the site, the Hobbit Farmer should now automatically be copying it. + assertTrue(scn.ShadowActionAvailable("Farmer Maggot's Fields")); + assertTrue(scn.ShadowActionAvailable("Use Hobbit Farmer")); + } + + @Test + public void FarmerImmediatelyCopiesAbilitiesAfterReplacingDownThePath() throws DecisionResultInvalidException, CardNotFoundException { + //Pre-game setup + var scn = GetScenario(); + + var opponentSite1 = scn.GetCurrentSite(); + scn.FreepsMoveCardToSupportArea("farmer"); + + //Player 2 version of the Farmer will test replacing + var evilFarmer = scn.GetShadowCard("farmer"); + var evilMerry = scn.GetShadowCard("merry"); + var evilPippin = scn.GetShadowCard("pippin"); + var site1 = scn.GetShadowSite("site1"); + + scn.ShadowMoveCardToSupportArea(evilFarmer); + + scn.StartGame(); + + assertFalse(scn.FreepsDecisionAvailable("Use Hobbit Farmer")); + + //Getting everyone far away from site 1 + scn.SkipToSite(3); + + scn.SkipToMovementDecision(); + scn.ShadowMoveCardsToTopOfDeck(evilMerry, evilPippin); + scn.FreepsChooseToStay(); + scn.FreepsDeclineReconciliation(); + + assertEquals(Phase.FELLOWSHIP, scn.GetCurrentPhase()); + + assertEquals(Zone.ADVENTURE_PATH, opponentSite1.getZone()); + assertEquals(Zone.ADVENTURE_DECK, site1.getZone()); + assertTrue(scn.ShadowActionAvailable(evilFarmer)); + assertEquals(2, scn.GetVitality(evilFarmer)); + + scn.ShadowUseCardAction(evilFarmer); + + assertEquals(Zone.ADVENTURE_PATH, site1.getZone()); + assertEquals(Zone.ADVENTURE_DECK, opponentSite1.getZone()); + assertEquals(1, scn.GetVitality(evilFarmer)); + + //Now that we have replaced the site, the Hobbit Farmer should now automatically be copying it. + assertTrue(scn.ShadowActionAvailable("Use Hobbit Farmer")); + } + + @Test + public void FarmerCopiesModifiersDownThePath() throws DecisionResultInvalidException, CardNotFoundException { + //Pre-game setup + var scn = GetDiscountScenario(); + + var farmer = scn.GetFreepsCard("farmer"); + var merry = scn.GetFreepsCard("merry"); + var pippin = scn.GetFreepsCard("pippin"); + var site1 = scn.GetCurrentSite(); + scn.FreepsMoveCardToSupportArea("farmer"); + scn.FreepsMoveCardToHand(merry, pippin); + + var opponentSite1 = scn.GetShadowSite("site1"); + + scn.StartGame(); + + //Ensuring Green Hill Country's -1 twilight discount is working natively. + assertEquals(1, pippin.getBlueprint().getTwilightCost()); + assertEquals(0, scn.GetTwilight()); + scn.FreepsPlayCard(pippin); + assertEquals(0, scn.GetTwilight()); + + //Getting everyone far away from site 1 + scn.SkipToSite(3); + + assertEquals(Phase.FELLOWSHIP, scn.GetCurrentPhase()); + + assertEquals(Zone.ADVENTURE_DECK, opponentSite1.getZone()); + assertEquals(Zone.ADVENTURE_PATH, site1.getZone()); + + //We've never replaced the site, but the Hobbit Farmer should still automatically be copying the twilight discount. + assertEquals(1, merry.getBlueprint().getTwilightCost()); + assertEquals(0, scn.GetTwilight()); + scn.FreepsPlayCard(merry); + assertEquals(0, scn.GetTwilight()); + } + + @Test + public void FarmerImmediatelyCopiesModifiersAfterReplacingDownThePath() throws DecisionResultInvalidException, CardNotFoundException { + //Pre-game setup + var scn = GetDiscountScenario(); + + var opponentSite1 = scn.GetCurrentSite(); + scn.FreepsMoveCardToSupportArea("farmer"); + + //Player 2 version of the Farmer will test replacing + var evilFarmer = scn.GetShadowCard("farmer"); + var evilMerry = scn.GetShadowCard("merry"); + var site1 = scn.GetShadowSite("site1"); + + scn.ShadowMoveCardToSupportArea(evilFarmer); + + scn.StartGame(); + + assertFalse(scn.FreepsDecisionAvailable("Use Hobbit Farmer")); + + //Getting everyone far away from site 1 + scn.SkipToSite(3); + + scn.SkipToMovementDecision(); + scn.FreepsChooseToStay(); + scn.FreepsDeclineReconciliation(); + + assertEquals(Phase.FELLOWSHIP, scn.GetCurrentPhase()); + + assertEquals(Zone.ADVENTURE_PATH, opponentSite1.getZone()); + assertEquals(Zone.ADVENTURE_DECK, site1.getZone()); + assertTrue(scn.ShadowActionAvailable(evilFarmer)); + assertEquals(2, scn.GetVitality(evilFarmer)); + + scn.ShadowUseCardAction(evilFarmer); + + assertEquals(Zone.ADVENTURE_PATH, site1.getZone()); + assertEquals(Zone.ADVENTURE_DECK, opponentSite1.getZone()); + assertEquals(1, scn.GetVitality(evilFarmer)); + + //Now that we have replaced the site, the Hobbit Farmer should now automatically be copying the twilight discount. + assertEquals(1, evilMerry.getBlueprint().getTwilightCost()); + assertEquals(0, scn.GetTwilight()); + scn.ShadowPlayCard(evilMerry); + assertEquals(0, scn.GetTwilight()); + } + +} diff --git a/gemp-lotr/gemp-lotr-server/src/test/java/com/gempukku/lotro/cards/unofficial/pc/errata/set03/Card_03_068_ErrataTests.java b/gemp-lotr/gemp-lotr-server/src/test/java/com/gempukku/lotro/cards/unofficial/pc/errata/set03/Card_03_068_ErrataTests.java index 64ed5ac90..15cd143aa 100644 --- a/gemp-lotr/gemp-lotr-server/src/test/java/com/gempukku/lotro/cards/unofficial/pc/errata/set03/Card_03_068_ErrataTests.java +++ b/gemp-lotr/gemp-lotr-server/src/test/java/com/gempukku/lotro/cards/unofficial/pc/errata/set03/Card_03_068_ErrataTests.java @@ -27,6 +27,7 @@ public class Card_03_068_ErrataTests ); } + @Test public void SarumanStatsAndKeywordsAreCorrect() throws DecisionResultInvalidException, CardNotFoundException { /** @@ -59,7 +60,7 @@ public class Card_03_068_ErrataTests assertEquals(4, saruman.getBlueprint().getTwilightCost()); assertEquals(8, saruman.getBlueprint().getStrength()); assertEquals(4, saruman.getBlueprint().getVitality()); - assertEquals(4, saruman.getBlueprint().getSiteNumber()); // Change this to getAllyHomeSiteNumbers for allies + assertEquals(4, saruman.getBlueprint().getSiteNumber()); } @Test diff --git a/gemp-lotr/gemp-lotr-server/src/test/java/com/gempukku/lotro/cards/unofficial/pc/errata/set03/Card_03_090_ErrataTests.java b/gemp-lotr/gemp-lotr-server/src/test/java/com/gempukku/lotro/cards/unofficial/pc/errata/set03/Card_03_090_ErrataTests.java index 48088d8d2..4fd7825f8 100644 --- a/gemp-lotr/gemp-lotr-server/src/test/java/com/gempukku/lotro/cards/unofficial/pc/errata/set03/Card_03_090_ErrataTests.java +++ b/gemp-lotr/gemp-lotr-server/src/test/java/com/gempukku/lotro/cards/unofficial/pc/errata/set03/Card_03_090_ErrataTests.java @@ -45,7 +45,9 @@ public class Card_03_090_ErrataTests * Twilight Cost: 0 * Type: event * Subtype: Maneuver - * Game Text: Exert a unique [sauron] minion to exert a companion (except the Ring-bearer) and discard a possession attached to that companion. The Free Peoples player may discard 1 hand at random from their hand to prevent this. + * Game Text: Exert a unique [sauron] minion to exert a companion (except the Ring-bearer) and + * discard a possession attached to that companion. The Free Peoples player may discard 1 + * card at random from their hand to prevent this. */ //Pre-game setup 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 index 793e198d6..b59d3a38d 100644 --- 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 @@ -65,7 +65,9 @@ public class Card_03_103_ErrataTests * 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. + * 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