Added Item filter and DiscardFromDeck trigger

Added item filter (which is just possession + artifact)
Added trigger which keys off of cards being discarded from the deck.  Added the bulk of Deepest Delvings as a result.
This commit is contained in:
Christian 'ketura' McCarty
2021-09-22 03:15:49 -05:00
parent bf5204edfb
commit 35a8ca86b8
12 changed files with 128 additions and 82 deletions

View File

@@ -17,18 +17,18 @@
"type": "location",
"filter": "siteBlock(fellowship),or(siteNumber(4),siteNumber(5),siteNumber(6),siteNumber(7),siteNumber(8))"
},
"filter": "dwarf,hasAttachedCount(2,or(possession,artifact))"
"filter": "dwarf,hasAttachedCount(2,or(item))"
}
},
{
"type": "trigger",
"optional": true,
"trigger": {
"type": "moves",
"type": "moves"
},
"condition": {
"type": "canSpot",
"filter": "dwarf,hasAttachedCount(2,or(possession,artifact))"
"filter": "dwarf,hasAttachedCount(2,item)"
},
"effect": {
"type": "drawCards",
@@ -47,24 +47,22 @@
"support area"
],
"effects": [
{
"type": "extraCost",
"cost": {
"type": "exert",
"filter": "choose(dwarf)"
}
},
{
"type": "trigger",
"optional": true,
"trigger": {
"type": "played",
"filter": "orc",
"memorize": "playedOrc"
"type": "discardfromdeck",
"filter": "your,culture(dwarven)",
"memorize": "topcard"
},
"cost":{
"type": "addTwilight",
"amount": 2
},
"effect": {
"type": "discardTopCardsFromDeck",
"forced": true,
"deck": "ownerFromMemory(playedOrc)"
"type": "stackcardsfromdiscard",
"where": "self",
"filter": "memory(topcard)"
}
}
]

View File

@@ -37,6 +37,7 @@ public class FilterFactory {
simpleFilters.put("character", (actionContext) -> Filters.character);
simpleFilters.put("mounted", (actionContext) -> Filters.mounted);
simpleFilters.put("weapon", (actionContext) -> Filters.weapon);
simpleFilters.put("item", (actionContext) -> Filters.item);
simpleFilters.put("wounded", (actionContext) -> Filters.wounded);
simpleFilters.put("unwounded", (actionContext) -> Filters.unwounded);
simpleFilters.put("exhausted", (actionContext) -> Filters.exhausted);

View File

@@ -0,0 +1,36 @@
package com.gempukku.lotro.cards.build.field.effect.trigger;
import com.gempukku.lotro.cards.build.*;
import com.gempukku.lotro.cards.build.field.FieldUtils;
import com.gempukku.lotro.logic.timing.TriggerConditions;
import com.gempukku.lotro.logic.timing.results.DiscardCardFromDeckResult;
import org.json.simple.JSONObject;
public class DiscardFromDeck implements TriggerCheckerProducer {
@Override
public TriggerChecker getTriggerChecker(JSONObject value, CardGenerationEnvironment environment) throws InvalidCardDefinitionException {
FieldUtils.validateAllowedFields(value, "filter", "memorize");
final String filter = FieldUtils.getString(value.get("filter"), "filter", "any");
final String memorize = FieldUtils.getString(value.get("memorize"), "memorize");
final FilterableSource filterableSource = environment.getFilterFactory().generateFilter(filter, environment);
return new TriggerChecker() {
@Override
public boolean isBefore() {
return false;
}
@Override
public boolean accepts(ActionContext actionContext) {
boolean result = TriggerConditions.forEachDiscardedFromDeck(actionContext.getGame(), actionContext.getEffectResult(),
filterableSource.getFilterable(actionContext));
if (result && memorize != null) {
actionContext.setCardMemory(memorize, ((DiscardCardFromDeckResult) actionContext.getEffectResult()).getDiscardedCard());
}
return result;
}
};
}
}

View File

@@ -37,6 +37,7 @@ public class TriggerCheckerFactory {
triggerCheckers.put("exerts", new Exerts());
triggerCheckers.put("discarded", new Discarded());
triggerCheckers.put("discardfromhand", new DiscardFromHand());
triggerCheckers.put("discardfromdeck", new DiscardFromDeck());
triggerCheckers.put("putsonring", new PutsOnRing());
triggerCheckers.put("addsburden", new AddsBurden());
triggerCheckers.put("removesburden", new RemovesBurden());

View File

@@ -410,6 +410,7 @@ public class Filters {
public static final Filter galadriel = Filters.name("Galadriel");
public static final Filter weapon = Filters.or(PossessionClass.HAND_WEAPON, PossessionClass.RANGED_WEAPON);
public static final Filter item = Filters.or(CardType.ARTIFACT, CardType.POSSESSION);
public static final Filter character = Filters.or(CardType.ALLY, CardType.COMPANION, CardType.MINION);
public static final Filter ringBearer = new Filter() {

View File

@@ -6,6 +6,8 @@ import com.gempukku.lotro.game.state.GameState;
import com.gempukku.lotro.game.state.LotroGame;
import com.gempukku.lotro.logic.timing.AbstractEffect;
import com.gempukku.lotro.logic.timing.Effect;
import com.gempukku.lotro.logic.timing.results.DiscardCardFromDeckResult;
import com.gempukku.lotro.logic.timing.results.DiscardCardFromPlayResult;
import java.util.Collection;
import java.util.LinkedList;
@@ -61,6 +63,9 @@ public class DiscardTopCardFromDeckEffect extends AbstractEffect {
cardsDiscardedCallback(cardsDiscarded);
}
for (PhysicalCard discardedCard : cardsDiscarded)//PhysicalCard source, PhysicalCard card, String handPlayerId, boolean forced
game.getActionsEnvironment().emitEffectResult(new DiscardCardFromDeckResult(_source, discardedCard, _forced));
return new FullEffectResult(_count == cardsDiscarded.size());
}
return new FullEffectResult(false);

View File

@@ -15,6 +15,7 @@ public abstract class EffectResult {
FOR_EACH_RETURNED_TO_HAND,
FOR_EACH_DISCARDED_FROM_HAND,
FOR_EACH_DISCARDED_FROM_DECK,
FREE_PEOPLE_PLAYER_STARTS_ASSIGNING,
SKIRMISH_ABOUT_TO_END,

View File

@@ -197,6 +197,12 @@ public class TriggerConditions {
return false;
}
public static boolean forEachDiscardedFromDeck(LotroGame game, EffectResult effectResult, Filterable... filters) {
if (effectResult.getType() == EffectResult.Type.FOR_EACH_DISCARDED_FROM_DECK)
return Filters.and(filters).accepts(game, ((DiscardCardFromDeckResult) effectResult).getDiscardedCard());
return false;
}
public static boolean forEachWounded(LotroGame game, EffectResult effectResult, Filterable... filters) {
if (effectResult.getType() == EffectResult.Type.FOR_EACH_WOUNDED)
return Filters.and(filters).accepts(game, ((WoundResult) effectResult).getWoundedCard());

View File

@@ -0,0 +1,30 @@
package com.gempukku.lotro.logic.timing.results;
import com.gempukku.lotro.game.PhysicalCard;
import com.gempukku.lotro.logic.timing.EffectResult;
public class DiscardCardFromDeckResult extends EffectResult {
private PhysicalCard _source;
private PhysicalCard _card;
private boolean _forced;
public DiscardCardFromDeckResult(PhysicalCard source, PhysicalCard card, boolean forced) {
super(Type.FOR_EACH_DISCARDED_FROM_DECK);
_source = source;
_card = card;
_forced = forced;
}
public PhysicalCard getSource() {
return _source;
}
public boolean isForced() {
return _forced;
}
public PhysicalCard getDiscardedCard() {
return _card;
}
}

View File

@@ -238,6 +238,9 @@ public class GenericCardTestHelper extends AbstractAtTest {
public void AttachCard(PhysicalCardImpl card, PhysicalCardImpl bearer) { _game.getGameState().attachCard(_game, card, bearer); }
public void AttachCardsTo(PhysicalCardImpl holder, PhysicalCardImpl...cards) {
Arrays.stream(cards).forEach(card -> _game.getGameState().attachCard(_game, card, holder));
}
public void FreepsMoveCardToDeck(String...cardNames) {
Arrays.stream(cardNames).forEach(cardName -> FreepsMoveCardToDeck(GetFreepsCard(cardName)));
@@ -270,15 +273,17 @@ public class GenericCardTestHelper extends AbstractAtTest {
Arrays.stream(cards).forEach(card -> MoveCardToZone(P1, card, Zone.SUPPORT));
}
public void FreepsMoveCardToDiscard(String cardName) { FreepsMoveCardToSupportArea(GetFreepsCard(cardName)); }
public void FreepsMoveCardToDiscard(String cardName) { FreepsMoveCardToDiscard(GetFreepsCard(cardName)); }
public void FreepsMoveCardToDiscard(PhysicalCardImpl...cards) {
Arrays.stream(cards).forEach(card -> MoveCardToZone(P1, card, Zone.DISCARD));
}
public void ShadowMoveCardToDiscard(String cardName) { ShadowMoveCardToSupportArea(GetShadowCard(cardName)); }
public void ShadowMoveCardToDiscard(String cardName) { ShadowMoveCardToDiscard(GetShadowCard(cardName)); }
public void ShadowMoveCardToDiscard(PhysicalCardImpl...cards) {
Arrays.stream(cards).forEach(card -> MoveCardToZone(P1, card, Zone.DISCARD));
}
public void MoveCardToZone(String player, PhysicalCardImpl card, Zone zone) {
if(card.getZone() != null)
{
@@ -428,6 +433,7 @@ public class GenericCardTestHelper extends AbstractAtTest {
public void FreepsChoose(String choice) throws DecisionResultInvalidException { playerDecided(P1, choice); }
public void ShadowChoose(String choice) throws DecisionResultInvalidException { playerDecided(P2, choice); }
public void FreepsChooseToMove() throws DecisionResultInvalidException { playerDecided(P1, "0"); }
public void FreepsChooseToStay() throws DecisionResultInvalidException { playerDecided(P1, "1"); }

View File

@@ -41,7 +41,7 @@ public class Card_V1_001Tests
/**
* Set: VSet1, VPack1
* Title: Hospitality of the Dwarves
* Title: *Hospitality of the Dwarves
* Side: Free Peoples
* Culture: Dwarven
* Twilight Cost: 1

View File

@@ -20,12 +20,15 @@ public class Card_V1_002Tests
return new GenericCardTestHelper(
new HashMap<String, String>()
{{
put("aragorn", "1_89");
put("boromir", "1_97");
put("whitecity", "101_2");
put("gimli", "1_13");
put("axe", "1_9");
put("axe2", "1_9");
put("deep", "151_2");
put("beneath", "2_1");
put("runner", "1_178");
put("plunder", "1_193");
put("attea", "1_229");
put("cantea", "1_230");
}}
);
}
@@ -36,14 +39,14 @@ public class Card_V1_002Tests
/**
* Set: VSet1, VPack1
* Title: *I Will Not Let the White City Fall
* Title: *Deepest Delvings
* Side: Free Peoples
* Culture: Gondor
* Twilight Cost: 2
* Culture: Dwarven
* Twilight Cost: 1
* Type: Condition
* Subtype: Support Area
* Game Text: Each time Boromir loses a skirmish, make Aragorn strength +2 until the regroup phase.
* Each time Aragorn loses a skirmish, make Boromir strength +2 until the regroup phase.
* Game Text: Each time you discard a [dwarven] card from the top of your deck you may add (1) to stack that card here.
* Maneuver: Exert a dwarf to take a card stacked here into hand.
*/
//Pre-game setup
@@ -57,68 +60,26 @@ public class Card_V1_002Tests
}
@Test
public void OneIsBuffedWhenOtherLosesSkirmish() throws DecisionResultInvalidException, CardNotFoundException {
public void topdecktest() throws DecisionResultInvalidException, CardNotFoundException {
//Pre-game setup
GenericCardTestHelper scn = GetScenario();
PhysicalCardImpl aragorn = scn.GetFreepsCard("aragorn");
PhysicalCardImpl boromir = scn.GetFreepsCard("boromir");
PhysicalCardImpl whitecity = scn.GetFreepsCard("whitecity");
scn.FreepsMoveCharToTable(aragorn);
scn.FreepsMoveCharToTable(boromir);
scn.FreepsMoveCardToHand(whitecity);
PhysicalCardImpl cantea = scn.GetShadowCard("cantea");
PhysicalCardImpl attea = scn.GetShadowCard("attea");
scn.ShadowMoveCharToTable(cantea, attea);
PhysicalCardImpl beneath = scn.GetFreepsCard("beneath");
PhysicalCardImpl deep = scn.GetFreepsCard("deep");
scn.FreepsMoveCardToSupportArea(beneath);
scn.FreepsMoveCardToSupportArea(deep);
scn.FreepsMoveCharToTable("gimli");
scn.FreepsMoveCardToDiscard("axe");
scn.StartGame();
scn.FreepsPlayCard(whitecity);
scn.FreepsUseCardAction(beneath);
scn.SkipToPhase(Phase.ASSIGNMENT);
assertEquals(7, scn.GetStrength(boromir));
assertEquals(8, scn.GetStrength(aragorn));
scn.SkipCurrentPhaseActions();
//Standard assignment
scn.FreepsAssignToMinions(new PhysicalCardImpl[] { aragorn, cantea}, new PhysicalCardImpl[] { boromir, attea});
scn.FreepsResolveSkirmish(aragorn);
scn.SkipCurrentPhaseActions();
scn.FreepsAcceptOptionalTrigger(); //Have to resolve the skirmish and the condition trigger
// 14 > 8, Aragorn lost, Boromir should be buffed
assertEquals(9, scn.GetStrength(boromir));
assertEquals(8, scn.GetStrength(aragorn));
scn.FreepsResolveSkirmish(boromir);
scn.SkipCurrentPhaseActions();
scn.FreepsAcceptOptionalTrigger(); //Have to resolve the skirmish and the condition trigger
// 12 > 9, Boromir lost, Aragorn should be buffed
assertEquals(9, scn.GetStrength(boromir));
assertEquals(10, scn.GetStrength(aragorn));
//Fierce assignment
scn.FreepsSkipCurrentPhaseAction();
scn.ShadowSkipCurrentPhaseAction();
scn.FreepsAssignToMinions(new PhysicalCardImpl[] { aragorn, cantea}, new PhysicalCardImpl[] { boromir, attea});
scn.FreepsResolveSkirmish(boromir);
scn.SkipCurrentPhaseActions();
scn.FreepsAcceptOptionalTrigger(); //Have to resolve the skirmish and the condition trigger
// 10 > 9, Boromir lost again, Aragorn should be buffed again
assertEquals(9, scn.GetStrength(boromir));
assertEquals(12, scn.GetStrength(aragorn));
scn.FreepsResolveSkirmish(aragorn);
//Aragorn now wins his skirmish, so there's no loss trigger to evaluate
scn.SkipToPhase(Phase.REGROUP);
//strength should be back to normal
assertEquals(7, scn.GetStrength(boromir));
assertEquals(8, scn.GetStrength(aragorn));
}