Merge branch 'grand-card-rework' into v2-cards
# Conflicts: # gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/effect/appender/PlayCardFromDiscard.java
This commit is contained in:
@@ -108,8 +108,9 @@
|
||||
multiplier: -1
|
||||
}
|
||||
}
|
||||
cost: [
|
||||
{
|
||||
effect: {
|
||||
type: CostToEffect
|
||||
cost: {
|
||||
type: chooseANumber
|
||||
text: Choose how many {raider} tokens to remove
|
||||
from: 0
|
||||
@@ -120,26 +121,34 @@
|
||||
}
|
||||
memorize: tokenCount
|
||||
}
|
||||
{
|
||||
type: RemoveCultureTokens
|
||||
culture: raider
|
||||
select: self
|
||||
count: {
|
||||
type: fromMemory
|
||||
memory: tokenCount
|
||||
}
|
||||
effect: {
|
||||
type: CostToEffect
|
||||
cost: {
|
||||
type: RemoveCultureTokens
|
||||
culture: raider
|
||||
select: self
|
||||
count: {
|
||||
type: fromMemory
|
||||
memory: tokenCount
|
||||
}
|
||||
}
|
||||
effect: {
|
||||
type: playCardFromDiscard
|
||||
select: choose(corsair)
|
||||
maxDiscount: {
|
||||
type: ForEachCultureToken
|
||||
culture: raider
|
||||
filter: self
|
||||
multiplier: -1
|
||||
}
|
||||
discount: {
|
||||
type: fromMemory
|
||||
memory: tokenCount
|
||||
multiplier: -1
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
effect: {
|
||||
type: playCardFromDiscard
|
||||
select: choose(corsair)
|
||||
discount: {
|
||||
type: ForEachCultureToken
|
||||
culture: raider
|
||||
filter: self
|
||||
multiplier: -1
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
gametext: When you play this possession, you may add a [raider] token here.<br><b>Shadow:</b> Remove X [raider] tokens here to play a corsair from your discard pile; its twilight cost is -X. Discard this possession.
|
||||
|
||||
@@ -27,13 +27,16 @@ import java.util.Collection;
|
||||
public class PlayCardFromDiscard implements EffectAppenderProducer {
|
||||
@Override
|
||||
public EffectAppender createEffectAppender(JSONObject effectObject, CardGenerationEnvironment environment) throws InvalidCardDefinitionException {
|
||||
FieldUtils.validateAllowedFields(effectObject, "player", "select", "on", "discount", "removedTwilight", "optional", "extraEffects", "memorize");
|
||||
FieldUtils.validateAllowedFields(effectObject, "select", "on", "discount", "maxDiscount", "removedTwilight", "optional", "extraEffects", "memorize");
|
||||
|
||||
final String player = FieldUtils.getString(effectObject.get("player"), "player", "you");
|
||||
final String select = FieldUtils.getString(effectObject.get("select"), "select");
|
||||
final String onFilter = FieldUtils.getString(effectObject.get("on"), "on");
|
||||
|
||||
final ValueSource costModifierSource = ValueResolver.resolveEvaluator(effectObject.get("discount"), 0, environment);
|
||||
final ValueSource maxDiscountSource = effectObject.get("maxDiscount") == null ? costModifierSource : ValueResolver.resolveEvaluator(effectObject.get("maxDiscount"), 0, environment);
|
||||
final int removedTwilight = FieldUtils.getInteger(effectObject.get("removedTwilight"), "removedTwilight", 0);
|
||||
|
||||
final boolean optional = FieldUtils.getBoolean(effectObject.get("optional"), "optional", false);
|
||||
final String memorize = FieldUtils.getString(effectObject.get("memorize"), "memorize", "_temp");
|
||||
|
||||
@@ -61,13 +64,13 @@ public class PlayCardFromDiscard implements EffectAppenderProducer {
|
||||
},
|
||||
(actionContext) -> {
|
||||
final LotroGame game = actionContext.getGame();
|
||||
final int costModifier = costModifierSource.getEvaluator(actionContext).evaluateExpression(game, actionContext.getSource());
|
||||
final int maxDiscountModifier = maxDiscountSource.getEvaluator(actionContext).evaluateExpression(game, actionContext.getSource());
|
||||
if (onFilterableSource != null) {
|
||||
final Filterable onFilterable = onFilterableSource.getFilterable(actionContext);
|
||||
return Filters.and(Filters.playable(actionContext.getGame(), removedTwilight, costModifier, false, false, true), ExtraFilters.attachableTo(actionContext.getGame(), costModifier, onFilterable));
|
||||
return Filters.and(Filters.playable(actionContext.getGame(), removedTwilight, maxDiscountModifier, false, false, true), ExtraFilters.attachableTo(actionContext.getGame(), maxDiscountModifier, onFilterable));
|
||||
}
|
||||
|
||||
return Filters.playable(actionContext.getGame(), removedTwilight, costModifier, false, false, true);
|
||||
return Filters.playable(actionContext.getGame(), removedTwilight, maxDiscountModifier, false, false, true);
|
||||
},
|
||||
actionContext -> countEvaluator, memorize, player, "Choose card to play from discard", environment));
|
||||
result.addEffectAppender(
|
||||
|
||||
@@ -17,8 +17,8 @@ public class Card_08_050_Tests
|
||||
return new GenericCardTestHelper(
|
||||
new HashMap<>()
|
||||
{{
|
||||
put("card", "8_50");
|
||||
// put other cards in here as needed for the test case
|
||||
put("blacksails", "8_50");
|
||||
put("corsair", "8_53");
|
||||
}},
|
||||
GenericCardTestHelper.FellowshipSites,
|
||||
GenericCardTestHelper.FOTRFrodo,
|
||||
@@ -43,7 +43,7 @@ public class Card_08_050_Tests
|
||||
|
||||
var scn = GetScenario();
|
||||
|
||||
var card = scn.GetFreepsCard("card");
|
||||
var card = scn.GetFreepsCard("blacksails");
|
||||
|
||||
assertEquals("Black Sails of Umbar", card.getBlueprint().getTitle());
|
||||
assertNull(card.getBlueprint().getSubtitle());
|
||||
@@ -55,18 +55,228 @@ public class Card_08_050_Tests
|
||||
assertEquals(2, card.getBlueprint().getTwilightCost());
|
||||
}
|
||||
|
||||
// Uncomment any @Test markers below once this is ready to be used
|
||||
//@Test
|
||||
public void BlackSailsofUmbarTest1() throws DecisionResultInvalidException, CardNotFoundException {
|
||||
@Test
|
||||
public void BlackSailsOnPlayAdds1Token() throws DecisionResultInvalidException, CardNotFoundException {
|
||||
//Pre-game setup
|
||||
var scn = GetScenario();
|
||||
|
||||
var card = scn.GetFreepsCard("card");
|
||||
scn.FreepsMoveCardToHand(card);
|
||||
var blacksails = scn.GetShadowCard("blacksails");
|
||||
scn.ShadowMoveCardToHand(blacksails);
|
||||
|
||||
scn.StartGame();
|
||||
scn.FreepsPlayCard(card);
|
||||
scn.SkipToPhase(Phase.SHADOW);
|
||||
|
||||
assertEquals(2, scn.GetTwilight());
|
||||
assertTrue(scn.ShadowPlayAvailable(blacksails));
|
||||
scn.ShadowPlayCard(blacksails);
|
||||
|
||||
assertEquals(0, scn.GetCultureTokensOn(blacksails));
|
||||
assertTrue(scn.ShadowHasOptionalTriggerAvailable());
|
||||
scn.ShadowAcceptOptionalTrigger();
|
||||
assertEquals(1, scn.GetCultureTokensOn(blacksails));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void BlackSailsAbilityCannotActivateIfNoCorsairInDiscard() throws DecisionResultInvalidException, CardNotFoundException {
|
||||
//Pre-game setup
|
||||
var scn = GetScenario();
|
||||
|
||||
var blacksails = scn.GetShadowCard("blacksails");
|
||||
var corsair = scn.GetShadowCard("corsair");
|
||||
scn.ShadowMoveCardToSupportArea(blacksails);
|
||||
scn.ShadowMoveCardsToTopOfDeck(corsair);
|
||||
|
||||
scn.StartGame();
|
||||
scn.SetTwilight(50);
|
||||
scn.SkipToPhase(Phase.SHADOW);
|
||||
|
||||
assertEquals(Zone.DECK, corsair.getZone());
|
||||
assertFalse(scn.ShadowActionAvailable(blacksails));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void BlackSailsAbilityCanRemove0TokensToDiscount0() throws DecisionResultInvalidException, CardNotFoundException {
|
||||
//Pre-game setup
|
||||
var scn = GetScenario();
|
||||
|
||||
var blacksails = scn.GetShadowCard("blacksails");
|
||||
var corsair = scn.GetShadowCard("corsair");
|
||||
scn.ShadowMoveCardToSupportArea(blacksails);
|
||||
scn.ShadowMoveCardToDiscard(corsair);
|
||||
|
||||
scn.StartGame();
|
||||
scn.SetTwilight(47);
|
||||
scn.AddTokensToCard(blacksails, 5);
|
||||
scn.SkipToPhase(Phase.SHADOW);
|
||||
|
||||
assertEquals(50, scn.GetTwilight());
|
||||
assertEquals(Zone.DISCARD, corsair.getZone());
|
||||
assertTrue(scn.ShadowActionAvailable(blacksails));
|
||||
scn.ShadowUseCardAction(blacksails);
|
||||
assertTrue(scn.ShadowDecisionAvailable("remove"));
|
||||
scn.ShadowChoose("0");
|
||||
|
||||
assertEquals(Zone.SHADOW_CHARACTERS, corsair.getZone());
|
||||
//Buccaneer costs 3 + 2 for roaming, with no discount = 5
|
||||
assertEquals(45, scn.GetTwilight());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void BlackSailsAbilityCanRemove1TokensToDiscount1() throws DecisionResultInvalidException, CardNotFoundException {
|
||||
//Pre-game setup
|
||||
var scn = GetScenario();
|
||||
|
||||
var blacksails = scn.GetShadowCard("blacksails");
|
||||
var corsair = scn.GetShadowCard("corsair");
|
||||
scn.ShadowMoveCardToSupportArea(blacksails);
|
||||
scn.ShadowMoveCardToDiscard(corsair);
|
||||
|
||||
scn.StartGame();
|
||||
scn.SetTwilight(47);
|
||||
scn.AddTokensToCard(blacksails, 5);
|
||||
scn.SkipToPhase(Phase.SHADOW);
|
||||
|
||||
assertEquals(50, scn.GetTwilight());
|
||||
assertEquals(Zone.DISCARD, corsair.getZone());
|
||||
assertTrue(scn.ShadowActionAvailable(blacksails));
|
||||
scn.ShadowUseCardAction(blacksails);
|
||||
assertTrue(scn.ShadowDecisionAvailable("remove"));
|
||||
scn.ShadowChoose("1");
|
||||
|
||||
assertEquals(Zone.SHADOW_CHARACTERS, corsair.getZone());
|
||||
//Buccaneer costs 3 + 2 for roaming, with a -1 discount = 4
|
||||
assertEquals(46, scn.GetTwilight());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void BlackSailsAbilityCanRemove2TokensToDiscount2() throws DecisionResultInvalidException, CardNotFoundException {
|
||||
//Pre-game setup
|
||||
var scn = GetScenario();
|
||||
|
||||
var blacksails = scn.GetShadowCard("blacksails");
|
||||
var corsair = scn.GetShadowCard("corsair");
|
||||
scn.ShadowMoveCardToSupportArea(blacksails);
|
||||
scn.ShadowMoveCardToDiscard(corsair);
|
||||
|
||||
scn.StartGame();
|
||||
scn.SetTwilight(47);
|
||||
scn.AddTokensToCard(blacksails, 5);
|
||||
scn.SkipToPhase(Phase.SHADOW);
|
||||
|
||||
assertEquals(50, scn.GetTwilight());
|
||||
assertEquals(Zone.DISCARD, corsair.getZone());
|
||||
assertTrue(scn.ShadowActionAvailable(blacksails));
|
||||
scn.ShadowUseCardAction(blacksails);
|
||||
assertTrue(scn.ShadowDecisionAvailable("remove"));
|
||||
scn.ShadowChoose("2");
|
||||
|
||||
assertEquals(Zone.SHADOW_CHARACTERS, corsair.getZone());
|
||||
//Buccaneer costs 3 + 2 for roaming, with a -2 discount = 3
|
||||
assertEquals(47, scn.GetTwilight());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void BlackSailsAbilityCanRemove3TokensToDiscount3() throws DecisionResultInvalidException, CardNotFoundException {
|
||||
//Pre-game setup
|
||||
var scn = GetScenario();
|
||||
|
||||
var blacksails = scn.GetShadowCard("blacksails");
|
||||
var corsair = scn.GetShadowCard("corsair");
|
||||
scn.ShadowMoveCardToSupportArea(blacksails);
|
||||
scn.ShadowMoveCardToDiscard(corsair);
|
||||
|
||||
scn.StartGame();
|
||||
scn.SetTwilight(47);
|
||||
scn.AddTokensToCard(blacksails, 5);
|
||||
scn.SkipToPhase(Phase.SHADOW);
|
||||
|
||||
assertEquals(50, scn.GetTwilight());
|
||||
assertEquals(Zone.DISCARD, corsair.getZone());
|
||||
assertTrue(scn.ShadowActionAvailable(blacksails));
|
||||
scn.ShadowUseCardAction(blacksails);
|
||||
assertTrue(scn.ShadowDecisionAvailable("remove"));
|
||||
scn.ShadowChoose("3");
|
||||
|
||||
assertEquals(Zone.SHADOW_CHARACTERS, corsair.getZone());
|
||||
//Buccaneer costs 3 + 2 for roaming, with a -3 discount = 2
|
||||
assertEquals(48, scn.GetTwilight());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void BlackSailsAbilityRemovingTooManyTokensCapsAtZeroCost() throws DecisionResultInvalidException, CardNotFoundException {
|
||||
//Pre-game setup
|
||||
var scn = GetScenario();
|
||||
|
||||
var blacksails = scn.GetShadowCard("blacksails");
|
||||
var corsair = scn.GetShadowCard("corsair");
|
||||
scn.ShadowMoveCardToSupportArea(blacksails);
|
||||
scn.ShadowMoveCardToDiscard(corsair);
|
||||
|
||||
scn.StartGame();
|
||||
scn.SetTwilight(47);
|
||||
scn.AddTokensToCard(blacksails, 5);
|
||||
scn.SkipToPhase(Phase.SHADOW);
|
||||
|
||||
assertEquals(50, scn.GetTwilight());
|
||||
assertEquals(Zone.DISCARD, corsair.getZone());
|
||||
assertTrue(scn.ShadowActionAvailable(blacksails));
|
||||
scn.ShadowUseCardAction(blacksails);
|
||||
assertTrue(scn.ShadowDecisionAvailable("remove"));
|
||||
scn.ShadowChoose("5");
|
||||
|
||||
assertEquals(Zone.SHADOW_CHARACTERS, corsair.getZone());
|
||||
//Buccaneer costs 3 + 2 for roaming, with a -3 discount = 2, even tho 5 was removed
|
||||
assertEquals(48, scn.GetTwilight());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void BlackSailsAbilityUsableWhenDiscountRequired() throws DecisionResultInvalidException, CardNotFoundException {
|
||||
//Pre-game setup
|
||||
var scn = GetScenario();
|
||||
|
||||
var blacksails = scn.GetShadowCard("blacksails");
|
||||
var corsair = scn.GetShadowCard("corsair");
|
||||
scn.ShadowMoveCardToSupportArea(blacksails);
|
||||
scn.ShadowMoveCardToDiscard(corsair);
|
||||
|
||||
scn.StartGame();
|
||||
scn.AddTokensToCard(blacksails, 5);
|
||||
scn.SkipToPhase(Phase.SHADOW);
|
||||
|
||||
assertEquals(3, scn.GetTwilight());
|
||||
assertEquals(Zone.DISCARD, corsair.getZone());
|
||||
assertTrue(scn.ShadowActionAvailable(blacksails));
|
||||
scn.ShadowUseCardAction(blacksails);
|
||||
assertTrue(scn.ShadowDecisionAvailable("remove"));
|
||||
scn.ShadowChoose("2");
|
||||
|
||||
assertEquals(Zone.SHADOW_CHARACTERS, corsair.getZone());
|
||||
//Buccaneer costs 3 + 2 for roaming, with a -2 discount = 3
|
||||
assertEquals(0, scn.GetTwilight());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void BlackSailsAbilityUsableWhenPlayerFumblesAmounts() throws DecisionResultInvalidException, CardNotFoundException {
|
||||
//Pre-game setup
|
||||
var scn = GetScenario();
|
||||
|
||||
var blacksails = scn.GetShadowCard("blacksails");
|
||||
var corsair = scn.GetShadowCard("corsair");
|
||||
scn.ShadowMoveCardToSupportArea(blacksails);
|
||||
scn.ShadowMoveCardToDiscard(corsair);
|
||||
|
||||
scn.StartGame();
|
||||
scn.AddTokensToCard(blacksails, 5);
|
||||
scn.SkipToPhase(Phase.SHADOW);
|
||||
|
||||
assertEquals(3, scn.GetTwilight());
|
||||
assertEquals(Zone.DISCARD, corsair.getZone());
|
||||
assertTrue(scn.ShadowActionAvailable(blacksails));
|
||||
scn.ShadowUseCardAction(blacksails);
|
||||
assertTrue(scn.ShadowDecisionAvailable("remove"));
|
||||
scn.ShadowChoose("1");
|
||||
|
||||
assertEquals(Zone.DISCARD, corsair.getZone());
|
||||
//Buccaneer costs 3 + 2 for roaming, with a -1 discount = 4....which is not enough to have played the buccaneer.
|
||||
assertEquals(3, scn.GetTwilight());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user