Fixed a bug where Asfaloth (and other self-discounting cards) would transfer for free.

This commit is contained in:
Christian 'ketura' McCarty
2022-07-27 22:45:16 -05:00
parent 455b19786a
commit 10841df2ed
3 changed files with 264 additions and 0 deletions

View File

@@ -27,6 +27,9 @@ public class ModifyOwnCost implements EffectProcessor {
return 0;
}
if(target == null && onFilterableSource.getFilterable(actionContext) != Filters.any)
return 0;
if (target != null) {
if (!Filters.and(onFilterableSource.getFilterable(actionContext)).accepts(actionContext.getGame(), target))
return 0;

View File

@@ -172,9 +172,11 @@ public class GenericCardTestHelper extends AbstractAtTest {
public Boolean FreepsActionAvailable(String action) { return ActionAvailable(P1, action); }
public Boolean FreepsCardActionAvailable(PhysicalCardImpl card) { return ActionAvailable(P1, "Use " + GameUtils.getFullName(card)); }
public Boolean FreepsCardPlayAvailable(PhysicalCardImpl card) { return ActionAvailable(P1, "Play " + GameUtils.getFullName(card)); }
public Boolean FreepsCardTransferAvailable(PhysicalCardImpl card) { return ActionAvailable(P1, "Transfer " + GameUtils.getFullName(card)); }
public Boolean ShadowActionAvailable(String action) { return ActionAvailable(P2, action); }
public Boolean ShadowCardActionAvailable(PhysicalCardImpl card) { return ActionAvailable(P2, "Use " + GameUtils.getFullName(card)); }
public Boolean ShadowCardPlayAvailable(PhysicalCardImpl card) { return ActionAvailable(P2, "Play " + GameUtils.getFullName(card)); }
public Boolean ShadowCardTransferAvailable(PhysicalCardImpl card) { return ActionAvailable(P2, "Transfer " + GameUtils.getFullName(card)); }
public Boolean ActionAvailable(String player, String action) {
List<String> actions = GetAvailableActions(player);
if(actions == null)
@@ -222,8 +224,12 @@ public class GenericCardTestHelper extends AbstractAtTest {
public void FreepsUseCardAction(String name) throws DecisionResultInvalidException { playerDecided(P1, getCardActionId(P1, name)); }
public void FreepsUseCardAction(PhysicalCardImpl card) throws DecisionResultInvalidException { playerDecided(P1, getCardActionId(P1, "Use " + GameUtils.getFullName(card))); }
public void FreepsTransferCard(String name) throws DecisionResultInvalidException { FreepsTransferCard(GetFreepsCard(name)); }
public void FreepsTransferCard(PhysicalCardImpl card) throws DecisionResultInvalidException { playerDecided(P1, getCardActionId(P1, "Transfer " + GameUtils.getFullName(card))); }
public void ShadowUseCardAction(String name) throws DecisionResultInvalidException { playerDecided(P2, getCardActionId(P2, name)); }
public void ShadowUseCardAction(PhysicalCardImpl card) throws DecisionResultInvalidException { playerDecided(P2, getCardActionId(P2, "Use " + GameUtils.getFullName(card))); }
public void ShadowTransferCard(String name) throws DecisionResultInvalidException { ShadowTransferCard(GetShadowCard(name)); }
public void ShadowTransferCard(PhysicalCardImpl card) throws DecisionResultInvalidException { playerDecided(P2, getCardActionId(P2, "Transfer " + GameUtils.getFullName(card))); }
public void FreepsPlayCard(String name) throws DecisionResultInvalidException { FreepsPlayCard(GetFreepsCard(name)); }
public void FreepsPlayCard(PhysicalCardImpl card) throws DecisionResultInvalidException { playerDecided(P1, getCardActionId(P1, "Play " + GameUtils.getFullName(card))); }
@@ -786,4 +792,39 @@ public class GenericCardTestHelper extends AbstractAtTest {
{
return _game.getModifiersQuerying().getOverwhelmMultiplier(_game, card);
}
public void SkipToSite(int siteNum) throws DecisionResultInvalidException {
for(int i = GetCurrentSite().getSiteNumber(); i < siteNum; i++)
{
PhysicalCardImpl site = GetCurrentSite();
SkipToPhase(Phase.REGROUP);
if(i == 8)
return; // Game finished
PassCurrentPhaseActions();
if(ShadowDecisionAvailable("reconcile"))
{
ShadowDeclineReconciliation();
}
FreepsChooseToStay();
if(FreepsDecisionAvailable("reconcile"))
{
FreepsChoose(""); //decline reconcile
}
//Shadow player
SkipToPhase(Phase.REGROUP);
FreepsPassCurrentPhaseAction(); // actually shadow with the swap
if(FreepsDecisionAvailable("reconcile"))
{
FreepsChoose(""); //decline reconcile
}
ShadowChoose("1"); // Choose to stay
if(ShadowDecisionAvailable("reconcile"))
{
ShadowDeclineReconciliation();
}
Assert.assertEquals(Phase.FELLOWSHIP, GetCurrentPhase());
}
}
}

View File

@@ -0,0 +1,220 @@
package com.gempukku.lotro.cards.official.set01;
import com.gempukku.lotro.cards.GenericCardTestHelper;
import com.gempukku.lotro.common.*;
import com.gempukku.lotro.filters.Filters;
import com.gempukku.lotro.game.CardNotFoundException;
import com.gempukku.lotro.game.PhysicalCardImpl;
import com.gempukku.lotro.logic.decisions.DecisionResultInvalidException;
import com.gempukku.lotro.logic.modifiers.KeywordModifier;
import com.gempukku.lotro.logic.modifiers.MoveLimitModifier;
import org.junit.Test;
import java.util.HashMap;
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
public class Card_01_031_Tests
{
protected GenericCardTestHelper GetScenario() throws CardNotFoundException, DecisionResultInvalidException {
return new GenericCardTestHelper(
new HashMap<String, String>()
{{
put("asfaloth", "1_31");
put("arwen", "3_7");
put("legolas", "1_50");
put("erestor", "3_14");
put("orophin", "1_56");
}},
GenericCardTestHelper.FellowshipSites,
GenericCardTestHelper.FOTRFrodo,
GenericCardTestHelper.FOTRRing
);
}
@Test
public void AsfalothStatsAndKeywordsAreCorrect() throws DecisionResultInvalidException, CardNotFoundException {
/**
* Set: 1
* Title: *Asfaloth
* Side: Free Peoples
* Culture: Elven
* Twilight Cost: 2
* Type: Possession
* Item Class: Mount
* Game Text: Bearer must be an Elf. When played on Arwen, Asfaloth's twilight cost is -2. While at a plains
* site, bearer is strength +2. Discard Asfaloth when at an underground site.
*/
//Pre-game setup
GenericCardTestHelper scn = GetScenario();
PhysicalCardImpl asfaloth = scn.GetFreepsCard("asfaloth");
assertTrue(asfaloth.getBlueprint().isUnique());
assertEquals(Side.FREE_PEOPLE, asfaloth.getBlueprint().getSide());
assertEquals(Culture.ELVEN, asfaloth.getBlueprint().getCulture());
assertEquals(CardType.POSSESSION, asfaloth.getBlueprint().getCardType());
assertEquals(PossessionClass.MOUNT, asfaloth.getBlueprint().getPossessionClasses().stream().findFirst().get());
assertEquals(2, asfaloth.getBlueprint().getTwilightCost());
assertEquals(2, asfaloth.getBlueprint().getStrength());
// assertEquals(3, asfaloth.getBlueprint().getVitality());
//assertEquals(, asfaloth.getBlueprint().getResistance());
//assertEquals(Signet., asfaloth.getBlueprint().getSignet());
//assertEquals(3, asfaloth.getBlueprint().getAllyHomeSiteNumbers()[0]); // Change this to getAllyHomeSiteNumbers for allies
}
@Test
public void BearerMustBeAnElf() throws DecisionResultInvalidException, CardNotFoundException {
//Pre-game setup
GenericCardTestHelper scn = GetScenario();
PhysicalCardImpl asfaloth = scn.GetFreepsCard("asfaloth");
PhysicalCardImpl arwen = scn.GetFreepsCard("arwen");
PhysicalCardImpl erestor = scn.GetFreepsCard("erestor");
PhysicalCardImpl orophin = scn.GetFreepsCard("orophin");
scn.FreepsMoveCardToHand(asfaloth, arwen, erestor, orophin);
scn.StartGame();
assertFalse(scn.FreepsCardPlayAvailable(asfaloth));
scn.FreepsPlayCard(orophin);
assertTrue(scn.FreepsCardPlayAvailable(asfaloth));
scn.FreepsPlayCard(arwen);
scn.FreepsPlayCard(asfaloth);
assertEquals(2, scn.GetFreepsCardChoiceCount()); // can go on either arwen or orophin
}
@Test
public void TwilightCost2OnNonArwen() throws DecisionResultInvalidException, CardNotFoundException {
//Pre-game setup
GenericCardTestHelper scn = GetScenario();
PhysicalCardImpl asfaloth = scn.GetFreepsCard("asfaloth");
PhysicalCardImpl arwen = scn.GetFreepsCard("arwen");
PhysicalCardImpl erestor = scn.GetFreepsCard("erestor");
PhysicalCardImpl orophin = scn.GetFreepsCard("orophin");
scn.FreepsMoveCharToTable(arwen, erestor, orophin);
scn.FreepsMoveCardToHand(asfaloth);
scn.StartGame();
assertEquals(0, scn.GetTwilight());
scn.FreepsPlayCard(asfaloth);
scn.FreepsChooseCard(erestor);
assertEquals(2, scn.GetTwilight());
}
@Test
public void TwilightCost0OnArwen() throws DecisionResultInvalidException, CardNotFoundException {
//Pre-game setup
GenericCardTestHelper scn = GetScenario();
PhysicalCardImpl asfaloth = scn.GetFreepsCard("asfaloth");
PhysicalCardImpl arwen = scn.GetFreepsCard("arwen");
PhysicalCardImpl erestor = scn.GetFreepsCard("erestor");
PhysicalCardImpl orophin = scn.GetFreepsCard("orophin");
scn.FreepsMoveCharToTable(arwen, erestor, orophin);
scn.FreepsMoveCardToHand(asfaloth);
scn.StartGame();
assertEquals(0, scn.GetTwilight());
scn.FreepsPlayCard(asfaloth);
scn.FreepsChooseCard(arwen);
assertEquals(0, scn.GetTwilight());
}
@Test
public void BearerIsStrengthPlus2AtPlains() throws DecisionResultInvalidException, CardNotFoundException {
//Pre-game setup
GenericCardTestHelper scn = GetScenario();
PhysicalCardImpl asfaloth = scn.GetFreepsCard("asfaloth");
PhysicalCardImpl arwen = scn.GetFreepsCard("arwen");
PhysicalCardImpl erestor = scn.GetFreepsCard("erestor");
PhysicalCardImpl orophin = scn.GetFreepsCard("orophin");
scn.FreepsMoveCharToTable(arwen, erestor, orophin);
scn.FreepsMoveCardToHand(asfaloth);
//cheating to ensure site 2 qualifies
scn.ApplyAdHocModifier(new KeywordModifier(null, Filters.siteNumber(2), Keyword.PLAINS));
scn.StartGame();
assertEquals(6, scn.GetStrength(arwen));
scn.FreepsPlayCard(asfaloth);
scn.FreepsChooseCard(arwen);
assertEquals(8, scn.GetStrength(arwen));
scn.FreepsPassCurrentPhaseAction();
assertEquals(10, scn.GetStrength(arwen));
}
@Test
public void SelfDiscardsAtUnderground() throws DecisionResultInvalidException, CardNotFoundException {
//Pre-game setup
GenericCardTestHelper scn = GetScenario();
PhysicalCardImpl asfaloth = scn.GetFreepsCard("asfaloth");
PhysicalCardImpl arwen = scn.GetFreepsCard("arwen");
PhysicalCardImpl erestor = scn.GetFreepsCard("erestor");
PhysicalCardImpl orophin = scn.GetFreepsCard("orophin");
scn.FreepsMoveCharToTable(arwen, erestor, orophin);
scn.FreepsMoveCardToHand(asfaloth);
//cheating to ensure site 2 qualifies
scn.ApplyAdHocModifier(new KeywordModifier(null, Filters.siteNumber(2), Keyword.UNDERGROUND));
scn.StartGame();
scn.FreepsPlayCard(asfaloth);
scn.FreepsChooseCard(arwen);
assertEquals(Zone.ATTACHED, asfaloth.getZone());
scn.FreepsPassCurrentPhaseAction();
scn.FreepsChoose("0"); // timing tie between Asfaloth and Site
assertEquals(Zone.DISCARD, asfaloth.getZone());
}
@Test
public void TransferBetweenAllyAndCompanionPaysTwilight() throws DecisionResultInvalidException, CardNotFoundException {
// Bug reported: https://play.lotrtcgpc.net/gemp-lotr/game.html?replayId=FallsLover$ilpahhdbsdmp8i2x
// Site 6 permitted multiple transfers between Rumil and Legolas on site 6 with 0 twilight added to the pool.
//Pre-game setup
GenericCardTestHelper scn = GetScenario();
PhysicalCardImpl asfaloth = scn.GetFreepsCard("asfaloth");
PhysicalCardImpl arwen = scn.GetFreepsCard("arwen");
PhysicalCardImpl legolas = scn.GetFreepsCard("legolas");
PhysicalCardImpl erestor = scn.GetFreepsCard("erestor");
PhysicalCardImpl orophin = scn.GetFreepsCard("orophin");
scn.FreepsMoveCharToTable(arwen, legolas, erestor, orophin);
scn.FreepsMoveCardToHand(asfaloth);
scn.ApplyAdHocModifier(new MoveLimitModifier(null, 10));
scn.StartGame();
assertEquals(0, scn.GetTwilight());
scn.FreepsPlayCard(asfaloth);
scn.FreepsChooseCard(erestor);
assertEquals(2, scn.GetTwilight());
scn.SkipToSite(3);
assertEquals(0, scn.GetTwilight());
assertTrue(scn.FreepsCardTransferAvailable(asfaloth));
scn.FreepsTransferCard(asfaloth);
scn.FreepsChooseCard(legolas);
assertEquals(2, scn.GetTwilight());
}
}