Add remaining Movie block balancing errata to playtesting

This commit is contained in:
Troy Biesterfeld
2021-06-06 19:28:17 -05:00
parent d041744b85
commit 9317b96daa
9 changed files with 409 additions and 19 deletions

View File

@@ -150,5 +150,59 @@
]
}
]
},
"78_103": {
"title": "*Grond",
"subtitle": "Hammer of the Underworld",
"culture": "Sauron",
"cost": 3,
"type": "possession",
"keyword": [
"Support Area",
"Engine"
],
"condition": {
"type": "canSpot",
"filter": "culture(sauron),minion"
},
"effects": [
{
"type": "activated",
"phase": "fellowship",
"cost": {
"type": "play",
"filter": "choose(culture(sauron),minion)"
},
"effect": {
"type": "addTokens",
"culture": "sauron",
"filter": "self"
}
},
{
"type": "trigger",
"optional": true,
"trigger": {
"type": "startOfPhase",
"phase": "regroup"
},
"cost": {
"type": "chooseandremovetokens",
"culture": "sauron",
"filter": "self",
"memorize": "numberOfTokens"
},
"effect": [
{
"type": "discard",
"filter": "choose(side(free people),not(companion),minTwilight(memory(numberOfTokens)),maxTwilight(memory(numberOfTokens)))"
},
{
"type": "discard",
"filter": "choose(or(and(culture(sauron),minion),self))"
}
]
}
]
}
}

View File

@@ -0,0 +1,84 @@
{
"79_12": {
"title": "*Aiglos",
"culture": "elven",
"cost": 2,
"type": "artifact",
"possession": "hand weapon",
"vitality": 1,
"target": "elf,not(archer)",
"effects": [
{
"type": "modifier",
"modifier": {
"type": "modifyStrength",
"filter": "bearer,name(Gil-galad)",
"amount": {
"type": "forEachYouCanSpot",
"filter": "culture(elven),artifact",
"limit": 6
}
}
},
{
"type": "activated",
"phase": "regroup",
"cost": {
"type": "discard",
"filter": "self"
},
"effect": [
{
"type": "chooseHowManyToSpot",
"filter": "elf",
"memorize": "spottedElfCount"
},
{
"type": "duplicate",
"amount": {
"type": "fromMemory",
"memory": "spottedElfCount"
},
"effect": {
"type": "wound",
"filter": "choose(minion)"
}
}
]
}
]
},
"79_14": {
"title": "*Galadriel",
"subtitle": "Bearer of Wisdom",
"culture": "elven",
"cost": 3,
"type": "companion",
"race": "elf",
"strength": 3,
"vitality": 3,
"resistance": 3,
"keyword": "can start with ring",
"effects": [
{
"type": "modifier",
"modifier": {
"type": "modifyResistance",
"filter": "self,hasAttached(or(artifact,name(The One Ring)))",
"amount": {
"type": "forEachYouCanSpot",
"filter": "culture(elven),companion"
}
}
},
{
"type": "modifier",
"modifier": {
"type": "cantBear",
"filter": "self",
"cardFilter": "ranged weapon"
}
}
]
}
}

View File

@@ -0,0 +1,2 @@
{
}

View File

@@ -1,2 +1,115 @@
{
"80_8": {
"title": "*Cirdan",
"subtitle": "The Shipwright",
"culture": "Elven",
"cost": 4,
"type": "companion",
"race": "Elf",
"strength": 7,
"vitality": 4,
"resistance": 6,
"condition": {
"type": "canSpot",
"filter": "elf",
"count": 2
},
"effects": {
"type": "activated",
"phase": "skirmish",
"cost": {
"type": "exert",
"filter": "self"
},
"effect": {
"type": "modifyStrength",
"filter": "choose(minion,inSkirmishAgainst(self))",
"amount": {
"type": "forEachInDiscard",
"filter": "culture(elven),event",
"limit": 4,
"multiplier": -1
}
}
}
},
"80_17": {
"title": "Out of the High Airs",
"cost": 3,
"culture": "Gandalf",
"type": "event",
"keyword": "response",
"condition": {
"type": "phase",
"phase": "regroup"
},
"effects": {
"type": "responseEvent",
"trigger": {
"type": "moves"
},
"cost": {
"type": "exert",
"filter": "choose(your,wizard)"
},
"effect": {
"type": "discard",
"count": "0-3",
"filter": "choose(minion)"
}
}
},
"80_32": {
"title": "*Fifth Level",
"culture": "Gondor",
"cost": 1,
"type": "condition",
"keyword": [
"Support Area",
"Fortification"
],
"effects": [
{
"type": "modifier",
"modifier": {
"type": "modifyStrength",
"filter": "bearer",
"amount": {
"type": "forEachYouCanSpot",
"filter": "fortification",
"multiplier": -1
}
}
},
{
"type": "activated",
"phase": "maneuver",
"cost": {
"type": "choice",
"texts": [
"Exert 2 GONDOR Men",
"Spot 3 Knights"
],
"effects": [
{
"type": "exert",
"filter": "choose(culture(gondor),man)",
"count": 2
},
{
"type": "spot",
"filter": "knight",
"count": 3,
"skipMemorize": true
}
]
},
"effect": {
"type": "transfer",
"filter": "choose(self,zone(support))",
"where": "choose(minion)"
}
}
]
}
}

View File

@@ -124,15 +124,21 @@ var PCCards = {
'71_55': 'https://i.lotrtcgpc.net/errata/xlist/71_055.jpg',
'71_254': 'https://i.lotrtcgpc.net/errata/xlist/71_254.jpg',
'71_282': 'https://i.lotrtcgpc.net/errata/xlist/71_282.jpg',
'72_6': 'https://i.lotrtcgpc.net/errata/xlist/72_6.jpg',
'72_7': 'https://i.lotrtcgpc.net/errata/xlist/72_7.jpg',
'72_55': 'https://i.lotrtcgpc.net/errata/xlist/72_55.jpg',
'73_54': 'https://i.lotrtcgpc.net/errata/xlist/73_54.jpg',
'72_6': 'https://i.lotrtcgpc.net/errata/xlist/72_006.jpg',
'72_7': 'https://i.lotrtcgpc.net/errata/xlist/72_007.jpg',
'72_55': 'https://i.lotrtcgpc.net/errata/xlist/72_055.jpg',
'73_54': 'https://i.lotrtcgpc.net/errata/xlist/73_054.jpg',
'73_120': 'https://i.lotrtcgpc.net/errata/xlist/73_120.jpg',
'78_24': 'https://i.lotrtcgpc.net/errata/xlist/78_24.jpg',
'78_51': 'https://i.lotrtcgpc.net/errata/xlist/78_51.jpg',
'78_57': 'https://i.lotrtcgpc.net/errata/xlist/78_57.jpg',
'78_59': 'https://i.lotrtcgpc.net/errata/xlist/78_59.jpg',
'78_24': 'https://i.lotrtcgpc.net/errata/xlist/78_024.jpg',
'78_51': 'https://i.lotrtcgpc.net/errata/xlist/78_051.jpg',
'78_57': 'https://i.lotrtcgpc.net/errata/xlist/78_057.jpg',
'78_59': 'https://i.lotrtcgpc.net/errata/xlist/78_059.jpg',
'78_103': 'https://i.lotrtcgpc.net/errata/xlist/78_103.jpg',
'79_12': 'https://i.lotrtcgpc.net/errata/xlist/79_012.jpg',
'79_14': 'https://i.lotrtcgpc.net/errata/xlist/79_014.jpg',
'80_8': 'https://i.lotrtcgpc.net/errata/xlist/80_008.jpg',
'80_17': 'https://i.lotrtcgpc.net/errata/xlist/80_017.jpg',
'80_32': 'https://i.lotrtcgpc.net/errata/xlist/80_032.jpg',
/// Player's Council League Promos
// April 2021

View File

@@ -100,6 +100,7 @@ public class EffectAppenderFactory {
effectAppenderProducers.put("revealcards", new RevealCards());
effectAppenderProducers.put("addtokens", new AddTokens());
effectAppenderProducers.put("removetokens", new RemoveTokens());
effectAppenderProducers.put("chooseandremovetokens", new ChooseAndRemoveTokens());
effectAppenderProducers.put("transfer", new Transfer());
effectAppenderProducers.put("transfertosupport", new TransferToSupport());
effectAppenderProducers.put("transferfromdiscard", new TransferFromDiscard());

View File

@@ -0,0 +1,98 @@
package com.gempukku.lotro.cards.build.field.effect.appender;
import com.gempukku.lotro.cards.build.ActionContext;
import com.gempukku.lotro.cards.build.CardGenerationEnvironment;
import com.gempukku.lotro.cards.build.InvalidCardDefinitionException;
import com.gempukku.lotro.cards.build.field.FieldUtils;
import com.gempukku.lotro.cards.build.field.effect.EffectAppender;
import com.gempukku.lotro.cards.build.field.effect.EffectAppenderProducer;
import com.gempukku.lotro.cards.build.field.effect.appender.resolver.CardResolver;
import com.gempukku.lotro.common.Culture;
import com.gempukku.lotro.common.Token;
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.decisions.DecisionResultInvalidException;
import com.gempukku.lotro.logic.decisions.IntegerAwaitingDecision;
import com.gempukku.lotro.logic.effects.PlayoutDecisionEffect;
import com.gempukku.lotro.logic.effects.RemoveTokenEffect;
import com.gempukku.lotro.logic.modifiers.ModifierFlag;
import com.gempukku.lotro.logic.modifiers.evaluator.ConstantEvaluator;
import com.gempukku.lotro.logic.timing.Effect;
import org.json.simple.JSONObject;
import java.util.LinkedList;
import java.util.List;
public class ChooseAndRemoveTokens implements EffectAppenderProducer {
@Override
public EffectAppender createEffectAppender(JSONObject effectObject, CardGenerationEnvironment environment) throws InvalidCardDefinitionException {
FieldUtils.validateAllowedFields(effectObject, "culture", "filter", "memorize", "memorizeCard");
final Culture culture = FieldUtils.getEnum(Culture.class, effectObject.get("culture"), "culture");
final String filter = FieldUtils.getString(effectObject.get("filter"), "filter", "self");
final String memory = FieldUtils.getString(effectObject.get("memorize"), "memorize", "_temp");
final String memorizeCard = FieldUtils.getString(effectObject.get("memorizeCard"), "memorizeCard");
final Token token = (culture != null) ? Token.findTokenForCulture(culture) : null;
MultiEffectAppender result = new MultiEffectAppender();
result.addEffectAppender(
CardResolver.resolveCards(filter, null, new ConstantEvaluator(1),
memorizeCard, "you", "Choose card to remove tokens from", environment));
result.addEffectAppender(
new DelayedAppender() {
@Override
public boolean isPlayableInFull(ActionContext actionContext) {
final LotroGame game = actionContext.getGame();
return !game.getModifiersQuerying().hasFlagActive(game, ModifierFlag.CANT_TOUCH_CULTURE_TOKENS);
}
@Override
protected Effect createEffect(boolean cost, CostToEffectAction action, ActionContext actionContext) {
final PhysicalCard cardFromMemory = actionContext.getCardFromMemory(memorizeCard);
return new PlayoutDecisionEffect(actionContext.getPerformingPlayer(),
new IntegerAwaitingDecision(1, "How many tokens do you wish to remove",
0, actionContext.getGame().getGameState().getTokenCount(cardFromMemory, token)) {
@Override
public void decisionMade(String result) throws DecisionResultInvalidException {
actionContext.setValueToMemory(memory, String.valueOf(getValidatedResult(result)));
}
});
}
});
result.addEffectAppender(
new DelayedAppender() {
@Override
public boolean isPlayableInFull(ActionContext actionContext) {
final LotroGame game = actionContext.getGame();
return !game.getModifiersQuerying().hasFlagActive(game, ModifierFlag.CANT_TOUCH_CULTURE_TOKENS);
}
@Override
protected List<Effect> createEffects(boolean cost, CostToEffectAction action, ActionContext actionContext) {
final PhysicalCard cardFromMemory = actionContext.getCardFromMemory(memorizeCard);
int tokenCount = Integer.parseInt(actionContext.getValueFromMemory(memory));
List<Effect> result = new LinkedList<>();
if (token != null)
result.add(new RemoveTokenEffect(actionContext.getSource(), cardFromMemory, token, tokenCount));
else {
result.add(new RemoveTokenEffect(actionContext.getSource(), cardFromMemory,
getCultureTokenOnCard(actionContext.getGame(), cardFromMemory), tokenCount));
}
return result;
}
});
return result;
}
private Token getCultureTokenOnCard(LotroGame game, PhysicalCard card) {
for (Token token : Token.values())
if (token.getCulture() != null && game.getGameState().getTokenCount(card, token) > 0)
return token;
return null;
}
}

View File

@@ -1,23 +1,53 @@
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.*;
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.cards.build.field.effect.appender.resolver.ValueResolver;
import com.gempukku.lotro.common.Filterable;
import com.gempukku.lotro.game.state.LotroGame;
import com.gempukku.lotro.logic.actions.CostToEffectAction;
import com.gempukku.lotro.logic.timing.Effect;
import com.gempukku.lotro.logic.timing.PlayConditions;
import com.gempukku.lotro.logic.timing.UnrespondableEffect;
import org.json.simple.JSONObject;
public class Spot implements EffectAppenderProducer {
@Override
public EffectAppender createEffectAppender(JSONObject effectObject, CardGenerationEnvironment environment) throws InvalidCardDefinitionException {
FieldUtils.validateAllowedFields(effectObject, "filter", "memorize", "text");
FieldUtils.validateAllowedFields(effectObject, "count", "filter", "memorize", "text", "skipMemorize");
final ValueSource valueSource = ValueResolver.resolveEvaluator(effectObject.get("count"), 1, environment);
final String filter = FieldUtils.getString(effectObject.get("filter"), "filter");
final String memorize = FieldUtils.getString(effectObject.get("memorize"), "memorize", "_temp");
final String text = FieldUtils.getString(effectObject.get("text"), "text", "Choose card to spot");
final boolean skipMemorize = FieldUtils.getBoolean(effectObject.get("skipMemorize"), "skipMemorize", false);
return CardResolver.resolveCard(
filter, memorize, "you", text, environment);
if (skipMemorize) {
final FilterableSource filterableSource = environment.getFilterFactory().generateFilter(filter, environment);
return new DelayedAppender() {
@Override
protected Effect createEffect(boolean cost, CostToEffectAction action, ActionContext actionContext) {
return new UnrespondableEffect() {
@Override
protected void doPlayEffect(LotroGame game) {
}
};
}
@Override
public boolean isPlayableInFull(ActionContext actionContext) {
final int count = valueSource.getEvaluator(actionContext).evaluateExpression(actionContext.getGame(), null);
Filterable filterable = filterableSource.getFilterable(actionContext);
return PlayConditions.canSpot(actionContext.getGame(), count, filterable);
}
};
} else {
return CardResolver.resolveCards(
filter, valueSource, memorize, "you", text, environment);
}
}
}

View File

@@ -460,8 +460,9 @@
"2_32":"52_32", "2_55":"72_55", "2_75":"52_75", "2_101":"52_101", "2_108":"52_108", "2_121":"52_121", "3_17":"53_17",
"3_38":"53_38", "3_42":"53_42", "3_54":"73_54", "3_67":"53_67", "3_68":"53_68", "3_106":"53_106", "3_108":"53_108",
"3_113":"53_113", "3_120":"73_120", "4_73":"54_73", "4_192":"54_192", "4_276":"54_276", "4_304":"54_304", "7_49":"57_49",
"7_96":"57_96", "8_1":"58_1", "8_24":"58_24", "8_51":"58_51", "8_57":"58_57", "8_59":"58_59", "10_2":"60_2",
"10_11":"60_11", "10_91":"60_91"}
"7_96":"57_96", "8_1":"58_1", "8_24":"78_24", "8_51":"78_51", "8_57":"78_57", "8_59":"78_59", "8_103":"78_103",
"9_12":"79_12", "9_14":"79_14", "10_2":"60_2", "10_8":"80_8", "10_11":"60_11", "10_17":"80_17", "10_32":"80_32",
"10_91":"60_91"}
},
{
"name":"PLAYTEST - Expanded (PC)",
@@ -475,9 +476,10 @@
"1_254":"71_254", "1_282":"71_282", "1_311":"51_311", "1_313":"51_313", "1_316":"51_316", "2_6":"72_6", "2_7":"72_7",
"2_32":"52_32", "2_55":"72_55", "2_75":"52_75", "2_101":"52_101", "2_108":"52_108", "2_121":"52_121", "3_17":"53_17",
"3_38":"53_38", "3_42":"53_42", "3_54":"73_54", "3_67":"53_67", "3_68":"53_68", "3_106":"53_106", "3_108":"53_108",
"3_113":"53_113", "3_120":"73_120", "4_73":"54_73", "4_192":"54_192", "4_276":"54_276", "4_304":"54_304", "7_49":"57_49",
"7_96":"57_96", "8_1":"58_1", "8_24":"58_24", "8_51":"58_51", "8_57":"58_57", "8_59":"58_59", "10_2":"60_2",
"10_11":"60_11", "10_91":"60_91", "11_31":"61_31", "11_100":"61_100", "11_114":"61_114", "11_132":"61_132",
"13_188":"63_188", "15_64":"65_64"}
"3_113":"53_113", "3_120":"73_120", "4_73":"54_73", "4_192":"54_192", "4_276":"54_276", "4_304":"54_304", "7_49":"57_49",
"7_96":"57_96", "8_1":"58_1", "8_24":"78_24", "8_51":"78_51", "8_57":"78_57", "8_59":"78_59", "8_103":"78_103",
"9_12":"79_12", "9_14":"79_14", "10_2":"60_2", "10_8":"80_8", "10_11":"60_11", "10_17":"80_17", "10_32":"80_32",
"10_91":"60_91", "11_31":"61_31", "11_100":"61_100", "11_114":"61_114", "11_132":"61_132", "13_188":"63_188",
"15_64":"65_64"}
}
]