From 294efcd80c5b826605ef26627f052a611dd1301a Mon Sep 17 00:00:00 2001 From: Christian 'ketura' McCarty Date: Wed, 17 Aug 2022 18:56:38 -0500 Subject: [PATCH] Overhauled FilterFactory - rearranged all simple and parameterized behavior filters to be alphabetized - altered parameterized filters to all be case insensitive - altered parameter interpretation to ignore spaces - altered memory handling to be case insensitive - improved Side and Signet interpretation to be case insensitive and to be flexible in what it accepts --- .../java/com/gempukku/lotro/common/Side.java | 7 +- .../com/gempukku/lotro/common/Signet.java | 11 + .../cards/build/DefaultActionContext.java | 8 +- .../cards/build/DelegateActionContext.java | 12 +- .../field/effect/filter/FilterFactory.java | 613 +++++++++--------- .../lotro/logic/effects/AddTokenEffect.java | 5 +- 6 files changed, 351 insertions(+), 305 deletions(-) diff --git a/gemp-lotr/gemp-lotr-common/src/main/java/com/gempukku/lotro/common/Side.java b/gemp-lotr/gemp-lotr-common/src/main/java/com/gempukku/lotro/common/Side.java index 06da5c0c6..4dad7781f 100644 --- a/gemp-lotr/gemp-lotr-common/src/main/java/com/gempukku/lotro/common/Side.java +++ b/gemp-lotr/gemp-lotr-common/src/main/java/com/gempukku/lotro/common/Side.java @@ -6,12 +6,13 @@ public enum Side implements Filterable { public static Side Parse(String value) { value = value .toLowerCase() - .replace("_", " ") - .replace("-", " "); + .replace(" ", "") + .replace("_", "") + .replace("-", ""); if(value.contains("shadow")) return SHADOW; - if(value.contains("freeps") || value.contains("free people") || value.contains("free peoples")) + if(value.contains("freeps") || value.contains("free") || value.contains("people")) return FREE_PEOPLE; return null; diff --git a/gemp-lotr/gemp-lotr-common/src/main/java/com/gempukku/lotro/common/Signet.java b/gemp-lotr/gemp-lotr-common/src/main/java/com/gempukku/lotro/common/Signet.java index 12cb84ba5..1f6f858e9 100644 --- a/gemp-lotr/gemp-lotr-common/src/main/java/com/gempukku/lotro/common/Signet.java +++ b/gemp-lotr/gemp-lotr-common/src/main/java/com/gempukku/lotro/common/Signet.java @@ -12,4 +12,15 @@ public enum Signet implements Filterable { public String toString() { return displayText; } + + public static Signet findSignet(String name) { + String nameCaps = name.toUpperCase().replace(" ", ""); + String nameLower = name.toLowerCase(); + + for (Signet signet : values()) { + if (signet.toString().toLowerCase().equals(nameLower) || signet.toString().equals(nameCaps)) + return signet; + } + return null; + } } diff --git a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/DefaultActionContext.java b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/DefaultActionContext.java index 809f37f37..2af8d38e9 100644 --- a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/DefaultActionContext.java +++ b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/DefaultActionContext.java @@ -31,11 +31,12 @@ public class DefaultActionContext implements ActionContext { @Override public void setValueToMemory(String memory, String value) { - valueMemory.put(memory, value); + valueMemory.put(memory.toLowerCase(), value); } @Override public String getValueFromMemory(String memory) { + memory = memory.toLowerCase(); final String result = valueMemory.get(memory); if (result == null) throw new IllegalArgumentException("Memory not found - " + memory); @@ -44,6 +45,7 @@ public class DefaultActionContext implements ActionContext { @Override public void setCardMemory(String memory, PhysicalCard card) { + memory = memory.toLowerCase(); cardMemory.removeAll(memory); if (card != null) cardMemory.put(memory, card); @@ -51,17 +53,19 @@ public class DefaultActionContext implements ActionContext { @Override public void setCardMemory(String memory, Collection cards) { + memory = memory.toLowerCase(); cardMemory.removeAll(memory); cardMemory.putAll(memory, cards); } @Override public Collection getCardsFromMemory(String memory) { - return cardMemory.get(memory); + return cardMemory.get(memory.toLowerCase()); } @Override public PhysicalCard getCardFromMemory(String memory) { + memory = memory.toLowerCase(); final Collection physicalCards = cardMemory.get(memory); if (physicalCards.size() == 0) return null; 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 index b20602f2a..fb379354a 100644 --- 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 @@ -27,32 +27,32 @@ public class DelegateActionContext implements ActionContext { @Override public void setValueToMemory(String memory, String value) { - delegate.setValueToMemory(memory, value); + delegate.setValueToMemory(memory.toLowerCase(), value); } @Override public String getValueFromMemory(String memory) { - return delegate.getValueFromMemory(memory); + return delegate.getValueFromMemory(memory.toLowerCase()); } @Override public void setCardMemory(String memory, PhysicalCard card) { - delegate.setCardMemory(memory, card); + delegate.setCardMemory(memory.toLowerCase(), card); } @Override public void setCardMemory(String memory, Collection cards) { - delegate.setCardMemory(memory, cards); + delegate.setCardMemory(memory.toLowerCase(), cards); } @Override public Collection getCardsFromMemory(String memory) { - return delegate.getCardsFromMemory(memory); + return delegate.getCardsFromMemory(memory.toLowerCase()); } @Override public PhysicalCard getCardFromMemory(String memory) { - return delegate.getCardFromMemory(memory); + return delegate.getCardFromMemory(memory.toLowerCase()); } @Override 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 2561fbae5..067d31733 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 @@ -29,277 +29,83 @@ public class FilterFactory { for (Race value : Race.values()) appendFilter(value); - simpleFilters.put("ring bearer", (actionContext) -> Filters.ringBearer); - simpleFilters.put("ringbearer", (actionContext) -> Filters.ringBearer); - simpleFilters.put("ring-bearer", (actionContext) -> Filters.ringBearer); - simpleFilters.put("any", (actionContext) -> Filters.any); - simpleFilters.put("self", ActionContext::getSource); + simpleFilters.put("allyincurrentregion", (actionContext) -> Filters.isAllyInCurrentRegion()); simpleFilters.put("another", (actionContext) -> Filters.not(actionContext.getSource())); - simpleFilters.put("your", (actionContext) -> Filters.owner(actionContext.getPerformingPlayer())); - simpleFilters.put("unique", (actionContext) -> Filters.unique); - simpleFilters.put("bearer", (actionContext -> Filters.hasAttached(actionContext.getSource()))); - simpleFilters.put("character", (actionContext) -> Filters.character); - simpleFilters.put("mounted", (actionContext) -> Filters.mounted); - simpleFilters.put("weapon", (actionContext) -> Filters.weapon); - simpleFilters.put("item", (actionContext) -> Filters.item); - simpleFilters.put("wounded", (actionContext) -> Filters.wounded); - simpleFilters.put("unwounded", (actionContext) -> Filters.unwounded); - simpleFilters.put("exhausted", (actionContext) -> Filters.exhausted); - simpleFilters.put("inskirmish", (actionContext) -> Filters.inSkirmish); - simpleFilters.put("infierceskirmish", (actionContext) -> Filters.inFierceSkirmish); - simpleFilters.put("inplay", (actionContext) -> Filters.inPlay); - simpleFilters.put("notassignedtoskirmish", - (actionContext) -> Filters.notAssignedToSkirmish); - simpleFilters.put("skirmishloser", - (actionContext) -> { - final CharacterLostSkirmishResult lostSkirmish = (CharacterLostSkirmishResult) actionContext.getEffectResult(); - return lostSkirmish.getLoser(); - }); - simpleFilters.put("ring bound", - (actionContext) -> Filters.ringBoundCompanion); - simpleFilters.put("ringbound", - (actionContext) -> Filters.ringBoundCompanion); - simpleFilters.put("ring-bound", - (actionContext) -> Filters.ringBoundCompanion); - simpleFilters.put("unbound", - (actionContext) -> Filters.unboundCompanion); + simpleFilters.put("any", (actionContext) -> Filters.any); simpleFilters.put("attachedtoinsameregion", actionContext -> { final PhysicalCard attachedTo = actionContext.getSource().getAttachedTo(); return Filters.region(GameUtils.getRegion(attachedTo.getSiteNumber())); }); - simpleFilters.put("insameregion", - actionContext -> Filters.region(GameUtils.getRegion(actionContext.getSource().getSiteNumber()))); + simpleFilters.put("bearer", (actionContext -> Filters.hasAttached(actionContext.getSource()))); + simpleFilters.put("character", (actionContext) -> Filters.character); + simpleFilters.put("controlledsite", + (actionContext -> Filters.siteControlled(actionContext.getPerformingPlayer()))); simpleFilters.put("currentsite", (actionContext) -> Filters.currentSite); simpleFilters.put("currentsitenumber", (actionContext -> Filters.siteNumber(actionContext.getGame().getGameState().getCurrentSiteNumber()))); - simpleFilters.put("siteincurrentregion", - (actionContext) -> Filters.siteInCurrentRegion); - simpleFilters.put("sitehassitenumber", - (actionContext) -> Filters.siteHasSiteNumber); + simpleFilters.put("exhausted", (actionContext) -> Filters.exhausted); simpleFilters.put("idinstored", (actionContext -> - new Filter() { - @Override - public boolean accepts(LotroGame game, PhysicalCard physicalCard) { - final String whileInZoneData = (String) actionContext.getSource().getWhileInZoneData(); - if (whileInZoneData == null) - return false; - for (String cardId : whileInZoneData.split(",")) { - if (cardId.equals(String.valueOf(physicalCard.getCardId()))) - return true; - } - + (Filter) (game, physicalCard) -> { + final String whileInZoneData = (String) actionContext.getSource().getWhileInZoneData(); + if (whileInZoneData == null) return false; + for (String cardId : whileInZoneData.split(",")) { + if (cardId.equals(String.valueOf(physicalCard.getCardId()))) + return true; } - })); - simpleFilters.put("controlledsite", - (actionContext -> Filters.siteControlled(actionContext.getPerformingPlayer()))); - parameterFilters.put("culture", (parameter, environment) -> { - final Culture culture = Culture.valueOf(parameter.toUpperCase()); - if (culture == null) - throw new InvalidCardDefinitionException("Unable to find culture for: " + parameter); - - return (actionContext) -> culture; - }); - parameterFilters.put("signet", (parameter, environment) -> { - final Signet signet = Signet.valueOf(parameter.toUpperCase()); - if (signet == null) - throw new InvalidCardDefinitionException("Unable to find culture for: " + parameter); - - return (actionContext) -> signet; - }); - parameterFilters.put("cultureFromMemory", ((parameter, environment) -> actionContext -> { - Set cultures = new HashSet<>(); - for (PhysicalCard physicalCard : actionContext.getCardsFromMemory(parameter)) { - cultures.add(physicalCard.getBlueprint().getCulture()); - } - return Filters.or(cultures.toArray(new Culture[0])); - })); - parameterFilters.put("side", (parameter, environment) -> { - final Side side = Side.Parse(parameter); - if (side == null) - throw new InvalidCardDefinitionException("Unable to find side for: " + parameter); - - return (actionContext) -> side; - }); - parameterFilters.put("hasToken", (parameter, environment) -> { - final Culture culture = Culture.valueOf(parameter.toUpperCase()); - if (culture == null) - throw new InvalidCardDefinitionException("Unable to find culture for: " + parameter); - final Token token = Token.findTokenForCulture(culture); - if (token == null) - throw new InvalidCardDefinitionException("Unable to find token for culture: " + parameter); - - return (actionContext) -> Filters.hasToken(token); - }); - parameterFilters.put("hasTokenCount", (parameter, environment) -> { - String[] parameterSplit = parameter.split(",", 2); - int count = Integer.parseInt(parameterSplit[0]); - final Culture culture = Culture.valueOf(parameterSplit[1].toUpperCase()); - if (culture == null) - throw new InvalidCardDefinitionException("Unable to find culture for: " + parameter); - final Token token = Token.findTokenForCulture(culture); - if (token == null) - throw new InvalidCardDefinitionException("Unable to find token for culture: " + parameter); - - return (actionContext) -> Filters.hasToken(token, count); - }); - parameterFilters.put("hasAttached", - (parameter, environment) -> { - final FilterableSource filterableSource = environment.getFilterFactory().generateFilter(parameter, environment); - return (actionContext) -> Filters.hasAttached(filterableSource.getFilterable(actionContext)); - }); - parameterFilters.put("hasAttachedCount", - (parameter, environment) -> { - String[] parameterSplit = parameter.split(",", 2); - int count = Integer.parseInt(parameterSplit[0]); - final FilterableSource filterableSource = environment.getFilterFactory().generateFilter(parameterSplit[1], environment); - return (actionContext) -> Filters.hasAttached(count, filterableSource.getFilterable(actionContext)); - }); - parameterFilters.put("hasStacked", - (parameter, environment) -> { - final FilterableSource filterableSource = environment.getFilterFactory().generateFilter(parameter, environment); - return (actionContext) -> Filters.hasStacked(filterableSource.getFilterable(actionContext)); - }); - parameterFilters.put("hasStackedCount", - (parameter, environment) -> { - String[] parameterSplit = parameter.split(",", 2); - int count = Integer.parseInt(parameterSplit[0]); - final FilterableSource filterableSource = environment.getFilterFactory().generateFilter(parameterSplit[1], environment); - return (actionContext) -> Filters.hasStacked(count, filterableSource.getFilterable(actionContext)); - }); - parameterFilters.put("attachedTo", - (parameter, environment) -> { - final FilterableSource filterableSource = environment.getFilterFactory().generateFilter(parameter, environment); - return (actionContext) -> Filters.attachedTo(filterableSource.getFilterable(actionContext)); - }); - parameterFilters.put("name", - (parameter, environment) -> (actionContext) -> (Filter) - (game, physicalCard) -> physicalCard.getBlueprint().getTitle().equalsIgnoreCase(parameter)); - parameterFilters.put("title",parameterFilters.get("name")); - parameterFilters.put("nameInStackedOn", - (parameter, environment) -> { - final FilterableSource filterableSource = environment.getFilterFactory().generateFilter(parameter, environment); - return actionContext -> { - final Filterable sourceFilterable = filterableSource.getFilterable(actionContext); - return (Filter) (game, physicalCard) -> { - for (PhysicalCard cardWithStack : Filters.filterActive(game, sourceFilterable)) { - for (PhysicalCard stackedCard : game.getGameState().getStackedCards(cardWithStack)) { - if (stackedCard.getBlueprint().getTitle().equals(physicalCard.getBlueprint().getTitle())) - return true; - } - } return false; - }; - }; + })); + simpleFilters.put("infierceskirmish", (actionContext) -> Filters.inFierceSkirmish); + simpleFilters.put("inplay", (actionContext) -> Filters.inPlay); + simpleFilters.put("insameregion", + actionContext -> Filters.region(GameUtils.getRegion(actionContext.getSource().getSiteNumber()))); + simpleFilters.put("inskirmish", (actionContext) -> Filters.inSkirmish); + simpleFilters.put("item", (actionContext) -> Filters.item); + simpleFilters.put("mounted", (actionContext) -> Filters.mounted); + simpleFilters.put("notassignedtoskirmish", + (actionContext) -> Filters.notAssignedToSkirmish); + simpleFilters.put("ringbearer", (actionContext) -> Filters.ringBearer); + simpleFilters.put("ring-bearer", (actionContext) -> Filters.ringBearer); + simpleFilters.put("ringbound", + (actionContext) -> Filters.ringBoundCompanion); + simpleFilters.put("ring-bound", + (actionContext) -> Filters.ringBoundCompanion); + simpleFilters.put("self", ActionContext::getSource); + simpleFilters.put("sitehassitenumber", + (actionContext) -> Filters.siteHasSiteNumber); + simpleFilters.put("siteincurrentregion", + (actionContext) -> Filters.siteInCurrentRegion); + simpleFilters.put("skirmishloser", + (actionContext) -> { + final CharacterLostSkirmishResult lostSkirmish = (CharacterLostSkirmishResult) actionContext.getEffectResult(); + return lostSkirmish.getLoser(); }); - parameterFilters.put("inSkirmishAgainst", - (parameter, environment) -> { - final FilterableSource filterableSource = environment.getFilterFactory().generateFilter(parameter, environment); - return (actionContext) -> Filters.inSkirmishAgainst(filterableSource.getFilterable(actionContext)); - }); - parameterFilters.put("assignedToSkirmish", - (parameter, environment) -> { - final FilterableSource filterableSource = environment.getFilterFactory().generateFilter(parameter, environment); - return (actionContext) -> Filters.assignedToSkirmishAgainst(filterableSource.getFilterable(actionContext)); - }); - parameterFilters.put("resistanceLessThan", - (parameter, environment) -> { - int amount = Integer.parseInt(parameter); - return (actionContext) -> Filters.maxResistance(amount - 1); - }); - parameterFilters.put("resistanceMoreThan", - (parameter, environment) -> { - int amount = Integer.parseInt(parameter); - return (actionContext) -> Filters.minResistance(amount + 1); - }); - parameterFilters.put("strengthLessThan", - (parameter, environment) -> { - int amount = Integer.parseInt(parameter); - return (actionContext) -> Filters.lessStrengthThan(amount); - }); - parameterFilters.put("strengthMoreThan", - (parameter, environment) -> { - int amount = Integer.parseInt(parameter); - return (actionContext) -> Filters.moreStrengthThan(amount); - }); - parameterFilters.put("vitalityMoreThan", - (parameter, environment) -> { - int amount = Integer.parseInt(parameter); - return (actionContext) -> Filters.moreVitalityThan(amount); - }); - parameterFilters.put("not", - (parameter, environment) -> { - final FilterableSource filterableSource = environment.getFilterFactory().generateFilter(parameter, environment); - return (actionContext) -> Filters.not(filterableSource.getFilterable(actionContext)); - }); - parameterFilters.put("allyHome", + simpleFilters.put("unbound", + (actionContext) -> Filters.unboundCompanion); + simpleFilters.put("unique", (actionContext) -> Filters.unique); + simpleFilters.put("unwounded", (actionContext) -> Filters.unwounded); + simpleFilters.put("weapon", (actionContext) -> Filters.weapon); + simpleFilters.put("wounded", (actionContext) -> Filters.wounded); + simpleFilters.put("your", (actionContext) -> Filters.owner(actionContext.getPerformingPlayer())); + + parameterFilters.put("allyhome", (parameter, environment) -> { final String[] parameterSplit = parameter.split(","); - final SitesBlock sitesBlock = Enum.valueOf(SitesBlock.class, parameterSplit[0].toUpperCase().replace('_', ' ')); + final SitesBlock sitesBlock = SitesBlock.findBlock(parameterSplit[0]); int number = Integer.parseInt(parameterSplit[1]); return (actionContext) -> Filters.isAllyHome(number, sitesBlock); }); - parameterFilters.put("allyInRegion", + parameterFilters.put("allyinregion", (parameter, environment) -> { final String[] parameterSplit = parameter.split(","); final SitesBlock sitesBlock = Enum.valueOf(SitesBlock.class, parameterSplit[0].toUpperCase().replace('_', ' ')); int number = Integer.parseInt(parameterSplit[1]); return (actionContext) -> Filters.isAllyInRegion(number, sitesBlock); }); - parameterFilters.put("allyInCurrentRegion", - (parameter, environment) -> (actionContext) -> Filters.isAllyInCurrentRegion()); - parameterFilters.put("siteBlock", - (parameter, environment) -> { - final SitesBlock sitesBlock = Enum.valueOf(SitesBlock.class, parameter.toUpperCase().replace(' ', '_')); - return (actionContext) -> Filters.siteBlock(sitesBlock); - }); - parameterFilters.put("siteNumber", - (parameter, environment) -> { - int min, max; - if (parameter.contains("-")) { - final String[] split = parameter.split("-", 2); - min = Integer.parseInt(split[0]); - max = Integer.parseInt(split[1]); - } else { - min = max = Integer.parseInt(parameter); - } - - return (actionContext) -> Filters.siteNumberBetweenInclusive(min, max); - }); - parameterFilters.put("regionNumber", - (parameter, environment) -> { - int min, max; - if (parameter.contains("-")) { - final String[] split = parameter.split("-", 2); - min = Integer.parseInt(split[0]); - max = Integer.parseInt(split[1]); - } else { - min = max = Integer.parseInt(parameter); - } - - if(min < 0 || max > 3 || max < min) - throw new InvalidCardDefinitionException("Region number definition is invalid: " + parameter); - - return (actionContext) -> Filters.regionNumberBetweenInclusive(min, max); - }); - parameterFilters.put("or", - (parameter, environment) -> { - final String[] filters = splitIntoFilters(parameter); - FilterableSource[] filterables = new FilterableSource[filters.length]; - for (int i = 0; i < filters.length; i++) - filterables[i] = environment.getFilterFactory().generateFilter(filters[i], environment); - return (actionContext) -> { - Filterable[] filters1 = new Filterable[filterables.length]; - for (int i = 0; i < filterables.length; i++) - filters1[i] = filterables[i].getFilterable(actionContext); - - return Filters.or(filters1); - }; - }); parameterFilters.put("and", (parameter, environment) -> { final String[] filters = splitIntoFilters(parameter); @@ -314,9 +120,116 @@ public class FilterFactory { return Filters.and(filters1); }; }); - parameterFilters.put("memory", - (parameter, environment) -> (actionContext) -> Filters.in(actionContext.getCardsFromMemory(parameter))); - parameterFilters.put("maxTwilight", + parameterFilters.put("assignabletoskirmishagainst", + (parameter, environment) -> { + final FilterableSource againstFilterableSource = environment.getFilterFactory().generateFilter(parameter, environment); + return actionContext -> { + final Side side = GameUtils.getSide(actionContext.getGame(), actionContext.getPerformingPlayer()); + return Filters.assignableToSkirmishAgainst(side, againstFilterableSource.getFilterable(actionContext)); + }; + }); + parameterFilters.put("assignedtoskirmish", + (parameter, environment) -> { + final FilterableSource filterableSource = environment.getFilterFactory().generateFilter(parameter, environment); + return (actionContext) -> Filters.assignedToSkirmishAgainst(filterableSource.getFilterable(actionContext)); + }); + parameterFilters.put("attachedto", + (parameter, environment) -> { + final FilterableSource filterableSource = environment.getFilterFactory().generateFilter(parameter, environment); + return (actionContext) -> Filters.attachedTo(filterableSource.getFilterable(actionContext)); + }); + parameterFilters.put("culture", (parameter, environment) -> { + final Culture culture = Culture.findCulture(parameter); + if (culture == null) + throw new InvalidCardDefinitionException("Unable to find culture for: " + parameter); + + return (actionContext) -> culture; + }); + parameterFilters.put("culturefrommemory", ((parameter, environment) -> actionContext -> { + Set cultures = new HashSet<>(); + for (PhysicalCard physicalCard : actionContext.getCardsFromMemory(parameter)) { + cultures.add(physicalCard.getBlueprint().getCulture()); + } + return Filters.or(cultures.toArray(new Culture[0])); + })); + parameterFilters.put("hasattached", + (parameter, environment) -> { + final FilterableSource filterableSource = environment.getFilterFactory().generateFilter(parameter, environment); + return (actionContext) -> Filters.hasAttached(filterableSource.getFilterable(actionContext)); + }); + parameterFilters.put("hasattachedcount", + (parameter, environment) -> { + String[] parameterSplit = parameter.split(",", 2); + int count = Integer.parseInt(parameterSplit[0]); + final FilterableSource filterableSource = environment.getFilterFactory().generateFilter(parameterSplit[1], environment); + return (actionContext) -> Filters.hasAttached(count, filterableSource.getFilterable(actionContext)); + }); + parameterFilters.put("hasstacked", + (parameter, environment) -> { + final FilterableSource filterableSource = environment.getFilterFactory().generateFilter(parameter, environment); + return (actionContext) -> Filters.hasStacked(filterableSource.getFilterable(actionContext)); + }); + parameterFilters.put("hasstackedcount", + (parameter, environment) -> { + String[] parameterSplit = parameter.split(",", 2); + int count = Integer.parseInt(parameterSplit[0]); + final FilterableSource filterableSource = environment.getFilterFactory().generateFilter(parameterSplit[1], environment); + return (actionContext) -> Filters.hasStacked(count, filterableSource.getFilterable(actionContext)); + }); + parameterFilters.put("hasanytokens", (parameter, environment) -> { + int count = Integer.parseInt(parameter != null ? parameter : "1"); + return (actionContext) -> Filters.hasAnyCultureTokens(count); + }); + parameterFilters.put("hastoken", (parameter, environment) -> { + final Culture culture = Culture.findCulture(parameter); + if (culture == null) + throw new InvalidCardDefinitionException("Unable to find culture for: " + parameter); + final Token token = Token.findTokenForCulture(culture); + if (token == null) + throw new InvalidCardDefinitionException("Unable to find token for culture: " + parameter); + + return (actionContext) -> Filters.hasToken(token); + }); + parameterFilters.put("hastokencount", (parameter, environment) -> { + String[] parameterSplit = parameter.split(",", 2); + int count = Integer.parseInt(parameterSplit[0]); + final Culture culture = Culture.findCulture(parameterSplit[1]); + if (culture == null) + throw new InvalidCardDefinitionException("Unable to find culture for: " + parameter); + final Token token = Token.findTokenForCulture(culture); + if (token == null) + throw new InvalidCardDefinitionException("Unable to find token for culture: " + parameter); + + return (actionContext) -> Filters.hasToken(token, count); + }); + parameterFilters.put("inskirmishagainst", + (parameter, environment) -> { + final FilterableSource filterableSource = environment.getFilterFactory().generateFilter(parameter, environment); + return (actionContext) -> Filters.inSkirmishAgainst(filterableSource.getFilterable(actionContext)); + }); + parameterFilters.put("loweststrength", + (parameter, environment) -> { + final FilterableSource filterableSource = environment.getFilterFactory().generateFilter(parameter, environment); + return actionContext -> { + final Filterable sourceFilterable = filterableSource.getFilterable(actionContext); + return Filters.and( + sourceFilterable, Filters.strengthEqual( + new SingleMemoryEvaluator( + new Evaluator() { + @Override + public int evaluateExpression(LotroGame game, PhysicalCard cardAffected) { + int minStrength = Integer.MAX_VALUE; + for (PhysicalCard card : Filters.filterActive(game, sourceFilterable)) + minStrength = Math.min(minStrength, game.getModifiersQuerying().getStrength(game, card)); + return minStrength; + } + } + ) + ) + ); + }; + }); + parameterFilters.put("maxtwilight", (parameter, environment) -> { if (parameter.startsWith("memory(") && parameter.endsWith(")")) { String memory = parameter.substring(parameter.indexOf("(") + 1, parameter.lastIndexOf(")")); @@ -337,7 +250,9 @@ public class FilterFactory { }; } }); - parameterFilters.put("minTwilight", + parameterFilters.put("memory", + (parameter, environment) -> (actionContext) -> Filters.in(actionContext.getCardsFromMemory(parameter))); + parameterFilters.put("mintwilight", (parameter, environment) -> { if (parameter.startsWith("memory(") && parameter.endsWith(")")) { String memory = parameter.substring(parameter.indexOf("(") + 1, parameter.lastIndexOf(")")); @@ -358,34 +273,55 @@ public class FilterFactory { }; } }); - parameterFilters.put("lowestStrength", + + parameterFilters.put("name", + (parameter, environment) -> { + String name = Sanitize(parameter); + return (actionContext) -> (Filter) + (game, physicalCard) -> name != null + && physicalCard.getBlueprint().getTitle() != null + && name.equals(Sanitize(physicalCard.getBlueprint().getTitle())); + }); + parameterFilters.put("namefrommemory", + (parameter, environment) -> actionContext -> { + Set titles = new HashSet<>(); + for (PhysicalCard physicalCard : actionContext.getCardsFromMemory(parameter)) + titles.add(physicalCard.getBlueprint().getTitle()); + return (Filter) (game, physicalCard) -> titles.contains(physicalCard.getBlueprint().getTitle()); + }); + parameterFilters.put("nameinstackedon", (parameter, environment) -> { final FilterableSource filterableSource = environment.getFilterFactory().generateFilter(parameter, environment); return actionContext -> { final Filterable sourceFilterable = filterableSource.getFilterable(actionContext); - return Filters.and( - sourceFilterable, Filters.strengthEqual( - new SingleMemoryEvaluator( - new Evaluator() { - @Override - public int evaluateExpression(LotroGame game, PhysicalCard cardAffected) { - int minStrength = Integer.MAX_VALUE; - for (PhysicalCard card : Filters.filterActive(game, sourceFilterable)) - minStrength = Math.min(minStrength, game.getModifiersQuerying().getStrength(game, card)); - return minStrength; - } - } - ) - ) - ); + return (Filter) (game, physicalCard) -> { + for (PhysicalCard cardWithStack : Filters.filterActive(game, sourceFilterable)) { + for (PhysicalCard stackedCard : game.getGameState().getStackedCards(cardWithStack)) { + if (stackedCard.getBlueprint().getTitle().equals(physicalCard.getBlueprint().getTitle())) + return true; + } + } + return false; + }; }; }); - parameterFilters.put("assignableToSkirmishAgainst", + parameterFilters.put("not", (parameter, environment) -> { - final FilterableSource againstFilterableSource = environment.getFilterFactory().generateFilter(parameter, environment); - return actionContext -> { - final Side side = GameUtils.getSide(actionContext.getGame(), actionContext.getPerformingPlayer()); - return Filters.assignableToSkirmishAgainst(side, againstFilterableSource.getFilterable(actionContext)); + final FilterableSource filterableSource = environment.getFilterFactory().generateFilter(parameter, environment); + return (actionContext) -> Filters.not(filterableSource.getFilterable(actionContext)); + }); + parameterFilters.put("or", + (parameter, environment) -> { + final String[] filters = splitIntoFilters(parameter); + FilterableSource[] filterables = new FilterableSource[filters.length]; + for (int i = 0; i < filters.length; i++) + filterables[i] = environment.getFilterFactory().generateFilter(filters[i], environment); + return (actionContext) -> { + Filterable[] filters1 = new Filterable[filterables.length]; + for (int i = 0; i < filterables.length; i++) + filters1[i] = filterables[i].getFilterable(actionContext); + + return Filters.or(filters1); }; }); parameterFilters.put("race", @@ -398,7 +334,7 @@ public class FilterFactory { else return Race.valueOf(value) == physicalCard.getBlueprint().getRace(); }; - } else if (parameter.equals("cannotSpot")) { + } else if (parameter.equals("cannotspot")) { return actionContext -> (Filter) (game, physicalCard) -> { final Race race = physicalCard.getBlueprint().getRace(); if (race != null) @@ -406,27 +342,108 @@ public class FilterFactory { return false; }; } - throw new InvalidCardDefinitionException("Unknown race definition in filter"); + throw new InvalidCardDefinitionException("Unknown race definition in filter: " + parameter + + ". Do not use race() for races; instead just list the race by itself."); }); - parameterFilters.put("nameFromMemory", - new FilterableSourceProducer() { - @Override - public FilterableSource createFilterableSource(String parameter, CardGenerationEnvironment environment) { - return new FilterableSource() { - @Override - public Filterable getFilterable(ActionContext actionContext) { - Set titles = new HashSet<>(); - for (PhysicalCard physicalCard : actionContext.getCardsFromMemory(parameter)) - titles.add(physicalCard.getBlueprint().getTitle()); - return new Filter() { - @Override - public boolean accepts(LotroGame game, PhysicalCard physicalCard) { - return titles.contains(physicalCard.getBlueprint().getTitle()); - } - }; - } - }; + parameterFilters.put("regionnumber", + (parameter, environment) -> { + int min, max; + if (parameter.contains("-")) { + final String[] split = parameter.split("-", 2); + min = Integer.parseInt(split[0]); + max = Integer.parseInt(split[1]); + } else { + min = max = Integer.parseInt(parameter); } + + if(min < 0 || max > 3 || max < min) + throw new InvalidCardDefinitionException("Region number definition is invalid: " + parameter); + + return (actionContext) -> Filters.regionNumberBetweenInclusive(min, max); + }); + parameterFilters.put("resistancelessthan", + (parameter, environment) -> { + final ValueSource valueSource = ValueResolver.resolveEvaluator(parameter, environment); + + return (actionContext) -> { + int amount = valueSource.getEvaluator(actionContext).evaluateExpression(actionContext.getGame(), null); + return Filters.maxResistance(amount - 1); + }; + }); + parameterFilters.put("resistancemorethan", + (parameter, environment) -> { + final ValueSource valueSource = ValueResolver.resolveEvaluator(parameter, environment); + return (actionContext) -> { + int amount = valueSource.getEvaluator(actionContext).evaluateExpression(actionContext.getGame(), null); + return Filters.minResistance(amount + 1); + }; + }); + parameterFilters.put("side", (parameter, environment) -> { + final Side side = Side.Parse(parameter); + if (side == null) + throw new InvalidCardDefinitionException("Unable to find side for: " + parameter); + + return (actionContext) -> side; + }); + parameterFilters.put("signet", (parameter, environment) -> { + final Signet signet = Signet.findSignet(parameter); + if (signet == null) + throw new InvalidCardDefinitionException("Unable to find signet for: " + parameter); + + return (actionContext) -> signet; + }); + parameterFilters.put("siteblock", + (parameter, environment) -> { + final SitesBlock sitesBlock = SitesBlock.findBlock(parameter); + return (actionContext) -> Filters.siteBlock(sitesBlock); + }); + parameterFilters.put("sitenumber", + (parameter, environment) -> { + int min, max; + if (parameter.contains("-")) { + final String[] split = parameter.split("-", 2); + min = Integer.parseInt(split[0]); + max = Integer.parseInt(split[1]); + } else { + min = max = Integer.parseInt(parameter); + } + + return (actionContext) -> Filters.siteNumberBetweenInclusive(min, max); + }); + parameterFilters.put("strengthlessthan", + (parameter, environment) -> { + final ValueSource valueSource = ValueResolver.resolveEvaluator(parameter, environment); + + return (actionContext) -> { + int amount = valueSource.getEvaluator(actionContext).evaluateExpression(actionContext.getGame(), null); + return Filters.lessStrengthThan(amount); + }; + }); + parameterFilters.put("strengthmorethan", + (parameter, environment) -> { + final ValueSource valueSource = ValueResolver.resolveEvaluator(parameter, environment); + + return (actionContext) -> { + int amount = valueSource.getEvaluator(actionContext).evaluateExpression(actionContext.getGame(), null); + return Filters.moreStrengthThan(amount); + }; + }); + parameterFilters.put("title",parameterFilters.get("name")); + parameterFilters.put("vitalitylessthan", + (parameter, environment) -> { + final ValueSource valueSource = ValueResolver.resolveEvaluator(parameter, environment); + return (actionContext) -> { + int amount = valueSource.getEvaluator(actionContext).evaluateExpression(actionContext.getGame(), null); + return Filters.lessVitalityThan(amount); + }; + }); + parameterFilters.put("vitalitymorethan", + (parameter, environment) -> { + final ValueSource valueSource = ValueResolver.resolveEvaluator(parameter, environment); + return (actionContext) -> { + int amount = valueSource.getEvaluator(actionContext).evaluateExpression(actionContext.getGame(), null); + return Filters.moreVitalityThan(amount); + }; }); parameterFilters.put("zone", (parameter, environment) -> { @@ -436,7 +453,7 @@ public class FilterFactory { } private void appendFilter(Filterable value) { - final String filterName = value.toString().toLowerCase().replace("_", " "); + final String filterName = Sanitize(value.toString()); final String optionalFilterName = value.toString().toLowerCase().replace("_", "-"); if (simpleFilters.containsKey(filterName)) throw new RuntimeException("Duplicate filter name: " + filterName); @@ -508,23 +525,33 @@ public class FilterFactory { if (filterString.contains("(") && filterString.endsWith(")")) { String filterName = filterString.substring(0, filterString.indexOf("(")); String filterParameter = filterString.substring(filterString.indexOf("(") + 1, filterString.lastIndexOf(")")); - return lookupFilter(filterName, filterParameter, environment); + return lookupFilter(Sanitize(filterName), Sanitize(filterParameter), environment); } - return lookupFilter(filterString, null, environment); + return lookupFilter(Sanitize(filterString), null, environment); } + + private FilterableSource lookupFilter(String name, String parameter, CardGenerationEnvironment environment) throws InvalidCardDefinitionException { if (parameter == null) { - FilterableSource result = simpleFilters.get(name.toLowerCase()); + FilterableSource result = simpleFilters.get(Sanitize(name)); if (result != null) return result; } - final FilterableSourceProducer filterableSourceProducer = parameterFilters.get(name); + final FilterableSourceProducer filterableSourceProducer = parameterFilters.get(Sanitize(name)); if (filterableSourceProducer == null) throw new InvalidCardDefinitionException("Unable to find filter: " + name); return filterableSourceProducer.createFilterableSource(parameter, environment); } + + public static String Sanitize(String input) + { + return input + .toLowerCase() + .replace(" ", "") + .replace("_", ""); + } } diff --git a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/logic/effects/AddTokenEffect.java b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/logic/effects/AddTokenEffect.java index d6262a70c..726256c1e 100644 --- a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/logic/effects/AddTokenEffect.java +++ b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/logic/effects/AddTokenEffect.java @@ -37,7 +37,10 @@ public class AddTokenEffect extends AbstractEffect { @Override public String getText(LotroGame game) { - return null; + if (_token != null) + return "Add " + _count + " " + _token.getCulture().getHumanReadable() + " token" + (_count > 1 ? "s" : ""); + else + return "Add " + _count + " culture token" + (_count > 1 ? "s" : ""); } @Override