Orc Butchery errata tests

This commit is contained in:
Christian 'ketura' McCarty
2023-03-04 01:04:05 -06:00
parent 5023b56245
commit 022fdad2ec
6 changed files with 341 additions and 42 deletions

View File

@@ -379,44 +379,87 @@
twilight: 0
type: event
keyword: response
requires: {
type: canSpot
filter: culture(sauron),orc,inSkirmish
}
effects: {
type: responseEvent
trigger: {
type: killed
filter: companion
}
effect: {
type: repeat
amount: {
type: ForEachInDeadPile
filter: any
effects: [
{
type: responseEvent
trigger: {
type: killed
filter: companion
}
requires: {
type: canSpot
filter: culture(sauron),orc,inSkirmish
}
effect: {
type: choice
player: freeps
texts: [
Add a burden
Discard the top 4 cards of your draw deck
]
effects: [
{
type: addBurdens
amount: 1
}
{
type: discardTopCardsFromDeck
deck: freeps
count: 4
forced: false
}
]
type: repeat
amount: {
type: ForEachInDeadPile
filter: any
}
effect: {
type: choice
player: freeps
texts: [
Add a burden
Discard the top 4 cards of your draw deck
]
effects: [
{
type: addBurdens
amount: 1
}
{
type: discardTopCardsFromDeck
deck: freeps
count: 4
forced: false
}
]
}
}
},
{
type: responseEvent
requires: {
type: cantSpot
filter: culture(sauron),orc,inSkirmish
}
trigger: {
type: TakesWound
filter: companion,zone(dead)
source: culture(sauron),orc
}
effect: {
type: repeat
amount: {
type: ForEachInDeadPile
filter: any
}
effect: {
type: choice
player: freeps
texts: [
Add a burden
Discard the top 4 cards of your draw deck
]
effects: [
{
type: addBurdens
amount: 1
}
{
type: discardTopCardsFromDeck
deck: freeps
count: 4
forced: false
}
]
}
}
}
}
]
gametext: If a companion is killed by a [sauron] Orc, for each card in the dead pile the Free Peoples player must choose to add a burden or discard 4 cards from the top of their draw deck.
lore: For sport, Orcs hew cruelly at the bodies of those they slay.
promotext: ""

View File

@@ -11,7 +11,7 @@ import org.json.simple.JSONObject;
public class ResponseEventEffectProcessor implements EffectProcessor {
@Override
public void processEffect(JSONObject value, BuiltLotroCardBlueprint blueprint, CardGenerationEnvironment environment) throws InvalidCardDefinitionException {
FieldUtils.validateAllowedFields(value, "trigger", "cost", "effect");
FieldUtils.validateAllowedFields(value, "trigger", "requires", "cost", "effect");
final JSONObject[] triggerArray = FieldUtils.getObjectArray(value.get("trigger"), "trigger");
@@ -21,7 +21,7 @@ public class ResponseEventEffectProcessor implements EffectProcessor {
DefaultActionSource triggerActionSource = new DefaultActionSource();
triggerActionSource.addPlayRequirement(triggerChecker);
EffectUtils.processCostsAndEffects(value, environment, triggerActionSource);
EffectUtils.processRequirementsCostsAndEffects(value, environment, triggerActionSource);
if (before) {
blueprint.appendOptionalInHandBeforeAction(triggerActionSource);

View File

@@ -16,7 +16,7 @@ public class AboutToTakeWound implements TriggerCheckerProducer {
FieldUtils.validateAllowedFields(value, "source", "filter");
String source = FieldUtils.getString(value.get("source"), "source", "any");
String filter = FieldUtils.getString(value.get("filter"), "source");
String filter = FieldUtils.getString(value.get("filter"), "filter");
final FilterableSource sourceFilter = environment.getFilterFactory().generateFilter(source, environment);
final FilterableSource affectedFilter = environment.getFilterFactory().generateFilter(filter, environment);

View File

@@ -6,6 +6,7 @@ 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.Filterable;
import com.gempukku.lotro.filters.Filters;
import com.gempukku.lotro.game.PhysicalCard;
import com.gempukku.lotro.logic.timing.TriggerConditions;
import com.gempukku.lotro.logic.timing.results.WoundResult;
@@ -14,12 +15,15 @@ import org.json.simple.JSONObject;
public class TakesWound implements TriggerCheckerProducer {
@Override
public TriggerChecker getTriggerChecker(JSONObject value, CardGenerationEnvironment environment) throws InvalidCardDefinitionException {
FieldUtils.validateAllowedFields(value, "filter", "memorize");
FieldUtils.validateAllowedFields(value, "filter", "source", "memorize");
String source = FieldUtils.getString(value.get("source"), "source", "any");
String filter = FieldUtils.getString(value.get("filter"), "filter", "any");
final String filter = FieldUtils.getString(value.get("filter"), "filter", "any");
final String memorize = FieldUtils.getString(value.get("memorize"), "memorize");
final FilterableSource filterableSource = environment.getFilterFactory().generateFilter(filter, environment);
final FilterableSource sourceFilter = environment.getFilterFactory().generateFilter(source, environment);
final FilterableSource targetFilterable = environment.getFilterFactory().generateFilter(filter, environment);
return new TriggerChecker() {
@Override
@@ -29,8 +33,15 @@ public class TakesWound implements TriggerCheckerProducer {
@Override
public boolean accepts(ActionContext actionContext) {
final Filterable filterable = filterableSource.getFilterable(actionContext);
final Filterable filterable = targetFilterable.getFilterable(actionContext);
final Filterable sourceFilterable = sourceFilter.getFilterable(actionContext);
final boolean result = TriggerConditions.forEachWounded(actionContext.getGame(), actionContext.getEffectResult(), filterable);
if(result && !source.equals("any")) {
var sources = ((WoundResult) actionContext.getEffectResult()).getSources();
if(sources.stream().noneMatch(x -> Filters.and(sourceFilterable).accepts(actionContext.getGame(), x))) {
return false;
}
}
if (result && memorize != null) {
final PhysicalCard woundedCard = ((WoundResult) actionContext.getEffectResult()).getWoundedCard();
actionContext.setCardMemory(memorize, woundedCard);

View File

@@ -233,6 +233,16 @@ public class GenericCardTestHelper extends AbstractAtTest {
return actions.stream().anyMatch(x -> x.toLowerCase().contains(lowerAction));
}
public Boolean FreepsChoiceAvailable(String choice) { return ChoiceAvailable(P1, choice); }
public Boolean ShadowChoiceAvailable(String choice) { return ChoiceAvailable(P2, choice); }
public Boolean ChoiceAvailable(String player, String choice) {
List<String> actions = GetADParamAsList(player, "results");
if(actions == null)
return false;
String lowerChoice = choice.toLowerCase();
return actions.stream().anyMatch(x -> x.toLowerCase().contains(lowerChoice));
}
public Boolean FreepsAnyActionsAvailable() { return AnyActionsAvailable(P1); }
public Boolean ShadowAnyActionsAvailable() { return AnyActionsAvailable(P2); }
public Boolean AnyActionsAvailable(String player) {
@@ -498,7 +508,7 @@ public class GenericCardTestHelper extends AbstractAtTest {
Arrays.stream(cards).forEach(card -> MoveCardToZone(P1, card, Zone.SUPPORT));
}
public void ShadowMoveCardToSupportArea(String...names) {
Arrays.stream(names).forEach(name -> ShadowMoveCardToSupportArea(GetFreepsCard(name)));
Arrays.stream(names).forEach(name -> ShadowMoveCardToSupportArea(GetShadowCard(name)));
}
public void ShadowMoveCardToSupportArea(PhysicalCardImpl...cards) {
Arrays.stream(cards).forEach(card -> MoveCardToZone(P2, card, Zone.SUPPORT));
@@ -790,6 +800,7 @@ public class GenericCardTestHelper extends AbstractAtTest {
return _game.getModifiersQuerying().getStrength(_game, card);
}
public int GetVitality(PhysicalCardImpl card) { return _game.getModifiersQuerying().getVitality(_game, card); }
public int GetResistance(PhysicalCardImpl card) { return _game.getModifiersQuerying().getResistance(_game, card); }
public int GetMinionSiteNumber(PhysicalCardImpl card) { return _game.getModifiersQuerying().getMinionSiteNumber(_game, card); }
public int GetGeneralSiteNumber(PhysicalCardImpl card)
{

View File

@@ -0,0 +1,234 @@
package com.gempukku.lotro.cards.unofficial.pc.errata.set01;
import com.gempukku.lotro.cards.GenericCardTestHelper;
import com.gempukku.lotro.common.*;
import com.gempukku.lotro.game.CardNotFoundException;
import com.gempukku.lotro.logic.decisions.DecisionResultInvalidException;
import org.junit.Test;
import java.util.HashMap;
import static org.junit.Assert.*;
public class Card_01_265_ErrataTests
{
protected GenericCardTestHelper GetScenario() throws CardNotFoundException, DecisionResultInvalidException {
return new GenericCardTestHelper(
new HashMap<>()
{{
put("butchery", "51_265");
put("slayer", "3_93");
put("scavengers", "1_179");
put("sam", "2_114");
put("sword", "1_299");
put("guard1", "1_7");
put("guard2", "1_7");
}},
GenericCardTestHelper.FellowshipSites,
GenericCardTestHelper.FOTRFrodo,
GenericCardTestHelper.FOTRRing
);
}
@Test
public void OrcButcheryStatsAndKeywordsAreCorrect() throws DecisionResultInvalidException, CardNotFoundException {
/**
* Set: 1
* Title: Orc Butchery
* Unique: False
* Side: SHADOW
* Culture: Sauron
* Twilight Cost: 0
* Type: event
* Subtype: Response
* Game Text: If a companion is killed by a [sauron] Orc, then for each card in the dead pile the Free Peoples
* player must choose to add a burden or discard 4 cards from the top of their draw deck.
*/
//Pre-game setup
var scn = GetScenario();
var butchery = scn.GetFreepsCard("butchery");
assertFalse(butchery.getBlueprint().isUnique());
assertEquals(Side.SHADOW, butchery.getBlueprint().getSide());
assertEquals(Culture.SAURON, butchery.getBlueprint().getCulture());
assertEquals(CardType.EVENT, butchery.getBlueprint().getCardType());
assertTrue(scn.HasKeyword(butchery, Keyword.RESPONSE));
assertEquals(0, butchery.getBlueprint().getTwilightCost());
}
@Test
public void ButcheryIsTriggeredBySkirmishOverwhelmKill() throws DecisionResultInvalidException, CardNotFoundException {
//Pre-game setup
var scn = GetScenario();
var butchery = scn.GetShadowCard("butchery");
var slayer = scn.GetShadowCard("slayer");
scn.ShadowMoveCardToHand(butchery);
scn.ShadowMoveCharToTable(slayer);
var sam = scn.GetFreepsCard("sam");
scn.FreepsMoveCharToTable(sam);
scn.StartGame();
scn.SkipToAssignments();
scn.FreepsAssignToMinions(sam, slayer);
scn.FreepsResolveSkirmish(sam);
scn.PassCurrentPhaseActions();
assertTrue(scn.ShadowHasOptionalTriggerAvailable());
}
@Test
public void ButcheryIsTriggeredBySkirmishWoundKill() throws DecisionResultInvalidException, CardNotFoundException {
//Pre-game setup
var scn = GetScenario();
var butchery = scn.GetShadowCard("butchery");
var slayer = scn.GetShadowCard("slayer");
scn.ShadowMoveCardToHand(butchery);
scn.ShadowMoveCharToTable(slayer);
var sam = scn.GetFreepsCard("sam");
scn.FreepsMoveCharToTable(sam);
scn.FreepsAttachCardsTo(sam, "sword");
scn.StartGame();
scn.AddWoundsToChar(sam, 3);
scn.SkipToAssignments();
scn.FreepsAssignToMinions(sam, slayer);
scn.FreepsResolveSkirmish(sam);
scn.PassCurrentPhaseActions();
assertTrue(scn.ShadowHasOptionalTriggerAvailable());
}
@Test
public void ButcheryIsTriggeredByDirectWoundAbility() throws DecisionResultInvalidException, CardNotFoundException {
//Pre-game setup
var scn = GetScenario();
var butchery = scn.GetShadowCard("butchery");
var slayer = scn.GetShadowCard("slayer");
scn.ShadowMoveCardToHand(butchery);
scn.ShadowMoveCharToTable(slayer);
var sam = scn.GetFreepsCard("sam");
scn.FreepsMoveCharToTable(sam);
scn.StartGame();
scn.AddWoundsToChar(sam, 3);
scn.SkipToAssignments();
scn.FreepsDeclineAssignments();
scn.ShadowDeclineAssignments();
assertEquals(Phase.REGROUP, scn.GetCurrentPhase());
scn.FreepsPassCurrentPhaseAction();
scn.ShadowUseCardAction(slayer);
assertTrue(scn.ShadowHasOptionalTriggerAvailable());
}
@Test
public void ButcheryForcesBurdenIfLessThan4TopDeckCards() throws DecisionResultInvalidException, CardNotFoundException {
//Pre-game setup
var scn = GetScenario();
var butchery = scn.GetShadowCard("butchery");
var slayer = scn.GetShadowCard("slayer");
scn.ShadowMoveCardToHand(butchery);
scn.ShadowMoveCharToTable(slayer);
var sam = scn.GetFreepsCard("sam");
scn.FreepsMoveCharToTable(sam);
scn.FreepsMoveCardToDiscard("sword", "guard1", "guard2");
scn.StartGame();
scn.SkipToAssignments();
scn.FreepsAssignToMinions(sam, slayer);
scn.FreepsResolveSkirmish(sam);
scn.PassCurrentPhaseActions();
assertEquals(3, scn.GetFreepsDeckCount());
assertEquals(1, scn.GetBurdens());
assertEquals(Zone.HAND, butchery.getZone());
scn.ShadowAcceptOptionalTrigger();
assertEquals(2, scn.GetBurdens());
assertEquals(Zone.DISCARD, butchery.getZone());
}
@Test
public void ButcheryOffersChoiceOfBurdenOr4TopDeck() throws DecisionResultInvalidException, CardNotFoundException {
//Pre-game setup
var scn = GetScenario();
var butchery = scn.GetShadowCard("butchery");
var slayer = scn.GetShadowCard("slayer");
scn.ShadowMoveCardToHand(butchery);
scn.ShadowMoveCharToTable(slayer);
var sam = scn.GetFreepsCard("sam");
scn.FreepsMoveCharToTable(sam);
scn.StartGame();
scn.SkipToAssignments();
scn.FreepsAssignToMinions(sam, slayer);
scn.FreepsResolveSkirmish(sam);
scn.PassCurrentPhaseActions();
assertTrue(scn.ShadowHasOptionalTriggerAvailable());
scn.ShadowAcceptOptionalTrigger();
assertTrue(scn.FreepsDecisionAvailable("Choose action to perform"));
assertTrue(scn.FreepsChoiceAvailable("Add a burden"));
assertTrue(scn.FreepsChoiceAvailable("Discard the top 4 cards of your draw deck"));
assertEquals(6, scn.GetFreepsDeckCount());
scn.FreepsChooseMultipleChoiceOption("Discard");
assertEquals(2, scn.GetFreepsDeckCount());
}
@Test
public void ButcheryForcesChoicePerDeadPileDenizen() throws DecisionResultInvalidException, CardNotFoundException {
//Pre-game setup
var scn = GetScenario();
var butchery = scn.GetShadowCard("butchery");
var slayer = scn.GetShadowCard("slayer");
scn.ShadowMoveCardToHand(butchery);
scn.ShadowMoveCharToTable(slayer);
var sam = scn.GetFreepsCard("sam");
scn.FreepsMoveCharToTable(sam);
scn.FreepsMoveCardToDeadPile("guard1", "guard2");
scn.StartGame();
scn.SkipToAssignments();
scn.FreepsAssignToMinions(sam, slayer);
scn.FreepsResolveSkirmish(sam);
scn.PassCurrentPhaseActions();
assertEquals(1, scn.GetBurdens());
assertTrue(scn.ShadowHasOptionalTriggerAvailable());
scn.ShadowAcceptOptionalTrigger();
assertTrue(scn.FreepsChoiceAvailable("Add a burden"));
scn.FreepsChooseMultipleChoiceOption("Burden");
assertEquals(2, scn.GetBurdens());
assertTrue(scn.FreepsChoiceAvailable("Add a burden"));
scn.FreepsChooseMultipleChoiceOption("Burden");
assertEquals(3, scn.GetBurdens());
assertTrue(scn.FreepsChoiceAvailable("Add a burden"));
scn.FreepsChooseMultipleChoiceOption("Burden");
assertEquals(4, scn.GetBurdens());
}
}