diff --git a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/communication/GameStateListener.java b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/communication/GameStateListener.java index aa1f0bbff..d50855e36 100644 --- a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/communication/GameStateListener.java +++ b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/communication/GameStateListener.java @@ -41,4 +41,6 @@ public interface GameStateListener { public void setSite(PhysicalCard card); public void setZoneSize(String playerId, Zone zone, int size); + + public void cardAffectedByCard(PhysicalCard card, PhysicalCard affectedCard); } diff --git a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/communication/UserFeedback.java b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/communication/UserFeedback.java index aeb7649b0..e3352627a 100644 --- a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/communication/UserFeedback.java +++ b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/communication/UserFeedback.java @@ -5,5 +5,7 @@ import com.gempukku.lotro.logic.decisions.AwaitingDecision; public interface UserFeedback { public void sendAwaitingDecision(String playerId, AwaitingDecision awaitingDecision); + public void sendWarning(String playerId, String warning); + public boolean hasPendingDecisions(); } diff --git a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/game/state/GameState.java b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/game/state/GameState.java index ca648df5c..42befc293 100644 --- a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/game/state/GameState.java +++ b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/game/state/GameState.java @@ -219,6 +219,11 @@ public class GameState { addCardToZone(card, Zone.ATTACHED); } + public void cardAffectsCard(PhysicalCard card, PhysicalCard affectedCard) { + for (GameStateListener listener : getAllGameStateListeners()) + listener.cardAffectedByCard(card, affectedCard); + } + public void stackCard(PhysicalCard card, PhysicalCard stackOn) { ((PhysicalCardImpl) card).stackOn((PhysicalCardImpl) stackOn); addCardToZone(card, Zone.STACKED); diff --git a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/game/DefaultUserFeedback.java b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/game/DefaultUserFeedback.java index a312b662e..32a3739b1 100644 --- a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/game/DefaultUserFeedback.java +++ b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/game/DefaultUserFeedback.java @@ -9,6 +9,7 @@ import java.util.Set; public class DefaultUserFeedback implements UserFeedback { private Map _awaitingDecisionMap = new HashMap(); + private Map _warnings = new HashMap(); public void participantDecided(String playerId) { _awaitingDecisionMap.remove(playerId); @@ -23,11 +24,20 @@ public class DefaultUserFeedback implements UserFeedback { _awaitingDecisionMap.put(playerId, awaitingDecision); } + @Override + public void sendWarning(String playerId, String warning) { + _warnings.put(playerId, warning); + } + @Override public boolean hasPendingDecisions() { return _awaitingDecisionMap.size() > 0; } + public String consumeWarning(String playerId) { + return _warnings.remove(playerId); + } + public Set getUsersPendingDecision() { return _awaitingDecisionMap.keySet(); } diff --git a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/game/GameEvent.java b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/game/GameEvent.java index 6635004df..36eb3e437 100644 --- a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/game/GameEvent.java +++ b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/game/GameEvent.java @@ -15,7 +15,8 @@ public class GameEvent { START_SKIRMISH, END_SKIRMISH, ADD_TOKENS, REMOVE_TOKENS, MESSAGE, WARNING, - ZONE_SIZE + ZONE_SIZE, + CARD_AFFECTS_CARD } private String _message; diff --git a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/game/GatheringParticipantCommunicationChannel.java b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/game/GatheringParticipantCommunicationChannel.java index 840056d61..80ed827ce 100644 --- a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/game/GatheringParticipantCommunicationChannel.java +++ b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/game/GatheringParticipantCommunicationChannel.java @@ -115,6 +115,11 @@ public class GatheringParticipantCommunicationChannel implements GameStateListen _events.add(new GameEvent(ZONE_SIZE).participantId(playerId).zone(zone).count(size)); } + @Override + public void cardAffectedByCard(PhysicalCard card, PhysicalCard affectedCard) { + _events.add(new GameEvent(CARD_AFFECTS_CARD).card(card).targetCardId(affectedCard.getCardId())); + } + public List consumeGameEvents() { List result = _events; _events = new LinkedList(); diff --git a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/game/LotroGameMediator.java b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/game/LotroGameMediator.java index f9cf2c12f..582bbe55c 100644 --- a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/game/LotroGameMediator.java +++ b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/game/LotroGameMediator.java @@ -168,7 +168,7 @@ public class LotroGameMediator { } catch (DecisionResultInvalidException decisionResultInvalidException) { // Participant provided wrong answer - send a warning message, and ask again for the same decision -// _userCommunication.sendWarning(lotroGameParticipant, decisionResultInvalidException.getWarningMessage()); + _userFeedback.sendWarning(lotroGameParticipant, decisionResultInvalidException.getWarningMessage()); _userFeedback.sendAwaitingDecision(lotroGameParticipant, awaitingDecision); } } @@ -185,6 +185,11 @@ public class LotroGameMediator { if (communicationChannel != null) { for (GameEvent gameEvent : communicationChannel.consumeGameEvents()) visitor.visitGameEvent(gameEvent); + + String warning = _userFeedback.consumeWarning(participantId); + if (warning != null) + visitor.visitGameEvent(new GameEvent(GameEvent.Type.WARNING).message(warning)); + AwaitingDecision awaitingDecision = _userFeedback.getAwaitingDecision(participantId); if (awaitingDecision != null) visitor.visitAwaitingDecision(awaitingDecision); diff --git a/gemp-lotr/gemp-lotr-web/src/main/webapp/js/gameUi.js b/gemp-lotr/gemp-lotr-web/src/main/webapp/js/gameUi.js index b258dfbe1..6cadeda7a 100644 --- a/gemp-lotr/gemp-lotr-web/src/main/webapp/js/gameUi.js +++ b/gemp-lotr/gemp-lotr-web/src/main/webapp/js/gameUi.js @@ -54,6 +54,8 @@ var GempLotrGameUI = Class.extend({ tabPane: null, + animationEffectDiv: null, + init: function(url) { log("ui initialized"); var that = this; @@ -116,7 +118,6 @@ var GempLotrGameUI = Class.extend({ }); } - this.specialGroup = new NormalCardGroup(this.cardActionDialog, function(card) { return (card.zone == "SPECIAL"); }, false); @@ -180,6 +181,10 @@ var GempLotrGameUI = Class.extend({ function (event) { that.clickCardFunction(event); }); + + this.animationEffectDiv = $("
"); + this.animationEffectDiv.hide(); + $("#main").append(this.animationEffectDiv); }, addBottomLeftTabPane: function() { @@ -260,21 +265,21 @@ var GempLotrGameUI = Class.extend({ initializeDialogs: function() { this.smallDialog = $("
") .dialog({ - autoOpen: false, - closeOnEscape: false, - resizable: false, - width: 400, - height: 200 - }); + autoOpen: false, + closeOnEscape: false, + resizable: false, + width: 400, + height: 200 + }); this.cardActionDialog = $("
") .dialog({ - autoOpen: false, - closeOnEscape: false, - resizable: true, - width: 600, - height: 300 - }); + autoOpen: false, + closeOnEscape: false, + resizable: true, + width: 600, + height: 300 + }); var that = this; @@ -286,15 +291,15 @@ var GempLotrGameUI = Class.extend({ this.infoDialog = $("
") .dialog({ - autoOpen: false, - closeOnEscape: true, - resizable: true, - title: "Card information", - minHeight: 80, - minWidth: 200, - width: 600, - height: 300 - }); + autoOpen: false, + closeOnEscape: true, + resizable: true, + title: "Card information", + minHeight: 80, + minWidth: 200, + width: 600, + height: 300 + }); var swipeOptions = { threshold: 20, @@ -499,6 +504,8 @@ var GempLotrGameUI = Class.extend({ this.message(gameEvent); } else if (eventType == "WARNING") { this.warning(gameEvent); + } else if (eventType == "CARD_AFFECTS_CARD") { + this.cardAffectsCard(gameEvent); } } var skirmish = element.getElementsByTagName("skirmish") @@ -573,9 +580,9 @@ var GempLotrGameUI = Class.extend({ else if (zone == "DISCARD") $("#discard" + this.getPlayerIndex(playerId)).text("Discard: " + count); else if (zone == "DEAD") - $("#deadPile" + this.getPlayerIndex(playerId)).text("Dead pile: " + count); - else if (zone == "DECK") - $("#deck" + this.getPlayerIndex(playerId)).text("Deck: " + count); + $("#deadPile" + this.getPlayerIndex(playerId)).text("Dead pile: " + count); + else if (zone == "DECK") + $("#deck" + this.getPlayerIndex(playerId)).text("Deck: " + count); }, playerPosition: function(element) { @@ -631,6 +638,38 @@ var GempLotrGameUI = Class.extend({ this.chatBox.appendMessage(message, "warningMessage"); }, + cardAffectsCard: function(element) { + var participantId = element.getAttribute("participantId"); + var blueprintId = element.getAttribute("blueprintId"); + var targetCardId = element.getAttribute("targetCardId"); + + var card = new Card(blueprintId, "ANIMATION", "anim", participantId); + var cardDiv = createCardDiv(card.imageUrl); + + this.animationEffectDiv.queue("anim", + function(next) { + var targetCard = $(".card:cardId(" + targetCardId + ")"); + if (targetCard.length > 0) { + targetCard = targetCard[0]; + $("#animation").html(cardDiv); + $("#animation").css({ + position: "absolute", + left: targetCard.position().left(), + top: targetCard.position().top, + width: targetCard.width(), + height: targetCard.height(), + "z-index": 100}); + $("#animation").show(); + $('#animation').animate( + {opacity: 0}, + {duration: 500, + queue: false, + complete: next + }); + } + }).dequeue("anim"); + }, + startSkirmish: function(element) { var cardId = element.getAttribute("cardId"); var opposingCardIds = element.getAttribute("opposingCardIds").split(","); @@ -729,7 +768,7 @@ var GempLotrGameUI = Class.extend({ if (index != -1) cardData.attachedCards.splice(index, 1); } - ); + ); var card = $(".card:cardId(" + cardId + ")"); var cardData = card.data("card"); @@ -850,7 +889,7 @@ var GempLotrGameUI = Class.extend({ if (index != -1) cardData.attachedCards.splice(index, 1); } - ); + ); } card.remove(); @@ -922,13 +961,13 @@ var GempLotrGameUI = Class.extend({ this.smallDialog .html(text + "
") .dialog("option", "buttons", - { - "OK": function() { - $(this).dialog("close"); - that.decisionFunction(id, $("#integerDecision").val()); - } - } - ); + { + "OK": function() { + $(this).dialog("close"); + that.decisionFunction(id, $("#integerDecision").val()); + } + } + ); $("#integerDecision").SpinnerControl({ type: 'range', typedata: { @@ -960,13 +999,13 @@ var GempLotrGameUI = Class.extend({ this.smallDialog .html(html) .dialog("option", "buttons", - { - "OK": function() { - $(this).dialog("close"); - that.decisionFunction(id, $("#multipleChoiceDecision").val()); - } - } - ); + { + "OK": function() { + $(this).dialog("close"); + that.decisionFunction(id, $("#multipleChoiceDecision").val()); + } + } + ); this.smallDialog.dialog("open"); }, diff --git a/gemp-lotr/todo.txt b/gemp-lotr/todo.txt index 5f938e93e..ffe7ef32d 100644 --- a/gemp-lotr/todo.txt +++ b/gemp-lotr/todo.txt @@ -1,7 +1,5 @@ TO DO: Before release: -31. Allow to cancel selection to reset to none-selected and go with different selection if no auto-accept is set or -multiple choices required. Next priority: 24. The events that are played and cards affected should be shown to the players briefly using animations to make it @@ -14,7 +12,7 @@ Optional: 4. Modify the Blueprint hierarchy to return possible return objects (PlayEventAction), TriggeredAction, etc. Use final methods were possible to avoid implementation errors on new cards added. 10. Add active/all cards switch to the user interface. -34. +35. DONE: 1. Introduce AbstractPermanent into Blueprint hierarchy. @@ -48,3 +46,6 @@ with Filters.sameCard(...) filter. 26. The game area should display chat from the start. 13. Add dead/discard pile displays. 25. Remove all non-essencial alerts, instead add warnings to chat panel. +31. Allow to cancel selection to reset to none-selected and go with different selection if no auto-accept is set or +multiple choices required. +34. Player should be able to concede the game at any time.