Merge remote-tracking branch 'upstream/grand-card-rework' into grand-card-rework

# Conflicts:
#	gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/filters/Filters.java
This commit is contained in:
Marcin Sciesinski
2024-10-18 22:14:47 +07:00
10 changed files with 440 additions and 315 deletions

View File

@@ -976,10 +976,22 @@
site: 3 site: 3
effects: { effects: {
type: trigger type: trigger
optional: true
trigger: { trigger: {
type: played type: played
filter: self filter: self
} }
requires: [
{
type: CanSpot
filter: companion
count: 5
}
{
type: PlayableFromDiscard
filter: minion
}
]
effect: [ effect: [
{ {
type: MemorizeInfo type: MemorizeInfo
@@ -987,61 +999,47 @@
info: yes info: yes
} }
{ {
type: If type: Repeat
check: [ times: {
{ type: forEachYouCanSpot
type: CanSpot filter: companion
filter: companion over: 4
count: 5 }
} effect: {
{ type: if
type: PlayableFromDiscard check: [
filter: minion {
} type: MemoryIs
] memory: choice
true: { value: yes
type: Repeat }
times: { {
type: forEachYouCanSpot type: HasCardInDiscard
filter: companion filter: playable,minion
over: 4 }
} ]
effect: { true: [
type: If {
check: [ type: chooseYesOrNo
{ player: you
type: MemoryIs text: Would you like to play a minion from your discard?
memory: choice memorize: choice
value: yes }
} {
{ type: if
type: HasCardInDiscard check: [
filter: playable,minion {
} type: MemoryIs
] memory: choice
true: [ value: yes
{
type: chooseYesOrNo
player: you
text: Would you like to play a minion from your discard?
memorize: choice
}
{
type: if
check: [
{
type: MemoryIs
memory: choice
value: yes
}
]
true: {
type: playCardFromDiscard
select: choose(minion)
} }
]
true: {
type: playCardFromDiscard
select: choose(minion)
} }
] }
} ]
} }
} }
] ]

View File

@@ -26,10 +26,22 @@
site: 3 site: 3
effects: { effects: {
type: trigger type: trigger
optional: true
trigger: { trigger: {
type: played type: played
filter: self filter: self
} }
requires: [
{
type: CanSpot
filter: companion
count: 5
}
{
type: PlayableFromDiscard
filter: minion
}
]
effect: [ effect: [
{ {
type: MemorizeInfo type: MemorizeInfo
@@ -37,61 +49,47 @@
info: yes info: yes
} }
{ {
type: If type: Repeat
check: [ times: {
{ type: forEachYouCanSpot
type: CanSpot filter: companion
filter: companion over: 4
count: 5 }
} effect: {
{ type: if
type: PlayableFromDiscard check: [
filter: unique,culture(wraith),minion {
} type: MemoryIs
] memory: choice
true: { value: yes
type: Repeat }
times: { {
type: forEachYouCanSpot type: HasCardInDiscard
filter: companion filter: playable,unique,culture(wraith),minion
over: 4 }
} ]
effect: { true: [
type: If {
check: [ type: chooseYesOrNo
{ player: you
type: MemoryIs text: Would you like to play a unique WRAITH minion from your discard?
memory: choice memorize: choice
value: yes }
} {
{ type: if
type: HasCardInDiscard check: [
filter: playable,unique,culture(wraith),minion {
} type: MemoryIs
] memory: choice
true: [ value: yes
{
type: chooseYesOrNo
player: you
text: Would you like to play a unique WRAITH minion from your discard?
memorize: choice
}
{
type: if
check: [
{
type: MemoryIs
memory: choice
value: yes
}
]
true: {
type: playCardFromDiscard
select: choose(unique,culture(wraith),minion)
} }
]
true: {
type: playCardFromDiscard
select: choose(unique,culture(wraith),minion)
} }
] }
} ]
} }
} }
] ]

View File

@@ -243,7 +243,13 @@ public class Filters {
|| game.getModifiersQuerying().isUnhastyCompanionAllowedToParticipateInSkirmishes(game, physicalCard)), || game.getModifiersQuerying().isUnhastyCompanionAllowedToParticipateInSkirmishes(game, physicalCard)),
Filters.and( Filters.and(
CardType.MINION, CardType.MINION,
(Filter) (game, physicalCard) -> (!game.getGameState().isFierceSkirmishes()) || game.getModifiersQuerying().hasKeyword(game, physicalCard, Keyword.FIERCE))); Filters.notAssignedToSkirmish,
new Filter() {
@Override
public boolean accepts(LotroGame game, PhysicalCard physicalCard) {
return (game.getGameState().getCurrentPhase() != Phase.ASSIGNMENT || !game.getGameState().isFierceSkirmishes()) || game.getModifiersQuerying().hasKeyword(game, physicalCard, Keyword.FIERCE);
}
}));
return Filters.and( return Filters.and(
assignableFilter, assignableFilter,

View File

@@ -132,7 +132,7 @@ public interface Tournament {
return new SwissPairingMechanism(PairingType.SWISS_3.name(), 3); return new SwissPairingMechanism(PairingType.SWISS_3.name(), 3);
} }
case WC_SWISS -> { case WC_SWISS -> {
return new ChampionshipSwissPairingMechanism(PairingType.WC_SWISS.name(), 8); return new ChampionshipSwissPairingMechanism(PairingType.WC_SWISS.name(), 10);
} }
} }

View File

@@ -515,90 +515,6 @@ public class IndividualCardAtTest extends AbstractAtTest {
assertEquals(1, _game.getGameState().getTokenCount(corsairWarGalley, Token.RAIDER)); assertEquals(1, _game.getGameState().getTokenCount(corsairWarGalley, Token.RAIDER));
} }
@Test
public void returnToItsMaster() throws DecisionResultInvalidException, CardNotFoundException {
LotroDeck p1Deck = createSimplestDeck();
p1Deck.setRing("4_1");
LotroDeck p2Deck = createSimplestDeck();
Map<String, LotroDeck> decks = new HashMap<>();
decks.put(P1, p1Deck);
decks.put(P2, p2Deck);
initializeGameWithDecks(decks);
skipMulligans();
PhysicalCardImpl returnToItsMaster = new PhysicalCardImpl(102, "1_224", P2, _cardLibrary.getLotroCardBlueprint("1_224"));
_game.getGameState().addCardToZone(_game, returnToItsMaster, Zone.HAND);
PhysicalCardImpl nelya = new PhysicalCardImpl(102, "1_233", P2, _cardLibrary.getLotroCardBlueprint("1_233"));
_game.getGameState().addCardToZone(_game, nelya, Zone.SHADOW_CHARACTERS);
PhysicalCardImpl hobbitSword = new PhysicalCardImpl(102, "1_299", P1, _cardLibrary.getLotroCardBlueprint("1_299"));
_game.getGameState().attachCard(_game, hobbitSword, _game.getGameState().getRingBearer(P1));
// End fellowship
playerDecided(P1, "");
// End shadow
playerDecided(P2, "");
// End maneuvers phase
playerDecided(P1, "");
playerDecided(P2, "");
// End archery phase
playerDecided(P1, "");
playerDecided(P2, "");
// End assignment phase
playerDecided(P1, "");
playerDecided(P2, "");
// Assign
playerDecided(P1, _game.getGameState().getRingBearer(P1).getCardId() + " " + nelya.getCardId());
// Choose skirmish to resolve
playerDecided(P1, "" + _game.getGameState().getRingBearer(P1).getCardId());
// Skirmish phase
AwaitingDecision skirmishAction = _userFeedback.getAwaitingDecision(P1);
playerDecided(P1, getCardActionId(skirmishAction, "Use The One"));
assertTrue(_game.getGameState().isWearingRing());
// End skirmish phase
playerDecided(P2, "");
playerDecided(P1, "");
// Don't use Return to Its Master
playerDecided(P2, "");
// End assignment phase
playerDecided(P1, "");
playerDecided(P2, "");
// Assign
playerDecided(P1, _game.getGameState().getRingBearer(P1).getCardId() + " " + nelya.getCardId());
// Choose skirmish to resolve
playerDecided(P1, "" + _game.getGameState().getRingBearer(P1).getCardId());
// End fierce skirmish phase
playerDecided(P1, "");
playerDecided(P2, "");
AwaitingDecision playeReturnDecision = _userFeedback.getAwaitingDecision(P2);
playerDecided(P2, getCardActionId(playeReturnDecision, "Play Return"));
// Choose skirmish to resolve
playerDecided(P1, "" + _game.getGameState().getRingBearer(P1).getCardId());
assertEquals(_game.getGameState().getRingBearer(P1), _game.getGameState().getSkirmish().getFellowshipCharacter());
assertEquals(1, _game.getGameState().getSkirmish().getShadowCharacters().size());
assertEquals(nelya, _game.getGameState().getSkirmish().getShadowCharacters().iterator().next());
}
@Test @Test
public void moreYetToComeWorks() throws DecisionResultInvalidException, CardNotFoundException { public void moreYetToComeWorks() throws DecisionResultInvalidException, CardNotFoundException {

View File

@@ -284,6 +284,12 @@ public class GenericCardTestHelper extends AbstractAtTest {
public List<String> ShadowGetBPChoices() { return GetADParamAsList(P2, "blueprintId"); } public List<String> ShadowGetBPChoices() { return GetADParamAsList(P2, "blueprintId"); }
public List<String> FreepsGetMultipleChoices() { return GetADParamAsList(P1, "results"); } public List<String> FreepsGetMultipleChoices() { return GetADParamAsList(P1, "results"); }
public List<String> ShadowGetMultipleChoices() { return GetADParamAsList(P2, "results"); } public List<String> ShadowGetMultipleChoices() { return GetADParamAsList(P2, "results"); }
public List<String> FreepsGetFreepsAssignmentTargets() { return GetADParamAsList(P1, "freeCharacters"); }
public List<String> FreepsGetShadowAssignmentTargets() { return GetADParamAsList(P1, "minions"); }
public List<String> ShadowGetFreepsAssignmentTargets() { return GetADParamAsList(P2, "freeCharacters"); }
public List<String> ShadowGetShadowAssignmentTargets() { return GetADParamAsList(P2, "minions"); }
public List<String> FreepsGetADParamAsList(String paramName) { return GetADParamAsList(P1, paramName); } public List<String> FreepsGetADParamAsList(String paramName) { return GetADParamAsList(P1, paramName); }
public List<String> ShadowGetADParamAsList(String paramName) { return GetADParamAsList(P2, paramName); } public List<String> ShadowGetADParamAsList(String paramName) { return GetADParamAsList(P2, paramName); }
public List<String> GetADParamAsList(String playerID, String paramName) { return Arrays.asList(GetAwaitingDecisionParam(playerID, paramName)); } public List<String> GetADParamAsList(String playerID, String paramName) { return Arrays.asList(GetAwaitingDecisionParam(playerID, paramName)); }
@@ -670,6 +676,11 @@ public class GenericCardTestHelper extends AbstractAtTest {
SkipToPhase(Phase.ASSIGNMENT); SkipToPhase(Phase.ASSIGNMENT);
PassCurrentPhaseActions(); PassCurrentPhaseActions();
} }
public void SkipToShadowAssignments() throws DecisionResultInvalidException {
SkipToAssignments();
FreepsDeclineAssignments();
}
public void SkipToMovementDecision() throws DecisionResultInvalidException { public void SkipToMovementDecision() throws DecisionResultInvalidException {
SkipToPhase(Phase.REGROUP); SkipToPhase(Phase.REGROUP);
PassCurrentPhaseActions(); PassCurrentPhaseActions();
@@ -829,6 +840,11 @@ public class GenericCardTestHelper extends AbstractAtTest {
public int GetFreepsCardChoiceCount() { return FreepsGetCardChoices().size(); } public int GetFreepsCardChoiceCount() { return FreepsGetCardChoices().size(); }
public int GetShadowCardChoiceCount() { return ShadowGetCardChoices().size(); } public int GetShadowCardChoiceCount() { return ShadowGetCardChoices().size(); }
public int FreepsGetFreepsAssignmentTargetCount() { return FreepsGetFreepsAssignmentTargets().size(); }
public int FreepsGetShadowAssignmentTargetCount() { return FreepsGetShadowAssignmentTargets().size(); }
public int ShadowGetFreepsAssignmentTargetCount() { return ShadowGetFreepsAssignmentTargets().size(); }
public int ShadowGetShadowAssignmentTargetCount() { return ShadowGetShadowAssignmentTargets().size(); }
public void FreepsChooseCardBPFromSelection(PhysicalCardImpl...cards) throws DecisionResultInvalidException { ChooseCardBPFromSelection(P1, cards);} public void FreepsChooseCardBPFromSelection(PhysicalCardImpl...cards) throws DecisionResultInvalidException { ChooseCardBPFromSelection(P1, cards);}
public void ShadowChooseCardBPFromSelection(PhysicalCardImpl...cards) throws DecisionResultInvalidException { ChooseCardBPFromSelection(P2, cards);} public void ShadowChooseCardBPFromSelection(PhysicalCardImpl...cards) throws DecisionResultInvalidException { ChooseCardBPFromSelection(P2, cards);}

View File

@@ -1,75 +1,201 @@
package com.gempukku.lotro.cards.official.set01; package com.gempukku.lotro.cards.official.set01;
import com.gempukku.lotro.cards.GenericCardTestHelper; import com.gempukku.lotro.cards.GenericCardTestHelper;
import com.gempukku.lotro.common.CardType; import com.gempukku.lotro.common.*;
import com.gempukku.lotro.common.Culture;
import com.gempukku.lotro.common.Side;
import com.gempukku.lotro.common.Timeword;
import com.gempukku.lotro.game.CardNotFoundException; 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 com.gempukku.lotro.logic.decisions.DecisionResultInvalidException;
import com.gempukku.lotro.logic.vo.LotroDeck;
import org.junit.Test; import org.junit.Test;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map;
import static org.junit.Assert.*; import static org.junit.Assert.*;
public class Card_01_224_Tests public class Card_01_224_Tests
{ {
protected GenericCardTestHelper GetScenario() throws CardNotFoundException, DecisionResultInvalidException { protected GenericCardTestHelper GetScenario() throws CardNotFoundException, DecisionResultInvalidException {
return new GenericCardTestHelper( return new GenericCardTestHelper(
new HashMap<>() new HashMap<>()
{{ {{
put("card", "1_224"); put("rtim", "1_224");
// put other cards in here as needed for the test case put("enquea", "2_83");
}}, put("twk", "1_237");
GenericCardTestHelper.FellowshipSites,
GenericCardTestHelper.FOTRFrodo,
GenericCardTestHelper.RulingRing
);
}
@Test put("guard", "1_7");
public void ReturntoItsMasterStatsAndKeywordsAreCorrect() throws DecisionResultInvalidException, CardNotFoundException { }},
GenericCardTestHelper.FellowshipSites,
GenericCardTestHelper.FOTRFrodo,
GenericCardTestHelper.ATARRing
);
}
/** @Test
* Set: 1 public void ReturntoItsMasterStatsAndKeywordsAreCorrect() throws DecisionResultInvalidException, CardNotFoundException {
* Name: Return to Its Master
* Unique: False
* Side: Shadow
* Culture: Wraith
* Twilight Cost: 0
* Type: Event
* Subtype:
* Game Text: <b>Response:</b> If the Ring-bearer wears The One Ring at the end of a skirmish phase, cancel all remaining assignments and assign a Nazgûl to skirmish the Ring-bearer; The One Ring's game text does not apply during this skirmish.
*/
var scn = GetScenario(); /**
* Set: 1
* Name: Return to Its Master
* Unique: False
* Side: Shadow
* Culture: Wraith
* Twilight Cost: 0
* Type: Event
* Subtype:
* Game Text: <b>Response:</b> If the Ring-bearer wears The One Ring at the end of a skirmish phase, cancel all remaining assignments and assign a Nazgûl to skirmish the Ring-bearer; The One Ring's game text does not apply during this skirmish.
*/
var card = scn.GetFreepsCard("card"); var scn = GetScenario();
assertEquals("Return to Its Master", card.getBlueprint().getTitle()); var card = scn.GetFreepsCard("rtim");
assertNull(card.getBlueprint().getSubtitle());
assertFalse(card.getBlueprint().isUnique()); assertEquals("Return to Its Master", card.getBlueprint().getTitle());
assertEquals(Side.SHADOW, card.getBlueprint().getSide()); assertNull(card.getBlueprint().getSubtitle());
assertEquals(Culture.WRAITH, card.getBlueprint().getCulture()); assertFalse(card.getBlueprint().isUnique());
assertEquals(CardType.EVENT, card.getBlueprint().getCardType()); assertEquals(Side.SHADOW, card.getBlueprint().getSide());
assertEquals(Culture.WRAITH, card.getBlueprint().getCulture());
assertEquals(CardType.EVENT, card.getBlueprint().getCardType());
assertTrue(scn.hasTimeword(card, Timeword.RESPONSE)); assertTrue(scn.hasTimeword(card, Timeword.RESPONSE));
assertEquals(0, card.getBlueprint().getTwilightCost()); assertEquals(0, card.getBlueprint().getTwilightCost());
} }
// Uncomment any @Test markers below once this is ready to be used @Test
//@Test public void ReturntoItsMasterPermitsAssigningOfNonFierceNazgulWhenUsedDuringFierceSkirmish() throws DecisionResultInvalidException, CardNotFoundException {
public void ReturntoItsMasterTest1() throws DecisionResultInvalidException, CardNotFoundException { //Pre-game setup
//Pre-game setup var scn = GetScenario();
var scn = GetScenario();
var card = scn.GetFreepsCard("card"); var rtim = scn.GetShadowCard("rtim");
scn.FreepsMoveCardToHand(card); var enquea = scn.GetShadowCard("enquea");
var twk = scn.GetShadowCard("twk");
scn.ShadowMoveCardToHand(rtim);
scn.ShadowMoveCharToTable(enquea, twk);
scn.StartGame(); var frodo = scn.GetRingBearer();
scn.FreepsPlayCard(card); var onering = scn.GetFreepsRing();
var guard = scn.GetFreepsCard("guard");
scn.FreepsMoveCharToTable(guard);
scn.StartGame();
//Enquea is the twilight version, who is not fierce. He should still be a valid target
// when RTIM triggers during a fierce skirmish.
scn.SkipToShadowAssignments();
assertEquals(2, scn.ShadowGetShadowAssignmentTargetCount()); // both enquea and TWK
//We will skip the non-fierce skirmishes
scn.ShadowDeclineAssignments();
//Fierce skirmish assignment phase
scn.SkipToShadowAssignments();
assertEquals(1, scn.ShadowGetShadowAssignmentTargetCount()); // TWK, but not enquea
scn.ShadowAssignToMinions(guard, twk);
scn.FreepsResolveSkirmish(guard);
//Need the One Ring to be worn
scn.FreepsUseCardAction(onering);
scn.ShadowPassCurrentPhaseAction();
scn.FreepsPassCurrentPhaseAction();
assertTrue(scn.ShadowPlayAvailable(rtim));
scn.ShadowPlayCard(rtim);
assertEquals(2, scn.GetShadowCardChoiceCount()); // both enquea and TWK
scn.ShadowChooseCard(enquea);
assertEquals(Phase.SKIRMISH, scn.GetCurrentPhase());
assertTrue(scn.IsCharAssigned(enquea));
}
//Legacy AT test
@Test
public void returnToItsMaster() throws DecisionResultInvalidException, CardNotFoundException {
var scn = GetScenario();
var p1Deck = scn.createSimplestDeck();
p1Deck.setRing("4_1");
var p2Deck = scn.createSimplestDeck();
Map<String, LotroDeck> decks = new HashMap<>();
decks.put(scn.P1, p1Deck);
decks.put(scn.P2, p2Deck);
scn.initializeGameWithDecks(decks);
scn.skipMulligans();
PhysicalCardImpl returnToItsMaster = new PhysicalCardImpl(102, "1_224", scn.P2, scn._cardLibrary.getLotroCardBlueprint("1_224"));
scn._game.getGameState().addCardToZone(scn._game, returnToItsMaster, Zone.HAND);
PhysicalCardImpl nelya = new PhysicalCardImpl(102, "1_233", scn.P2, scn._cardLibrary.getLotroCardBlueprint("1_233"));
scn._game.getGameState().addCardToZone(scn._game, nelya, Zone.SHADOW_CHARACTERS);
PhysicalCardImpl hobbitSword = new PhysicalCardImpl(102, "1_299", scn.P1, scn._cardLibrary.getLotroCardBlueprint("1_299"));
scn._game.getGameState().attachCard(scn._game, hobbitSword, scn._game.getGameState().getRingBearer(scn.P1));
// End fellowship
scn.playerDecided(scn.P1, "");
// End shadow
scn.playerDecided(scn.P2, "");
// End maneuvers phase
scn.playerDecided(scn.P1, "");
scn.playerDecided(scn.P2, "");
// End archery phase
scn.playerDecided(scn.P1, "");
scn.playerDecided(scn.P2, "");
// End assignment phase
scn.playerDecided(scn.P1, "");
scn.playerDecided(scn.P2, "");
// Assign
scn.playerDecided(scn.P1, scn._game.getGameState().getRingBearer(scn.P1).getCardId() + " " + nelya.getCardId());
// Choose skirmish to resolve
scn.playerDecided(scn.P1, "" + scn._game.getGameState().getRingBearer(scn.P1).getCardId());
// Skirmish phase
AwaitingDecision skirmishAction = scn._userFeedback.getAwaitingDecision(scn.P1);
scn.playerDecided(scn.P1, scn.getCardActionId(skirmishAction, "Use The One"));
assertTrue(scn._game.getGameState().isWearingRing());
// End skirmish phase
scn.playerDecided(scn.P2, "");
scn.playerDecided(scn.P1, "");
// Don't use Return to Its Master
scn.playerDecided(scn.P2, "");
// End assignment phase
scn.playerDecided(scn.P1, "");
scn.playerDecided(scn.P2, "");
// Assign
scn.playerDecided(scn.P1, scn._game.getGameState().getRingBearer(scn.P1).getCardId() + " " + nelya.getCardId());
// Choose skirmish to resolve
scn.playerDecided(scn.P1, "" + scn._game.getGameState().getRingBearer(scn.P1).getCardId());
// End fierce skirmish phase
scn.playerDecided(scn.P1, "");
scn.playerDecided(scn.P2, "");
AwaitingDecision playeReturnDecision = scn._userFeedback.getAwaitingDecision(scn.P2);
scn.playerDecided(scn.P2, scn.getCardActionId(playeReturnDecision, "Play Return"));
// Choose skirmish to resolve
scn.playerDecided(scn.P1, "" + scn._game.getGameState().getRingBearer(scn.P1).getCardId());
assertEquals(scn._game.getGameState().getRingBearer(scn.P1), scn._game.getGameState().getSkirmish().getFellowshipCharacter());
assertEquals(1, scn._game.getGameState().getSkirmish().getShadowCharacters().size());
assertEquals(nelya, scn._game.getGameState().getSkirmish().getShadowCharacters().iterator().next());
}
assertEquals(0, scn.GetTwilight());
}
} }

View File

@@ -110,6 +110,8 @@ public class Card_01_234_Tests
scn.FreepsPassCurrentPhaseAction(); scn.FreepsPassCurrentPhaseAction();
scn.ShadowPlayCard(nertea); scn.ShadowPlayCard(nertea);
assertTrue(scn.ShadowHasOptionalTriggerAvailable());
scn.ShadowAcceptOptionalTrigger();
assertTrue(scn.ShadowDecisionAvailable("play a minion")); assertTrue(scn.ShadowDecisionAvailable("play a minion"));
scn.ShadowChooseYes(); scn.ShadowChooseYes();
//twk, attea, rit, and runner //twk, attea, rit, and runner
@@ -141,6 +143,8 @@ public class Card_01_234_Tests
scn.FreepsPassCurrentPhaseAction(); scn.FreepsPassCurrentPhaseAction();
scn.ShadowPlayCard(nertea); scn.ShadowPlayCard(nertea);
assertTrue(scn.ShadowHasOptionalTriggerAvailable());
scn.ShadowAcceptOptionalTrigger();
assertTrue(scn.ShadowDecisionAvailable("play a minion")); assertTrue(scn.ShadowDecisionAvailable("play a minion"));
scn.ShadowChooseYes(); scn.ShadowChooseYes();
//twk, attea, rit, and runner //twk, attea, rit, and runner
@@ -178,6 +182,8 @@ public class Card_01_234_Tests
scn.FreepsPassCurrentPhaseAction(); scn.FreepsPassCurrentPhaseAction();
scn.ShadowPlayCard(nertea); scn.ShadowPlayCard(nertea);
assertTrue(scn.ShadowHasOptionalTriggerAvailable());
scn.ShadowAcceptOptionalTrigger();
assertTrue(scn.ShadowDecisionAvailable("play a minion")); assertTrue(scn.ShadowDecisionAvailable("play a minion"));
scn.ShadowChooseNo(); scn.ShadowChooseNo();
@@ -203,6 +209,8 @@ public class Card_01_234_Tests
scn.FreepsPassCurrentPhaseAction(); scn.FreepsPassCurrentPhaseAction();
scn.ShadowPlayCard(nertea); scn.ShadowPlayCard(nertea);
assertTrue(scn.ShadowHasOptionalTriggerAvailable());
scn.ShadowAcceptOptionalTrigger();
assertTrue(scn.ShadowDecisionAvailable("play a minion")); assertTrue(scn.ShadowDecisionAvailable("play a minion"));
scn.ShadowChooseYes(); scn.ShadowChooseYes();
assertEquals(4, scn.GetShadowCardChoiceCount()); assertEquals(4, scn.GetShadowCardChoiceCount());

View File

@@ -13,91 +13,140 @@ import static org.junit.Assert.*;
public class Card_01_338_Tests public class Card_01_338_Tests
{ {
protected GenericCardTestHelper GetScenario() throws CardNotFoundException, DecisionResultInvalidException { protected GenericCardTestHelper GetScenario() throws CardNotFoundException, DecisionResultInvalidException {
return new GenericCardTestHelper( return new GenericCardTestHelper(
new HashMap<>() new HashMap<>()
{{ {{
put("twk", "1_237"); put("twk", "1_237");
put("lemenya", "1_232"); put("lemenya", "1_232");
// put other cards in here as needed for the test case put("nertea", "1_234");
}},
new HashMap<>() {{
put("site1", "1_319");
put("site2", "1_327");
put("site3", "1_338");
put("site4", "1_343");
put("site5", "1_349");
put("site6", "1_351");
put("site7", "1_353");
put("site8", "1_356");
put("site9", "1_360");
}},
GenericCardTestHelper.FOTRFrodo,
GenericCardTestHelper.RulingRing
);
}
@Test put("guard1", "1_7");
public void FordofBruinenStatsAndKeywordsAreCorrect() throws DecisionResultInvalidException, CardNotFoundException { put("guard2", "1_7");
put("guard3", "1_7");
put("guard4", "1_7");
}},
new HashMap<>() {{
put("site1", "1_319");
put("site2", "1_327");
put("site3", "1_338");
put("site4", "1_343");
put("site5", "1_349");
put("site6", "1_351");
put("site7", "1_353");
put("site8", "1_356");
put("site9", "1_360");
}},
GenericCardTestHelper.FOTRFrodo,
GenericCardTestHelper.RulingRing
);
}
/** @Test
* Set: 1 public void FordofBruinenStatsAndKeywordsAreCorrect() throws DecisionResultInvalidException, CardNotFoundException {
* Name: Ford of Bruinen
* Unique: False
* Side:
* Culture:
* Shadow Number: 0
* Type: Sanctuary
* Subtype:
* Site Number: 3
* Game Text: <b>River</b>. <b>Sanctuary</b>. The twilight cost of the first Nazgûl played to Ford of Bruinen each turn is -5.
*/
var scn = GetScenario(); /**
* Set: 1
* Name: Ford of Bruinen
* Unique: False
* Side:
* Culture:
* Shadow Number: 0
* Type: Sanctuary
* Subtype:
* Site Number: 3
* Game Text: <b>River</b>. <b>Sanctuary</b>. The twilight cost of the first Nazgûl played to Ford of Bruinen each turn is -5.
*/
var card = scn.GetFreepsSite(3); var scn = GetScenario();
assertEquals("Ford of Bruinen", card.getBlueprint().getTitle()); var card = scn.GetFreepsSite(3);
assertNull(card.getBlueprint().getSubtitle());
assertFalse(card.getBlueprint().isUnique());
assertEquals(CardType.SITE, card.getBlueprint().getCardType());
assertTrue(scn.hasKeyword(card, Keyword.RIVER));
assertTrue(scn.hasKeyword(card, Keyword.SANCTUARY));
assertEquals(0, card.getBlueprint().getTwilightCost());
assertEquals(3, card.getBlueprint().getSiteNumber());
}
@Test assertEquals("Ford of Bruinen", card.getBlueprint().getTitle());
public void FordofBruinenOnlyDiscountsTheFirstNazgul() throws DecisionResultInvalidException, CardNotFoundException { assertNull(card.getBlueprint().getSubtitle());
//Pre-game setup assertFalse(card.getBlueprint().isUnique());
var scn = GetScenario(); assertEquals(CardType.SITE, card.getBlueprint().getCardType());
assertTrue(scn.hasKeyword(card, Keyword.RIVER));
assertTrue(scn.hasKeyword(card, Keyword.SANCTUARY));
assertEquals(0, card.getBlueprint().getTwilightCost());
assertEquals(3, card.getBlueprint().getSiteNumber());
}
var ford = scn.GetShadowSite(3); @Test
public void FordofBruinenOnlyDiscountsTheFirstNazgul() throws DecisionResultInvalidException, CardNotFoundException {
//Pre-game setup
var scn = GetScenario();
var twk = scn.GetShadowCard("twk"); var ford = scn.GetShadowSite(3);
var lemenya = scn.GetShadowCard("lemenya");
scn.ShadowMoveCardToHand(twk, lemenya);
scn.StartGame(); var twk = scn.GetShadowCard("twk");
//Start our test on 2 so that moving to 3 is the first thing we do var lemenya = scn.GetShadowCard("lemenya");
scn.SkipToSite(2); scn.ShadowMoveCardToHand(twk, lemenya);
scn.SetTwilight(9); scn.StartGame();
scn.FreepsPassCurrentPhaseAction(); //Start our test on 2 so that moving to 3 is the first thing we do
scn.SkipToSite(2);
assertEquals(ford, scn.GetCurrentSite()); scn.SetTwilight(9);
scn.FreepsPassCurrentPhaseAction();
//9 manual + 1 from the fellowship moving assertEquals(ford, scn.GetCurrentSite());
assertEquals(10, scn.GetTwilight());
scn.ShadowPlayCard(twk); //9 manual + 1 from the fellowship moving
//TWK costs 8 (no roaming), discounted by 5 to 3 total assertEquals(10, scn.GetTwilight());
//10 - 3
assertEquals(7, scn.GetTwilight());
scn.ShadowPlayCard(lemenya); scn.ShadowPlayCard(twk);
//Lemenya costs 4, should have no discount //TWK costs 8 (no roaming), discounted by 5 to 3 total
//7 - 4 //10 - 3
assertEquals(3, scn.GetTwilight()); assertEquals(7, scn.GetTwilight());
}
scn.ShadowPlayCard(lemenya);
//Lemenya costs 4, should have no discount
//7 - 4
assertEquals(3, scn.GetTwilight());
}
@Test
public void FordDiscountsNerteaButNotNerteasTrigger() throws DecisionResultInvalidException, CardNotFoundException {
//Pre-game setup
var scn = GetScenario();
var ford = scn.GetShadowSite(3);
var twk = scn.GetShadowCard("twk");
var nertea = scn.GetShadowCard("nertea");
scn.ShadowMoveCardToHand(nertea);
scn.ShadowMoveCardToDiscard(twk);
scn.FreepsMoveCharToTable("guard1", "guard2", "guard3", "guard4");
scn.StartGame();
//Start our test on 2 so that moving to 3 is the first thing we do
scn.SkipToSite(2);
scn.SetTwilight(5);
scn.FreepsPassCurrentPhaseAction();
assertEquals(ford, scn.GetCurrentSite());
//5 manual + 5 from the fellowship moving
assertEquals(10, scn.GetTwilight());
scn.ShadowPlayCard(nertea);
//Nertea costs 4 (no roaming), discounted by 5 to 0 total
//10 - 0
assertEquals(10, scn.GetTwilight());
//Nertea pulls a minion from discard, which should not get discounted
// as Nertea should have consumed the only discount
assertTrue(scn.ShadowHasOptionalTriggerAvailable());
scn.ShadowAcceptOptionalTrigger();
assertTrue(scn.ShadowDecisionAvailable("play a minion"));
scn.ShadowChooseYes();
scn.ShadowChooseCardBPFromSelection(twk);
//TWK costs 8, should not be discounted
//10 - 8
assertEquals(2, scn.GetTwilight());
}
} }

View File

@@ -108,6 +108,8 @@ public class Card_01_234_ErrataTests
scn.FreepsPassCurrentPhaseAction(); scn.FreepsPassCurrentPhaseAction();
scn.ShadowPlayCard(nertea); scn.ShadowPlayCard(nertea);
assertTrue(scn.ShadowHasOptionalTriggerAvailable());
scn.ShadowAcceptOptionalTrigger();
assertTrue(scn.ShadowDecisionAvailable("play a unique WRAITH minion")); assertTrue(scn.ShadowDecisionAvailable("play a unique WRAITH minion"));
scn.ShadowChooseYes(); scn.ShadowChooseYes();
//twk and attea, but not rit or runner //twk and attea, but not rit or runner
@@ -138,6 +140,8 @@ public class Card_01_234_ErrataTests
scn.FreepsPassCurrentPhaseAction(); scn.FreepsPassCurrentPhaseAction();
scn.ShadowPlayCard(nertea); scn.ShadowPlayCard(nertea);
assertTrue(scn.ShadowHasOptionalTriggerAvailable());
scn.ShadowAcceptOptionalTrigger();
assertTrue(scn.ShadowDecisionAvailable("play a unique WRAITH minion")); assertTrue(scn.ShadowDecisionAvailable("play a unique WRAITH minion"));
scn.ShadowChooseYes(); scn.ShadowChooseYes();
//twk and attea, but not rit or runner //twk and attea, but not rit or runner
@@ -174,6 +178,8 @@ public class Card_01_234_ErrataTests
scn.FreepsPassCurrentPhaseAction(); scn.FreepsPassCurrentPhaseAction();
scn.ShadowPlayCard(nertea); scn.ShadowPlayCard(nertea);
assertTrue(scn.ShadowHasOptionalTriggerAvailable());
scn.ShadowAcceptOptionalTrigger();
assertTrue(scn.ShadowDecisionAvailable("play a unique WRAITH minion")); assertTrue(scn.ShadowDecisionAvailable("play a unique WRAITH minion"));
scn.ShadowChooseNo(); scn.ShadowChooseNo();
@@ -199,6 +205,8 @@ public class Card_01_234_ErrataTests
scn.FreepsPassCurrentPhaseAction(); scn.FreepsPassCurrentPhaseAction();
scn.ShadowPlayCard(nertea); scn.ShadowPlayCard(nertea);
assertTrue(scn.ShadowHasOptionalTriggerAvailable());
scn.ShadowAcceptOptionalTrigger();
assertTrue(scn.ShadowDecisionAvailable("play a unique WRAITH minion")); assertTrue(scn.ShadowDecisionAvailable("play a unique WRAITH minion"));
scn.ShadowChooseYes(); scn.ShadowChooseYes();
//twk and attea, but not rit or runner //twk and attea, but not rit or runner