Merge branch 'gemp-dev' into card-dev

This commit is contained in:
Christian 'ketura' McCarty
2021-02-24 21:59:57 -06:00
14 changed files with 169 additions and 49 deletions

View File

@@ -1438,7 +1438,7 @@
"modifier": {
"type": "cantBeAssignedToSkirmishAgainst",
"side": "free people",
"fpCharacter": "race(stored)",
"fpCharacter": "companion,race(stored)",
"minion": "self"
}
}

View File

@@ -715,7 +715,8 @@
"filter": "bearer"
},
"effect": {
"type": "removeTokens"
"type": "removeTokens",
"filter": "choose(any)"
}
},
{

Binary file not shown.

Before

Width:  |  Height:  |  Size: 59 KiB

After

Width:  |  Height:  |  Size: 59 KiB

View File

@@ -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 () {

View File

@@ -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));

View File

@@ -186,8 +186,8 @@
15U187
15S188
15S189
15U190
15U191
15S190
15S191
15U192
15R193
15S194

View File

@@ -44,7 +44,7 @@
17R44
17R45
17C46
17U47
17C47
17S48
17R49
17U50
@@ -154,4 +154,4 @@
17A154
17A155
17A156
17A157
17A157

View File

@@ -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

View File

@@ -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<PhysicalCard> 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<PhysicalCard> 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<PhysicalCard> 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<PhysicalCard> 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);
}
}
};
}

View File

@@ -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");

View File

@@ -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));

View File

@@ -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<String> fellowshipSiteCheck = new HashSet<>(Arrays.asList("Council Courtyard",
"Ford of Bruinen", "Frodo's Bedroom", "Rivendell Terrace", "Rivendell Valley", "Rivendell Waterfall",
"House of Elrond"));
private Set<String> towersSiteCheck = new HashSet<>(Arrays.asList("Derndingle", "Eastfold",
"Fangorn Forest", "Plains of Rohan Camp", "Rohirrim Village", "Uruk Camp", "Wold of Rohan"));
private Set<String> kingSiteCheck = new HashSet<>(Arrays.asList("King's Tent", "Rohirrim Camp",
"West Road"));
private Set<String> fellowshipSiteCheck = new HashSet<>(Arrays.asList("council courtyard",
"ford of bruinen", "frodo's bedroom", "rivendell terrace", "rivendell valley", "rivendell waterfall",
"house of elrond"));
private Set<String> towersSiteCheck = new HashSet<>(Arrays.asList("derndingle", "eastfold",
"fangorn forest", "plains of rohan camp", "rohirrim village", "uruk camp", "wold of rohan"));
private Set<String> kingSiteCheck = new HashSet<>(Arrays.asList("king's tent", "rohirrim camp", "west road"));
public List<CardCollection.Item> process(String rawDecklist, LotroCardBlueprintLibrary cardLibrary) {
List<CardCount> decklist = getDecklist(rawDecklist);

View File

@@ -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);

View File

@@ -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));
}
}