From 7ba8203fa6a9a77a3bba615eaa1cbeac150a9e45 Mon Sep 17 00:00:00 2001 From: Christian 'ketura' McCarty Date: Sat, 6 Feb 2021 19:11:09 -0600 Subject: [PATCH] Adding new PC keywords Concealed and Exposed, with associated rules and unit tests. Adding new PC race Warg. Adding new PC possession type Pony. --- .../com/gempukku/lotro/common/Keyword.java | 5 +- .../lotro/common/PossessionClass.java | 7 +- .../java/com/gempukku/lotro/common/Race.java | 5 +- .../lotro/logic/modifiers/ModifiersLogic.java | 3 +- .../gempukku/lotro/logic/timing/RuleSet.java | 1 + .../logic/timing/rules/ConcealedRule.java | 64 ++++++++++ .../lotro/at/ConcealedExposedAtTest.java | 120 ++++++++++++++++++ 7 files changed, 201 insertions(+), 4 deletions(-) create mode 100644 gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/logic/timing/rules/ConcealedRule.java create mode 100644 gemp-lotr/gemp-lotr-server/src/test/java/com/gempukku/lotro/at/ConcealedExposedAtTest.java diff --git a/gemp-lotr/gemp-lotr-common/src/main/java/com/gempukku/lotro/common/Keyword.java b/gemp-lotr/gemp-lotr-common/src/main/java/com/gempukku/lotro/common/Keyword.java index 48ff68dab..a5f3879a0 100644 --- a/gemp-lotr/gemp-lotr-common/src/main/java/com/gempukku/lotro/common/Keyword.java +++ b/gemp-lotr/gemp-lotr-common/src/main/java/com/gempukku/lotro/common/Keyword.java @@ -30,7 +30,10 @@ public enum Keyword implements Filterable { WARG_RIDER("Warg-rider", true), BESIEGER("Besieger", true), CORSAIR("Corsair", true), //Additional Hobbit Draft keywords - WISE("Wise", true), BURGLAR("Burglar", true); + WISE("Wise", true), BURGLAR("Burglar", true), + + //PC Keywords + CONCEALED("Concealed", true), EXPOSED("Exposed", true); private String _humanReadable; private boolean _infoDisplayable; diff --git a/gemp-lotr/gemp-lotr-common/src/main/java/com/gempukku/lotro/common/PossessionClass.java b/gemp-lotr/gemp-lotr-common/src/main/java/com/gempukku/lotro/common/PossessionClass.java index 39c2da085..265b5bf97 100644 --- a/gemp-lotr/gemp-lotr-common/src/main/java/com/gempukku/lotro/common/PossessionClass.java +++ b/gemp-lotr/gemp-lotr-common/src/main/java/com/gempukku/lotro/common/PossessionClass.java @@ -4,7 +4,12 @@ public enum PossessionClass implements Filterable { HAND_WEAPON("Hand Weapon"), ARMOR("Armor"), HELM("Helm"), MOUNT("Mount"), RANGED_WEAPON("Ranged Weapon"), CLOAK("Cloak"), PIPE("Pipe"), SHIELD("Shield"), BRACERS("Bracers"), STAFF("Staff"), RING("Ring"), BROOCH("Brooch"), GAUNTLETS("Gauntlets"), BOX("Box"), PALANTIR("Palantir"), PHIAL("Phial"), HORN("Horn"), - CLASSLESS("Classless"); + CLASSLESS("Classless"), + + //PC Classes + PONY("Pony") + + ; private String _humanReadable; diff --git a/gemp-lotr/gemp-lotr-common/src/main/java/com/gempukku/lotro/common/Race.java b/gemp-lotr/gemp-lotr-common/src/main/java/com/gempukku/lotro/common/Race.java index 185c438a3..9e96a814d 100644 --- a/gemp-lotr/gemp-lotr-common/src/main/java/com/gempukku/lotro/common/Race.java +++ b/gemp-lotr/gemp-lotr-common/src/main/java/com/gempukku/lotro/common/Race.java @@ -7,7 +7,10 @@ public enum Race implements Filterable { GOBLIN("Goblin"), //Additional Hobbit Draft races - DRAGON("Dragon"), EAGLE("Eagle"), BIRD("Bird"); + DRAGON("Dragon"), EAGLE("Eagle"), BIRD("Bird"), + + //PC Races + WARG("Warg"); private String _humanReadable; diff --git a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/logic/modifiers/ModifiersLogic.java b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/logic/modifiers/ModifiersLogic.java index 2a73c0d86..dbac1beb9 100644 --- a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/logic/modifiers/ModifiersLogic.java +++ b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/logic/modifiers/ModifiersLogic.java @@ -384,9 +384,10 @@ public class ModifiersLogic implements ModifiersEnvironment, ModifiersQuerying { @Override public boolean addsTwilightForCompanionMove(LotroGame game, PhysicalCard companion) { - for (Modifier modifier : getModifiersAffectingCard(game, ModifierEffect.MOVE_TWILIGHT_MODIFIER, companion)) + for (Modifier modifier : getModifiersAffectingCard(game, ModifierEffect.MOVE_TWILIGHT_MODIFIER, companion)) { if (!modifier.addsTwilightForCompanionMove(game, companion)) return false; + } return true; } diff --git a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/logic/timing/RuleSet.java b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/logic/timing/RuleSet.java index 41631ec95..f7a42f5be 100644 --- a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/logic/timing/RuleSet.java +++ b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/logic/timing/RuleSet.java @@ -65,5 +65,6 @@ public class RuleSet { new HealByDiscardRule(_actionsEnvironment).applyRule(); new TakeOffRingRule(_actionsEnvironment).applyRule(); + new ConcealedRule(_actionsEnvironment).applyRule(); } } diff --git a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/logic/timing/rules/ConcealedRule.java b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/logic/timing/rules/ConcealedRule.java new file mode 100644 index 000000000..13561a237 --- /dev/null +++ b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/logic/timing/rules/ConcealedRule.java @@ -0,0 +1,64 @@ +package com.gempukku.lotro.logic.timing.rules; + +import com.gempukku.lotro.common.CardType; +import com.gempukku.lotro.common.Keyword; +import com.gempukku.lotro.common.Phase; +import com.gempukku.lotro.filters.Filters; +import com.gempukku.lotro.game.AbstractActionProxy; +import com.gempukku.lotro.game.PhysicalCard; +import com.gempukku.lotro.game.state.LotroGame; +import com.gempukku.lotro.game.state.actions.DefaultActionsEnvironment; +import com.gempukku.lotro.logic.GameUtils; +import com.gempukku.lotro.logic.actions.OptionalTriggerAction; +import com.gempukku.lotro.logic.actions.RequiredTriggerAction; +import com.gempukku.lotro.logic.effects.*; +import com.gempukku.lotro.logic.modifiers.evaluator.ConstantEvaluator; +import com.gempukku.lotro.logic.modifiers.evaluator.Evaluator; +import com.gempukku.lotro.logic.modifiers.evaluator.LocationEvaluator; +import com.gempukku.lotro.logic.timing.Effect; +import com.gempukku.lotro.logic.timing.EffectResult; +import com.gempukku.lotro.logic.timing.PlayConditions; +import com.gempukku.lotro.logic.timing.TriggerConditions; + +import java.util.*; + +public class ConcealedRule { + private DefaultActionsEnvironment _actionsEnvironment; + + public ConcealedRule(DefaultActionsEnvironment actionsEnvironment) { + _actionsEnvironment = actionsEnvironment; + } + + public void applyRule() { + _actionsEnvironment.addAlwaysOnActionProxy( + new AbstractActionProxy() { + @Override + public List getRequiredAfterTriggers(final LotroGame game, EffectResult effectResult) { + if (TriggerConditions.moves(game, effectResult) + && game.getGameState().getCurrentPhase() == Phase.FELLOWSHIP) { + List actions = new ArrayList<>(); + + int twilight = Filters.filterActive(game, CardType.COMPANION, Keyword.CONCEALED).size(); + + if(twilight == 0) + return null; + + final RequiredTriggerAction action = new RequiredTriggerAction(null); + LocationEvaluator loc = new LocationEvaluator(twilight, 0, Keyword.EXPOSED); + action.appendEffect(new RemoveTwilightEffect(new LocationEvaluator(twilight, 0, Keyword.EXPOSED))); + + if(loc.evaluateExpression(game, null) == 0) { + action.setText("Concealed companions were exposed! No twilight was removed."); + } + else { + action.setText("Concealed companions trigger removal of " + twilight + " twilight."); + } + actions.add(action); + + return actions; + } + return null; + } + }); + } +} diff --git a/gemp-lotr/gemp-lotr-server/src/test/java/com/gempukku/lotro/at/ConcealedExposedAtTest.java b/gemp-lotr/gemp-lotr-server/src/test/java/com/gempukku/lotro/at/ConcealedExposedAtTest.java new file mode 100644 index 000000000..7efefcd71 --- /dev/null +++ b/gemp-lotr/gemp-lotr-server/src/test/java/com/gempukku/lotro/at/ConcealedExposedAtTest.java @@ -0,0 +1,120 @@ +package com.gempukku.lotro.at; + +import com.gempukku.lotro.cards.GenericCardTestHelper; +import com.gempukku.lotro.common.CardType; +import com.gempukku.lotro.common.Keyword; +import com.gempukku.lotro.game.CardNotFoundException; +import com.gempukku.lotro.game.PhysicalCardImpl; +import com.gempukku.lotro.logic.decisions.DecisionResultInvalidException; +import com.gempukku.lotro.logic.modifiers.KeywordModifier; +import org.junit.Test; + +import java.util.HashMap; + +import static junit.framework.Assert.*; +import static org.junit.Assert.assertTrue; + +public class ConcealedExposedAtTest extends AbstractAtTest { + protected GenericCardTestHelper GetScenario() throws CardNotFoundException, DecisionResultInvalidException { + return new GenericCardTestHelper( + new HashMap() + {{ + put("aragorn", "1_89"); + put("arwen", "1_30"); + }} + ); + } + + + @Test + public void ConcealedDoesNothingIfNoTwilight() throws DecisionResultInvalidException, CardNotFoundException { + //Pre-game setup + GenericCardTestHelper scn = GetScenario(); + + PhysicalCardImpl aragorn = scn.GetFreepsCard("aragorn"); + + scn.FreepsMoveCharToTable(aragorn); + + scn.StartGame(); + + scn.InsertAdHocModifier(new KeywordModifier(aragorn, aragorn, Keyword.CONCEALED)); + + assertEquals(0, scn.GetTwilight()); + scn.FreepsSkipCurrentPhaseAction(); + + //1 for the ring-bearer, 1 for aragorn, 1 for the site (King's Tent) + assertEquals(3, scn.GetTwilight()); + } + + @Test + public void ConcealedRemovesOneIfAvailable() throws DecisionResultInvalidException, CardNotFoundException { + //Pre-game setup + GenericCardTestHelper scn = GetScenario(); + + PhysicalCardImpl aragorn = scn.GetFreepsCard("aragorn"); + PhysicalCardImpl nostranger = scn.GetFreepsCard("nostranger"); + + scn.FreepsMoveCardToHand(aragorn); + + scn.StartGame(); + + scn.FreepsPlayCard(aragorn); + scn.InsertAdHocModifier(new KeywordModifier(aragorn, aragorn, Keyword.CONCEALED)); + + //4 from playing aragorn + assertEquals(4, scn.GetTwilight()); + scn.FreepsSkipCurrentPhaseAction(); + + //4 from playing aragorn, 1 for the ring-bearer, 1 for aragorn, 1 for the site (King's Tent), -1 for concealed + assertEquals(6, scn.GetTwilight()); + } + + @Test + public void TwoConcealedRemovesTwoIfAvailable() throws DecisionResultInvalidException, CardNotFoundException { + //Pre-game setup + GenericCardTestHelper scn = GetScenario(); + + PhysicalCardImpl aragorn = scn.GetFreepsCard("aragorn"); + PhysicalCardImpl arwen = scn.GetFreepsCard("arwen"); + + scn.FreepsMoveCardToHand(aragorn); + scn.FreepsMoveCharToTable(arwen); + + scn.StartGame(); + + scn.FreepsPlayCard(aragorn); + scn.InsertAdHocModifier(new KeywordModifier(aragorn, Keyword.RANGER, Keyword.CONCEALED)); + + + //4 from playing aragorn + assertEquals(4, scn.GetTwilight()); + scn.FreepsSkipCurrentPhaseAction(); + + //4 from playing aragorn, 1+1+1 for companions, 1 for the site (King's Tent), -2 for concealed + assertEquals(6, scn.GetTwilight()); + } + + @Test + public void ConcealedRemovesNothingIfExposed() throws DecisionResultInvalidException, CardNotFoundException { + //Pre-game setup + GenericCardTestHelper scn = GetScenario(); + + PhysicalCardImpl aragorn = scn.GetFreepsCard("aragorn"); + + scn.FreepsMoveCardToHand(aragorn); + + scn.StartGame(); + + scn.FreepsPlayCard(aragorn); + scn.InsertAdHocModifier(new KeywordModifier(aragorn, Keyword.RANGER, Keyword.CONCEALED)); + + scn.InsertAdHocModifier(new KeywordModifier(null, CardType.SITE, Keyword.EXPOSED)); + + //4 from playing aragorn + assertEquals(4, scn.GetTwilight()); + scn.FreepsSkipCurrentPhaseAction(); + + //4 from playing aragorn, 1 for the ring-bearer, 1 for aragorn, 1 for the site (King's Tent), 0 for exposed concealed + assertEquals(7, scn.GetTwilight()); + } +}