Optional effect type overhaul
- So it turns out that Optional is frequently used to wrap a CostToEffect, but because of how that's set up the Optional does not ensure the "Cost" part is actually enforced. Thus someone can choose "yes" and it will always treat both halves of a CostToEffect as optional. - Added the standard "requires" and "cost" fields to Optional - Refactored about 30 cards to no longer use CostToEffect nested within an Optional, instead opting to use the cost field of Optional itself
This commit is contained in:
@@ -688,20 +688,17 @@
|
||||
}
|
||||
true: {
|
||||
type: optional
|
||||
text: Would you like to discard an ISENGARD minion revealed to draw 2 cards?
|
||||
text: Would you like to discard an {ISENGARD} minion revealed to draw 2 cards?
|
||||
cost: {
|
||||
type: discardFromHand
|
||||
hand: shadowPlayer
|
||||
forced: true
|
||||
player: you
|
||||
select: choose(memory(revealedCards),culture(isengard),minion)
|
||||
}
|
||||
effect: {
|
||||
type: costToEffect
|
||||
cost: {
|
||||
type: discardFromHand
|
||||
hand: shadowPlayer
|
||||
forced: true
|
||||
player: you
|
||||
select: choose(memory(revealedCards),culture(isengard),minion)
|
||||
}
|
||||
effect: {
|
||||
type: drawCards
|
||||
count: 2
|
||||
}
|
||||
type: drawCards
|
||||
count: 2
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,19 +28,16 @@
|
||||
type: optional
|
||||
player: fp
|
||||
text: Would you like to discard 2 cards from hand to discard Dunlending Rampager?
|
||||
cost: {
|
||||
type: discardFromHand
|
||||
forced: false
|
||||
player: fp
|
||||
hand: fp
|
||||
count: 2
|
||||
}
|
||||
effect: {
|
||||
type: costToEffect
|
||||
cost: {
|
||||
type: discardFromHand
|
||||
forced: false
|
||||
player: fp
|
||||
hand: fp
|
||||
count: 2
|
||||
}
|
||||
effect: {
|
||||
type: discard
|
||||
select: self
|
||||
}
|
||||
type: discard
|
||||
select: self
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -84,19 +81,16 @@
|
||||
type: optional
|
||||
player: fp
|
||||
text: Would you like to discard 2 cards from hand to discard Dunlending Rampager?
|
||||
cost: {
|
||||
type: discardFromHand
|
||||
forced: false
|
||||
player: fp
|
||||
hand: fp
|
||||
count: 2
|
||||
}
|
||||
effect: {
|
||||
type: costToEffect
|
||||
cost: {
|
||||
type: discardFromHand
|
||||
forced: false
|
||||
player: fp
|
||||
hand: fp
|
||||
count: 2
|
||||
}
|
||||
effect: {
|
||||
type: discard
|
||||
select: self
|
||||
}
|
||||
type: discard
|
||||
select: self
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -204,19 +198,16 @@
|
||||
type: optional
|
||||
player: fp
|
||||
text: Would you like to discard 4 cards from hand to discard Wild Men of the Hills?
|
||||
cost: {
|
||||
type: discardFromHand
|
||||
forced: false
|
||||
player: fp
|
||||
hand: fp
|
||||
count: 4
|
||||
}
|
||||
effect: {
|
||||
type: costToEffect
|
||||
cost: {
|
||||
type: discardFromHand
|
||||
forced: false
|
||||
player: fp
|
||||
hand: fp
|
||||
count: 4
|
||||
}
|
||||
effect: {
|
||||
type: discard
|
||||
select: self
|
||||
}
|
||||
type: discard
|
||||
select: self
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -240,20 +240,17 @@
|
||||
{
|
||||
type: optional
|
||||
text: Would you like to exert Glorfindel to make a Nazgul he is skirmishing strength -X, where X is the twilight cost the the card revealed?
|
||||
cost: {
|
||||
type: exert
|
||||
select: self
|
||||
}
|
||||
effect: {
|
||||
type: costToEffect
|
||||
cost: {
|
||||
type: exert
|
||||
select: self
|
||||
}
|
||||
effect: {
|
||||
type: modifyStrength
|
||||
select: choose(nazgul,inSkirmishAgainst(self))
|
||||
amount: {
|
||||
type: twilightCostInMemory
|
||||
memory: revealedCard
|
||||
multiplier: -1
|
||||
}
|
||||
type: modifyStrength
|
||||
select: choose(nazgul,inSkirmishAgainst(self))
|
||||
amount: {
|
||||
type: twilightCostInMemory
|
||||
memory: revealedCard
|
||||
multiplier: -1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -168,17 +168,17 @@
|
||||
type: optional
|
||||
player: shadowPlayer
|
||||
text: Would you like to discard 2 cards to draw 2 cards?
|
||||
cost: {
|
||||
type: discardFromHand
|
||||
player: shadow
|
||||
hand: shadow
|
||||
forced: false
|
||||
count: 2
|
||||
}
|
||||
effect: {
|
||||
type: costToEffect
|
||||
cost: {
|
||||
type: discardFromHand
|
||||
forced: false
|
||||
count: 2
|
||||
}
|
||||
effect: {
|
||||
type: drawCards
|
||||
count: 2
|
||||
}
|
||||
type: drawCards
|
||||
player: shadow
|
||||
count: 2
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -80,19 +80,16 @@
|
||||
}
|
||||
{
|
||||
type: optional
|
||||
text: Would you like exert the played ROHAN Man to play a possession on him or her?
|
||||
text: Would you like exert the played {ROHAN} Man to play a possession on him or her?
|
||||
cost: {
|
||||
type: exert
|
||||
select: memory(playedRohanMan)
|
||||
ignoreCostCheckFailure: true
|
||||
}
|
||||
effect: {
|
||||
type: costToEffect
|
||||
cost: {
|
||||
type: exert
|
||||
select: memory(playedRohanMan)
|
||||
ignoreCostCheckFailure: true
|
||||
}
|
||||
effect: {
|
||||
type: PlayCardFromHand
|
||||
select: choose(possession)
|
||||
on: memory(playedRohanMan)
|
||||
}
|
||||
type: PlayCardFromHand
|
||||
select: choose(possession)
|
||||
on: memory(playedRohanMan)
|
||||
}
|
||||
}
|
||||
{
|
||||
|
||||
@@ -199,19 +199,16 @@
|
||||
}
|
||||
true: {
|
||||
type: optional
|
||||
text: Discard the card?
|
||||
text: Discard the card to wound each minion in this skirmish?
|
||||
cost: {
|
||||
type: discardCardsFromDrawDeck
|
||||
select: memory(revealedCard)
|
||||
showAll: false
|
||||
shuffle: false
|
||||
}
|
||||
effect: {
|
||||
type: costToEffect
|
||||
cost: {
|
||||
type: discardCardsFromDrawDeck
|
||||
select: memory(revealedCard)
|
||||
showAll: false
|
||||
shuffle: false
|
||||
}
|
||||
effect: {
|
||||
type: wound
|
||||
select: all(minion,inSkirmish)
|
||||
}
|
||||
type: wound
|
||||
select: all(minion,inSkirmish)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -381,15 +381,12 @@
|
||||
}
|
||||
{
|
||||
type: optional
|
||||
text: Do you want to return it to hand?
|
||||
text: Do you want to add a burden to return {self} to hand?
|
||||
cost: {
|
||||
type: addBurdens
|
||||
}
|
||||
effect: {
|
||||
type: costToEffect
|
||||
cost: {
|
||||
type: addBurdens
|
||||
}
|
||||
effect: {
|
||||
type: putPlayedEventIntoHand
|
||||
}
|
||||
type: putPlayedEventIntoHand
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
@@ -1733,16 +1733,13 @@
|
||||
true: {
|
||||
type: optional
|
||||
text: Would you like to remove (3) to wound {woundedCharacter} again?
|
||||
cost: {
|
||||
type: removeTwilight
|
||||
amount: 3
|
||||
}
|
||||
effect: {
|
||||
type: costToEffect
|
||||
cost: {
|
||||
type: removeTwilight
|
||||
amount: 3
|
||||
}
|
||||
effect: {
|
||||
type: wound
|
||||
select: memory(woundedCharacter)
|
||||
}
|
||||
type: wound
|
||||
select: memory(woundedCharacter)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -349,17 +349,14 @@
|
||||
}
|
||||
true: {
|
||||
type: optional
|
||||
text: Would you like to discard 2 cards to return this event to your hand?
|
||||
text: Would you like to discard 2 cards to return {self} to your hand?
|
||||
cost: {
|
||||
type: discardFromHand
|
||||
forced: false
|
||||
count: 2
|
||||
}
|
||||
effect: {
|
||||
type: costToEffect
|
||||
cost: {
|
||||
type: discardFromHand
|
||||
forced: false
|
||||
count: 2
|
||||
}
|
||||
effect: {
|
||||
type: putPlayedEventIntoHand
|
||||
}
|
||||
type: putPlayedEventIntoHand
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -856,15 +856,12 @@
|
||||
effect: {
|
||||
type: optional
|
||||
text: Would you like to heal the Ring-beaer to add a burden?
|
||||
cost: {
|
||||
type: heal
|
||||
select: choose(ringBearer)
|
||||
}
|
||||
effect: {
|
||||
type: costToEffect
|
||||
cost: {
|
||||
type: heal
|
||||
select: choose(ringBearer)
|
||||
}
|
||||
effect: {
|
||||
type: addBurdens
|
||||
}
|
||||
type: addBurdens
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -963,18 +963,15 @@
|
||||
type: event
|
||||
cost: {
|
||||
type: optional
|
||||
text: Would you like to remove 2 burdens?
|
||||
text: Would you like to remove 2 burdens to add +4 more strength?
|
||||
cost: {
|
||||
type: removeBurdens
|
||||
amount: 2
|
||||
}
|
||||
effect: {
|
||||
type: costToEffect
|
||||
cost: {
|
||||
type: removeBurdens
|
||||
amount: 2
|
||||
}
|
||||
effect: {
|
||||
type: MemorizeInfo
|
||||
memory: removedBurdens
|
||||
info: yes
|
||||
}
|
||||
type: MemorizeInfo
|
||||
memory: removedBurdens
|
||||
info: yes
|
||||
}
|
||||
}
|
||||
effect: [
|
||||
|
||||
@@ -740,10 +740,8 @@
|
||||
}
|
||||
true: {
|
||||
type: optional
|
||||
text: Would you like to exert Théoden?
|
||||
effect: {
|
||||
type: costToEffect
|
||||
cost: {
|
||||
text: Would you like to exert Théoden to add +3 strength and damage +1?
|
||||
cost: {
|
||||
type: exert
|
||||
select: choose(name(Théoden))
|
||||
}
|
||||
@@ -752,7 +750,6 @@
|
||||
memory: exertedTheoden
|
||||
info: yes
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
{
|
||||
|
||||
@@ -671,31 +671,28 @@
|
||||
type: optional
|
||||
player: free people
|
||||
text: Would you like to add a burden or exert the Ring-bearer twice to discard Orkish Sneak?
|
||||
cost: {
|
||||
type: choice
|
||||
player: free people
|
||||
texts: [
|
||||
Add a burden
|
||||
Exert the Ring-bearer twice
|
||||
]
|
||||
effects: [
|
||||
{
|
||||
type: addBurdens
|
||||
}
|
||||
{
|
||||
type: exert
|
||||
select: choose(ringBearer)
|
||||
times: 2
|
||||
}
|
||||
]
|
||||
}
|
||||
effect: {
|
||||
type: costToEffect
|
||||
cost: {
|
||||
type: choice
|
||||
player: free people
|
||||
texts: [
|
||||
Add a burden
|
||||
Exert the Ring-bearer twice
|
||||
]
|
||||
effects: [
|
||||
{
|
||||
type: addBurdens
|
||||
}
|
||||
{
|
||||
type: exert
|
||||
select: choose(ringBearer)
|
||||
times: 2
|
||||
}
|
||||
]
|
||||
}
|
||||
effect: {
|
||||
type: discard
|
||||
player: free people
|
||||
select: self
|
||||
}
|
||||
type: discard
|
||||
player: free people
|
||||
select: self
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
@@ -25,15 +25,12 @@
|
||||
}
|
||||
{
|
||||
type: optional
|
||||
text: Would you like to remove (1) to place this event on the bottom of your draw deck?
|
||||
text: Would you like to remove (1) to place {self} on the bottom of your draw deck?
|
||||
cost: {
|
||||
type: removeTwilight
|
||||
}
|
||||
effect: {
|
||||
type: costToEffect
|
||||
cost: {
|
||||
type: removeTwilight
|
||||
}
|
||||
effect: {
|
||||
type: putPlayedEventOnBottomOfDrawDeck
|
||||
}
|
||||
type: putPlayedEventOnBottomOfDrawDeck
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
@@ -281,17 +281,14 @@
|
||||
{
|
||||
type: optional
|
||||
player: fp
|
||||
text: Would you like to add a burden to discard this minion?
|
||||
text: Would you like to add a burden to discard {self}?
|
||||
cost: {
|
||||
type: addBurdens
|
||||
amount: 1
|
||||
}
|
||||
effect: {
|
||||
type: costToEffect
|
||||
cost: {
|
||||
type: addBurdens
|
||||
amount: 1
|
||||
}
|
||||
effect: {
|
||||
type: discard
|
||||
select: self
|
||||
}
|
||||
type: discard
|
||||
select: self
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
@@ -1133,10 +1133,8 @@
|
||||
}
|
||||
{
|
||||
type: optional
|
||||
text: Would you like to discard 2 Orcs to take this event back into hand?
|
||||
effect: {
|
||||
type: costToEffect
|
||||
cost: {
|
||||
text: Would you like to discard 2 Orcs to take {self} back into hand?
|
||||
cost: {
|
||||
type: discard
|
||||
select: choose(orc)
|
||||
count: 2
|
||||
@@ -1144,7 +1142,6 @@
|
||||
effect: {
|
||||
type: putPlayedEventIntoHand
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -47,17 +47,14 @@
|
||||
type: Optional
|
||||
player: you
|
||||
text: Would you like to exert another Elf ally to discard another condition?
|
||||
cost: {
|
||||
type: exert
|
||||
select: choose(Elf,ally,not(memory(firstAlly)))
|
||||
}
|
||||
effect: {
|
||||
type: CostToEffect
|
||||
cost: {
|
||||
type: exert
|
||||
select: choose(Elf,ally,not(memory(firstAlly)))
|
||||
}
|
||||
effect: {
|
||||
type: Discard
|
||||
count: 1
|
||||
select: choose(condition)
|
||||
}
|
||||
type: Discard
|
||||
count: 1
|
||||
select: choose(condition)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -152,20 +152,17 @@
|
||||
{
|
||||
type: optional
|
||||
text: Would you like to exert Glorfindel to make a Nazgul he is skirmishing strength -X, where X is the twilight cost the the card revealed?
|
||||
cost: {
|
||||
type: exert
|
||||
select: self
|
||||
}
|
||||
effect: {
|
||||
type: costToEffect
|
||||
cost: {
|
||||
type: exert
|
||||
select: self
|
||||
}
|
||||
effect: {
|
||||
type: modifyStrength
|
||||
select: choose(nazgul,inSkirmishAgainst(self))
|
||||
amount: {
|
||||
type: twilightCostInMemory
|
||||
memory: revealedCard
|
||||
multiplier: -1
|
||||
}
|
||||
type: modifyStrength
|
||||
select: choose(nazgul,inSkirmishAgainst(self))
|
||||
amount: {
|
||||
type: twilightCostInMemory
|
||||
memory: revealedCard
|
||||
multiplier: -1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
twilight: 4
|
||||
type: Companion
|
||||
race: Wizard
|
||||
#keyword: damage+1
|
||||
strength: 7
|
||||
vitality: 4
|
||||
signet: Gandalf
|
||||
@@ -42,17 +41,17 @@
|
||||
type: optional
|
||||
player: shadowPlayer
|
||||
text: Would you like to discard 2 cards to draw 2 cards?
|
||||
cost: {
|
||||
type: discardFromHand
|
||||
player: shadow
|
||||
hand: shadow
|
||||
forced: false
|
||||
count: 2
|
||||
}
|
||||
effect: {
|
||||
type: costToEffect
|
||||
cost: {
|
||||
type: discardFromHand
|
||||
forced: false
|
||||
count: 2
|
||||
}
|
||||
effect: {
|
||||
type: drawCards
|
||||
count: 2
|
||||
}
|
||||
type: drawCards
|
||||
player: shadow
|
||||
count: 2
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,18 +30,15 @@
|
||||
type: optional
|
||||
player: shadow
|
||||
text: Would you like to discard 2 cards from hand to add a burden?
|
||||
cost: {
|
||||
type: discardFromHand
|
||||
hand: shadowPlayer
|
||||
player: shadowPlayer
|
||||
forced: false
|
||||
count: 2
|
||||
}
|
||||
effect: {
|
||||
type: costToEffect
|
||||
cost: {
|
||||
type: discardFromHand
|
||||
hand: shadowPlayer
|
||||
player: shadowPlayer
|
||||
forced: false
|
||||
count: 2
|
||||
}
|
||||
effect: {
|
||||
type: addBurdens
|
||||
}
|
||||
type: addBurdens
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,24 +29,21 @@
|
||||
}
|
||||
effect: {
|
||||
type: optional
|
||||
text: Would you like to pay this card's twilight cost to take it into hand?
|
||||
text: Would you like to pay {chosenAlly} twilight cost to take it into hand?
|
||||
cost: {
|
||||
type: addtwilight
|
||||
amount: {
|
||||
type: twilightCostInMemory
|
||||
memory: chosenAlly
|
||||
}
|
||||
}
|
||||
effect: {
|
||||
type: costToEffect
|
||||
cost: {
|
||||
type: addtwilight
|
||||
amount: {
|
||||
type: twilightCostInMemory
|
||||
memory: chosenAlly
|
||||
}
|
||||
}
|
||||
effect: {
|
||||
type: putcardsfromdeckintohand
|
||||
count: 1
|
||||
select: memory(chosenAlly)
|
||||
reveal: true
|
||||
shuffle: false
|
||||
showAll: false
|
||||
}
|
||||
type: putcardsfromdeckintohand
|
||||
count: 1
|
||||
select: memory(chosenAlly)
|
||||
reveal: true
|
||||
shuffle: false
|
||||
showAll: false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,18 +32,15 @@
|
||||
effect: {
|
||||
type: Optional
|
||||
text: Would you like to discard 2 cards to draw 2?
|
||||
cost: {
|
||||
type: DiscardFromHand
|
||||
forced: false
|
||||
select: choose(any)
|
||||
count: 2
|
||||
}
|
||||
effect: {
|
||||
type: CostToEffect
|
||||
cost: {
|
||||
type: DiscardFromHand
|
||||
forced: false
|
||||
select: choose(any)
|
||||
count: 2
|
||||
}
|
||||
effect: {
|
||||
type: DrawCards
|
||||
count: 2
|
||||
}
|
||||
type: DrawCards
|
||||
count: 2
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -70,6 +70,16 @@ public class CostToEffect implements EffectAppenderProducer {
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPlayabilityCheckedForEffect() {
|
||||
//This is done intentinally, even though one would think that you would want to
|
||||
// check the "cost" part of "CostToEffect". The reason for this is because CostToEffect
|
||||
// is frequently used as a wrapper in contexts where the Cost cannot actually be checked
|
||||
// ahead of time, such as when memory values are crucial to the execution (which of course
|
||||
// are not popuulated before the action itself is executed at time of checking).
|
||||
return false;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,31 +17,43 @@ import org.json.simple.JSONObject;
|
||||
public class Optional implements EffectAppenderProducer {
|
||||
@Override
|
||||
public EffectAppender createEffectAppender(boolean cost, JSONObject effectObject, CardGenerationEnvironment environment) throws InvalidCardDefinitionException {
|
||||
FieldUtils.validateAllowedFields(effectObject, "player", "text", "effect");
|
||||
FieldUtils.validateAllowedFields(effectObject, "player", "text", "requires", "cost", "effect");
|
||||
|
||||
final String player = FieldUtils.getString(effectObject.get("player"), "player", "you");
|
||||
final String text = FieldUtils.getString(effectObject.get("text"), "text");
|
||||
final JSONObject[] costArray = FieldUtils.getObjectArray(effectObject.get("cost"), "cost");
|
||||
final JSONObject[] effectArray = FieldUtils.getObjectArray(effectObject.get("effect"), "effect");
|
||||
final JSONObject[] requiresArray = FieldUtils.getObjectArray(effectObject.get("requires"), "requires");
|
||||
|
||||
if (text == null)
|
||||
throw new InvalidCardDefinitionException("There is a text required for optional effects");
|
||||
|
||||
final PlayerSource playerSource = PlayerResolver.resolvePlayer(player);
|
||||
final EffectAppender[] costAppenders = environment.getEffectAppenderFactory().getEffectAppenders(true, costArray, environment);
|
||||
final EffectAppender[] effectAppenders = environment.getEffectAppenderFactory().getEffectAppenders(cost, effectArray, environment);
|
||||
final Requirement[] requirements = environment.getRequirementFactory().getRequirements(requiresArray, environment);
|
||||
|
||||
return new DelayedAppender() {
|
||||
@Override
|
||||
protected Effect createEffect(boolean cost, CostToEffectAction action, ActionContext actionContext) {
|
||||
final String choosingPlayer = playerSource.getPlayer(actionContext);
|
||||
ActionContext delegate = new DelegateActionContext(actionContext,
|
||||
choosingPlayer, actionContext.getGame(), actionContext.getSource(),
|
||||
actionContext.getEffectResult(), actionContext.getEffect());
|
||||
|
||||
if(!isPlayableInFull(actionContext))
|
||||
return null;
|
||||
|
||||
SubAction subAction = new SubAction(action);
|
||||
|
||||
subAction.appendCost(
|
||||
new PlayoutDecisionEffect(choosingPlayer,
|
||||
new YesNoDecision(GameUtils.substituteText(text, actionContext)) {
|
||||
@Override
|
||||
protected void yes() {
|
||||
ActionContext delegate = new DelegateActionContext(actionContext,
|
||||
choosingPlayer, actionContext.getGame(), actionContext.getSource(),
|
||||
actionContext.getEffectResult(), actionContext.getEffect());
|
||||
for (EffectAppender costAppender : costAppenders)
|
||||
costAppender.appendEffect(true, subAction, actionContext);
|
||||
|
||||
for (EffectAppender effectAppender : effectAppenders) {
|
||||
effectAppender.appendEffect(cost, subAction, delegate);
|
||||
}
|
||||
@@ -56,8 +68,18 @@ public class Optional implements EffectAppenderProducer {
|
||||
ActionContext delegate = new DelegateActionContext(actionContext,
|
||||
choosingPlayer, actionContext.getGame(), actionContext.getSource(),
|
||||
actionContext.getEffectResult(), actionContext.getEffect());
|
||||
|
||||
if(!checkRequirements(delegate))
|
||||
return false;
|
||||
|
||||
for (EffectAppender costAppender : costAppenders) {
|
||||
if (!costAppender.isPlayableInFull(delegate))
|
||||
return false;
|
||||
}
|
||||
|
||||
for (EffectAppender effectAppender : effectAppenders) {
|
||||
if (!effectAppender.isPlayableInFull(delegate))
|
||||
if (effectAppender.isPlayabilityCheckedForEffect()
|
||||
&& !effectAppender.isPlayableInFull(delegate))
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -72,6 +94,14 @@ public class Optional implements EffectAppenderProducer {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean checkRequirements(ActionContext actionContext) {
|
||||
for (Requirement req : requirements) {
|
||||
if (!req.accepts(actionContext))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,7 +55,7 @@ public class ExertAtTest extends AbstractAtTest{
|
||||
// Pass on viewing revealed card
|
||||
playerDecided(P2, "");
|
||||
// Can't exert (already exhausted)
|
||||
playerDecided(P1, "0");
|
||||
//playerDecided(P1, "0");
|
||||
assertEquals(10, _game.getModifiersQuerying().getStrength(_game, cantea));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@ package com.gempukku.lotro.cards.official.set05;
|
||||
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;
|
||||
|
||||
@@ -18,7 +17,7 @@ public class Card_05_001_Tests
|
||||
return new GenericCardTestHelper(
|
||||
new HashMap<>()
|
||||
{{
|
||||
put("card", "5_1");
|
||||
put("rampager", "5_1");
|
||||
// put other cards in here as needed for the test case
|
||||
}},
|
||||
GenericCardTestHelper.FellowshipSites,
|
||||
@@ -47,7 +46,7 @@ public class Card_05_001_Tests
|
||||
|
||||
var scn = GetScenario();
|
||||
|
||||
var card = scn.GetFreepsCard("card");
|
||||
var card = scn.GetFreepsCard("rampager");
|
||||
|
||||
assertEquals("Dunlending Rampager", card.getBlueprint().getTitle());
|
||||
assertNull(card.getBlueprint().getSubtitle());
|
||||
@@ -62,18 +61,21 @@ public class Card_05_001_Tests
|
||||
assertEquals(3, card.getBlueprint().getSiteNumber());
|
||||
}
|
||||
|
||||
// Uncomment any @Test markers below once this is ready to be used
|
||||
//@Test
|
||||
public void DunlendingRampagerTest1() throws DecisionResultInvalidException, CardNotFoundException {
|
||||
@Test
|
||||
public void DunlendingRampagerDoesNotOfferChoiceWhenNotEnoughCardsInFreepsHand() throws DecisionResultInvalidException, CardNotFoundException {
|
||||
//Pre-game setup
|
||||
var scn = GetScenario();
|
||||
|
||||
var card = scn.GetFreepsCard("card");
|
||||
scn.FreepsMoveCardToHand(card);
|
||||
var rampager = scn.GetShadowCard("rampager");
|
||||
scn.ShadowMoveCardToHand(rampager);
|
||||
|
||||
scn.StartGame();
|
||||
scn.FreepsPlayCard(card);
|
||||
scn.FreepsPassCurrentPhaseAction();
|
||||
assertTrue(scn.ShadowPlayAvailable(rampager));
|
||||
scn.ShadowPlayCard(rampager);
|
||||
|
||||
assertEquals(1, scn.GetTwilight());
|
||||
assertEquals(Zone.SHADOW_CHARACTERS, rampager.getZone());
|
||||
assertEquals(0, scn.GetFreepsHandCount());
|
||||
assertFalse(scn.FreepsDecisionAvailable("Would you like to discard 2 cards from hand to discard Dunlending Rampager?"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
package com.gempukku.lotro.cards.official.set11;
|
||||
|
||||
import com.gempukku.lotro.cards.GenericCardTestHelper;
|
||||
import com.gempukku.lotro.common.CardType;
|
||||
import com.gempukku.lotro.common.Culture;
|
||||
import com.gempukku.lotro.common.Side;
|
||||
import com.gempukku.lotro.common.Timeword;
|
||||
import com.gempukku.lotro.common.*;
|
||||
import com.gempukku.lotro.filters.Filters;
|
||||
import com.gempukku.lotro.game.CardNotFoundException;
|
||||
import com.gempukku.lotro.logic.decisions.DecisionResultInvalidException;
|
||||
import com.gempukku.lotro.logic.modifiers.AddKeywordModifier;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.HashMap;
|
||||
@@ -20,8 +19,8 @@ public class Card_11_104_Tests
|
||||
return new GenericCardTestHelper(
|
||||
new HashMap<>()
|
||||
{{
|
||||
put("card", "11_104");
|
||||
// put other cards in here as needed for the test case
|
||||
put("death", "11_104");
|
||||
put("mouth", "12_73");
|
||||
}},
|
||||
GenericCardTestHelper.FellowshipSites,
|
||||
GenericCardTestHelper.FOTRFrodo,
|
||||
@@ -41,12 +40,13 @@ public class Card_11_104_Tests
|
||||
* Twilight Cost: 3
|
||||
* Type: Event
|
||||
* Subtype: Skirmish
|
||||
* Game Text: Wound a character skirmishing a [men] minion. If the fellowship is at a battleground site, you may remove (3) to wound that character again.
|
||||
* Game Text: Wound a character skirmishing a [men] minion.
|
||||
* If the fellowship is at a battleground site, you may remove (3) to wound that character again.
|
||||
*/
|
||||
|
||||
var scn = GetScenario();
|
||||
|
||||
var card = scn.GetFreepsCard("card");
|
||||
var card = scn.GetFreepsCard("death");
|
||||
|
||||
assertEquals("Whistling Death", card.getBlueprint().getTitle());
|
||||
assertNull(card.getBlueprint().getSubtitle());
|
||||
@@ -58,18 +58,117 @@ public class Card_11_104_Tests
|
||||
assertEquals(3, card.getBlueprint().getTwilightCost());
|
||||
}
|
||||
|
||||
// Uncomment any @Test markers below once this is ready to be used
|
||||
//@Test
|
||||
public void WhistlingDeathTest1() throws DecisionResultInvalidException, CardNotFoundException {
|
||||
@Test
|
||||
public void WhistlingDeathWoundsThenRemoves3MoreToWoundAgain() throws DecisionResultInvalidException, CardNotFoundException {
|
||||
//Pre-game setup
|
||||
var scn = GetScenario();
|
||||
|
||||
var card = scn.GetFreepsCard("card");
|
||||
scn.FreepsMoveCardToHand(card);
|
||||
var death = scn.GetShadowCard("death");
|
||||
var mouth = scn.GetShadowCard("mouth");
|
||||
scn.ShadowMoveCharToTable(mouth);
|
||||
scn.ShadowMoveCardToHand(death);
|
||||
|
||||
var frodo = scn.GetRingBearer();
|
||||
|
||||
//cheating to ensure site 2 qualifies
|
||||
scn.ApplyAdHocModifier(new AddKeywordModifier(null, Filters.siteNumber(2), null, Keyword.BATTLEGROUND));
|
||||
|
||||
scn.StartGame();
|
||||
scn.FreepsPlayCard(card);
|
||||
|
||||
assertEquals(3, scn.GetTwilight());
|
||||
scn.SetTwilight(7);
|
||||
scn.FreepsPassCurrentPhaseAction();
|
||||
scn.SkipToAssignments();
|
||||
scn.FreepsAssignToMinions(frodo, mouth);
|
||||
scn.FreepsResolveSkirmish(frodo);
|
||||
scn.FreepsPassCurrentPhaseAction();
|
||||
|
||||
assertEquals(0, scn.GetWoundsOn(frodo));
|
||||
assertEquals(10, scn.GetTwilight());
|
||||
assertTrue(scn.hasKeyword(scn.GetCurrentSite(), Keyword.BATTLEGROUND));
|
||||
assertTrue(scn.ShadowPlayAvailable(death));
|
||||
|
||||
scn.ShadowPlayCard(death);
|
||||
scn.FreepsDeclineOptionalTrigger(); //the one ring
|
||||
assertEquals(1, scn.GetWoundsOn(frodo));
|
||||
assertEquals(7, scn.GetTwilight());
|
||||
|
||||
assertTrue(scn.ShadowDecisionAvailable("Would you like to remove (3) to wound"));
|
||||
scn.ShadowChooseYes();
|
||||
scn.FreepsDeclineOptionalTrigger(); //the one ring
|
||||
assertEquals(2, scn.GetWoundsOn(frodo));
|
||||
assertEquals(4, scn.GetTwilight());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void WhistlingDeathSecondWoundIsNotOfferedAtNonBattleground() throws DecisionResultInvalidException, CardNotFoundException {
|
||||
//Pre-game setup
|
||||
var scn = GetScenario();
|
||||
|
||||
var death = scn.GetShadowCard("death");
|
||||
var mouth = scn.GetShadowCard("mouth");
|
||||
scn.ShadowMoveCharToTable(mouth);
|
||||
scn.ShadowMoveCardToHand(death);
|
||||
|
||||
var frodo = scn.GetRingBearer();
|
||||
|
||||
scn.StartGame();
|
||||
|
||||
scn.SetTwilight(7);
|
||||
scn.FreepsPassCurrentPhaseAction();
|
||||
scn.SkipToAssignments();
|
||||
scn.FreepsAssignToMinions(frodo, mouth);
|
||||
scn.FreepsResolveSkirmish(frodo);
|
||||
scn.FreepsPassCurrentPhaseAction();
|
||||
|
||||
assertEquals(0, scn.GetWoundsOn(frodo));
|
||||
assertEquals(10, scn.GetTwilight());
|
||||
assertFalse(scn.hasKeyword(scn.GetCurrentSite(), Keyword.BATTLEGROUND));
|
||||
assertTrue(scn.ShadowPlayAvailable(death));
|
||||
|
||||
scn.ShadowPlayCard(death);
|
||||
scn.FreepsDeclineOptionalTrigger(); //the one ring
|
||||
assertEquals(1, scn.GetWoundsOn(frodo));
|
||||
assertEquals(7, scn.GetTwilight());
|
||||
|
||||
assertFalse(scn.ShadowDecisionAvailable("Would you like to remove (3) to wound"));
|
||||
assertTrue(scn.FreepsAnyDecisionsAvailable());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void WhistlingDeathSecondWoundIsNotOfferedWhenLessThan3TwilightAvailable() throws DecisionResultInvalidException, CardNotFoundException {
|
||||
//Pre-game setup
|
||||
var scn = GetScenario();
|
||||
|
||||
var death = scn.GetShadowCard("death");
|
||||
var mouth = scn.GetShadowCard("mouth");
|
||||
scn.ShadowMoveCharToTable(mouth);
|
||||
scn.ShadowMoveCardToHand(death);
|
||||
|
||||
var frodo = scn.GetRingBearer();
|
||||
|
||||
//cheating to ensure site 2 qualifies
|
||||
scn.ApplyAdHocModifier(new AddKeywordModifier(null, Filters.siteNumber(2), null, Keyword.BATTLEGROUND));
|
||||
|
||||
scn.StartGame();
|
||||
|
||||
scn.SetTwilight(2);
|
||||
scn.FreepsPassCurrentPhaseAction();
|
||||
scn.SkipToAssignments();
|
||||
scn.FreepsAssignToMinions(frodo, mouth);
|
||||
scn.FreepsResolveSkirmish(frodo);
|
||||
scn.FreepsPassCurrentPhaseAction();
|
||||
|
||||
assertEquals(0, scn.GetWoundsOn(frodo));
|
||||
assertEquals(5, scn.GetTwilight());
|
||||
assertTrue(scn.hasKeyword(scn.GetCurrentSite(), Keyword.BATTLEGROUND));
|
||||
assertTrue(scn.ShadowPlayAvailable(death));
|
||||
|
||||
scn.ShadowPlayCard(death);
|
||||
scn.FreepsDeclineOptionalTrigger(); //the one ring
|
||||
assertEquals(1, scn.GetWoundsOn(frodo));
|
||||
assertEquals(2, scn.GetTwilight());
|
||||
|
||||
assertFalse(scn.ShadowDecisionAvailable("Would you like to remove (3) to wound"));
|
||||
assertTrue(scn.FreepsAnyDecisionsAvailable());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -137,7 +137,7 @@ public class Card_18_134_ErrataTests
|
||||
assertTrue(scn.FreepsPlayAvailable(onegoodturn));
|
||||
scn.FreepsPlayCard(onegoodturn);
|
||||
//This ensures that we have skipped over choosing a site and instead OGT has moved on to its other clause.
|
||||
assertTrue(scn.FreepsDecisionAvailable("Do you want to return"));
|
||||
assertTrue(scn.FreepsDecisionAvailable("Do you want to add a burden"));
|
||||
|
||||
assertNotEquals(scn.GetSite(3), freepsSite3);
|
||||
assertEquals(scn.GetSite(3), doorway);
|
||||
|
||||
Reference in New Issue
Block a user