From 86bd454dedbada494018c9b682486e7e6e5b9ba6 Mon Sep 17 00:00:00 2001 From: "marcin.sciesinski" Date: Tue, 3 Sep 2019 21:55:49 -0700 Subject: [PATCH] Added all Gandalf cards from Second Edition --- .../main/web/cards/set40/set40-gandalf.json | 162 ++++++++++++++++++ .../field/effect/EffectAppenderFactory.java | 4 +- .../effect/appender/PlayCardFromDiscard.java | 18 +- .../effect/appender/PlayCardFromDrawDeck.java | 71 ++++++++ .../effect/appender/PlayCardFromHand.java | 19 +- .../field/effect/appender/PlayNextSite.java | 46 +++++ .../field/effect/filter/FilterFactory.java | 14 +- 7 files changed, 323 insertions(+), 11 deletions(-) create mode 100644 gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/effect/appender/PlayCardFromDrawDeck.java create mode 100644 gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/effect/appender/PlayNextSite.java 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 30c4abd5f..5f133c121 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 @@ -732,6 +732,32 @@ ] } }, + "40_84": { + "title": "Mysterious Wizard", + "culture": "gandalf", + "cost": 2, + "type": "event", + "keyword": [ + "skirmish", + "spell" + ], + "effects": { + "type": "event", + "effect": { + "type": "modifyStrength", + "filter": "choose(name(Gandalf))", + "amount": { + "type": "condition", + "condition": { + "type": "canSpotBurdens", + "amount": 5 + }, + "yes": 2, + "no": 4 + } + } + } + }, "40_86": { "title": "Protector of the West", "culture": "gandalf", @@ -759,6 +785,142 @@ ] } }, + "40_87": { + "title": "Roll of Thunder", + "culture": "gandalf", + "cost": 3, + "type": "event", + "keyword": [ + "fellowship", + "maneuver" + ], + "condition": { + "type": "canSpot", + "filter": "name(Gandalf)" + }, + "effects": { + "type": "event", + "effect": { + "type": "discard", + "filter": "choose(side(shadow),or(possession,artifact))" + } + } + }, + "40_88": { + "title": "Speak \"Friend\" and Enter", + "culture": "gandalf", + "cost": 1, + "type": "event", + "keyword": [ + "fellowship", + "regroup" + ], + "condition": { + "type": "canSpot", + "filter": "name(Gandalf)" + }, + "effects": { + "type": "event", + "effect": [ + { + "type": "playNextSite", + "memorize": "playedSite" + }, + { + "type": "conditional", + "condition": { + "type": "memoryMatches", + "memory": "playedSite", + "filter": "underground" + }, + "effect": { + "type": "drawCards" + } + } + ] + } + }, + "40_89": { + "title": "Trusted Advisor", + "culture": "gandalf", + "cost": 1, + "type": "event", + "keyword": "fellowship", + "condition": { + "type": "canSpot", + "filter": "name(Gandalf)" + }, + "effects": { + "type": "event", + "cost": { + "type": "exert", + "filter": "choose(companion,not(culture(gandalf)))", + "memorize": "exertedCompanion" + }, + "effect": { + "type": "putCardsFromDeckIntoHand", + "filter": "choose(cultureFromMemory(exertedCompanion))" + } + } + }, + "40_90": { + "title": "A Wizard is Never Late", + "culture": "gandalf", + "cost": 1, + "type": "event", + "keyword": "fellowship", + "effects": { + "type": "event", + "effect": { + "type": "playCardFromDrawDeck", + "filter": "choose(culture(gandalf),character)" + } + } + }, + "40_91": { + "title": "Wizard Staff", + "culture": "gandalf", + "cost": 2, + "type": "possession", + "possession": "hand weapon", + "strength": 1, + "target": "wizard", + "effects": { + "type": "activated", + "phase": "skirmish", + "cost": { + "type": "exert", + "filter": "choose(bearer)" + }, + "effect": { + "type": "modifyStrength", + "filter": "choose(minion)", + "amount": -3 + } + } + }, + "40_311": { + "title": "*Gandalf", + "subtitle": "Wisest of the Istari", + "culture": "gandalf", + "cost": 4, + "type": "companion", + "race": "wizard", + "strength": 7, + "vitality": 4, + "resistance": 8, + "effects": { + "type": "trigger", + "trigger": { + "type": "played", + "filter": "culture(gandalf),spell" + }, + "optional": true, + "effect": { + "type": "drawCards" + } + } + }, "40_312": { "title": "Go Back to the Shadow!", "culture": "gandalf", 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 ef26755ae..5ed29b2cb 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 @@ -47,7 +47,9 @@ public class EffectAppenderFactory { effectAppenderProducers.put("putcardsfromdiscardintohand", new PutCardsFromDiscardIntoHand()); effectAppenderProducers.put("addtrigger", new AddTrigger()); effectAppenderProducers.put("stackplayedevent", new StackPlayedEvent()); + effectAppenderProducers.put("play", new PlayCardFromHand()); effectAppenderProducers.put("playcardfromdiscard", new PlayCardFromDiscard()); + effectAppenderProducers.put("playcardfromdrawdeck", new PlayCardFromDrawDeck()); effectAppenderProducers.put("reducearcherytotal", new ReduceArcheryTotal()); effectAppenderProducers.put("revealtopcardsofdrawdeck", new RevealTopCardsOfDrawDeck()); effectAppenderProducers.put("optional", new Optional()); @@ -58,7 +60,6 @@ public class EffectAppenderFactory { effectAppenderProducers.put("cantbeassignedtoskirmish", new CantBeAssignedToSkirmish()); effectAppenderProducers.put("preventable", new PreventableAppenderProducer()); effectAppenderProducers.put("cantbeoverwhelmedmultiplier", new CantBeOverwhelmedMultiplier()); - effectAppenderProducers.put("play", new PlayCardFromHand()); effectAppenderProducers.put("cancelskirmish", new CancelSkirmish()); effectAppenderProducers.put("discardfromhand", new DiscardCardsFromHand()); effectAppenderProducers.put("chooseandremovetwilight", new ChooseAndRemoveTwilight()); @@ -74,6 +75,7 @@ public class EffectAppenderFactory { effectAppenderProducers.put("revealrandomcardsfromhand", new RevealRandomCardsFromHand()); effectAppenderProducers.put("putcardsfromdeckintohand", new PutCardsFromDeckIntoHand()); effectAppenderProducers.put("addmodifier", new AddModifier()); + effectAppenderProducers.put("playnextsite", new PlayNextSite()); } 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/PlayCardFromDiscard.java b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/effect/appender/PlayCardFromDiscard.java index 8b262c9fc..8611ac3e9 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 @@ -16,8 +16,11 @@ 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.UnrespondableEffect; import org.json.simple.JSONObject; +import java.util.Collection; + public class PlayCardFromDiscard implements EffectAppenderProducer { @Override public EffectAppender createEffectAppender(JSONObject effectObject, CardGenerationEnvironment environment) throws InvalidCardDefinitionException { @@ -38,9 +41,18 @@ public class PlayCardFromDiscard implements EffectAppenderProducer { new DelayedAppender() { @Override protected Effect createEffect(boolean cost, CostToEffectAction action, ActionContext actionContext) { - final PhysicalCard cardToPlay = actionContext.getCardFromMemory("_temp"); - final CostToEffectAction playCardAction = PlayUtils.getPlayCardAction(actionContext.getGame(), cardToPlay, 0, Filters.any, false); - return new StackActionEffect(playCardAction); + final Collection cardsToPlay = actionContext.getCardsFromMemory("_temp"); + if (cardsToPlay.size() == 1) { + final CostToEffectAction playCardAction = PlayUtils.getPlayCardAction(actionContext.getGame(), cardsToPlay.iterator().next(), 0, Filters.any, false); + return new StackActionEffect(playCardAction); + } else { + return new UnrespondableEffect() { + @Override + protected void doPlayEffect(LotroGame game) { + // do nothing + } + }; + } } @Override diff --git a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/effect/appender/PlayCardFromDrawDeck.java b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/effect/appender/PlayCardFromDrawDeck.java new file mode 100644 index 000000000..3dede8169 --- /dev/null +++ b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/effect/appender/PlayCardFromDrawDeck.java @@ -0,0 +1,71 @@ +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.cards.build.field.effect.appender.resolver.CardResolver; +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.CostToEffectAction; +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.UnrespondableEffect; +import org.json.simple.JSONObject; + +import java.util.Collection; + +public class PlayCardFromDrawDeck implements EffectAppenderProducer { + @Override + public EffectAppender createEffectAppender(JSONObject effectObject, CardGenerationEnvironment environment) throws InvalidCardDefinitionException { + FieldUtils.validateAllowedFields(effectObject, "filter"); + + final String filter = FieldUtils.getString(effectObject.get("filter"), "filter"); + + MultiEffectAppender result = new MultiEffectAppender(); + result.setPlayabilityCheckedForEffect(true); + + result.addEffectAppender( + CardResolver.resolveCardsInDeck(filter, + (actionContext) -> Filters.playable(actionContext.getGame()), + (actionContext) -> Filters.playable(actionContext.getGame()), + new ConstantEvaluator(1), "_temp", "you", "Choose card to play", environment)); + result.addEffectAppender( + new DelayedAppender() { + @Override + 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); + return new StackActionEffect(playCardAction); + } else { + return new UnrespondableEffect() { + @Override + protected void doPlayEffect(LotroGame game) { + // do nothing + } + }; + } + } + + @Override + public boolean isPlayableInFull(ActionContext actionContext) { + final LotroGame game = actionContext.getGame(); + return !game.getModifiersQuerying().hasFlagActive(game, ModifierFlag.CANT_PLAY_FROM_DISCARD_OR_DECK); + } + + @Override + public boolean isPlayabilityCheckedForEffect() { + return true; + } + }); + + return result; + } +} diff --git a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/effect/appender/PlayCardFromHand.java b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/effect/appender/PlayCardFromHand.java index e45a27615..f421b7a17 100644 --- a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/effect/appender/PlayCardFromHand.java +++ b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/effect/appender/PlayCardFromHand.java @@ -9,13 +9,17 @@ import com.gempukku.lotro.cards.build.field.effect.EffectAppenderProducer; import com.gempukku.lotro.cards.build.field.effect.appender.resolver.CardResolver; 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.CostToEffectAction; import com.gempukku.lotro.logic.effects.StackActionEffect; import com.gempukku.lotro.logic.modifiers.evaluator.ConstantEvaluator; import com.gempukku.lotro.logic.timing.Effect; +import com.gempukku.lotro.logic.timing.UnrespondableEffect; import org.json.simple.JSONObject; +import java.util.Collection; + public class PlayCardFromHand implements EffectAppenderProducer { @Override public EffectAppender createEffectAppender(JSONObject effectObject, CardGenerationEnvironment environment) throws InvalidCardDefinitionException { @@ -34,9 +38,18 @@ public class PlayCardFromHand implements EffectAppenderProducer { new DelayedAppender() { @Override protected Effect createEffect(boolean cost, CostToEffectAction action, ActionContext actionContext) { - final PhysicalCard cardToPlay = actionContext.getCardFromMemory("_temp"); - final CostToEffectAction playCardAction = PlayUtils.getPlayCardAction(actionContext.getGame(), cardToPlay, 0, Filters.any, false); - return new StackActionEffect(playCardAction); + final Collection cardsToPlay = actionContext.getCardsFromMemory("_temp"); + if (cardsToPlay.size() == 1) { + final CostToEffectAction playCardAction = PlayUtils.getPlayCardAction(actionContext.getGame(), cardsToPlay.iterator().next(), 0, Filters.any, false); + return new StackActionEffect(playCardAction); + } else { + return new UnrespondableEffect() { + @Override + protected void doPlayEffect(LotroGame game) { + // do nothing + } + }; + } } }); diff --git a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/effect/appender/PlayNextSite.java b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/effect/appender/PlayNextSite.java new file mode 100644 index 000000000..295da5510 --- /dev/null +++ b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/effect/appender/PlayNextSite.java @@ -0,0 +1,46 @@ +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.game.PhysicalCard; +import com.gempukku.lotro.game.state.LotroGame; +import com.gempukku.lotro.logic.actions.CostToEffectAction; +import com.gempukku.lotro.logic.effects.PlayNextSiteEffect; +import com.gempukku.lotro.logic.timing.Effect; +import org.json.simple.JSONObject; + +public class PlayNextSite 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 + public boolean isPlayableInFull(ActionContext actionContext) { + final LotroGame game = actionContext.getGame(); + final int currentSiteNumber = game.getGameState().getCurrentSiteNumber(); + final PhysicalCard nextSite = game.getGameState().getSite(currentSiteNumber + 1); + return currentSiteNumber < 9 + && (nextSite == null || game.getModifiersQuerying().canReplaceSite(game, actionContext.getPerformingPlayer(), nextSite)); + } + + @Override + protected Effect createEffect(boolean cost, CostToEffectAction action, ActionContext actionContext) { + return new PlayNextSiteEffect(action, actionContext.getPerformingPlayer()) { + @Override + protected void sitePlayedCallback(PhysicalCard site) { + if (memorize != null) { + actionContext.setCardMemory(memorize, site); + } + } + }; + } + }; + } +} 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 49f54307b..1bb1ebcfe 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 @@ -5,12 +5,10 @@ import com.gempukku.lotro.cards.build.field.effect.appender.resolver.ValueResolv 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.logic.timing.results.CharacterLostSkirmishResult; -import java.util.HashMap; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; +import java.util.*; public class FilterFactory { private Map simpleFilters = new HashMap<>(); @@ -33,6 +31,7 @@ public class FilterFactory { simpleFilters.put("self", (actionContext) -> actionContext.getSource()); simpleFilters.put("your", (actionContext) -> Filters.owner(actionContext.getPerformingPlayer())); simpleFilters.put("bearer", (actionContext -> Filters.hasAttached(actionContext.getSource()))); + simpleFilters.put("character", (actionContext) -> Filters.character); simpleFilters.put("weapon", (actionContext) -> Filters.weapon); simpleFilters.put("wounded", (actionContext) -> Filters.wounded); simpleFilters.put("unwounded", (actionContext) -> Filters.unwounded); @@ -54,6 +53,13 @@ public class FilterFactory { 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("side", (parameter, environment) -> { final Side side = Side.valueOf(parameter.toUpperCase().replace(" ", "_")); if (side == null)