Fixed a persistent issue with testing stacked cards via the test rig (finally). Improved ChooseANumber to use value resolvers.

This commit is contained in:
Christian 'ketura' McCarty
2022-07-21 07:35:14 -05:00
parent 6319bd3820
commit d7e7fcfaa4
4 changed files with 120 additions and 50 deletions

View File

@@ -1,13 +1,11 @@
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.PlayerSource;
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.PlayerResolver;
import com.gempukku.lotro.cards.build.field.effect.appender.resolver.ValueResolver;
import com.gempukku.lotro.logic.actions.CostToEffectAction;
import com.gempukku.lotro.logic.decisions.DecisionResultInvalidException;
import com.gempukku.lotro.logic.decisions.IntegerAwaitingDecision;
@@ -22,8 +20,9 @@ public class ChooseANumber implements EffectAppenderProducer {
final String player = FieldUtils.getString(effectObject.get("player"), "player", "you");
final String displayText = FieldUtils.getString(effectObject.get("text"), "text", "Choose a number");
final int from = FieldUtils.getInteger(effectObject.get("from"), "from", 0);
final int to = FieldUtils.getInteger(effectObject.get("to"), "to", 1);
final ValueSource fromSource = ValueResolver.resolveEvaluator(effectObject.get("from"), 0, environment);
final ValueSource toSource = ValueResolver.resolveEvaluator(effectObject.get("to"), 1, environment);
final String memorize = FieldUtils.getString(effectObject.get("memorize"), "memorize");
final PlayerSource playerSource = PlayerResolver.resolvePlayer(player, environment);
@@ -35,7 +34,10 @@ public class ChooseANumber implements EffectAppenderProducer {
@Override
protected Effect createEffect(boolean cost, CostToEffectAction action, ActionContext actionContext) {
return new PlayoutDecisionEffect(actionContext.getPerformingPlayer(),
new IntegerAwaitingDecision(1, displayText, from, to) {
new IntegerAwaitingDecision(1, displayText,
fromSource.getEvaluator(actionContext).evaluateExpression(actionContext.getGame(), null),
toSource.getEvaluator(actionContext).evaluateExpression(actionContext.getGame(), null))
{
@Override
public void decisionMade(String result) throws DecisionResultInvalidException {
actionContext.setValueToMemory(memorize, String.valueOf(getValidatedResult(result)));

View File

@@ -46,7 +46,8 @@ public class CardResolver {
if (type.startsWith("memory(") && type.endsWith(")")) {
return resolveMemoryCards(type, choiceFilter, playabilityFilter, countSource, memory, cardSource);
} else if (type.startsWith("choose(") && type.endsWith(")")) {
}
else if (type.startsWith("choose(") && type.endsWith(")")) {
final PlayerSource playerSource = PlayerResolver.resolvePlayer(choicePlayer, environment);
ChoiceEffectSource effectSource = (possibleCards, action, actionContext, min, max) -> {
String choicePlayerId = playerSource.getPlayer(actionContext);

View File

@@ -55,13 +55,15 @@ public class GenericCardTestHelper extends AbstractAtTest {
// Player key, then name/card
public Map<String, Map<String, PhysicalCardImpl>> Cards = new HashMap<>();
public GenericCardTestHelper(Map<String, String> cardIDs) throws CardNotFoundException, DecisionResultInvalidException {
public GenericCardTestHelper(HashMap<String, String> cardIDs) throws CardNotFoundException, DecisionResultInvalidException {
this(cardIDs, null, null, null);
}
public GenericCardTestHelper(Map<String, String> cardIDs, Map<String, String> siteIDs, String ringBearerID, String ringID) throws CardNotFoundException, DecisionResultInvalidException {
public GenericCardTestHelper(HashMap<String, String> cardIDs, HashMap<String, String> siteIDs, String ringBearerID, String ringID) throws CardNotFoundException, DecisionResultInvalidException {
super();
if(siteIDs == null || ringBearerID == null || ringID == null) {
initializeSimplestGame();
}
@@ -91,20 +93,17 @@ public class GenericCardTestHelper extends AbstractAtTest {
if(cardIDs != null) {
for(String name : cardIDs.keySet()) {
String id = cardIDs.get(name);
PhysicalCardImpl card = CreateCard(P1, id);
PhysicalCardImpl card = createCard(P1, id);
Cards.get(P1).put(name, card);
FreepsMoveCardsToTopOfDeck(card);
card = CreateCard(P2, id);
card = createCard(P2, id);
Cards.get(P2).put(name, card);
FreepsMoveCardsToTopOfDeck(card);
}
}
}
public PhysicalCardImpl CreateCard(String playerID, String cardID) throws CardNotFoundException {
return new PhysicalCardImpl(LastCardID++, cardID, playerID, _library.getLotroCardBlueprint(cardID));
}
public void StartGame() throws DecisionResultInvalidException {
skipMulligans();
@@ -256,10 +255,9 @@ public class GenericCardTestHelper extends AbstractAtTest {
public int GetFreepsDiscardCount() { return GetPlayerDiscardCount(P1); }
public int GetShadowDiscardCount() { return GetPlayerDiscardCount(P2); }
public int GetPlayerDiscardCount(String player)
{
return _game.getGameState().getDiscard(player).size();
}
public int GetPlayerDiscardCount(String player) { return _game.getGameState().getDiscard(player).size(); }
public int GetFreepsDeadCount() { return _game.getGameState().getDeadPile(P1).size(); }
public Phase GetCurrentPhase() { return _game.getGameState().getCurrentPhase(); }
@@ -360,6 +358,8 @@ public class GenericCardTestHelper extends AbstractAtTest {
RemoveCardZone(card.getOwner(), card);
_game.getGameState().putCardOnTopOfDeck(card);
});
ShuffleFreepsDeck();
}
public void ShadowShuffleCardsInDeck(String...cardNames) {
Arrays.stream(cardNames).forEach(cardName -> ShadowShuffleCardsInDeck(GetShadowCard(cardName)));
@@ -369,6 +369,14 @@ public class GenericCardTestHelper extends AbstractAtTest {
RemoveCardZone(card.getOwner(), card);
_game.getGameState().putCardOnTopOfDeck(card);
});
ShuffleShadowDeck();
}
public void ShuffleFreepsDeck() { ShuffleDeck(P1); }
public void ShuffleShadowDeck() { ShuffleDeck(P2); }
public void ShuffleDeck(String player) {
_game.getGameState().shuffleDeck(player);
}
public void FreepsMoveCharToTable(String...names) {
@@ -385,22 +393,43 @@ public class GenericCardTestHelper extends AbstractAtTest {
}
public void FreepsMoveCardToSupportArea(String cardName) { FreepsMoveCardToSupportArea(GetFreepsCard(cardName)); }
public void FreepsMoveCardToSupportArea(String...names) {
Arrays.stream(names).forEach(name -> FreepsMoveCardToSupportArea(GetFreepsCard(name)));
}
public void FreepsMoveCardToSupportArea(PhysicalCardImpl...cards) {
Arrays.stream(cards).forEach(card -> MoveCardToZone(P1, card, Zone.SUPPORT));
}
public void ShadowMoveCardToSupportArea(String cardName) { ShadowMoveCardToSupportArea(GetShadowCard(cardName)); }
public void ShadowMoveCardToSupportArea(PhysicalCardImpl...cards) {
Arrays.stream(cards).forEach(card -> MoveCardToZone(P1, card, Zone.SUPPORT));
public void ShadowMoveCardToSupportArea(String...names) {
Arrays.stream(names).forEach(name -> ShadowMoveCardToSupportArea(GetFreepsCard(name)));
}
public void ShadowMoveCardToSupportArea(PhysicalCardImpl...cards) {
Arrays.stream(cards).forEach(card -> MoveCardToZone(P2, card, Zone.SUPPORT));
}
public void FreepsMoveCardToDiscard(String...names) {
Arrays.stream(names).forEach(name -> FreepsMoveCardToDiscard(GetFreepsCard(name)));
}
public void FreepsMoveCardToDiscard(String cardName) { FreepsMoveCardToDiscard(GetFreepsCard(cardName)); }
public void FreepsMoveCardToDiscard(PhysicalCardImpl...cards) {
Arrays.stream(cards).forEach(card -> MoveCardToZone(P1, card, Zone.DISCARD));
}
public void ShadowMoveCardToDiscard(String cardName) { ShadowMoveCardToDiscard(GetShadowCard(cardName)); }
public void ShadowMoveCardToDiscard(String...names) {
Arrays.stream(names).forEach(name -> ShadowMoveCardToDiscard(GetFreepsCard(name)));
}
public void ShadowMoveCardToDiscard(PhysicalCardImpl...cards) {
Arrays.stream(cards).forEach(card -> MoveCardToZone(P1, card, Zone.DISCARD));
Arrays.stream(cards).forEach(card -> MoveCardToZone(P2, card, Zone.DISCARD));
}
public void FreepsMoveCardToDeadPile(String...names) {
Arrays.stream(names).forEach(name -> FreepsMoveCardToDeadPile(GetFreepsCard(name)));
}
public void FreepsMoveCardToDeadPile(PhysicalCardImpl...cards) {
Arrays.stream(cards).forEach(card -> MoveCardToZone(P1, card, Zone.DEAD));
}
public void ShadowMoveCardToDeadPile(String...names) {
Arrays.stream(names).forEach(name -> ShadowMoveCardToDeadPile(GetFreepsCard(name)));
}
public void ShadowMoveCardToDeadPile(PhysicalCardImpl...cards) {
Arrays.stream(cards).forEach(card -> MoveCardToZone(P2, card, Zone.DEAD));
}
@@ -557,25 +586,27 @@ public class GenericCardTestHelper extends AbstractAtTest {
public int GetFreepsCardChoiceCount() { return FreepsGetCardChoices().size(); }
public int GetShadowCardChoiceCount() { return ShadowGetCardChoices().size(); }
public void FreepsChooseCardBPFromSelection(PhysicalCardImpl card) throws DecisionResultInvalidException { ChooseCardBPFromSelection(P1, card);}
public void ShadowChooseCardBPFromSelection(PhysicalCardImpl card) throws DecisionResultInvalidException { ChooseCardBPFromSelection(P2, card);}
public void FreepsChooseCardBPFromSelection(PhysicalCardImpl...cards) throws DecisionResultInvalidException { ChooseCardBPFromSelection(P1, cards);}
public void ShadowChooseCardBPFromSelection(PhysicalCardImpl...cards) throws DecisionResultInvalidException { ChooseCardBPFromSelection(P2, cards);}
public void ChooseCardBPFromSelection(String player, PhysicalCardImpl card) throws DecisionResultInvalidException {
AwaitingDecision decision = _userFeedback.getAwaitingDecision(player);
public void ChooseCardBPFromSelection(String player, PhysicalCardImpl...cards) throws DecisionResultInvalidException {
String[] choices = GetAwaitingDecisionParam(player,"blueprintId");
ArrayList<String> bps = new ArrayList<String>();
String[] ids = GetAwaitingDecisionParam(player,"blueprintId");
for(int i = 0; i < ids.length; i++)
for(int i = 0; i < choices.length; i++)
{
String id = ids[i];
if(id == card.getBlueprintId())
for(PhysicalCardImpl card : cards)
{
// I have no idea why the spacing is required, but the BP parser skips to the fourth position
playerDecided(player, " " + i);
return;
if(card.getBlueprintId() == choices[i])
{
// I have no idea why the spacing is required, but the BP parser skips to the fourth position
bps.add(" " + i);
break;
}
}
}
playerDecided(player, card.getBlueprintId());
playerDecided(player, String.join(",", bps));
}
public void FreepsChooseCardIDFromSelection(PhysicalCardImpl card) throws DecisionResultInvalidException { ChooseCardIDFromSelection(P1, card);}

View File

@@ -112,19 +112,18 @@ public class Card_09_039_Tests
PhysicalCardImpl library = scn.GetShadowCard("library");
PhysicalCardImpl troop1 = scn.GetShadowCard("troop1");
PhysicalCardImpl troop2 = scn.GetShadowCard("troop2");
PhysicalCardImpl axe1 = scn.GetShadowCard("axe1");
scn.ShadowMoveCardToHand(library, troop1);
scn.ShadowMoveCardToSupportArea(library);
scn.ShadowMoveCharToTable(troop1);
scn.StackCardsOn(library, axe1, troop2);
scn.StartGame();
scn.SetTwilight(20);
scn.FreepsSkipCurrentPhaseAction();
scn.ShadowPlayCard(library);
scn.ShadowUseCardAction(library);
assertEquals(library, axe1.getStackedOn());
scn.SkipToPhase(Phase.ASSIGNMENT);
scn.SkipCurrentPhaseActions();
scn.FreepsAssignToMinions(scn.GetRingBearer(), troop1);
@@ -132,17 +131,54 @@ public class Card_09_039_Tests
scn.FreepsSkipCurrentPhaseAction();
assertTrue(scn.ShadowCardActionAvailable(library));
// 20 initially, +2 from move, -2 from library, -5 for troop, -2 for roaming
assertEquals(13, scn.GetTwilight());
// 20 initially, +2 from move, the rest were all cheated in
assertEquals(22, scn.GetTwilight());
assertEquals(9, scn.GetStrength(troop1));
assertEquals(1, scn.GetStackedCards(library).size());
assertEquals(2, scn.GetStackedCards(library).size());
scn.ShadowUseCardAction(library);
assertEquals(13, scn.GetTwilight());
assertEquals(9, scn.GetStrength(troop1));
assertEquals(0, scn.GetStackedCards(library).size());
assertFalse(scn.ShadowAnyDecisionsAvailable()); // only 1 valid choice even with 2 stacked, so should have no decision
assertEquals(21, scn.GetTwilight());
assertEquals(10, scn.GetStrength(troop1));
assertEquals(1, scn.GetStackedCards(library).size());
assertEquals(Zone.DISCARD, axe1.getZone());
}
@Test
public void RegroupAbilityRemoves1AndTakesStackedIsengardCardIntoHand() throws DecisionResultInvalidException, CardNotFoundException {
//Pre-game setup
GenericCardTestHelper scn = GetScenario();
PhysicalCardImpl library = scn.GetShadowCard("library");
PhysicalCardImpl troop1 = scn.GetShadowCard("troop1");
PhysicalCardImpl runner = scn.GetShadowCard("runner");
PhysicalCardImpl axe1 = scn.GetShadowCard("axe1");
scn.ShadowMoveCardToSupportArea(library);
scn.StackCardsOn(library, axe1, runner, troop1);
scn.StartGame();
scn.SetTwilight(20);
scn.FreepsSkipCurrentPhaseAction();
scn.SkipToPhase(Phase.REGROUP);
scn.FreepsSkipCurrentPhaseAction();
assertTrue(scn.ShadowCardActionAvailable(library));
// 20 initially, +2 from move, the rest were all cheated in
assertEquals(22, scn.GetTwilight());
assertEquals(0, scn.GetShadowHandCount());
assertEquals(3, scn.GetStackedCards(library).size());
scn.ShadowUseCardAction(library);
assertFalse(scn.ShadowAnyDecisionsAvailable()); // only 1 valid choice even with 3 stacked, so should have no decision
assertEquals(21, scn.GetTwilight());
assertEquals(1, scn.GetShadowHandCount());
assertEquals(2, scn.GetStackedCards(library).size());
assertEquals(Zone.HAND, troop1.getZone());
}