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
effects: {
type: trigger
optional: true
trigger: {
type: played
filter: self
}
requires: [
{
type: CanSpot
filter: companion
count: 5
}
{
type: PlayableFromDiscard
filter: minion
}
]
effect: [
{
type: MemorizeInfo
@@ -987,61 +999,47 @@
info: yes
}
{
type: If
check: [
{
type: CanSpot
filter: companion
count: 5
}
{
type: PlayableFromDiscard
filter: minion
}
]
true: {
type: Repeat
times: {
type: forEachYouCanSpot
filter: companion
over: 4
}
effect: {
type: If
check: [
{
type: MemoryIs
memory: choice
value: yes
}
{
type: HasCardInDiscard
filter: playable,minion
}
]
true: [
{
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)
type: Repeat
times: {
type: forEachYouCanSpot
filter: companion
over: 4
}
effect: {
type: if
check: [
{
type: MemoryIs
memory: choice
value: yes
}
{
type: HasCardInDiscard
filter: playable,minion
}
]
true: [
{
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)
}
]
}
}
]
}
}
]

View File

@@ -26,10 +26,22 @@
site: 3
effects: {
type: trigger
optional: true
trigger: {
type: played
filter: self
}
requires: [
{
type: CanSpot
filter: companion
count: 5
}
{
type: PlayableFromDiscard
filter: minion
}
]
effect: [
{
type: MemorizeInfo
@@ -37,61 +49,47 @@
info: yes
}
{
type: If
check: [
{
type: CanSpot
filter: companion
count: 5
}
{
type: PlayableFromDiscard
filter: unique,culture(wraith),minion
}
]
true: {
type: Repeat
times: {
type: forEachYouCanSpot
filter: companion
over: 4
}
effect: {
type: If
check: [
{
type: MemoryIs
memory: choice
value: yes
}
{
type: HasCardInDiscard
filter: playable,unique,culture(wraith),minion
}
]
true: [
{
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)
type: Repeat
times: {
type: forEachYouCanSpot
filter: companion
over: 4
}
effect: {
type: if
check: [
{
type: MemoryIs
memory: choice
value: yes
}
{
type: HasCardInDiscard
filter: playable,unique,culture(wraith),minion
}
]
true: [
{
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)
}
]
}
}
]
}
}
]

View File

@@ -243,7 +243,13 @@ public class Filters {
|| game.getModifiersQuerying().isUnhastyCompanionAllowedToParticipateInSkirmishes(game, physicalCard)),
Filters.and(
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(
assignableFilter,

View File

@@ -132,7 +132,7 @@ public interface Tournament {
return new SwissPairingMechanism(PairingType.SWISS_3.name(), 3);
}
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));
}
@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
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> FreepsGetMultipleChoices() { return GetADParamAsList(P1, "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> ShadowGetADParamAsList(String paramName) { return GetADParamAsList(P2, 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);
PassCurrentPhaseActions();
}
public void SkipToShadowAssignments() throws DecisionResultInvalidException {
SkipToAssignments();
FreepsDeclineAssignments();
}
public void SkipToMovementDecision() throws DecisionResultInvalidException {
SkipToPhase(Phase.REGROUP);
PassCurrentPhaseActions();
@@ -829,6 +840,11 @@ public class GenericCardTestHelper extends AbstractAtTest {
public int GetFreepsCardChoiceCount() { return FreepsGetCardChoices().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 ShadowChooseCardBPFromSelection(PhysicalCardImpl...cards) throws DecisionResultInvalidException { ChooseCardBPFromSelection(P2, cards);}

View File

@@ -1,75 +1,201 @@
package com.gempukku.lotro.cards.official.set01;
import com.gempukku.lotro.cards.GenericCardTestHelper;
import com.gempukku.lotro.common.CardType;
import com.gempukku.lotro.common.Culture;
import com.gempukku.lotro.common.Side;
import com.gempukku.lotro.common.Timeword;
import com.gempukku.lotro.common.*;
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.vo.LotroDeck;
import org.junit.Test;
import java.util.HashMap;
import java.util.Map;
import static org.junit.Assert.*;
public class Card_01_224_Tests
{
protected GenericCardTestHelper GetScenario() throws CardNotFoundException, DecisionResultInvalidException {
return new GenericCardTestHelper(
new HashMap<>()
{{
put("card", "1_224");
// put other cards in here as needed for the test case
}},
GenericCardTestHelper.FellowshipSites,
GenericCardTestHelper.FOTRFrodo,
GenericCardTestHelper.RulingRing
);
}
protected GenericCardTestHelper GetScenario() throws CardNotFoundException, DecisionResultInvalidException {
return new GenericCardTestHelper(
new HashMap<>()
{{
put("rtim", "1_224");
put("enquea", "2_83");
put("twk", "1_237");
@Test
public void ReturntoItsMasterStatsAndKeywordsAreCorrect() throws DecisionResultInvalidException, CardNotFoundException {
put("guard", "1_7");
}},
GenericCardTestHelper.FellowshipSites,
GenericCardTestHelper.FOTRFrodo,
GenericCardTestHelper.ATARRing
);
}
/**
* 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.
*/
@Test
public void ReturntoItsMasterStatsAndKeywordsAreCorrect() throws DecisionResultInvalidException, CardNotFoundException {
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());
assertNull(card.getBlueprint().getSubtitle());
assertFalse(card.getBlueprint().isUnique());
assertEquals(Side.SHADOW, card.getBlueprint().getSide());
assertEquals(Culture.WRAITH, card.getBlueprint().getCulture());
assertEquals(CardType.EVENT, card.getBlueprint().getCardType());
var card = scn.GetFreepsCard("rtim");
assertEquals("Return to Its Master", card.getBlueprint().getTitle());
assertNull(card.getBlueprint().getSubtitle());
assertFalse(card.getBlueprint().isUnique());
assertEquals(Side.SHADOW, card.getBlueprint().getSide());
assertEquals(Culture.WRAITH, card.getBlueprint().getCulture());
assertEquals(CardType.EVENT, card.getBlueprint().getCardType());
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
public void ReturntoItsMasterTest1() throws DecisionResultInvalidException, CardNotFoundException {
//Pre-game setup
var scn = GetScenario();
@Test
public void ReturntoItsMasterPermitsAssigningOfNonFierceNazgulWhenUsedDuringFierceSkirmish() throws DecisionResultInvalidException, CardNotFoundException {
//Pre-game setup
var scn = GetScenario();
var card = scn.GetFreepsCard("card");
scn.FreepsMoveCardToHand(card);
var rtim = scn.GetShadowCard("rtim");
var enquea = scn.GetShadowCard("enquea");
var twk = scn.GetShadowCard("twk");
scn.ShadowMoveCardToHand(rtim);
scn.ShadowMoveCharToTable(enquea, twk);
scn.StartGame();
scn.FreepsPlayCard(card);
var frodo = scn.GetRingBearer();
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.ShadowPlayCard(nertea);
assertTrue(scn.ShadowHasOptionalTriggerAvailable());
scn.ShadowAcceptOptionalTrigger();
assertTrue(scn.ShadowDecisionAvailable("play a minion"));
scn.ShadowChooseYes();
//twk, attea, rit, and runner
@@ -141,6 +143,8 @@ public class Card_01_234_Tests
scn.FreepsPassCurrentPhaseAction();
scn.ShadowPlayCard(nertea);
assertTrue(scn.ShadowHasOptionalTriggerAvailable());
scn.ShadowAcceptOptionalTrigger();
assertTrue(scn.ShadowDecisionAvailable("play a minion"));
scn.ShadowChooseYes();
//twk, attea, rit, and runner
@@ -178,6 +182,8 @@ public class Card_01_234_Tests
scn.FreepsPassCurrentPhaseAction();
scn.ShadowPlayCard(nertea);
assertTrue(scn.ShadowHasOptionalTriggerAvailable());
scn.ShadowAcceptOptionalTrigger();
assertTrue(scn.ShadowDecisionAvailable("play a minion"));
scn.ShadowChooseNo();
@@ -203,6 +209,8 @@ public class Card_01_234_Tests
scn.FreepsPassCurrentPhaseAction();
scn.ShadowPlayCard(nertea);
assertTrue(scn.ShadowHasOptionalTriggerAvailable());
scn.ShadowAcceptOptionalTrigger();
assertTrue(scn.ShadowDecisionAvailable("play a minion"));
scn.ShadowChooseYes();
assertEquals(4, scn.GetShadowCardChoiceCount());

View File

@@ -13,91 +13,140 @@ import static org.junit.Assert.*;
public class Card_01_338_Tests
{
protected GenericCardTestHelper GetScenario() throws CardNotFoundException, DecisionResultInvalidException {
return new GenericCardTestHelper(
new HashMap<>()
{{
put("twk", "1_237");
put("lemenya", "1_232");
// put other cards in here as needed for the test case
}},
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
);
}
protected GenericCardTestHelper GetScenario() throws CardNotFoundException, DecisionResultInvalidException {
return new GenericCardTestHelper(
new HashMap<>()
{{
put("twk", "1_237");
put("lemenya", "1_232");
put("nertea", "1_234");
@Test
public void FordofBruinenStatsAndKeywordsAreCorrect() throws DecisionResultInvalidException, CardNotFoundException {
put("guard1", "1_7");
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
);
}
/**
* 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.
*/
@Test
public void FordofBruinenStatsAndKeywordsAreCorrect() throws DecisionResultInvalidException, CardNotFoundException {
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());
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());
}
var card = scn.GetFreepsSite(3);
@Test
public void FordofBruinenOnlyDiscountsTheFirstNazgul() throws DecisionResultInvalidException, CardNotFoundException {
//Pre-game setup
var scn = GetScenario();
assertEquals("Ford of Bruinen", card.getBlueprint().getTitle());
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());
}
var ford = scn.GetShadowSite(3);
@Test
public void FordofBruinenOnlyDiscountsTheFirstNazgul() throws DecisionResultInvalidException, CardNotFoundException {
//Pre-game setup
var scn = GetScenario();
var twk = scn.GetShadowCard("twk");
var lemenya = scn.GetShadowCard("lemenya");
scn.ShadowMoveCardToHand(twk, lemenya);
var ford = scn.GetShadowSite(3);
scn.StartGame();
//Start our test on 2 so that moving to 3 is the first thing we do
scn.SkipToSite(2);
var twk = scn.GetShadowCard("twk");
var lemenya = scn.GetShadowCard("lemenya");
scn.ShadowMoveCardToHand(twk, lemenya);
scn.SetTwilight(9);
scn.FreepsPassCurrentPhaseAction();
scn.StartGame();
//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(10, scn.GetTwilight());
assertEquals(ford, scn.GetCurrentSite());
scn.ShadowPlayCard(twk);
//TWK costs 8 (no roaming), discounted by 5 to 3 total
//10 - 3
assertEquals(7, scn.GetTwilight());
//9 manual + 1 from the fellowship moving
assertEquals(10, scn.GetTwilight());
scn.ShadowPlayCard(lemenya);
//Lemenya costs 4, should have no discount
//7 - 4
assertEquals(3, scn.GetTwilight());
}
scn.ShadowPlayCard(twk);
//TWK costs 8 (no roaming), discounted by 5 to 3 total
//10 - 3
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.ShadowPlayCard(nertea);
assertTrue(scn.ShadowHasOptionalTriggerAvailable());
scn.ShadowAcceptOptionalTrigger();
assertTrue(scn.ShadowDecisionAvailable("play a unique WRAITH minion"));
scn.ShadowChooseYes();
//twk and attea, but not rit or runner
@@ -138,6 +140,8 @@ public class Card_01_234_ErrataTests
scn.FreepsPassCurrentPhaseAction();
scn.ShadowPlayCard(nertea);
assertTrue(scn.ShadowHasOptionalTriggerAvailable());
scn.ShadowAcceptOptionalTrigger();
assertTrue(scn.ShadowDecisionAvailable("play a unique WRAITH minion"));
scn.ShadowChooseYes();
//twk and attea, but not rit or runner
@@ -174,6 +178,8 @@ public class Card_01_234_ErrataTests
scn.FreepsPassCurrentPhaseAction();
scn.ShadowPlayCard(nertea);
assertTrue(scn.ShadowHasOptionalTriggerAvailable());
scn.ShadowAcceptOptionalTrigger();
assertTrue(scn.ShadowDecisionAvailable("play a unique WRAITH minion"));
scn.ShadowChooseNo();
@@ -199,6 +205,8 @@ public class Card_01_234_ErrataTests
scn.FreepsPassCurrentPhaseAction();
scn.ShadowPlayCard(nertea);
assertTrue(scn.ShadowHasOptionalTriggerAvailable());
scn.ShadowAcceptOptionalTrigger();
assertTrue(scn.ShadowDecisionAvailable("play a unique WRAITH minion"));
scn.ShadowChooseYes();
//twk and attea, but not rit or runner