AllyRegion filter added for Horn of Boromir errata

Added errata'd Horn of Boromir and unit tests.  Added new "AllyInCurrentRegion" and "AllyInRegion" filters to facilitate it.  Refactored base of PC card unit tests to be a bit easier to customize card lists.
This commit is contained in:
Christian 'ketura' McCarty
2021-01-30 03:34:46 -06:00
parent 87b27551b2
commit 31d65e0683
11 changed files with 302 additions and 49 deletions

View File

@@ -442,19 +442,23 @@
"effects": {
"type": "activated",
"phase": "assignment",
"condition": {
"type": "canSpot",
"filter": "bearer,notAssignedToSkirmish"
},
"cost": [
{
"type": "exert",
"filter": "self"
},
"filter": "bearer"
}
],
"effect":[
{
"type": "assignFpCharacterToSkirmish",
"player": "fp",
"fpCharacter": "self",
"against": "minion"
}
],
"effect":[
"fpCharacter": "bearer",
"against": "choose(minion)"
},
{
"type": "modifyStrength",
"filter": "choose(ally,allyInCurrentRegion)",

View File

@@ -199,6 +199,17 @@ public class FilterFactory {
int number = Integer.parseInt(parameterSplit[1]);
return (actionContext) -> Filters.isAllyHome(number, sitesBlock);
});
parameterFilters.put("allyInRegion",
(parameter, environment) -> {
final String[] parameterSplit = parameter.split(",");
final SitesBlock sitesBlock = Enum.valueOf(SitesBlock.class, parameterSplit[0].toUpperCase().replace('_', ' '));
int number = Integer.parseInt(parameterSplit[1]);
return (actionContext) -> Filters.isAllyInRegion(number, sitesBlock);
});
parameterFilters.put("allyInCurrentRegion",
(parameter, environment) -> {
return (actionContext) -> Filters.isAllyInCurrentRegion();
});
parameterFilters.put("siteBlock",
(parameter, environment) -> {
final SitesBlock sitesBlock = Enum.valueOf(SitesBlock.class, parameter.toUpperCase().replace(' ', '_'));

View File

@@ -665,6 +665,28 @@ public class Filters {
});
}
public static Filter isAllyInRegion(final int regionNumber, final SitesBlock siteBlock) {
return Filters.and(
CardType.ALLY,
new Filter() {
@Override
public boolean accepts(LotroGame game, PhysicalCard physicalCard) {
return RuleUtils.isAllyInRegion(physicalCard, regionNumber, siteBlock);
}
});
}
public static Filter isAllyInCurrentRegion() {
return Filters.and(
CardType.ALLY,
new Filter() {
@Override
public boolean accepts(LotroGame game, PhysicalCard physicalCard) {
return RuleUtils.isAllyInRegion(physicalCard, GameUtils.getRegion(game), game.getGameState().getCurrentSiteBlock());
}
});
}
public static final Filter allyAtHome = Filters.and(
CardType.ALLY,
new Filter() {
@@ -709,6 +731,8 @@ public class Filters {
}
};
public static Filter siteNumber(final int siteNumber) {
return siteNumberBetweenInclusive(siteNumber, siteNumber);
}

View File

@@ -7,8 +7,10 @@ import com.gempukku.lotro.game.LotroCardBlueprint;
import com.gempukku.lotro.game.PhysicalCard;
import com.gempukku.lotro.game.state.LotroGame;
import com.gempukku.lotro.game.state.Skirmish;
import com.gempukku.lotro.logic.GameUtils;
import com.gempukku.lotro.logic.modifiers.evaluator.Evaluator;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Set;
@@ -186,4 +188,18 @@ public class RuleUtils {
return true;
return false;
}
public static boolean isAllyInRegion(PhysicalCard ally, int regionNumber, SitesBlock siteBlock) {
final SitesBlock allySiteBlock = ally.getBlueprint().getAllyHomeSiteBlock();
final int[] allyHomeSites = ally.getBlueprint().getAllyHomeSiteNumbers();
if (allySiteBlock != siteBlock)
return false;
// for (int number : allyHomeSites)
// if (regionNumber == GameUtils.getRegion(number))
// return true;
// return false;
return Arrays.stream(ally.getBlueprint().getAllyHomeSiteNumbers()).anyMatch(x -> regionNumber == GameUtils.getRegion(x));
}
}

View File

@@ -53,7 +53,7 @@ public abstract class AbstractAtTest {
_userFeedback = new DefaultUserFeedback();
LotroFormatLibrary formatLibrary = new LotroFormatLibrary(new DefaultAdventureLibrary(), _library);
LotroFormat format = formatLibrary.getFormat("movie");
LotroFormat format = formatLibrary.getFormat("multipath");
_game = new DefaultLotroGame(format, decks, _userFeedback, _library);
_userFeedback.setGame(_game);

View File

@@ -8,8 +8,10 @@ import com.gempukku.lotro.common.Zone;
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.decisions.AwaitingDecision;
import com.gempukku.lotro.logic.decisions.DecisionResultInvalidException;
import com.gempukku.lotro.logic.vo.LotroDeck;
import java.util.*;
@@ -19,32 +21,68 @@ public class GenericCardTest extends AbstractAtTest {
private int LastCardID = 100;
//TODO: refactor this to not have different freeps/shadows collections
public Map<String, PhysicalCardImpl> freepsCards = new HashMap<>();
public Map<String, PhysicalCardImpl> shadowCards = new HashMap<>();
public static final HashMap<String, String> FellowshipSites = new HashMap<String, String>() {{
put("site1", "1_319");
put("site2", "1_327");
put("site3", "1_337");
put("site4", "1_343");
put("site5", "1_349");
put("site6", "1_350");
put("site7", "1_353");
put("site8", "1_356");
put("site9", "1_360");
}};
public GenericCardTest(Map<String, String> freepsIDs, Map<String, String> shadowIDs) throws CardNotFoundException, DecisionResultInvalidException {
public static final String FOTRFrodo = "1_290";
public static final String FOTRRing = "1_2";
// Player key, then name/card
public Map<String, Map<String, PhysicalCardImpl>> Cards = new HashMap<>();
public GenericCardTest(Map<String, String> cardIDs) throws CardNotFoundException, DecisionResultInvalidException {
this(cardIDs, null, null, null);
}
public GenericCardTest(Map<String, String> cardIDs, Map<String, String> siteIDs, String ringBearerID, String ringID) throws CardNotFoundException, DecisionResultInvalidException {
super();
initializeSimplestGame();
if(siteIDs == null || ringBearerID == null || ringID == null) {
initializeSimplestGame();
}
else {
Map<String, LotroDeck> decks = new HashMap<String, LotroDeck>();
decks.put(P1, new LotroDeck(P1));
decks.put(P2, new LotroDeck(P2));
if(freepsIDs != null) {
for(String name : freepsIDs.keySet()) {
String id = freepsIDs.get(name);
PhysicalCardImpl card = CreateCard(P1, id);
freepsCards.put(name, card);
FreepsMoveCardToDeck(card);
ShadowMoveCardToDeck(CreateCard(P2, id));
for(String name : siteIDs.keySet()) {
String id = siteIDs.get(name);
decks.get(P1).addSite(id);
decks.get(P2).addSite(id);
}
decks.get(P1).setRingBearer(ringBearerID);
decks.get(P2).setRingBearer(ringBearerID);
decks.get(P1).setRing(ringID);
decks.get(P2).setRing(ringID);
initializeGameWithDecks(decks);
}
if(shadowIDs != null) {
for(String name : shadowIDs.keySet()) {
String id = shadowIDs.get(name);
PhysicalCardImpl card = CreateCard(P2, id);
shadowCards.put(name, card);
ShadowMoveCardToDeck(card);
FreepsMoveCardToDeck(CreateCard(P1, id));
Cards.put(P1, new HashMap<>());
Cards.put(P2, new HashMap<>());
if(cardIDs != null) {
for(String name : cardIDs.keySet()) {
String id = cardIDs.get(name);
PhysicalCardImpl card = CreateCard(P1, id);
Cards.get(P1).put(name, card);
FreepsMoveCardToDeck(card);
card = CreateCard(P2, id);
Cards.get(P2).put(name, card);
FreepsMoveCardToDeck(card);
}
}
}
@@ -57,8 +95,8 @@ public class GenericCardTest extends AbstractAtTest {
skipMulligans();
}
public PhysicalCardImpl GetFreepsCard(String cardName) { return freepsCards.get(cardName); }
public PhysicalCardImpl GetShadowCard(String cardName) { return shadowCards.get(cardName); }
public PhysicalCardImpl GetFreepsCard(String cardName) { return Cards.get(P1).get(cardName); }
public PhysicalCardImpl GetShadowCard(String cardName) { return Cards.get(P2).get(cardName); }
public List<String> FreepsGetAvailableActions() { return GetAvailableActions(P1); }
public List<String> ShadowGetAvailableActions() { return GetAvailableActions(P2); }
@@ -213,18 +251,38 @@ public class GenericCardTest extends AbstractAtTest {
public void FreepsAssignToMinion(PhysicalCardImpl comp, PhysicalCardImpl minion) throws DecisionResultInvalidException {
playerDecided(P1, comp.getCardId() + " " + minion.getCardId());
}
public void FreepsAssignToMinions(PhysicalCardImpl[]... groups) throws DecisionResultInvalidException {
String result = "";
for (PhysicalCardImpl[] group : groups) {
result += group[0].getCardId();
for(int i = 1; i < group.length; i++)
{
result += " " + group[i].getCardId();
}
result += ",";
}
playerDecided(P1, result);
}
public List<PhysicalCardImpl> FreepsGetAttachedCards(String name) { return GetAttachedCards(GetFreepsCard(name)); }
public List<PhysicalCardImpl> GetAttachedCards(PhysicalCardImpl card)
{
public List<PhysicalCardImpl> GetAttachedCards(PhysicalCardImpl card) {
return (List<PhysicalCardImpl>)(List<?>)_game.getGameState().getAttachedCards(card);
}
public void FreepsResolveSkirmish(String name) throws DecisionResultInvalidException { FreepsResolveSkirmish(GetFreepsCard(name)); }
public void FreepsResolveSkirmish(PhysicalCardImpl comp) throws DecisionResultInvalidException {
playerDecided(P1, String.valueOf(comp.getCardId()));
public void FreepsResolveSkirmish(PhysicalCardImpl comp) throws DecisionResultInvalidException { FreepsChooseCard(comp); }
public void FreepsChooseCard(PhysicalCardImpl card) throws DecisionResultInvalidException {
playerDecided(P1, String.valueOf(card.getCardId()));
}
public boolean IsCharAssigned(PhysicalCardImpl card) {
List<Assignment> assigns = _game.getGameState().getAssignments();
return assigns.stream().anyMatch(x -> x.getFellowshipCharacter() == card || x.getShadowCharacters().contains(card));
}
public int FreepsGetStrength(String name) { return GetStrength(GetFreepsCard(name)); }
public int ShadowGetStrength(String name) { return GetStrength(GetShadowCard(name)); }
public int GetStrength(PhysicalCardImpl card)

View File

@@ -22,8 +22,7 @@ public class Elrond_LoRErrataTest
{{
put("elrond", "21_1040");
put("randomcard", "1_3");
}},
null
}}
);
}
@@ -34,8 +33,7 @@ public class Elrond_LoRErrataTest
put("elrond", "21_1040");
put("gandalf", "1_72");
put("arwen", "1_30");
}},
null
}}
);
}
@@ -48,8 +46,7 @@ public class Elrond_LoRErrataTest
put("allyHome3_2", "1_27");
put("allyHome6_1", "1_56");
put("allyHome6_2", "1_57");
}},
null
}}
);
}

View File

@@ -25,9 +25,7 @@ public class FlamingBrandErrataTest
put("arwen", "1_30");
put("boromir", "1_97");
put("aragorn", "1_89");
}},
new HashMap<String, String>()
{{
put("nazgul", "1_229");
put("runner", "1_178");
}}

View File

@@ -18,8 +18,7 @@ public class Galadriel_LoLErrataTest
{{
put("galadriel", "21_1045");
put("elrond", "1_40");
}},
null
}}
);
}
@@ -32,8 +31,7 @@ public class Galadriel_LoLErrataTest
put("allyHome3_2", "1_27");
put("allyHome6_1", "1_56");
put("allyHome6_2", "1_57");
}},
null
}}
);
}

View File

@@ -0,0 +1,149 @@
package com.gempukku.lotro.cards.unofficial.pc.errata;
import com.gempukku.lotro.cards.GenericCardTest;
import com.gempukku.lotro.common.Phase;
import com.gempukku.lotro.common.Zone;
import com.gempukku.lotro.game.CardNotFoundException;
import com.gempukku.lotro.game.PhysicalCardImpl;
import com.gempukku.lotro.logic.decisions.DecisionResultInvalidException;
import junit.framework.Assert;
import org.junit.Test;
import java.util.HashMap;
import static junit.framework.Assert.assertEquals;
import static org.junit.Assert.*;
public class HornOfBoromirErrataTest
{
protected GenericCardTest GetFOTRScenario() throws CardNotFoundException, DecisionResultInvalidException {
return new GenericCardTest(
new HashMap<String, String>()
{{
put("horn", "21_3042");
put("elrond", "1_40");
put("boromir", "1_97");
put("aragorn", "1_89");
put("runner1", "1_178");
put("runner2", "1_178");
}},
GenericCardTest.FellowshipSites,
GenericCardTest.FOTRFrodo,
GenericCardTest.FOTRRing
);
}
protected GenericCardTest GetMovieScenario() throws CardNotFoundException, DecisionResultInvalidException {
return new GenericCardTest(
new HashMap<String, String>()
{{
put("horn", "21_3042");
put("elrond", "1_40");
put("boromir", "1_97");
put("aragorn", "1_89");
put("runner1", "1_178");
put("runner2", "1_178");
}}
);
}
@Test
public void CanBeBorneByBoromir() throws DecisionResultInvalidException, CardNotFoundException {
//Pre-game setup
GenericCardTest scn = GetFOTRScenario();
PhysicalCardImpl elrond = scn.GetFreepsCard("elrond");
PhysicalCardImpl boromir = scn.GetFreepsCard("boromir");
PhysicalCardImpl aragorn = scn.GetFreepsCard("aragorn");
PhysicalCardImpl horn = scn.GetFreepsCard("horn");
scn.FreepsMoveCharToTable(elrond);
scn.FreepsMoveCharToTable(aragorn);
scn.FreepsMoveCardToHand(horn);
scn.FreepsMoveCardToHand(boromir);
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");
Assert.assertEquals(Zone.ATTACHED, horn.getZone());
Assert.assertEquals(boromir, horn.getAttachedTo());
}
@Test
public void AbilityExertsAndAssignsBoromir() throws DecisionResultInvalidException, CardNotFoundException {
//Pre-game setup
GenericCardTest scn = GetFOTRScenario();
PhysicalCardImpl elrond = scn.GetFreepsCard("elrond");
PhysicalCardImpl boromir = scn.GetFreepsCard("boromir");
PhysicalCardImpl horn = scn.GetFreepsCard("horn");
PhysicalCardImpl runner1 = scn.GetShadowCard("runner1");
PhysicalCardImpl runner2 = scn.GetShadowCard("runner2");
scn.FreepsMoveCharToTable(elrond);
scn.FreepsMoveCharToTable(boromir);
scn.FreepsMoveCardToHand(horn);
scn.ShadowMoveCharToTable(runner1);
scn.ShadowMoveCharToTable(runner2);
scn.StartGame();
scn.FreepsUseAction("Play Horn of Boromir");
scn.SkipToPhase(Phase.ASSIGNMENT);
assertTrue(scn.FreepsActionAvailable("Use Horn of Boromir"));
scn.FreepsUseAction("Use Horn of Boromir");
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"));
scn.SkipCurrentPhaseActions();
assertTrue(scn.IsCharAssigned(boromir));
scn.FreepsAssignToMinion(elrond, runner2);
assertTrue(scn.IsCharAssigned(elrond));
}
@Test
public void AbilityDoesNotPumpFarAwayAllies() throws DecisionResultInvalidException, CardNotFoundException {
GenericCardTest scn = GetMovieScenario();
PhysicalCardImpl elrond = scn.GetFreepsCard("elrond");
PhysicalCardImpl boromir = scn.GetFreepsCard("boromir");
PhysicalCardImpl horn = scn.GetFreepsCard("horn");
PhysicalCardImpl runner1 = scn.GetShadowCard("runner1");
PhysicalCardImpl runner2 = scn.GetShadowCard("runner2");
scn.FreepsMoveCharToTable(elrond);
scn.FreepsMoveCharToTable(boromir);
scn.FreepsMoveCardToHand(horn);
scn.ShadowMoveCharToTable(runner1);
scn.ShadowMoveCharToTable(runner2);
scn.StartGame();
scn.FreepsUseAction("Play Horn of Boromir");
scn.SkipToPhase(Phase.ASSIGNMENT);
scn.FreepsUseAction("Use Horn of Boromir");
scn.FreepsChooseCard(runner1);
assertEquals(1, scn.GetWoundsOn(boromir));
assertEquals(8, scn.GetStrength(elrond));
//Skip shadow player's action
scn.SkipCurrentPhaseActions();
}
}

View File

@@ -17,9 +17,7 @@ public class Sam_SoHErrataTest
new HashMap<String, String>()
{{
put("sam", "21_10311");
}},
new HashMap<String, String>()
{{
put("orc", "1_272");
}}
);