From 9ca35cee95ef1ad3440a71ff4c9174efbe34d8e9 Mon Sep 17 00:00:00 2001 From: Christian 'ketura' McCarty Date: Tue, 2 Aug 2022 17:09:43 -0500 Subject: [PATCH] Converted All Life Flees and wrote unit tests for it, before realizing it's not actually broken, it's just bad. --- .../main/web/cards/set18/set18-wraith.json | 40 ++++ .../lotro/cards/set18/wraith/Card18_132.java | 80 ------- .../effect/appender/PlayCardFromDrawDeck.java | 2 +- .../official/set18/Card_18_132_Tests.java | 204 ++++++++++++++++++ 4 files changed, 245 insertions(+), 81 deletions(-) create mode 100644 gemp-lotr/gemp-lotr-async/src/main/web/cards/set18/set18-wraith.json delete mode 100644 gemp-lotr/gemp-lotr-cards/src/main/java/com/gempukku/lotro/cards/set18/wraith/Card18_132.java create mode 100644 gemp-lotr/gemp-lotr-server/src/test/java/com/gempukku/lotro/cards/official/set18/Card_18_132_Tests.java diff --git a/gemp-lotr/gemp-lotr-async/src/main/web/cards/set18/set18-wraith.json b/gemp-lotr/gemp-lotr-async/src/main/web/cards/set18/set18-wraith.json new file mode 100644 index 000000000..7b115fe63 --- /dev/null +++ b/gemp-lotr/gemp-lotr-async/src/main/web/cards/set18/set18-wraith.json @@ -0,0 +1,40 @@ +{ + "18_132": { + "title": "All Life Flees", + "subtitle": "Duplicitous Lieutenant", + "side": "shadow", + "culture": "Wraith", + "cost": 2, + "type": "event", + "keyword": "Shadow", + "condition": { + "type": "canSpot", + "filter": "nazgul" + }, + "effects": { + "type": "event", + "cost": { + "type": "chooseAndRemoveTwilight", + "memorize": "X" + }, + "effect": { + "type": "choice", + "texts": [ + "Discard a follower from play with a twilight cost of {X}", + "Play a {wraith} minion from your draw deck with a twilight cost of {X}" + ], + "effects": [ + { + "type": "discard", + "filter": "choose(follower,minTwilight(memory(X)),maxTwilight(memory(X)))" + }, + { + "type": "playCardFromDrawDeck", + "filter": "choose(culture(wraith),minion,minTwilight(memory(X)),maxTwilight(memory(X)))" + }, + ] + } + } + }, + +} \ No newline at end of file diff --git a/gemp-lotr/gemp-lotr-cards/src/main/java/com/gempukku/lotro/cards/set18/wraith/Card18_132.java b/gemp-lotr/gemp-lotr-cards/src/main/java/com/gempukku/lotro/cards/set18/wraith/Card18_132.java deleted file mode 100644 index ff9b676cb..000000000 --- a/gemp-lotr/gemp-lotr-cards/src/main/java/com/gempukku/lotro/cards/set18/wraith/Card18_132.java +++ /dev/null @@ -1,80 +0,0 @@ -package com.gempukku.lotro.cards.set18.wraith; - -import com.gempukku.lotro.common.*; -import com.gempukku.lotro.filters.Filters; -import com.gempukku.lotro.game.PhysicalCard; -import com.gempukku.lotro.game.state.LotroGame; -import com.gempukku.lotro.logic.actions.PlayEventAction; -import com.gempukku.lotro.logic.cardtype.AbstractEvent; -import com.gempukku.lotro.logic.decisions.DecisionResultInvalidException; -import com.gempukku.lotro.logic.decisions.IntegerAwaitingDecision; -import com.gempukku.lotro.logic.effects.ChoiceEffect; -import com.gempukku.lotro.logic.effects.PlayoutDecisionEffect; -import com.gempukku.lotro.logic.effects.RemoveTwilightEffect; -import com.gempukku.lotro.logic.effects.choose.ChooseAndDiscardCardsFromPlayEffect; -import com.gempukku.lotro.logic.effects.choose.ChooseAndPlayCardFromDeckEffect; -import com.gempukku.lotro.logic.timing.Effect; -import com.gempukku.lotro.logic.timing.PlayConditions; -import com.gempukku.lotro.logic.timing.UnrespondableEffect; - -import java.util.LinkedList; -import java.util.List; - -/** - * Set: Treachery & Deceit - * Side: Shadow - * Culture: Wraith - * Twilight Cost: 2 - * Type: Event • Shadow - * Game Text: To play, spot a Nazgul. Remove (X) to choose one: discard a follower from play that has a twilight - * cost of X; or play from deck a [WRAITH] minion that has a twilight cost of X. - */ -public class Card18_132 extends AbstractEvent { - public Card18_132() { - super(Side.SHADOW, 2, Culture.WRAITH, "All Life Flees", Phase.SHADOW); - } - - @Override - public boolean checkPlayRequirements(LotroGame game, PhysicalCard self) { - return PlayConditions.canSpot(game, Race.NAZGUL); - } - - @Override - public PlayEventAction getPlayEventCardAction(final String playerId, LotroGame game, PhysicalCard self) { - final PlayEventAction action = new PlayEventAction(self); - action.appendCost( - new UnrespondableEffect() { - @Override - protected void doPlayEffect(LotroGame game) { - action.appendCost( - new PlayoutDecisionEffect(playerId, - new IntegerAwaitingDecision(1, "Choose X", 0, game.getGameState().getTwilightPool()) { - @Override - public void decisionMade(String result) throws DecisionResultInvalidException { - final int twilight = getValidatedResult(result); - action.appendCost( - new RemoveTwilightEffect(twilight)); - List possibleEffects = new LinkedList(); - possibleEffects.add( - new ChooseAndDiscardCardsFromPlayEffect(action, playerId, 1, 1, CardType.FOLLOWER, Filters.printedTwilightCost(twilight)) { - @Override - public String getText(LotroGame game) { - return "Discard follower with twilight cost " + twilight; - } - }); - possibleEffects.add( - new ChooseAndPlayCardFromDeckEffect(playerId, Culture.WRAITH, CardType.MINION, Filters.printedTwilightCost(twilight)) { - @Override - public String getText(LotroGame game) { - return "Play WRAITH minion with twilight cost " + twilight + " from deck"; - } - }); - action.appendEffect( - new ChoiceEffect(action, playerId, possibleEffects)); - } - })); - } - }); - return action; - } -} diff --git a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/effect/appender/PlayCardFromDrawDeck.java b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/effect/appender/PlayCardFromDrawDeck.java index 9f4f43c3f..7e0c8e7b1 100644 --- a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/effect/appender/PlayCardFromDrawDeck.java +++ b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/effect/appender/PlayCardFromDrawDeck.java @@ -72,7 +72,7 @@ public class PlayCardFromDrawDeck implements EffectAppenderProducer { final CostToEffectAction playCardAction = PlayUtils.getPlayCardAction(actionContext.getGame(), cardsToPlay.iterator().next(), costModifier, onFilterable, false); return new StackActionEffect(playCardAction); } else { - return null; //Fix Wizard is Never Late by changing this to a DoNothingEffect? + return null; } } diff --git a/gemp-lotr/gemp-lotr-server/src/test/java/com/gempukku/lotro/cards/official/set18/Card_18_132_Tests.java b/gemp-lotr/gemp-lotr-server/src/test/java/com/gempukku/lotro/cards/official/set18/Card_18_132_Tests.java new file mode 100644 index 000000000..36edcf24f --- /dev/null +++ b/gemp-lotr/gemp-lotr-server/src/test/java/com/gempukku/lotro/cards/official/set18/Card_18_132_Tests.java @@ -0,0 +1,204 @@ +package com.gempukku.lotro.cards.official.set18; + +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 junit.framework.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + + +public class Card_18_132_Tests +{ + protected GenericCardTestHelper GetScenario() throws CardNotFoundException, DecisionResultInvalidException { + return new GenericCardTestHelper( + new HashMap() + {{ + put("flees", "18_132"); + put("nazgul", "1_232"); + put("orc", "7_196"); + put("orc2", "7_192"); //2 cost to ensure that it trips the choice + put("cantea", "1_230"); + put("twk", "1_237"); + + put("follower0", "18_47"); + put("follower1", "18_17"); + put("follower2", "15_26"); + put("follower3", "18_7"); + + }} + ); + } + + @Test + public void AllLifeFleesStatsAndKeywordsAreCorrect() throws DecisionResultInvalidException, CardNotFoundException { + + /** + * Set: 18 + * Title: All Life Flees + * Side: Shadow + * Culture: Wraith + * Twilight Cost: 2 + * Type: Event + * Subtype: Shadow + * Game Text: To play, spot a Nazgul. + * Remove (X) to choose one: discard a follower from play that has a twilight cost of X, or play from deck a + * [RINGWRAITH] minion that has a twilight cost of X. + */ + + //Pre-game setup + GenericCardTestHelper scn = GetScenario(); + + PhysicalCardImpl flees = scn.GetFreepsCard("flees"); + + assertFalse(flees.getBlueprint().isUnique()); + assertEquals(Side.SHADOW, flees.getBlueprint().getSide()); + assertEquals(Culture.WRAITH, flees.getBlueprint().getCulture()); + assertEquals(CardType.EVENT, flees.getBlueprint().getCardType()); + //assertEquals(Race.CREATURE, flees.getBlueprint().getRace()); + assertTrue(scn.HasKeyword(flees, Keyword.SHADOW)); // test for keywords as needed + assertEquals(2, flees.getBlueprint().getTwilightCost()); + //assertEquals(, flees.getBlueprint().getStrength()); + //assertEquals(, flees.getBlueprint().getVitality()); + //assertEquals(, flees.getBlueprint().getResistance()); + //assertEquals(Signet., flees.getBlueprint().getSignet()); + //assertEquals(, flees.getBlueprint().getSiteNumber()); // Change this to getAllyHomeSiteNumbers for allies + + } + + @Test + public void RequiresNazgulToPlay() throws DecisionResultInvalidException, CardNotFoundException { + //Pre-game setup + GenericCardTestHelper scn = GetScenario(); + + PhysicalCardImpl flees = scn.GetShadowCard("flees"); + PhysicalCardImpl nazgul = scn.GetShadowCard("nazgul"); + scn.ShadowMoveCardToHand(flees, nazgul); + + scn.StartGame(); + + scn.SetTwilight(10); + scn.FreepsPassCurrentPhaseAction(); + + assertFalse(scn.ShadowCardPlayAvailable(flees)); + scn.ShadowPlayCard(nazgul); + assertTrue(scn.ShadowCardPlayAvailable(flees)); + } + + @Test + public void CanDiscardFollowerCostingX() throws DecisionResultInvalidException, CardNotFoundException { + //Pre-game setup + GenericCardTestHelper scn = GetScenario(); + + PhysicalCardImpl flees = scn.GetShadowCard("flees"); + PhysicalCardImpl nazgul = scn.GetShadowCard("nazgul"); + PhysicalCardImpl orc = scn.GetShadowCard("orc"); + PhysicalCardImpl cantea = scn.GetShadowCard("cantea"); + scn.ShadowMoveCardToHand(flees); + scn.ShadowMoveCharToTable(nazgul); + + PhysicalCardImpl follower0 = scn.GetFreepsCard("follower0"); + PhysicalCardImpl follower1 = scn.GetFreepsCard("follower1"); + PhysicalCardImpl follower2 = scn.GetFreepsCard("follower2"); + PhysicalCardImpl follower3 = scn.GetFreepsCard("follower3"); + scn.FreepsMoveCardToSupportArea(follower0, follower1, follower2, follower3); + + scn.StartGame(); + + scn.SetTwilight(10); + scn.FreepsPassCurrentPhaseAction(); + + assertEquals(Zone.SUPPORT, follower2.getZone()); + assertEquals(12, scn.GetTwilight()); // 10 initial, +2 from moving + scn.ShadowPlayCard(flees); + + assertEquals(10, scn.GetTwilight()); + scn.ShadowChoose("2"); + assertEquals(8, scn.GetTwilight()); + assertTrue(scn.ShadowDecisionAvailable("Choose action to perform")); + assertEquals(2, scn.ShadowGetMultipleChoices().size()); + scn.ShadowChooseMultipleChoiceOption("Discard a follower"); + + assertEquals(Zone.DISCARD, follower2.getZone()); + + + } + + @Test + public void CanDiscardFollowerCosting0() throws DecisionResultInvalidException, CardNotFoundException { + //Pre-game setup + GenericCardTestHelper scn = GetScenario(); + + PhysicalCardImpl flees = scn.GetShadowCard("flees"); + PhysicalCardImpl nazgul = scn.GetShadowCard("nazgul"); + scn.ShadowMoveCardToHand(flees); + scn.ShadowMoveCharToTable(nazgul); + + PhysicalCardImpl follower0 = scn.GetFreepsCard("follower0"); + PhysicalCardImpl follower1 = scn.GetFreepsCard("follower1"); + PhysicalCardImpl follower2 = scn.GetFreepsCard("follower2"); + PhysicalCardImpl follower3 = scn.GetFreepsCard("follower3"); + scn.FreepsMoveCardToSupportArea(follower0, follower1, follower2, follower3); + + scn.StartGame(); + + scn.SetTwilight(10); + scn.FreepsPassCurrentPhaseAction(); + + assertEquals(Zone.SUPPORT, follower0.getZone()); + assertEquals(12, scn.GetTwilight()); // 10 initial, +2 from moving + scn.ShadowPlayCard(flees); + + assertEquals(10, scn.GetTwilight()); + scn.ShadowChoose("0"); + assertEquals(10, scn.GetTwilight()); + + assertEquals(Zone.DISCARD, follower0.getZone()); + + } + + @Test + public void CanPlayWraithMinionFromDrawDeck() throws DecisionResultInvalidException, CardNotFoundException { + //Pre-game setup + GenericCardTestHelper scn = GetScenario(); + + PhysicalCardImpl flees = scn.GetShadowCard("flees"); + PhysicalCardImpl nazgul = scn.GetShadowCard("nazgul"); + PhysicalCardImpl orc = scn.GetShadowCard("orc"); + PhysicalCardImpl cantea = scn.GetShadowCard("cantea"); + PhysicalCardImpl twk = scn.GetShadowCard("twk"); + scn.ShadowMoveCardToHand(flees); + scn.ShadowMoveCharToTable(nazgul); + + scn.StartGame(); + + scn.SetTwilight(20); + scn.FreepsPassCurrentPhaseAction(); + assertEquals(22, scn.GetTwilight()); // 20 initial, +2 from moving + scn.ShadowPlayCard(flees); + + assertEquals(20, scn.GetTwilight()); + + assertEquals(5, orc.getBlueprint().getTwilightCost()); + assertEquals(5, cantea.getBlueprint().getTwilightCost()); + assertEquals(Zone.DECK, orc.getZone()); + assertEquals(Zone.DECK, cantea.getZone()); + + scn.ShadowChoose("5"); + + assertEquals(2, scn.ShadowGetCardChoices().size()); // orc + cantea, but not TWK + scn.ShadowChooseCardBPFromSelection(orc); + + assertEquals(Zone.SHADOW_CHARACTERS, orc.getZone()); + + } + + + +} \ No newline at end of file