diff --git a/gemp-lotr/gemp-lotr-cards/src/main/java/com/gempukku/lotro/cards/AbstractAlly.java b/gemp-lotr/gemp-lotr-cards/src/main/java/com/gempukku/lotro/cards/AbstractAlly.java index 6db153864..362a36e4a 100644 --- a/gemp-lotr/gemp-lotr-cards/src/main/java/com/gempukku/lotro/cards/AbstractAlly.java +++ b/gemp-lotr/gemp-lotr-cards/src/main/java/com/gempukku/lotro/cards/AbstractAlly.java @@ -14,7 +14,7 @@ import java.util.List; public class AbstractAlly extends AbstractPermanent { private Block _siteBlock; - private int _siteNumber; + private int[] _siteNumbers; private int _strength; private int _vitality; private Race _race; @@ -24,9 +24,17 @@ public class AbstractAlly extends AbstractPermanent { } public AbstractAlly(int twilight, Block siteBlock, int siteNumber, int strength, int vitality, Race race, Culture culture, String name, boolean unique) { + this(twilight, siteBlock, new int[]{siteNumber}, strength, vitality, race, culture, name, unique); + } + + public AbstractAlly(int twilight, Block siteBlock, int[] siteNumbers, int strength, int vitality, Race race, Culture culture, String name) { + this(twilight, siteBlock, siteNumbers, strength, vitality, race, culture, name, false); + } + + public AbstractAlly(int twilight, Block siteBlock, int[] siteNumbers, int strength, int vitality, Race race, Culture culture, String name, boolean unique) { super(Side.FREE_PEOPLE, twilight, CardType.ALLY, culture, Zone.SUPPORT, name, unique); _siteBlock = siteBlock; - _siteNumber = siteNumber; + _siteNumbers = siteNumbers; _strength = strength; _vitality = vitality; _race = race; @@ -55,13 +63,13 @@ public class AbstractAlly extends AbstractPermanent { } @Override - public Block getSiteBlock() { - return _siteBlock; - } - - @Override - public final int getSiteNumber() { - return _siteNumber; + public final boolean isAllyAtHome(int siteNumber, Block block) { + if (block != _siteBlock) + return false; + for (int number : _siteNumbers) + if (number == siteNumber) + return true; + return false; } @Override diff --git a/gemp-lotr/gemp-lotr-cards/src/main/java/com/gempukku/lotro/cards/AbstractAttachableFPPossession.java b/gemp-lotr/gemp-lotr-cards/src/main/java/com/gempukku/lotro/cards/AbstractAttachableFPPossession.java index bce45f6b2..f43486f6f 100644 --- a/gemp-lotr/gemp-lotr-cards/src/main/java/com/gempukku/lotro/cards/AbstractAttachableFPPossession.java +++ b/gemp-lotr/gemp-lotr-cards/src/main/java/com/gempukku/lotro/cards/AbstractAttachableFPPossession.java @@ -48,16 +48,15 @@ public abstract class AbstractAttachableFPPossession extends AbstractAttachable validTransferFilter = Filters.and(validTargetFilter, Filters.or( Filters.type(CardType.COMPANION), - Filters.allyOnHomeSite())); - } else if (attachedTo.getSiteNumber() == gameState.getCurrentSiteNumber() - && attachedTo.getSiteBlock() == gameState.getCurrentSite().getBlueprint().getSiteBlock()) { + Filters.isAllyAtHome())); + } else if (attachedTo.isAllyAtHome(gameState.getCurrentSiteNumber(), gameState.getCurrentSite().getBlueprint().getSiteBlock())) { validTransferFilter = Filters.and(validTargetFilter, Filters.or( Filters.type(CardType.COMPANION), - Filters.allyOnHomeSite())); + Filters.isAllyAtHome())); } else { validTransferFilter = Filters.and(validTargetFilter, - Filters.type(CardType.ALLY), Filters.siteNumber(attachedTo.getSiteNumber()), Filters.siteBlock(attachedTo.getSiteBlock()) + Filters.type(CardType.ALLY), Filters.isAllyAtHome() ); } diff --git a/gemp-lotr/gemp-lotr-cards/src/main/java/com/gempukku/lotro/cards/AbstractLotroCardBlueprint.java b/gemp-lotr/gemp-lotr-cards/src/main/java/com/gempukku/lotro/cards/AbstractLotroCardBlueprint.java index 84636f6b8..5ae8ed4f7 100644 --- a/gemp-lotr/gemp-lotr-cards/src/main/java/com/gempukku/lotro/cards/AbstractLotroCardBlueprint.java +++ b/gemp-lotr/gemp-lotr-cards/src/main/java/com/gempukku/lotro/cards/AbstractLotroCardBlueprint.java @@ -115,6 +115,11 @@ public abstract class AbstractLotroCardBlueprint implements LotroCardBlueprint { throw new UnsupportedOperationException("This method should not be called on this card"); } + @Override + public boolean isAllyAtHome(int siteNumber, Block siteBlock) { + throw new UnsupportedOperationException("This method should not be called on this card"); + } + @Override public Block getSiteBlock() { throw new UnsupportedOperationException("This method should not be called on this card"); diff --git a/gemp-lotr/gemp-lotr-cards/src/main/java/com/gempukku/lotro/cards/modifiers/AllyParticipatesInArcheryFireAndSkirmishesModifier.java b/gemp-lotr/gemp-lotr-cards/src/main/java/com/gempukku/lotro/cards/modifiers/AllyParticipatesInArcheryFireAndSkirmishesModifier.java index 4bc6b2607..f84da3030 100644 --- a/gemp-lotr/gemp-lotr-cards/src/main/java/com/gempukku/lotro/cards/modifiers/AllyParticipatesInArcheryFireAndSkirmishesModifier.java +++ b/gemp-lotr/gemp-lotr-cards/src/main/java/com/gempukku/lotro/cards/modifiers/AllyParticipatesInArcheryFireAndSkirmishesModifier.java @@ -1,5 +1,8 @@ package com.gempukku.lotro.cards.modifiers; +import com.gempukku.lotro.common.Culture; +import com.gempukku.lotro.common.Keyword; +import com.gempukku.lotro.common.Side; import com.gempukku.lotro.filters.Filter; import com.gempukku.lotro.game.PhysicalCard; import com.gempukku.lotro.game.state.GameState; @@ -8,8 +11,11 @@ import com.gempukku.lotro.logic.modifiers.ModifierEffect; import com.gempukku.lotro.logic.modifiers.ModifiersQuerying; public class AllyParticipatesInArcheryFireAndSkirmishesModifier extends AbstractModifier { + private PhysicalCard _source; + public AllyParticipatesInArcheryFireAndSkirmishesModifier(PhysicalCard source, Filter affectFilter) { super(source, "Can participate in archery and skirmishes", affectFilter, new ModifierEffect[]{ModifierEffect.PRESENCE_MODIFIER}); + _source = source; } @Override @@ -18,7 +24,9 @@ public class AllyParticipatesInArcheryFireAndSkirmishesModifier extends Abstract } @Override - public boolean isAllyParticipateInSkirmishes(GameState gameState, ModifiersQuerying modifiersQuerying, PhysicalCard card) { - return true; + public boolean isAllyParticipateInSkirmishes(GameState gameState, Side sidePlayer, ModifiersQuerying modifiersQuerying, PhysicalCard card) { + boolean unhasty = modifiersQuerying.hasKeyword(gameState, card, Keyword.UNHASTY); + return sidePlayer == Side.SHADOW + || !unhasty || _source.getBlueprint().getCulture() == Culture.GANDALF; } } diff --git a/gemp-lotr/gemp-lotr-cards/src/main/java/com/gempukku/lotro/cards/modifiers/spotting/SimpleLotroCardBlueprint.java b/gemp-lotr/gemp-lotr-cards/src/main/java/com/gempukku/lotro/cards/modifiers/spotting/SimpleLotroCardBlueprint.java index 4d5f50583..5c581589a 100644 --- a/gemp-lotr/gemp-lotr-cards/src/main/java/com/gempukku/lotro/cards/modifiers/spotting/SimpleLotroCardBlueprint.java +++ b/gemp-lotr/gemp-lotr-cards/src/main/java/com/gempukku/lotro/cards/modifiers/spotting/SimpleLotroCardBlueprint.java @@ -44,6 +44,11 @@ public class SimpleLotroCardBlueprint implements LotroCardBlueprint { return null; } + @Override + public boolean isAllyAtHome(int siteNumber, Block siteBlock) { + return false; + } + @Override public List getOptionalAfterActions(String playerId, LotroGame game, EffectResult effectResult, PhysicalCard self) { return null; diff --git a/gemp-lotr/gemp-lotr-cards/src/main/java/com/gempukku/lotro/cards/set4/gandalf/Card4_103.java b/gemp-lotr/gemp-lotr-cards/src/main/java/com/gempukku/lotro/cards/set4/gandalf/Card4_103.java new file mode 100644 index 000000000..dfb267c8a --- /dev/null +++ b/gemp-lotr/gemp-lotr-cards/src/main/java/com/gempukku/lotro/cards/set4/gandalf/Card4_103.java @@ -0,0 +1,88 @@ +package com.gempukku.lotro.cards.set4.gandalf; + +import com.gempukku.lotro.cards.AbstractAlly; +import com.gempukku.lotro.cards.PlayConditions; +import com.gempukku.lotro.cards.effects.AddTwilightEffect; +import com.gempukku.lotro.cards.effects.ChooseArbitraryCardsEffect; +import com.gempukku.lotro.cards.effects.ExertCharactersEffect; +import com.gempukku.lotro.cards.effects.StackCardFromPlayEffect; +import com.gempukku.lotro.common.*; +import com.gempukku.lotro.filters.Filters; +import com.gempukku.lotro.game.PhysicalCard; +import com.gempukku.lotro.game.state.LotroGame; +import com.gempukku.lotro.logic.actions.ActivateCardAction; +import com.gempukku.lotro.logic.effects.ChooseActiveCardEffect; +import com.gempukku.lotro.logic.effects.DiscardCardsFromPlayEffect; +import com.gempukku.lotro.logic.timing.Action; +import com.gempukku.lotro.logic.timing.Effect; +import com.gempukku.lotro.logic.timing.EffectResult; + +import java.util.Collection; +import java.util.Collections; +import java.util.List; + +/** + * Set: The Two Towers + * Side: Free + * Culture: Gandalf + * Twilight Cost: 4 + * Type: Ally • Home 2T & 8T • Ent + * Strength: 12 + * Vitality: 4 + * Site: 2T, 8T + * Game Text: Unhasty. Response: If an unbound Hobbit is about to be discarded, stack him here instead. + * Fellowship: Exert Treebeard and add(1) to play an unbound Hobbit stacked here. + */ +public class Card4_103 extends AbstractAlly { + public Card4_103() { + super(4, Block.TWO_TOWERS, new int[]{2, 8}, 12, 4, Race.ENT, Culture.GANDALF, "Treebeard", true); + addKeyword(Keyword.UNHASTY); + } + + @Override + public List getOptionalBeforeActions(String playerId, LotroGame game, Effect effect, final PhysicalCard self) { + if (effect.getType() == EffectResult.Type.DISCARD_FROM_PLAY + && PlayConditions.canUseFPCardDuringPhase(game.getGameState(), null, self)) { + DiscardCardsFromPlayEffect discardEffect = (DiscardCardsFromPlayEffect) effect; + Collection discardedHobbits = Filters.filter(discardEffect.getAffectedCardsMinusPrevented(game), game.getGameState(), game.getModifiersQuerying(), Filters.unboundCompanion(), Filters.race(Race.HOBBIT)); + if (discardedHobbits.size() > 0) { + final ActivateCardAction action = new ActivateCardAction(self, Keyword.RESPONSE); + action.appendEffect( + new ChooseActiveCardEffect(self, playerId, "Choose unbound hobbit", Filters.in(discardedHobbits)) { + @Override + protected void cardSelected(PhysicalCard card) { + action.insertEffect( + new StackCardFromPlayEffect(card, self)); + } + }); + return Collections.singletonList(action); + } + } + return null; + } + + @Override + protected List getExtraInPlayPhaseActions(final String playerId, LotroGame game, PhysicalCard self) { + if (PlayConditions.canUseFPCardDuringPhase(game.getGameState(), Phase.FELLOWSHIP, self) + && PlayConditions.canExert(self, game.getGameState(), game.getModifiersQuerying(), self) + && Filters.filter(game.getGameState().getStackedCards(self), game.getGameState(), game.getModifiersQuerying(), Filters.unboundCompanion(), Filters.race(Race.HOBBIT), Filters.playable(game)).size() > 0) { + ActivateCardAction action = new ActivateCardAction(self, Keyword.FELLOWSHIP); + action.appendCost( + new ExertCharactersEffect(self, self)); + action.appendCost( + new AddTwilightEffect(self, 1)); + action.appendEffect( + new ChooseArbitraryCardsEffect(playerId, "Choose an Orc to play", game.getGameState().getStackedCards(self), Filters.playable(game), 1, 1) { + @Override + protected void cardsSelected(LotroGame game, Collection stackedHobbits) { + if (stackedHobbits.size() > 0) { + PhysicalCard stackedHobbit = stackedHobbits.iterator().next(); + game.getActionsEnvironment().addActionToStack(stackedHobbit.getBlueprint().getPlayCardAction(playerId, game, stackedHobbit, 0)); + } + } + }); + return Collections.singletonList(action); + } + return null; + } +} diff --git a/gemp-lotr/gemp-lotr-common/src/main/java/com/gempukku/lotro/common/Keyword.java b/gemp-lotr/gemp-lotr-common/src/main/java/com/gempukku/lotro/common/Keyword.java index b2793dafb..b280f195d 100644 --- a/gemp-lotr/gemp-lotr-common/src/main/java/com/gempukku/lotro/common/Keyword.java +++ b/gemp-lotr/gemp-lotr-common/src/main/java/com/gempukku/lotro/common/Keyword.java @@ -14,7 +14,8 @@ public enum Keyword { RIVER("River", true), PLAINS("Plains", true), UNDERGROUND("Underground", true), SANCTUARY("Sanctuary", true), FOREST("Forest", true), MARSH("Marsh", true), MOUNTAIN("Mountain", true), BATTLEGROUND("Battleground", true), - DAMAGE("Damage", true, true), DEFENDER("Defender", true, true), FIERCE("Fierce", true), ARCHER("Archer", true), RANGER("Ranger", true), TRACKER("Tracker", true), + DAMAGE("Damage", true, true), DEFENDER("Defender", true, true), FIERCE("Fierce", true), ARCHER("Archer", true), UNHASTY("Unhasty", true), + RANGER("Ranger", true), TRACKER("Tracker", true), HAND_WEAPON("Hand Weapon"), ARMOR("Armor"), HELM("Helm"), MOUNT("Mount"), RANGED_WEAPON("Ranged Weapon"), CLOAK("Cloak"), PIPE("Pipe"), PIPEWEED("Pipeweed"), SHIELD("Shield"), BRACERS("Bracers"), STAFF("Staff"), RING("Ring"), diff --git a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/filters/Filters.java b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/filters/Filters.java index b62886577..45d379508 100644 --- a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/filters/Filters.java +++ b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/filters/Filters.java @@ -82,19 +82,6 @@ public class Filters { }; } - public static Filter allyOnHomeSite() { - return Filters.and( - Filters.type(CardType.ALLY), - new Filter() { - @Override - public boolean accepts(GameState gameState, ModifiersQuerying modifiersQuerying, PhysicalCard physicalCard) { - return physicalCard.getBlueprint().getSiteNumber() == gameState.getCurrentSiteNumber() - && physicalCard.getBlueprint().getSiteBlock() == gameState.getCurrentSite().getBlueprint().getSiteBlock(); - } - } - ); - } - public static Filter siteBlock(final Block block) { return new Filter() { @Override @@ -259,6 +246,17 @@ public class Filters { }; } + public static Filter isAllyAtHome() { + return Filters.and( + Filters.type(CardType.ALLY), + new Filter() { + @Override + public boolean accepts(GameState gameState, ModifiersQuerying modifiersQuerying, PhysicalCard physicalCard) { + return physicalCard.getBlueprint().isAllyAtHome(gameState.getCurrentSiteNumber(), gameState.getCurrentSiteBlock()); + } + }); + } + public static Filter siteNumber(final int siteNumber) { return new Filter() { @Override diff --git a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/game/LotroCardBlueprint.java b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/game/LotroCardBlueprint.java index 6dd4dada3..3b68f84d4 100644 --- a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/game/LotroCardBlueprint.java +++ b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/game/LotroCardBlueprint.java @@ -38,6 +38,8 @@ public interface LotroCardBlueprint { public int getResistance(); + public boolean isAllyAtHome(int siteNumber, Block siteBlock); + public List getAlwaysOnModifiers(PhysicalCard self); public boolean checkPlayRequirements(String playerId, LotroGame game, PhysicalCard self, int twilightModifier); diff --git a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/logic/modifiers/AbstractModifier.java b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/logic/modifiers/AbstractModifier.java index 829aaa5f1..47c7a21b4 100644 --- a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/logic/modifiers/AbstractModifier.java +++ b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/logic/modifiers/AbstractModifier.java @@ -121,7 +121,7 @@ public abstract class AbstractModifier implements Modifier { } @Override - public boolean isAllyParticipateInSkirmishes(GameState gameState, ModifiersQuerying modifiersQuerying, PhysicalCard card) { + public boolean isAllyParticipateInSkirmishes(GameState gameState, Side sidePlayer, ModifiersQuerying modifiersQuerying, PhysicalCard card) { return false; } diff --git a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/logic/modifiers/Modifier.java b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/logic/modifiers/Modifier.java index d9adaa64c..aa9e02101 100644 --- a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/logic/modifiers/Modifier.java +++ b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/logic/modifiers/Modifier.java @@ -50,7 +50,7 @@ public interface Modifier { public boolean isAllyParticipateInArcheryFire(GameState gameState, ModifiersQuerying modifiersQuerying, PhysicalCard card); - public boolean isAllyParticipateInSkirmishes(GameState gameState, ModifiersQuerying modifiersQuerying, PhysicalCard card); + public boolean isAllyParticipateInSkirmishes(GameState gameState, Side sidePlayer, ModifiersQuerying modifiersQuerying, PhysicalCard card); public int getArcheryTotal(GameState gameState, ModifiersQuerying modifiersQuerying, Side side, int result); diff --git a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/logic/modifiers/ModifiersLogic.java b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/logic/modifiers/ModifiersLogic.java index d2e4b1d3e..a198ccf41 100644 --- a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/logic/modifiers/ModifiersLogic.java +++ b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/logic/modifiers/ModifiersLogic.java @@ -328,10 +328,10 @@ public class ModifiersLogic implements ModifiersEnvironment, ModifiersQuerying { } @Override - public boolean isAllyParticipateInSkirmishes(GameState gameState, PhysicalCard card) { + public boolean isAllyParticipateInSkirmishes(GameState gameState, Side sidePlayer, PhysicalCard card) { for (Modifier modifier : getModifiers(ModifierEffect.PRESENCE_MODIFIER)) { if (affectsCardWithSkipSet(gameState, card, modifier)) - if (modifier.isAllyParticipateInSkirmishes(gameState, this, card)) + if (modifier.isAllyParticipateInSkirmishes(gameState, sidePlayer, this, card)) return true; } return false; diff --git a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/logic/modifiers/ModifiersQuerying.java b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/logic/modifiers/ModifiersQuerying.java index 9381f343e..d04c708b5 100644 --- a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/logic/modifiers/ModifiersQuerying.java +++ b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/logic/modifiers/ModifiersQuerying.java @@ -54,7 +54,7 @@ public interface ModifiersQuerying { // Assignments public boolean canBeAssignedToSkirmish(GameState gameState, Side playerSide, PhysicalCard card); - public boolean isAllyParticipateInSkirmishes(GameState gameState, PhysicalCard card); + public boolean isAllyParticipateInSkirmishes(GameState gameState, Side sidePlayer, PhysicalCard card); public boolean isAllyParticipateInArcheryFire(GameState gameState, PhysicalCard card); diff --git a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/logic/timing/processes/turn/assign/FreePeoplePlayerAssignsMinionsGameProcess.java b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/logic/timing/processes/turn/assign/FreePeoplePlayerAssignsMinionsGameProcess.java index e346e5a98..c302f90b7 100644 --- a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/logic/timing/processes/turn/assign/FreePeoplePlayerAssignsMinionsGameProcess.java +++ b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/logic/timing/processes/turn/assign/FreePeoplePlayerAssignsMinionsGameProcess.java @@ -54,7 +54,7 @@ public class FreePeoplePlayerAssignsMinionsGameProcess implements GameProcess { new Filter() { @Override public boolean accepts(GameState gameState, ModifiersQuerying modifiersQuerying, PhysicalCard physicalCard) { - return modifiersQuerying.isAllyParticipateInSkirmishes(gameState, physicalCard); + return modifiersQuerying.isAllyParticipateInSkirmishes(gameState, Side.FREE_PEOPLE, physicalCard); } } ) diff --git a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/logic/timing/processes/turn/assign/ShadowPlayerAssignsHisMinionsGameProcess.java b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/logic/timing/processes/turn/assign/ShadowPlayerAssignsHisMinionsGameProcess.java index db8c15e84..490352f49 100644 --- a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/logic/timing/processes/turn/assign/ShadowPlayerAssignsHisMinionsGameProcess.java +++ b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/logic/timing/processes/turn/assign/ShadowPlayerAssignsHisMinionsGameProcess.java @@ -57,7 +57,7 @@ public class ShadowPlayerAssignsHisMinionsGameProcess implements GameProcess { new Filter() { @Override public boolean accepts(GameState gameState, ModifiersQuerying modifiersQuerying, PhysicalCard physicalCard) { - return modifiersQuerying.isAllyParticipateInSkirmishes(gameState, physicalCard); + return modifiersQuerying.isAllyParticipateInSkirmishes(gameState, Side.SHADOW, physicalCard); } } )