Playing cards from discard
This commit is contained in:
@@ -758,6 +758,88 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"40_27": {
|
||||
"title": "*Second Wind",
|
||||
"side": "free people",
|
||||
"culture": "dwarven",
|
||||
"cost": 2,
|
||||
"type": "condition",
|
||||
"keyword": "support area",
|
||||
"effects": {
|
||||
"type": "trigger",
|
||||
"trigger": {
|
||||
"type": "startOfPhase",
|
||||
"phase": "maneuver"
|
||||
},
|
||||
"optional": true,
|
||||
"cost": {
|
||||
"type": "discardStackedCards",
|
||||
"on": "self"
|
||||
},
|
||||
"effect": {
|
||||
"type": "heal",
|
||||
"filter": "choose(dwarf,companion)"
|
||||
}
|
||||
}
|
||||
},
|
||||
"40_28": {
|
||||
"title": "*Seven for the Dwarf-lords",
|
||||
"side": "free people",
|
||||
"culture": "dwarven",
|
||||
"cost": 0,
|
||||
"type": "artifact",
|
||||
"keyword": "support area",
|
||||
"effects": [
|
||||
{
|
||||
"type": "activated",
|
||||
"phase": "fellowship",
|
||||
"effect": {
|
||||
"type": "stackCardsFromHand",
|
||||
"where": "self",
|
||||
"filter": "choose(culture(dwarven))"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "activated",
|
||||
"phase": "skirmish",
|
||||
"cost": {
|
||||
"type": "discardStackedCards",
|
||||
"on": "self",
|
||||
"count": 2
|
||||
},
|
||||
"effect": {
|
||||
"type": "playCardFromDiscard",
|
||||
"filter": "choose(culture(dwarven),skirmish,event)"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "activated",
|
||||
"phase": "regroup",
|
||||
"limitPerPhase": 1,
|
||||
"cost": [
|
||||
{
|
||||
"type": "discardStackedCards",
|
||||
"on": "self",
|
||||
"count": 3
|
||||
},
|
||||
{
|
||||
"type": "exert",
|
||||
"filter": "choose(dwarf)",
|
||||
"times": 2,
|
||||
"memorize": "exertedDwarf"
|
||||
}
|
||||
],
|
||||
"effect": {
|
||||
"type": "drawCards",
|
||||
"count": {
|
||||
"type": "forEachKeywordOnCardInMemory",
|
||||
"memory": "exertedDwarf",
|
||||
"keyword": "damage"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"40_184": {
|
||||
"title": "Black Steed",
|
||||
"subtitle": "Bred to Serve",
|
||||
|
||||
@@ -5,16 +5,24 @@ import com.gempukku.lotro.cards.build.CardGenerationEnvironment;
|
||||
import com.gempukku.lotro.cards.build.InvalidCardDefinitionException;
|
||||
import com.gempukku.lotro.cards.build.field.EffectProcessor;
|
||||
import com.gempukku.lotro.cards.build.field.FieldUtils;
|
||||
import com.gempukku.lotro.cards.build.field.effect.appender.AbstractEffectAppender;
|
||||
import com.gempukku.lotro.common.Phase;
|
||||
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.IncrementPhaseLimitEffect;
|
||||
import com.gempukku.lotro.logic.timing.Effect;
|
||||
import com.gempukku.lotro.logic.timing.EffectResult;
|
||||
import com.gempukku.lotro.logic.timing.PlayConditions;
|
||||
import org.json.simple.JSONObject;
|
||||
|
||||
public class ActivatedEffectProcessor implements EffectProcessor {
|
||||
@Override
|
||||
public void processEffect(JSONObject value, BuiltLotroCardBlueprint blueprint, CardGenerationEnvironment environment) throws InvalidCardDefinitionException {
|
||||
FieldUtils.validateAllowedFields(value, "phase", "requirement", "cost", "effect");
|
||||
FieldUtils.validateAllowedFields(value, "phase", "requirement", "cost", "effect", "limitPerPhase");
|
||||
|
||||
final String[] phaseArray = FieldUtils.getStringArray(value.get("phase"), "phase");
|
||||
final int limitPerPhase = FieldUtils.getInteger(value.get("limitPerPhase"), "limitPerPhase", 0);
|
||||
|
||||
if (phaseArray.length == 0)
|
||||
throw new InvalidCardDefinitionException("Unable to find phase for an activated effect");
|
||||
@@ -23,6 +31,22 @@ public class ActivatedEffectProcessor implements EffectProcessor {
|
||||
final Phase phase = Phase.valueOf(phaseString.toUpperCase());
|
||||
|
||||
DefaultActionSource actionSource = new DefaultActionSource();
|
||||
if (limitPerPhase > 0) {
|
||||
actionSource.addPlayRequirement(
|
||||
(action, playerId, game, self, effectResult, effect) -> PlayConditions.checkPhaseLimit(game, self, phase, limitPerPhase));
|
||||
actionSource.addCost(
|
||||
new AbstractEffectAppender() {
|
||||
@Override
|
||||
public boolean isPlayableInFull(CostToEffectAction action, String playerId, LotroGame game, PhysicalCard self, EffectResult effectResult, Effect effect) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Effect createEffect(CostToEffectAction action, String playerId, LotroGame game, PhysicalCard self, EffectResult effectResult, Effect effect) {
|
||||
return new IncrementPhaseLimitEffect(self, phase, limitPerPhase);
|
||||
}
|
||||
});
|
||||
}
|
||||
actionSource.addPlayRequirement(
|
||||
(action, playerId, game, self, effectResult, effect) -> PlayConditions.isPhase(game, phase));
|
||||
EffectUtils.processRequirementsCostsAndEffects(value, environment, actionSource);
|
||||
|
||||
@@ -12,4 +12,8 @@ public interface EffectAppender {
|
||||
void appendEffect(CostToEffectAction action, String playerId, LotroGame game, PhysicalCard self, EffectResult effectResult, Effect effect);
|
||||
|
||||
boolean isPlayableInFull(CostToEffectAction action, String playerId, LotroGame game, PhysicalCard self, EffectResult effectResult, Effect effect);
|
||||
|
||||
default boolean isPlayabilityCheckedForEffect() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,6 +46,7 @@ public class EffectAppenderFactory {
|
||||
effectAppenderProducers.put("putcardsfromdiscardintohand", new PutCardsFromDiscardIntoHand());
|
||||
effectAppenderProducers.put("addtrigger", new AddTrigger());
|
||||
effectAppenderProducers.put("stackplayedevent", new StackPlayedEvent());
|
||||
effectAppenderProducers.put("playcardfromdiscard", new PlayCardFromDiscard());
|
||||
}
|
||||
|
||||
public EffectAppender getEffectAppender(JSONObject effectObject, CardGenerationEnvironment environment) throws InvalidCardDefinitionException {
|
||||
|
||||
@@ -23,14 +23,19 @@ public class EffectUtils {
|
||||
for (JSONObject cost : costArray) {
|
||||
final EffectAppender effectAppender = effectAppenderFactory.getEffectAppender(cost, environment);
|
||||
actionSource.addPlayRequirement(
|
||||
(action, playerId, game, self, effectResult, effect) -> effectAppender.isPlayableInFull(action, playerId, game, self, effectResult, effect)
|
||||
);
|
||||
(action, playerId, game, self, effectResult, effect) -> effectAppender.isPlayableInFull(action, playerId, game, self, effectResult, effect));
|
||||
actionSource.addCost(effectAppender);
|
||||
}
|
||||
|
||||
final JSONObject[] effectArray = FieldUtils.getObjectArray(value.get("effect"), "effect");
|
||||
for (JSONObject effect : effectArray) {
|
||||
final EffectAppender effectAppender = effectAppenderFactory.getEffectAppender(effect, environment);
|
||||
if (effectAppender == null) {
|
||||
System.out.println("");
|
||||
}
|
||||
if (effectAppender.isPlayabilityCheckedForEffect())
|
||||
actionSource.addPlayRequirement(
|
||||
(action, playerId, game, self, effectResult, effect1) -> effectAppender.isPlayableInFull(action, playerId, game, self, effectResult, effect1));
|
||||
actionSource.addEffect(effectAppender);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,8 +11,14 @@ import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
public class MultiEffectAppender implements EffectAppender {
|
||||
private boolean playabilityCheckedForEffect;
|
||||
|
||||
private List<EffectAppender> effectAppenders = new LinkedList<>();
|
||||
|
||||
public void setPlayabilityCheckedForEffect(boolean playabilityCheckedForEffect) {
|
||||
this.playabilityCheckedForEffect = playabilityCheckedForEffect;
|
||||
}
|
||||
|
||||
public void addEffectAppender(EffectAppender effectAppender) {
|
||||
effectAppenders.add(effectAppender);
|
||||
}
|
||||
@@ -38,4 +44,9 @@ public class MultiEffectAppender implements EffectAppender {
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPlayabilityCheckedForEffect() {
|
||||
return playabilityCheckedForEffect;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
package com.gempukku.lotro.cards.build.field.effect.appender;
|
||||
|
||||
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.modifiers.ModifierFlag;
|
||||
import com.gempukku.lotro.logic.modifiers.evaluator.ConstantEvaluator;
|
||||
import com.gempukku.lotro.logic.timing.Effect;
|
||||
import com.gempukku.lotro.logic.timing.EffectResult;
|
||||
import com.gempukku.lotro.logic.timing.UnrespondableEffect;
|
||||
import org.json.simple.JSONObject;
|
||||
|
||||
public class PlayCardFromDiscard 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.resolveCardsInDiscard(filter,
|
||||
(playerId, game, source, effectResult, effect) -> Filters.playable(game),
|
||||
new ConstantEvaluator(1), "_temp", "owner", "Choose card to play", environment));
|
||||
result.addEffectAppender(
|
||||
new DelayedAppender() {
|
||||
@Override
|
||||
protected Effect createEffect(CostToEffectAction action, String playerId, LotroGame game, PhysicalCard self, EffectResult effectResult, Effect effect) {
|
||||
final PhysicalCard cardToPlay = action.getCardFromMemory("_temp");
|
||||
return new UnrespondableEffect() {
|
||||
@Override
|
||||
protected void doPlayEffect(LotroGame game) {
|
||||
final CostToEffectAction playCardAction = PlayUtils.getPlayCardAction(game, cardToPlay, 0, Filters.any, false);
|
||||
game.getActionsEnvironment().addActionToStack(playCardAction);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPlayableInFull(CostToEffectAction action, String playerId, LotroGame game, PhysicalCard self, EffectResult effectResult, Effect effect) {
|
||||
return !game.getModifiersQuerying().hasFlagActive(game, ModifierFlag.CANT_PLAY_FROM_DISCARD_OR_DECK);
|
||||
}
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -47,7 +47,7 @@ public class PutStackedCardsIntoHand implements EffectAppenderProducer {
|
||||
}
|
||||
});
|
||||
|
||||
return null;
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -135,11 +135,24 @@ public class CardResolver {
|
||||
}
|
||||
|
||||
public static EffectAppender resolveCardsInDiscard(String type, ValueSource countSource, String memory, String choicePlayer, String choiceText, CardGenerationEnvironment environment) throws InvalidCardDefinitionException {
|
||||
return resolveCardsInDiscard(type, null, countSource, memory, choicePlayer, choiceText, environment);
|
||||
}
|
||||
|
||||
public static EffectAppender resolveCardsInDiscard(String type, FilterableSource additionalFilter, ValueSource countSource, String memory, String choicePlayer, String choiceText, CardGenerationEnvironment environment) throws InvalidCardDefinitionException {
|
||||
if (type.startsWith("memory(") && type.endsWith(")")) {
|
||||
final PlayerSource playerSource = PlayerResolver.resolvePlayer(choicePlayer, environment);
|
||||
|
||||
String sourceMemory = type.substring(type.indexOf("(") + 1, type.lastIndexOf(")"));
|
||||
return new AbstractEffectAppender() {
|
||||
@Override
|
||||
public boolean isPlayableInFull(CostToEffectAction action, String playerId, LotroGame game, PhysicalCard self, EffectResult effectResult, Effect effect) {
|
||||
if (additionalFilter != null) {
|
||||
int min = countSource.getMinimum(null, playerId, game, self, effectResult, effect);
|
||||
String choicePlayerId = playerSource.getPlayer(playerId, game, self, effectResult, effect);
|
||||
final Collection<? extends PhysicalCard> cardsFromMemory = action.getCardsFromMemory(sourceMemory);
|
||||
Filterable filter = additionalFilter.getFilterable(playerId, game, self, effectResult, effect);
|
||||
return Filters.filter(game.getGameState().getDiscard(choicePlayerId), game, filter, Filters.in(cardsFromMemory)).size() >= min;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -163,7 +176,10 @@ public class CardResolver {
|
||||
int min = countSource.getMinimum(null, playerId, game, self, effectResult, effect);
|
||||
final Filterable filterable = filterableSource.getFilterable(playerId, game, self, effectResult, effect);
|
||||
String choicePlayerId = playerSource.getPlayer(playerId, game, self, effectResult, effect);
|
||||
return Filters.filter(game.getGameState().getDiscard(choicePlayerId), game, filterable).size() >= min;
|
||||
Filterable additionalFilterable = Filters.any;
|
||||
if (additionalFilter != null)
|
||||
additionalFilterable = additionalFilter.getFilterable(playerId, game, self, effectResult, effect);
|
||||
return Filters.filter(game.getGameState().getDiscard(choicePlayerId), game, filterable, additionalFilterable).size() >= min;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -172,7 +188,10 @@ public class CardResolver {
|
||||
int max = countSource.getMaximum(action, playerId, game, self, effectResult, effect);
|
||||
final Filterable filterable = filterableSource.getFilterable(playerId, game, self, effectResult, effect);
|
||||
String choicePlayerId = playerSource.getPlayer(playerId, game, self, effectResult, effect);
|
||||
return new ChooseCardsFromDiscardEffect(choicePlayerId, min, max, filterable) {
|
||||
Filterable additionalFilterable = Filters.any;
|
||||
if (additionalFilter != null)
|
||||
additionalFilterable = additionalFilter.getFilterable(playerId, game, self, effectResult, effect);
|
||||
return new ChooseCardsFromDiscardEffect(choicePlayerId, min, max, filterable, additionalFilterable) {
|
||||
@Override
|
||||
protected void cardsSelected(LotroGame game, Collection<PhysicalCard> cards) {
|
||||
action.setCardMemory(memory, cards);
|
||||
|
||||
@@ -3,6 +3,7 @@ package com.gempukku.lotro.cards.build.field.effect.appender.resolver;
|
||||
import com.gempukku.lotro.cards.build.*;
|
||||
import com.gempukku.lotro.cards.build.field.FieldUtils;
|
||||
import com.gempukku.lotro.common.Filterable;
|
||||
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;
|
||||
@@ -70,6 +71,13 @@ public class ValueResolver {
|
||||
final int count = action.getCardsFromMemory(memory).size();
|
||||
return new ConstantEvaluator(count);
|
||||
};
|
||||
} else if (type.equalsIgnoreCase("forEachKeywordOnCardInMemory")) {
|
||||
final String memory = FieldUtils.getString(object.get("memory"), "memory");
|
||||
final Keyword keyword = FieldUtils.getEnum(Keyword.class, object.get("keyword"), "keyword");
|
||||
return (action, playerId, game, self, effectResult, effect) -> {
|
||||
int count = game.getModifiersQuerying().getKeywordCount(game, action.getCardFromMemory(memory), keyword);
|
||||
return new ConstantEvaluator(count);
|
||||
};
|
||||
} else if (type.equalsIgnoreCase("limit")) {
|
||||
final int limit = FieldUtils.getInteger(object.get("value"), "value");
|
||||
ValueSource valueSource = resolveEvaluator(object.get("amount"), 0, environment);
|
||||
|
||||
Reference in New Issue
Block a user