diff --git a/gemp-lotr/gemp-lotr-async/src/main/web/cards/set40/set40-gandalf.json b/gemp-lotr/gemp-lotr-async/src/main/web/cards/set40/set40-gandalf.json index 96eefb4c1..f3494a824 100644 --- a/gemp-lotr/gemp-lotr-async/src/main/web/cards/set40/set40-gandalf.json +++ b/gemp-lotr/gemp-lotr-async/src/main/web/cards/set40/set40-gandalf.json @@ -752,8 +752,8 @@ "type": "canSpotBurdens", "amount": 5 }, - "yes": 2, - "no": 4 + "true": 2, + "false": 4 } } } 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 947808b47..b4f0872c9 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 @@ -636,8 +636,8 @@ "type": "canSpot", "filter": "dwarf" }, - "yes": 3, - "no": 2 + "true": 3, + "false": 2 } } } 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 36e144244..399d49bfe 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 @@ -78,6 +78,105 @@ } ] }, + "40_215": { + "title": "Enduring Evil", + "culture": "sauron", + "cost": 0, + "type": "event", + "keyword": "skirmish", + "effects": { + "type": "event", + "cost": { + "type": "chooseHowManyBurdensToSpot", + "memorize": "spottedBurdens" + }, + "effect": { + "type": "modifyStrength", + "filter": "choose(character,inSkirmishAgainst(culture(sauron),orc))", + "amount": { + "type": "multiply", + "multiplier": -1, + "source": { + "type": "fromMemory", + "memory": "spottedBurdens" + } + } + } + } + }, + "40_216": { + "title": "Ever Watchful", + "culture": "sauron", + "cost": 0, + "type": "condition", + "target": "companion,not(hasAttached(name(Ever Watchful)))", + "effects": [ + { + "type": "extraCost", + "cost": { + "type": "exert", + "filter": "choose(culture(sauron),tracker)" + } + }, + { + "type": "trigger", + "trigger": { + "type": "moves" + }, + "effect": { + "type": "choice", + "player": "fp", + "texts": [ + "Add (3)", + "Exert bearer of Ever Watchful" + ], + "effects": [ + { + "type": "addTwilight", + "amount": 3 + }, + { + "type": "exert", + "player": "fp", + "filter": "choose(bearer)" + } + ] + } + } + ] + }, + "40_217": { + "title": "Fires Raged Unchecked", + "culture": "sauron", + "cost": 1, + "type": "condition", + "keyword": "support area", + "effects": [ + { + "type": "modifier", + "modifier": { + "type": "modifySiteNumber", + "filter": "culture(sauron),orc", + "amount": { + "type": "forEachThreat", + "multiplier": -1 + } + } + }, + { + "type": "modifier", + "modifier": { + "type": "modifyStrength", + "condition": { + "type": "canSpotThreats", + "amount": 3 + }, + "filter": "culture(sauron),orc,not(roaming)", + "amount": 1 + } + } + ] + }, "40_221": { "title": "It Will Destroy Them All", "culture": "sauron", 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 0e8104e68..0d523df8d 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 @@ -59,6 +59,7 @@ public class EffectAppenderFactory { effectAppenderProducers.put("costtoeffect", new CostToEffect()); effectAppenderProducers.put("spot", new Spot()); effectAppenderProducers.put("choosehowmanytospot", new ChooseHowManyToSpot()); + effectAppenderProducers.put("choosehowmanyburdenstospot", new ChooseHowManyBurdensToSpot()); effectAppenderProducers.put("reordertopcardsofdrawdeck", new ReorderTopCardsOfDrawDeck()); effectAppenderProducers.put("cantbeassignedtoskirmish", new CantBeAssignedToSkirmish()); effectAppenderProducers.put("preventable", new PreventableAppenderProducer()); diff --git a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/effect/appender/ChooseHowManyBurdensToSpot.java b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/effect/appender/ChooseHowManyBurdensToSpot.java new file mode 100644 index 000000000..c0e3d1515 --- /dev/null +++ b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/effect/appender/ChooseHowManyBurdensToSpot.java @@ -0,0 +1,38 @@ +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.timing.Effect; +import org.json.simple.JSONObject; + +public class ChooseHowManyBurdensToSpot 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"); + + return new DelayedAppender() { + @Override + protected Effect createEffect(boolean cost, CostToEffectAction action, ActionContext actionContext) { + final int count = actionContext.getGame().getGameState().getBurdens(); + return new PlayoutDecisionEffect(actionContext.getPerformingPlayer(), + new IntegerAwaitingDecision(1, "Choose how many burdens to spot", 0, count, count) { + @Override + public void decisionMade(String result) throws DecisionResultInvalidException { + final int spotCount = getValidatedResult(result); + actionContext.setValueToMemory(memorize, String.valueOf(spotCount)); + } + }); + } + }; + } +} diff --git a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/effect/appender/resolver/ValueResolver.java b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/effect/appender/resolver/ValueResolver.java index b291a3073..7df5380f0 100644 --- a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/effect/appender/resolver/ValueResolver.java +++ b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/effect/appender/resolver/ValueResolver.java @@ -50,6 +50,7 @@ public class ValueResolver { JSONObject object = (JSONObject) value; final String type = FieldUtils.getString(object.get("type"), "type"); if (type.equalsIgnoreCase("condition")) { + FieldUtils.validateAllowedFields(object, "condition", "true", "false"); final JSONObject[] conditionArray = FieldUtils.getObjectArray(object.get("condition"), "condition"); final Requirement[] conditions = environment.getRequirementFactory().getRequirements(conditionArray, environment); int trueValue = FieldUtils.getInteger(object.get("true"), "true"); @@ -62,16 +63,21 @@ public class ValueResolver { return trueValue; }; } else if (type.equalsIgnoreCase("forRegionNumber")) { + FieldUtils.validateAllowedFields(object); return (actionContext) -> (Evaluator) (game, cardAffected) -> GameUtils.getRegion(actionContext.getGame()); } else if (type.equalsIgnoreCase("forEachInMemory")) { + FieldUtils.validateAllowedFields(object, "memory"); final String memory = FieldUtils.getString(object.get("memory"), "memory"); return (actionContext) -> { final int count = actionContext.getCardsFromMemory(memory).size(); return new ConstantEvaluator(count); }; } else if (type.equalsIgnoreCase("forEachThreat")) { - return actionContext -> new ForEachThreatEvaluator(); + FieldUtils.validateAllowedFields(object, "multiplier"); + final int multiplier = FieldUtils.getInteger(object.get("multiplier"), "multiplier", 1); + return actionContext -> new MultiplyEvaluator(multiplier, new ForEachThreatEvaluator()); } else if (type.equalsIgnoreCase("forEachWound")) { + FieldUtils.validateAllowedFields(object, "filter"); final String filter = FieldUtils.getString(object.get("filter"), "filter"); final FilterableSource filterableSource = environment.getFilterFactory().generateFilter(filter, environment); return (actionContext) -> (Evaluator) (game, cardAffected) -> { @@ -82,6 +88,7 @@ public class ValueResolver { return wounds; }; } else if (type.equalsIgnoreCase("forEachKeywordOnCardInMemory")) { + FieldUtils.validateAllowedFields(object, "memory", "keyword"); final String memory = FieldUtils.getString(object.get("memory"), "memory"); final Keyword keyword = FieldUtils.getEnum(Keyword.class, object.get("keyword"), "keyword"); return (actionContext) -> { @@ -90,10 +97,12 @@ public class ValueResolver { return new ConstantEvaluator(count); }; } else if (type.equalsIgnoreCase("limit")) { + FieldUtils.validateAllowedFields(object, "value", "amount"); final int limit = FieldUtils.getInteger(object.get("value"), "value"); ValueSource valueSource = resolveEvaluator(object.get("amount"), 0, environment); return (actionContext) -> new LimitEvaluator(valueSource.getEvaluator(actionContext), limit); } else if (type.equalsIgnoreCase("countStacked")) { + FieldUtils.validateAllowedFields(object, "on", "filter"); final String on = FieldUtils.getString(object.get("on"), "on"); final String filter = FieldUtils.getString(object.get("filter"), "filter", "any"); @@ -105,31 +114,37 @@ public class ValueResolver { return new CountStackedEvaluator(on1, filterableSource.getFilterable(actionContext)); }; } else if (type.equalsIgnoreCase("forEachYouCanSpot")) { + FieldUtils.validateAllowedFields(object, "filter", "over", "limit"); final String filter = FieldUtils.getString(object.get("filter"), "filter"); final int over = FieldUtils.getInteger(object.get("over"), "over", 0); final int limit = FieldUtils.getInteger(object.get("limit"), "limit", Integer.MAX_VALUE); final FilterableSource filterableSource = environment.getFilterFactory().generateFilter(filter, environment); return actionContext -> new CountSpottableEvaluator(over, limit, filterableSource.getFilterable(actionContext)); } else if (type.equalsIgnoreCase("forEachInHand")) { + FieldUtils.validateAllowedFields(object, "filter"); final String filter = FieldUtils.getString(object.get("filter"), "filter"); final FilterableSource filterableSource = environment.getFilterFactory().generateFilter(filter, environment); return actionContext -> (Evaluator) (game, cardAffected) -> Filters.filter(game.getGameState().getHand(actionContext.getPerformingPlayer()), game, filterableSource.getFilterable(actionContext)).size(); } else if (type.equalsIgnoreCase("fromMemory")) { + FieldUtils.validateAllowedFields(object, "memory"); String memory = FieldUtils.getString(object.get("memory"), "memory"); return (actionContext) -> { int value1 = Integer.parseInt(actionContext.getValueFromMemory(memory)); return new ConstantEvaluator(value1); }; } else if (type.equalsIgnoreCase("multiply")) { + FieldUtils.validateAllowedFields(object, "multiplier", "source"); final int multiplier = FieldUtils.getInteger(object.get("multiplier"), "multiplier"); final ValueSource valueSource = ValueResolver.resolveEvaluator(object.get("source"), 0, environment); return (actionContext) -> new MultiplyEvaluator(multiplier, valueSource.getEvaluator(actionContext)); } else if (type.equalsIgnoreCase("forEachVitality")) { + FieldUtils.validateAllowedFields(object, "over"); final int over = FieldUtils.getInteger(object.get("over"), "over", 0); return (actionContext) -> (game, cardAffected) -> Math.max(0, game.getModifiersQuerying().getVitality(game, cardAffected) - over); } else if (type.equalsIgnoreCase("subtract")) { + FieldUtils.validateAllowedFields(object, "firstNumber", "secondNumber"); final ValueSource firstNumber = ValueResolver.resolveEvaluator(object.get("firstNumber"), 0, environment); final ValueSource secondNumber = ValueResolver.resolveEvaluator(object.get("secondNumber"), 0, environment); return actionContext -> (Evaluator) (game, cardAffected) -> { @@ -138,6 +153,7 @@ public class ValueResolver { return first - second; }; } else if (type.equals("twilightCostInMemory")) { + FieldUtils.validateAllowedFields(object, "memory"); final String memory = FieldUtils.getString(object.get("memory"), "memory"); return actionContext -> (Evaluator) (game, cardAffected) -> { int total = 0; diff --git a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/effect/requirement/CanSpotThreats.java b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/effect/requirement/CanSpotThreats.java new file mode 100644 index 000000000..e45316f62 --- /dev/null +++ b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/effect/requirement/CanSpotThreats.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.timing.PlayConditions; +import org.json.simple.JSONObject; + +public class CanSpotThreats implements RequirementProducer { + @Override + public Requirement getPlayRequirement(JSONObject object, CardGenerationEnvironment environment) throws InvalidCardDefinitionException { + FieldUtils.validateAllowedFields(object, "amount"); + + final int count = FieldUtils.getInteger(object.get("amount"), "amount", 1); + return (actionContext) -> PlayConditions.canSpotThreat(actionContext.getGame(), count); + } +} 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 61efa039d..11b126d12 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 @@ -16,6 +16,7 @@ public class RequirementFactory { requirementProducers.put("not", new NotRequirementProducer()); requirementProducers.put("canspot", new CanSpot()); requirementProducers.put("canspotburdens", new CanSpotBurdens()); + requirementProducers.put("canspotthreats", new CanSpotThreats()); requirementProducers.put("controlssite", new ControlsSite()); requirementProducers.put("twilightpoollessthan", new TwilightPoolLessThan()); requirementProducers.put("location", new Location());