Migrated Isengard cards in set 5 to hjson

This commit is contained in:
MarcinSc
2024-04-22 11:25:10 +07:00
parent 803e0e6470
commit c0cda4eec7
37 changed files with 787 additions and 366 deletions

View File

@@ -23,7 +23,7 @@
]
effect: {
type: repeat
amount: {
times: {
type: forEachYouCanSpot
filter: companion
over: 4
@@ -371,7 +371,7 @@
]
effect: {
type: repeat
amount: {
times: {
type: forEachYouCanSpot
filter: companion
over: 5

View File

@@ -1008,7 +1008,7 @@
]
effect: {
type: Repeat
amount: {
times: {
type: forEachYouCanSpot
filter: companion
over: 4

View File

@@ -1228,7 +1228,7 @@
effect: [
{
type: repeat
amount: 3
times: 3
effect: {
type: playCardFromDiscard
filter: choose(tracker)

View File

@@ -802,7 +802,7 @@
}
{
type: repeat
amount: {
times: {
type: forEachInMemory
memory: stackedCards
}

View File

@@ -554,7 +554,7 @@
}
effect: {
type: repeat
amount: 3
times: 3
effect: {
type: heal
count: 0-1

View File

@@ -422,7 +422,7 @@
}
{
type: repeat
amount: {
times: {
type: forEachMatchingInMemory
filter: side(shadow)
memory: revealedCards

View File

@@ -566,39 +566,18 @@
effect: [
{
type: doWhile
condition: [
{
type: memoryIs
memory: answer
value: yes
}
{
type: memoryMatches
memory: playedCard
filter: possession
}
]
effect: [
{
type: chooseYesOrNo
text: Would you like to play next possession?
memorize: answer
}
{
type: conditional
requires: {
type: memoryIs
memory: answer
value: yes
}
effect: {
type: playCardFromDiscard
filter: choose(possession)
on: companion,signet(Aragorn)
memorize: playedCard
}
}
]
effect: {
type: playCardFromDiscard
optional: true
filter: choose(possession)
on: companion,signet(Aragorn)
memorize: playedCard
}
condition: {
type: memoryMatches
memory: playedCard
filter: possession
}
}
]
}

View File

@@ -490,7 +490,7 @@
}
{
type: repeat
amount: {
times: {
type: fromMemory
memory: spottedElfCount
}
@@ -740,7 +740,7 @@
effect: [
{
type: repeat
amount: {
times: {
type: forEachVitality
filter: bearer
}

View File

@@ -109,7 +109,7 @@
}
{
type: repeat
amount: {
times: {
type: forEachInHand
filter: side(shadow)
}

View File

@@ -512,7 +512,7 @@
filter: choose(uruk-hai)
count: 0-1
}
amount: {
times: {
type: forEachYouCanSpot
filter: companion
}

View File

@@ -65,7 +65,7 @@
}
effect: {
type: repeat
amount: {
times: {
type: twilightCostInMemory
memory: discardedFollower
}

View File

@@ -745,7 +745,7 @@
}
effect: {
type: repeat
amount: {
times: {
type: forEachYouCanSpot
filter: culture(dwarven),companion
over: 3

View File

@@ -185,7 +185,7 @@
}
effect: {
type: repeat
amount: {
times: {
type: forEachYouCanSpot
filter: culture(dwarven),companion
over: 3

View File

@@ -753,7 +753,7 @@
}
{
type: repeat
amount: {
times: {
type: forEachMatchingInMemory
memory: cardsInHand
filter: side(free people),skirmish,event

View File

@@ -112,7 +112,7 @@
}
{
type: repeat
amount: {
times: {
type: forEachYouCanSpot
filter: follower,culture(dwarven),not(memory(transferredFollowers))
}

View File

@@ -61,7 +61,7 @@
]
effect: {
type: Repeat
amount: {
times: {
type: forEachYouCanSpot
filter: companion
over: 4

View File

@@ -392,7 +392,7 @@
}
effect: {
type: repeat
amount: {
times: {
type: ForEachInDeadPile
filter: any
}
@@ -432,7 +432,7 @@
}
effect: {
type: repeat
amount: {
times: {
type: ForEachInDeadPile
filter: any
}

View File

@@ -164,7 +164,7 @@
}
{
type: Repeat
amount: 9
times: 9
effect: {
type: conditional
requires: {

View File

@@ -53,7 +53,7 @@
}
{
type: repeat
amount: {
times: {
type: sum
source: [
{

View File

@@ -50,7 +50,7 @@
}
{
type: Repeat
amount: {
times: {
type: Sum
source: [
1

View File

@@ -63,7 +63,7 @@
effect: [
{
type: repeat
amount: {
times: {
type: ForEachToken
filter: self
culture: isengard

View File

@@ -62,7 +62,7 @@
}
{
type: Repeat
amount: {
times: {
type: ForEachWound
filter: minion,InSkirmishAgainst(self)
}

View File

@@ -132,7 +132,7 @@
}
effect: {
type: repeat
amount: {
times: {
type: forEachThreat
}
effect: {

View File

@@ -405,7 +405,7 @@
}
effect: {
type: repeat
amount: {
times: {
type: forEachYouCanSpot
filter: companion
over: 5

View File

@@ -7,12 +7,10 @@ import com.gempukku.lotro.cards.build.Requirement;
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.state.LotroGame;
import com.gempukku.lotro.logic.actions.CostToEffectAction;
import com.gempukku.lotro.logic.actions.SubAction;
import com.gempukku.lotro.logic.actions.DoWhileSubAction;
import com.gempukku.lotro.logic.effects.StackActionEffect;
import com.gempukku.lotro.logic.timing.Effect;
import com.gempukku.lotro.logic.timing.UnrespondableEffect;
import org.json.simple.JSONObject;
public class DoWhile implements EffectAppenderProducer {
@@ -36,30 +34,15 @@ public class DoWhile implements EffectAppenderProducer {
return true;
}
private SubAction createSubAction(CostToEffectAction action, ActionContext actionContext) {
SubAction subAction = new SubAction(action);
for (EffectAppender effectAppender : effectAppenders)
effectAppender.appendEffect(false, subAction, actionContext);
subAction.appendEffect(
new UnrespondableEffect() {
@Override
protected void doPlayEffect(LotroGame game) {
if (conditionsMatch(actionContext)) {
game.getActionsEnvironment().addActionToStack(createSubAction(action, actionContext));
}
}
}
);
return subAction;
}
@Override
protected Effect createEffect(boolean cost, CostToEffectAction action, ActionContext actionContext) {
if (conditionsMatch(actionContext)) {
return new StackActionEffect(createSubAction(action, actionContext));
} else {
return null;
}
DoWhileSubAction doWhile = new DoWhileSubAction(action,
() -> conditionsMatch(actionContext),
costToEffectAction -> {
for (EffectAppender effectAppender : effectAppenders)
effectAppender.appendEffect(false, costToEffectAction, actionContext);
});
return new StackActionEffect(doWhile);
}
};
}

View File

@@ -15,6 +15,8 @@ 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.modifiers.evaluator.Evaluator;
import com.gempukku.lotro.logic.modifiers.evaluator.RangeEvaluator;
import com.gempukku.lotro.logic.timing.Effect;
import com.gempukku.lotro.logic.timing.ExtraFilters;
import com.gempukku.lotro.logic.timing.FailedEffect;
@@ -25,12 +27,13 @@ import java.util.Collection;
public class PlayCardFromDiscard implements EffectAppenderProducer {
@Override
public EffectAppender createEffectAppender(JSONObject effectObject, CardGenerationEnvironment environment) throws InvalidCardDefinitionException {
FieldUtils.validateAllowedFields(effectObject, "filter", "on", "cost", "removedTwilight", "memorize");
FieldUtils.validateAllowedFields(effectObject, "filter", "on", "cost", "removedTwilight", "optional", "memorize");
final String filter = FieldUtils.getString(effectObject.get("filter"), "filter");
final String onFilter = FieldUtils.getString(effectObject.get("on"), "on");
final int removedTwilight = FieldUtils.getInteger(effectObject.get("removedTwilight"), "removedTwilight", 0);
final ValueSource costModifierSource = ValueResolver.resolveEvaluator(effectObject.get("cost"), 0, environment);
final boolean optional = FieldUtils.getBoolean(effectObject.get("optional"), "optional", false);
final String memorize = FieldUtils.getString(effectObject.get("memorize"), "memorize", "_temp");
final FilterableSource onFilterableSource = (onFilter != null) ? environment.getFilterFactory().generateFilter(onFilter, environment) : null;
@@ -38,6 +41,8 @@ public class PlayCardFromDiscard implements EffectAppenderProducer {
MultiEffectAppender result = new MultiEffectAppender();
result.setPlayabilityCheckedForEffect(true);
Evaluator countEvaluator = optional ? new RangeEvaluator(0, 1) : new ConstantEvaluator(1);
result.addEffectAppender(
CardResolver.resolveCardsInDiscard(filter,
(actionContext) -> {
@@ -60,7 +65,7 @@ public class PlayCardFromDiscard implements EffectAppenderProducer {
return Filters.playable(actionContext.getGame(), removedTwilight, costModifier, false, false, true);
},
new ConstantEvaluator(1), memorize, "you", "Choose card to play", environment));
countEvaluator, memorize, "you", "Choose card to play", environment));
result.addEffectAppender(
new DelayedAppender() {
@Override

View File

@@ -19,9 +19,9 @@ import java.util.Arrays;
public class Repeat implements EffectAppenderProducer {
@Override
public EffectAppender createEffectAppender(JSONObject effectObject, CardGenerationEnvironment environment) throws InvalidCardDefinitionException {
FieldUtils.validateAllowedFields(effectObject, "amount", "effect");
FieldUtils.validateAllowedFields(effectObject, "times", "effect");
final ValueSource amountSource = ValueResolver.resolveEvaluator(effectObject.get("amount"), environment);
final ValueSource timesSource = ValueResolver.resolveEvaluator(effectObject.get("times"), environment);
final JSONObject[] effectArray = FieldUtils.getObjectArray(effectObject.get("effect"), "effect");
final EffectAppender[] effectAppenders = environment.getEffectAppenderFactory().getEffectAppenders(effectArray, environment);
@@ -29,10 +29,10 @@ public class Repeat implements EffectAppenderProducer {
return new DelayedAppender() {
@Override
protected Effect createEffect(boolean cost, CostToEffectAction action, ActionContext actionContext) {
final int count = amountSource.getEvaluator(actionContext).evaluateExpression(actionContext.getGame(), null);
if (count > 0) {
final int times = timesSource.getEvaluator(actionContext).evaluateExpression(actionContext.getGame(), null);
if (times > 0) {
SubAction subAction = new SubAction(action);
for (int i = 0; i < count; i++) {
for (int i = 0; i < times; i++) {
for (EffectAppender effectAppender : effectAppenders)
effectAppender.appendEffect(false, subAction, actionContext);
}

View File

@@ -41,6 +41,7 @@ public class FilterFactory {
});
simpleFilters.put("bearer", (actionContext -> Filters.hasAttached(actionContext.getSource())));
simpleFilters.put("character", (actionContext) -> Filters.character);
simpleFilters.put("canbereturnedtohand", (actionContext -> Filters.canBeReturnedToHand(actionContext.getSource())));
simpleFilters.put("canexert", (actionContext -> Filters.canExert(actionContext.getSource())));
simpleFilters.put("controlledbyotherplayer",
(actionContext -> Filters.siteControlledByOtherPlayer(actionContext.getPerformingPlayer())));

View File

@@ -0,0 +1,18 @@
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 com.gempukku.lotro.logic.GameUtils;
import org.json.simple.JSONObject;
public class CanSpotFPCultures implements RequirementProducer {
@Override
public Requirement getPlayRequirement(JSONObject object, CardGenerationEnvironment environment) throws InvalidCardDefinitionException {
FieldUtils.validateAllowedFields(object, "amount");
final int amount = FieldUtils.getInteger(object.get("amount"), "amount");
return (actionContext) -> GameUtils.getSpottableFPCulturesCount(actionContext.getGame(), actionContext.getPerformingPlayer()) >= amount;
}
}

View File

@@ -20,6 +20,7 @@ public class RequirementFactory {
requirementProducers.put("canspot", new CanSpot());
requirementProducers.put("canspotburdens", new CanSpotBurdens());
requirementProducers.put("canspotculturetokens", new CanSpotCultureTokens());
requirementProducers.put("canspotfpcultures", new CanSpotFPCultures());
requirementProducers.put("canspotthreats", new CanSpotThreats());
requirementProducers.put("canspottwilight", new CanSpotTwilight());
requirementProducers.put("canspotwounds", new CanSpotWounds());

View File

@@ -11,10 +11,11 @@ import org.json.simple.JSONObject;
public class AboutToDiscardFromPlay implements TriggerCheckerProducer {
@Override
public TriggerChecker getTriggerChecker(JSONObject value, CardGenerationEnvironment environment) throws InvalidCardDefinitionException {
FieldUtils.validateAllowedFields(value, "source", "filter");
FieldUtils.validateAllowedFields(value, "source", "filter", "opponent");
String source = FieldUtils.getString(value.get("source"), "source", "any");
String filter = FieldUtils.getString(value.get("filter"), "filter");
boolean opponent = FieldUtils.getBoolean(value.get("opponent"), "opponent", false);
final FilterableSource sourceFilter = environment.getFilterFactory().generateFilter(source, environment);
final FilterableSource affectedFilter = environment.getFilterFactory().generateFilter(filter, environment);
@@ -22,9 +23,16 @@ public class AboutToDiscardFromPlay implements TriggerCheckerProducer {
return new TriggerChecker() {
@Override
public boolean accepts(ActionContext actionContext) {
return TriggerConditions.isGettingDiscardedBy(actionContext.getEffect(), actionContext.getGame(),
sourceFilter.getFilterable(actionContext),
affectedFilter.getFilterable(actionContext));
if (opponent) {
return TriggerConditions.isGettingDiscardedByOpponent(actionContext.getEffect(), actionContext.getGame(),
actionContext.getPerformingPlayer(),
sourceFilter.getFilterable(actionContext),
affectedFilter.getFilterable(actionContext));
} else {
return TriggerConditions.isGettingDiscardedBy(actionContext.getEffect(), actionContext.getGame(),
sourceFilter.getFilterable(actionContext),
affectedFilter.getFilterable(actionContext));
}
}
@Override

View File

@@ -5,6 +5,7 @@ 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.common.Phase;
import com.gempukku.lotro.game.PhysicalCard;
import com.gempukku.lotro.logic.timing.TriggerConditions;
import com.gempukku.lotro.logic.timing.results.ActivateCardResult;
@@ -13,10 +14,11 @@ import org.json.simple.JSONObject;
public class UsesSpecialAbility implements TriggerCheckerProducer {
@Override
public TriggerChecker getTriggerChecker(JSONObject value, CardGenerationEnvironment environment) throws InvalidCardDefinitionException {
FieldUtils.validateAllowedFields(value, "filter", "memorize");
FieldUtils.validateAllowedFields(value, "filter", "memorize", "phase");
String filter = FieldUtils.getString(value.get("filter"), "filter", "any");
final FilterableSource filterableSource = environment.getFilterFactory().generateFilter(filter, environment);
final Phase phase = FieldUtils.getEnum(Phase.class, value.get("phase"), "phase");
final String memorize = FieldUtils.getString(value.get("memorize"), "memorize");
return new TriggerChecker() {
@@ -31,6 +33,10 @@ public class UsesSpecialAbility implements TriggerCheckerProducer {
if (activated) {
ActivateCardResult activateCardResult = (ActivateCardResult) actionContext.getEffectResult();
if (phase != null) {
if (activateCardResult.getActionTimeword() != phase)
return false;
}
if (memorize != null) {
PhysicalCard playedCard = activateCardResult.getSource();

View File

@@ -519,6 +519,15 @@ public class Filters {
};
}
public static Filter canBeReturnedToHand(final PhysicalCard source) {
return new Filter() {
@Override
public boolean accepts(LotroGame game, PhysicalCard physicalCard) {
return game.getModifiersQuerying().canBeReturnedToHand(game, physicalCard, source);
}
};
}
public static Filter canExert(final PhysicalCard source) {
return canExert(source, 1);
}

View File

@@ -122,6 +122,10 @@ public abstract class AbstractCostToEffectAction implements CostToEffectAction {
return sum;
}
protected final boolean hasNextCost() {
return !_costs.isEmpty();
}
protected final Effect getNextCost() {
Effect cost = _costs.poll();
if (cost != null)
@@ -129,6 +133,10 @@ public abstract class AbstractCostToEffectAction implements CostToEffectAction {
return cost;
}
protected final boolean hasNextEffect() {
return !_effects.isEmpty();
}
protected final Effect getNextEffect() {
final Effect effect = _effects.poll();
if (effect != null)

View File

@@ -0,0 +1,37 @@
package com.gempukku.lotro.logic.actions;
import com.gempukku.lotro.game.state.LotroGame;
import com.gempukku.lotro.logic.timing.Action;
import com.gempukku.lotro.logic.timing.Effect;
import java.util.function.BooleanSupplier;
import java.util.function.Consumer;
public class DoWhileSubAction extends SubAction {
private final BooleanSupplier condition;
private final Consumer<CostToEffectAction> effectsAppender;
private boolean firstExecution = true;
public DoWhileSubAction(Action action, BooleanSupplier condition, Consumer<CostToEffectAction> effectsAppender) {
super(action);
this.condition = condition;
this.effectsAppender = effectsAppender;
}
@Override
public Effect nextEffect(LotroGame game) {
if (firstExecution) {
effectsAppender.accept(this);
firstExecution = false;
}
if (!hasNextEffect()) {
if (condition.getAsBoolean()) {
effectsAppender.accept(this);
}
}
return getNextEffect();
}
}

View File

@@ -419,10 +419,11 @@ public class TriggerConditions {
return false;
}
public static boolean isGettingDiscardedByOpponent(Effect effect, LotroGame game, String playerId, Filterable... filters) {
public static boolean isGettingDiscardedByOpponent(Effect effect, LotroGame game, String playerId, Filterable sourceFilter, Filterable... filters) {
if (effect.getType() == Effect.Type.BEFORE_DISCARD_FROM_PLAY) {
PreventableCardEffect preventableEffect = (PreventableCardEffect) effect;
if (effect.getSource() != null && !effect.getPerformingPlayer().equals(playerId))
if (effect.getSource() != null && Filters.and(sourceFilter).accepts(game, effect.getSource())
&& !effect.getPerformingPlayer().equals(playerId))
return Filters.filter(preventableEffect.getAffectedCardsMinusPrevented(game), game, filters).size() > 0;
}
return false;