diff --git a/gemp-lotr/gemp-lotr-cards/src/main/resources/cards/official/set01/set1-wraith.hjson b/gemp-lotr/gemp-lotr-cards/src/main/resources/cards/official/set01/set1-wraith.hjson
index 744747fd2..53513a22d 100644
--- a/gemp-lotr/gemp-lotr-cards/src/main/resources/cards/official/set01/set1-wraith.hjson
+++ b/gemp-lotr/gemp-lotr-cards/src/main/resources/cards/official/set01/set1-wraith.hjson
@@ -978,10 +978,22 @@
site: 3
effects: {
type: trigger
+ optional: true
trigger: {
type: played
filter: self
}
+ requires: [
+ {
+ type: CanSpot
+ filter: companion
+ count: 5
+ }
+ {
+ type: PlayableFromDiscard
+ filter: minion
+ }
+ ]
effect: [
{
type: MemorizeValue
@@ -989,61 +1001,47 @@
value: yes
}
{
- type: conditional
- requires: [
- {
- type: CanSpot
- filter: companion
- count: 5
- }
- {
- type: PlayableFromDiscard
- filter: minion
- }
- ]
+ type: Repeat
+ amount: {
+ type: forEachYouCanSpot
+ filter: companion
+ over: 4
+ }
effect: {
- type: Repeat
- amount: {
- type: forEachYouCanSpot
- filter: companion
- over: 4
- }
- effect: {
- type: conditional
- requires: [
- {
- type: MemoryIs
- memory: choice
- value: yes
- }
- {
- type: HasCardInDiscard
- filter: playable,minion
- }
- ]
- effect: [
- {
- type: chooseYesOrNo
- player: you
- text: Would you like to play a minion from your discard?
- memorize: choice
- }
- {
- type: conditional
- requires: [
- {
- type: MemoryIs
- memory: choice
- value: yes
- }
- ]
- effect: {
- type: playCardFromDiscard
- filter: choose(minion)
+ type: conditional
+ requires: [
+ {
+ type: MemoryIs
+ memory: choice
+ value: yes
+ }
+ {
+ type: HasCardInDiscard
+ filter: playable,minion
+ }
+ ]
+ effect: [
+ {
+ type: chooseYesOrNo
+ player: you
+ text: Would you like to play a minion from your discard?
+ memorize: choice
+ }
+ {
+ type: conditional
+ requires: [
+ {
+ type: MemoryIs
+ memory: choice
+ value: yes
}
+ ]
+ effect: {
+ type: playCardFromDiscard
+ filter: choose(minion)
}
- ]
- }
+ }
+ ]
}
}
]
diff --git a/gemp-lotr/gemp-lotr-cards/src/main/resources/cards/official/set01/set1.hjson b/gemp-lotr/gemp-lotr-cards/src/main/resources/cards/official/set01/set1.hjson
index 9437e663f..ad963c84e 100644
--- a/gemp-lotr/gemp-lotr-cards/src/main/resources/cards/official/set01/set1.hjson
+++ b/gemp-lotr/gemp-lotr-cards/src/main/resources/cards/official/set01/set1.hjson
@@ -526,7 +526,10 @@
type: site
site: 3
block: fellowship
- keyword: river
+ keywords: [
+ river
+ Sanctuary
+ ]
direction: right
effects: [
{
@@ -534,11 +537,8 @@
modifier: {
type: modifyCost
requires: {
- type: not
- requires: {
- type: hasInZoneData
- filter: self
- }
+ type: perTurnLimit
+ limit: 1
}
filter: nazgul
amount: -5
@@ -549,41 +549,10 @@
trigger: {
type: played
filter: nazgul
- memorize: playedNazgul
- }
- requires: {
- type: not
- requires: {
- type: hasInZoneData
- filter: self
- }
}
effect: {
- type: appendCardIdsToWhileInZone
- memory: playedNazgul
- }
- }
- {
- type: trigger
- trigger: {
- type: endOfTurn
- }
- effect: {
- type: resetWhileInZoneData
- }
- }
- {
- type: trigger
- trigger: {
- type: movesFrom
- filter: self
- }
- requires: {
- type: phase
- phase: regroup
- }
- effect: {
- type: resetWhileInZoneData
+ type: incrementPerTurnLimit
+ limit: 1
}
}
]
@@ -900,17 +869,15 @@
site: 6
block: fellowship
direction: left
+ keywords: Sanctuary
effects: [
{
type: modifier
modifier: {
type: modifyCost
requires: {
- type: not
- requires: {
- type: hasInZoneData
- filter: self
- }
+ type: perPhaseLimit
+ limit: 1
}
filter: culture(moria),orc
amount: -2
@@ -923,26 +890,9 @@
filter: culture(moria),orc
memorize: playedOrc
}
- requires: {
- type: not
- requires: {
- type: hasInZoneData
- filter: self
- }
- }
effect: {
- type: appendCardIdsToWhileInZone
- memory: playedOrc
- }
- }
- {
- type: trigger
- trigger: {
- type: endOfPhase
- phase: shadow
- }
- effect: {
- type: resetWhileInZoneData
+ type: incrementPerPhaseLimit
+ limit: 1
}
}
]
diff --git a/gemp-lotr/gemp-lotr-cards/src/main/resources/cards/unofficial/pc/errata/set01/set01-Ringwraith-errata.hjson b/gemp-lotr/gemp-lotr-cards/src/main/resources/cards/unofficial/pc/errata/set01/set01-Ringwraith-errata.hjson
index 90f35f81d..b6214aa1a 100644
--- a/gemp-lotr/gemp-lotr-cards/src/main/resources/cards/unofficial/pc/errata/set01/set01-Ringwraith-errata.hjson
+++ b/gemp-lotr/gemp-lotr-cards/src/main/resources/cards/unofficial/pc/errata/set01/set01-Ringwraith-errata.hjson
@@ -26,10 +26,22 @@
site: 3
effects: {
type: trigger
+ optional: true
trigger: {
type: played
filter: self
}
+ requires: [
+ {
+ type: CanSpot
+ filter: companion
+ count: 5
+ }
+ {
+ type: PlayableFromDiscard
+ filter: minion
+ }
+ ]
effect: [
{
type: MemorizeValue
@@ -37,61 +49,47 @@
value: yes
}
{
- type: conditional
- requires: [
- {
- type: CanSpot
- filter: companion
- count: 5
- }
- {
- type: PlayableFromDiscard
- filter: unique,culture(wraith),minion
- }
- ]
+ type: Repeat
+ amount: {
+ type: forEachYouCanSpot
+ filter: companion
+ over: 4
+ }
effect: {
- type: Repeat
- amount: {
- type: forEachYouCanSpot
- filter: companion
- over: 4
- }
- effect: {
- type: conditional
- requires: [
- {
- type: MemoryIs
- memory: choice
- value: yes
- }
- {
- type: HasCardInDiscard
- filter: playable,unique,culture(wraith),minion
- }
- ]
- effect: [
- {
- type: chooseYesOrNo
- player: you
- text: Would you like to play a unique WRAITH minion from your discard?
- memorize: choice
- }
- {
- type: conditional
- requires: [
- {
- type: MemoryIs
- memory: choice
- value: yes
- }
- ]
- effect: {
- type: playCardFromDiscard
- filter: choose(unique,culture(wraith),minion)
+ type: conditional
+ requires: [
+ {
+ type: MemoryIs
+ memory: choice
+ value: yes
+ }
+ {
+ type: HasCardInDiscard
+ filter: playable,unique,culture(wraith),minion
+ }
+ ]
+ effect: [
+ {
+ type: chooseYesOrNo
+ player: you
+ text: Would you like to play a unique WRAITH minion from your discard?
+ memorize: choice
+ }
+ {
+ type: conditional
+ requires: [
+ {
+ type: MemoryIs
+ memory: choice
+ value: yes
}
+ ]
+ effect: {
+ type: playCardFromDiscard
+ filter: choose(unique,culture(wraith),minion)
}
- ]
- }
+ }
+ ]
}
}
]
diff --git a/gemp-lotr/gemp-lotr-server/src/test/java/com/gempukku/lotro/cards/official/set01/Card_01_234_Tests.java b/gemp-lotr/gemp-lotr-server/src/test/java/com/gempukku/lotro/cards/official/set01/Card_01_234_Tests.java
index b22006981..4f0f57c32 100644
--- a/gemp-lotr/gemp-lotr-server/src/test/java/com/gempukku/lotro/cards/official/set01/Card_01_234_Tests.java
+++ b/gemp-lotr/gemp-lotr-server/src/test/java/com/gempukku/lotro/cards/official/set01/Card_01_234_Tests.java
@@ -108,6 +108,8 @@ public class Card_01_234_Tests
scn.FreepsPassCurrentPhaseAction();
scn.ShadowPlayCard(nertea);
+ assertTrue(scn.ShadowHasOptionalTriggerAvailable());
+ scn.ShadowAcceptOptionalTrigger();
assertTrue(scn.ShadowDecisionAvailable("play a minion"));
scn.ShadowChooseYes();
//twk, attea, rit, and runner
@@ -139,6 +141,8 @@ public class Card_01_234_Tests
scn.FreepsPassCurrentPhaseAction();
scn.ShadowPlayCard(nertea);
+ assertTrue(scn.ShadowHasOptionalTriggerAvailable());
+ scn.ShadowAcceptOptionalTrigger();
assertTrue(scn.ShadowDecisionAvailable("play a minion"));
scn.ShadowChooseYes();
//twk, attea, rit, and runner
@@ -176,6 +180,8 @@ public class Card_01_234_Tests
scn.FreepsPassCurrentPhaseAction();
scn.ShadowPlayCard(nertea);
+ assertTrue(scn.ShadowHasOptionalTriggerAvailable());
+ scn.ShadowAcceptOptionalTrigger();
assertTrue(scn.ShadowDecisionAvailable("play a minion"));
scn.ShadowChooseNo();
@@ -201,6 +207,8 @@ public class Card_01_234_Tests
scn.FreepsPassCurrentPhaseAction();
scn.ShadowPlayCard(nertea);
+ assertTrue(scn.ShadowHasOptionalTriggerAvailable());
+ scn.ShadowAcceptOptionalTrigger();
assertTrue(scn.ShadowDecisionAvailable("play a minion"));
scn.ShadowChooseYes();
assertEquals(4, scn.GetShadowCardChoiceCount());
diff --git a/gemp-lotr/gemp-lotr-server/src/test/java/com/gempukku/lotro/cards/official/set01/Card_01_338_Tests.java b/gemp-lotr/gemp-lotr-server/src/test/java/com/gempukku/lotro/cards/official/set01/Card_01_338_Tests.java
new file mode 100644
index 000000000..4a7530d8a
--- /dev/null
+++ b/gemp-lotr/gemp-lotr-server/src/test/java/com/gempukku/lotro/cards/official/set01/Card_01_338_Tests.java
@@ -0,0 +1,152 @@
+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.logic.decisions.DecisionResultInvalidException;
+import org.junit.Test;
+
+import java.util.HashMap;
+
+import static org.junit.Assert.*;
+
+public class Card_01_338_Tests
+{
+
+ protected GenericCardTestHelper GetScenario() throws CardNotFoundException, DecisionResultInvalidException {
+ return new GenericCardTestHelper(
+ new HashMap<>()
+ {{
+ put("twk", "1_237");
+ put("lemenya", "1_232");
+ put("nertea", "1_234");
+
+ put("guard1", "1_7");
+ put("guard2", "1_7");
+ put("guard3", "1_7");
+ put("guard4", "1_7");
+ }},
+ new HashMap<>() {{
+ put("site1", "1_319");
+ put("site2", "1_327");
+ put("site3", "1_338");
+ put("site4", "1_343");
+ put("site5", "1_349");
+ put("site6", "1_351");
+ put("site7", "1_353");
+ put("site8", "1_356");
+ put("site9", "1_360");
+ }},
+ GenericCardTestHelper.FOTRFrodo,
+ GenericCardTestHelper.RulingRing
+ );
+ }
+
+ @Test
+ public void FordofBruinenStatsAndKeywordsAreCorrect() throws DecisionResultInvalidException, CardNotFoundException {
+
+ /**
+ * Set: 1
+ * Name: Ford of Bruinen
+ * Unique: False
+ * Side:
+ * Culture:
+ * Shadow Number: 0
+ * Type: Sanctuary
+ * Subtype:
+ * Site Number: 3
+ * Game Text: River. Sanctuary. The twilight cost of the first Nazgûl played to Ford of Bruinen each turn is -5.
+ */
+
+ var scn = GetScenario();
+
+ var card = scn.GetFreepsSite(3);
+
+ assertEquals("Ford of Bruinen", card.getBlueprint().getTitle());
+ assertNull(card.getBlueprint().getSubtitle());
+ assertFalse(card.getBlueprint().isUnique());
+ assertEquals(CardType.SITE, card.getBlueprint().getCardType());
+ assertTrue(scn.HasKeyword(card, Keyword.RIVER));
+ assertTrue(scn.HasKeyword(card, Keyword.SANCTUARY));
+ assertEquals(0, card.getBlueprint().getTwilightCost());
+ assertEquals(3, card.getBlueprint().getSiteNumber());
+ }
+
+ @Test
+ public void FordofBruinenOnlyDiscountsTheFirstNazgul() throws DecisionResultInvalidException, CardNotFoundException {
+ //Pre-game setup
+ var scn = GetScenario();
+
+ var ford = scn.GetShadowSite(3);
+
+ var twk = scn.GetShadowCard("twk");
+ var lemenya = scn.GetShadowCard("lemenya");
+ scn.ShadowMoveCardToHand(twk, lemenya);
+
+ scn.StartGame();
+ //Start our test on 2 so that moving to 3 is the first thing we do
+ scn.SkipToSite(2);
+
+ scn.SetTwilight(9);
+ scn.FreepsPassCurrentPhaseAction();
+
+ assertEquals(ford, scn.GetCurrentSite());
+
+ //9 manual + 1 from the fellowship moving
+ assertEquals(10, scn.GetTwilight());
+
+ scn.ShadowPlayCard(twk);
+ //TWK costs 8 (no roaming), discounted by 5 to 3 total
+ //10 - 3
+ assertEquals(7, scn.GetTwilight());
+
+ scn.ShadowPlayCard(lemenya);
+ //Lemenya costs 4, should have no discount
+ //7 - 4
+ assertEquals(3, scn.GetTwilight());
+ }
+
+ @Test
+ public void FordDiscountsNerteaButNotNerteasTrigger() throws DecisionResultInvalidException, CardNotFoundException {
+ //Pre-game setup
+ var scn = GetScenario();
+
+ var ford = scn.GetShadowSite(3);
+
+ var twk = scn.GetShadowCard("twk");
+ var nertea = scn.GetShadowCard("nertea");
+ scn.ShadowMoveCardToHand(nertea);
+ scn.ShadowMoveCardToDiscard(twk);
+
+ scn.FreepsMoveCharToTable("guard1", "guard2", "guard3", "guard4");
+
+ scn.StartGame();
+ //Start our test on 2 so that moving to 3 is the first thing we do
+ scn.SkipToSite(2);
+
+ scn.SetTwilight(5);
+ scn.FreepsPassCurrentPhaseAction();
+
+ assertEquals(ford, scn.GetCurrentSite());
+
+ //5 manual + 5 from the fellowship moving
+ assertEquals(10, scn.GetTwilight());
+
+ scn.ShadowPlayCard(nertea);
+ //Nertea costs 4 (no roaming), discounted by 5 to 0 total
+ //10 - 0
+ assertEquals(10, scn.GetTwilight());
+
+ //Nertea pulls a minion from discard, which should not get discounted
+ // as Nertea should have consumed the only discount
+ assertTrue(scn.ShadowHasOptionalTriggerAvailable());
+ scn.ShadowAcceptOptionalTrigger();
+ assertTrue(scn.ShadowDecisionAvailable("play a minion"));
+ scn.ShadowChooseYes();
+
+ scn.ShadowChooseCardBPFromSelection(twk);
+ //TWK costs 8, should not be discounted
+ //10 - 8
+ assertEquals(2, scn.GetTwilight());
+ }
+}
diff --git a/gemp-lotr/gemp-lotr-server/src/test/java/com/gempukku/lotro/cards/unofficial/pc/errata/set01/Card_01_234_ErrataTests.java b/gemp-lotr/gemp-lotr-server/src/test/java/com/gempukku/lotro/cards/unofficial/pc/errata/set01/Card_01_234_ErrataTests.java
index 128efe00c..501d2d6ce 100644
--- a/gemp-lotr/gemp-lotr-server/src/test/java/com/gempukku/lotro/cards/unofficial/pc/errata/set01/Card_01_234_ErrataTests.java
+++ b/gemp-lotr/gemp-lotr-server/src/test/java/com/gempukku/lotro/cards/unofficial/pc/errata/set01/Card_01_234_ErrataTests.java
@@ -108,6 +108,8 @@ public class Card_01_234_ErrataTests
scn.FreepsPassCurrentPhaseAction();
scn.ShadowPlayCard(nertea);
+ assertTrue(scn.ShadowHasOptionalTriggerAvailable());
+ scn.ShadowAcceptOptionalTrigger();
assertTrue(scn.ShadowDecisionAvailable("play a unique WRAITH minion"));
scn.ShadowChooseYes();
//twk and attea, but not rit or runner
@@ -138,6 +140,8 @@ public class Card_01_234_ErrataTests
scn.FreepsPassCurrentPhaseAction();
scn.ShadowPlayCard(nertea);
+ assertTrue(scn.ShadowHasOptionalTriggerAvailable());
+ scn.ShadowAcceptOptionalTrigger();
assertTrue(scn.ShadowDecisionAvailable("play a unique WRAITH minion"));
scn.ShadowChooseYes();
//twk and attea, but not rit or runner
@@ -174,6 +178,8 @@ public class Card_01_234_ErrataTests
scn.FreepsPassCurrentPhaseAction();
scn.ShadowPlayCard(nertea);
+ assertTrue(scn.ShadowHasOptionalTriggerAvailable());
+ scn.ShadowAcceptOptionalTrigger();
assertTrue(scn.ShadowDecisionAvailable("play a unique WRAITH minion"));
scn.ShadowChooseNo();
@@ -199,6 +205,8 @@ public class Card_01_234_ErrataTests
scn.FreepsPassCurrentPhaseAction();
scn.ShadowPlayCard(nertea);
+ assertTrue(scn.ShadowHasOptionalTriggerAvailable());
+ scn.ShadowAcceptOptionalTrigger();
assertTrue(scn.ShadowDecisionAvailable("play a unique WRAITH minion"));
scn.ShadowChooseYes();
//twk and attea, but not rit or runner