From 644f8448db874809967b487361d76bbf02c87c52 Mon Sep 17 00:00:00 2001 From: "marcin.sciesinski" Date: Sun, 1 Sep 2019 02:03:40 -0700 Subject: [PATCH] Added all the cards --- .../main/web/cards/set40/set40-isengard.json | 57 ++++++++++ .../src/main/web/cards/set40/set40-moria.json | 45 ++++++++ .../main/web/cards/set40/set40-sauron.json | 28 +++++ .../src/main/web/cards/set40/set40-shire.json | 106 ++++++++++++++++++ .../src/main/resources/set40-rarity.txt | 9 +- .../cards/build/DelegateActionContext.java | 82 ++++++++++++++ .../field/effect/EffectAppenderFactory.java | 3 + .../appender/ChooseAndRemoveTwilight.java | 50 +++++++++ .../effect/appender/ConditionEffect.java | 4 +- .../effect/appender/PlayCardFromDiscard.java | 9 +- .../appender/PreventableAppenderProducer.java | 10 +- .../field/effect/appender/RemoveTwilight.java | 36 ++++++ .../effect/appender/StackCardsFromPlay.java | 56 +++++++++ .../appender/resolver/CardResolver.java | 16 ++- .../field/effect/filter/FilterFactory.java | 14 +++ 15 files changed, 511 insertions(+), 14 deletions(-) create mode 100644 gemp-lotr/gemp-lotr-async/src/main/web/cards/set40/set40-isengard.json create mode 100644 gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/DelegateActionContext.java create mode 100644 gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/effect/appender/ChooseAndRemoveTwilight.java create mode 100644 gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/effect/appender/RemoveTwilight.java create mode 100644 gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/effect/appender/StackCardsFromPlay.java diff --git a/gemp-lotr/gemp-lotr-async/src/main/web/cards/set40/set40-isengard.json b/gemp-lotr/gemp-lotr-async/src/main/web/cards/set40/set40-isengard.json new file mode 100644 index 000000000..865710d86 --- /dev/null +++ b/gemp-lotr/gemp-lotr-async/src/main/web/cards/set40/set40-isengard.json @@ -0,0 +1,57 @@ +{ + "40_314": { + "title": "Brute Force", + "side": "shadow", + "culture": "isengard", + "cost": 1, + "type": "event", + "keyword": "maneuver", + "effects": { + "type": "event", + "cost": [ + { + "type": "exert", + "filter": "choose(uruk-hai)" + }, + { + "type": "chooseAndRemoveTwilight", + "memorize": "twilightRemoved" + } + ], + "effect": { + "type": "discard", + "filter": "choose(not(weapon),side(free people),possession,maxTwilight(memory(twilightRemoved)))" + } + } + }, + "40_315": { + "title": "*Uruk Taskmaster", + "side": "shadow", + "culture": "isengard", + "cost": 4, + "type": "minion", + "race": "uruk-hai", + "strength": 9, + "vitality": 3, + "site": 5, + "effects": { + "type": "activated", + "phase": "skirmish", + "cost": [ + { + "type": "exert", + "filter": "self" + }, + { + "type": "removeTwilight", + "amount": 3 + } + ], + "effect": { + "type": "addKeyword", + "filter": "choose(uruk-hai)", + "keyword": "damage+1" + } + } + } +} \ No newline at end of file diff --git a/gemp-lotr/gemp-lotr-async/src/main/web/cards/set40/set40-moria.json b/gemp-lotr/gemp-lotr-async/src/main/web/cards/set40/set40-moria.json index 23d5b35f3..1e58fdf93 100644 --- a/gemp-lotr/gemp-lotr-async/src/main/web/cards/set40/set40-moria.json +++ b/gemp-lotr/gemp-lotr-async/src/main/web/cards/set40/set40-moria.json @@ -60,5 +60,50 @@ "filter": "memory(unboundCompanion)" } } + }, + "40_316": { + "title": "Deep Places of the World", + "side": "shadow", + "culture": "moria", + "cost": 1, + "type": "condition", + "keyword": "support area", + "effects": { + "type": "activated", + "phase": [ + "shadow", + "maneuver" + ], + "cost": { + "type": "removeTwilight", + "amount": 4 + }, + "effect": { + "type": "playCardFromDiscard", + "filter": "choose(culture(moria),goblin)", + "removedTwilight": 4 + } + } + }, + "40_317": { + "title": "Scurrying Away", + "side": "shadow", + "culture": "moria", + "cost": 2, + "type": "condition", + "keyword": "support area", + "effects": { + "type": "activated", + "phase": "skirmish", + "cost": { + "type": "removeTwilight", + "amount": 3 + }, + "effect": { + "type": "stackCards", + "filter": "choose(culture(moria),goblin)", + "where": "choose(culture(moria),support area,condition)" + } + } } } \ No newline at end of file diff --git a/gemp-lotr/gemp-lotr-async/src/main/web/cards/set40/set40-sauron.json b/gemp-lotr/gemp-lotr-async/src/main/web/cards/set40/set40-sauron.json index 560fc44d3..8990c17a0 100644 --- a/gemp-lotr/gemp-lotr-async/src/main/web/cards/set40/set40-sauron.json +++ b/gemp-lotr/gemp-lotr-async/src/main/web/cards/set40/set40-sauron.json @@ -133,5 +133,33 @@ } } ] + }, + "40_318": { + "title": "*Orc Flanker", + "side": "shadow", + "culture": "sauron", + "cost": 3, + "type": "minion", + "race": "orc", + "strength": 8, + "vitality": 3, + "site": 6, + "keyword": "tracker", + "effects": { + "type": "activated", + "phase": "skirmish", + "condition": { + "type": "canSpot", + "filter": "not(self),tracker" + }, + "cost": { + "type": "removeTwilight", + "amount": 4 + }, + "effect": { + "type": "exert", + "filter": "choose(companion,notAssignedToSkirmish)" + } + } } } \ No newline at end of file diff --git a/gemp-lotr/gemp-lotr-async/src/main/web/cards/set40/set40-shire.json b/gemp-lotr/gemp-lotr-async/src/main/web/cards/set40/set40-shire.json index 990a0485c..da6006025 100644 --- a/gemp-lotr/gemp-lotr-async/src/main/web/cards/set40/set40-shire.json +++ b/gemp-lotr/gemp-lotr-async/src/main/web/cards/set40/set40-shire.json @@ -239,5 +239,111 @@ } } ] + }, + "40_319": { + "title": "*A Hobbit's Tale", + "side": "free people", + "culture": "shire", + "cost": 2, + "type": "condition", + "target": "companion,ring bound,hobbit", + "keyword": "tale", + "effects": [ + { + "type": "activated", + "phase": "maneuver", + "condition": [ + { + "type": "location", + "filter": "siteNumber(1-4)" + }, + { + "type": "canSpot", + "count": 2, + "filter": "hobbit,companion" + } + ], + "cost": { + "type": "discard", + "filter": "self" + }, + "effect": { + "type": "modifyStrength", + "until": "start(regroup)", + "filter": "all(hobbit,companion)", + "amount": 2 + } + }, + { + "type": "activated", + "phase": "maneuver", + "condition": { + "type": "location", + "filter": "siteNumber(1-4)" + }, + "cost": [ + { + "type": "memorize", + "filter": "hasAttached(self)", + "memory": "bearer" + }, + { + "type": "discard", + "filter": "self" + } + ], + "effect": [ + { + "type": "heal", + "filter": "memory(bearer)" + }, + { + "type": "removeBurdens" + } + ] + } + ] + }, + "40_320": { + "title": "Get Out of the Shire", + "side": "free people", + "culture": "shire", + "cost": 1, + "type": "event", + "keyword": "skirmish", + "effects": { + "type": "event", + "effect": { + "type": "choice", + "texts": [ + "Prevent Hobbit from being overwhelmed unless that Hobbit's strength is tripled", + "Cancel skirmish involving a Hobbit" + ], + "effects": [ + { + "type": "cantBeOverwhelmedMultiplier", + "filter": "choose(hobbit)" + }, + { + "type": "conditional", + "condition": [ + { + "type": "canSpot", + "count": 2, + "filter": "hobbit,companion" + }, + { + "type": "location", + "filter": "siteNumber(1-4)" + } + ], + "effect": { + "type": "cancelSkirmish", + "filter": "hobbit" + } + } + ] + } + } } } \ No newline at end of file diff --git a/gemp-lotr/gemp-lotr-cards/src/main/resources/set40-rarity.txt b/gemp-lotr/gemp-lotr-cards/src/main/resources/set40-rarity.txt index 6f8d34899..767e77108 100644 --- a/gemp-lotr/gemp-lotr-cards/src/main/resources/set40-rarity.txt +++ b/gemp-lotr/gemp-lotr-cards/src/main/resources/set40-rarity.txt @@ -310,4 +310,11 @@ 40S310 40S311 40S312 -40S313 \ No newline at end of file +40S313 +40S314 +40S315 +40S316 +40S317 +40S318 +40S319 +40S320 \ No newline at end of file diff --git a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/DelegateActionContext.java b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/DelegateActionContext.java new file mode 100644 index 000000000..e68d33446 --- /dev/null +++ b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/DelegateActionContext.java @@ -0,0 +1,82 @@ +package com.gempukku.lotro.cards.build; + +import com.gempukku.lotro.game.PhysicalCard; +import com.gempukku.lotro.game.state.LotroGame; +import com.gempukku.lotro.logic.timing.Effect; +import com.gempukku.lotro.logic.timing.EffectResult; + +import java.util.Collection; + +public class DelegateActionContext implements ActionContext { + private ActionContext delegate; + + private String performingPlayer; + private LotroGame game; + private PhysicalCard source; + private EffectResult effectResult; + private Effect effect; + + public DelegateActionContext(ActionContext delegate, String performingPlayer, LotroGame game, PhysicalCard source, EffectResult effectResult, Effect effect) { + this.delegate = delegate; + this.performingPlayer = performingPlayer; + this.game = game; + this.source = source; + this.effectResult = effectResult; + this.effect = effect; + } + + @Override + public void setValueToMemory(String memory, String value) { + delegate.setValueToMemory(memory, value); + } + + @Override + public String getValueFromMemory(String memory) { + return delegate.getValueFromMemory(memory); + } + + @Override + public void setCardMemory(String memory, PhysicalCard card) { + delegate.setCardMemory(memory, card); + } + + @Override + public void setCardMemory(String memory, Collection cards) { + delegate.setCardMemory(memory, cards); + } + + @Override + public Collection getCardsFromMemory(String memory) { + return delegate.getCardsFromMemory(memory); + } + + @Override + public PhysicalCard getCardFromMemory(String memory) { + return delegate.getCardFromMemory(memory); + } + + @Override + public String getPerformingPlayer() { + return performingPlayer; + } + + @Override + public LotroGame getGame() { + return game; + } + + @Override + public PhysicalCard getSource() { + return source; + } + + @Override + public EffectResult getEffectResult() { + return effectResult; + } + + @Override + public Effect getEffect() { + return effect; + } +} diff --git a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/effect/EffectAppenderFactory.java b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/effect/EffectAppenderFactory.java index 0029039a8..51cdc78ae 100644 --- a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/effect/EffectAppenderFactory.java +++ b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/effect/EffectAppenderFactory.java @@ -60,6 +60,9 @@ public class EffectAppenderFactory { effectAppenderProducers.put("play", new PlayCardFromHand()); effectAppenderProducers.put("cancelskirmish", new CancelSkirmish()); effectAppenderProducers.put("discardfromhand", new CancelSkirmish()); + effectAppenderProducers.put("chooseandremovetwilight", new ChooseAndRemoveTwilight()); + effectAppenderProducers.put("removetwilight", new RemoveTwilight()); + effectAppenderProducers.put("stackcards", new StackCardsFromPlay()); } public EffectAppender getEffectAppender(JSONObject effectObject, CardGenerationEnvironment environment) throws InvalidCardDefinitionException { diff --git a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/effect/appender/ChooseAndRemoveTwilight.java b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/effect/appender/ChooseAndRemoveTwilight.java new file mode 100644 index 000000000..1ebb3d651 --- /dev/null +++ b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/effect/appender/ChooseAndRemoveTwilight.java @@ -0,0 +1,50 @@ +package com.gempukku.lotro.cards.build.field.effect.appender; + +import com.gempukku.lotro.cards.build.ActionContext; +import com.gempukku.lotro.cards.build.CardGenerationEnvironment; +import com.gempukku.lotro.cards.build.InvalidCardDefinitionException; +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.logic.actions.CostToEffectAction; +import com.gempukku.lotro.logic.decisions.DecisionResultInvalidException; +import com.gempukku.lotro.logic.decisions.IntegerAwaitingDecision; +import com.gempukku.lotro.logic.effects.PlayoutDecisionEffect; +import com.gempukku.lotro.logic.effects.RemoveTwilightEffect; +import com.gempukku.lotro.logic.timing.Effect; +import org.json.simple.JSONObject; + +public class ChooseAndRemoveTwilight implements EffectAppenderProducer { + @Override + public EffectAppender createEffectAppender(JSONObject effectObject, CardGenerationEnvironment environment) throws InvalidCardDefinitionException { + FieldUtils.validateAllowedFields(effectObject, "memorize"); + + final String memorize = FieldUtils.getString(effectObject.get("memorize"), "memorize"); + + MultiEffectAppender result = new MultiEffectAppender(); + result.addEffectAppender( + new DelayedAppender() { + @Override + protected Effect createEffect(boolean cost, CostToEffectAction action, ActionContext actionContext) { + return new PlayoutDecisionEffect(actionContext.getPerformingPlayer(), + new IntegerAwaitingDecision(1, "How much twilight do you wish to remove", + 0, actionContext.getGame().getGameState().getTwilightPool()) { + @Override + public void decisionMade(String result) throws DecisionResultInvalidException { + actionContext.setValueToMemory(memorize, String.valueOf(getValidatedResult(result))); + } + }); + } + }); + result.addEffectAppender( + new DelayedAppender() { + @Override + protected Effect createEffect(boolean cost, CostToEffectAction action, ActionContext actionContext) { + int twilight = Integer.parseInt(actionContext.getValueFromMemory(memorize)); + return new RemoveTwilightEffect(twilight); + } + }); + + return result; + } +} diff --git a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/effect/appender/ConditionEffect.java b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/effect/appender/ConditionEffect.java index 0a3471e13..f94264f52 100644 --- a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/effect/appender/ConditionEffect.java +++ b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/effect/appender/ConditionEffect.java @@ -54,7 +54,9 @@ public class ConditionEffect implements EffectAppenderProducer { // TODO, maybe check the requirements, and if met, check if the effect is playable? @Override public boolean isPlayableInFull(ActionContext actionContext) { - return true; + if (!checkConditions(actionContext)) + return false; + return effectAppender.isPlayableInFull(actionContext); } }; } 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 d4fbcfafc..8b262c9fc 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 @@ -21,9 +21,10 @@ import org.json.simple.JSONObject; public class PlayCardFromDiscard implements EffectAppenderProducer { @Override public EffectAppender createEffectAppender(JSONObject effectObject, CardGenerationEnvironment environment) throws InvalidCardDefinitionException { - FieldUtils.validateAllowedFields(effectObject, "filter"); + FieldUtils.validateAllowedFields(effectObject, "filter", "removedTwilight"); final String filter = FieldUtils.getString(effectObject.get("filter"), "filter"); + final int removedTwilight = FieldUtils.getInteger(effectObject.get("removedTwilight"), "removedTwilight", 0); MultiEffectAppender result = new MultiEffectAppender(); result.setPlayabilityCheckedForEffect(true); @@ -31,6 +32,7 @@ public class PlayCardFromDiscard implements EffectAppenderProducer { result.addEffectAppender( CardResolver.resolveCardsInDiscard(filter, (actionContext) -> Filters.playable(actionContext.getGame()), + (actionContext) -> Filters.playable(actionContext.getGame(), removedTwilight, 0, false, false), new ConstantEvaluator(1), "_temp", "you", "Choose card to play", environment)); result.addEffectAppender( new DelayedAppender() { @@ -46,6 +48,11 @@ public class PlayCardFromDiscard implements EffectAppenderProducer { final LotroGame game = actionContext.getGame(); return !game.getModifiersQuerying().hasFlagActive(game, ModifierFlag.CANT_PLAY_FROM_DISCARD_OR_DECK); } + + @Override + public boolean isPlayabilityCheckedForEffect() { + return true; + } }); return result; diff --git a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/effect/appender/PreventableAppenderProducer.java b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/effect/appender/PreventableAppenderProducer.java index e5dd50553..ed34aaddd 100644 --- a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/effect/appender/PreventableAppenderProducer.java +++ b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/effect/appender/PreventableAppenderProducer.java @@ -1,9 +1,6 @@ package com.gempukku.lotro.cards.build.field.effect.appender; -import com.gempukku.lotro.cards.build.ActionContext; -import com.gempukku.lotro.cards.build.CardGenerationEnvironment; -import com.gempukku.lotro.cards.build.InvalidCardDefinitionException; -import com.gempukku.lotro.cards.build.PlayerSource; +import com.gempukku.lotro.cards.build.*; 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; @@ -44,7 +41,10 @@ public class PreventableAppenderProducer implements EffectAppenderProducer { new YesNoDecision(text) { @Override protected void yes() { - costAppender.appendEffect(false, subAction, actionContext); + DelegateActionContext delegate = new DelegateActionContext(actionContext, + preventingPlayer, actionContext.getGame(), actionContext.getSource(), actionContext.getEffectResult(), + actionContext.getEffect()); + costAppender.appendEffect(false, subAction, delegate); } @Override diff --git a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/effect/appender/RemoveTwilight.java b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/effect/appender/RemoveTwilight.java new file mode 100644 index 000000000..2bce67774 --- /dev/null +++ b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/effect/appender/RemoveTwilight.java @@ -0,0 +1,36 @@ +package com.gempukku.lotro.cards.build.field.effect.appender; + +import com.gempukku.lotro.cards.build.ActionContext; +import com.gempukku.lotro.cards.build.CardGenerationEnvironment; +import com.gempukku.lotro.cards.build.InvalidCardDefinitionException; +import com.gempukku.lotro.cards.build.ValueSource; +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.cards.build.field.effect.appender.resolver.ValueResolver; +import com.gempukku.lotro.logic.actions.CostToEffectAction; +import com.gempukku.lotro.logic.effects.RemoveTwilightEffect; +import com.gempukku.lotro.logic.timing.Effect; +import org.json.simple.JSONObject; + +public class RemoveTwilight implements EffectAppenderProducer { + @Override + public EffectAppender createEffectAppender(JSONObject effectObject, CardGenerationEnvironment environment) throws InvalidCardDefinitionException { + FieldUtils.validateAllowedFields(effectObject, "amount"); + final ValueSource amount = ValueResolver.resolveEvaluator(effectObject.get("amount"), 1, environment); + + return new DelayedAppender() { + @Override + protected Effect createEffect(boolean cost, CostToEffectAction action, ActionContext actionContext) { + int value = amount.getEvaluator(actionContext).evaluateExpression(actionContext.getGame(), null); + return new RemoveTwilightEffect(value); + } + + @Override + public boolean isPlayableInFull(ActionContext actionContext) { + int value = amount.getEvaluator(actionContext).evaluateExpression(actionContext.getGame(), null); + return actionContext.getGame().getGameState().getTwilightPool() >= value; + } + }; + } +} diff --git a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/effect/appender/StackCardsFromPlay.java b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/effect/appender/StackCardsFromPlay.java new file mode 100644 index 000000000..28e03d596 --- /dev/null +++ b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/effect/appender/StackCardsFromPlay.java @@ -0,0 +1,56 @@ +package com.gempukku.lotro.cards.build.field.effect.appender; + +import com.gempukku.lotro.cards.build.ActionContext; +import com.gempukku.lotro.cards.build.CardGenerationEnvironment; +import com.gempukku.lotro.cards.build.InvalidCardDefinitionException; +import com.gempukku.lotro.cards.build.ValueSource; +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.cards.build.field.effect.appender.resolver.CardResolver; +import com.gempukku.lotro.cards.build.field.effect.appender.resolver.ValueResolver; +import com.gempukku.lotro.game.PhysicalCard; +import com.gempukku.lotro.logic.actions.CostToEffectAction; +import com.gempukku.lotro.logic.effects.StackCardFromPlayEffect; +import com.gempukku.lotro.logic.timing.Effect; +import org.json.simple.JSONObject; + +import java.util.Collection; +import java.util.LinkedList; +import java.util.List; + +public class StackCardsFromPlay implements EffectAppenderProducer { + @Override + public EffectAppender createEffectAppender(JSONObject effectObject, CardGenerationEnvironment environment) throws InvalidCardDefinitionException { + FieldUtils.validateAllowedFields(effectObject, "filter", "where", "count"); + + final String filter = FieldUtils.getString(effectObject.get("filter"), "filter", "choose(any)"); + final String where = FieldUtils.getString(effectObject.get("where"), "where"); + final ValueSource valueSource = ValueResolver.resolveEvaluator(effectObject.get("count"), 1, environment); + + MultiEffectAppender result = new MultiEffectAppender(); + + result.addEffectAppender( + CardResolver.resolveCard(where, "_temp1", "you", "Choose card to stack on", environment)); + result.addEffectAppender( + CardResolver.resolveCards(filter, valueSource, "_temp2", "you", "Choose cards to stack", environment)); + result.addEffectAppender( + new DelayedAppender() { + @Override + protected List createEffects(boolean cost, CostToEffectAction action, ActionContext actionContext) { + final PhysicalCard card = actionContext.getCardFromMemory("_temp1"); + final Collection cardsInHand = actionContext.getCardsFromMemory("_temp2"); + + List result = new LinkedList<>(); + for (PhysicalCard physicalCard : cardsInHand) { + result.add(new StackCardFromPlayEffect(physicalCard, card)); + } + + return result; + } + }); + + return result; + } + +} diff --git a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/effect/appender/resolver/CardResolver.java b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/effect/appender/resolver/CardResolver.java index 396b16ec1..80e95f38f 100644 --- a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/effect/appender/resolver/CardResolver.java +++ b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/effect/appender/resolver/CardResolver.java @@ -160,6 +160,10 @@ public class CardResolver { } public static EffectAppender resolveCardsInDiscard(String type, FilterableSource additionalFilter, ValueSource countSource, String memory, String choicePlayer, String choiceText, CardGenerationEnvironment environment) throws InvalidCardDefinitionException { + return resolveCardsInDiscard(type, additionalFilter, additionalFilter, countSource, memory, choicePlayer, choiceText, environment); + } + + public static EffectAppender resolveCardsInDiscard(String type, FilterableSource choiceFilter, FilterableSource playabilityFilter, ValueSource countSource, String memory, String choicePlayer, String choiceText, CardGenerationEnvironment environment) throws InvalidCardDefinitionException { if (type.startsWith("memory(") && type.endsWith(")")) { final PlayerSource playerSource = PlayerResolver.resolvePlayer(choicePlayer, environment); @@ -167,11 +171,11 @@ public class CardResolver { return new DelayedAppender() { @Override public boolean isPlayableInFull(ActionContext actionContext) { - if (additionalFilter != null) { + if (playabilityFilter != null) { int min = countSource.getMinimum(null); String choicePlayerId = playerSource.getPlayer(actionContext); final Collection cardsFromMemory = actionContext.getCardsFromMemory(sourceMemory); - Filterable filter = additionalFilter.getFilterable(actionContext); + Filterable filter = playabilityFilter.getFilterable(actionContext); final LotroGame game = actionContext.getGame(); return Filters.filter(game.getGameState().getDiscard(choicePlayerId), game, filter, Filters.in(cardsFromMemory)).size() >= min; } @@ -199,8 +203,8 @@ public class CardResolver { final Filterable filterable = filterableSource.getFilterable(actionContext); String choicePlayerId = playerSource.getPlayer(actionContext); Filterable additionalFilterable = Filters.any; - if (additionalFilter != null) - additionalFilterable = additionalFilter.getFilterable(actionContext); + if (playabilityFilter != null) + additionalFilterable = playabilityFilter.getFilterable(actionContext); final LotroGame game = actionContext.getGame(); return Filters.filter(game.getGameState().getDiscard(choicePlayerId), game, filterable, additionalFilterable).size() >= min; } @@ -212,8 +216,8 @@ public class CardResolver { final Filterable filterable = filterableSource.getFilterable(actionContext); String choicePlayerId = playerSource.getPlayer(actionContext); Filterable additionalFilterable = Filters.any; - if (additionalFilter != null) - additionalFilterable = additionalFilter.getFilterable(actionContext); + if (choiceFilter != null) + additionalFilterable = choiceFilter.getFilterable(actionContext); return new ChooseCardsFromDiscardEffect(choicePlayerId, min, max, filterable, additionalFilterable) { @Override protected void cardsSelected(LotroGame game, Collection cards) { 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 ab49ef0cb..73a8fae52 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 @@ -148,13 +148,27 @@ public class FilterFactory { }); parameterFilters.put("memory", (parameter, filterFactory) -> (actionContext) -> Filters.in(actionContext.getCardsFromMemory(parameter))); + parameterFilters.put("maxTwilight", + (parameter, filterFactory) -> (actionContext) -> { + if (parameter.startsWith("memory(") && parameter.endsWith(")")) { + String memory = parameter.substring(parameter.indexOf("(") + 1, parameter.lastIndexOf(")")); + final int value = Integer.parseInt(actionContext.getValueFromMemory(memory)); + return Filters.maxPrintedTwilightCost(value); + } else { + int value = Integer.parseInt(parameter); + return Filters.maxPrintedTwilightCost(value); + } + }); } private void appendFilter(Filterable value) { final String filterName = value.toString().toLowerCase().replace("_", " "); + final String optionalFilterName = value.toString().toLowerCase().replace("_", "-"); if (simpleFilters.containsKey(filterName)) throw new RuntimeException("Duplicate filter name: " + filterName); simpleFilters.put(filterName, (actionContext) -> value); + if (!optionalFilterName.equals(filterName)) + simpleFilters.put(optionalFilterName, (actionContext -> value)); } public FilterableSource generateFilter(String value) throws InvalidCardDefinitionException {