Fixed V2 Sirannon Dam ability not replacing a tentacle with the Watcher properly.

This commit is contained in:
Christian 'ketura' McCarty
2025-03-20 18:07:32 -05:00
parent d55418f1d4
commit 5bd3ec8dff
5 changed files with 227 additions and 125 deletions

View File

@@ -640,8 +640,8 @@
effect: [
{
type: replaceInSkirmish
filter: tentacle
with: choose(name(Water in the Water))
filter: tentacle,InSkirmishAgainst(unbound,companion)
with: choose(name(Watcher in the Water))
}
]
}

View File

@@ -8,6 +8,7 @@ import com.gempukku.lotro.cards.build.field.FieldUtils;
import com.gempukku.lotro.cards.build.field.effect.EffectAppender;
import com.gempukku.lotro.cards.build.field.effect.EffectAppenderProducer;
import com.gempukku.lotro.cards.build.field.effect.appender.resolver.CardResolver;
import com.gempukku.lotro.filters.Filters;
import com.gempukku.lotro.game.PhysicalCard;
import com.gempukku.lotro.logic.actions.CostToEffectAction;
import com.gempukku.lotro.logic.effects.ReplaceInSkirmishEffect;
@@ -23,6 +24,12 @@ public class ReplaceInSkirmish implements EffectAppenderProducer {
final String filter = FieldUtils.getString(effectObject.get("filter"), "filter");
final String with = FieldUtils.getString(effectObject.get("with"), "with");
if (filter == null)
throw new InvalidCardDefinitionException("'filter' is required for ReplaceInSkirmish effect.");
if (with == null)
throw new InvalidCardDefinitionException("'with' is required for ReplaceInSkirmish effect.");
final FilterableSource filterableSource = environment.getFilterFactory().generateFilter(filter, environment);
MultiEffectAppender result = new MultiEffectAppender();
@@ -34,7 +41,8 @@ public class ReplaceInSkirmish implements EffectAppenderProducer {
protected Effect createEffect(boolean cost, CostToEffectAction action, ActionContext actionContext) {
final PhysicalCard card = actionContext.getCardFromMemory("_temp");
if (card != null)
return new ReplaceInSkirmishEffect(card, filterableSource.getFilterable(actionContext));
return new ReplaceInSkirmishEffect(card, filterableSource.getFilterable(actionContext),
Filters.inSkirmish);
else
return new DoNothingEffect();
}

View File

@@ -435,42 +435,6 @@ public class GameState {
return _inPlay;
}
public void removeFromSkirmish(PhysicalCard card) {
removeFromSkirmish(card, true);
}
public void replaceInSkirmish(PhysicalCard card) {
_skirmish.setFellowshipCharacter(card);
for (GameStateListener gameStateListener : getAllGameStateListeners()) {
gameStateListener.finishSkirmish();
gameStateListener.startSkirmish(_skirmish.getFellowshipCharacter(), _skirmish.getShadowCharacters());
}
}
public void replaceInSkirmishMinion(PhysicalCard card, PhysicalCard removeMinion) {
removeFromSkirmish(removeMinion);
_skirmish.getShadowCharacters().add(card);
for (GameStateListener listener : getAllGameStateListeners())
listener.addToSkirmish(card);
}
private void removeFromSkirmish(PhysicalCard card, boolean notify) {
if (_skirmish != null) {
if (_skirmish.getFellowshipCharacter() == card) {
_skirmish.setFellowshipCharacter(null);
_skirmish.addRemovedFromSkirmish(card);
if (notify)
for (GameStateListener listener : getAllGameStateListeners())
listener.removeFromSkirmish(card);
}
if (_skirmish.getShadowCharacters().remove(card)) {
_skirmish.addRemovedFromSkirmish(card);
if (notify)
for (GameStateListener listener : getAllGameStateListeners())
listener.removeFromSkirmish(card);
}
}
}
public void removeCardsFromZone(String playerPerforming, Collection<PhysicalCard> cards) {
for (PhysicalCard card : cards) {
@@ -500,15 +464,7 @@ public class GameState {
if (zone == Zone.STACKED)
((PhysicalCardImpl) card).stackOn(null);
for (Assignment assignment : new LinkedList<>(_assignments)) {
if (assignment.getFellowshipCharacter() == card)
removeAssignment(assignment);
if (assignment.getShadowCharacters().remove(card))
if (assignment.getShadowCharacters().isEmpty())
removeAssignment(assignment);
}
if (_skirmish != null)
removeFromAssignment(card);
removeFromSkirmish(card, false);
removeAllTokens(card);
@@ -593,6 +549,135 @@ public class GameState {
}
}
public void replaceInSkirmish(PhysicalCard card) {
_skirmish.setFellowshipCharacter(card);
for (GameStateListener gameStateListener : getAllGameStateListeners()) {
gameStateListener.finishSkirmish();
gameStateListener.startSkirmish(_skirmish.getFellowshipCharacter(), _skirmish.getShadowCharacters());
}
}
public void replaceInSkirmishMinion(PhysicalCard card, PhysicalCard removeMinion) {
removeFromSkirmish(removeMinion);
if(_skirmish.getShadowCharacters().contains(card)) {
removeFromSkirmish(card);
}
_skirmish.getShadowCharacters().add(card);
for (GameStateListener listener : getAllGameStateListeners())
listener.addToSkirmish(card);
}
public void removeFromSkirmish(PhysicalCard card) {
removeFromSkirmish(card, true);
}
private void removeFromSkirmish(PhysicalCard card, boolean notify) {
if (_skirmish == null)
return;
if (_skirmish.getFellowshipCharacter() == card) {
_skirmish.setFellowshipCharacter(null);
_skirmish.addRemovedFromSkirmish(card);
if (notify)
for (GameStateListener listener : getAllGameStateListeners())
listener.removeFromSkirmish(card);
}
if (_skirmish.getShadowCharacters().remove(card)) {
_skirmish.addRemovedFromSkirmish(card);
if (notify)
for (GameStateListener listener : getAllGameStateListeners())
listener.removeFromSkirmish(card);
}
}
public void removeFromAssignment(PhysicalCard card) {
if( _assignments.isEmpty())
return;
for (var assignment : new LinkedList<>(_assignments)) {
if (assignment.getFellowshipCharacter() == card) {
removeAssignment(assignment);
}
if (assignment.getShadowCharacters().remove(card)) {
if (assignment.getShadowCharacters().isEmpty()) {
removeAssignment(assignment);
}
else {
refreshAssignment(assignment);
}
}
}
}
public void assignToSkirmishes(PhysicalCard fp, Set<PhysicalCard> minions) {
removeFromSkirmish(fp);
for (PhysicalCard minion : minions) {
removeFromSkirmish(minion);
for (Assignment assignment : new LinkedList<>(_assignments)) {
if (assignment.getShadowCharacters().remove(minion))
if (assignment.getShadowCharacters().isEmpty())
removeAssignment(assignment);
}
}
Assignment assignment = findFreepsAssignment(fp);
if (assignment != null)
assignment.getShadowCharacters().addAll(minions);
else
_assignments.add(new Assignment(fp, new HashSet<>(minions)));
for (GameStateListener listener : getAllGameStateListeners())
listener.addAssignment(fp, minions);
}
public void refreshAssignment(Assignment assignment) {
removeAssignment(assignment);
assignToSkirmishes(assignment.getFellowshipCharacter(), assignment.getShadowCharacters());
}
public void removeAssignment(Assignment assignment) {
_assignments.remove(assignment);
for (GameStateListener listener : getAllGameStateListeners()) {
listener.removeAssignment(assignment.getFellowshipCharacter());
}
}
public List<Assignment> getAssignments() {
return _assignments;
}
private Assignment findFreepsAssignment(PhysicalCard fp) {
for (Assignment assignment : _assignments)
if (assignment.getFellowshipCharacter() == fp)
return assignment;
return null;
}
public void startSkirmish(PhysicalCard fellowshipCharacter, Set<PhysicalCard> shadowCharacters) {
_skirmish = new Skirmish(fellowshipCharacter, new HashSet<>(shadowCharacters));
for (GameStateListener listener : getAllGameStateListeners())
listener.startSkirmish(_skirmish.getFellowshipCharacter(), _skirmish.getShadowCharacters());
}
public void restartSkirmish(Skirmish skirmish) {
_skirmish = skirmish;
for (GameStateListener listener : getAllGameStateListeners())
listener.startSkirmish(_skirmish.getFellowshipCharacter(), _skirmish.getShadowCharacters());
}
public Skirmish getSkirmish() {
return _skirmish;
}
public void finishSkirmish() {
if (_skirmish != null) {
_skirmish = null;
for (GameStateListener listener : getAllGameStateListeners())
listener.finishSkirmish();
}
}
public void shuffleCardsIntoDeck(Collection<? extends PhysicalCard> cards, String playerId) {
List<PhysicalCardImpl> zoneCards = _decks.get(playerId);
@@ -1028,69 +1113,6 @@ public class GameState {
setTwilight(_twilightPool - Math.min(Math.max(0, twilight), _twilightPool));
}
public void assignToSkirmishes(PhysicalCard fp, Set<PhysicalCard> minions) {
removeFromSkirmish(fp);
for (PhysicalCard minion : minions) {
removeFromSkirmish(minion);
for (Assignment assignment : new LinkedList<>(_assignments)) {
if (assignment.getShadowCharacters().remove(minion))
if (assignment.getShadowCharacters().size() == 0)
removeAssignment(assignment);
}
}
Assignment assignment = findAssignment(fp);
if (assignment != null)
assignment.getShadowCharacters().addAll(minions);
else
_assignments.add(new Assignment(fp, new HashSet<>(minions)));
for (GameStateListener listener : getAllGameStateListeners())
listener.addAssignment(fp, minions);
}
public void removeAssignment(Assignment assignment) {
_assignments.remove(assignment);
for (GameStateListener listener : getAllGameStateListeners())
listener.removeAssignment(assignment.getFellowshipCharacter());
}
public List<Assignment> getAssignments() {
return _assignments;
}
private Assignment findAssignment(PhysicalCard fp) {
for (Assignment assignment : _assignments)
if (assignment.getFellowshipCharacter() == fp)
return assignment;
return null;
}
public void startSkirmish(PhysicalCard fellowshipCharacter, Set<PhysicalCard> shadowCharacters) {
_skirmish = new Skirmish(fellowshipCharacter, new HashSet<>(shadowCharacters));
for (GameStateListener listener : getAllGameStateListeners())
listener.startSkirmish(_skirmish.getFellowshipCharacter(), _skirmish.getShadowCharacters());
}
public void restartSkirmish(Skirmish skirmish) {
_skirmish = skirmish;
for (GameStateListener listener : getAllGameStateListeners())
listener.startSkirmish(_skirmish.getFellowshipCharacter(), _skirmish.getShadowCharacters());
}
public Skirmish getSkirmish() {
return _skirmish;
}
public void finishSkirmish() {
if (_skirmish != null) {
_skirmish = null;
for (GameStateListener listener : getAllGameStateListeners())
listener.finishSkirmish();
}
}
public PhysicalCard removeTopDeckCard(String player) {
List<PhysicalCardImpl> deck = _decks.get(player);
if (deck.size() > 0) {

View File

@@ -1,6 +1,7 @@
package com.gempukku.lotro.logic.effects;
import com.gempukku.lotro.common.Filterable;
import com.gempukku.lotro.common.Side;
import com.gempukku.lotro.filters.Filters;
import com.gempukku.lotro.game.PhysicalCard;
import com.gempukku.lotro.game.state.LotroGame;
@@ -33,7 +34,14 @@ public class ReplaceInSkirmishEffect extends AbstractEffect {
@Override
protected FullEffectResult playEffectReturningResult(LotroGame game) {
if (isPlayableInFull(game)) {
if(_replacedBy.getBlueprint().getSide() == Side.FREE_PEOPLE) {
game.getGameState().replaceInSkirmish(_replacedBy);
}
else if(_replacedBy.getBlueprint().getSide() == Side.SHADOW) {
var replacing = Filters.findFirstActive(game, _replacingFilter);
game.getGameState().replaceInSkirmishMinion(_replacedBy, replacing);
}
return new FullEffectResult(true);
}
return new FullEffectResult(false);

View File

@@ -1,9 +1,11 @@
package com.gempukku.lotro.cards.unofficial.pc.vsets.set_v01;
import com.gempukku.lotro.cards.GenericCardTestHelper;
import com.gempukku.lotro.common.*;
import com.gempukku.lotro.common.CardType;
import com.gempukku.lotro.common.Culture;
import com.gempukku.lotro.common.Keyword;
import com.gempukku.lotro.common.Side;
import com.gempukku.lotro.game.CardNotFoundException;
import com.gempukku.lotro.game.PhysicalCardImpl;
import com.gempukku.lotro.logic.decisions.DecisionResultInvalidException;
import org.junit.Test;
@@ -18,8 +20,12 @@ public class Card_V1_065_Tests
return new GenericCardTestHelper(
new HashMap<>()
{{
put("card", "101_65");
// put other cards in here as needed for the test case
put("dam", "101_65");
put("foul", "2_58");
put("watcher", "2_73");
put("aragorn", "1_89");
}},
GenericCardTestHelper.FellowshipSites,
GenericCardTestHelper.FOTRFrodo,
@@ -46,7 +52,7 @@ public class Card_V1_065_Tests
var scn = GetScenario();
var card = scn.GetFreepsCard("card");
var card = scn.GetFreepsCard("dam");
assertEquals("Sirannon Dam", card.getBlueprint().getTitle());
assertNull(card.getBlueprint().getSubtitle());
@@ -58,18 +64,76 @@ public class Card_V1_065_Tests
assertEquals(0, card.getBlueprint().getTwilightCost());
}
// Uncomment any @Test markers below once this is ready to be used
//@Test
public void SirannonDamTest1() throws DecisionResultInvalidException, CardNotFoundException {
@Test
public void SirannonDamMakesCompanionsDefenderPlus1() throws DecisionResultInvalidException, CardNotFoundException {
//Pre-game setup
var scn = GetScenario();
var card = scn.GetFreepsCard("card");
scn.FreepsMoveCardToHand(card);
var frodo = scn.GetRingBearer();
var dam = scn.GetShadowCard("dam");
scn.ShadowMoveCardToSupportArea(dam);
scn.StartGame();
scn.FreepsPlayCard(card);
assertTrue(scn.hasKeyword(frodo, Keyword.DEFENDER));
}
assertEquals(0, scn.GetTwilight());
@Test
public void SirannonDamMakesSitesWithNoKeywordGainMarsh() throws DecisionResultInvalidException, CardNotFoundException {
//Pre-game setup
var scn = GetScenario();
var frodo = scn.GetRingBearer();
var dam = scn.GetShadowCard("dam");
scn.ShadowMoveCardToHand(dam);
scn.StartGame();
scn.FreepsPassCurrentPhaseAction();
assertFalse(scn.hasKeyword(scn.GetCurrentSite(), Keyword.MARSH));
scn.ShadowPlayCard(dam);
assertTrue(scn.hasKeyword(scn.GetCurrentSite(), Keyword.MARSH));
}
@Test
public void SirannonDamCanRemove2BurdensToMakeWatcherReplaceTentacleInSkirmish() throws DecisionResultInvalidException, CardNotFoundException {
//Pre-game setup
var scn = GetScenario();
var frodo = scn.GetRingBearer();
var aragorn = scn.GetFreepsCard("aragorn");
scn.FreepsMoveCharToTable(aragorn);
var dam = scn.GetShadowCard("dam");
var foul = scn.GetShadowCard("foul");
var watcher = scn.GetShadowCard("watcher");
scn.ShadowMoveCardToSupportArea(dam);
scn.ShadowMoveCardToHand(foul, watcher);
scn.StartGame();
scn.AddBurdens(2);
scn.SetTwilight(10);
scn.FreepsPassCurrentPhaseAction();
scn.ShadowPlayCard(foul);
scn.ShadowDeclineOptionalTrigger();
scn.ShadowPlayCard(watcher);
scn.SkipToAssignments();
scn.FreepsAssignToMinions(aragorn, foul);
scn.ShadowDeclineAssignments();
scn.FreepsResolveSkirmish(aragorn);
scn.FreepsPassCurrentPhaseAction();
assertEquals(3, scn.GetBurdens());
assertTrue(scn.IsCharSkirmishing(foul));
assertFalse(scn.IsCharSkirmishing(watcher));
assertTrue(scn.ShadowActionAvailable(dam));
scn.ShadowUseCardAction(dam);
assertEquals(1, scn.GetBurdens());
assertTrue(scn.IsCharSkirmishing(watcher));
assertFalse(scn.IsCharSkirmishing(foul));
}
}