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: [ effect: [
{ {
type: replaceInSkirmish type: replaceInSkirmish
filter: tentacle filter: tentacle,InSkirmishAgainst(unbound,companion)
with: choose(name(Water in the Water)) 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.EffectAppender;
import com.gempukku.lotro.cards.build.field.effect.EffectAppenderProducer; import com.gempukku.lotro.cards.build.field.effect.EffectAppenderProducer;
import com.gempukku.lotro.cards.build.field.effect.appender.resolver.CardResolver; 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.game.PhysicalCard;
import com.gempukku.lotro.logic.actions.CostToEffectAction; import com.gempukku.lotro.logic.actions.CostToEffectAction;
import com.gempukku.lotro.logic.effects.ReplaceInSkirmishEffect; 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 filter = FieldUtils.getString(effectObject.get("filter"), "filter");
final String with = FieldUtils.getString(effectObject.get("with"), "with"); 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); final FilterableSource filterableSource = environment.getFilterFactory().generateFilter(filter, environment);
MultiEffectAppender result = new MultiEffectAppender(); MultiEffectAppender result = new MultiEffectAppender();
@@ -34,7 +41,8 @@ public class ReplaceInSkirmish implements EffectAppenderProducer {
protected Effect createEffect(boolean cost, CostToEffectAction action, ActionContext actionContext) { protected Effect createEffect(boolean cost, CostToEffectAction action, ActionContext actionContext) {
final PhysicalCard card = actionContext.getCardFromMemory("_temp"); final PhysicalCard card = actionContext.getCardFromMemory("_temp");
if (card != null) if (card != null)
return new ReplaceInSkirmishEffect(card, filterableSource.getFilterable(actionContext)); return new ReplaceInSkirmishEffect(card, filterableSource.getFilterable(actionContext),
Filters.inSkirmish);
else else
return new DoNothingEffect(); return new DoNothingEffect();
} }

View File

@@ -435,42 +435,6 @@ public class GameState {
return _inPlay; 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) { public void removeCardsFromZone(String playerPerforming, Collection<PhysicalCard> cards) {
for (PhysicalCard card : cards) { for (PhysicalCard card : cards) {
@@ -500,16 +464,8 @@ public class GameState {
if (zone == Zone.STACKED) if (zone == Zone.STACKED)
((PhysicalCardImpl) card).stackOn(null); ((PhysicalCardImpl) card).stackOn(null);
for (Assignment assignment : new LinkedList<>(_assignments)) { removeFromAssignment(card);
if (assignment.getFellowshipCharacter() == card) removeFromSkirmish(card, false);
removeAssignment(assignment);
if (assignment.getShadowCharacters().remove(card))
if (assignment.getShadowCharacters().isEmpty())
removeAssignment(assignment);
}
if (_skirmish != null)
removeFromSkirmish(card, false);
removeAllTokens(card); removeAllTokens(card);
//If this is reset, then there is no way for self-discounting effects (which are evaluated while in the void) //If this is reset, then there is no way for self-discounting effects (which are evaluated while in the void)
@@ -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) { public void shuffleCardsIntoDeck(Collection<? extends PhysicalCard> cards, String playerId) {
List<PhysicalCardImpl> zoneCards = _decks.get(playerId); List<PhysicalCardImpl> zoneCards = _decks.get(playerId);
@@ -1028,69 +1113,6 @@ public class GameState {
setTwilight(_twilightPool - Math.min(Math.max(0, twilight), _twilightPool)); 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) { public PhysicalCard removeTopDeckCard(String player) {
List<PhysicalCardImpl> deck = _decks.get(player); List<PhysicalCardImpl> deck = _decks.get(player);
if (deck.size() > 0) { if (deck.size() > 0) {

View File

@@ -1,6 +1,7 @@
package com.gempukku.lotro.logic.effects; package com.gempukku.lotro.logic.effects;
import com.gempukku.lotro.common.Filterable; import com.gempukku.lotro.common.Filterable;
import com.gempukku.lotro.common.Side;
import com.gempukku.lotro.filters.Filters; import com.gempukku.lotro.filters.Filters;
import com.gempukku.lotro.game.PhysicalCard; import com.gempukku.lotro.game.PhysicalCard;
import com.gempukku.lotro.game.state.LotroGame; import com.gempukku.lotro.game.state.LotroGame;
@@ -33,7 +34,14 @@ public class ReplaceInSkirmishEffect extends AbstractEffect {
@Override @Override
protected FullEffectResult playEffectReturningResult(LotroGame game) { protected FullEffectResult playEffectReturningResult(LotroGame game) {
if (isPlayableInFull(game)) { if (isPlayableInFull(game)) {
game.getGameState().replaceInSkirmish(_replacedBy); 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(true);
} }
return new FullEffectResult(false); return new FullEffectResult(false);

View File

@@ -1,9 +1,11 @@
package com.gempukku.lotro.cards.unofficial.pc.vsets.set_v01; package com.gempukku.lotro.cards.unofficial.pc.vsets.set_v01;
import com.gempukku.lotro.cards.GenericCardTestHelper; 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.CardNotFoundException;
import com.gempukku.lotro.game.PhysicalCardImpl;
import com.gempukku.lotro.logic.decisions.DecisionResultInvalidException; import com.gempukku.lotro.logic.decisions.DecisionResultInvalidException;
import org.junit.Test; import org.junit.Test;
@@ -18,8 +20,12 @@ public class Card_V1_065_Tests
return new GenericCardTestHelper( return new GenericCardTestHelper(
new HashMap<>() new HashMap<>()
{{ {{
put("card", "101_65"); put("dam", "101_65");
// put other cards in here as needed for the test case put("foul", "2_58");
put("watcher", "2_73");
put("aragorn", "1_89");
}}, }},
GenericCardTestHelper.FellowshipSites, GenericCardTestHelper.FellowshipSites,
GenericCardTestHelper.FOTRFrodo, GenericCardTestHelper.FOTRFrodo,
@@ -46,7 +52,7 @@ public class Card_V1_065_Tests
var scn = GetScenario(); var scn = GetScenario();
var card = scn.GetFreepsCard("card"); var card = scn.GetFreepsCard("dam");
assertEquals("Sirannon Dam", card.getBlueprint().getTitle()); assertEquals("Sirannon Dam", card.getBlueprint().getTitle());
assertNull(card.getBlueprint().getSubtitle()); assertNull(card.getBlueprint().getSubtitle());
@@ -58,18 +64,76 @@ public class Card_V1_065_Tests
assertEquals(0, card.getBlueprint().getTwilightCost()); assertEquals(0, card.getBlueprint().getTwilightCost());
} }
// Uncomment any @Test markers below once this is ready to be used @Test
//@Test public void SirannonDamMakesCompanionsDefenderPlus1() throws DecisionResultInvalidException, CardNotFoundException {
public void SirannonDamTest1() throws DecisionResultInvalidException, CardNotFoundException {
//Pre-game setup //Pre-game setup
var scn = GetScenario(); var scn = GetScenario();
var card = scn.GetFreepsCard("card"); var frodo = scn.GetRingBearer();
scn.FreepsMoveCardToHand(card);
var dam = scn.GetShadowCard("dam");
scn.ShadowMoveCardToSupportArea(dam);
scn.StartGame(); 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));
} }
} }