From d3a383cc0b6a3ce99e7b2b575e01c277c9473d2c Mon Sep 17 00:00:00 2001 From: "marcin.sciesinski" Date: Wed, 4 Sep 2019 19:51:53 -0700 Subject: [PATCH] Couple of Isengard cards --- .../main/web/cards/set40/set40-isengard.json | 349 ++++++++++++++++++ .../cards/set40/isengard/Card40_133.java | 41 -- .../cards/set40/isengard/Card40_134.java | 69 ---- .../cards/set40/isengard/Card40_135.java | 65 ---- .../cards/set40/isengard/Card40_136.java | 51 --- .../cards/set40/isengard/Card40_137.java | 77 ---- .../cards/set40/isengard/Card40_138.java | 65 ---- .../cards/set40/isengard/Card40_139.java | 52 --- .../cards/set40/isengard/Card40_140.java | 74 ---- .../cards/set40/isengard/Card40_141.java | 49 --- .../cards/set40/isengard/Card40_142.java | 69 ---- .../field/effect/EffectAppenderFactory.java | 1 + .../effect/appender/PlayCardFromStacked.java | 61 +++ .../appender/resolver/CardResolver.java | 19 +- .../appender/resolver/ValueResolver.java | 9 +- .../field/effect/filter/FilterFactory.java | 1 + .../field/effect/modifier/CantTakeWounds.java | 25 ++ .../modifier/ModifierSourceFactory.java | 2 + .../field/effect/modifier/RemoveKeyword.java | 32 ++ .../requirement/NotRequirementProducer.java | 20 + .../requirement/RequirementFactory.java | 1 + 21 files changed, 517 insertions(+), 615 deletions(-) delete mode 100644 gemp-lotr/gemp-lotr-cards/src/main/java/com/gempukku/lotro/cards/set40/isengard/Card40_133.java delete mode 100644 gemp-lotr/gemp-lotr-cards/src/main/java/com/gempukku/lotro/cards/set40/isengard/Card40_134.java delete mode 100644 gemp-lotr/gemp-lotr-cards/src/main/java/com/gempukku/lotro/cards/set40/isengard/Card40_135.java delete mode 100644 gemp-lotr/gemp-lotr-cards/src/main/java/com/gempukku/lotro/cards/set40/isengard/Card40_136.java delete mode 100644 gemp-lotr/gemp-lotr-cards/src/main/java/com/gempukku/lotro/cards/set40/isengard/Card40_137.java delete mode 100644 gemp-lotr/gemp-lotr-cards/src/main/java/com/gempukku/lotro/cards/set40/isengard/Card40_138.java delete mode 100644 gemp-lotr/gemp-lotr-cards/src/main/java/com/gempukku/lotro/cards/set40/isengard/Card40_139.java delete mode 100644 gemp-lotr/gemp-lotr-cards/src/main/java/com/gempukku/lotro/cards/set40/isengard/Card40_140.java delete mode 100644 gemp-lotr/gemp-lotr-cards/src/main/java/com/gempukku/lotro/cards/set40/isengard/Card40_141.java delete mode 100644 gemp-lotr/gemp-lotr-cards/src/main/java/com/gempukku/lotro/cards/set40/isengard/Card40_142.java create mode 100644 gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/effect/appender/PlayCardFromStacked.java create mode 100644 gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/effect/modifier/CantTakeWounds.java create mode 100644 gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/effect/modifier/RemoveKeyword.java create mode 100644 gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/effect/requirement/NotRequirementProducer.java diff --git a/gemp-lotr/gemp-lotr-async/src/main/web/cards/set40/set40-isengard.json b/gemp-lotr/gemp-lotr-async/src/main/web/cards/set40/set40-isengard.json index 6c424b510..8ab5ce157 100644 --- a/gemp-lotr/gemp-lotr-async/src/main/web/cards/set40/set40-isengard.json +++ b/gemp-lotr/gemp-lotr-async/src/main/web/cards/set40/set40-isengard.json @@ -312,6 +312,355 @@ } ] }, + "40_133": { + "title": "Relentless Uruk", + "culture": "isengard", + "cost": 4, + "type": "minion", + "race": "uruk-hai", + "strength": 9, + "vitality": 2, + "site": 5, + "keyword": "damage+1", + "effects": { + "type": "modifier", + "modifier": { + "type": "addKeyword", + "condition": { + "type": "location", + "filter": "battleground" + }, + "filter": "self", + "keyword": "fierce" + } + } + }, + "40_134": { + "title": "*Saruman", + "subtitle": "Mind of Metal", + "culture": "isengard", + "cost": 4, + "type": "minion", + "race": "wizard", + "strength": 8, + "vitality": 8, + "site": 4, + "keyword": "cunning", + "effects": [ + { + "type": "trigger", + "trigger": { + "type": "startOfPhase", + "phase": "maneuver" + }, + "optional": true, + "effect": { + "type": "addTwilight", + "amount": { + "type": "forEachThreat" + } + } + }, + { + "type": "activated", + "phase": "shadow", + "cost": { + "type": "exert", + "filter": "self" + }, + "effect": { + "type": "playCardFromDiscard", + "filter": "choose(name(Saruman's Staff))" + } + } + ] + }, + "40_135": { + "title": "*Saruman", + "subtitle": "The White Wizard", + "culture": "isengard", + "cost": 4, + "type": "minion", + "race": "wizard", + "strength": 8, + "vitality": 4, + "site": 4, + "effects": { + "type": "activated", + "phase": "skirmish", + "cost": [ + { + "type": "exert", + "filter": "choose(name(Saruman))" + }, + { + "type": "discardStackedCards", + "on": "culture(isengard),artifact", + "filter": "choose(spell)" + } + ], + "effect": { + "type": "preventable", + "player": "fp", + "effect": { + "type": "wound", + "filter": "choose(companion,inSkirmishAgainst(name(Saruman)))" + }, + "cost": { + "type": "addThreats", + "player": "fp" + } + } + } + }, + "40_136": { + "title": "Saruman's Ambition", + "culture": "isengard", + "cost": 0, + "type": "condition", + "keyword": "support area", + "effects": [ + { + "type": "modifier", + "modifier": { + "type": "modifyCost", + "amount": -1, + "filter": "culture(isengard),event" + } + }, + { + "type": "activated", + "phase": "skirmish", + "cost": { + "type": "discard", + "filter": "self" + }, + "effect": { + "type": "modifyStrength", + "filter": "choose(uruk-hai)", + "amount": 2 + } + } + ] + }, + "40_137": { + "title": "*Saruman's Staff", + "subtitle": "Instrument of War", + "culture": "isengard", + "cost": 2, + "type": "artifact", + "possession": "staff", + "strength": 2, + "vitality": 1, + "target": "name(Saruman)", + "effects": [ + { + "type": "modifier", + "modifier": { + "type": "removeKeyword", + "filter": "bearer", + "keyword": "cunning" + } + }, + { + "type": "modifier", + "modifier": { + "type": "addKeyword", + "filter": "bearer", + "keyword": "fierce" + } + }, + { + "type": "activatedTrigger", + "trigger": { + "type": "aboutToTakeWound", + "filter": "bearer" + }, + "cost": { + "type": "removeThreats" + }, + "effect": { + "type": "preventWound", + "filter": "choose(bearer)" + } + } + ] + }, + "40_138": { + "title": "Seeking My Counsel", + "culture": "isengard", + "cost": 2, + "type": "event", + "keyword": "shadow", + "effects": { + "type": "event", + "cost": { + "type": "choice", + "texts": [ + "Play Saruman from your draw deck", + "Play Saruman from your discard pile" + ], + "effects": [ + { + "type": "playCardFromDrawDeck", + "filter": "choose(name(Saruman))" + }, + { + "type": "playCardFromDiscard", + "filter": "choose(name(Saruman))" + } + ] + }, + "effect": { + "type": "addThreats", + "amount": { + "type": "forRegionNumber" + } + } + } + }, + "40_139": { + "title": "Sword of Orthanc", + "culture": "isengard", + "cost": 1, + "type": "possession", + "possession": "hand weapon", + "strength": 2, + "target": "uruk-hai", + "effects": { + "type": "modifier", + "modifier": { + "type": "cantTakeWounds", + "filter": "bearer", + "condition": { + "type": "not", + "condition": { + "type": "phase", + "phase": "skirmish" + } + } + } + } + }, + "40_140": { + "title": "*Ten Thousand Strong", + "culture": "isengard", + "cost": 0, + "type": "condition", + "target": "site", + "effects": [ + { + "type": "extraCost", + "cost": { + "type": "exert", + "filter": "choose(uruk-hai)" + } + }, + { + "type": "modifier", + "modifier": { + "type": "addKeyword", + "filter": "uruk-hai", + "keyword": "fierce", + "condition": { + "type": "location", + "filter": "hasAttached(self)" + } + } + }, + { + "type": "activated", + "phase": "shadow", + "condition": { + "type": "canSpot", + "filter": "uruk-hai" + }, + "cost": { + "type": "discard", + "filter": "self" + }, + "effect": { + "type": "playCardFromDiscard", + "filter": "choose(uruk-hai)" + } + } + ] + }, + "40_141": { + "title": "The Hour Grows Late", + "culture": "isengard", + "cost": 1, + "type": "event", + "keyword": [ + "maneuver", + "spell" + ], + "condition": { + "type": "canSpot", + "filter": "name(Saruman)" + }, + "effects": { + "type": "event", + "cost": { + "type": "spot", + "filter": "choose(exhausted,companion)", + "memorize": "exhaustedCompanion" + }, + "effect": { + "type": "addThreats", + "amount": { + "type": "forEachWound", + "filter": "memory(exhaustedCompanion)" + } + } + } + }, + "40_142": { + "title": "*Throne of Orthanc", + "culture": "isengard", + "cost": 2, + "type": "artifact", + "keyword": "support area", + "effects": [ + { + "type": "modifier", + "modifier": { + "type": "modifyCost", + "filter": "culture(isengard),event", + "amount": { + "type": "multiply", + "multiplier": -1, + "source": { + "type": "countStacked", + "on": "self", + "filter": "minion" + } + } + } + }, + { + "type": "activated", + "phase": "regroup", + "effect": { + "type": "stackCards", + "filter": "choose(name(Saruman),not(exhausted))", + "where": "self" + } + }, + { + "type": "activated", + "phase": "shadow", + "cost": { + "type": "removeThreats" + }, + "effect": { + "type": "playCardFromStacked", + "filter": "choose(name(Saruman))", + "on": "self" + } + } + ] + }, "40_314": { "title": "Brute Force", "culture": "isengard", diff --git a/gemp-lotr/gemp-lotr-cards/src/main/java/com/gempukku/lotro/cards/set40/isengard/Card40_133.java b/gemp-lotr/gemp-lotr-cards/src/main/java/com/gempukku/lotro/cards/set40/isengard/Card40_133.java deleted file mode 100644 index b815d23a8..000000000 --- a/gemp-lotr/gemp-lotr-cards/src/main/java/com/gempukku/lotro/cards/set40/isengard/Card40_133.java +++ /dev/null @@ -1,41 +0,0 @@ -package com.gempukku.lotro.cards.set40.isengard; - -import com.gempukku.lotro.common.Culture; -import com.gempukku.lotro.common.Keyword; -import com.gempukku.lotro.common.Race; -import com.gempukku.lotro.game.PhysicalCard; -import com.gempukku.lotro.game.state.LotroGame; -import com.gempukku.lotro.logic.cardtype.AbstractMinion; -import com.gempukku.lotro.logic.modifiers.KeywordModifier; -import com.gempukku.lotro.logic.modifiers.Modifier; -import com.gempukku.lotro.logic.modifiers.condition.LocationCondition; - -import java.util.Collections; -import java.util.List; - -/** - * Title: Relentless Uruk - * Set: Second Edition - * Side: Shadow - * Culture: Isengard - * Twilight Cost: 4 - * Type: Minion - Uruk-hai - * Strength: 9 - * Vitality: 2 - * Home: 5 - * Card Number: 1C133 - * Game Text: Damage +1. While at a battleground, this minion is fierce. - */ -public class Card40_133 extends AbstractMinion { - public Card40_133() { - super(4, 9, 2, 5, Race.URUK_HAI, Culture.ISENGARD, "Relentless Uruk"); - addKeyword(Keyword.DAMAGE, 1); - } - - @Override - public List getInPlayModifiers(LotroGame game, PhysicalCard self) { - KeywordModifier modifier = new KeywordModifier(self, self, - new LocationCondition(Keyword.BATTLEGROUND), Keyword.FIERCE, 1); - return Collections.singletonList(modifier); - } -} diff --git a/gemp-lotr/gemp-lotr-cards/src/main/java/com/gempukku/lotro/cards/set40/isengard/Card40_134.java b/gemp-lotr/gemp-lotr-cards/src/main/java/com/gempukku/lotro/cards/set40/isengard/Card40_134.java deleted file mode 100644 index 90fff2141..000000000 --- a/gemp-lotr/gemp-lotr-cards/src/main/java/com/gempukku/lotro/cards/set40/isengard/Card40_134.java +++ /dev/null @@ -1,69 +0,0 @@ -package com.gempukku.lotro.cards.set40.isengard; - -import com.gempukku.lotro.common.Culture; -import com.gempukku.lotro.common.Keyword; -import com.gempukku.lotro.common.Phase; -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.actions.OptionalTriggerAction; -import com.gempukku.lotro.logic.cardtype.AbstractMinion; -import com.gempukku.lotro.logic.effects.AddTwilightEffect; -import com.gempukku.lotro.logic.effects.SelfExertEffect; -import com.gempukku.lotro.logic.effects.choose.ChooseAndPlayCardFromDiscardEffect; -import com.gempukku.lotro.logic.modifiers.evaluator.ForEachThreatEvaluator; -import com.gempukku.lotro.logic.timing.EffectResult; -import com.gempukku.lotro.logic.timing.PlayConditions; -import com.gempukku.lotro.logic.timing.TriggerConditions; - -import java.util.Collections; -import java.util.List; - -/** - * Title: *Saruman, Mind of Metal - * Set: Second Edition - * Side: Shadow - * Culture: Isengard - * Twilight Cost: 4 - * Type: Minion - Wizard - * Strength: 8 - * Vitality: 4 - * Home: 4 - * Card Number: 1U134 - * Game Text: Cunning. At the beginning of the maneuver phase, you may add (1) for each threat. - * Shadow: Exert Saruman to play Saruman's Staff from your discard pile. - */ -public class Card40_134 extends AbstractMinion { - public Card40_134() { - super(4, 8, 4, 4, Race.WIZARD, Culture.ISENGARD, "Saruman", "Mind of Metal", true); - addKeyword(Keyword.CUNNING); - } - - @Override - public List getOptionalAfterTriggers(String playerId, LotroGame game, EffectResult effectResult, PhysicalCard self) { - if (TriggerConditions.startOfPhase(game, effectResult, Phase.MANEUVER)) { - OptionalTriggerAction action = new OptionalTriggerAction(self); - action.appendEffect( - new AddTwilightEffect(self, new ForEachThreatEvaluator())); - return Collections.singletonList(action); - } - return null; - } - - @Override - public List getPhaseActionsInPlay(String playerId, LotroGame game, PhysicalCard self) { - if (PlayConditions.canUseShadowCardDuringPhase(game, Phase.SHADOW, self, 0) - && PlayConditions.canSelfExert(self, game) - && PlayConditions.canPlayFromDiscard(playerId, game, Filters.name("Saruman's Staff"))) { - ActivateCardAction action = new ActivateCardAction(self); - action.appendCost( - new SelfExertEffect(action, self)); - action.appendEffect( - new ChooseAndPlayCardFromDiscardEffect(playerId, game, Filters.name("Saruman's Staff"))); - return Collections.singletonList(action); - } - return null; - } -} diff --git a/gemp-lotr/gemp-lotr-cards/src/main/java/com/gempukku/lotro/cards/set40/isengard/Card40_135.java b/gemp-lotr/gemp-lotr-cards/src/main/java/com/gempukku/lotro/cards/set40/isengard/Card40_135.java deleted file mode 100644 index 940973415..000000000 --- a/gemp-lotr/gemp-lotr-cards/src/main/java/com/gempukku/lotro/cards/set40/isengard/Card40_135.java +++ /dev/null @@ -1,65 +0,0 @@ -package com.gempukku.lotro.cards.set40.isengard; - -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.GameUtils; -import com.gempukku.lotro.logic.actions.ActivateCardAction; -import com.gempukku.lotro.logic.actions.CostToEffectAction; -import com.gempukku.lotro.logic.cardtype.AbstractMinion; -import com.gempukku.lotro.logic.effects.AddThreatsEffect; -import com.gempukku.lotro.logic.effects.ChooseAndWoundCharactersEffect; -import com.gempukku.lotro.logic.effects.PreventableEffect; -import com.gempukku.lotro.logic.effects.SelfExertEffect; -import com.gempukku.lotro.logic.effects.choose.ChooseAndDiscardStackedCardsEffect; -import com.gempukku.lotro.logic.timing.Effect; -import com.gempukku.lotro.logic.timing.PlayConditions; - -import java.util.Collections; -import java.util.List; - -/** - * Title: *Saruman, The White Wizard - * Set: Second Edition - * Side: Shadow - * Culture: Isengard - * Twilight Cost: 4 - * Type: Minion - Wizard - * Strength: 8 - * Vitality: 4 - * Home: 4 - * Card Number: 1R135 - * Game Text: Skirmish: Exert Saruman and discard a spell stacked on an [ISENGARD] artifact to wound a companion - * skirmishing Saruman. The Free Peoples player may add a threat to prevent this. - */ -public class Card40_135 extends AbstractMinion { - public Card40_135() { - super(4, 8, 4, 4, Race.WIZARD, Culture.ISENGARD, "Saruman", "The White Wizard", true); - } - - @Override - public List getPhaseActionsInPlay(String playerId, LotroGame game, final PhysicalCard self) { - if (PlayConditions.canUseShadowCardDuringPhase(game, Phase.SKIRMISH, self, 0) - && PlayConditions.canExert(self, game, Filters.saruman) - && PlayConditions.canDiscardFromStacked(self, game, playerId, 1, Filters.and(Culture.ISENGARD, CardType.ARTIFACT), Keyword.SPELL)) { - ActivateCardAction action = new ActivateCardAction(self); - action.appendCost( - new SelfExertEffect(action, self)); - action.appendCost( - new ChooseAndDiscardStackedCardsEffect(action, playerId, 1, 1, Filters.and(Culture.ISENGARD, CardType.ARTIFACT), - Keyword.SPELL)); - action.appendEffect( - new PreventableEffect(action, - new ChooseAndWoundCharactersEffect(action, playerId, 1, 1, CardType.COMPANION, Filters.inSkirmishAgainst(self)), - GameUtils.getFreePeoplePlayer(game), new PreventableEffect.PreventionCost() { - @Override - public Effect createPreventionCostForPlayer(CostToEffectAction subAction, String playerId) { - return new AddThreatsEffect(playerId, self, 1); - } - })); - return Collections.singletonList(action); - } - return null; - } -} diff --git a/gemp-lotr/gemp-lotr-cards/src/main/java/com/gempukku/lotro/cards/set40/isengard/Card40_136.java b/gemp-lotr/gemp-lotr-cards/src/main/java/com/gempukku/lotro/cards/set40/isengard/Card40_136.java deleted file mode 100644 index 917012c50..000000000 --- a/gemp-lotr/gemp-lotr-cards/src/main/java/com/gempukku/lotro/cards/set40/isengard/Card40_136.java +++ /dev/null @@ -1,51 +0,0 @@ -package com.gempukku.lotro.cards.set40.isengard; - -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.ActivateCardAction; -import com.gempukku.lotro.logic.cardtype.AbstractPermanent; -import com.gempukku.lotro.logic.effects.SelfDiscardEffect; -import com.gempukku.lotro.logic.effects.choose.ChooseAndAddUntilEOPStrengthBonusEffect; -import com.gempukku.lotro.logic.modifiers.Modifier; -import com.gempukku.lotro.logic.modifiers.TwilightCostModifier; -import com.gempukku.lotro.logic.timing.PlayConditions; - -import java.util.Collections; -import java.util.List; - -/** - * Title: Saruman's Ambition - * Set: Second Edition - * Side: Shadow - * Culture: Isengard - * Twilight Cost: 0 - * Type: Condition - Support Area - * Card Number: 1C136 - * Game Text: The twilight cost of each [ISENGARD] event is -1. Skirmish: Discard this condition to make an Uruk-hai strength +2. - */ -public class Card40_136 extends AbstractPermanent { - public Card40_136() { - super(Side.SHADOW, 0, CardType.CONDITION, Culture.ISENGARD, "Saruman's Ambition"); - } - - @Override - public List getPhaseActionsInPlay(String playerId, LotroGame game, final PhysicalCard self) { - if (PlayConditions.canUseShadowCardDuringPhase(game, Phase.SKIRMISH, self, 0)) { - final ActivateCardAction action = new ActivateCardAction(self); - action.appendCost(new SelfDiscardEffect(self)); - action.appendEffect( - new ChooseAndAddUntilEOPStrengthBonusEffect(action, self, playerId, 2, Race.URUK_HAI)); - - return Collections.singletonList(action); - } - - return null; - } - - @Override - public List getInPlayModifiers(LotroGame game, PhysicalCard self) { -return Collections.singletonList(new TwilightCostModifier(self, Filters.and(Culture.ISENGARD, CardType.EVENT, Filters.owner(self.getOwner())), -1)); -} -} diff --git a/gemp-lotr/gemp-lotr-cards/src/main/java/com/gempukku/lotro/cards/set40/isengard/Card40_137.java b/gemp-lotr/gemp-lotr-cards/src/main/java/com/gempukku/lotro/cards/set40/isengard/Card40_137.java deleted file mode 100644 index c0ed6954d..000000000 --- a/gemp-lotr/gemp-lotr-cards/src/main/java/com/gempukku/lotro/cards/set40/isengard/Card40_137.java +++ /dev/null @@ -1,77 +0,0 @@ -package com.gempukku.lotro.cards.set40.isengard; - -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.ActivateCardAction; -import com.gempukku.lotro.logic.cardtype.AbstractAttachable; -import com.gempukku.lotro.logic.effects.PreventCardEffect; -import com.gempukku.lotro.logic.effects.RemoveThreatsEffect; -import com.gempukku.lotro.logic.effects.WoundCharactersEffect; -import com.gempukku.lotro.logic.modifiers.KeywordModifier; -import com.gempukku.lotro.logic.modifiers.Modifier; -import com.gempukku.lotro.logic.modifiers.RemoveKeywordModifier; -import com.gempukku.lotro.logic.timing.Effect; -import com.gempukku.lotro.logic.timing.PlayConditions; -import com.gempukku.lotro.logic.timing.TriggerConditions; - -import java.util.Arrays; -import java.util.Collections; -import java.util.List; - -/** - * Title: *Saruman's Staff, Instrument of War - * Set: Second Edition - * Side: Shadow - * Culture: Isengard - * Twilight Cost: 2 - * Type: Artifact - Staff - * Strength: +2 - * Vitality: +1 - * Card Number: 1R137 - * Game Text: Bearer must be Saruman. He loses cunning and is fierce. - * Response: If Saruman is about to take a wound, remove a threat to prevent that wound. - */ -public class Card40_137 extends AbstractAttachable { - public Card40_137() { - super(Side.SHADOW, CardType.ARTIFACT, 2, Culture.ISENGARD, PossessionClass.STAFF, "Saruman's Staff", "Instrument of War", true); - } - - @Override - public Filterable getValidTargetFilter(String playerId, LotroGame game, PhysicalCard self) { - return Filters.saruman; - } - - @Override - public List getInPlayModifiers(LotroGame game, PhysicalCard self) { - RemoveKeywordModifier losesCunning = new RemoveKeywordModifier(self, Filters.hasAttached(self), Keyword.CUNNING); - KeywordModifier fierce = new KeywordModifier(self, Filters.hasAttached(self), Keyword.FIERCE); - return Arrays.asList(losesCunning, fierce); - } - - @Override - public List getOptionalInPlayBeforeActions(String playerId, LotroGame game, Effect effect, PhysicalCard self) { - if (TriggerConditions.isGettingWounded(effect, game, Filters.hasAttached(self)) - && PlayConditions.canRemoveThreat(game, self, 1)) { - WoundCharactersEffect woundEffect = (WoundCharactersEffect) effect; - ActivateCardAction action = new ActivateCardAction(self); - action.appendCost( - new RemoveThreatsEffect(self, 1)); - action.appendEffect( - new PreventCardEffect(woundEffect, self.getAttachedTo())); - return Collections.singletonList(action); - } - return null; - } - - @Override - public int getStrength() { - return 2; - } - - @Override - public int getVitality() { - return 1; - } -} diff --git a/gemp-lotr/gemp-lotr-cards/src/main/java/com/gempukku/lotro/cards/set40/isengard/Card40_138.java b/gemp-lotr/gemp-lotr-cards/src/main/java/com/gempukku/lotro/cards/set40/isengard/Card40_138.java deleted file mode 100644 index 5ab753b6a..000000000 --- a/gemp-lotr/gemp-lotr-cards/src/main/java/com/gempukku/lotro/cards/set40/isengard/Card40_138.java +++ /dev/null @@ -1,65 +0,0 @@ -package com.gempukku.lotro.cards.set40.isengard; - -import com.gempukku.lotro.common.Culture; -import com.gempukku.lotro.common.Phase; -import com.gempukku.lotro.common.Side; -import com.gempukku.lotro.filters.Filters; -import com.gempukku.lotro.game.PhysicalCard; -import com.gempukku.lotro.game.state.LotroGame; -import com.gempukku.lotro.logic.GameUtils; -import com.gempukku.lotro.logic.actions.PlayEventAction; -import com.gempukku.lotro.logic.cardtype.AbstractEvent; -import com.gempukku.lotro.logic.effects.AddThreatsEffect; -import com.gempukku.lotro.logic.effects.ChoiceEffect; -import com.gempukku.lotro.logic.effects.choose.ChooseAndPlayCardFromDeckEffect; -import com.gempukku.lotro.logic.effects.choose.ChooseAndPlayCardFromDiscardEffect; -import com.gempukku.lotro.logic.modifiers.evaluator.Evaluator; -import com.gempukku.lotro.logic.timing.Effect; -import com.gempukku.lotro.logic.timing.PlayConditions; - -import java.util.ArrayList; -import java.util.List; - -/** - * Title: Seeking My Counsel - * Set: Second Edition - * Side: Shadow - * Culture: Isengard - * Twilight Cost: 2 - * Type: Event - Shadow - * Card Number: 1R138 - * Game Text: Play Saruman from your draw deck or discard pile to add X threats, where X is the fellowship's current region number. - */ -public class Card40_138 extends AbstractEvent { - public Card40_138() { - super(Side.SHADOW, 2, Culture.ISENGARD, "Seeking My Counsel", Phase.SHADOW); - } - - @Override - public boolean checkPlayRequirements(LotroGame game, PhysicalCard self) { - return (PlayConditions.canPlayFromDeck(self.getOwner(), game, Filters.saruman) - || PlayConditions.canPlayFromDiscard(self.getOwner(), game, Filters.saruman)); - } - - @Override - public PlayEventAction getPlayEventCardAction(String playerId, LotroGame game, PhysicalCard self) { - PlayEventAction action = new PlayEventAction(self); - List possibleCosts = new ArrayList(2); - possibleCosts.add( - new ChooseAndPlayCardFromDeckEffect(playerId, Filters.saruman)); - possibleCosts.add( - new ChooseAndPlayCardFromDiscardEffect(playerId, game, Filters.saruman)); - action.appendCost( - new ChoiceEffect( - action, playerId, possibleCosts)); - action.appendEffect( - new AddThreatsEffect(playerId, self, - new Evaluator() { - @Override - public int evaluateExpression(LotroGame game, PhysicalCard cardAffected) { - return GameUtils.getRegion(game); - } - })); - return action; - } -} diff --git a/gemp-lotr/gemp-lotr-cards/src/main/java/com/gempukku/lotro/cards/set40/isengard/Card40_139.java b/gemp-lotr/gemp-lotr-cards/src/main/java/com/gempukku/lotro/cards/set40/isengard/Card40_139.java deleted file mode 100644 index c5a11f41e..000000000 --- a/gemp-lotr/gemp-lotr-cards/src/main/java/com/gempukku/lotro/cards/set40/isengard/Card40_139.java +++ /dev/null @@ -1,52 +0,0 @@ -package com.gempukku.lotro.cards.set40.isengard; - -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.cardtype.AbstractAttachable; -import com.gempukku.lotro.logic.modifiers.CantTakeWoundsModifier; -import com.gempukku.lotro.logic.modifiers.Modifier; -import com.gempukku.lotro.logic.modifiers.condition.AndCondition; -import com.gempukku.lotro.logic.modifiers.condition.LocationCondition; -import com.gempukku.lotro.logic.modifiers.condition.NotCondition; -import com.gempukku.lotro.logic.modifiers.condition.PhaseCondition; - -import java.util.Collections; -import java.util.List; - -/** - * Title: Sword of Orthanc - * Set: Second Edition - * Side: Shadow - * Culture: Isengard - * Twilight Cost: 1 - * Type: Possession - Hand Weapon - * Strength: +2 - * Card Number: 1C139 - * Game Text: Bearer must be an Uruk-hai. While at a battleground, bearer may only take wounds during skirmishes. - */ -public class Card40_139 extends AbstractAttachable { - public Card40_139() { - super(Side.SHADOW, CardType.POSSESSION, 1, Culture.ISENGARD, PossessionClass.HAND_WEAPON, "Sword of Orthanc"); - } - - @Override - public Filterable getValidTargetFilter(String playerId, LotroGame game, PhysicalCard self) { - return Race.URUK_HAI; - } - - @Override - public int getStrength() { - return 2; - } - - @Override - public List getInPlayModifiers(LotroGame game, PhysicalCard self) { - CantTakeWoundsModifier modifier = new CantTakeWoundsModifier(self, - new AndCondition( - new NotCondition(new PhaseCondition(Phase.SKIRMISH)), - new LocationCondition(Keyword.BATTLEGROUND)), Filters.hasAttached(self)); - return Collections.singletonList(modifier); - } -} diff --git a/gemp-lotr/gemp-lotr-cards/src/main/java/com/gempukku/lotro/cards/set40/isengard/Card40_140.java b/gemp-lotr/gemp-lotr-cards/src/main/java/com/gempukku/lotro/cards/set40/isengard/Card40_140.java deleted file mode 100644 index 97ed8d43d..000000000 --- a/gemp-lotr/gemp-lotr-cards/src/main/java/com/gempukku/lotro/cards/set40/isengard/Card40_140.java +++ /dev/null @@ -1,74 +0,0 @@ -package com.gempukku.lotro.cards.set40.isengard; - -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.ActivateCardAction; -import com.gempukku.lotro.logic.cardtype.AbstractAttachable; -import com.gempukku.lotro.logic.effects.SelfDiscardEffect; -import com.gempukku.lotro.logic.effects.choose.ChooseAndPlayCardFromDiscardEffect; -import com.gempukku.lotro.logic.modifiers.AbstractExtraPlayCostModifier; -import com.gempukku.lotro.logic.modifiers.KeywordModifier; -import com.gempukku.lotro.logic.modifiers.Modifier; -import com.gempukku.lotro.logic.modifiers.condition.LocationCondition; -import com.gempukku.lotro.logic.modifiers.cost.ExertExtraPlayCostModifier; -import com.gempukku.lotro.logic.timing.PlayConditions; - -import java.util.Collections; -import java.util.List; - -/** - * Title: *Ten Thousand Strong - * Set: Second Edition - * Side: Shadow - * Culture: Isengard - * Twilight Cost: 0 - * Type: Condition - Site - * Card Number: 1R140 - * Game Text: To play, exert an Uruk-hai. Uruk-hai are fierce while at this site. - * Shadow: Spot an Uruk-hai and discard this condition to play an Uruk-hai from your discard pile. - */ -public class Card40_140 extends AbstractAttachable { - public Card40_140() { - super(Side.SHADOW, CardType.CONDITION, 0, Culture.ISENGARD, null, "Ten Thousand Strong", null, true); - } - - @Override - public boolean checkPlayRequirements(LotroGame game, PhysicalCard self) { - return PlayConditions.canExert(self, game, Race.URUK_HAI); - } - - @Override - public Filterable getValidTargetFilter(String playerId, LotroGame game, PhysicalCard self) { - return CardType.SITE; - } - - @Override - public List getExtraCostToPlay(LotroGame game, PhysicalCard self) { - return Collections.singletonList( - new ExertExtraPlayCostModifier(self, self, null, Race.URUK_HAI)); - } - - @Override - public List getInPlayModifiers(LotroGame game, PhysicalCard self) { - KeywordModifier modifier = new KeywordModifier(self, Race.URUK_HAI, new LocationCondition(Filters.hasAttached(self)), Keyword.FIERCE, 1); - return Collections.singletonList(modifier); - } - - @Override - public List getPhaseActionsInPlay(String playerId, LotroGame game, PhysicalCard self) { - if (PlayConditions.canUseShadowCardDuringPhase(game, Phase.SHADOW, self, 0) - && PlayConditions.canSpot(game, Race.URUK_HAI) - && PlayConditions.canSelfDiscard(self, game) - && PlayConditions.canPlayFromDiscard(playerId, game, Race.URUK_HAI)) { - ActivateCardAction action = new ActivateCardAction(self); - action.appendCost( - new SelfDiscardEffect(self)); - action.appendEffect( - new ChooseAndPlayCardFromDiscardEffect(playerId, game, Race.URUK_HAI)); - return Collections.singletonList(action); - } - return null; - } -} diff --git a/gemp-lotr/gemp-lotr-cards/src/main/java/com/gempukku/lotro/cards/set40/isengard/Card40_141.java b/gemp-lotr/gemp-lotr-cards/src/main/java/com/gempukku/lotro/cards/set40/isengard/Card40_141.java deleted file mode 100644 index 6d8772d95..000000000 --- a/gemp-lotr/gemp-lotr-cards/src/main/java/com/gempukku/lotro/cards/set40/isengard/Card40_141.java +++ /dev/null @@ -1,49 +0,0 @@ -package com.gempukku.lotro.cards.set40.isengard; - -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.AddThreatsEffect; -import com.gempukku.lotro.logic.effects.ChooseActiveCardEffect; -import com.gempukku.lotro.logic.timing.PlayConditions; - -/** - * Title: The Hour Grows Late - * Set: Second Edition - * Side: Shadow - * Culture: Isengard - * Twilight Cost: 1 - * Type: Event - Maneuver - * Card Number: 1U141 - * Game Text: Spell. Spot Saruman and an exhausted companion to add a threat for each wound on that companion. - */ -public class Card40_141 extends AbstractEvent { - public Card40_141() { - super(Side.SHADOW, 1, Culture.ISENGARD, "The Hour Grows Late", Phase.MANEUVER); - addKeyword(Keyword.SPELL); - } - - @Override - public boolean checkPlayRequirements(LotroGame game, PhysicalCard self) { - return PlayConditions.canSpot(game, Filters.saruman) - && PlayConditions.canSpot(game, CardType.COMPANION, Filters.exhausted); - } - - @Override - public PlayEventAction getPlayEventCardAction(final String playerId, LotroGame game, final PhysicalCard self) { - final PlayEventAction action = new PlayEventAction(self); - action.appendEffect( - new ChooseActiveCardEffect(self, playerId, "Choose exhausted companion", CardType.COMPANION, Filters.exhausted) { - @Override - protected void cardSelected(LotroGame game, PhysicalCard card) { - final int wounds = game.getGameState().getWounds(card); - action.appendEffect( - new AddThreatsEffect(playerId, self, wounds)); - } - }); - return action; - } -} diff --git a/gemp-lotr/gemp-lotr-cards/src/main/java/com/gempukku/lotro/cards/set40/isengard/Card40_142.java b/gemp-lotr/gemp-lotr-cards/src/main/java/com/gempukku/lotro/cards/set40/isengard/Card40_142.java deleted file mode 100644 index 036d783ea..000000000 --- a/gemp-lotr/gemp-lotr-cards/src/main/java/com/gempukku/lotro/cards/set40/isengard/Card40_142.java +++ /dev/null @@ -1,69 +0,0 @@ -package com.gempukku.lotro.cards.set40.isengard; - -import com.gempukku.lotro.common.CardType; -import com.gempukku.lotro.common.Culture; -import com.gempukku.lotro.common.Phase; -import com.gempukku.lotro.common.Side; -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.cardtype.AbstractPermanent; -import com.gempukku.lotro.logic.effects.RemoveThreatsEffect; -import com.gempukku.lotro.logic.effects.choose.ChooseAndPlayCardFromStackedEffect; -import com.gempukku.lotro.logic.effects.choose.ChooseAndStackCardFromPlayEffect; -import com.gempukku.lotro.logic.modifiers.Modifier; -import com.gempukku.lotro.logic.modifiers.TwilightCostModifier; -import com.gempukku.lotro.logic.modifiers.evaluator.CountStackedEvaluator; -import com.gempukku.lotro.logic.modifiers.evaluator.NegativeEvaluator; -import com.gempukku.lotro.logic.timing.PlayConditions; - -import java.util.Collections; -import java.util.List; - -/** - * Title: *Throne of Orthanc - * Set: Second Edition - * Side: Shadow - * Culture: Isengard - * Twilight Cost: 2 - * Type: Artifact - Support Area - * Card Number: 1R142 - * Game Text: The twilight cost of each [ISENGARD] event is -1 for each minion stacked on this artifact. - * Regroup: If Saruman is not exhausted, stack him on this artifact. - * Shadow: Remove a threat to play Saruman stacked here as if from hand. - */ -public class Card40_142 extends AbstractPermanent { - public Card40_142() { - super(Side.SHADOW, 2, CardType.ARTIFACT, Culture.ISENGARD, "Throne of Orthanc", null, true); - } - - @Override - public List getInPlayModifiers(LotroGame game, PhysicalCard self) { - TwilightCostModifier modifier = new TwilightCostModifier(self, Filters.and(Culture.ISENGARD, CardType.EVENT), null, - new NegativeEvaluator(new CountStackedEvaluator(self, CardType.MINION))); - return Collections.singletonList(modifier); - } - - @Override - public List getPhaseActionsInPlay(String playerId, LotroGame game, PhysicalCard self) { - if (PlayConditions.canUseShadowCardDuringPhase(game, Phase.SHADOW, self, 0) - && PlayConditions.canRemoveThreat(game, self, 1) - && PlayConditions.canPlayFromStacked(playerId, game, self, Filters.saruman)) { - ActivateCardAction action = new ActivateCardAction(self); - action.appendCost( - new RemoveThreatsEffect(self, 1)); - action.appendEffect( - new ChooseAndPlayCardFromStackedEffect(playerId, self, Filters.saruman)); - return Collections.singletonList(action); - } - if (PlayConditions.canUseShadowCardDuringPhase(game, Phase.REGROUP, self, 1) - && PlayConditions.canSpot(game, Filters.saruman, Filters.not(Filters.exhausted))) { - ActivateCardAction action = new ActivateCardAction(self); - action.appendEffect( - new ChooseAndStackCardFromPlayEffect(action, playerId, self, Filters.saruman, Filters.not(Filters.exhausted))); - 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 7b9319a35..d8d110997 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 @@ -51,6 +51,7 @@ public class EffectAppenderFactory { effectAppenderProducers.put("play", new PlayCardFromHand()); effectAppenderProducers.put("playcardfromdiscard", new PlayCardFromDiscard()); effectAppenderProducers.put("playcardfromdrawdeck", new PlayCardFromDrawDeck()); + effectAppenderProducers.put("playcardfromstacked", new PlayCardFromStacked()); effectAppenderProducers.put("reducearcherytotal", new ReduceArcheryTotal()); effectAppenderProducers.put("revealtopcardsofdrawdeck", new RevealTopCardsOfDrawDeck()); effectAppenderProducers.put("optional", new Optional()); diff --git a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/effect/appender/PlayCardFromStacked.java b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/effect/appender/PlayCardFromStacked.java new file mode 100644 index 000000000..9a1d3889a --- /dev/null +++ b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/effect/appender/PlayCardFromStacked.java @@ -0,0 +1,61 @@ +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.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 PlayCardFromStacked implements EffectAppenderProducer { + @Override + public EffectAppender createEffectAppender(JSONObject effectObject, CardGenerationEnvironment environment) throws InvalidCardDefinitionException { + FieldUtils.validateAllowedFields(effectObject, "filter", "on"); + + final String filter = FieldUtils.getString(effectObject.get("filter"), "filter"); + final String onFilter = FieldUtils.getString(effectObject.get("on"), "on"); + + final FilterableSource onFilterableSource = (onFilter != null) ? environment.getFilterFactory().generateFilter(onFilter, environment) : null; + + MultiEffectAppender result = new MultiEffectAppender(); + result.setPlayabilityCheckedForEffect(true); + + result.addEffectAppender( + CardResolver.resolveStackedCards(filter, actionContext -> Filters.playable(actionContext.getGame()), + new ConstantEvaluator(1), onFilterableSource, "_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 + } + }; + } + } + }); + + return result; + } +} 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 f04763f50..483b4ac4a 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 @@ -23,8 +23,15 @@ import java.util.LinkedList; import java.util.List; public class CardResolver { + + public static EffectAppender resolveStackedCards(String type, ValueSource countSource, FilterableSource stackedOn, String memory, String choicePlayer, String choiceText, CardGenerationEnvironment environment) throws InvalidCardDefinitionException { + return resolveStackedCards(type, null, countSource, stackedOn, memory, choicePlayer, choiceText, environment); + } + + public static EffectAppender resolveStackedCards(String type, FilterableSource additionalFilter, ValueSource countSource, FilterableSource stackedOn, + 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(")")); return new DelayedAppender() { @@ -54,12 +61,16 @@ public class CardResolver { final Filterable filterable = filterableSource.getFilterable(actionContext); final Filterable stackedOnFilter = stackedOn.getFilterable(actionContext); + Filterable additionalFilterable = Filters.any; + if (additionalFilter != null) + additionalFilterable = additionalFilter.getFilterable(actionContext); + List choice = new LinkedList<>(); final LotroGame game = actionContext.getGame(); for (PhysicalCard stackedOn : Filters.filterActive(game, stackedOnFilter)) { final List stackedCards = game.getGameState().getStackedCards(stackedOn); - choice.addAll(Filters.filter(stackedCards, game, filterable)); + choice.addAll(Filters.filter(stackedCards, game, filterable, additionalFilterable)); } return choice.size() >= min; @@ -73,7 +84,11 @@ public class CardResolver { int min = countSource.getMinimum(actionContext); int max = countSource.getMaximum(actionContext); - return new ChooseStackedCardsEffect(action, choicePlayerId, min, max, stackedOnFilter, filterable) { + Filterable additionalFilterable = Filters.any; + if (additionalFilter != null) + additionalFilterable = additionalFilter.getFilterable(actionContext); + + return new ChooseStackedCardsEffect(action, choicePlayerId, min, max, stackedOnFilter, Filters.and(filterable, additionalFilterable)) { @Override protected void cardsChosen(LotroGame game, Collection stackedCards) { actionContext.setCardMemory(memory, stackedCards); 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 a626e24a1..7172877d0 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 @@ -7,6 +7,7 @@ import com.gempukku.lotro.common.Keyword; import com.gempukku.lotro.filters.Filters; import com.gempukku.lotro.game.PhysicalCard; import com.gempukku.lotro.game.state.LotroGame; +import com.gempukku.lotro.logic.GameUtils; import com.gempukku.lotro.logic.modifiers.evaluator.*; import org.json.simple.JSONObject; @@ -60,12 +61,16 @@ public class ValueResolver { } return trueValue; }; + } else if (type.equalsIgnoreCase("forRegionNumber")) { + return (actionContext) -> (Evaluator) (game, cardAffected) -> GameUtils.getRegion(actionContext.getGame()); } else if (type.equalsIgnoreCase("forEachInMemory")) { final String memory = FieldUtils.getString(object.get("memory"), "memory"); return (actionContext) -> { final int count = actionContext.getCardsFromMemory(memory).size(); return new ConstantEvaluator(count); }; + } else if (type.equalsIgnoreCase("forEachThreat")) { + return actionContext -> new ForEachThreatEvaluator(); } else if (type.equalsIgnoreCase("forEachWound")) { final String filter = FieldUtils.getString(object.get("filter"), "filter"); final FilterableSource filterableSource = environment.getFilterFactory().generateFilter(filter, environment); @@ -90,12 +95,14 @@ public class ValueResolver { return (actionContext) -> new LimitEvaluator(valueSource.getEvaluator(actionContext), limit); } else if (type.equalsIgnoreCase("countStacked")) { final String on = FieldUtils.getString(object.get("on"), "on"); + final String filter = FieldUtils.getString(object.get("filter"), "filter", "any"); + final FilterableSource filterableSource = environment.getFilterFactory().generateFilter(filter, environment); final FilterableSource onFilter = environment.getFilterFactory().generateFilter(on, environment); return (actionContext) -> { final Filterable on1 = onFilter.getFilterable(actionContext); - return new CountStackedEvaluator(on1, Filters.any); + return new CountStackedEvaluator(on1, filterableSource.getFilterable(actionContext)); }; } else if (type.equalsIgnoreCase("forEachYouCanSpot")) { final String filter = FieldUtils.getString(object.get("filter"), "filter"); 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 98d4c1b4f..577b02966 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 @@ -36,6 +36,7 @@ public class FilterFactory { simpleFilters.put("weapon", (actionContext) -> Filters.weapon); 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("inplay", (actionContext) -> Filters.inPlay); simpleFilters.put("notassignedtoskirmish", diff --git a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/effect/modifier/CantTakeWounds.java b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/effect/modifier/CantTakeWounds.java new file mode 100644 index 000000000..c6ca504f9 --- /dev/null +++ b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/effect/modifier/CantTakeWounds.java @@ -0,0 +1,25 @@ +package com.gempukku.lotro.cards.build.field.effect.modifier; + +import com.gempukku.lotro.cards.build.*; +import com.gempukku.lotro.cards.build.field.FieldUtils; +import com.gempukku.lotro.logic.modifiers.CantTakeWoundsModifier; +import org.json.simple.JSONObject; + +public class CantTakeWounds implements ModifierSourceProducer { + @Override + public ModifierSource getModifierSource(JSONObject object, CardGenerationEnvironment environment) throws InvalidCardDefinitionException { + FieldUtils.validateAllowedFields(object, "filter", "condition"); + + final JSONObject[] conditionArray = FieldUtils.getObjectArray(object.get("condition"), "condition"); + final String filter = FieldUtils.getString(object.get("filter"), "filter", "self"); + + final FilterableSource filterableSource = environment.getFilterFactory().generateFilter(filter, environment); + final Requirement[] requirements = environment.getRequirementFactory().getRequirements(conditionArray, environment); + + return (actionContext) -> { + return new CantTakeWoundsModifier(actionContext.getSource(), + new RequirementCondition(requirements, actionContext), + filterableSource.getFilterable(actionContext)); + }; + } +} diff --git a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/effect/modifier/ModifierSourceFactory.java b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/effect/modifier/ModifierSourceFactory.java index a9336b323..f53fd850b 100644 --- a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/effect/modifier/ModifierSourceFactory.java +++ b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/effect/modifier/ModifierSourceFactory.java @@ -14,10 +14,12 @@ public class ModifierSourceFactory { public ModifierSourceFactory() { modifierProducers.put("addkeyword", new AddKeyword()); + modifierProducers.put("removekeyword", new RemoveKeyword()); modifierProducers.put("archerytotal", new ArcheryTotal()); modifierProducers.put("cantbeexerted", new CantBeExerted()); modifierProducers.put("cantbeoverwhelmedmultiplier", new CantBeOverwhelmedMultiplier()); modifierProducers.put("canttakemorewoundsthan", new CantTakeMoreWoundsThan()); + modifierProducers.put("canttakewounds", new CantTakeWounds()); modifierProducers.put("modifycost", new ModifyCost()); modifierProducers.put("modifyroamingpenalty", new ModifyRoamingPenalty()); modifierProducers.put("modifystrength", new ModifyStrength()); diff --git a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/effect/modifier/RemoveKeyword.java b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/effect/modifier/RemoveKeyword.java new file mode 100644 index 000000000..bf9a48fba --- /dev/null +++ b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/effect/modifier/RemoveKeyword.java @@ -0,0 +1,32 @@ +package com.gempukku.lotro.cards.build.field.effect.modifier; + +import com.gempukku.lotro.cards.build.*; +import com.gempukku.lotro.cards.build.field.FieldUtils; +import com.gempukku.lotro.common.Keyword; +import com.gempukku.lotro.logic.modifiers.Modifier; +import com.gempukku.lotro.logic.modifiers.RemoveKeywordModifier; +import org.json.simple.JSONObject; + +public class RemoveKeyword implements ModifierSourceProducer { + @Override + public ModifierSource getModifierSource(JSONObject object, CardGenerationEnvironment environment) throws InvalidCardDefinitionException { + FieldUtils.validateAllowedFields(object, "filter", "condition", "keyword"); + + final JSONObject[] conditionArray = FieldUtils.getObjectArray(object.get("condition"), "condition"); + final String filter = FieldUtils.getString(object.get("filter"), "filter", "self"); + + Keyword keyword = FieldUtils.getEnum(Keyword.class, object.get("keyword"), "keyword"); + + final FilterableSource filterableSource = environment.getFilterFactory().generateFilter(filter, environment); + final Requirement[] requirements = environment.getRequirementFactory().getRequirements(conditionArray, environment); + + return new ModifierSource() { + @Override + public Modifier getModifier(ActionContext actionContext) { + return new RemoveKeywordModifier(actionContext.getSource(), + filterableSource.getFilterable(actionContext), + new RequirementCondition(requirements, actionContext), keyword); + } + }; + } +} diff --git a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/effect/requirement/NotRequirementProducer.java b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/effect/requirement/NotRequirementProducer.java new file mode 100644 index 000000000..59165f44f --- /dev/null +++ b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/effect/requirement/NotRequirementProducer.java @@ -0,0 +1,20 @@ +package com.gempukku.lotro.cards.build.field.effect.requirement; + +import com.gempukku.lotro.cards.build.CardGenerationEnvironment; +import com.gempukku.lotro.cards.build.InvalidCardDefinitionException; +import com.gempukku.lotro.cards.build.Requirement; +import com.gempukku.lotro.cards.build.field.FieldUtils; +import org.json.simple.JSONObject; + +public class NotRequirementProducer implements RequirementProducer { + @Override + public Requirement getPlayRequirement(JSONObject object, CardGenerationEnvironment environment) throws InvalidCardDefinitionException { + FieldUtils.validateAllowedFields(object, "condition"); + + final Requirement condition = environment.getRequirementFactory().getRequirement((JSONObject) object.get("condition"), environment); + + return (actionContext) -> { + return !condition.accepts(actionContext); + }; + } +} diff --git a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/effect/requirement/RequirementFactory.java b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/effect/requirement/RequirementFactory.java index 57aade283..c0f54149f 100644 --- a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/effect/requirement/RequirementFactory.java +++ b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/effect/requirement/RequirementFactory.java @@ -13,6 +13,7 @@ public class RequirementFactory { private Map requirementProducers = new HashMap<>(); public RequirementFactory() { + requirementProducers.put("not", new NotRequirementProducer()); requirementProducers.put("canspot", new CanSpot()); requirementProducers.put("canspotburdens", new CanSpotBurdens()); requirementProducers.put("controlssite", new ControlsSite());