diff --git a/gemp-lotr/gemp-lotr-cards/src/main/resources/cards/official/set01/set1-sauron.hjson b/gemp-lotr/gemp-lotr-cards/src/main/resources/cards/official/set01/set1-sauron.hjson
index c2850a3df..b6f64491d 100644
--- a/gemp-lotr/gemp-lotr-cards/src/main/resources/cards/official/set01/set1-sauron.hjson
+++ b/gemp-lotr/gemp-lotr-cards/src/main/resources/cards/official/set01/set1-sauron.hjson
@@ -23,7 +23,7 @@
]
effect: {
type: repeat
- amount: {
+ times: {
type: forEachYouCanSpot
filter: companion
over: 4
@@ -371,7 +371,7 @@
]
effect: {
type: repeat
- amount: {
+ times: {
type: forEachYouCanSpot
filter: companion
over: 5
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 2a6bd0d6f..f08db05d1 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
@@ -1008,7 +1008,7 @@
]
effect: {
type: Repeat
- amount: {
+ times: {
type: forEachYouCanSpot
filter: companion
over: 4
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 a5918523f..a0967584b 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
@@ -1228,7 +1228,7 @@
effect: [
{
type: repeat
- amount: 3
+ times: 3
effect: {
type: playCardFromDiscard
filter: choose(tracker)
diff --git a/gemp-lotr/gemp-lotr-cards/src/main/resources/cards/official/set04/set04-Dwarven.hjson b/gemp-lotr/gemp-lotr-cards/src/main/resources/cards/official/set04/set04-Dwarven.hjson
index cbe342c05..dc4724a28 100644
--- a/gemp-lotr/gemp-lotr-cards/src/main/resources/cards/official/set04/set04-Dwarven.hjson
+++ b/gemp-lotr/gemp-lotr-cards/src/main/resources/cards/official/set04/set04-Dwarven.hjson
@@ -802,7 +802,7 @@
}
{
type: repeat
- amount: {
+ times: {
type: forEachInMemory
memory: stackedCards
}
diff --git a/gemp-lotr/gemp-lotr-cards/src/main/resources/cards/official/set04/set04-Sites.hjson b/gemp-lotr/gemp-lotr-cards/src/main/resources/cards/official/set04/set04-Sites.hjson
index 9aacbef69..f15edd73d 100644
--- a/gemp-lotr/gemp-lotr-cards/src/main/resources/cards/official/set04/set04-Sites.hjson
+++ b/gemp-lotr/gemp-lotr-cards/src/main/resources/cards/official/set04/set04-Sites.hjson
@@ -554,7 +554,7 @@
}
effect: {
type: repeat
- amount: 3
+ times: 3
effect: {
type: heal
count: 0-1
diff --git a/gemp-lotr/gemp-lotr-cards/src/main/resources/cards/official/set05/set05-Gollum.hjson b/gemp-lotr/gemp-lotr-cards/src/main/resources/cards/official/set05/set05-Gollum.hjson
index cdf5fe21c..55ff57a2e 100644
--- a/gemp-lotr/gemp-lotr-cards/src/main/resources/cards/official/set05/set05-Gollum.hjson
+++ b/gemp-lotr/gemp-lotr-cards/src/main/resources/cards/official/set05/set05-Gollum.hjson
@@ -422,7 +422,7 @@
}
{
type: repeat
- amount: {
+ times: {
type: forEachMatchingInMemory
filter: side(shadow)
memory: revealedCards
diff --git a/gemp-lotr/gemp-lotr-cards/src/main/resources/cards/official/set05/set05-Gondor.hjson b/gemp-lotr/gemp-lotr-cards/src/main/resources/cards/official/set05/set05-Gondor.hjson
index 9d1e2ed6b..1d4084ec8 100644
--- a/gemp-lotr/gemp-lotr-cards/src/main/resources/cards/official/set05/set05-Gondor.hjson
+++ b/gemp-lotr/gemp-lotr-cards/src/main/resources/cards/official/set05/set05-Gondor.hjson
@@ -566,39 +566,18 @@
effect: [
{
type: doWhile
- condition: [
- {
- type: memoryIs
- memory: answer
- value: yes
- }
- {
- type: memoryMatches
- memory: playedCard
- filter: possession
- }
- ]
- effect: [
- {
- type: chooseYesOrNo
- text: Would you like to play next possession?
- memorize: answer
- }
- {
- type: conditional
- requires: {
- type: memoryIs
- memory: answer
- value: yes
- }
- effect: {
- type: playCardFromDiscard
- filter: choose(possession)
- on: companion,signet(Aragorn)
- memorize: playedCard
- }
- }
- ]
+ effect: {
+ type: playCardFromDiscard
+ optional: true
+ filter: choose(possession)
+ on: companion,signet(Aragorn)
+ memorize: playedCard
+ }
+ condition: {
+ type: memoryMatches
+ memory: playedCard
+ filter: possession
+ }
}
]
}
diff --git a/gemp-lotr/gemp-lotr-cards/src/main/resources/card-stubs/set05-Isengard.hjson b/gemp-lotr/gemp-lotr-cards/src/main/resources/cards/official/set05/set05-Isengard.hjson
similarity index 58%
rename from gemp-lotr/gemp-lotr-cards/src/main/resources/card-stubs/set05-Isengard.hjson
rename to gemp-lotr/gemp-lotr-cards/src/main/resources/cards/official/set05/set05-Isengard.hjson
index 531c15b10..3fe0e9252 100644
--- a/gemp-lotr/gemp-lotr-cards/src/main/resources/card-stubs/set05-Isengard.hjson
+++ b/gemp-lotr/gemp-lotr-cards/src/main/resources/cards/official/set05/set05-Isengard.hjson
@@ -25,17 +25,35 @@
Machine
Support Area
]
- /*requires: {
-
- }
effects: [
- {
-
- }
- {
-
- }
- ]*/
+ {
+ type: activated
+ phase: skirmish
+ requires: [
+ {
+ type: canSpot
+ filter: companion
+ count: 5
+ }
+ {
+ type: canSpot
+ filter: self,hasToken(isengard)
+ }
+ ]
+ effect: [
+ {
+ type: addKeyword
+ filter: choose(urukHai)
+ keyword: damage
+ amount: 1
+ }
+ {
+ type: discard
+ filter: self
+ }
+ ]
+ }
+ ]
gametext: Machine. Plays to your support area.
Shadow: Exert an Uruk-hai to place an [isengard] token on this card.
Skirmish: Spot 5 companions and an [isengard] token here to make an Uruk-hai damage +1. Discard this condition.
lore: The trees... smote the timbers with a rending boom.
promotext: ""
@@ -73,17 +91,41 @@
vitality: 3
site: 5
keywords: Damage+1
- /*requires: {
-
- }
effects: [
- {
-
- }
- {
-
- }
- ]*/
+ {
+ type: modifier
+ modifier: {
+ type: modifyStrength
+ filter: self,inSkirmish
+ amount: {
+ type: forEachWound
+ filter: character,inSkirmish
+ }
+ }
+ }
+ {
+ type: activated
+ phase: skirmish
+ cost: [
+ {
+ type: removeTokens
+ filter: choose(machine)
+ culture: isengard
+ count: 3
+ }
+ {
+ type: exert
+ filter: self
+ times: 2
+ }
+ ]
+ effect: {
+ type: wound
+ filter: all(ally)
+ times: 2
+ }
+ }
+ ]
gametext: Damage +1.
Berserk Rager is strength +1 for each wound on a character in its skirmish.
Skirmish: Remove 3 [isengard] tokens from a machine and exert Berserk Rager twice to wound every ally twice.
lore: Their mission at Helm's Deep was to clear the walls.
promotext: ""
@@ -121,17 +163,41 @@
vitality: 3
site: 5
keywords: Damage+1
- /*requires: {
-
- }
effects: [
- {
-
- }
- {
-
- }
- ]*/
+ {
+ type: modifier
+ modifier: {
+ type: modifyStrength
+ filter: self,inSkirmish
+ amount: {
+ type: forEachWound
+ filter: character,inSkirmish
+ }
+ }
+ }
+ {
+ type: activated
+ phase: skirmish
+ cost: [
+ {
+ type: removeTokens
+ filter: choose(machine)
+ culture: isengard
+ count: 4
+ }
+ {
+ type: exert
+ filter: self
+ times: 2
+ }
+ ]
+ effect: {
+ type: modifyStrength
+ filter: self
+ amount: 8
+ }
+ }
+ ]
gametext: Damage +1.
Berserk Savage is strength +1 for each wound on a character in its skirmish.
Skirmish: Remove 4 [isengard] tokens from a machine and exert Berserk Savage twice to make it strength +8.
lore: Skull-like helmets are distinctive to the Berserkers.
promotext: ""
@@ -169,17 +235,41 @@
vitality: 3
site: 5
keywords: Damage+1
- /*requires: {
-
- }
effects: [
- {
-
- }
- {
-
- }
- ]*/
+ {
+ type: modifier
+ modifier: {
+ type: modifyStrength
+ filter: self,inSkirmish
+ amount: {
+ type: forEachWound
+ filter: character,inSkirmish
+ multiplier: 2
+ }
+ }
+ }
+ {
+ type: activated
+ phase: skirmish
+ cost: [
+ {
+ type: removeTokens
+ filter: choose(machine)
+ culture: isengard
+ count: 5
+ }
+ {
+ type: exert
+ filter: self
+ times: 2
+ }
+ ]
+ effect: {
+ type: wound
+ filter: all(companion)
+ }
+ }
+ ]
gametext: Damage +1.
Berserk Slayer is strength +2 for each wound on a character in its skirmish.
Skirmish: Remove 5 [isengard] tokens from a machine and exert Berserk Slayer twice to wound every companion.
lore: Berserkers are the first wave of Uruks sent to battle.
promotext: ""
@@ -213,20 +303,41 @@
twilight: 1
type: Event
keywords: Maneuver
- /*requires: {
-
- }
effects: {
type: event
cost: {
-
+ type: chooseHowManyToSpot
+ filter: urukHai
+ text: Choose how many Uruk-hai to spot
+ memorize: spotCount
},
effect: [
{
-
+ type: repeat
+ times: {
+ type: fromMemory
+ memory: spotCount
+ }
+ effect: {
+ type: wound
+ player: fp
+ filter: choose(minion)
+ count: 0-1
+ }
+ }
+ {
+ type: repeat
+ times: {
+ type: fromMemory
+ memory: spotCount
+ }
+ effect: {
+ type: playCardFromDiscard
+ filter: choose(culture(isengard),weapon)
+ }
}
]
- }*/
+ }
gametext: Maneuver: Spot X Uruk-hai. The Free Peoples player may assign X wounds to your minions. Play X [isengard] weapons from your discard pile.
lore: Some were squat and broad, some were tall and grim, with high helms and sable shields.
promotext: ""
@@ -263,17 +374,39 @@
Machine
Support Area
]
- /*requires: {
-
- }
effects: [
- {
-
- }
- {
-
- }
- ]*/
+ {
+ type: activated
+ phase: shadow
+ cost: {
+ type: exert
+ filter: choose(urukHai)
+ }
+ effect: {
+ type: addTokens
+ culture: isengard
+ filter: self
+ }
+ }
+ {
+ type: activated
+ phase: maneuver
+ requires: {
+ type: canSpot
+ filter: self,hasTokenCount(5,isengard)
+ }
+ effect: [
+ {
+ type: exert
+ filter: all(character)
+ }
+ {
+ type: discard
+ filter: self
+ }
+ ]
+ }
+ ]
gametext: Machine. Plays to your support area.
Shadow: Exert an Uruk-hai to place an [isengard] token on this card.
Maneuver: Spot 8 [isengard] tokens here to exert every character. Discard this condition.
lore: They have a blasting fire, and... they took the Wall.'
promotext: ""
@@ -311,17 +444,34 @@
vitality: 3
site: 4
keywords: Warg-rider
- /*requires: {
-
- }
effects: [
- {
-
- }
- {
-
- }
- ]*/
+ {
+ type: modifier
+ modifier: {
+ type: addKeyword
+ filter: self,not(exhausted)
+ keyword: fierce
+ }
+ }
+ {
+ type: modifier
+ modifier: {
+ type: addKeyword
+ filter: self,vitalityMoreThan(2)
+ keyword: ambush
+ amount: 1
+ }
+ }
+ {
+ type: modifier
+ modifier: {
+ type: addKeyword
+ filter: self,vitalityMoreThan(3)
+ keyword: damage
+ amount: 1
+ }
+ }
+ ]
gametext: Warg-rider.
While Foul Horde is not exhausted, it is fierce.
While Foul Horde has at least 3 vitality, it is ambush (1).
While Foul Horde has at least 4 vitality, it is damage +1.
lore: ""
promotext: ""
@@ -359,17 +509,32 @@
strength: 4
vitality: 3
site: 3
- /*requires: {
-
- }
effects: [
- {
-
- }
- {
-
- }
- ]*/
+ {
+ type: activated
+ phase: maneuver
+ requires: {
+ type: canSpotFPCultures
+ amount: 4
+ }
+ cost: {
+ type: exert
+ filter: self
+ }
+ effect: [
+ {
+ type: chooseActiveCards
+ filter: choose(unbound,companion,canBeReturnedToHand)
+ text: Choose unbound companion to return to hand
+ memorize: chosenCompanion
+ }
+ {
+ type: returnToHand
+ filter: all(or(memory(chosenCompanion),attachedTo(memory(chosenCompanion))))
+ }
+ ]
+ }
+ ]
gametext: Maneuver: Spot 4 Free Peoples cultures and exert GrĂma to return an unbound companion, and all cards on him or her, to their owners' hands.
lore: I care for you and yours as best I may.... Let others deal with these irksome guests.'
promotext: ""
@@ -407,17 +572,16 @@
vitality: 2
site: 4
keywords: Warg-rider
- /*requires: {
-
- }
effects: [
- {
-
- }
- {
-
- }
- ]*/
+ {
+ type: modifier
+ modifier: {
+ type: addKeyword
+ filter: self,not(exhausted)
+ keyword: fierce
+ }
+ }
+ ]
gametext: Warg-rider.
While this minion is not exhausted, he is fierce.
lore: Sharku used his warg-riders to scout and defend.
promotext: ""
@@ -455,17 +619,16 @@
vitality: 3
site: 4
keywords: Warg-rider
- /*requires: {
-
- }
effects: [
- {
-
- }
- {
-
- }
- ]*/
+ {
+ type: modifier
+ modifier: {
+ type: addKeyword
+ filter: self,not(exhausted)
+ keyword: fierce
+ }
+ }
+ ]
gametext: Warg-rider.
While this minion is not exhausted, he is fierce.
lore: He has taken Orcs into his service, and Wolf-riders, and evil Men....'
promotext: ""
@@ -500,18 +663,24 @@
type: Possession
strength: 2
itemclass: Hand weapon
- #target: title(an [isengard] Orc)
- /*requires: {
-
- }
+ target: culture(isengard),orc
effects: [
- {
-
- }
- {
-
- }
- ]*/
+ {
+ type: trigger
+ optional: true
+ trigger: {
+ type: played
+ filter: self
+ }
+ effect: {
+ type: addTwilight
+ amount: {
+ type: forEachYouCanSpot
+ filter: controlledSite
+ }
+ }
+ }
+ ]
gametext: Bearer must be an [isengard] Orc.
When you play this weapon, you may add (1) for each site you control.
lore: Orcs from Isengard favor a short, curved sword when mounted.
promotext: ""
@@ -549,17 +718,31 @@
vitality: 3
site: 4
keywords: Warg-rider
- /*requires: {
-
- }
effects: [
- {
-
- }
- {
-
- }
- ]*/
+ {
+ type: modifier
+ modifier: {
+ type: addKeyword
+ filter: self,not(exhausted)
+ keyword: fierce
+ }
+ }
+ {
+ type: trigger
+ optional: true
+ trigger: {
+ type: winsSkirmish
+ filter: culture(isengard),orc
+ }
+ cost: {
+ type: exert
+ filter: self
+ }
+ effect: {
+ type: takeControlOfSite
+ }
+ }
+ ]
gametext: Warg-rider.
While this minion is not exhausted, it is fierce.
Each time an [isengard] Orc wins a skirmish, you may exert this minion to control a site.
lore: ...where the warg howls, there also the orc prowls.'
promotext: ""
@@ -597,17 +780,58 @@
strength: 8
vitality: 4
site: 4
- /*requires: {
-
- }
effects: [
- {
-
- }
- {
-
- }
- ]*/
+ {
+ type: modifier
+ modifier: {
+ type: cantTakeWounds
+ requires: [
+ {
+ type: sarumanFirstSentenceActive
+ }
+ {
+ type: phase
+ phase: archery
+ }
+ ]
+ filter: self
+ }
+ }
+ {
+ type: modifier
+ modifier: {
+ type: cantBeAssignedToSkirmish
+ requires: {
+ type: sarumanFirstSentenceActive
+ }
+ filter: self
+ }
+ }
+ {
+ type: trigger
+ optional: true
+ trigger: {
+ type: moves
+ }
+ effect: {
+ type: heal
+ filter: all(culture(isengard),orc)
+ times: 2
+ }
+ }
+ {
+ type: activated
+ phase: shadow
+ cost: {
+ type: exert
+ filter: self
+ }
+ effect: {
+ type: playCardFromDiscard
+ filter: choose(culture(isengard),possession)
+ }
+ }
+ ]
gametext: Saruman may not take wounds during the archery phase and may not be assigned to a skirmish.
Each time the fellowship moves, you may heal each [isengard] Orc twice.
Shadow: Exert Saruman to play an [isengard] possession from your discard pile.
lore: ""
promotext: ""
@@ -644,17 +868,39 @@
Machine
Support Area
]
- /*requires: {
-
- }
effects: [
- {
-
- }
- {
-
- }
- ]*/
+ {
+ type: activated
+ phase: shadow
+ cost: {
+ type: exert
+ filter: choose(urukHai)
+ }
+ effect: {
+ type: addTokens
+ culture: isengard
+ filter: self
+ }
+ }
+ {
+ type: activated
+ phase: skirmish
+ requires: {
+ type: canSpot
+ filter: self,hasToken(isengard)
+ }
+ effect: [
+ {
+ type: heal
+ filter: choose(urukHai)
+ }
+ {
+ type: discard
+ filter: self
+ }
+ ]
+ }
+ ]
gametext: Machine. Plays to your support area.
Shadow: Exert an Uruk-hai to place an [isengard] token on this card.
Skirmish: Spot an [isengard] token here to heal an Uruk-hai. Discard this condition.
lore: Hundreds of long ladders were lifted up. Many were cast down in ruin, but many more replaced them....
promotext: ""
@@ -693,17 +939,29 @@
vitality: 2
site: 4
keywords: Warg-rider
- /*requires: {
-
- }
effects: [
- {
-
- }
- {
-
- }
- ]*/
+ {
+ type: modifier
+ modifier: {
+ type: addKeyword
+ filter: self,not(exhausted)
+ keyword: fierce
+ }
+ }
+ {
+ type: trigger
+ optional: true
+ trigger: {
+ type: played
+ filter: culture(isengard),mount
+ }
+ effect: {
+ type: exert
+ player: fp
+ filter: choose(companion,not(hobbit))
+ }
+ }
+ ]
gametext: Warg-rider.
While Sharku is not exhausted, he is fierce.
Each time you play an [isengard] mount, you may make the Free Peoples player exert a companion (except a Hobbit).
lore: Only Sharku commanded enough respect to control Saruman's warg-riders.
promotext: ""
@@ -739,18 +997,36 @@
strength: 5
vitality: 3
itemclass: Mount
- #target: a warg-rider
- /*requires: {
-
- }
+ target: warg-rider
effects: [
- {
-
- }
- {
-
- }
- ]*/
+ {
+ type: modifier
+ modifier: {
+ type: addKeyword
+ filter: bearer,name(Sharku)
+ keyword: damage
+ amount: 1
+ }
+ }
+ {
+ type: activatedTrigger
+ trigger: {
+ type: usesSpecialAbility
+ phase: skirmish
+ }
+ requires: {
+ type: canSpot
+ filter: bearer,inSkirmish
+ }
+ cost: {
+ type: exert
+ filter: bearer
+ }
+ effect: {
+ type: cancelSpecialAbility
+ }
+ }
+ ]
gametext: Bearer must be a warg-rider.
If bearer is Sharku, he is damage +1.
Response: If a skirmish special ability is used in a skirmish involving bearer, exert bearer to cancel that action.
lore: The warg-captain picked the fastest and strongest mount.
promotext: ""
@@ -787,17 +1063,37 @@
Machine
Support Area
]
- /*requires: {
-
- }
effects: [
- {
-
- }
- {
-
- }
- ]*/
+ {
+ type: activated
+ phase: shadow
+ cost: {
+ type: play
+ filter: choose(urukHai)
+ }
+ effect: {
+ type: addTokens
+ culture: isengard
+ filter: self
+ }
+ }
+ {
+ type: activatedTrigger
+ trigger: {
+ type: aboutToDiscard
+ opponent: true
+ filter: machine
+ }
+ cost: {
+ type: discard
+ filter: self
+ }
+ effect: {
+ type: preventDiscard
+ filter: choose(machine)
+ }
+ }
+ ]
gametext: Machine. Plays to your support area.
Shadow: Play an Uruk-hai to place an [isengard] token on a machine.
Response: If one or more machines are about to be discarded by an opponent, discard this condition to prevent that.
lore: Ropes... were hurled over the parapet....
promotext: ""
@@ -835,17 +1131,21 @@
vitality: 2
site: 5
keywords: Damage+1
- /*requires: {
-
- }
effects: [
- {
-
- }
- {
-
- }
- ]*/
+ {
+ type: trigger
+ optional: true
+ trigger: {
+ type: played
+ filter: self
+ }
+ effect: {
+ type: addTokens
+ filter: choose(machine)
+ culture: isengard
+ }
+ }
+ ]
gametext: Damage +1.
When you play this minion, you may place an [isengard] token on a machine.
lore: Trained Uruk-hai operated Saruman's siege engines at Helm's Deep.
promotext: ""
@@ -883,17 +1183,21 @@
vitality: 2
site: 5
keywords: Damage+1
- /*requires: {
-
- }
effects: [
- {
-
- }
- {
-
- }
- ]*/
+ {
+ type: trigger
+ optional: true
+ trigger: {
+ type: played
+ filter: self
+ }
+ effect: {
+ type: addTokens
+ filter: choose(machine)
+ culture: isengard
+ }
+ }
+ ]
gametext: Damage +1.
When you play this minion, you may place an [isengard] token on a machine.
lore: The destruction of the Hornburg fortifications was the task of Saruman's engineer troops.
promotext: ""
@@ -931,17 +1235,19 @@
vitality: 3
site: 5
keywords: Damage+1
- /*requires: {
-
- }
effects: [
- {
-
- }
- {
-
- }
- ]*/
+ {
+ type: modifier
+ modifier: {
+ type: modifyStrength
+ filter: self,inSkirmish
+ amount: {
+ type: forEachWound
+ filter: character,inSkirmish
+ }
+ }
+ }
+ ]
gametext: Damage +1.
This minion is strength +1 for each wound on a character in its skirmish.
lore: Goatskins full of blood poured upon berserkers before battle instill their bloodlust.
promotext: ""
@@ -977,18 +1283,27 @@
strength: 4
vitality: 2
itemclass: Mount
- #target: a warg-rider
- /*requires: {
-
- }
+ target: warg-rider
effects: [
- {
-
- }
- {
-
- }
- ]*/
+ {
+ type: activatedTrigger
+ trigger: {
+ type: usesSpecialAbility
+ phase: skirmish
+ }
+ requires: {
+ type: canSpot
+ filter: bearer,inSkirmish
+ }
+ cost: {
+ type: exert
+ filter: bearer
+ }
+ effect: {
+ type: cancelSpecialAbility
+ }
+ }
+ ]
gametext: Bearer must be a warg-rider.
Response: If a skirmish special ability is used in a skirmish involving bearer, exert bearer to cancel that action.
lore: Bigger and stronger wargs were ridden into battle.
promotext: ""
@@ -1024,18 +1339,27 @@
strength: 3
vitality: 1
itemclass: Mount
- #target: a warg-rider
- /*requires: {
-
- }
+ target: warg-rider
effects: [
- {
-
- }
- {
-
- }
- ]*/
+ {
+ type: activatedTrigger
+ trigger: {
+ type: usesSpecialAbility
+ phase: skirmish
+ }
+ requires: {
+ type: canSpot
+ filter: bearer,inSkirmish
+ }
+ cost: {
+ type: exert
+ filter: bearer
+ }
+ effect: {
+ type: cancelSpecialAbility
+ }
+ }
+ ]
gametext: Bearer must be a warg-rider.
Response: If a skirmish special ability is used in a skirmish involving bearer, exert bearer to cancel that action.
lore: Tell him there is no hope ahead. He should return to Edoras before the wolves of Isengard come there.'
promotext: ""
@@ -1073,17 +1397,28 @@
vitality: 2
site: 4
keywords: Warg-rider
- /*requires: {
-
- }
effects: [
- {
-
- }
- {
-
- }
- ]*/
+ {
+ type: trigger
+ optional: true
+ trigger: {
+ type: played
+ filter: self
+ }
+ effect: {
+ type: playCardFromDiscard
+ filter: choose(culture(isengard),mount)
+ }
+ }
+ {
+ type: modifier
+ modifier: {
+ type: addKeyword
+ filter: self,not(exhausted)
+ keyword: fierce
+ }
+ }
+ ]
gametext: Warg-rider. When you play this minion, you may play an [isengard] mount from your discard pile.
While this minion is not exhausted, he is fierce.
lore: ...yet I feared that wolf-riders and plunderers might ride nonetheless to Meduseld, while it was undefended.'
promotext: ""
@@ -1121,17 +1456,16 @@
vitality: 2
site: 4
keywords: Warg-rider
- /*requires: {
-
- }
effects: [
- {
-
- }
- {
-
- }
- ]*/
+ {
+ type: modifier
+ modifier: {
+ type: addKeyword
+ filter: self,not(exhausted)
+ keyword: fierce
+ }
+ }
+ ]
gametext: Warg-rider.
While this minion is not exhausted, he is fierce.
lore: Swiftly a scout rode back and reported that wolf-riders were abroad in the valley....
promotext: ""
@@ -1165,20 +1499,29 @@
twilight: 1
type: Event
keywords: Skirmish
- /*requires: {
-
- }
effects: {
type: event
- cost: {
-
- },
effect: [
{
-
+ type: modifyStrength
+ filter: choose(culture(isengard),orc)
+ amount: 2
+ memorize: chosenOrc
+ }
+ {
+ type: conditional
+ requires: {
+ type: memoryMatches
+ memory: chosenOrc
+ filter: mounted
+ }
+ effect: {
+ type: heal
+ filter: memory(chosenOrc)
+ }
}
]
- }*/
+ }
gametext: Skirmish: Make an [isengard] Orc strength +2 (and heal it if mounted).
lore: ...these howls freeze my blood.'
promotext: ""
@@ -1211,17 +1554,22 @@
culture: Isengard
twilight: 2
type: Condition
- /*requires: {
-
- }
+ target: controlledSite,plains
effects: [
- {
-
- }
- {
-
- }
- ]*/
+ {
+ type: activated
+ phase: regroup
+ cost: {
+ type: exert
+ filter: choose(culture(isengard),orc)
+ }
+ effect: {
+ type: wound
+ player: fp
+ filter: choose(companion)
+ }
+ }
+ ]
gametext: Plays on a plains site you control.
Regroup: Exert an [isengard] Orc to make the Free Peoples player wound a companion.
lore: Saruman's warg-riders traveled the plains faster than even the Riders of Rohan.
promotext: ""
@@ -1259,17 +1607,34 @@
vitality: 3
site: 4
keywords: Warg-rider
- /*requires: {
-
- }
effects: [
- {
-
- }
- {
-
- }
- ]*/
+ {
+ type: modifier
+ modifier: {
+ type: addKeyword
+ filter: self,not(exhausted)
+ keyword: fierce
+ }
+ }
+ {
+ type: modifier
+ modifier: {
+ type: addKeyword
+ filter: self,vitalityMoreThan(2)
+ keyword: ambush
+ amount: 1
+ }
+ }
+ {
+ type: modifier
+ modifier: {
+ type: addKeyword
+ filter: self,vitalityMoreThan(3)
+ keyword: damage
+ amount: 1
+ }
+ }
+ ]
gametext: Warg-rider.
While Foul Horde is not exhausted, it is fierce.
While Foul Horde has at least 3 vitality, it is ambush (1).
While Foul Horde has at least 4 vitality, it is damage +1.
lore: ""
promotext: ""
diff --git a/gemp-lotr/gemp-lotr-cards/src/main/resources/cards/official/set09/set9-1.hjson b/gemp-lotr/gemp-lotr-cards/src/main/resources/cards/official/set09/set9-1.hjson
index 63c4e2d26..50fed3e86 100644
--- a/gemp-lotr/gemp-lotr-cards/src/main/resources/cards/official/set09/set9-1.hjson
+++ b/gemp-lotr/gemp-lotr-cards/src/main/resources/cards/official/set09/set9-1.hjson
@@ -490,7 +490,7 @@
}
{
type: repeat
- amount: {
+ times: {
type: fromMemory
memory: spottedElfCount
}
@@ -740,7 +740,7 @@
effect: [
{
type: repeat
- amount: {
+ times: {
type: forEachVitality
filter: bearer
}
diff --git a/gemp-lotr/gemp-lotr-cards/src/main/resources/cards/official/set09/set9-2.hjson b/gemp-lotr/gemp-lotr-cards/src/main/resources/cards/official/set09/set9-2.hjson
index f8a405e52..2f221e43d 100644
--- a/gemp-lotr/gemp-lotr-cards/src/main/resources/cards/official/set09/set9-2.hjson
+++ b/gemp-lotr/gemp-lotr-cards/src/main/resources/cards/official/set09/set9-2.hjson
@@ -109,7 +109,7 @@
}
{
type: repeat
- amount: {
+ times: {
type: forEachInHand
filter: side(shadow)
}
diff --git a/gemp-lotr/gemp-lotr-cards/src/main/resources/cards/official/set14/set14.hjson b/gemp-lotr/gemp-lotr-cards/src/main/resources/cards/official/set14/set14.hjson
index 414e99041..5a91a7326 100644
--- a/gemp-lotr/gemp-lotr-cards/src/main/resources/cards/official/set14/set14.hjson
+++ b/gemp-lotr/gemp-lotr-cards/src/main/resources/cards/official/set14/set14.hjson
@@ -512,7 +512,7 @@
filter: choose(uruk-hai)
count: 0-1
}
- amount: {
+ times: {
type: forEachYouCanSpot
filter: companion
}
diff --git a/gemp-lotr/gemp-lotr-cards/src/main/resources/cards/unofficial/hobbit/set31/set31-fp.hjson b/gemp-lotr/gemp-lotr-cards/src/main/resources/cards/unofficial/hobbit/set31/set31-fp.hjson
index bfdfd2713..f33f385e9 100644
--- a/gemp-lotr/gemp-lotr-cards/src/main/resources/cards/unofficial/hobbit/set31/set31-fp.hjson
+++ b/gemp-lotr/gemp-lotr-cards/src/main/resources/cards/unofficial/hobbit/set31/set31-fp.hjson
@@ -65,7 +65,7 @@
}
effect: {
type: repeat
- amount: {
+ times: {
type: twilightCostInMemory
memory: discardedFollower
}
diff --git a/gemp-lotr/gemp-lotr-cards/src/main/resources/cards/unofficial/hobbit/set31/set31-shadow.hjson b/gemp-lotr/gemp-lotr-cards/src/main/resources/cards/unofficial/hobbit/set31/set31-shadow.hjson
index f0e332717..3ee1231ed 100644
--- a/gemp-lotr/gemp-lotr-cards/src/main/resources/cards/unofficial/hobbit/set31/set31-shadow.hjson
+++ b/gemp-lotr/gemp-lotr-cards/src/main/resources/cards/unofficial/hobbit/set31/set31-shadow.hjson
@@ -745,7 +745,7 @@
}
effect: {
type: repeat
- amount: {
+ times: {
type: forEachYouCanSpot
filter: culture(dwarven),companion
over: 3
diff --git a/gemp-lotr/gemp-lotr-cards/src/main/resources/cards/unofficial/hobbit/set32/set32-shadow.hjson b/gemp-lotr/gemp-lotr-cards/src/main/resources/cards/unofficial/hobbit/set32/set32-shadow.hjson
index 3ba76216e..ce90cb24f 100644
--- a/gemp-lotr/gemp-lotr-cards/src/main/resources/cards/unofficial/hobbit/set32/set32-shadow.hjson
+++ b/gemp-lotr/gemp-lotr-cards/src/main/resources/cards/unofficial/hobbit/set32/set32-shadow.hjson
@@ -185,7 +185,7 @@
}
effect: {
type: repeat
- amount: {
+ times: {
type: forEachYouCanSpot
filter: culture(dwarven),companion
over: 3
diff --git a/gemp-lotr/gemp-lotr-cards/src/main/resources/cards/unofficial/hobbit/set33/set33-fp.hjson b/gemp-lotr/gemp-lotr-cards/src/main/resources/cards/unofficial/hobbit/set33/set33-fp.hjson
index c958bc6b6..b39df3b7b 100644
--- a/gemp-lotr/gemp-lotr-cards/src/main/resources/cards/unofficial/hobbit/set33/set33-fp.hjson
+++ b/gemp-lotr/gemp-lotr-cards/src/main/resources/cards/unofficial/hobbit/set33/set33-fp.hjson
@@ -753,7 +753,7 @@
}
{
type: repeat
- amount: {
+ times: {
type: forEachMatchingInMemory
memory: cardsInHand
filter: side(free people),skirmish,event
diff --git a/gemp-lotr/gemp-lotr-cards/src/main/resources/cards/unofficial/hobbit/set33/set33-sites.hjson b/gemp-lotr/gemp-lotr-cards/src/main/resources/cards/unofficial/hobbit/set33/set33-sites.hjson
index 7bf60eb68..7ec80e2b5 100644
--- a/gemp-lotr/gemp-lotr-cards/src/main/resources/cards/unofficial/hobbit/set33/set33-sites.hjson
+++ b/gemp-lotr/gemp-lotr-cards/src/main/resources/cards/unofficial/hobbit/set33/set33-sites.hjson
@@ -112,7 +112,7 @@
}
{
type: repeat
- amount: {
+ times: {
type: forEachYouCanSpot
filter: follower,culture(dwarven),not(memory(transferredFollowers))
}
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 3a83323e3..825a1ff54 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
@@ -61,7 +61,7 @@
]
effect: {
type: Repeat
- amount: {
+ times: {
type: forEachYouCanSpot
filter: companion
over: 4
diff --git a/gemp-lotr/gemp-lotr-cards/src/main/resources/cards/unofficial/pc/errata/set01/set01-Sauron-errata.hjson b/gemp-lotr/gemp-lotr-cards/src/main/resources/cards/unofficial/pc/errata/set01/set01-Sauron-errata.hjson
index 03a678a46..a013f3074 100644
--- a/gemp-lotr/gemp-lotr-cards/src/main/resources/cards/unofficial/pc/errata/set01/set01-Sauron-errata.hjson
+++ b/gemp-lotr/gemp-lotr-cards/src/main/resources/cards/unofficial/pc/errata/set01/set01-Sauron-errata.hjson
@@ -392,7 +392,7 @@
}
effect: {
type: repeat
- amount: {
+ times: {
type: ForEachInDeadPile
filter: any
}
@@ -432,7 +432,7 @@
}
effect: {
type: repeat
- amount: {
+ times: {
type: ForEachInDeadPile
filter: any
}
diff --git a/gemp-lotr/gemp-lotr-cards/src/main/resources/cards/unofficial/pc/errata/set02/set02-Dwarven-errata.hjson b/gemp-lotr/gemp-lotr-cards/src/main/resources/cards/unofficial/pc/errata/set02/set02-Dwarven-errata.hjson
index b333f4c71..587ba9bcc 100644
--- a/gemp-lotr/gemp-lotr-cards/src/main/resources/cards/unofficial/pc/errata/set02/set02-Dwarven-errata.hjson
+++ b/gemp-lotr/gemp-lotr-cards/src/main/resources/cards/unofficial/pc/errata/set02/set02-Dwarven-errata.hjson
@@ -164,7 +164,7 @@
}
{
type: Repeat
- amount: 9
+ times: 9
effect: {
type: conditional
requires: {
diff --git a/gemp-lotr/gemp-lotr-cards/src/main/resources/cards/unofficial/pc/errata/set03/set03-Moria-errata.hjson b/gemp-lotr/gemp-lotr-cards/src/main/resources/cards/unofficial/pc/errata/set03/set03-Moria-errata.hjson
index 4bf77bae8..551fc25f5 100644
--- a/gemp-lotr/gemp-lotr-cards/src/main/resources/cards/unofficial/pc/errata/set03/set03-Moria-errata.hjson
+++ b/gemp-lotr/gemp-lotr-cards/src/main/resources/cards/unofficial/pc/errata/set03/set03-Moria-errata.hjson
@@ -53,7 +53,7 @@
}
{
type: repeat
- amount: {
+ times: {
type: sum
source: [
{
diff --git a/gemp-lotr/gemp-lotr-cards/src/main/resources/cards/unofficial/pc/errata/set04/set04-Isengard-errata.hjson b/gemp-lotr/gemp-lotr-cards/src/main/resources/cards/unofficial/pc/errata/set04/set04-Isengard-errata.hjson
index 9af56d8ac..67348de1e 100644
--- a/gemp-lotr/gemp-lotr-cards/src/main/resources/cards/unofficial/pc/errata/set04/set04-Isengard-errata.hjson
+++ b/gemp-lotr/gemp-lotr-cards/src/main/resources/cards/unofficial/pc/errata/set04/set04-Isengard-errata.hjson
@@ -50,7 +50,7 @@
}
{
type: Repeat
- amount: {
+ times: {
type: Sum
source: [
1
diff --git a/gemp-lotr/gemp-lotr-cards/src/main/resources/cards/unofficial/pc/errata/set05/set05-Isengard-errata.hjson b/gemp-lotr/gemp-lotr-cards/src/main/resources/cards/unofficial/pc/errata/set05/set05-Isengard-errata.hjson
index bc2c5f03f..3a0f18dd1 100644
--- a/gemp-lotr/gemp-lotr-cards/src/main/resources/cards/unofficial/pc/errata/set05/set05-Isengard-errata.hjson
+++ b/gemp-lotr/gemp-lotr-cards/src/main/resources/cards/unofficial/pc/errata/set05/set05-Isengard-errata.hjson
@@ -63,7 +63,7 @@
effect: [
{
type: repeat
- amount: {
+ times: {
type: ForEachToken
filter: self
culture: isengard
diff --git a/gemp-lotr/gemp-lotr-cards/src/main/resources/cards/unofficial/pc/errata/set10/set10-Rohan-errata.hjson b/gemp-lotr/gemp-lotr-cards/src/main/resources/cards/unofficial/pc/errata/set10/set10-Rohan-errata.hjson
index dd623418d..84132dcea 100644
--- a/gemp-lotr/gemp-lotr-cards/src/main/resources/cards/unofficial/pc/errata/set10/set10-Rohan-errata.hjson
+++ b/gemp-lotr/gemp-lotr-cards/src/main/resources/cards/unofficial/pc/errata/set10/set10-Rohan-errata.hjson
@@ -62,7 +62,7 @@
}
{
type: Repeat
- amount: {
+ times: {
type: ForEachWound
filter: minion,InSkirmishAgainst(self)
}
diff --git a/gemp-lotr/gemp-lotr-cards/src/main/resources/cards/unofficial/pc/errata/set15/set15-Gondor-errata.hjson b/gemp-lotr/gemp-lotr-cards/src/main/resources/cards/unofficial/pc/errata/set15/set15-Gondor-errata.hjson
index d5b5e4c8e..5732dc38c 100644
--- a/gemp-lotr/gemp-lotr-cards/src/main/resources/cards/unofficial/pc/errata/set15/set15-Gondor-errata.hjson
+++ b/gemp-lotr/gemp-lotr-cards/src/main/resources/cards/unofficial/pc/errata/set15/set15-Gondor-errata.hjson
@@ -132,7 +132,7 @@
}
effect: {
type: repeat
- amount: {
+ times: {
type: forEachThreat
}
effect: {
diff --git a/gemp-lotr/gemp-lotr-cards/src/main/resources/cards/unofficial/second-edition/set40/set40-moria.hjson b/gemp-lotr/gemp-lotr-cards/src/main/resources/cards/unofficial/second-edition/set40/set40-moria.hjson
index ca8f1cab4..8685b0025 100644
--- a/gemp-lotr/gemp-lotr-cards/src/main/resources/cards/unofficial/second-edition/set40/set40-moria.hjson
+++ b/gemp-lotr/gemp-lotr-cards/src/main/resources/cards/unofficial/second-edition/set40/set40-moria.hjson
@@ -405,7 +405,7 @@
}
effect: {
type: repeat
- amount: {
+ times: {
type: forEachYouCanSpot
filter: companion
over: 5
diff --git a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/effect/appender/DoWhile.java b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/effect/appender/DoWhile.java
index 761e55037..ff7e9646b 100644
--- a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/effect/appender/DoWhile.java
+++ b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/effect/appender/DoWhile.java
@@ -7,12 +7,10 @@ import com.gempukku.lotro.cards.build.Requirement;
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.actions.SubAction;
+import com.gempukku.lotro.logic.actions.DoWhileSubAction;
import com.gempukku.lotro.logic.effects.StackActionEffect;
import com.gempukku.lotro.logic.timing.Effect;
-import com.gempukku.lotro.logic.timing.UnrespondableEffect;
import org.json.simple.JSONObject;
public class DoWhile implements EffectAppenderProducer {
@@ -36,30 +34,15 @@ public class DoWhile implements EffectAppenderProducer {
return true;
}
- private SubAction createSubAction(CostToEffectAction action, ActionContext actionContext) {
- SubAction subAction = new SubAction(action);
- for (EffectAppender effectAppender : effectAppenders)
- effectAppender.appendEffect(false, subAction, actionContext);
- subAction.appendEffect(
- new UnrespondableEffect() {
- @Override
- protected void doPlayEffect(LotroGame game) {
- if (conditionsMatch(actionContext)) {
- game.getActionsEnvironment().addActionToStack(createSubAction(action, actionContext));
- }
- }
- }
- );
- return subAction;
- }
-
@Override
protected Effect createEffect(boolean cost, CostToEffectAction action, ActionContext actionContext) {
- if (conditionsMatch(actionContext)) {
- return new StackActionEffect(createSubAction(action, actionContext));
- } else {
- return null;
- }
+ DoWhileSubAction doWhile = new DoWhileSubAction(action,
+ () -> conditionsMatch(actionContext),
+ costToEffectAction -> {
+ for (EffectAppender effectAppender : effectAppenders)
+ effectAppender.appendEffect(false, costToEffectAction, actionContext);
+ });
+ return new StackActionEffect(doWhile);
}
};
}
diff --git a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/effect/appender/PlayCardFromDiscard.java b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/effect/appender/PlayCardFromDiscard.java
index c6d2a07c1..c6b30fbc7 100644
--- a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/effect/appender/PlayCardFromDiscard.java
+++ b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/effect/appender/PlayCardFromDiscard.java
@@ -15,6 +15,8 @@ import com.gempukku.lotro.logic.actions.CostToEffectAction;
import com.gempukku.lotro.logic.effects.StackActionEffect;
import com.gempukku.lotro.logic.modifiers.ModifierFlag;
import com.gempukku.lotro.logic.modifiers.evaluator.ConstantEvaluator;
+import com.gempukku.lotro.logic.modifiers.evaluator.Evaluator;
+import com.gempukku.lotro.logic.modifiers.evaluator.RangeEvaluator;
import com.gempukku.lotro.logic.timing.Effect;
import com.gempukku.lotro.logic.timing.ExtraFilters;
import com.gempukku.lotro.logic.timing.FailedEffect;
@@ -25,12 +27,13 @@ import java.util.Collection;
public class PlayCardFromDiscard implements EffectAppenderProducer {
@Override
public EffectAppender createEffectAppender(JSONObject effectObject, CardGenerationEnvironment environment) throws InvalidCardDefinitionException {
- FieldUtils.validateAllowedFields(effectObject, "filter", "on", "cost", "removedTwilight", "memorize");
+ FieldUtils.validateAllowedFields(effectObject, "filter", "on", "cost", "removedTwilight", "optional", "memorize");
final String filter = FieldUtils.getString(effectObject.get("filter"), "filter");
final String onFilter = FieldUtils.getString(effectObject.get("on"), "on");
final int removedTwilight = FieldUtils.getInteger(effectObject.get("removedTwilight"), "removedTwilight", 0);
final ValueSource costModifierSource = ValueResolver.resolveEvaluator(effectObject.get("cost"), 0, environment);
+ final boolean optional = FieldUtils.getBoolean(effectObject.get("optional"), "optional", false);
final String memorize = FieldUtils.getString(effectObject.get("memorize"), "memorize", "_temp");
final FilterableSource onFilterableSource = (onFilter != null) ? environment.getFilterFactory().generateFilter(onFilter, environment) : null;
@@ -38,6 +41,8 @@ public class PlayCardFromDiscard implements EffectAppenderProducer {
MultiEffectAppender result = new MultiEffectAppender();
result.setPlayabilityCheckedForEffect(true);
+ Evaluator countEvaluator = optional ? new RangeEvaluator(0, 1) : new ConstantEvaluator(1);
+
result.addEffectAppender(
CardResolver.resolveCardsInDiscard(filter,
(actionContext) -> {
@@ -60,7 +65,7 @@ public class PlayCardFromDiscard implements EffectAppenderProducer {
return Filters.playable(actionContext.getGame(), removedTwilight, costModifier, false, false, true);
},
- new ConstantEvaluator(1), memorize, "you", "Choose card to play", environment));
+ countEvaluator, memorize, "you", "Choose card to play", environment));
result.addEffectAppender(
new DelayedAppender() {
@Override
diff --git a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/effect/appender/Repeat.java b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/effect/appender/Repeat.java
index 2c10f19a0..9081eff80 100644
--- a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/effect/appender/Repeat.java
+++ b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/effect/appender/Repeat.java
@@ -19,9 +19,9 @@ import java.util.Arrays;
public class Repeat implements EffectAppenderProducer {
@Override
public EffectAppender createEffectAppender(JSONObject effectObject, CardGenerationEnvironment environment) throws InvalidCardDefinitionException {
- FieldUtils.validateAllowedFields(effectObject, "amount", "effect");
+ FieldUtils.validateAllowedFields(effectObject, "times", "effect");
- final ValueSource amountSource = ValueResolver.resolveEvaluator(effectObject.get("amount"), environment);
+ final ValueSource timesSource = ValueResolver.resolveEvaluator(effectObject.get("times"), environment);
final JSONObject[] effectArray = FieldUtils.getObjectArray(effectObject.get("effect"), "effect");
final EffectAppender[] effectAppenders = environment.getEffectAppenderFactory().getEffectAppenders(effectArray, environment);
@@ -29,10 +29,10 @@ public class Repeat implements EffectAppenderProducer {
return new DelayedAppender() {
@Override
protected Effect createEffect(boolean cost, CostToEffectAction action, ActionContext actionContext) {
- final int count = amountSource.getEvaluator(actionContext).evaluateExpression(actionContext.getGame(), null);
- if (count > 0) {
+ final int times = timesSource.getEvaluator(actionContext).evaluateExpression(actionContext.getGame(), null);
+ if (times > 0) {
SubAction subAction = new SubAction(action);
- for (int i = 0; i < count; i++) {
+ for (int i = 0; i < times; i++) {
for (EffectAppender effectAppender : effectAppenders)
effectAppender.appendEffect(false, subAction, actionContext);
}
diff --git a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/effect/filter/FilterFactory.java b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/effect/filter/FilterFactory.java
index 62bf05153..484a7f56b 100644
--- a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/effect/filter/FilterFactory.java
+++ b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/effect/filter/FilterFactory.java
@@ -41,6 +41,7 @@ public class FilterFactory {
});
simpleFilters.put("bearer", (actionContext -> Filters.hasAttached(actionContext.getSource())));
simpleFilters.put("character", (actionContext) -> Filters.character);
+ simpleFilters.put("canbereturnedtohand", (actionContext -> Filters.canBeReturnedToHand(actionContext.getSource())));
simpleFilters.put("canexert", (actionContext -> Filters.canExert(actionContext.getSource())));
simpleFilters.put("controlledbyotherplayer",
(actionContext -> Filters.siteControlledByOtherPlayer(actionContext.getPerformingPlayer())));
diff --git a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/effect/requirement/CanSpotFPCultures.java b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/effect/requirement/CanSpotFPCultures.java
new file mode 100644
index 000000000..c19b33a77
--- /dev/null
+++ b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/effect/requirement/CanSpotFPCultures.java
@@ -0,0 +1,18 @@
+package com.gempukku.lotro.cards.build.field.effect.requirement;
+
+import com.gempukku.lotro.cards.build.CardGenerationEnvironment;
+import com.gempukku.lotro.cards.build.InvalidCardDefinitionException;
+import com.gempukku.lotro.cards.build.Requirement;
+import com.gempukku.lotro.cards.build.field.FieldUtils;
+import com.gempukku.lotro.logic.GameUtils;
+import org.json.simple.JSONObject;
+
+public class CanSpotFPCultures implements RequirementProducer {
+ @Override
+ public Requirement getPlayRequirement(JSONObject object, CardGenerationEnvironment environment) throws InvalidCardDefinitionException {
+ FieldUtils.validateAllowedFields(object, "amount");
+ final int amount = FieldUtils.getInteger(object.get("amount"), "amount");
+
+ return (actionContext) -> GameUtils.getSpottableFPCulturesCount(actionContext.getGame(), actionContext.getPerformingPlayer()) >= amount;
+ }
+}
diff --git a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/effect/requirement/RequirementFactory.java b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/effect/requirement/RequirementFactory.java
index 1680e01bf..295a14991 100644
--- a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/effect/requirement/RequirementFactory.java
+++ b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/effect/requirement/RequirementFactory.java
@@ -20,6 +20,7 @@ public class RequirementFactory {
requirementProducers.put("canspot", new CanSpot());
requirementProducers.put("canspotburdens", new CanSpotBurdens());
requirementProducers.put("canspotculturetokens", new CanSpotCultureTokens());
+ requirementProducers.put("canspotfpcultures", new CanSpotFPCultures());
requirementProducers.put("canspotthreats", new CanSpotThreats());
requirementProducers.put("canspottwilight", new CanSpotTwilight());
requirementProducers.put("canspotwounds", new CanSpotWounds());
diff --git a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/effect/trigger/AboutToDiscardFromPlay.java b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/effect/trigger/AboutToDiscardFromPlay.java
index 070d9583c..b4292a6c0 100644
--- a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/effect/trigger/AboutToDiscardFromPlay.java
+++ b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/effect/trigger/AboutToDiscardFromPlay.java
@@ -11,10 +11,11 @@ import org.json.simple.JSONObject;
public class AboutToDiscardFromPlay implements TriggerCheckerProducer {
@Override
public TriggerChecker getTriggerChecker(JSONObject value, CardGenerationEnvironment environment) throws InvalidCardDefinitionException {
- FieldUtils.validateAllowedFields(value, "source", "filter");
+ FieldUtils.validateAllowedFields(value, "source", "filter", "opponent");
String source = FieldUtils.getString(value.get("source"), "source", "any");
String filter = FieldUtils.getString(value.get("filter"), "filter");
+ boolean opponent = FieldUtils.getBoolean(value.get("opponent"), "opponent", false);
final FilterableSource sourceFilter = environment.getFilterFactory().generateFilter(source, environment);
final FilterableSource affectedFilter = environment.getFilterFactory().generateFilter(filter, environment);
@@ -22,9 +23,16 @@ public class AboutToDiscardFromPlay implements TriggerCheckerProducer {
return new TriggerChecker() {
@Override
public boolean accepts(ActionContext actionContext) {
- return TriggerConditions.isGettingDiscardedBy(actionContext.getEffect(), actionContext.getGame(),
- sourceFilter.getFilterable(actionContext),
- affectedFilter.getFilterable(actionContext));
+ if (opponent) {
+ return TriggerConditions.isGettingDiscardedByOpponent(actionContext.getEffect(), actionContext.getGame(),
+ actionContext.getPerformingPlayer(),
+ sourceFilter.getFilterable(actionContext),
+ affectedFilter.getFilterable(actionContext));
+ } else {
+ return TriggerConditions.isGettingDiscardedBy(actionContext.getEffect(), actionContext.getGame(),
+ sourceFilter.getFilterable(actionContext),
+ affectedFilter.getFilterable(actionContext));
+ }
}
@Override
diff --git a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/effect/trigger/UsesSpecialAbility.java b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/effect/trigger/UsesSpecialAbility.java
index 58a1fc95a..b41dad522 100644
--- a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/effect/trigger/UsesSpecialAbility.java
+++ b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/effect/trigger/UsesSpecialAbility.java
@@ -5,6 +5,7 @@ import com.gempukku.lotro.cards.build.CardGenerationEnvironment;
import com.gempukku.lotro.cards.build.FilterableSource;
import com.gempukku.lotro.cards.build.InvalidCardDefinitionException;
import com.gempukku.lotro.cards.build.field.FieldUtils;
+import com.gempukku.lotro.common.Phase;
import com.gempukku.lotro.game.PhysicalCard;
import com.gempukku.lotro.logic.timing.TriggerConditions;
import com.gempukku.lotro.logic.timing.results.ActivateCardResult;
@@ -13,10 +14,11 @@ import org.json.simple.JSONObject;
public class UsesSpecialAbility implements TriggerCheckerProducer {
@Override
public TriggerChecker getTriggerChecker(JSONObject value, CardGenerationEnvironment environment) throws InvalidCardDefinitionException {
- FieldUtils.validateAllowedFields(value, "filter", "memorize");
+ FieldUtils.validateAllowedFields(value, "filter", "memorize", "phase");
String filter = FieldUtils.getString(value.get("filter"), "filter", "any");
final FilterableSource filterableSource = environment.getFilterFactory().generateFilter(filter, environment);
+ final Phase phase = FieldUtils.getEnum(Phase.class, value.get("phase"), "phase");
final String memorize = FieldUtils.getString(value.get("memorize"), "memorize");
return new TriggerChecker() {
@@ -31,6 +33,10 @@ public class UsesSpecialAbility implements TriggerCheckerProducer {
if (activated) {
ActivateCardResult activateCardResult = (ActivateCardResult) actionContext.getEffectResult();
+ if (phase != null) {
+ if (activateCardResult.getActionTimeword() != phase)
+ return false;
+ }
if (memorize != null) {
PhysicalCard playedCard = activateCardResult.getSource();
diff --git a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/filters/Filters.java b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/filters/Filters.java
index 54856ff74..209414a94 100644
--- a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/filters/Filters.java
+++ b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/filters/Filters.java
@@ -519,6 +519,15 @@ public class Filters {
};
}
+ public static Filter canBeReturnedToHand(final PhysicalCard source) {
+ return new Filter() {
+ @Override
+ public boolean accepts(LotroGame game, PhysicalCard physicalCard) {
+ return game.getModifiersQuerying().canBeReturnedToHand(game, physicalCard, source);
+ }
+ };
+ }
+
public static Filter canExert(final PhysicalCard source) {
return canExert(source, 1);
}
diff --git a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/logic/actions/AbstractCostToEffectAction.java b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/logic/actions/AbstractCostToEffectAction.java
index 936ea814a..103d4f452 100644
--- a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/logic/actions/AbstractCostToEffectAction.java
+++ b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/logic/actions/AbstractCostToEffectAction.java
@@ -122,6 +122,10 @@ public abstract class AbstractCostToEffectAction implements CostToEffectAction {
return sum;
}
+ protected final boolean hasNextCost() {
+ return !_costs.isEmpty();
+ }
+
protected final Effect getNextCost() {
Effect cost = _costs.poll();
if (cost != null)
@@ -129,6 +133,10 @@ public abstract class AbstractCostToEffectAction implements CostToEffectAction {
return cost;
}
+ protected final boolean hasNextEffect() {
+ return !_effects.isEmpty();
+ }
+
protected final Effect getNextEffect() {
final Effect effect = _effects.poll();
if (effect != null)
diff --git a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/logic/actions/DoWhileSubAction.java b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/logic/actions/DoWhileSubAction.java
new file mode 100644
index 000000000..fe056dc2e
--- /dev/null
+++ b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/logic/actions/DoWhileSubAction.java
@@ -0,0 +1,37 @@
+package com.gempukku.lotro.logic.actions;
+
+import com.gempukku.lotro.game.state.LotroGame;
+import com.gempukku.lotro.logic.timing.Action;
+import com.gempukku.lotro.logic.timing.Effect;
+
+import java.util.function.BooleanSupplier;
+import java.util.function.Consumer;
+
+public class DoWhileSubAction extends SubAction {
+ private final BooleanSupplier condition;
+ private final Consumer effectsAppender;
+
+ private boolean firstExecution = true;
+
+ public DoWhileSubAction(Action action, BooleanSupplier condition, Consumer effectsAppender) {
+ super(action);
+ this.condition = condition;
+ this.effectsAppender = effectsAppender;
+ }
+
+ @Override
+ public Effect nextEffect(LotroGame game) {
+ if (firstExecution) {
+ effectsAppender.accept(this);
+ firstExecution = false;
+ }
+
+ if (!hasNextEffect()) {
+ if (condition.getAsBoolean()) {
+ effectsAppender.accept(this);
+ }
+ }
+
+ return getNextEffect();
+ }
+}
diff --git a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/logic/timing/TriggerConditions.java b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/logic/timing/TriggerConditions.java
index fa5e1464e..1f0629d6b 100644
--- a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/logic/timing/TriggerConditions.java
+++ b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/logic/timing/TriggerConditions.java
@@ -419,10 +419,11 @@ public class TriggerConditions {
return false;
}
- public static boolean isGettingDiscardedByOpponent(Effect effect, LotroGame game, String playerId, Filterable... filters) {
+ public static boolean isGettingDiscardedByOpponent(Effect effect, LotroGame game, String playerId, Filterable sourceFilter, Filterable... filters) {
if (effect.getType() == Effect.Type.BEFORE_DISCARD_FROM_PLAY) {
PreventableCardEffect preventableEffect = (PreventableCardEffect) effect;
- if (effect.getSource() != null && !effect.getPerformingPlayer().equals(playerId))
+ if (effect.getSource() != null && Filters.and(sourceFilter).accepts(game, effect.getSource())
+ && !effect.getPerformingPlayer().equals(playerId))
return Filters.filter(preventableEffect.getAffectedCardsMinusPrevented(game), game, filters).size() > 0;
}
return false;