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 1d168aaba..6b2c09b29 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 @@ -350,6 +350,156 @@ } } }, + "40_167": { + "title": "*Goblin Reclaimer", + "culture": "moria", + "cost": 2, + "type": "minion", + "race": "goblin", + "strength": 6, + "vitality": 2, + "site": 4, + "effects": { + "type": "trigger", + "optional": true, + "trigger": { + "type": "played", + "filter": "self" + }, + "condition": { + "type": "canSpot", + "filter": "another,culture(moria),goblin" + }, + "effect": { + "type": "playCardFromDiscard", + "filter": "choose(culture(moria),condition)" + } + } + }, + "40_168": { + "title": "*Goblin Reinforcements", + "culture": "moria", + "cost": 4, + "type": "minion", + "race": "goblin", + "strength": 10, + "vitality": 2, + "site": 4, + "effects": { + "type": "trigger", + "optional": true, + "trigger": { + "type": "played", + "filter": "self" + }, + "effect": { + "type": "duplicate", + "amount": { + "type": "forEachYouCanSpot", + "filter": "companion", + "over": 5 + }, + "effect": { + "type": "playCardFromDiscard", + "filter": "choose(culture(moria),goblin)" + } + } + } + }, + "40_169": { + "title": "Goblin Runner", + "culture": "moria", + "cost": 1, + "type": "minion", + "race": "goblin", + "strength": 5, + "vitality": 1, + "site": 4, + "effects": { + "type": "trigger", + "optional": true, + "trigger": { + "type": "played", + "filter": "self" + }, + "condition": { + "type": "canSpot", + "filter": "another,culture(moria),goblin" + }, + "effect": { + "type": "addTwilight", + "amount": 2 + } + } + }, + "40_170": { + "title": "Goblin Scavengers", + "culture": "moria", + "cost": 3, + "type": "minion", + "race": "goblin", + "strength": 8, + "vitality": 1, + "site": 4, + "effects": { + "type": "trigger", + "optional": true, + "trigger": { + "type": "played", + "filter": "self" + }, + "effect": { + "type": "playCardFromDiscard", + "filter": "choose(weapon)", + "on": "culture(moria),goblin" + } + } + }, + "40_171": { + "title": "Goblin Scimitar", + "culture": "moria", + "cost": 0, + "type": "possession", + "possession": "hand weapon", + "strength": 2, + "target": "culture(moria),goblin", + "effects": { + "type": "trigger", + "optional": true, + "trigger": { + "type": "played", + "filter": "self" + }, + "effect": { + "type": "drawCards" + } + } + }, + "40_172": { + "title": "Goblin Scrapper", + "culture": "moria", + "cost": 2, + "type": "minion", + "race": "goblin", + "strength": 6, + "vitality": 2, + "site": 4, + "effects": { + "type": "activatedTrigger", + "trigger": { + "type": "aboutToTakeWound", + "filter": "culture(moria),goblin" + }, + "cost": { + "type": "discardStackedCards", + "on": "culture(moria),condition" + }, + "effect": { + "type": "preventWound", + "filter": "choose(culture(moria),goblin)" + } + } + }, "40_316": { "title": "Deep Places of the World", "culture": "moria", diff --git a/gemp-lotr/gemp-lotr-cards/src/main/java/com/gempukku/lotro/cards/set40/moria/Card40_167.java b/gemp-lotr/gemp-lotr-cards/src/main/java/com/gempukku/lotro/cards/set40/moria/Card40_167.java deleted file mode 100644 index 73e2d9c14..000000000 --- a/gemp-lotr/gemp-lotr-cards/src/main/java/com/gempukku/lotro/cards/set40/moria/Card40_167.java +++ /dev/null @@ -1,49 +0,0 @@ -package com.gempukku.lotro.cards.set40.moria; - -import com.gempukku.lotro.logic.cardtype.AbstractMinion; -import com.gempukku.lotro.logic.timing.PlayConditions; -import com.gempukku.lotro.logic.timing.TriggerConditions; -import com.gempukku.lotro.logic.effects.choose.ChooseAndPlayCardFromDiscardEffect; -import com.gempukku.lotro.common.CardType; -import com.gempukku.lotro.common.Culture; -import com.gempukku.lotro.common.Race; -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.OptionalTriggerAction; -import com.gempukku.lotro.logic.timing.EffectResult; - -import java.util.Collections; -import java.util.List; - -/** - * Title: *Goblin Reclaimer - * Set: Second Edition - * Side: Shadow - * Culture: Moria - * Twilight Cost: 2 - * Type: Minion - Goblin - * Strength: 6 - * Vitality: 2 - * Home: 4 - * Card Number: 1R167 - * Game Text: When you play this minion, you may spot another [MORIA] Goblin to play a [MORIA] condition from your discard pile. - */ -public class Card40_167 extends AbstractMinion { - public Card40_167() { - super(2, 6, 2, 4, Race.GOBLIN, Culture.MORIA, "Goblin Reclaimer", null, true); - } - - @Override - public List getOptionalAfterTriggers(String playerId, LotroGame game, EffectResult effectResult, PhysicalCard self) { - if (TriggerConditions.played(game, effectResult, self) - && PlayConditions.canSpot(game, Culture.MORIA, Race.GOBLIN, Filters.not(self)) - && PlayConditions.canPlayFromDiscard(playerId, game, Culture.MORIA, CardType.CONDITION)) { - OptionalTriggerAction action = new OptionalTriggerAction(self); - action.appendEffect( - new ChooseAndPlayCardFromDiscardEffect(playerId, game, Culture.MORIA, CardType.CONDITION)); - return Collections.singletonList(action); - } - return null; - } -} diff --git a/gemp-lotr/gemp-lotr-cards/src/main/java/com/gempukku/lotro/cards/set40/moria/Card40_168.java b/gemp-lotr/gemp-lotr-cards/src/main/java/com/gempukku/lotro/cards/set40/moria/Card40_168.java deleted file mode 100644 index 17a4269b5..000000000 --- a/gemp-lotr/gemp-lotr-cards/src/main/java/com/gempukku/lotro/cards/set40/moria/Card40_168.java +++ /dev/null @@ -1,51 +0,0 @@ -package com.gempukku.lotro.cards.set40.moria; - -import com.gempukku.lotro.logic.cardtype.AbstractMinion; -import com.gempukku.lotro.logic.timing.PlayConditions; -import com.gempukku.lotro.logic.timing.TriggerConditions; -import com.gempukku.lotro.logic.effects.choose.ChooseAndPlayCardFromDiscardEffect; -import com.gempukku.lotro.common.CardType; -import com.gempukku.lotro.common.Culture; -import com.gempukku.lotro.common.Race; -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.OptionalTriggerAction; -import com.gempukku.lotro.logic.timing.EffectResult; - -import java.util.Collections; -import java.util.List; - -/** - * Title: *Goblin Reinforcements - * Set: Second Edition - * Side: Shadow - * Culture: Moria - * Twilight Cost: 4 - * Type: Minion - Goblin - * Strength: 10 - * Vitality: 2 - * Home: 4 - * Card Number: 1U168 - * Game Text: When you play this minion, you may play a [MORIA] Goblin from your discard pile for each companion over 5. - */ -public class Card40_168 extends AbstractMinion { - public Card40_168() { - super(4, 10, 2, 4, Race.GOBLIN, Culture.MORIA, "Goblin Reinforcements", null, true); - } - - @Override - public List getOptionalAfterTriggers(String playerId, LotroGame game, EffectResult effectResult, PhysicalCard self) { - final int companionCount = Filters.countActive(game, CardType.COMPANION); - if (TriggerConditions.played(game, effectResult, self) - && companionCount > 5 - && PlayConditions.canPlayFromDiscard(playerId, game, Culture.MORIA, Race.GOBLIN)) { - OptionalTriggerAction action = new OptionalTriggerAction(self); - for (int i = 5; i < companionCount; i++) - action.appendEffect( - new ChooseAndPlayCardFromDiscardEffect(playerId, game, Culture.MORIA, Race.GOBLIN)); - return Collections.singletonList(action); - } - return null; - } -} diff --git a/gemp-lotr/gemp-lotr-cards/src/main/java/com/gempukku/lotro/cards/set40/moria/Card40_169.java b/gemp-lotr/gemp-lotr-cards/src/main/java/com/gempukku/lotro/cards/set40/moria/Card40_169.java deleted file mode 100644 index 3fbfd40b9..000000000 --- a/gemp-lotr/gemp-lotr-cards/src/main/java/com/gempukku/lotro/cards/set40/moria/Card40_169.java +++ /dev/null @@ -1,47 +0,0 @@ -package com.gempukku.lotro.cards.set40.moria; - -import com.gempukku.lotro.logic.cardtype.AbstractMinion; -import com.gempukku.lotro.logic.timing.PlayConditions; -import com.gempukku.lotro.logic.timing.TriggerConditions; -import com.gempukku.lotro.common.Culture; -import com.gempukku.lotro.common.Race; -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.OptionalTriggerAction; -import com.gempukku.lotro.logic.effects.AddTwilightEffect; -import com.gempukku.lotro.logic.timing.EffectResult; - -import java.util.Collections; -import java.util.List; - -/** - * Title: Goblin Runner - * Set: Second Edition - * Side: Shadow - * Culture: Moria - * Twilight Cost: 1 - * Type: Minion - Goblin - * Strength: 5 - * Vitality: 1 - * Home: 4 - * Card Number: 1U169 - * Game Text: When you play this minion, you may spot another [MORIA] Goblin to add (2). - */ -public class Card40_169 extends AbstractMinion { - public Card40_169() { - super(1, 5, 1, 4, Race.GOBLIN, Culture.MORIA, "Goblin Runner"); - } - - @Override - public List getOptionalAfterTriggers(String playerId, LotroGame game, EffectResult effectResult, PhysicalCard self) { - if (TriggerConditions.played(game, effectResult, self) - && PlayConditions.canSpot(game, Culture.MORIA, Race.GOBLIN, Filters.not(self))) { - OptionalTriggerAction action = new OptionalTriggerAction(self); - action.appendEffect( - new AddTwilightEffect(self, 2)); - return Collections.singletonList(action); - } - return null; - } -} diff --git a/gemp-lotr/gemp-lotr-cards/src/main/java/com/gempukku/lotro/cards/set40/moria/Card40_170.java b/gemp-lotr/gemp-lotr-cards/src/main/java/com/gempukku/lotro/cards/set40/moria/Card40_170.java deleted file mode 100644 index 99bd20f9b..000000000 --- a/gemp-lotr/gemp-lotr-cards/src/main/java/com/gempukku/lotro/cards/set40/moria/Card40_170.java +++ /dev/null @@ -1,63 +0,0 @@ -package com.gempukku.lotro.cards.set40.moria; - -import com.gempukku.lotro.common.Culture; -import com.gempukku.lotro.common.Race; -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.PlayUtils; -import com.gempukku.lotro.logic.actions.OptionalTriggerAction; -import com.gempukku.lotro.logic.cardtype.AbstractMinion; -import com.gempukku.lotro.logic.effects.ChooseArbitraryCardsEffect; -import com.gempukku.lotro.logic.timing.EffectResult; -import com.gempukku.lotro.logic.timing.ExtraFilters; -import com.gempukku.lotro.logic.timing.PlayConditions; -import com.gempukku.lotro.logic.timing.TriggerConditions; - -import java.util.Collection; -import java.util.Collections; -import java.util.List; - -/** - * Title: Goblin Scavengers - * Set: Second Edition - * Side: Shadow - * Culture: Moria - * Twilight Cost: 3 - * Type: Minion - Goblin - * Strength: 8 - * Vitality: 1 - * Home: 4 - * Card Number: 1RC170 - * Game Text: When you play this minion, you may play a weapon from your discard pile on a [MORIA] Goblin. - */ -public class Card40_170 extends AbstractMinion { - public Card40_170() { - super(3, 8, 1, 4, Race.GOBLIN, Culture.MORIA, "Goblin Scavengers"); - } - - @Override - public List getOptionalAfterTriggers(final String playerId, final LotroGame game, EffectResult effectResult, final PhysicalCard self) { - final Filter additionalAttachmentFilter = Filters.and(Filters.owner(self.getOwner()), Culture.MORIA, Race.GOBLIN); - - if (TriggerConditions.played(game, effectResult, self) - && PlayConditions.canPlayFromDiscard(playerId, game, Filters.weapon, ExtraFilters.attachableTo(game, additionalAttachmentFilter))) { - OptionalTriggerAction action = new OptionalTriggerAction(self); - action.appendEffect( - new ChooseArbitraryCardsEffect(playerId, "Choose card to play", game.getGameState().getDiscard(playerId), - Filters.and( - Filters.weapon, - ExtraFilters.attachableTo(game, additionalAttachmentFilter)), 1, 1, true) { - @Override - protected void cardsSelected(LotroGame game, Collection selectedCards) { - if (selectedCards.size() > 0) { - PhysicalCard selectedCard = selectedCards.iterator().next(); - game.getActionsEnvironment().addActionToStack(PlayUtils.getPlayCardAction(game, selectedCard, 0, additionalAttachmentFilter, false)); - } - } - }); - return Collections.singletonList(action); - } - return null; - }} diff --git a/gemp-lotr/gemp-lotr-cards/src/main/java/com/gempukku/lotro/cards/set40/moria/Card40_171.java b/gemp-lotr/gemp-lotr-cards/src/main/java/com/gempukku/lotro/cards/set40/moria/Card40_171.java deleted file mode 100644 index eb713c214..000000000 --- a/gemp-lotr/gemp-lotr-cards/src/main/java/com/gempukku/lotro/cards/set40/moria/Card40_171.java +++ /dev/null @@ -1,52 +0,0 @@ -package com.gempukku.lotro.cards.set40.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.OptionalTriggerAction; -import com.gempukku.lotro.logic.cardtype.AbstractAttachable; -import com.gempukku.lotro.logic.effects.DrawCardsEffect; -import com.gempukku.lotro.logic.timing.EffectResult; -import com.gempukku.lotro.logic.timing.TriggerConditions; - -import java.util.Collections; -import java.util.List; - -/** - * Title: Goblin Scimitar - * Set: Second Edition - * Side: Shadow - * Culture: Moria - * Twilight Cost: 0 - * Type: Possession - Hand Weapon - * Strength: +2 - * Card Number: 1C171 - * Game Text: Bearer must be a [MORIA] Goblin. When you play this possession, you may draw a card. - */ -public class Card40_171 extends AbstractAttachable { - public Card40_171() { - super(Side.SHADOW, CardType.POSSESSION, 0, Culture.MORIA, PossessionClass.HAND_WEAPON, "Goblin Scimitar"); - } - - @Override - public Filterable getValidTargetFilter(String playerId, LotroGame game, PhysicalCard self) { - return Filters.and(Culture.MORIA, Race.GOBLIN); - } - - @Override - public List getOptionalAfterTriggers(String playerId, LotroGame game, EffectResult effectResult, PhysicalCard self) { - if (TriggerConditions.played(game, effectResult, self)) { - OptionalTriggerAction action = new OptionalTriggerAction(self); - action.appendEffect( - new DrawCardsEffect(action, playerId, 1)); - return Collections.singletonList(action); - } - return null; - } - - @Override - public int getStrength() { - return 2; - } -} diff --git a/gemp-lotr/gemp-lotr-cards/src/main/java/com/gempukku/lotro/cards/set40/moria/Card40_172.java b/gemp-lotr/gemp-lotr-cards/src/main/java/com/gempukku/lotro/cards/set40/moria/Card40_172.java deleted file mode 100644 index 097742afa..000000000 --- a/gemp-lotr/gemp-lotr-cards/src/main/java/com/gempukku/lotro/cards/set40/moria/Card40_172.java +++ /dev/null @@ -1,53 +0,0 @@ -package com.gempukku.lotro.cards.set40.moria; - -import com.gempukku.lotro.logic.cardtype.AbstractMinion; -import com.gempukku.lotro.logic.timing.PlayConditions; -import com.gempukku.lotro.logic.timing.TriggerConditions; -import com.gempukku.lotro.logic.effects.choose.ChooseAndDiscardStackedCardsEffect; -import com.gempukku.lotro.logic.effects.choose.ChooseAndPreventCardEffect; -import com.gempukku.lotro.common.CardType; -import com.gempukku.lotro.common.Culture; -import com.gempukku.lotro.common.Race; -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.ActivateCardAction; -import com.gempukku.lotro.logic.effects.WoundCharactersEffect; -import com.gempukku.lotro.logic.timing.Effect; - -import java.util.Collections; -import java.util.List; - -/** - * Title: Goblin Scrapper - * Set: Second Edition - * Side: Shadow - * Culture: Moria - * Twilight Cost: 2 - * Type: Minion - Goblin - * Strength: 6 - * Vitality: 2 - * Home: 4 - * Card Number: 1U172 - * Game Text: Response: If a [MORIA] Goblin is about to take a wound, discard a card stacked on a [MORIA] condition to prevent that wound. - */ -public class Card40_172 extends AbstractMinion { - public Card40_172() { - super(2, 6, 2, 4, Race.GOBLIN, Culture.MORIA, "Goblin Scrapper"); - } - - @Override - public List getOptionalInPlayBeforeActions(String playerId, LotroGame game, Effect effect, PhysicalCard self) { - if (TriggerConditions.isGettingWounded(effect, game, Culture.MORIA, Race.GOBLIN) - && PlayConditions.canDiscardFromStacked(self, game, playerId, 1, Filters.and(Culture.MORIA, CardType.CONDITION), Filters.any)) { - WoundCharactersEffect woundEffect = (WoundCharactersEffect) effect; - ActivateCardAction action = new ActivateCardAction(self); - action.appendCost( - new ChooseAndDiscardStackedCardsEffect(action, playerId, 1, 1, Filters.and(Culture.MORIA, Race.GOBLIN), Filters.any)); - action.appendEffect( - new ChooseAndPreventCardEffect(self, woundEffect, playerId, "Choose MORIA Goblin to prevent wound to", Culture.MORIA, Race.GOBLIN)); - return Collections.singletonList(action); - } - return null; - } -} 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 27a39992d..0e8104e68 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 @@ -80,6 +80,7 @@ public class EffectAppenderFactory { effectAppenderProducers.put("putcardsfromdeckintohand", new PutCardsFromDeckIntoHand()); effectAppenderProducers.put("addmodifier", new AddModifier()); effectAppenderProducers.put("playnextsite", new PlayNextSite()); + effectAppenderProducers.put("duplicate", new Duplicate()); } 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/Duplicate.java b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/effect/appender/Duplicate.java new file mode 100644 index 000000000..73db95099 --- /dev/null +++ b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/effect/appender/Duplicate.java @@ -0,0 +1,54 @@ +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.game.state.LotroGame; +import com.gempukku.lotro.logic.actions.CostToEffectAction; +import com.gempukku.lotro.logic.actions.SubAction; +import com.gempukku.lotro.logic.effects.StackActionEffect; +import com.gempukku.lotro.logic.timing.Effect; +import com.gempukku.lotro.logic.timing.UnrespondableEffect; +import org.json.simple.JSONObject; + +public class Duplicate implements EffectAppenderProducer { + @Override + public EffectAppender createEffectAppender(JSONObject effectObject, CardGenerationEnvironment environment) throws InvalidCardDefinitionException { + FieldUtils.validateAllowedFields(effectObject, "amount", "effect"); + + final ValueSource amountSource = ValueResolver.resolveEvaluator(effectObject.get("amount"), 1, environment); + final JSONObject effect = (JSONObject) effectObject.get("effect"); + + final EffectAppender effectAppender = environment.getEffectAppenderFactory().getEffectAppender(effect, environment); + + return new DelayedAppender() { + @Override + protected Effect createEffect(boolean cost, CostToEffectAction action, ActionContext actionContext) { + final int count = amountSource.getEvaluator(actionContext).evaluateExpression(actionContext.getGame(), null); + if (count > 0) { + SubAction subAction = new SubAction(action); + for (int i = 0; i < count; i++) + effectAppender.appendEffect(cost, subAction, actionContext); + return new StackActionEffect(subAction); + } else { + return new UnrespondableEffect() { + @Override + protected void doPlayEffect(LotroGame game) { + // Ignore + } + }; + } + } + + @Override + public boolean isPlayableInFull(ActionContext actionContext) { + 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 8611ac3e9..c7fe9e9f9 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 @@ -2,11 +2,13 @@ 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.FilterableSource; 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.cards.build.field.effect.appender.resolver.CardResolver; +import com.gempukku.lotro.common.Filterable; import com.gempukku.lotro.filters.Filters; import com.gempukku.lotro.game.PhysicalCard; import com.gempukku.lotro.game.state.LotroGame; @@ -16,6 +18,7 @@ import com.gempukku.lotro.logic.effects.StackActionEffect; import com.gempukku.lotro.logic.modifiers.ModifierFlag; import com.gempukku.lotro.logic.modifiers.evaluator.ConstantEvaluator; import com.gempukku.lotro.logic.timing.Effect; +import com.gempukku.lotro.logic.timing.ExtraFilters; import com.gempukku.lotro.logic.timing.UnrespondableEffect; import org.json.simple.JSONObject; @@ -24,18 +27,35 @@ import java.util.Collection; public class PlayCardFromDiscard implements EffectAppenderProducer { @Override public EffectAppender createEffectAppender(JSONObject effectObject, CardGenerationEnvironment environment) throws InvalidCardDefinitionException { - FieldUtils.validateAllowedFields(effectObject, "filter", "removedTwilight"); + FieldUtils.validateAllowedFields(effectObject, "filter", "on", "removedTwilight"); final String filter = FieldUtils.getString(effectObject.get("filter"), "filter"); + final String onFilter = FieldUtils.getString(effectObject.get("on"), "on"); final int removedTwilight = FieldUtils.getInteger(effectObject.get("removedTwilight"), "removedTwilight", 0); + final FilterableSource onFilterableSource = (onFilter != null) ? environment.getFilterFactory().generateFilter(onFilter, environment) : null; + MultiEffectAppender result = new MultiEffectAppender(); result.setPlayabilityCheckedForEffect(true); result.addEffectAppender( CardResolver.resolveCardsInDiscard(filter, - (actionContext) -> Filters.playable(actionContext.getGame()), - (actionContext) -> Filters.playable(actionContext.getGame(), removedTwilight, 0, false, false), + (actionContext) -> { + if (onFilterableSource != null) { + final Filterable onFilterable = onFilterableSource.getFilterable(actionContext); + return Filters.and(Filters.playable(actionContext.getGame()), ExtraFilters.attachableTo(actionContext.getGame(), onFilterable)); + } + + return Filters.playable(actionContext.getGame()); + }, + (actionContext) -> { + if (onFilterableSource != null) { + final Filterable onFilterable = onFilterableSource.getFilterable(actionContext); + return Filters.and(Filters.playable(actionContext.getGame(), removedTwilight, 0, false, false), ExtraFilters.attachableTo(actionContext.getGame(), onFilterable)); + } + + return Filters.playable(actionContext.getGame(), removedTwilight, 0, false, false); + }, new ConstantEvaluator(1), "_temp", "you", "Choose card to play", environment)); result.addEffectAppender( new DelayedAppender() { @@ -43,7 +63,9 @@ public class PlayCardFromDiscard implements EffectAppenderProducer { protected Effect createEffect(boolean cost, CostToEffectAction action, ActionContext actionContext) { final Collection cardsToPlay = actionContext.getCardsFromMemory("_temp"); if (cardsToPlay.size() == 1) { - final CostToEffectAction playCardAction = PlayUtils.getPlayCardAction(actionContext.getGame(), cardsToPlay.iterator().next(), 0, Filters.any, false); + Filterable onFilterable = (onFilterableSource != null) ? onFilterableSource.getFilterable(actionContext) : Filters.any; + + final CostToEffectAction playCardAction = PlayUtils.getPlayCardAction(actionContext.getGame(), cardsToPlay.iterator().next(), 0, onFilterable, false); return new StackActionEffect(playCardAction); } else { return new UnrespondableEffect() { 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 e7feafc7a..b291a3073 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 @@ -106,8 +106,10 @@ public class ValueResolver { }; } else if (type.equalsIgnoreCase("forEachYouCanSpot")) { 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(filterableSource.getFilterable(actionContext)); + return actionContext -> new CountSpottableEvaluator(over, limit, filterableSource.getFilterable(actionContext)); } else if (type.equalsIgnoreCase("forEachInHand")) { final String filter = FieldUtils.getString(object.get("filter"), "filter"); final FilterableSource filterableSource = environment.getFilterFactory().generateFilter(filter, environment); diff --git a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/game/LotroCardBlueprintLibrary.java b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/game/LotroCardBlueprintLibrary.java index 41215d5ea..36581d5e0 100644 --- a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/game/LotroCardBlueprintLibrary.java +++ b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/game/LotroCardBlueprintLibrary.java @@ -60,11 +60,13 @@ public class LotroCardBlueprintLibrary { final Set allCards = setDefinition.getAllCards(); for (String blueprintId : allCards) { if (getBaseBlueprintId(blueprintId).equals(blueprintId)) { - try { - // Ensure it's loaded - LotroCardBlueprint cardBlueprint = getLotroCardBlueprint(blueprintId); - } catch (CardNotFoundException exp) { - throw new RuntimeException("Unable to start the server, due to invalid (missing) card definition - " + blueprintId); + if (!_blueprintMap.containsKey(blueprintId)) { + try { + // Ensure it's loaded + LotroCardBlueprint cardBlueprint = getLotroCardBlueprint(blueprintId); + } catch (CardNotFoundException exp) { + throw new RuntimeException("Unable to start the server, due to invalid (missing) card definition - " + blueprintId); + } } } }