diff --git a/gemp-lotr/gemp-lotr-async/src/main/web/cards/set1/set1-dwarven.json b/gemp-lotr/gemp-lotr-async/src/main/web/cards/set1/set1-dwarven.json index ab78abd42..43a87b7de 100644 --- a/gemp-lotr/gemp-lotr-async/src/main/web/cards/set1/set1-dwarven.json +++ b/gemp-lotr/gemp-lotr-async/src/main/web/cards/set1/set1-dwarven.json @@ -719,11 +719,11 @@ }, { "type": "putCardsFromDeckIntoHand", - "filter": "memory(revealedCards),side(free people)" + "filter": "all(memory(revealedCards),side(free people))" }, { "type": "discardCardsFromDrawDeck", - "filter": "memory(revealedCards),not(side(free people))" + "filter": "all(memory(revealedCards),not(side(free people)))" } ] } diff --git a/gemp-lotr/gemp-lotr-async/src/main/web/cards/set1/set1-gandalf.json b/gemp-lotr/gemp-lotr-async/src/main/web/cards/set1/set1-gandalf.json index aa3f927b8..4959364d8 100644 --- a/gemp-lotr/gemp-lotr-async/src/main/web/cards/set1/set1-gandalf.json +++ b/gemp-lotr/gemp-lotr-async/src/main/web/cards/set1/set1-gandalf.json @@ -410,7 +410,7 @@ }, { "type": "discardCardsFromDrawDeck", - "filter": "memory(cardsOnTop),zone(deck)" + "filter": "all(memory(cardsOnTop),zone(deck))" } ] } @@ -449,7 +449,7 @@ }, { "type": "discardCardsFromDrawDeck", - "filter": "memory(cardsOnTop),zone(deck)" + "filter": "all(memory(cardsOnTop),zone(deck))" } ] } diff --git a/gemp-lotr/gemp-lotr-async/src/main/web/cards/set1/set1-moria.json b/gemp-lotr/gemp-lotr-async/src/main/web/cards/set1/set1-moria.json index 9fd084e2f..21ebfcee4 100644 --- a/gemp-lotr/gemp-lotr-async/src/main/web/cards/set1/set1-moria.json +++ b/gemp-lotr/gemp-lotr-async/src/main/web/cards/set1/set1-moria.json @@ -888,5 +888,90 @@ "amount": -2 } } + }, + "1_200": { + "title": "The Underdeeps of Moria", + "culture": "moria", + "cost": 2, + "type": "condition", + "keyword": "support area", + "effects": { + "type": "activated", + "phase": "shadow", + "cost": { + "type": "removeTwilight", + "amount": 3 + }, + "effect": [ + { + "type": "revealBottomCardsOfDrawDeck", + "memorize": "revealedCards" + }, + { + "type": "putCardsFromDeckIntoHand", + "filter": "all(memory(revealedCards),culture(moria),orc)" + }, + { + "type": "discardCardsFromDrawDeck", + "filter": "all(memory(revealedCards),zone(deck))" + } + ] + } + }, + "1_201": { + "title": "Unfamiliar Territory", + "culture": "moria", + "cost": 0, + "type": "event", + "keyword": "skirmish", + "effects": { + "type": "event", + "effect": { + "type": "modifyStrength", + "filter": "choose(culture(moria),orc)", + "memorize": "chosenOrc", + "amount": { + "type": "condition", + "condition": { + "type": "memoryMatches", + "memory": "chosenOrc", + "filter": "inSkirmishAgainst(archer)" + }, + "true": 4, + "false": 2 + } + } + } + }, + "1_202": { + "title": "What is this new devilry", + "culture": "moria", + "cost": 2, + "type": "condition", + "keyword": [ + "search", + "support area" + ], + "effects": [ + { + "type": "extraCost", + "cost": { + "type": "exert", + "filter": "choose(culture(moria),orc)" + } + }, + { + "type": "modifier", + "modifier": { + "type": "modifyCost", + "filter": "companion", + "condition": { + "type": "location", + "filter": "siteBlock(fellowship),siteNumber(5-9)" + }, + "amount": 2 + } + } + ] } } \ No newline at end of file diff --git a/gemp-lotr/gemp-lotr-async/src/main/web/cards/set9-1.json b/gemp-lotr/gemp-lotr-async/src/main/web/cards/set9-1.json index 4f34bfd98..9487ad63d 100644 --- a/gemp-lotr/gemp-lotr-async/src/main/web/cards/set9-1.json +++ b/gemp-lotr/gemp-lotr-async/src/main/web/cards/set9-1.json @@ -270,11 +270,11 @@ }, { "type": "putCardsFromDeckIntoHand", - "filter": "memory(revealedCards),side(free people)" + "filter": "all(memory(revealedCards),side(free people))" }, { "type": "discardCardsFromDrawDeck", - "filter": "memory(revealedCards),not(side(free people))" + "filter": "all(memory(revealedCards),not(side(free people)))" }, { "type": "discard", diff --git a/gemp-lotr/gemp-lotr-cards/src/main/java/com/gempukku/lotro/cards/set1/moria/Card1_200.java b/gemp-lotr/gemp-lotr-cards/src/main/java/com/gempukku/lotro/cards/set1/moria/Card1_200.java deleted file mode 100644 index e99fdfe9f..000000000 --- a/gemp-lotr/gemp-lotr-cards/src/main/java/com/gempukku/lotro/cards/set1/moria/Card1_200.java +++ /dev/null @@ -1,61 +0,0 @@ -package com.gempukku.lotro.cards.set1.moria; - -import com.gempukku.lotro.common.*; -import com.gempukku.lotro.game.PhysicalCard; -import com.gempukku.lotro.game.state.LotroGame; -import com.gempukku.lotro.logic.actions.ActivateCardAction; -import com.gempukku.lotro.logic.cardtype.AbstractPermanent; -import com.gempukku.lotro.logic.effects.DiscardCardFromDeckEffect; -import com.gempukku.lotro.logic.effects.PutCardFromDeckIntoHandOrDiscardEffect; -import com.gempukku.lotro.logic.effects.RemoveTwilightEffect; -import com.gempukku.lotro.logic.effects.RevealCardEffect; -import com.gempukku.lotro.logic.timing.PlayConditions; -import com.gempukku.lotro.logic.timing.UnrespondableEffect; - -import java.util.Collections; -import java.util.List; - -/** - * Set: The Fellowship of the Ring - * Side: Shadow - * Culture: Moria - * Twilight Cost: 2 - * Type: Condition - * Game Text: Plays to your support area. Shadow: Remove (3) to reveal the bottom card of your draw deck. If it is a - * [MORIA] Orc, take it into hand. Otherwise, discard it. - */ -public class Card1_200 extends AbstractPermanent { - public Card1_200() { - super(Side.SHADOW, 2, CardType.CONDITION, Culture.MORIA, "The Underdeeps of Moria"); - } - - @Override - public List getPhaseActionsInPlay(final String playerId, final LotroGame game, final PhysicalCard self) { - if (PlayConditions.canUseShadowCardDuringPhase(game, Phase.SHADOW, self, 3)) { - final ActivateCardAction action = new ActivateCardAction(self); - action.appendCost(new RemoveTwilightEffect(3)); - action.appendEffect( - new UnrespondableEffect() { - @Override - public void doPlayEffect(LotroGame game) { - List deck = game.getGameState().getDeck(playerId); - if (deck.size() > 0) { - PhysicalCard bottomCard = deck.get(deck.size() - 1); - action.appendEffect( - new RevealCardEffect(self, bottomCard)); - if (bottomCard.getBlueprint().getCulture() == Culture.MORIA - && bottomCard.getBlueprint().getRace() == Race.ORC) { - action.appendEffect( - new PutCardFromDeckIntoHandOrDiscardEffect(bottomCard)); - } else { - action.appendEffect( - new DiscardCardFromDeckEffect(bottomCard)); - } - } - } - }); - return Collections.singletonList(action); - } - return null; - } -} diff --git a/gemp-lotr/gemp-lotr-cards/src/main/java/com/gempukku/lotro/cards/set1/moria/Card1_201.java b/gemp-lotr/gemp-lotr-cards/src/main/java/com/gempukku/lotro/cards/set1/moria/Card1_201.java deleted file mode 100644 index 9e05d722c..000000000 --- a/gemp-lotr/gemp-lotr-cards/src/main/java/com/gempukku/lotro/cards/set1/moria/Card1_201.java +++ /dev/null @@ -1,34 +0,0 @@ -package com.gempukku.lotro.cards.set1.moria; - -import com.gempukku.lotro.common.*; -import com.gempukku.lotro.filters.Filters; -import com.gempukku.lotro.game.PhysicalCard; -import com.gempukku.lotro.game.state.LotroGame; -import com.gempukku.lotro.logic.actions.PlayEventAction; -import com.gempukku.lotro.logic.cardtype.AbstractEvent; -import com.gempukku.lotro.logic.effects.choose.ChooseAndAddUntilEOPStrengthBonusEffect; -import com.gempukku.lotro.logic.modifiers.evaluator.CardMatchesEvaluator; - -/** - * Set: The Fellowship of the Ring - * Side: Shadow - * Culture: Moria - * Twilight Cost: 0 - * Type: Event - * Game Text: Skirmish: Make a [MORIA] Orc strength +2 (or +4 if skirmishing an archer). - */ -public class Card1_201 extends AbstractEvent { - public Card1_201() { - super(Side.SHADOW, 0, Culture.MORIA, "Unfamiliar Territory", Phase.SKIRMISH); - } - - @Override - public PlayEventAction getPlayEventCardAction(String playerId, final LotroGame game, final PhysicalCard self) { - final PlayEventAction action = new PlayEventAction(self); - action.appendEffect( - new ChooseAndAddUntilEOPStrengthBonusEffect(action, self, playerId, - new CardMatchesEvaluator(2, 4, Filters.inSkirmishAgainst(Keyword.ARCHER)), - Culture.MORIA, Race.ORC)); - return action; - } -} diff --git a/gemp-lotr/gemp-lotr-cards/src/main/java/com/gempukku/lotro/cards/set1/moria/Card1_202.java b/gemp-lotr/gemp-lotr-cards/src/main/java/com/gempukku/lotro/cards/set1/moria/Card1_202.java deleted file mode 100644 index 09eb40730..000000000 --- a/gemp-lotr/gemp-lotr-cards/src/main/java/com/gempukku/lotro/cards/set1/moria/Card1_202.java +++ /dev/null @@ -1,52 +0,0 @@ -package com.gempukku.lotro.cards.set1.moria; - -import com.gempukku.lotro.common.*; -import com.gempukku.lotro.filters.Filter; -import com.gempukku.lotro.filters.Filters; -import com.gempukku.lotro.game.PhysicalCard; -import com.gempukku.lotro.game.state.LotroGame; -import com.gempukku.lotro.logic.cardtype.AbstractPermanent; -import com.gempukku.lotro.logic.modifiers.AbstractExtraPlayCostModifier; -import com.gempukku.lotro.logic.modifiers.Modifier; -import com.gempukku.lotro.logic.modifiers.TwilightCostModifier; -import com.gempukku.lotro.logic.modifiers.cost.ExertExtraPlayCostModifier; - -import java.util.Collections; -import java.util.List; - -/** - * Set: The Fellowship of the Ring - * Side: Shadow - * Culture: Moria - * Twilight Cost: 2 - * Type: Condition - * Game Text: Search. To play, exert a [MORIA] Orc. Plays to your support area. While the fellowship is at site 5 or - * higher, each companion's twilight cost is +2. - */ -public class Card1_202 extends AbstractPermanent { - public Card1_202() { - super(Side.SHADOW, 2, CardType.CONDITION, Culture.MORIA, "What Is This New Devilry?"); - addKeyword(Keyword.SEARCH); - } - - @Override - public List getExtraCostToPlay(LotroGame game, PhysicalCard self) { - return Collections.singletonList( - new ExertExtraPlayCostModifier(self, self, null, Culture.MORIA, Race.ORC)); - } - - @Override - public List getInPlayModifiers(LotroGame game, PhysicalCard self) { - return Collections.singletonList(new TwilightCostModifier(self, - Filters.and( - CardType.COMPANION, - new Filter() { - @Override - public boolean accepts(LotroGame game, PhysicalCard physicalCard) { - return game.getGameState().getCurrentSiteNumber() >= 5 && game.getGameState().getCurrentSiteBlock() == SitesBlock.FELLOWSHIP; - } - } - ) - , 2)); - } -} 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 2cde12c46..ebba0c6d7 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("playcardfromstacked", new PlayCardFromStacked()); effectAppenderProducers.put("reducearcherytotal", new ReduceArcheryTotal()); effectAppenderProducers.put("revealtopcardsofdrawdeck", new RevealTopCardsOfDrawDeck()); + effectAppenderProducers.put("revealbottomcardsofdrawdeck", new RevealBottomCardsOfDrawDeck()); effectAppenderProducers.put("optional", new Optional()); effectAppenderProducers.put("costtoeffect", new CostToEffect()); effectAppenderProducers.put("spot", new Spot()); diff --git a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/effect/appender/RevealBottomCardsOfDrawDeck.java b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/effect/appender/RevealBottomCardsOfDrawDeck.java new file mode 100644 index 000000000..3253c7558 --- /dev/null +++ b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/effect/appender/RevealBottomCardsOfDrawDeck.java @@ -0,0 +1,52 @@ +package com.gempukku.lotro.cards.build.field.effect.appender; + +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; +import com.gempukku.lotro.cards.build.field.effect.appender.resolver.PlayerResolver; +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.RevealBottomCardsOfDrawDeckEffect; +import com.gempukku.lotro.logic.timing.Effect; +import org.json.simple.JSONObject; + +import java.util.List; + +public class RevealBottomCardsOfDrawDeck implements EffectAppenderProducer { + @Override + public EffectAppender createEffectAppender(JSONObject effectObject, CardGenerationEnvironment environment) throws InvalidCardDefinitionException { + FieldUtils.validateAllowedFields(effectObject, "deck", "count", "memorize"); + + final String deck = FieldUtils.getString(effectObject.get("deck"), "deck", "you"); + final ValueSource valueSource = ValueResolver.resolveEvaluator(effectObject.get("count"), 1, environment); + final String memorize = FieldUtils.getString(effectObject.get("memorize"), "memorize"); + + final PlayerSource playerSource = PlayerResolver.resolvePlayer(deck, environment); + + return new DelayedAppender() { + @Override + public boolean isPlayableInFull(ActionContext actionContext) { + final String deckId = playerSource.getPlayer(actionContext); + final int count = valueSource.getEvaluator(actionContext).evaluateExpression(actionContext.getGame(), null); + + return actionContext.getGame().getGameState().getDeck(deckId).size() >= count; + } + + @Override + protected Effect createEffect(boolean cost, CostToEffectAction action, ActionContext actionContext) { + final String deckId = playerSource.getPlayer(actionContext); + final int count = valueSource.getEvaluator(actionContext).evaluateExpression(actionContext.getGame(), null); + + return new RevealBottomCardsOfDrawDeckEffect(actionContext.getSource(), deckId, count) { + @Override + protected void cardsRevealed(List revealedCards) { + if (memorize != null) + actionContext.setCardMemory(memorize, revealedCards); + } + }; + } + }; + } +} 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 b9541be5f..efcd3dd00 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 @@ -40,6 +40,8 @@ public class CardResolver { String memory, String choicePlayer, String choiceText, CardGenerationEnvironment environment) throws InvalidCardDefinitionException { if (type.startsWith("memory(") && type.endsWith(")")) { String sourceMemory = type.substring(type.indexOf("(") + 1, type.lastIndexOf(")")); + if (sourceMemory.contains("(") || sourceMemory.contains(")")) + throw new InvalidCardDefinitionException("Memory name cannot contain parenthesis"); return new DelayedAppender() { @Override public boolean isPlayableInFull(ActionContext actionContext) { @@ -152,9 +154,12 @@ public class CardResolver { } }; } else if (type.startsWith("memory(") && type.endsWith(")")) { + String sourceMemory = type.substring(type.indexOf("(") + 1, type.lastIndexOf(")")); + if (sourceMemory.contains("(") || sourceMemory.contains(")")) + throw new InvalidCardDefinitionException("Memory name cannot contain parenthesis"); + final PlayerSource handSource = PlayerResolver.resolvePlayer(handPlayer, environment); - String sourceMemory = type.substring(type.indexOf("(") + 1, type.lastIndexOf(")")); return new DelayedAppender() { @Override public boolean isPlayableInFull(ActionContext actionContext) { @@ -265,9 +270,12 @@ public class CardResolver { 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(")")) { + String sourceMemory = type.substring(type.indexOf("(") + 1, type.lastIndexOf(")")); + if (sourceMemory.contains("(") || sourceMemory.contains(")")) + throw new InvalidCardDefinitionException("Memory name cannot contain parenthesis"); + final PlayerSource playerSource = PlayerResolver.resolvePlayer(choicePlayer, environment); - String sourceMemory = type.substring(type.indexOf("(") + 1, type.lastIndexOf(")")); return new DelayedAppender() { @Override public boolean isPlayableInFull(ActionContext actionContext) { @@ -358,6 +366,8 @@ public class CardResolver { public static EffectAppender resolveCardsInDeck(String type, FilterableSource choiceFilter, ValueSource countSource, String memory, String choicePlayer, String choiceText, CardGenerationEnvironment environment) throws InvalidCardDefinitionException { if (type.startsWith("memory(") && type.endsWith(")")) { String sourceMemory = type.substring(type.indexOf("(") + 1, type.lastIndexOf(")")); + if (sourceMemory.contains("(") || sourceMemory.contains(")")) + throw new InvalidCardDefinitionException("Memory name cannot contain parenthesis"); return new DelayedAppender() { @Override public boolean isPlayableInFull(ActionContext actionContext) { @@ -374,6 +384,28 @@ public class CardResolver { }; } }; + } else if (type.startsWith("all(") && type.endsWith(")")) { + final String filter = type.substring(type.indexOf("(") + 1, type.lastIndexOf(")")); + final FilterableSource filterableSource = environment.getFilterFactory().generateFilter(filter, environment); + final PlayerSource playerSource = PlayerResolver.resolvePlayer(choicePlayer, environment); + return new DelayedAppender() { + @Override + protected Effect createEffect(boolean cost, CostToEffectAction action, ActionContext actionContext) { + return new UnrespondableEffect() { + @Override + protected void doPlayEffect(LotroGame game) { + final String player = playerSource.getPlayer(actionContext); + final Filterable filterable = filterableSource.getFilterable(actionContext); + actionContext.setCardMemory(memory, Filters.filter(game.getGameState().getDeck(player), game, filterable)); + } + }; + } + + @Override + public boolean isPlayableInFull(ActionContext actionContext) { + return true; + } + }; } else if (type.startsWith("choose(") && type.endsWith(")")) { final String filter = type.substring(type.indexOf("(") + 1, type.lastIndexOf(")")); final FilterableSource filterableSource = environment.getFilterFactory().generateFilter(filter, environment); @@ -465,6 +497,8 @@ public class CardResolver { }; } else if (type.startsWith("memory(") && type.endsWith(")")) { String sourceMemory = type.substring(type.indexOf("(") + 1, type.lastIndexOf(")")); + if (sourceMemory.contains("(") || sourceMemory.contains(")")) + throw new InvalidCardDefinitionException("Memory name cannot contain parenthesis"); return new DelayedAppender() { @Override public boolean isPlayableInFull(ActionContext actionContext) {