Fixed issues with discard from top of deck or hand

This commit is contained in:
marcin.sciesinski
2019-08-28 15:28:46 -07:00
parent cec066cb14
commit bafb2ccfdb
7 changed files with 75 additions and 20 deletions

View File

@@ -32,7 +32,8 @@
},
"effect": {
"type": "discardTopCardFromDeck",
"deck": "owner(skirmishLoser)"
"deck": "owner(skirmishLoser)",
"forced": true
}
}
},

View File

@@ -50,7 +50,8 @@
"filter": "choose(hasAttached(self))"
},
{
"type": "discardCardAtRandomFromHand"
"type": "discardCardAtRandomFromHand",
"forced": false
}
]
},

View File

@@ -44,6 +44,14 @@ public class FieldUtils {
return (String) value;
}
public static boolean getBoolean(Object value, String key) throws InvalidCardDefinitionException {
if (value == null)
throw new InvalidCardDefinitionException("Value of " + key + " is required");
if (!(value instanceof Boolean))
throw new InvalidCardDefinitionException("Unknown type in " + key + " field");
return (Boolean) value;
}
public static boolean getBoolean(Object value, String key, boolean defaultValue) throws InvalidCardDefinitionException {
if (value == null)
return defaultValue;

View File

@@ -17,24 +17,31 @@ import org.json.simple.JSONObject;
public class DiscardCardAtRandomFromHand implements EffectAppenderProducer {
@Override
public EffectAppender createEffectAppender(JSONObject effectObject, CardGenerationEnvironment environment) throws InvalidCardDefinitionException {
FieldUtils.validateAllowedFields(effectObject);
FieldUtils.validateAllowedFields(effectObject, "forced");
final boolean forced = FieldUtils.getBoolean(effectObject.get("forced"), "forced");
return new DelayedAppender() {
@Override
protected Effect createEffect(CostToEffectAction action, String playerId, LotroGame game, PhysicalCard self, EffectResult effectResult, Effect effect) {
return new DiscardCardAtRandomFromHandEffect(self, self.getOwner(), false);
return new DiscardCardAtRandomFromHandEffect(self, self.getOwner(), forced);
}
@Override
public boolean isPlayableInFull(String playerId, LotroGame game, PhysicalCard self, EffectResult effectResult, Effect effect) {
return game.getGameState().getHand(self.getOwner()).size() >= 1;
return game.getGameState().getHand(self.getOwner()).size() >= 1
&& (!forced || game.getModifiersQuerying().canDiscardCardsFromHand(game, playerId, self));
}
};
}
@Override
public Requirement createCostRequirement(JSONObject effectObject, CardGenerationEnvironment environment) throws InvalidCardDefinitionException {
FieldUtils.validateAllowedFields(effectObject);
return (playerId, game, self, effectResult, effect) -> game.getGameState().getHand(self.getOwner()).size() >= 1;
FieldUtils.validateAllowedFields(effectObject, "forced");
final boolean forced = FieldUtils.getBoolean(effectObject.get("forced"), "forced");
return (playerId, game, self, effectResult, effect) -> game.getGameState().getHand(self.getOwner()).size() >= 1
&& (!forced || game.getModifiersQuerying().canDiscardCardsFromHand(game, playerId, self));
}
}

View File

@@ -19,10 +19,11 @@ import org.json.simple.JSONObject;
public class DiscardTopCardFromDeck implements EffectAppenderProducer {
@Override
public EffectAppender createEffectAppender(JSONObject effectObject, CardGenerationEnvironment environment) throws InvalidCardDefinitionException {
FieldUtils.validateAllowedFields(effectObject, "deck", "count");
FieldUtils.validateAllowedFields(effectObject, "deck", "count", "forced");
final String deck = FieldUtils.getString(effectObject.get("deck"), "deck", "owner");
final int count = FieldUtils.getInteger(effectObject.get("count"), "count", 1);
final boolean forced = FieldUtils.getBoolean(effectObject.get("forced"), "forced");
final PlayerSource playerSource = PlayerResolver.resolvePlayer(deck, environment);
@@ -34,15 +35,16 @@ public class DiscardTopCardFromDeck implements EffectAppenderProducer {
public boolean isPlayableInFull(String playerId, LotroGame game, PhysicalCard self, EffectResult effectResult, Effect effect) {
final String deckId = playerSource.getPlayer(playerId, game, self, effectResult, effect);
// Don't check if can discard top cards, since it's a cost
return game.getGameState().getDeck(deckId).size() >= count
&& game.getModifiersQuerying().canDiscardCardsFromTopOfDeck(game, deckId, self);
&& (!forced || game.getModifiersQuerying().canDiscardCardsFromTopOfDeck(game, playerId, self));
}
@Override
protected Effect createEffect(CostToEffectAction action, String playerId, LotroGame game, PhysicalCard self, EffectResult effectResult, Effect effect) {
final String deckId = playerSource.getPlayer(playerId, game, self, effectResult, effect);
return new DiscardTopCardFromDeckEffect(self, deckId, count, true);
return new DiscardTopCardFromDeckEffect(self, deckId, count, forced);
}
});
@@ -51,17 +53,19 @@ public class DiscardTopCardFromDeck implements EffectAppenderProducer {
@Override
public Requirement createCostRequirement(JSONObject effectObject, CardGenerationEnvironment environment) throws InvalidCardDefinitionException {
FieldUtils.validateAllowedFields(effectObject, "deck", "count");
FieldUtils.validateAllowedFields(effectObject, "deck", "count", "forced");
final String deck = FieldUtils.getString(effectObject.get("deck"), "deck", "owner");
final int count = FieldUtils.getInteger(effectObject.get("count"), "count", 1);
final boolean forced = FieldUtils.getBoolean(effectObject.get("forced"), "forced");
final PlayerSource playerSource = PlayerResolver.resolvePlayer(deck, environment);
// Don't check if can discard top cards, since it's a cost
return (playerId, game, self, effectResult, effect) -> {
final String deckId = playerSource.getPlayer(playerId, game, self, effectResult, effect);
return game.getGameState().getDeck(deckId).size() >= count
&& game.getModifiersQuerying().canDiscardCardsFromTopOfDeck(game, deckId, self);
&& (!forced || game.getModifiersQuerying().canDiscardCardsFromTopOfDeck(game, playerId, self));
};
}
}

View File

@@ -1,34 +1,29 @@
package com.gempukku.lotro.logic.modifiers;
import com.gempukku.lotro.common.Filterable;
import com.gempukku.lotro.filters.Filter;
import com.gempukku.lotro.filters.Filters;
import com.gempukku.lotro.game.PhysicalCard;
import com.gempukku.lotro.game.state.LotroGame;
public class CantDiscardCardsFromHandOrTopOfDeckModifier extends AbstractModifier {
private Filter _discardSourceAffected;
private String _playerId;
public CantDiscardCardsFromHandOrTopOfDeckModifier(PhysicalCard source, Condition condition, String playerId, Filterable... discardSourceAffected) {
super(source, null, null, condition, ModifierEffect.DISCARD_NOT_FROM_PLAY);
super(source, null, Filters.and(discardSourceAffected), condition, ModifierEffect.DISCARD_NOT_FROM_PLAY);
_playerId = playerId;
_discardSourceAffected = Filters.and(discardSourceAffected);
}
@Override
public boolean canDiscardCardsFromHand(LotroGame game, String playerId, PhysicalCard source) {
if (playerId.equals(_playerId))
if (source == null || _discardSourceAffected.accepts(game, source))
return false;
return false;
return true;
}
@Override
public boolean canDiscardCardsFromTopOfDeck(LotroGame game, String playerId, PhysicalCard source) {
if (playerId.equals(_playerId))
if (source == null || _discardSourceAffected.accepts(game, source))
return false;
return false;
return true;
}
}

View File

@@ -1246,4 +1246,43 @@ public class IndividualCardAtTest extends AbstractAtTest {
assertTrue(_userFeedback.getAwaitingDecision(P1).getText().startsWith("Do you wish to mulligan"));
}
@Test
public void courteousFrodoPreventsDiscard() throws DecisionResultInvalidException, CardNotFoundException {
Map<String, LotroDeck> decks = new HashMap<String, LotroDeck>();
final LotroDeck p1Deck = createSimplestDeck();
p1Deck.setRingBearer("4_301");
decks.put(P1, p1Deck);
decks.put(P2, createSimplestDeck());
initializeGameWithDecks(decks);
PhysicalCardImpl arwen = new PhysicalCardImpl(100, "7_16", P1, _library.getLotroCardBlueprint("7_16"));
PhysicalCardImpl legolas = new PhysicalCardImpl(100, "1_50", P1, _library.getLotroCardBlueprint("1_50"));
PhysicalCardImpl aragorn = new PhysicalCardImpl(100, "1_89", P1, _library.getLotroCardBlueprint("1_89"));
PhysicalCardImpl cardInHand = new PhysicalCardImpl(100, "1_268", P1, _library.getLotroCardBlueprint("1_268"));
PhysicalCardImpl inquisitor = new PhysicalCardImpl(100, "1_268", P2, _library.getLotroCardBlueprint("1_268"));
_game.getGameState().addCardToZone(_game, arwen, Zone.FREE_CHARACTERS);
_game.getGameState().addCardToZone(_game, legolas, Zone.FREE_CHARACTERS);
_game.getGameState().addCardToZone(_game, aragorn, Zone.FREE_CHARACTERS);
_game.getGameState().addCardToZone(_game, inquisitor, Zone.HAND);
_game.getGameState().addCardToZone(_game, cardInHand, Zone.HAND);
skipMulligans();
// Pass in fellowship
playerDecided(P1, "");
// Play inquisitor
playerDecided(P2, "0");
// Use inquisitor
playerDecided(P2, "0");
assertEquals(Zone.HAND, cardInHand.getZone());
}
}