Saruman, Keeper of Isengard errata and associated changes

Added Saruman, KoI errata.  Added CantBeAssignedToSkirmish to the blueprint json loading.  Edited the PreventWound effect to support the Memorize directive (so saruman could remember the blocked uruk's id and make it fierce). Revamped the unit tests to support playing cards and using actions based on a card reference rather than a hard-coded string.  Edited existing unit tests to use the new functionality.
This commit is contained in:
Christian 'ketura' McCarty
2021-02-02 23:09:40 -06:00
parent b60b2b2df8
commit c71ac3a2cc
11 changed files with 293 additions and 57 deletions

View File

@@ -475,6 +475,61 @@
}
},
"21_3068": {
"side": "shadow",
"site": 4,
"cost": 4,
"race": "Wizard",
"strength": 8,
"culture": "Isengard",
"vitality": 4,
"subtitle": "Keeper of Isengard",
"title": "*Saruman",
"type": "minion",
"effects": [
{
"type": "modifier",
"modifier": {
"type": "cantbeassignedtoskirmish",
"filter": "self"
}
},
{
"type": "modifier",
"modifier": {
"type": "cantTakeWounds",
"filter": "self",
"condition": {
"type": "phase",
"phase": "archery"
}
}
},
{
"type": "activatedTrigger",
"trigger": {
"type": "aboutToTakeWound",
"filter": "uruk-hai"
},
"cost": {
"type": "exert",
"filter": "self",
"times": 1
},
"effect": [
{
"type": "preventWound",
"filter": "choose(uruk-hai)",
"memorize": "uruk"
},
{
"type": "addKeyword",
"filter": "memory(uruk)",
"keyword": "fierce"
}
]
},
]
},
}

View File

@@ -23,9 +23,10 @@ import java.util.Collection;
public class PreventWound implements EffectAppenderProducer {
@Override
public EffectAppender createEffectAppender(JSONObject effectObject, CardGenerationEnvironment environment) throws InvalidCardDefinitionException {
FieldUtils.validateAllowedFields(effectObject, "filter");
FieldUtils.validateAllowedFields(effectObject, "filter", "memorize");
final String filter = FieldUtils.getString(effectObject.get("filter"), "filter", "all(any)");
final String memory = FieldUtils.getString(effectObject.get("memorize"), "memorize", "_temp");
MultiEffectAppender result = new MultiEffectAppender();
@@ -34,12 +35,12 @@ public class PreventWound implements EffectAppenderProducer {
(actionContext) -> {
final PreventableCardEffect preventableEffect = (PreventableCardEffect) actionContext.getEffect();
return Filters.in(preventableEffect.getAffectedCardsMinusPrevented(actionContext.getGame()));
}, new ConstantEvaluator(1), "_temp", "you", "Choose characters to prevent effect to", environment));
}, new ConstantEvaluator(1), memory, "you", "Choose characters to prevent effect to", environment));
result.addEffectAppender(
new DelayedAppender() {
@Override
protected Effect createEffect(boolean cost, CostToEffectAction action, ActionContext actionContext) {
final Collection<? extends PhysicalCard> cards = actionContext.getCardsFromMemory("_temp");
final Collection<? extends PhysicalCard> cards = actionContext.getCardsFromMemory(memory);
final PreventableCardEffect preventableEffect = (PreventableCardEffect) actionContext.getEffect();
return new PreventCardEffect(preventableEffect, Filters.in(cards));

View File

@@ -0,0 +1,49 @@
package com.gempukku.lotro.cards.build.field.effect.modifier;
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.appender.DelayedAppender;
import com.gempukku.lotro.cards.build.field.effect.appender.MultiEffectAppender;
import com.gempukku.lotro.cards.build.field.effect.appender.resolver.CardResolver;
import com.gempukku.lotro.cards.build.field.effect.appender.resolver.TimeResolver;
import com.gempukku.lotro.common.Filterable;
import com.gempukku.lotro.filters.Filters;
import com.gempukku.lotro.game.PhysicalCard;
import com.gempukku.lotro.logic.actions.CostToEffectAction;
import com.gempukku.lotro.logic.effects.AddUntilModifierEffect;
import com.gempukku.lotro.logic.modifiers.CantBeAssignedToSkirmishModifier;
import com.gempukku.lotro.logic.modifiers.KeywordModifier;
import com.gempukku.lotro.logic.modifiers.Modifier;
import com.gempukku.lotro.logic.modifiers.OverwhelmedByMultiplierModifier;
import com.gempukku.lotro.logic.modifiers.evaluator.ConstantEvaluator;
import com.gempukku.lotro.logic.modifiers.evaluator.Evaluator;
import com.gempukku.lotro.logic.timing.Effect;
import org.json.simple.JSONObject;
import java.util.Collection;
public class CantBeAssignedToSkirmish implements ModifierSourceProducer {
@Override
public ModifierSource getModifierSource(JSONObject effectObject, CardGenerationEnvironment environment) throws InvalidCardDefinitionException {
FieldUtils.validateAllowedFields(effectObject, "filter", "condition");
final JSONObject[] conditionArray = FieldUtils.getObjectArray(effectObject.get("condition"), "condition");
final String filter = FieldUtils.getString(effectObject.get("filter"), "filter");
final FilterableSource filterableSource = environment.getFilterFactory().generateFilter(filter, environment);
final Requirement[] requirements = environment.getRequirementFactory().getRequirements(conditionArray, environment);
MultiEffectAppender result = new MultiEffectAppender();
return new ModifierSource() {
@Override
public Modifier getModifier(ActionContext actionContext) {
return new CantBeAssignedToSkirmishModifier(actionContext.getSource(),
new RequirementCondition(requirements, actionContext),
filterableSource.getFilterable(actionContext));
}
};
}
}

View File

@@ -54,6 +54,7 @@ public class ModifierSourceFactory {
modifierProducers.put("hastomoveifable", new HasToMoveIfAble());
modifierProducers.put("allycanparticipateinarcheryfireandskirmishes", new AllyCanParticipateInArcheryFireAndSkirmishes());
modifierProducers.put("cantlookorrevealhand", new CantLookOrRevealHand());
modifierProducers.put("cantbeassignedtoskirmish", new CantBeAssignedToSkirmish());
}
public ModifierSource getModifier(JSONObject object, CardGenerationEnvironment environment) throws InvalidCardDefinitionException {

View File

@@ -9,6 +9,7 @@ import com.gempukku.lotro.game.CardNotFoundException;
import com.gempukku.lotro.game.PhysicalCard;
import com.gempukku.lotro.game.PhysicalCardImpl;
import com.gempukku.lotro.game.state.Assignment;
import com.gempukku.lotro.logic.GameUtils;
import com.gempukku.lotro.logic.decisions.AwaitingDecision;
import com.gempukku.lotro.logic.decisions.DecisionResultInvalidException;
import com.gempukku.lotro.logic.vo.LotroDeck;
@@ -109,8 +110,41 @@ public class GenericCardTest extends AbstractAtTest {
public AwaitingDecision ShadowGetAwaitingDecision() { return GetAwaitingDecision(P2); }
public AwaitingDecision GetAwaitingDecision(String playerID) { return _userFeedback.getAwaitingDecision(playerID); }
public void FreepsUseAction(String name) throws DecisionResultInvalidException { playerDecided(P1, getCardActionId(P1, name)); }
public void ShadowUseAction(String name) throws DecisionResultInvalidException { playerDecided(P2, getCardActionId(P2, name)); }
public Boolean FreepsActionAvailable(String action) { return ActionAvailable(P1, action); }
public Boolean FreepsCardActionAvailable(PhysicalCardImpl card) { return ActionAvailable(P1, "Use " + GameUtils.getFullName(card)); }
public Boolean FreepsCardPlayAvailable(PhysicalCardImpl card) { return ActionAvailable(P1, "Play " + GameUtils.getFullName(card)); }
public Boolean ShadowActionAvailable(String action) { return ActionAvailable(P2, action); }
public Boolean ShadowCardActionAvailable(PhysicalCardImpl card) { return ActionAvailable(P2, "Use " + GameUtils.getFullName(card)); }
public Boolean ShadowCardPlayAvailable(PhysicalCardImpl card) { return ActionAvailable(P2, "Play " + GameUtils.getFullName(card)); }
public Boolean ActionAvailable(String player, String action) {
List<String> actions = GetAvailableActions(player);
String lowerAction = action.toLowerCase();
return actions.stream().anyMatch(x -> x.toLowerCase().startsWith(lowerAction));
}
public List<String> FreepsGetADParamAsList(String paramName) { return Arrays.asList((String[])GetAwaitingDecisionParam(P1, paramName)); }
public List<String> ShadowGetADParamAsList(String paramName) { return Arrays.asList((String[])GetAwaitingDecisionParam(P2, paramName)); }
public Object FreepsGetADParam(String paramName) { return GetAwaitingDecisionParam(P1, paramName); }
public Object ShadowGetADParam(String paramName) { return GetAwaitingDecisionParam(P2, paramName); }
public Object GetAwaitingDecisionParam(String playerID, String paramName) {
AwaitingDecision decision = _userFeedback.getAwaitingDecision(playerID);
return decision.getDecisionParameters().get(paramName);
}
public Map<String, Object> GetAwaitingDecisionParams(String playerID) {
AwaitingDecision decision = _userFeedback.getAwaitingDecision(playerID);
return decision.getDecisionParameters();
}
public void FreepsUseCardAction(String name) throws DecisionResultInvalidException { playerDecided(P1, getCardActionId(P1, name)); }
public void FreepsUseCardAction(PhysicalCardImpl card) throws DecisionResultInvalidException { playerDecided(P1, getCardActionId(P1, "Use " + GameUtils.getFullName(card))); }
public void ShadowUseCardAction(String name) throws DecisionResultInvalidException { playerDecided(P2, getCardActionId(P2, name)); }
public void ShadowUseCardAction(PhysicalCardImpl card) throws DecisionResultInvalidException { playerDecided(P2, getCardActionId(P2, "Use " + GameUtils.getFullName(card))); }
public void FreepsPlayCard(String name) throws DecisionResultInvalidException { playerDecided(P1, getCardActionId(P1, name)); }
public void FreepsPlayCard(PhysicalCardImpl card) throws DecisionResultInvalidException { playerDecided(P1, getCardActionId(P1, "Play " + GameUtils.getFullName(card))); }
public void ShadowPlayCard(String name) throws DecisionResultInvalidException { playerDecided(P2, getCardActionId(P2, name)); }
public void ShadowPlayCard(PhysicalCardImpl card) throws DecisionResultInvalidException { playerDecided(P2, getCardActionId(P2, "Play " + GameUtils.getFullName(card))); }
public int FreepsGetWoundsOn(String cardName) { return GetWoundsOn(GetFreepsCard(cardName)); }
public int ShadowGetWoundsOn(String cardName) { return GetWoundsOn(GetShadowCard(cardName)); }
@@ -134,13 +168,7 @@ public class GenericCardTest extends AbstractAtTest {
public Phase GetCurrentPhase() { return _game.getGameState().getCurrentPhase(); }
public Boolean FreepsActionAvailable(String action) { return ActionAvailable(P1, action); }
public Boolean ShadowActionAvailable(String action) { return ActionAvailable(P2, action); }
public Boolean ActionAvailable(String player, String action) {
List<String> actions = GetAvailableActions(player);
String lowerAction = action.toLowerCase();
return actions.stream().anyMatch(x -> x.toLowerCase().startsWith(lowerAction));
}
public void FreepsMoveCardToHand(String cardName) { MoveCardToZone(P1, GetFreepsCard(cardName), Zone.HAND); }
public void FreepsMoveCardToHand(PhysicalCardImpl card) { MoveCardToZone(P1, card, Zone.HAND); }
@@ -175,23 +203,6 @@ public class GenericCardTest extends AbstractAtTest {
_game.getGameState().addCardToZone(_game, card, zone);
}
public List<String> FreepsGetADParamAsList(String paramName) { return Arrays.asList((String[])GetAwaitingDecisionParam(P1, paramName)); }
public List<String> ShadowGetADParamAsList(String paramName) { return Arrays.asList((String[])GetAwaitingDecisionParam(P2, paramName)); }
public Object FreepsGetADParam(String paramName) { return GetAwaitingDecisionParam(P1, paramName); }
public Object ShadowGetADParam(String paramName) { return GetAwaitingDecisionParam(P2, paramName); }
public Object GetAwaitingDecisionParam(String playerID, String paramName) {
AwaitingDecision decision = _userFeedback.getAwaitingDecision(playerID);
return decision.getDecisionParameters().get(paramName);
}
public Map<String, Object> GetAwaitingDecisionParams(String playerID) {
AwaitingDecision decision = _userFeedback.getAwaitingDecision(playerID);
return decision.getDecisionParameters();
}
public void FreepsPlayCharFromHand(String cardName) throws DecisionResultInvalidException {
PhysicalCardImpl card = GetFreepsCard(cardName);
List<String> availableIds = FreepsGetADParamAsList("cardId");
@@ -235,12 +246,17 @@ public class GenericCardTest extends AbstractAtTest {
}
public void SkipCurrentPhaseActions() throws DecisionResultInvalidException {
Phase current = _game.getGameState().getCurrentPhase();
FreepsSkipCurrentPhaseAction();
ShadowSkipCurrentPhaseAction();
}
public void FreepsSkipCurrentPhaseAction() throws DecisionResultInvalidException {
if(_userFeedback.getAwaitingDecision(P1) != null) {
playerDecided(P1, "");
}
}
public void ShadowSkipCurrentPhaseAction() throws DecisionResultInvalidException {
if(_userFeedback.getAwaitingDecision(P2) != null) {
playerDecided(P2, "");
}
@@ -276,6 +292,11 @@ public class GenericCardTest extends AbstractAtTest {
public void FreepsChooseCard(PhysicalCardImpl card) throws DecisionResultInvalidException {
playerDecided(P1, String.valueOf(card.getCardId()));
}
public void ShadowChooseCard(PhysicalCardImpl card) throws DecisionResultInvalidException {
playerDecided(P2, String.valueOf(card.getCardId()));
}
public boolean FreepsCanChooseCharacter(PhysicalCardImpl card) { return FreepsGetADParamAsList("cardId").contains(card.getCardId()); }
public boolean ShadowCanChooseCharacter(PhysicalCardImpl card) { return ShadowGetADParamAsList("cardId").contains(card.getCardId()); }
public boolean IsCharAssigned(PhysicalCardImpl card) {
List<Assignment> assigns = _game.getGameState().getAssignments();

View File

@@ -4,7 +4,6 @@ import com.gempukku.lotro.cards.GenericCardTest;
import com.gempukku.lotro.common.Phase;
import com.gempukku.lotro.game.CardNotFoundException;
import com.gempukku.lotro.game.PhysicalCardImpl;
import com.gempukku.lotro.logic.decisions.AwaitingDecision;
import com.gempukku.lotro.logic.decisions.DecisionResultInvalidException;
import static org.junit.Assert.*;
import org.junit.Test;
@@ -61,13 +60,13 @@ public class Elrond_LoRErrataTest
scn.StartGame();
assertEquals(Phase.FELLOWSHIP, scn.GetCurrentPhase());
assertTrue(scn.FreepsActionAvailable("Use Elrond"));
assertTrue(scn.FreepsCardActionAvailable(elrond));
assertEquals(0, scn.GetWoundsOn(elrond));
assertEquals(0, scn.GetFreepsHandCount());
assertEquals(1, scn.GetFreepsDeckCount());
scn.FreepsUseAction("Use Elrond");
scn.FreepsUseCardAction(elrond);
assertEquals(2, scn.GetWoundsOn(elrond));
assertEquals(1, scn.GetFreepsHandCount());

View File

@@ -9,7 +9,6 @@ import com.gempukku.lotro.logic.decisions.DecisionResultInvalidException;
import org.junit.Test;
import java.util.HashMap;
import java.util.List;
import static junit.framework.Assert.assertEquals;
import static org.junit.Assert.*;
@@ -50,9 +49,9 @@ public class FlamingBrandErrataTest
scn.StartGame();
assertTrue(scn.FreepsActionAvailable("Play Flaming Brand"));
assertTrue(scn.FreepsCardPlayAvailable(brand));
scn.FreepsUseAction("Play Flaming Brand");
scn.FreepsPlayCard(brand);
//There are 3 companions in play, but only 2 rangers, so we should only see 2 options
assertEquals(2, scn.FreepsGetADParamAsList("cardId").size());
@@ -74,9 +73,9 @@ public class FlamingBrandErrataTest
scn.StartGame();
scn.FreepsUseAction("Play Flaming Brand");
assertTrue(scn.FreepsActionAvailable("Play Flaming Brand"));
scn.FreepsUseAction("Play Flaming Brand");
scn.FreepsPlayCard(brand);
assertTrue(scn.FreepsCardPlayAvailable(brand2));
scn.FreepsPlayCard(brand2);
assertEquals(2, scn.GetAttachedCards(aragorn).size());
}
@@ -100,7 +99,7 @@ public class FlamingBrandErrataTest
scn.StartGame();
assertEquals(8, scn.GetStrength(aragorn));
scn.FreepsUseAction("Play Flaming Brand");
scn.FreepsPlayCard(brand);
assertEquals(9, scn.GetStrength(aragorn));
scn.SkipToPhase(Phase.ASSIGNMENT);
@@ -122,10 +121,10 @@ public class FlamingBrandErrataTest
scn.FreepsResolveSkirmish(aragorn);
assertEquals(1, scn.FreepsGetAvailableActions().size());
assertTrue(scn.FreepsActionAvailable("Use Flaming Brand"));
assertTrue(scn.FreepsCardActionAvailable(brand));
assertFalse(scn.HasKeyword(aragorn, Keyword.DAMAGE));
scn.FreepsUseAction("Use Flaming Brand");
scn.FreepsUseCardAction(brand);
assertEquals(11, scn.GetStrength(aragorn));
assertTrue(scn.HasKeyword(aragorn, Keyword.DAMAGE));
}

View File

@@ -47,13 +47,13 @@ public class Galadriel_LoLErrataTest
scn.StartGame();
assertEquals(Phase.FELLOWSHIP, scn.GetCurrentPhase());
assertTrue(scn.FreepsActionAvailable("Use Galadriel"));
assertTrue(scn.FreepsCardActionAvailable(galadriel));
assertEquals(0, scn.GetWoundsOn(galadriel));
assertEquals(1, scn.GetFreepsHandCount());
assertEquals(0, scn.GetTwilight());
scn.FreepsUseAction("Use Galadriel");
scn.FreepsUseCardAction(galadriel);
assertEquals(2, scn.GetWoundsOn(galadriel));
assertEquals(0, scn.GetFreepsHandCount());

View File

@@ -67,10 +67,10 @@ public class HornOfBoromirErrataTest
scn.StartGame();
assertFalse(scn.FreepsActionAvailable("Play Horn of Boromir"));
scn.FreepsUseAction("Play Boromir");
assertTrue(scn.FreepsActionAvailable("Play Horn of Boromir"));
scn.FreepsUseAction("Play Horn of Boromir");
assertFalse(scn.FreepsCardPlayAvailable(horn));
scn.FreepsPlayCard(boromir);
assertTrue(scn.FreepsCardPlayAvailable(horn));
scn.FreepsPlayCard(horn);
Assert.assertEquals(Zone.ATTACHED, horn.getZone());
Assert.assertEquals(boromir, horn.getAttachedTo());
@@ -96,18 +96,18 @@ public class HornOfBoromirErrataTest
scn.StartGame();
scn.FreepsUseAction("Play Horn of Boromir");
scn.FreepsPlayCard(horn);
scn.SkipToPhase(Phase.ASSIGNMENT);
assertTrue(scn.FreepsActionAvailable("Use Horn of Boromir"));
scn.FreepsUseAction("Use Horn of Boromir");
assertTrue(scn.FreepsCardActionAvailable(horn));
scn.FreepsUseCardAction(horn);
scn.FreepsChooseCard(runner1);
assertEquals(1, scn.GetWoundsOn(boromir));
assertEquals(11, scn.GetStrength(elrond));
//Skip shadow player's action
scn.SkipCurrentPhaseActions();
assertFalse(scn.FreepsActionAvailable("Use Horn of Boromir"));
assertFalse(scn.FreepsCardActionAvailable(horn));
scn.SkipCurrentPhaseActions();
assertTrue(scn.IsCharAssigned(boromir));
@@ -134,10 +134,10 @@ public class HornOfBoromirErrataTest
scn.StartGame();
scn.FreepsUseAction("Play Horn of Boromir");
scn.FreepsPlayCard(horn);
scn.SkipToPhase(Phase.ASSIGNMENT);
scn.FreepsUseAction("Use Horn of Boromir");
scn.FreepsUseCardAction(horn);
scn.FreepsChooseCard(runner1);
assertEquals(1, scn.GetWoundsOn(boromir));

View File

@@ -35,12 +35,12 @@ public class Sam_SoHErrataTest
scn.StartGame();
assertEquals(Phase.FELLOWSHIP, scn.GetCurrentPhase());
assertTrue(scn.FreepsActionAvailable("Use Sam"));
assertTrue(scn.FreepsCardActionAvailable(sam));
assertEquals(0, scn.GetWoundsOn(sam));
assertEquals(1, scn.GetBurdens());
scn.FreepsUseAction("Use Sam");
scn.FreepsUseCardAction(sam);
assertEquals(2, scn.GetWoundsOn(sam));
assertEquals(0, scn.GetBurdens());

View File

@@ -0,0 +1,111 @@
package com.gempukku.lotro.cards.unofficial.pc.errata;
import com.gempukku.lotro.cards.GenericCardTest;
import com.gempukku.lotro.common.Keyword;
import com.gempukku.lotro.common.Phase;
import com.gempukku.lotro.game.CardNotFoundException;
import com.gempukku.lotro.game.PhysicalCardImpl;
import com.gempukku.lotro.logic.decisions.DecisionResultInvalidException;
import org.junit.Test;
import java.util.HashMap;
import static junit.framework.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
public class Saruman_KoIErrataTest
{
protected GenericCardTest GetScenario() throws CardNotFoundException, DecisionResultInvalidException {
return new GenericCardTest(
new HashMap<String, String>()
{{
put("legolas", "1_50");
put("tale", "1_66");
put("doubleshot", "1_38");
put("saruman", "21_3068");
put("uruk1", "1_151");
put("uruk2", "1_151");
}}
);
}
@Test
public void SarumanWorks() throws DecisionResultInvalidException, CardNotFoundException {
//Pre-game setup
GenericCardTest scn = GetScenario();
PhysicalCardImpl legolas = scn.GetFreepsCard("legolas");
PhysicalCardImpl tale = scn.GetFreepsCard("tale");
PhysicalCardImpl doubleshot = scn.GetFreepsCard("doubleshot");
PhysicalCardImpl saruman = scn.GetShadowCard("saruman");
PhysicalCardImpl uruk1 = scn.GetShadowCard("uruk1");
PhysicalCardImpl uruk2 = scn.GetShadowCard("uruk2");
scn.FreepsMoveCharToTable(legolas);
scn.FreepsMoveCardToHand(tale);
scn.FreepsMoveCardToHand(doubleshot);
scn.ShadowMoveCharToTable(saruman);
scn.ShadowMoveCharToTable(uruk1);
scn.ShadowMoveCharToTable(uruk2);
scn.StartGame();
scn.FreepsPlayCard(tale);
scn.SkipToPhase(Phase.ARCHERY);
//can't hit saruman
scn.FreepsUseCardAction(legolas);
assertFalse(scn.FreepsCanChooseCharacter(saruman));
scn.FreepsChooseCard(uruk1);
assertTrue(scn.ShadowCardActionAvailable(saruman));
//saruman blocks the uruk hit
scn.ShadowUseCardAction(saruman);
assertEquals(0, scn.GetWoundsOn(uruk1));
assertEquals(1, scn.GetWoundsOn(saruman));
assertTrue(scn.HasKeyword(uruk1, Keyword.FIERCE));
//shadow has to skip archery actions
scn.ShadowSkipCurrentPhaseAction();
//Repeat the greenleaf ability to ensure the last can't be blocked by saruman
scn.FreepsUseCardAction(legolas);
scn.FreepsChooseCard(uruk1);
scn.ShadowUseCardAction(saruman);
scn.ShadowSkipCurrentPhaseAction();
scn.FreepsUseCardAction(legolas);
scn.FreepsChooseCard(uruk1);
scn.ShadowUseCardAction(saruman);
scn.ShadowSkipCurrentPhaseAction();
//greenleaf is out of vitality, so play doubleshot
scn.FreepsPlayCard(doubleshot);
scn.ShadowSkipCurrentPhaseAction();
scn.FreepsSkipCurrentPhaseAction();
//Archery wound
scn.ShadowChooseCard(uruk1);
//Now that we've done 4 total wounds, we should see an exhausted saruman and an uruk1 with 1 wound
assertEquals(1, scn.GetWoundsOn(uruk1));
assertEquals(3, scn.GetWoundsOn(saruman));
scn.SkipToPhase(Phase.ASSIGNMENT);
scn.SkipCurrentPhaseActions();
//saruman is not on the list of assignable minions
assertEquals(2, scn.FreepsGetADParamAsList("minions").size());
}
}