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 0f689bcba..0d0e8bcf9 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 @@ -23,7 +23,8 @@ public class AbstractAttachableFPPossession extends AbstractAttachable { protected void appendTransferPossessionAction(List actions, LotroGame game, PhysicalCard self, Filter validTargetFilter) { GameState gameState = game.getGameState(); - if (gameState.getCurrentPhase() == Phase.FELLOWSHIP + if (Filters.canSpot(gameState, game.getModifiersQuerying(), validTargetFilter) + && gameState.getCurrentPhase() == Phase.FELLOWSHIP && self.getZone() == Zone.ATTACHED) { Filter vaildTransferFilter; diff --git a/gemp-lotr/gemp-lotr-cards/src/main/java/com/gempukku/lotro/cards/set1/elven/Card1_034.java b/gemp-lotr/gemp-lotr-cards/src/main/java/com/gempukku/lotro/cards/set1/elven/Card1_034.java index d8722ebf3..9fcdb1c93 100644 --- a/gemp-lotr/gemp-lotr-cards/src/main/java/com/gempukku/lotro/cards/set1/elven/Card1_034.java +++ b/gemp-lotr/gemp-lotr-cards/src/main/java/com/gempukku/lotro/cards/set1/elven/Card1_034.java @@ -42,7 +42,8 @@ public class Card1_034 extends AbstractAlly { appendPlayAllyActions(actions, game, self); appendHealAllyActions(actions, game, self); - if (PlayConditions.canUseFPCardDuringPhase(game.getGameState(), Phase.FELLOWSHIP, self)) { + if (PlayConditions.canUseFPCardDuringPhase(game.getGameState(), Phase.FELLOWSHIP, self) + && PlayConditions.canExert(game.getGameState(), game.getModifiersQuerying(), self)) { final CostToEffectAction action = new CostToEffectAction(self, Keyword.FELLOWSHIP, "Exert Celeborn to Heal an ELVEN ally"); action.addCost(new ExertCharacterEffect(self)); action.addEffect(new ChooseActiveCardEffect(playerId, "Choose an ELVEN ally", Filters.culture(Culture.ELVEN), Filters.type(CardType.ALLY)) { diff --git a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/logic/decisions/ActionSelectionDecision.java b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/logic/decisions/ActionSelectionDecision.java new file mode 100644 index 000000000..54a736589 --- /dev/null +++ b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/logic/decisions/ActionSelectionDecision.java @@ -0,0 +1,60 @@ +package com.gempukku.lotro.logic.decisions; + +import com.gempukku.lotro.game.PhysicalCard; +import com.gempukku.lotro.logic.timing.Action; + +import java.util.List; + +public abstract class ActionSelectionDecision extends AbstractAwaitingDecision { + private List _actions; + + public ActionSelectionDecision(int decisionId, String text, List actions) { + super(decisionId, text, AwaitingDecisionType.ACTION_CHOICE); + _actions = actions; + + setParam("actionId", getActionIds(actions)); + setParam("blueprintId", getCardIds(actions)); + setParam("actionText", getActionTexts(actions)); + } + + private String[] getActionIds(List actions) { + String[] result = new String[actions.size()]; + for (int i = 0; i < result.length; i++) + result[i] = String.valueOf(i); + return result; + } + + private String[] getCardIds(List actions) { + String[] result = new String[actions.size()]; + for (int i = 0; i < result.length; i++) { + PhysicalCard physicalCard = actions.get(i).getActionSource(); + if (physicalCard != null) + result[i] = String.valueOf(physicalCard.getBlueprintId()); + else + result[i] = "rules"; + } + return result; + } + + private String[] getActionTexts(List actions) { + String[] result = new String[actions.size()]; + for (int i = 0; i < result.length; i++) + result[i] = actions.get(i).getText(); + return result; + } + + protected Action getSelectedAction(String result) throws DecisionResultInvalidException { + if (result.equals("")) + throw new DecisionResultInvalidException(); + + try { + int actionIndex = Integer.parseInt(result); + if (actionIndex < 0 || actionIndex >= _actions.size()) + throw new DecisionResultInvalidException(); + + return _actions.get(actionIndex); + } catch (NumberFormatException exp) { + throw new DecisionResultInvalidException(); + } + } +} diff --git a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/logic/decisions/AwaitingDecisionType.java b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/logic/decisions/AwaitingDecisionType.java index f6297cd61..83ed2803d 100644 --- a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/logic/decisions/AwaitingDecisionType.java +++ b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/logic/decisions/AwaitingDecisionType.java @@ -1,5 +1,5 @@ package com.gempukku.lotro.logic.decisions; public enum AwaitingDecisionType { - INTEGER, MULTIPLE_CHOICE, ARBITRARY_CARDS, ACTION_CHOICE, CARD_SELECTION, ACTION_ORDER, ASSIGN_MINIONS + INTEGER, MULTIPLE_CHOICE, ARBITRARY_CARDS, CARD_ACTION_CHOICE, ACTION_CHOICE, CARD_SELECTION, ASSIGN_MINIONS } diff --git a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/logic/decisions/ActionsSelectionDecision.java b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/logic/decisions/CardActionSelectionDecision.java similarity index 84% rename from gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/logic/decisions/ActionsSelectionDecision.java rename to gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/logic/decisions/CardActionSelectionDecision.java index 0bebae1a7..db5d058ba 100644 --- a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/logic/decisions/ActionsSelectionDecision.java +++ b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/logic/decisions/CardActionSelectionDecision.java @@ -4,12 +4,12 @@ import com.gempukku.lotro.logic.timing.Action; import java.util.List; -public abstract class ActionsSelectionDecision extends AbstractAwaitingDecision { +public abstract class CardActionSelectionDecision extends AbstractAwaitingDecision { private List _actions; private boolean _optional; - public ActionsSelectionDecision(int decisionId, String text, List actions, boolean optional) { - super(decisionId, text, AwaitingDecisionType.ACTION_CHOICE); + public CardActionSelectionDecision(int decisionId, String text, List actions, boolean optional) { + super(decisionId, text, AwaitingDecisionType.CARD_ACTION_CHOICE); _actions = actions; _optional = optional; diff --git a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/logic/timing/TurnProcedure.java b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/logic/timing/TurnProcedure.java index 072f30eec..ded18327f 100644 --- a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/logic/timing/TurnProcedure.java +++ b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/logic/timing/TurnProcedure.java @@ -4,16 +4,17 @@ import com.gempukku.lotro.communication.UserFeedback; import com.gempukku.lotro.game.state.LotroGame; import com.gempukku.lotro.logic.PlayOrder; import com.gempukku.lotro.logic.actions.CostToEffectAction; -import com.gempukku.lotro.logic.decisions.AbstractAwaitingDecision; -import com.gempukku.lotro.logic.decisions.ActionsSelectionDecision; -import com.gempukku.lotro.logic.decisions.AwaitingDecisionType; +import com.gempukku.lotro.logic.decisions.ActionSelectionDecision; +import com.gempukku.lotro.logic.decisions.CardActionSelectionDecision; import com.gempukku.lotro.logic.decisions.DecisionResultInvalidException; -import com.gempukku.lotro.logic.effects.PlayoutDecisionEffect; import com.gempukku.lotro.logic.timing.actions.SystemAction; import com.gempukku.lotro.logic.timing.processes.GameProcess; import com.gempukku.lotro.logic.timing.processes.pregame.BiddingGameProcess; -import java.util.*; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; // Action generates multiple Effects, both costs and result of an action are Effects. @@ -34,7 +35,7 @@ public class TurnProcedure { } public void carryOutPendingActionsUntilDecisionNeeded() { - while (!_userFeedback.hasPendingDecisions() && _game.getGameState().getWinnerPlayerId() == null) { + while (!_userFeedback.hasPendingDecisions() && (_game.getGameState() == null || _game.getGameState().getWinnerPlayerId() == null)) { if (_actionStack.isEmpty()) { if (_playedGameProcess) { _gameProcess = _gameProcess.getNextProcess(); @@ -100,7 +101,10 @@ public class TurnProcedure { if (!_checkedIsAboutToOptionalResponses) { _checkedIsAboutToOptionalResponses = true; EffectResult effectResult = _effect.getRespondableResult(); - return new StackActionEffect(new PlayoutOptionalIsAboutToResponsesAction(_effect, effectResult)); + Map> optionalBeforeTriggers = _game.getActionsEnvironment().getOptionalBeforeTriggers(_game.getGameState().getPlayerOrder().getAllPlayers(), _effect, effectResult); + CostToEffectAction action = new CostToEffectAction(null, null, null); + action.addEffect(new PlayoutOptionalBeforeResponsesEffect(action, optionalBeforeTriggers, _game.getGameState().getPlayerOrder().getCounterClockwisePlayOrder(_game.getGameState().getCurrentPlayerId(), true), 0, _effect, effectResult)); + return new StackActionEffect(action); } if (!_effectPlayed) { if (_effect.canPlayEffect(_game)) @@ -135,6 +139,56 @@ public class TurnProcedure { } } + private class PlayoutOptionalBeforeResponsesEffect extends UnrespondableEffect { + private CostToEffectAction _action; + private Map> _actionMap = new HashMap>(); + private PlayOrder _playOrder; + private int _passCount; + private Effect _effect; + private EffectResult _effectResult; + + private PlayoutOptionalBeforeResponsesEffect(CostToEffectAction action, Map> actionMap, PlayOrder playOrder, int passCount, Effect effect, EffectResult effectResult) { + _action = action; + _actionMap = actionMap; + _playOrder = playOrder; + _passCount = passCount; + _effect = effect; + _effectResult = effectResult; + } + + @Override + public void playEffect(LotroGame game) { + if (!_effect.isCancelled()) { + final String activePlayer = _playOrder.getNextPlayer(); + List possibleActions = _actionMap.get(activePlayer); + possibleActions.addAll(_game.getActionsEnvironment().getOptionalAfterActions(activePlayer, _effectResult)); + + if (possibleActions.size() > 0) { + _game.getUserFeedback().sendAwaitingDecision(activePlayer, + new CardActionSelectionDecision(1, "Choose action to play or DONE", possibleActions, true) { + @Override + public void decisionMade(String result) throws DecisionResultInvalidException { + Action action = getSelectedAction(result); + if (action != null) { + _game.getActionsEnvironment().addActionToStack(action); + _actionMap.get(activePlayer).remove(action); + _action.addEffect(new PlayoutOptionalAfterResponsesEffect(_action, _actionMap, _playOrder, 0, _effectResult)); + } else { + if ((_passCount + 1) < _playOrder.getPlayerCount()) { + _action.addEffect(new PlayoutOptionalAfterResponsesEffect(_action, _actionMap, _playOrder, _passCount + 1, _effectResult)); + } + } + } + }); + } else { + if ((_passCount + 1) < _playOrder.getPlayerCount()) { + _action.addEffect(new PlayoutOptionalAfterResponsesEffect(_action, _actionMap, _playOrder, _passCount + 1, _effectResult)); + } + } + } + } + } + private class PlayoutOptionalAfterResponsesEffect extends UnrespondableEffect { private CostToEffectAction _action; private Map> _actionMap = new HashMap>(); @@ -158,7 +212,7 @@ public class TurnProcedure { if (possibleActions.size() > 0) { _game.getUserFeedback().sendAwaitingDecision(activePlayer, - new ActionsSelectionDecision(1, "Choose action to play or DONE", possibleActions, true) { + new CardActionSelectionDecision(1, "Choose action to play or DONE", possibleActions, true) { @Override public void decisionMade(String result) throws DecisionResultInvalidException { Action action = getSelectedAction(result); @@ -199,7 +253,7 @@ public class TurnProcedure { _game.getActionsEnvironment().addActionToStack(_actions.get(0)); } else { _game.getUserFeedback().sendAwaitingDecision(_game.getGameState().getCurrentPlayerId(), - new ActionsSelectionDecision(1, "Choose action to play now", _actions, false) { + new ActionSelectionDecision(1, "Choose action to play now", _actions) { @Override public void decisionMade(String result) throws DecisionResultInvalidException { Action action = getSelectedAction(result); @@ -213,32 +267,6 @@ public class TurnProcedure { } } - private class ChooseActionsOrderDecision extends AbstractAwaitingDecision { - private List _actions; - - private ChooseActionsOrderDecision(List actions) { - super(1, "Choose order of these actions", AwaitingDecisionType.ACTION_ORDER); - _actions = actions; - } - - @Override - public void decisionMade(String result) throws DecisionResultInvalidException { - String[] split = result.split(" "); - if (split.length != _actions.size()) - throw new DecisionResultInvalidException(); - List order = Arrays.asList(split); - for (int i = 0; i < _actions.size(); i++) - if (!order.contains(String.valueOf(i))) - throw new DecisionResultInvalidException(); - - Collections.reverse(order); - - // We need to stack them in reverse order, so that we can play them out from top to bottom - for (String index : order) - _actionStack.stackAction(_actions.get(Integer.parseInt(index))); - } - } - private class StackActionEffect extends UnrespondableEffect { private Action _action; @@ -251,41 +279,4 @@ public class TurnProcedure { _actionStack.stackAction(_action); } } - - private class PlayoutOptionalIsAboutToResponsesAction extends SystemAction { - private Effect _effect; - private EffectResult _effectResult; - private PlayOrder _playOrder; - private int _consecutivePassesCount = 0; - - private PlayoutOptionalIsAboutToResponsesAction(Effect effect, EffectResult effectResult) { - _effect = effect; - _effectResult = effectResult; - _playOrder = _game.getGameState().getPlayerOrder().getCounterClockwisePlayOrder(_game.getGameState().getCurrentPlayerId(), true); - } - - @Override - public Effect nextEffect() { - if (_effect.isCancelled()) - return null; - - if (_consecutivePassesCount == _playOrder.getPlayerCount()) - return null; - - String player = _playOrder.getNextPlayer(); - List actions = _game.getActionsEnvironment().getOptionalBeforeActions(player, _effect, _effectResult); - return new PlayoutDecisionEffect(_userFeedback, player, new ActionsSelectionDecision(1, "Choose action to play or DONE", actions, true) { - @Override - public void decisionMade(String result) throws DecisionResultInvalidException { - Action action = getSelectedAction(result); - if (action == null) - _consecutivePassesCount++; - else { - _consecutivePassesCount = 0; - _actionStack.stackAction(action); - } - } - }); - } - } } diff --git a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/logic/timing/processes/turn/general/PlayerPlaysPhaseActionsUntilPassesGameProcess.java b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/logic/timing/processes/turn/general/PlayerPlaysPhaseActionsUntilPassesGameProcess.java index f2b4e93f4..74bc09919 100644 --- a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/logic/timing/processes/turn/general/PlayerPlaysPhaseActionsUntilPassesGameProcess.java +++ b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/logic/timing/processes/turn/general/PlayerPlaysPhaseActionsUntilPassesGameProcess.java @@ -1,7 +1,7 @@ package com.gempukku.lotro.logic.timing.processes.turn.general; import com.gempukku.lotro.game.state.LotroGame; -import com.gempukku.lotro.logic.decisions.ActionsSelectionDecision; +import com.gempukku.lotro.logic.decisions.CardActionSelectionDecision; import com.gempukku.lotro.logic.decisions.DecisionResultInvalidException; import com.gempukku.lotro.logic.timing.Action; import com.gempukku.lotro.logic.timing.processes.GameProcess; @@ -34,7 +34,7 @@ public class PlayerPlaysPhaseActionsUntilPassesGameProcess implements GameProces playableActions.add(action); _game.getUserFeedback().sendAwaitingDecision(_playerId, - new ActionsSelectionDecision(1, "Choose action to play or press DONE", playableActions, true) { + new CardActionSelectionDecision(1, "Choose action to play or press DONE", playableActions, true) { @Override public void decisionMade(String result) throws DecisionResultInvalidException { Action action = getSelectedAction(result); diff --git a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/logic/timing/processes/turn/general/PlayersPlayPhaseActionsInOrderGameProcess.java b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/logic/timing/processes/turn/general/PlayersPlayPhaseActionsInOrderGameProcess.java index a490786b2..36e45972d 100644 --- a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/logic/timing/processes/turn/general/PlayersPlayPhaseActionsInOrderGameProcess.java +++ b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/logic/timing/processes/turn/general/PlayersPlayPhaseActionsInOrderGameProcess.java @@ -2,7 +2,7 @@ package com.gempukku.lotro.logic.timing.processes.turn.general; import com.gempukku.lotro.game.state.LotroGame; import com.gempukku.lotro.logic.PlayOrder; -import com.gempukku.lotro.logic.decisions.ActionsSelectionDecision; +import com.gempukku.lotro.logic.decisions.CardActionSelectionDecision; import com.gempukku.lotro.logic.decisions.DecisionResultInvalidException; import com.gempukku.lotro.logic.timing.Action; import com.gempukku.lotro.logic.timing.processes.GameProcess; @@ -40,7 +40,7 @@ public class PlayersPlayPhaseActionsInOrderGameProcess implements GameProcess { playableActions.add(action); _game.getUserFeedback().sendAwaitingDecision(playerId, - new ActionsSelectionDecision(1, "Choose action to play or press DONE", playableActions, true) { + new CardActionSelectionDecision(1, "Choose action to play or press DONE", playableActions, true) { @Override public void decisionMade(String result) throws DecisionResultInvalidException { Action action = getSelectedAction(result); diff --git a/gemp-lotr/gemp-lotr-web/src/main/webapp/js/ui.js b/gemp-lotr/gemp-lotr-web/src/main/webapp/js/ui.js index 79197403c..339a3d0fe 100644 --- a/gemp-lotr/gemp-lotr-web/src/main/webapp/js/ui.js +++ b/gemp-lotr/gemp-lotr-web/src/main/webapp/js/ui.js @@ -299,7 +299,7 @@ var GempLotrUI = Class.extend({ this.multipleChoiceDecision(decision); } else if (decisionType == "ARBITRARY_CARDS") { this.arbitraryCardsDecision(decision); - } else if (decisionType == "ACTION_CHOICE") { + } else if (decisionType == "CARD_ACTION_CHOICE") { this.actionChoiceDecision(decision); } else if (decisionType == "CARD_SELECTION") { this.cardSelectionDecision(decision);