diff --git a/gemp-lotr/gemp-lotr-async/src/main/web/cards/set19.json b/gemp-lotr/gemp-lotr-async/src/main/web/cards/set19.json index e8edfca96..e3729a02a 100644 --- a/gemp-lotr/gemp-lotr-async/src/main/web/cards/set19.json +++ b/gemp-lotr/gemp-lotr-async/src/main/web/cards/set19.json @@ -1438,7 +1438,7 @@ "modifier": { "type": "cantBeAssignedToSkirmishAgainst", "side": "free people", - "fpCharacter": "race(stored)", + "fpCharacter": "companion,race(stored)", "minion": "self" } } diff --git a/gemp-lotr/gemp-lotr-async/src/main/web/cards/set9-1.json b/gemp-lotr/gemp-lotr-async/src/main/web/cards/set9-1.json index 8bfd9f6d1..51cf32cfc 100644 --- a/gemp-lotr/gemp-lotr-async/src/main/web/cards/set9-1.json +++ b/gemp-lotr/gemp-lotr-async/src/main/web/cards/set9-1.json @@ -715,7 +715,8 @@ "filter": "bearer" }, "effect": { - "type": "removeTokens" + "type": "removeTokens", + "filter": "choose(any)" } }, { diff --git a/gemp-lotr/gemp-lotr-async/src/main/web/images/erratas/LOTR18008.jpg b/gemp-lotr/gemp-lotr-async/src/main/web/images/erratas/LOTR18008.jpg index 8e0a31b42..26b42ade0 100644 Binary files a/gemp-lotr/gemp-lotr-async/src/main/web/images/erratas/LOTR18008.jpg and b/gemp-lotr/gemp-lotr-async/src/main/web/images/erratas/LOTR18008.jpg differ diff --git a/gemp-lotr/gemp-lotr-async/src/main/web/js/gemp-022/deckBuildingUi.js b/gemp-lotr/gemp-lotr-async/src/main/web/js/gemp-022/deckBuildingUi.js index 05b1288db..ef43234ea 100644 --- a/gemp-lotr/gemp-lotr-async/src/main/web/js/gemp-022/deckBuildingUi.js +++ b/gemp-lotr/gemp-lotr-async/src/main/web/js/gemp-022/deckBuildingUi.js @@ -348,26 +348,25 @@ var GempLotrDeckBuildingUI = Class.extend({ } this.importDeckCollection(formattedText, function (xml) { - log(xml); - var cards = xml.documentElement.getElementsByTagName("card"); for (var i = 0; i < cards.length; i++) { var cardElem = cards[i]; var blueprintId = cardElem.getAttribute("blueprintId"); var side = cardElem.getAttribute("side"); var group = cardElem.getAttribute("group"); - if (group == "ringBearer") { - that.addCardToContainer(blueprintId, "special", that.ringBearerDiv, false).addClass("cardInDeck"); - that.layoutSpecialGroups(); - } - else if (group == "ring") { - that.addCardToContainer(blueprintId, "special", that.ringDiv, false).addClass("cardInDeck"); - that.layoutSpecialGroups(); - } - else { - that.addCardToDeckAndLayout(blueprintId, side); + var cardCount = parseInt(cardElem.getAttribute("count")); + for (var j = 0; j < cardCount; j++) { + if (group == "ringBearer") { + that.addCardToContainer(blueprintId, "special", that.ringBearerDiv, false).addClass("cardInDeck"); + } else if (group == "ring") { + that.addCardToContainer(blueprintId, "special", that.ringDiv, false).addClass("cardInDeck"); + } else { + that.addCardToDeckDontLayout(blueprintId, side); + } } } + that.deckModified(true); + that.layoutDeck(); $("#editingDeck").text("Imported Deck (unsaved)"); }); }, @@ -711,6 +710,18 @@ var GempLotrDeckBuildingUI = Class.extend({ this.selectionFunc = this.addCardToDeckAndLayout; }, + addCardToDeckDontLayout:function (blueprintId, side) { + var that = this; + if (side == "FREE_PEOPLE") { + this.addCardToDeck(blueprintId, side); + } else if (side == "SHADOW") { + this.addCardToDeck(blueprintId, side); + } else if (side == null) { + var div = this.addCardToContainer(blueprintId, side, this.siteDiv, false) + div.addClass("cardInDeck"); + } + }, + addCardToDeckAndLayout:function (blueprintId, side) { var that = this; if (side == "FREE_PEOPLE") { @@ -950,7 +961,6 @@ var GempLotrDeckBuildingUI = Class.extend({ this.ringBearerGroup.layoutCards(); this.ringGroup.layoutCards(); this.siteGroup.layoutCards(); - }, layoutDeck:function () { diff --git a/gemp-lotr/gemp-lotr-cards/src/main/java/com/gempukku/lotro/cards/set7/sauron/Card7_284.java b/gemp-lotr/gemp-lotr-cards/src/main/java/com/gempukku/lotro/cards/set7/sauron/Card7_284.java index 4a4092219..d7bbbdd21 100644 --- a/gemp-lotr/gemp-lotr-cards/src/main/java/com/gempukku/lotro/cards/set7/sauron/Card7_284.java +++ b/gemp-lotr/gemp-lotr-cards/src/main/java/com/gempukku/lotro/cards/set7/sauron/Card7_284.java @@ -45,7 +45,8 @@ public class Card7_284 extends AbstractMinion { KilledResult killResult = threatWoundsEffect.getKillResult(); if (killResult.getCause() == KillEffect.Cause.OVERWHELM && Filters.filter(killResult.getKilledCards(), game, CardType.COMPANION).size() > 0 - && Filters.canSpot(game, Filters.inSkirmish, Culture.SAURON, Race.ORC)) { + && Filters.canSpot(game, Filters.inSkirmish, Culture.SAURON, Race.ORC) + && Filters.canSpot(game, Filters.ringBearer)) { ActivateCardAction action = new ActivateCardAction(self); action.appendCost( new RemoveThreatsEffect(self, 1)); diff --git a/gemp-lotr/gemp-lotr-cards/src/main/resources/set15-rarity.txt b/gemp-lotr/gemp-lotr-cards/src/main/resources/set15-rarity.txt index ab03c4097..a80bb6c47 100644 --- a/gemp-lotr/gemp-lotr-cards/src/main/resources/set15-rarity.txt +++ b/gemp-lotr/gemp-lotr-cards/src/main/resources/set15-rarity.txt @@ -186,8 +186,8 @@ 15U187 15S188 15S189 -15U190 -15U191 +15S190 +15S191 15U192 15R193 15S194 diff --git a/gemp-lotr/gemp-lotr-cards/src/main/resources/set17-rarity.txt b/gemp-lotr/gemp-lotr-cards/src/main/resources/set17-rarity.txt index 6163e142e..52c7091c1 100644 --- a/gemp-lotr/gemp-lotr-cards/src/main/resources/set17-rarity.txt +++ b/gemp-lotr/gemp-lotr-cards/src/main/resources/set17-rarity.txt @@ -44,7 +44,7 @@ 17R44 17R45 17C46 -17U47 +17C47 17S48 17R49 17U50 @@ -154,4 +154,4 @@ 17A154 17A155 17A156 -17A157 \ No newline at end of file +17A157 diff --git a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/effect/appender/CantBeOverwhelmedMultiplier.java b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/effect/appender/CantBeOverwhelmedMultiplier.java index bb036124c..3c9ad4dde 100644 --- a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/effect/appender/CantBeOverwhelmedMultiplier.java +++ b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/effect/appender/CantBeOverwhelmedMultiplier.java @@ -31,7 +31,7 @@ public class CantBeOverwhelmedMultiplier implements EffectAppenderProducer { MultiEffectAppender result = new MultiEffectAppender(); result.addEffectAppender( - CardResolver.resolveCards(filter, new ConstantEvaluator(1), "_temp", "you", "Choose characters that you want to make unable to be assigned to skirmish", environment)); + CardResolver.resolveCards(filter, new ConstantEvaluator(1), "_temp", "you", "Choose characters to apply overwhelm multiplier on", environment)); result.addEffectAppender( new DelayedAppender() { @Override diff --git a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/effect/appender/resolver/CardResolver.java b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/effect/appender/resolver/CardResolver.java index b4b0b1359..f6d520ad9 100644 --- a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/effect/appender/resolver/CardResolver.java +++ b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/effect/appender/resolver/CardResolver.java @@ -16,11 +16,13 @@ import com.gempukku.lotro.logic.effects.choose.ChooseCardsFromDiscardEffect; import com.gempukku.lotro.logic.effects.choose.ChooseCardsFromHandEffect; import com.gempukku.lotro.logic.effects.choose.ChooseStackedCardsEffect; import com.gempukku.lotro.logic.modifiers.evaluator.ConstantEvaluator; +import com.gempukku.lotro.logic.timing.AbstractEffect; import com.gempukku.lotro.logic.timing.Effect; import com.gempukku.lotro.logic.timing.PlayConditions; import com.gempukku.lotro.logic.timing.UnrespondableEffect; import java.util.Collection; +import java.util.Collections; import java.util.List; import java.util.function.Function; @@ -239,23 +241,44 @@ public class CardResolver { return new DelayedAppender() { @Override public boolean isPlayableInFull(ActionContext actionContext) { - final PhysicalCard attachedTo = actionContext.getSource().getAttachedTo(); - if (attachedTo == null) - return false; - if (playabilityFilter != null) - return PlayConditions.isActive(actionContext.getGame(), attachedTo, playabilityFilter.getFilterable(actionContext)); - return true; + int min = countSource.getMinimum(actionContext); + return filterCards(actionContext, playabilityFilter).size() >= min; } @Override protected Effect createEffect(boolean cost, CostToEffectAction action, ActionContext actionContext) { - return new UnrespondableEffect() { + Collection result = filterCards(actionContext, additionalFilter); + return new AbstractEffect() { @Override - protected void doPlayEffect(LotroGame game) { - actionContext.setCardMemory(memory, actionContext.getSource().getAttachedTo()); + public boolean isPlayableInFull(LotroGame game) { + int min = countSource.getMinimum(actionContext); + return result.size() >= min; + } + + @Override + protected FullEffectResult playEffectReturningResult(LotroGame game) { + actionContext.setCardMemory(memory, result); + int min = countSource.getMinimum(actionContext); + if (result.size() >= min) { + return new FullEffectResult(true); + } else { + return new FullEffectResult(false); + } } }; } + + private Collection filterCards(ActionContext actionContext, FilterableSource filter) { + PhysicalCard source = actionContext.getSource(); + PhysicalCard attachedTo = source.getAttachedTo(); + if (attachedTo == null) + return Collections.emptySet(); + + Filterable additionalFilterable = Filters.any; + if (filter != null) + additionalFilterable = filter.getFilterable(actionContext); + return Filters.filter(cardSource.apply(actionContext), actionContext.getGame(), attachedTo, additionalFilterable); + } }; } else if (type.startsWith("memory(") && type.endsWith(")")) { return resolveMemoryCards(type, additionalFilter, playabilityFilter, countSource, memory, cardSource); @@ -291,10 +314,22 @@ public class CardResolver { @Override protected Effect createEffect(boolean cost, CostToEffectAction action, ActionContext actionContext) { Collection result = filterCards(actionContext, choiceFilter); - return new UnrespondableEffect() { + return new AbstractEffect() { @Override - protected void doPlayEffect(LotroGame game) { + public boolean isPlayableInFull(LotroGame game) { + int min = countSource.getMinimum(actionContext); + return result.size() >= min; + } + + @Override + protected FullEffectResult playEffectReturningResult(LotroGame game) { actionContext.setCardMemory(memory, result); + int min = countSource.getMinimum(actionContext); + if (result.size() >= min) { + return new FullEffectResult(true); + } else { + return new FullEffectResult(false); + } } }; } @@ -330,10 +365,22 @@ public class CardResolver { @Override protected Effect createEffect(boolean cost, CostToEffectAction action, ActionContext actionContext) { Collection result = filterCards(actionContext, choiceFilter); - return new UnrespondableEffect() { + return new AbstractEffect() { @Override - protected void doPlayEffect(LotroGame game) { + public boolean isPlayableInFull(LotroGame game) { + int min = countSource.getMinimum(actionContext); + return result.size() >= min; + } + + @Override + protected FullEffectResult playEffectReturningResult(LotroGame game) { actionContext.setCardMemory(memory, result); + int min = countSource.getMinimum(actionContext); + if (result.size() >= min) { + return new FullEffectResult(true); + } else { + return new FullEffectResult(false); + } } }; } diff --git a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/effect/appender/resolver/ValueResolver.java b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/effect/appender/resolver/ValueResolver.java index 51463c02d..e23469223 100644 --- a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/effect/appender/resolver/ValueResolver.java +++ b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/effect/appender/resolver/ValueResolver.java @@ -248,7 +248,7 @@ public class ValueResolver { final int multiplier = FieldUtils.getInteger(object.get("multiplier"), "multiplier", 1); final FilterableSource filterableSource = environment.getFilterFactory().generateFilter(filter, environment); return actionContext -> - (Evaluator) (game, cardAffected) -> multiplier * Filters.filter(game.getGameState().getDeadPile(actionContext.getPerformingPlayer()), + (Evaluator) (game, cardAffected) -> multiplier * Filters.filter(game.getGameState().getDeadPile(game.getGameState().getCurrentPlayerId()), game, filterableSource.getFilterable(actionContext)).size(); } else if (type.equalsIgnoreCase("fromMemory")) { FieldUtils.validateAllowedFields(object, "memory", "multiplier", "limit"); diff --git a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/logic/effects/DiscardCardsFromPlayEffect.java b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/logic/effects/DiscardCardsFromPlayEffect.java index c6837ea9e..8d8b12d5a 100644 --- a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/logic/effects/DiscardCardsFromPlayEffect.java +++ b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/logic/effects/DiscardCardsFromPlayEffect.java @@ -33,7 +33,7 @@ public class DiscardCardsFromPlayEffect extends AbstractPreventableCardEffect { protected Filter getExtraAffectableFilter() { if (_source == null) return Filters.any; - return Filters.canBeDiscarded(_source); + return Filters.canBeDiscarded(_performingPlayer, _source); } public String getPerformingPlayer() { @@ -69,17 +69,13 @@ public class DiscardCardsFromPlayEffect extends AbstractPreventableCardEffect { discardedCards.addAll(cards); toMoveFromZoneToDiscard.addAll(cards); - String sourcePlayer = null; - if (_source != null) - sourcePlayer = _source.getOwner(); - - gameState.removeCardsFromZone(sourcePlayer, toMoveFromZoneToDiscard); + gameState.removeCardsFromZone(_performingPlayer, toMoveFromZoneToDiscard); for (PhysicalCard card : toMoveFromZoneToDiscard) gameState.addCardToZone(game, card, Zone.DISCARD); if (_source != null && discardedCards.size() > 0) - game.getGameState().sendMessage(_source.getOwner() + " discards " + getAppendedNames(discardedCards) + " from play using " + GameUtils.getCardLink(_source)); + game.getGameState().sendMessage(_performingPlayer + " discards " + getAppendedNames(discardedCards) + " from play using " + GameUtils.getCardLink(_source)); for (PhysicalCard discardedCard : discardedCards) game.getActionsEnvironment().emitEffectResult(new DiscardCardsFromPlayResult(_source, getPerformingPlayer(), discardedCard)); diff --git a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/game/ImportCards.java b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/game/ImportCards.java index 67d468fa9..df049f332 100644 --- a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/game/ImportCards.java +++ b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/game/ImportCards.java @@ -7,13 +7,12 @@ import java.util.*; public class ImportCards { //For a deck to be legal in a Pre-shadows format, it must contain one of these sites - private Set fellowshipSiteCheck = new HashSet<>(Arrays.asList("Council Courtyard", - "Ford of Bruinen", "Frodo's Bedroom", "Rivendell Terrace", "Rivendell Valley", "Rivendell Waterfall", - "House of Elrond")); - private Set towersSiteCheck = new HashSet<>(Arrays.asList("Derndingle", "Eastfold", - "Fangorn Forest", "Plains of Rohan Camp", "Rohirrim Village", "Uruk Camp", "Wold of Rohan")); - private Set kingSiteCheck = new HashSet<>(Arrays.asList("King's Tent", "Rohirrim Camp", - "West Road")); + private Set fellowshipSiteCheck = new HashSet<>(Arrays.asList("council courtyard", + "ford of bruinen", "frodo's bedroom", "rivendell terrace", "rivendell valley", "rivendell waterfall", + "house of elrond")); + private Set towersSiteCheck = new HashSet<>(Arrays.asList("derndingle", "eastfold", + "fangorn forest", "plains of rohan camp", "rohirrim village", "uruk camp", "wold of rohan")); + private Set kingSiteCheck = new HashSet<>(Arrays.asList("king's tent", "rohirrim camp", "west road")); public List process(String rawDecklist, LotroCardBlueprintLibrary cardLibrary) { List decklist = getDecklist(rawDecklist); diff --git a/gemp-lotr/gemp-lotr-server/src/test/java/com/gempukku/lotro/at/AbstractAtTest.java b/gemp-lotr/gemp-lotr-server/src/test/java/com/gempukku/lotro/at/AbstractAtTest.java index 3f3e6d318..1ebc341ea 100644 --- a/gemp-lotr/gemp-lotr-server/src/test/java/com/gempukku/lotro/at/AbstractAtTest.java +++ b/gemp-lotr/gemp-lotr-server/src/test/java/com/gempukku/lotro/at/AbstractAtTest.java @@ -1,5 +1,6 @@ package com.gempukku.lotro.at; +import com.gempukku.lotro.common.Zone; import com.gempukku.lotro.game.*; import com.gempukku.lotro.game.formats.LotroFormatLibrary; import com.gempukku.lotro.logic.actions.SystemQueueAction; @@ -137,6 +138,10 @@ public abstract class AbstractAtTest { decks.put(player, deck); } + protected void moveCardToZone(PhysicalCardImpl card, Zone zone) { + _game.getGameState().addCardToZone(_game, card, zone); + } + protected void playerDecided(String player, String answer) throws DecisionResultInvalidException { AwaitingDecision decision = _userFeedback.getAwaitingDecision(player); _userFeedback.participantDecided(player); diff --git a/gemp-lotr/gemp-lotr-server/src/test/java/com/gempukku/lotro/at/ExertAtTest.java b/gemp-lotr/gemp-lotr-server/src/test/java/com/gempukku/lotro/at/ExertAtTest.java new file mode 100644 index 000000000..ce420bb27 --- /dev/null +++ b/gemp-lotr/gemp-lotr-server/src/test/java/com/gempukku/lotro/at/ExertAtTest.java @@ -0,0 +1,61 @@ +package com.gempukku.lotro.at; + +import com.gempukku.lotro.common.Token; +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 org.junit.Test; + +import static org.junit.Assert.assertEquals; + +public class ExertAtTest extends AbstractAtTest{ + @Test + public void glorfindelCantExertWhenExhausted() throws CardNotFoundException, DecisionResultInvalidException { + initializeSimplestGame(); + + PhysicalCardImpl glorfindel = createCard(P1, "9_16"); + PhysicalCardImpl elvenBow = createCard(P1, "1_41"); + + PhysicalCardImpl cantea = createCard(P2, "1_230"); + + skipMulligans(); + + moveCardToZone(glorfindel, Zone.FREE_CHARACTERS); + moveCardToZone(cantea, Zone.SHADOW_CHARACTERS); + _game.getGameState().addTokens(glorfindel, Token.WOUND, 2); + _game.getGameState().putCardOnTopOfDeck(elvenBow); + + // End Fellowship phase + playerDecided(P1, ""); + // End Shadow phase + playerDecided(P2, ""); + + // End maneuver phase + playerDecided(P1, ""); + playerDecided(P2, ""); + + // End archery phase + playerDecided(P1, ""); + playerDecided(P2, ""); + + // End assignment phase + playerDecided(P1, ""); + playerDecided(P2, ""); + + // Assign + playerDecided(P1, glorfindel.getCardId() + " " + cantea.getCardId()); + // Start skirmish + playerDecided(P1, String.valueOf(glorfindel.getCardId())); + + // Use Glorfindel + playerDecided(P1, getCardActionId(P1, "Use Glorfindel")); + // Pass on viewing revealed card + playerDecided(P1, ""); + // Pass on viewing revealed card + playerDecided(P2, ""); + // Can't exert (already exhausted) + playerDecided(P1, "0"); + assertEquals(10, _game.getModifiersQuerying().getStrength(_game, cantea)); + } +}