Playing cards from discard

This commit is contained in:
marcin.sciesinski
2019-08-29 19:55:37 -07:00
parent c62fd736f0
commit edb2707772
10 changed files with 217 additions and 6 deletions

View File

@@ -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",

View File

@@ -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);

View File

@@ -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;
}
}

View File

@@ -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 {

View File

@@ -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);
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -47,7 +47,7 @@ public class PutStackedCardsIntoHand implements EffectAppenderProducer {
}
});
return null;
return result;
}
}

View File

@@ -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);

View File

@@ -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);