Sending warnings to user when decision made was invalid.

Started work on animating when some card affects another card.
This commit is contained in:
marcins78@gmail.com
2011-09-21 10:39:08 +00:00
parent a66e3aa4f7
commit 2df7d2f261
9 changed files with 116 additions and 46 deletions

View File

@@ -41,4 +41,6 @@ public interface GameStateListener {
public void setSite(PhysicalCard card); public void setSite(PhysicalCard card);
public void setZoneSize(String playerId, Zone zone, int size); public void setZoneSize(String playerId, Zone zone, int size);
public void cardAffectedByCard(PhysicalCard card, PhysicalCard affectedCard);
} }

View File

@@ -5,5 +5,7 @@ import com.gempukku.lotro.logic.decisions.AwaitingDecision;
public interface UserFeedback { public interface UserFeedback {
public void sendAwaitingDecision(String playerId, AwaitingDecision awaitingDecision); public void sendAwaitingDecision(String playerId, AwaitingDecision awaitingDecision);
public void sendWarning(String playerId, String warning);
public boolean hasPendingDecisions(); public boolean hasPendingDecisions();
} }

View File

@@ -219,6 +219,11 @@ public class GameState {
addCardToZone(card, Zone.ATTACHED); 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) { public void stackCard(PhysicalCard card, PhysicalCard stackOn) {
((PhysicalCardImpl) card).stackOn((PhysicalCardImpl) stackOn); ((PhysicalCardImpl) card).stackOn((PhysicalCardImpl) stackOn);
addCardToZone(card, Zone.STACKED); addCardToZone(card, Zone.STACKED);

View File

@@ -9,6 +9,7 @@ import java.util.Set;
public class DefaultUserFeedback implements UserFeedback { public class DefaultUserFeedback implements UserFeedback {
private Map<String, AwaitingDecision> _awaitingDecisionMap = new HashMap<String, AwaitingDecision>(); private Map<String, AwaitingDecision> _awaitingDecisionMap = new HashMap<String, AwaitingDecision>();
private Map<String, String> _warnings = new HashMap<String, String>();
public void participantDecided(String playerId) { public void participantDecided(String playerId) {
_awaitingDecisionMap.remove(playerId); _awaitingDecisionMap.remove(playerId);
@@ -23,11 +24,20 @@ public class DefaultUserFeedback implements UserFeedback {
_awaitingDecisionMap.put(playerId, awaitingDecision); _awaitingDecisionMap.put(playerId, awaitingDecision);
} }
@Override
public void sendWarning(String playerId, String warning) {
_warnings.put(playerId, warning);
}
@Override @Override
public boolean hasPendingDecisions() { public boolean hasPendingDecisions() {
return _awaitingDecisionMap.size() > 0; return _awaitingDecisionMap.size() > 0;
} }
public String consumeWarning(String playerId) {
return _warnings.remove(playerId);
}
public Set<String> getUsersPendingDecision() { public Set<String> getUsersPendingDecision() {
return _awaitingDecisionMap.keySet(); return _awaitingDecisionMap.keySet();
} }

View File

@@ -15,7 +15,8 @@ public class GameEvent {
START_SKIRMISH, END_SKIRMISH, START_SKIRMISH, END_SKIRMISH,
ADD_TOKENS, REMOVE_TOKENS, ADD_TOKENS, REMOVE_TOKENS,
MESSAGE, WARNING, MESSAGE, WARNING,
ZONE_SIZE ZONE_SIZE,
CARD_AFFECTS_CARD
} }
private String _message; private String _message;

View File

@@ -115,6 +115,11 @@ public class GatheringParticipantCommunicationChannel implements GameStateListen
_events.add(new GameEvent(ZONE_SIZE).participantId(playerId).zone(zone).count(size)); _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<GameEvent> consumeGameEvents() { public List<GameEvent> consumeGameEvents() {
List<GameEvent> result = _events; List<GameEvent> result = _events;
_events = new LinkedList<GameEvent>(); _events = new LinkedList<GameEvent>();

View File

@@ -168,7 +168,7 @@ public class LotroGameMediator {
} catch (DecisionResultInvalidException decisionResultInvalidException) { } catch (DecisionResultInvalidException decisionResultInvalidException) {
// Participant provided wrong answer - send a warning message, and ask again for the same decision // 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); _userFeedback.sendAwaitingDecision(lotroGameParticipant, awaitingDecision);
} }
} }
@@ -185,6 +185,11 @@ public class LotroGameMediator {
if (communicationChannel != null) { if (communicationChannel != null) {
for (GameEvent gameEvent : communicationChannel.consumeGameEvents()) for (GameEvent gameEvent : communicationChannel.consumeGameEvents())
visitor.visitGameEvent(gameEvent); 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); AwaitingDecision awaitingDecision = _userFeedback.getAwaitingDecision(participantId);
if (awaitingDecision != null) if (awaitingDecision != null)
visitor.visitAwaitingDecision(awaitingDecision); visitor.visitAwaitingDecision(awaitingDecision);

View File

@@ -54,6 +54,8 @@ var GempLotrGameUI = Class.extend({
tabPane: null, tabPane: null,
animationEffectDiv: null,
init: function(url) { init: function(url) {
log("ui initialized"); log("ui initialized");
var that = this; var that = this;
@@ -116,7 +118,6 @@ var GempLotrGameUI = Class.extend({
}); });
} }
this.specialGroup = new NormalCardGroup(this.cardActionDialog, function(card) { this.specialGroup = new NormalCardGroup(this.cardActionDialog, function(card) {
return (card.zone == "SPECIAL"); return (card.zone == "SPECIAL");
}, false); }, false);
@@ -180,6 +181,10 @@ var GempLotrGameUI = Class.extend({
function (event) { function (event) {
that.clickCardFunction(event); that.clickCardFunction(event);
}); });
this.animationEffectDiv = $("<div id='animation'></div>");
this.animationEffectDiv.hide();
$("#main").append(this.animationEffectDiv);
}, },
addBottomLeftTabPane: function() { addBottomLeftTabPane: function() {
@@ -260,21 +265,21 @@ var GempLotrGameUI = Class.extend({
initializeDialogs: function() { initializeDialogs: function() {
this.smallDialog = $("<div></div>") this.smallDialog = $("<div></div>")
.dialog({ .dialog({
autoOpen: false, autoOpen: false,
closeOnEscape: false, closeOnEscape: false,
resizable: false, resizable: false,
width: 400, width: 400,
height: 200 height: 200
}); });
this.cardActionDialog = $("<div></div>") this.cardActionDialog = $("<div></div>")
.dialog({ .dialog({
autoOpen: false, autoOpen: false,
closeOnEscape: false, closeOnEscape: false,
resizable: true, resizable: true,
width: 600, width: 600,
height: 300 height: 300
}); });
var that = this; var that = this;
@@ -286,15 +291,15 @@ var GempLotrGameUI = Class.extend({
this.infoDialog = $("<div></div>") this.infoDialog = $("<div></div>")
.dialog({ .dialog({
autoOpen: false, autoOpen: false,
closeOnEscape: true, closeOnEscape: true,
resizable: true, resizable: true,
title: "Card information", title: "Card information",
minHeight: 80, minHeight: 80,
minWidth: 200, minWidth: 200,
width: 600, width: 600,
height: 300 height: 300
}); });
var swipeOptions = { var swipeOptions = {
threshold: 20, threshold: 20,
@@ -499,6 +504,8 @@ var GempLotrGameUI = Class.extend({
this.message(gameEvent); this.message(gameEvent);
} else if (eventType == "WARNING") { } else if (eventType == "WARNING") {
this.warning(gameEvent); this.warning(gameEvent);
} else if (eventType == "CARD_AFFECTS_CARD") {
this.cardAffectsCard(gameEvent);
} }
} }
var skirmish = element.getElementsByTagName("skirmish") var skirmish = element.getElementsByTagName("skirmish")
@@ -573,9 +580,9 @@ var GempLotrGameUI = Class.extend({
else if (zone == "DISCARD") else if (zone == "DISCARD")
$("#discard" + this.getPlayerIndex(playerId)).text("Discard: " + count); $("#discard" + this.getPlayerIndex(playerId)).text("Discard: " + count);
else if (zone == "DEAD") else if (zone == "DEAD")
$("#deadPile" + this.getPlayerIndex(playerId)).text("Dead pile: " + count); $("#deadPile" + this.getPlayerIndex(playerId)).text("Dead pile: " + count);
else if (zone == "DECK") else if (zone == "DECK")
$("#deck" + this.getPlayerIndex(playerId)).text("Deck: " + count); $("#deck" + this.getPlayerIndex(playerId)).text("Deck: " + count);
}, },
playerPosition: function(element) { playerPosition: function(element) {
@@ -631,6 +638,38 @@ var GempLotrGameUI = Class.extend({
this.chatBox.appendMessage(message, "warningMessage"); 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) { startSkirmish: function(element) {
var cardId = element.getAttribute("cardId"); var cardId = element.getAttribute("cardId");
var opposingCardIds = element.getAttribute("opposingCardIds").split(","); var opposingCardIds = element.getAttribute("opposingCardIds").split(",");
@@ -729,7 +768,7 @@ var GempLotrGameUI = Class.extend({
if (index != -1) if (index != -1)
cardData.attachedCards.splice(index, 1); cardData.attachedCards.splice(index, 1);
} }
); );
var card = $(".card:cardId(" + cardId + ")"); var card = $(".card:cardId(" + cardId + ")");
var cardData = card.data("card"); var cardData = card.data("card");
@@ -850,7 +889,7 @@ var GempLotrGameUI = Class.extend({
if (index != -1) if (index != -1)
cardData.attachedCards.splice(index, 1); cardData.attachedCards.splice(index, 1);
} }
); );
} }
card.remove(); card.remove();
@@ -922,13 +961,13 @@ var GempLotrGameUI = Class.extend({
this.smallDialog this.smallDialog
.html(text + "<br /><input id='integerDecision' type='text' value='0'>") .html(text + "<br /><input id='integerDecision' type='text' value='0'>")
.dialog("option", "buttons", .dialog("option", "buttons",
{ {
"OK": function() { "OK": function() {
$(this).dialog("close"); $(this).dialog("close");
that.decisionFunction(id, $("#integerDecision").val()); that.decisionFunction(id, $("#integerDecision").val());
} }
} }
); );
$("#integerDecision").SpinnerControl({ type: 'range', $("#integerDecision").SpinnerControl({ type: 'range',
typedata: { typedata: {
@@ -960,13 +999,13 @@ var GempLotrGameUI = Class.extend({
this.smallDialog this.smallDialog
.html(html) .html(html)
.dialog("option", "buttons", .dialog("option", "buttons",
{ {
"OK": function() { "OK": function() {
$(this).dialog("close"); $(this).dialog("close");
that.decisionFunction(id, $("#multipleChoiceDecision").val()); that.decisionFunction(id, $("#multipleChoiceDecision").val());
} }
} }
); );
this.smallDialog.dialog("open"); this.smallDialog.dialog("open");
}, },

View File

@@ -1,7 +1,5 @@
TO DO: TO DO:
Before release: 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: Next priority:
24. The events that are played and cards affected should be shown to the players briefly using animations to make it 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 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. final methods were possible to avoid implementation errors on new cards added.
10. Add active/all cards switch to the user interface. 10. Add active/all cards switch to the user interface.
34. 35.
DONE: DONE:
1. Introduce AbstractPermanent into Blueprint hierarchy. 1. Introduce AbstractPermanent into Blueprint hierarchy.
@@ -48,3 +46,6 @@ with Filters.sameCard(...) filter.
26. The game area should display chat from the start. 26. The game area should display chat from the start.
13. Add dead/discard pile displays. 13. Add dead/discard pile displays.
25. Remove all non-essencial alerts, instead add warnings to chat panel. 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.