2012-01-22 01:34:18 +00:00
|
|
|
/**
|
|
|
|
* Game interface.
|
|
|
|
*
|
|
|
|
* @author ajanata
|
|
|
|
*/
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Class to manage the game interface.
|
|
|
|
*
|
|
|
|
* @param {number}
|
|
|
|
* id The game id.
|
|
|
|
*
|
|
|
|
* @constructor
|
|
|
|
*/
|
|
|
|
cah.Game = function(id) {
|
|
|
|
/**
|
|
|
|
* The game id.
|
|
|
|
*
|
|
|
|
* @type {number}
|
|
|
|
* @private
|
|
|
|
*/
|
|
|
|
this.id_ = id;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* The element for this game lobby.
|
|
|
|
*
|
|
|
|
* @type {HTMLDivElement}
|
|
|
|
* @private
|
|
|
|
*/
|
|
|
|
this.element_ = $("#game_template").clone()[0];
|
2012-01-23 23:06:20 +00:00
|
|
|
this.element_.id = "game_" + id;
|
2012-01-23 07:58:36 +00:00
|
|
|
$(this.element_).removeClass("hide");
|
|
|
|
|
|
|
|
/**
|
|
|
|
* The element for the scoreboard for this game.
|
|
|
|
*
|
|
|
|
* @type {HTMLDivElement}
|
|
|
|
* @private
|
|
|
|
*/
|
|
|
|
this.scoreboardElement_ = $("#scoreboard_template").clone()[0];
|
2012-01-23 23:06:20 +00:00
|
|
|
this.scoreboardElement_.id = "scoreboard_" + id;
|
2012-01-23 07:58:36 +00:00
|
|
|
$(this.scoreboardElement_).removeClass("hide");
|
|
|
|
|
|
|
|
/**
|
|
|
|
* User->value mapping of scorecards in the scoreboard.
|
|
|
|
*
|
|
|
|
* @type {Object}
|
|
|
|
* @private
|
|
|
|
*/
|
|
|
|
this.scoreCards_ = {};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* The cards in the player's hand.
|
|
|
|
*
|
|
|
|
* @type {Array}
|
|
|
|
* @private
|
|
|
|
*/
|
|
|
|
this.hand_ = Array();
|
2012-01-23 21:20:15 +00:00
|
|
|
|
2012-01-27 23:41:57 +00:00
|
|
|
/**
|
|
|
|
* Map of id to card object for round cards.
|
|
|
|
*
|
|
|
|
* @type {Object}
|
|
|
|
* @private
|
|
|
|
*/
|
|
|
|
this.roundCards_ = {};
|
|
|
|
|
2012-01-25 00:20:43 +00:00
|
|
|
/**
|
|
|
|
* The game's state.
|
|
|
|
*
|
|
|
|
* @type {cah.$.GameState}
|
|
|
|
* @private
|
|
|
|
*/
|
|
|
|
this.state_ = cah.$.GameState.LOBBY;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* The black card on display.
|
|
|
|
*
|
|
|
|
* @type {cah.card.BlackCard}
|
|
|
|
* @private
|
|
|
|
*/
|
|
|
|
this.blackCard_ = null;
|
|
|
|
|
2012-01-25 06:39:19 +00:00
|
|
|
/**
|
|
|
|
* Selected card from the player's hand.
|
|
|
|
*
|
|
|
|
* @type {cah.card.WhiteCard}
|
|
|
|
* @private;
|
|
|
|
*/
|
|
|
|
this.handSelectedCard_ = null;
|
|
|
|
|
2012-01-27 08:14:48 +00:00
|
|
|
/**
|
|
|
|
* Selected card from the round's white cards.
|
|
|
|
*
|
|
|
|
* @type {cah.card.WhiteCard}
|
|
|
|
* @private;
|
|
|
|
*/
|
|
|
|
this.roundSelectedCard_ = null;
|
|
|
|
|
2012-01-27 02:07:39 +00:00
|
|
|
/**
|
|
|
|
* Card the player played this round.
|
|
|
|
*
|
|
|
|
* TODO make this an array when we support the multiple play blacks
|
|
|
|
*
|
|
|
|
* @type {cah.card.WhiteCard}
|
|
|
|
* @private
|
|
|
|
*/
|
|
|
|
this.myPlayedCard_ = null;
|
|
|
|
|
2012-01-25 06:39:19 +00:00
|
|
|
/**
|
|
|
|
* The judge of the current round.
|
|
|
|
*
|
|
|
|
* @type {String}
|
|
|
|
* @private
|
|
|
|
*/
|
2012-01-27 02:07:39 +00:00
|
|
|
this.judge_ = null;
|
2012-01-27 08:14:48 +00:00
|
|
|
|
2012-01-25 08:03:41 +00:00
|
|
|
/**
|
|
|
|
* Scale factor for hand cards when zoomed out.
|
|
|
|
*
|
|
|
|
* @type {Number}
|
|
|
|
* @private
|
|
|
|
*/
|
|
|
|
this.handCardSmallScale_ = .35;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Scale factor for hand cards when zoomed in.
|
|
|
|
*
|
|
|
|
* @type {Number}
|
|
|
|
* @private
|
|
|
|
*/
|
|
|
|
this.handCardLargeScale_ = .6;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Size for hand cards when zoomed out.
|
|
|
|
*
|
|
|
|
* @type {Number}
|
|
|
|
* @private
|
|
|
|
*/
|
|
|
|
this.handCardSmallSize_ = 83;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Size for hand cards when zoomed in.
|
|
|
|
*
|
|
|
|
* @type {Number}
|
|
|
|
* @private
|
|
|
|
*/
|
|
|
|
this.handCardLargeSize_ = 142;
|
|
|
|
|
2012-01-27 08:14:48 +00:00
|
|
|
/**
|
|
|
|
* Scale factor for round cards when zoomed out.
|
|
|
|
*
|
|
|
|
* @type {Number}
|
|
|
|
* @private
|
|
|
|
*/
|
|
|
|
this.roundCardSmallScale_ = 1;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Scale factor for round cards when zoomed in.
|
|
|
|
*
|
|
|
|
* @type {Number}
|
|
|
|
* @private
|
|
|
|
*/
|
|
|
|
this.roundCardLargeScale_ = 1;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Size for round cards when zoomed out.
|
|
|
|
*
|
|
|
|
* @type {Number}
|
|
|
|
* @private
|
|
|
|
*/
|
|
|
|
this.roundCardSmallSize_ = 236;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Size for round cards when zoomed in.
|
|
|
|
*
|
|
|
|
* @type {Number}
|
|
|
|
* @private
|
|
|
|
*/
|
|
|
|
this.roundCardLargeSize_ = 236;
|
|
|
|
|
2012-01-23 21:20:15 +00:00
|
|
|
$("#leave_game").click(cah.bind(this, this.leaveGameClick_));
|
|
|
|
$("#start_game").click(cah.bind(this, this.startGameClick_));
|
2012-01-25 06:39:19 +00:00
|
|
|
|
|
|
|
$(".confirm_card", this.element_).click(cah.bind(this, this.confirmClick_));
|
2012-01-25 08:03:41 +00:00
|
|
|
|
|
|
|
$(window).on("resize.game_" + this.id_, cah.bind(this, this.windowResize_));
|
2012-01-23 07:58:36 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Load game data from the server and display the game lobby.
|
|
|
|
*
|
2012-01-31 07:53:00 +00:00
|
|
|
* TODO reload round win state
|
|
|
|
*
|
2012-01-23 07:58:36 +00:00
|
|
|
* @param {number}
|
|
|
|
* gameId The game id.
|
|
|
|
*/
|
|
|
|
cah.Game.joinGame = function(gameId) {
|
|
|
|
cah.Ajax.build(cah.$.AjaxOperation.GET_GAME_INFO).withGameId(gameId).run();
|
2012-01-25 00:20:43 +00:00
|
|
|
cah.Ajax.build(cah.$.AjaxOperation.GET_CARDS).withGameId(gameId).run();
|
2012-01-23 07:58:36 +00:00
|
|
|
cah.GameList.instance.hide();
|
2012-01-23 21:20:15 +00:00
|
|
|
var game = new cah.Game(gameId);
|
|
|
|
cah.currentGames[gameId] = game;
|
|
|
|
game.insertIntoDocument();
|
2012-01-22 01:34:18 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @return {HTMLDivElement} This object's element.
|
|
|
|
*/
|
|
|
|
cah.Game.prototype.getElement = function() {
|
|
|
|
return this.element_;
|
|
|
|
};
|
|
|
|
|
2012-01-25 00:20:43 +00:00
|
|
|
/**
|
|
|
|
* Set the black card on display.
|
|
|
|
*
|
|
|
|
* @param {Object}
|
|
|
|
* card Black card data from server.
|
|
|
|
*/
|
|
|
|
cah.Game.prototype.setBlackCard = function(card) {
|
|
|
|
this.blackCard_ = new cah.card.BlackCard(true, card[cah.$.BlackCardData.ID]);
|
|
|
|
this.blackCard_.setText(card[cah.$.BlackCardData.TEXT]);
|
|
|
|
|
|
|
|
$(".game_black_card", this.element_).empty().append(this.blackCard_.getElement());
|
|
|
|
};
|
|
|
|
|
2012-01-23 23:06:20 +00:00
|
|
|
/**
|
|
|
|
* Add multiple cards to the player's hand.
|
|
|
|
*
|
|
|
|
* @param {Array}
|
|
|
|
* cards The array of card objects sent from the server.
|
|
|
|
*/
|
|
|
|
cah.Game.prototype.dealtCards = function(cards) {
|
|
|
|
for ( var index in cards) {
|
|
|
|
var thisCard = cards[index];
|
|
|
|
var card = new cah.card.WhiteCard(true, thisCard[cah.$.WhiteCardData.ID]);
|
|
|
|
card.setText(thisCard[cah.$.WhiteCardData.TEXT]);
|
|
|
|
this.dealtCard(card);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2012-01-23 07:58:36 +00:00
|
|
|
/**
|
|
|
|
* Add a card to the player's hand.
|
|
|
|
*
|
2012-01-24 03:14:29 +00:00
|
|
|
* TODO: in IE, for some reason, the logo is only on the leftmost card.
|
|
|
|
*
|
2012-01-23 07:58:36 +00:00
|
|
|
* @param {cah.card.WhiteCard}
|
|
|
|
* card Card to add to hand.
|
|
|
|
*/
|
|
|
|
cah.Game.prototype.dealtCard = function(card) {
|
|
|
|
this.hand_.push(card);
|
2012-01-24 01:41:02 +00:00
|
|
|
var element = card.getElement();
|
2012-01-25 06:39:19 +00:00
|
|
|
$(".game_hand_cards", this.element_).append(element);
|
2012-01-24 03:14:29 +00:00
|
|
|
|
2012-01-27 08:14:48 +00:00
|
|
|
$(element).css("transform-origin", "0 0");
|
2012-01-24 07:02:59 +00:00
|
|
|
|
2012-01-25 08:03:41 +00:00
|
|
|
var data = {
|
|
|
|
card : card,
|
|
|
|
};
|
2012-01-27 02:07:39 +00:00
|
|
|
$(element).on("mouseenter.hand", data, cah.bind(this, this.handCardMouseEnter_)).on(
|
|
|
|
"mouseleave.hand", data, cah.bind(this, this.handCardMouseLeave_)).on("click.hand", data,
|
|
|
|
cah.bind(this, this.handCardClick_));
|
|
|
|
|
|
|
|
this.resizeHandCards_();
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Remove a card from the hand.
|
|
|
|
*
|
|
|
|
* @param {cah.card.WhiteCard}
|
|
|
|
* card Card to remove.
|
|
|
|
*/
|
|
|
|
cah.Game.prototype.removeCardFromHand = function(card) {
|
|
|
|
var cardIndex = -1;
|
|
|
|
for ( var index in this.hand_) {
|
|
|
|
if (this.hand_[index] == card) {
|
|
|
|
cardIndex = index;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (cardIndex != -1) {
|
|
|
|
$(card.getElement()).css("width", "").css("height", "").css("transform-origin", "").css(
|
|
|
|
"z-index", "").css("-moz-transform", "").css("-ms-transform", "").css("-webkit-transform",
|
|
|
|
"").css("-o-transform", "").off(".hand");
|
|
|
|
this.hand_.splice(cardIndex, 1);
|
|
|
|
}
|
2012-01-27 03:25:40 +00:00
|
|
|
|
|
|
|
$(card.getElement(), $("game_hand_cards", this.element_)).remove();
|
|
|
|
this.resizeHandCards_();
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Set the round white cards.
|
|
|
|
*
|
|
|
|
* @param {Array}
|
|
|
|
* cards Array of cah.card.WhiteCard to display.
|
|
|
|
*/
|
|
|
|
cah.Game.prototype.setRoundWhiteCards = function(cards) {
|
|
|
|
for ( var index in cards) {
|
|
|
|
var card;
|
|
|
|
var id = cards[index][cah.$.WhiteCardData.ID];
|
|
|
|
if (id >= 0) {
|
|
|
|
card = new cah.card.WhiteCard(true, id);
|
|
|
|
card.setText(cards[index][cah.$.WhiteCardData.TEXT]);
|
|
|
|
} else {
|
|
|
|
card = new cah.card.WhiteCard();
|
|
|
|
}
|
|
|
|
this.addRoundWhiteCard_(card);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Add a white card to the round white cards area.
|
|
|
|
*
|
|
|
|
* @param {cah.card.WhiteCard}
|
|
|
|
* card Card to add to area.
|
|
|
|
* @private
|
|
|
|
*/
|
|
|
|
cah.Game.prototype.addRoundWhiteCard_ = function(card) {
|
2012-01-27 08:14:48 +00:00
|
|
|
var element = card.getElement();
|
|
|
|
$(".game_white_cards", this.element_).append(element);
|
|
|
|
$(element).css("transform-origin", "0 0");
|
|
|
|
|
|
|
|
var data = {
|
|
|
|
card : card,
|
|
|
|
};
|
|
|
|
$(element).on("mouseenter.round", data, cah.bind(this, this.roundCardMouseEnter_)).on(
|
|
|
|
"mouseleave.round", data, cah.bind(this, this.roundCardMouseLeave_)).on("click.round", data,
|
|
|
|
cah.bind(this, this.roundCardClick_));
|
|
|
|
|
2012-01-27 23:41:57 +00:00
|
|
|
this.roundCards_[card.getServerId()] = card;
|
|
|
|
|
2012-01-27 08:14:48 +00:00
|
|
|
this.resizeRoundCards_();
|
2012-01-25 08:03:41 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Event handler for hand card mouse enter.
|
|
|
|
*
|
|
|
|
* @param e
|
|
|
|
* @private
|
|
|
|
*/
|
|
|
|
cah.Game.prototype.handCardMouseEnter_ = function(e) {
|
2012-01-27 08:14:48 +00:00
|
|
|
$(e.data.card.getElement()).css("z-index", "2").animate({
|
2012-01-25 08:03:41 +00:00
|
|
|
scale : this.handCardLargeScale_,
|
|
|
|
width : this.handCardLargeSize_,
|
|
|
|
}, {
|
2012-01-23 07:58:36 +00:00
|
|
|
duration : 200,
|
2012-01-24 01:41:02 +00:00
|
|
|
queue : false,
|
2012-01-25 08:03:41 +00:00
|
|
|
});
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Event handler for hand card mouse leave.
|
|
|
|
*
|
|
|
|
* @param e
|
|
|
|
* @private
|
|
|
|
*/
|
|
|
|
cah.Game.prototype.handCardMouseLeave_ = function(e) {
|
|
|
|
$(e.data.card.getElement()).animate({
|
|
|
|
scale : this.handCardSmallScale_,
|
|
|
|
"z-index" : 1,
|
|
|
|
width : this.handCardSmallSize_,
|
|
|
|
}, {
|
|
|
|
duration : 200,
|
|
|
|
queue : false,
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
2012-01-27 08:14:48 +00:00
|
|
|
/**
|
|
|
|
* Event handler for round card mouse enter.
|
|
|
|
*
|
|
|
|
* @param e
|
|
|
|
* @private
|
|
|
|
*/
|
|
|
|
cah.Game.prototype.roundCardMouseEnter_ = function(e) {
|
|
|
|
$(e.data.card.getElement()).css("z-index", "2").animate({
|
|
|
|
scale : this.roundCardLargeScale_,
|
|
|
|
width : this.roundCardLargeSize_,
|
|
|
|
}, {
|
|
|
|
duration : 200,
|
|
|
|
queue : false,
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Event handler for round card mouse leave.
|
|
|
|
*
|
|
|
|
* @param e
|
|
|
|
* @private
|
|
|
|
*/
|
|
|
|
cah.Game.prototype.roundCardMouseLeave_ = function(e) {
|
|
|
|
$(e.data.card.getElement()).animate({
|
|
|
|
scale : this.roundCardSmallScale_,
|
|
|
|
"z-index" : 1,
|
|
|
|
width : this.roundCardSmallSize_,
|
|
|
|
}, {
|
|
|
|
duration : 200,
|
|
|
|
queue : false,
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
2012-01-25 08:03:41 +00:00
|
|
|
/**
|
|
|
|
* Event handler for window resize.
|
|
|
|
*
|
|
|
|
* @private
|
|
|
|
*/
|
|
|
|
cah.Game.prototype.windowResize_ = function() {
|
|
|
|
this.resizeHandCards_();
|
2012-01-27 08:14:48 +00:00
|
|
|
this.resizeRoundCards_();
|
2012-01-25 08:03:41 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Resize cards in hand to fit window size and hand size.
|
|
|
|
*
|
|
|
|
* @private
|
|
|
|
*/
|
|
|
|
cah.Game.prototype.resizeHandCards_ = function() {
|
|
|
|
var elems = $(".game_hand_cards .card_holder", this.element_);
|
|
|
|
var ct = elems.length;
|
|
|
|
this.handCardSmallSize_ = ($(".game_hand_cards", this.element_).width() - 20) / (ct + 1);
|
|
|
|
if (this.handCardSmallSize_ > 150) {
|
|
|
|
this.handCardSmallSize_ = 150;
|
|
|
|
}
|
|
|
|
this.handCardLargeSize_ = this.handCardSmallSize_ * 1.8;
|
|
|
|
this.handCardSmallScale_ = this.handCardSmallSize_ / 236;
|
|
|
|
this.handCardLargeScale_ = this.handCardSmallScale_ * 1.8;
|
|
|
|
elems.width(this.handCardSmallSize_).height(this.handCardSmallSize_).animate({
|
|
|
|
scale : this.handCardSmallScale_,
|
|
|
|
}, {
|
|
|
|
duration : 0,
|
|
|
|
});
|
2012-01-23 07:58:36 +00:00
|
|
|
};
|
|
|
|
|
2012-01-27 08:14:48 +00:00
|
|
|
/**
|
|
|
|
* Resize cards in the round white cards are to fit window size and number of players.
|
|
|
|
*
|
|
|
|
* TODO This will need some more consideration when there are multiple cards played per player.
|
|
|
|
*
|
|
|
|
* @private
|
|
|
|
*/
|
|
|
|
cah.Game.prototype.resizeRoundCards_ = function() {
|
|
|
|
var elems = $(".game_white_cards .card_holder", this.element_);
|
|
|
|
var ct = elems.length;
|
|
|
|
// 30 by experiment in chrome.
|
|
|
|
$(".game_right_side", this.element_).width(
|
|
|
|
$(window).width() - $(".game_left_side", this.element_).width() - 30);
|
|
|
|
this.roundCardSmallSize_ = ($(".game_white_cards", this.element_).width() - 20 - $(
|
|
|
|
".game_left_side", this.element_).width())
|
|
|
|
/ ct;
|
|
|
|
if (this.roundCardSmallSize_ > 236) {
|
|
|
|
this.roundCardSmallSize_ = 236;
|
|
|
|
}
|
|
|
|
if (this.roundCardSmallSize_ < 118) {
|
|
|
|
this.roundCardSmallSize_ = 118;
|
|
|
|
}
|
|
|
|
var maxScale = 236 / this.roundCardSmallSize_;
|
|
|
|
var scale = maxScale < 1.8 ? maxScale : 1.8;
|
|
|
|
this.roundCardLargeSize_ = this.roundCardSmallSize_ * scale;
|
|
|
|
if (this.roundCardLargeSize_ > 236) {
|
|
|
|
this.roundCardLargeSize_ = 236;
|
|
|
|
}
|
|
|
|
this.roundCardSmallScale_ = this.roundCardSmallSize_ / 236;
|
|
|
|
this.roundCardLargeScale_ = this.roundCardSmallScale_ * scale;
|
|
|
|
if (this.roundCardLargeScale_ > maxScale) {
|
|
|
|
this.roundCardLargeScale_ = maxScale;
|
|
|
|
}
|
|
|
|
elems.width(this.roundCardSmallSize_).height(this.roundCardSmallSize_).animate({
|
|
|
|
scale : this.roundCardSmallScale_,
|
|
|
|
}, {
|
|
|
|
duration : 0,
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
2012-01-23 07:58:36 +00:00
|
|
|
cah.Game.prototype.insertIntoDocument = function() {
|
|
|
|
$("#main_holder").empty().append(this.element_);
|
|
|
|
$("#info_area").empty().append(this.scoreboardElement_);
|
2012-01-23 21:20:15 +00:00
|
|
|
$("#leave_game").show();
|
2012-01-25 08:03:41 +00:00
|
|
|
this.windowResize_();
|
2012-01-23 07:58:36 +00:00
|
|
|
// TODO display a loading animation
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Update game status display.
|
|
|
|
*
|
|
|
|
* @param {Object}
|
|
|
|
* data Game data returned from server.
|
|
|
|
*/
|
|
|
|
cah.Game.prototype.updateGameStatus = function(data) {
|
|
|
|
if (data[cah.$.AjaxResponse.GAME_INFO][cah.$.GameInfo.HOST] == cah.nickname
|
|
|
|
&& data[cah.$.AjaxResponse.GAME_INFO][cah.$.GameInfo.STATE] == cah.$.GameState.LOBBY) {
|
2012-01-23 21:20:15 +00:00
|
|
|
$("#start_game").show();
|
2012-01-23 07:58:36 +00:00
|
|
|
} else {
|
2012-01-23 21:20:15 +00:00
|
|
|
$("#start_game").hide();
|
2012-01-22 01:34:18 +00:00
|
|
|
}
|
|
|
|
|
2012-01-27 03:25:40 +00:00
|
|
|
if (data[cah.$.AjaxResponse.GAME_INFO][cah.$.GameInfo.STATE] == cah.$.GameState.PLAYING) {
|
|
|
|
$(".game_white_cards", this.element_).empty();
|
|
|
|
}
|
|
|
|
|
2012-01-23 07:58:36 +00:00
|
|
|
var playerInfos = data[cah.$.AjaxResponse.PLAYER_INFO];
|
|
|
|
for ( var index in playerInfos) {
|
2012-01-27 02:07:39 +00:00
|
|
|
this.updateUserStatus(playerInfos[index]);
|
|
|
|
}
|
|
|
|
};
|
2012-01-25 00:20:43 +00:00
|
|
|
|
2012-01-27 02:07:39 +00:00
|
|
|
/**
|
|
|
|
* Update a single player's info.
|
|
|
|
*
|
|
|
|
* @param {Object}
|
|
|
|
* playerInfo The PlayerInfo from the server.
|
|
|
|
*/
|
|
|
|
cah.Game.prototype.updateUserStatus = function(playerInfo) {
|
|
|
|
var playerName = playerInfo[cah.$.GamePlayerInfo.NAME];
|
|
|
|
var playerStatus = playerInfo[cah.$.GamePlayerInfo.STATUS];
|
|
|
|
var panel = this.scoreCards_[playerName];
|
|
|
|
if (!panel) {
|
|
|
|
// new score panel
|
|
|
|
panel = new cah.GameScorePanel(playerName);
|
|
|
|
$(this.scoreboardElement_).append(panel.getElement());
|
|
|
|
this.scoreCards_[playerName] = panel;
|
|
|
|
}
|
|
|
|
var oldStatus = panel.getStatus();
|
|
|
|
panel.update(playerInfo[cah.$.GamePlayerInfo.SCORE], playerStatus);
|
|
|
|
|
|
|
|
if (playerName == cah.nickname) {
|
|
|
|
$(".game_message", this.element_).text(cah.$.GamePlayerStatus_msg_2[playerStatus]);
|
2012-01-27 08:18:36 +00:00
|
|
|
if (playerStatus == cah.$.GamePlayerStatus.PLAYING && this.handSelectedCard_ != null) {
|
|
|
|
$(".confirm_card", this.element_).removeAttr("disabled");
|
|
|
|
} else if (playerStatus == cah.$.GamePlayerStatus.JUDGING && this.roundSelectedCard_ != null) {
|
2012-01-27 02:07:39 +00:00
|
|
|
$(".confirm_card", this.element_).removeAttr("disabled");
|
|
|
|
} else {
|
2012-01-27 06:17:36 +00:00
|
|
|
$(".confirm_card", this.element_).attr("disabled", "disabled");
|
|
|
|
}
|
|
|
|
if (playerStatus != cah.$.GamePlayerStatus.PLAYING) {
|
2012-01-27 23:41:57 +00:00
|
|
|
if (this.handSelectedCard_ != null) {
|
|
|
|
// we have a card selected, but we're changing state. this almost certainly is an
|
|
|
|
// out-of-order reception of events. remove it from hand, we don't need to do anything else
|
|
|
|
this.removeCardFromHand(this.handSelectedCard_);
|
|
|
|
}
|
2012-01-27 02:07:39 +00:00
|
|
|
this.handSelectedCard_ = null;
|
|
|
|
$(".selected", $(".game_hand", this.element_)).removeClass("selected");
|
2012-01-25 00:20:43 +00:00
|
|
|
}
|
2012-01-31 00:35:06 +00:00
|
|
|
if (playerStatus == cah.$.GamePlayerStatus.HOST) {
|
|
|
|
$("#start_game").show();
|
|
|
|
}
|
2012-01-27 02:07:39 +00:00
|
|
|
}
|
2012-01-25 06:39:19 +00:00
|
|
|
|
2012-01-27 02:07:39 +00:00
|
|
|
if (playerStatus == cah.$.GamePlayerStatus.JUDGE
|
|
|
|
|| playerStatus == cah.$.GamePlayerStatus.JUDGING) {
|
|
|
|
this.judge_ = playerName;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (oldStatus == cah.$.GamePlayerStatus.PLAYING && playerStatus == cah.$.GamePlayerStatus.IDLE) {
|
2012-01-27 06:17:36 +00:00
|
|
|
// this player played a card. display a face-down white card in the area, or nothing if it is
|
|
|
|
// us. we put the card there when we get the acknowledgement from the server from playing.
|
2012-01-28 01:01:51 +00:00
|
|
|
// also, don't put the card up if we're already into judging state -- we already displayed all
|
|
|
|
// of the cards!
|
|
|
|
if (playerName != cah.nickname && this.state_ == cah.$.GameState.PLAYING) {
|
2012-01-27 06:17:36 +00:00
|
|
|
this.addRoundWhiteCard_(new cah.card.WhiteCard());
|
2012-01-25 06:39:19 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2012-01-27 23:41:57 +00:00
|
|
|
/**
|
|
|
|
* Round has completed. Update display of round cards to show winner.
|
|
|
|
*
|
|
|
|
* @param {Object}
|
|
|
|
* data Data from server.
|
|
|
|
*/
|
|
|
|
cah.Game.prototype.roundComplete = function(data) {
|
|
|
|
var card = this.roundCards_[data[cah.$.LongPollResponse.WINNING_CARD]];
|
2012-01-29 07:33:21 +00:00
|
|
|
$(".card", card.getElement()).addClass("selected");
|
2012-01-27 23:41:57 +00:00
|
|
|
var scoreCard = this.scoreCards_[data[cah.$.LongPollResponse.ROUND_WINNER]];
|
|
|
|
$(scoreCard.getElement()).addClass("selected");
|
2012-01-30 08:35:56 +00:00
|
|
|
$(".confirm_card", this.element_).attr("disabled", "disabled");
|
2012-01-27 23:41:57 +00:00
|
|
|
cah.log.status("The next round will begin in "
|
|
|
|
+ (data[cah.$.LongPollResponse.INTERMISSION] / 1000) + " seconds.");
|
|
|
|
};
|
|
|
|
|
2012-01-31 00:35:06 +00:00
|
|
|
/**
|
|
|
|
* Notify the player that a deck has been reshuffled.
|
|
|
|
*
|
|
|
|
* @param {String}
|
|
|
|
* deck Deck name which has been reshuffled.
|
|
|
|
*/
|
|
|
|
cah.Game.prototype.reshuffle = function(deck) {
|
|
|
|
cah.log.status("The " + deck + " deck has been reshuffled.");
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Notify the player that the judge has left the game and cards are being returned to hands.
|
|
|
|
*/
|
|
|
|
cah.Game.prototype.judgeLeft = function() {
|
|
|
|
cah.log
|
|
|
|
.status("The judge has left the game. Cards played this round are being returned to hands.");
|
|
|
|
};
|
|
|
|
|
2012-01-25 06:39:19 +00:00
|
|
|
/**
|
|
|
|
* Event handler for confirm selection button.
|
|
|
|
*
|
|
|
|
* @private
|
|
|
|
*/
|
|
|
|
cah.Game.prototype.confirmClick_ = function() {
|
2012-01-27 02:07:39 +00:00
|
|
|
if (this.judge_ == cah.nickname) {
|
2012-01-27 23:41:57 +00:00
|
|
|
if (this.roundSelectedCard_ != null) {
|
|
|
|
// TODO fix for multiple select
|
|
|
|
cah.Ajax.build(cah.$.AjaxOperation.JUDGE_SELECT).withGameId(this.id_).withCardId(
|
|
|
|
this.roundSelectedCard_.getServerId()).run();
|
|
|
|
}
|
2012-01-27 02:07:39 +00:00
|
|
|
} else {
|
|
|
|
if (this.handSelectedCard_ != null) {
|
|
|
|
cah.Ajax.build(cah.$.AjaxOperation.PLAY_CARD).withGameId(this.id_).withCardId(
|
|
|
|
this.handSelectedCard_.getServerId()).run();
|
|
|
|
}
|
|
|
|
}
|
2012-01-25 06:39:19 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Event handler for clicking on a card in the hand.
|
|
|
|
*
|
|
|
|
* @param e
|
|
|
|
* @private
|
|
|
|
*/
|
|
|
|
cah.Game.prototype.handCardClick_ = function(e) {
|
|
|
|
// judge can't select a card.
|
|
|
|
if (this.judge_ == cah.nickname) {
|
|
|
|
return;
|
|
|
|
}
|
2012-01-27 03:25:40 +00:00
|
|
|
// this player isn't in playing state
|
|
|
|
var scorecard = this.scoreCards_[cah.nickname];
|
|
|
|
if (scorecard && scorecard.getStatus() != cah.$.GamePlayerStatus.PLAYING) {
|
|
|
|
return;
|
|
|
|
}
|
2012-01-25 06:39:19 +00:00
|
|
|
/** @type {cah.card.WhiteCard} */
|
|
|
|
var card = e.data.card;
|
|
|
|
|
|
|
|
// remove style from existing selected card
|
|
|
|
if (this.handSelectedCard_) {
|
|
|
|
$(".card", this.handSelectedCard_.getElement()).removeClass("selected");
|
|
|
|
}
|
|
|
|
|
|
|
|
// if the user clicked on the same card, deselect it.
|
|
|
|
if (card == this.handSelectedCard_) {
|
|
|
|
this.handSelectedCard_ = null;
|
|
|
|
$(".confirm_card", this.element_).attr("disabled", "disabled");
|
|
|
|
} else {
|
|
|
|
this.handSelectedCard_ = card;
|
|
|
|
$(".card", card.getElement()).addClass("selected");
|
|
|
|
$(".confirm_card", this.element_).removeAttr("disabled");
|
2012-01-23 07:58:36 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2012-01-27 08:14:48 +00:00
|
|
|
/**
|
|
|
|
* Event handler for clicking on a card in the round.
|
|
|
|
*
|
|
|
|
* @param e
|
|
|
|
* @private
|
|
|
|
*/
|
|
|
|
cah.Game.prototype.roundCardClick_ = function(e) {
|
|
|
|
// this player isn't in judging state.
|
|
|
|
var scorecard = this.scoreCards_[cah.nickname];
|
|
|
|
if (scorecard && scorecard.getStatus() != cah.$.GamePlayerStatus.JUDGING) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
/** @type {cah.card.WhiteCard} */
|
|
|
|
var card = e.data.card;
|
|
|
|
|
|
|
|
// remove style from existing selected card
|
|
|
|
if (this.roundSelectedCard_) {
|
|
|
|
$(".card", this.roundSelectedCard_.getElement()).removeClass("selected");
|
|
|
|
}
|
|
|
|
|
|
|
|
// if the user clicked on the same card, deselect it.
|
|
|
|
if (card == this.roundSelectedCard_) {
|
|
|
|
this.roundSelectedCard_ = null;
|
|
|
|
$(".confirm_card", this.element_).attr("disabled", "disabled");
|
|
|
|
} else {
|
|
|
|
this.roundSelectedCard_ = card;
|
|
|
|
$(".card", card.getElement()).addClass("selected");
|
|
|
|
$(".confirm_card", this.element_).removeAttr("disabled");
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2012-01-23 21:20:15 +00:00
|
|
|
/**
|
|
|
|
* Event handler for leave game button.
|
|
|
|
*
|
|
|
|
* @private
|
|
|
|
*/
|
|
|
|
cah.Game.prototype.leaveGameClick_ = function() {
|
2012-01-23 23:06:20 +00:00
|
|
|
// TODO make sure everything cleans up right, I got an error when I tried to start a different
|
|
|
|
// game after leaving one
|
2012-01-23 21:20:15 +00:00
|
|
|
cah.Ajax.build(cah.$.AjaxOperation.LEAVE_GAME).withGameId(this.id_).run();
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Event handler for start game button.
|
|
|
|
*
|
|
|
|
* @private
|
|
|
|
*/
|
|
|
|
cah.Game.prototype.startGameClick_ = function() {
|
2012-01-25 00:20:43 +00:00
|
|
|
// TODO make the button go disabled
|
2012-01-23 23:06:20 +00:00
|
|
|
cah.Ajax.build(cah.$.AjaxOperation.START_GAME).withGameId(this.id_).run();
|
2012-01-23 21:20:15 +00:00
|
|
|
};
|
|
|
|
|
2012-01-25 00:20:43 +00:00
|
|
|
cah.Game.prototype.startGameComplete = function() {
|
|
|
|
$("#start_game").hide();
|
|
|
|
};
|
|
|
|
|
2012-01-27 02:07:39 +00:00
|
|
|
cah.Game.prototype.playCardComplete = function() {
|
|
|
|
if (this.handSelectedCard_) {
|
|
|
|
$(".card", this.handSelectedCard_.getElement()).removeClass("selected");
|
|
|
|
// TODO support for multiple play
|
|
|
|
this.myPlayedCard_ = this.handSelectedCard_;
|
|
|
|
this.removeCardFromHand(this.handSelectedCard_);
|
2012-01-27 06:17:36 +00:00
|
|
|
this.addRoundWhiteCard_(this.handSelectedCard_);
|
2012-01-27 02:07:39 +00:00
|
|
|
this.handSelectedCard_ = null;
|
|
|
|
}
|
|
|
|
$(".confirm_card", this.element_).attr("disabled", "disabled");
|
|
|
|
};
|
|
|
|
|
2012-01-23 21:20:15 +00:00
|
|
|
/**
|
|
|
|
* Free resources used by this game and remove from the document.
|
|
|
|
*/
|
|
|
|
cah.Game.prototype.dispose = function() {
|
|
|
|
$(this.element_).remove();
|
|
|
|
$(this.scoreboardElement_).remove();
|
2012-01-24 01:41:02 +00:00
|
|
|
$("#leave_game").unbind().hide();
|
|
|
|
$("#start_game").unbind().hide();
|
2012-01-25 08:03:41 +00:00
|
|
|
$(window).off("resize.game_" + this.id_);
|
2012-01-23 21:20:15 +00:00
|
|
|
};
|
|
|
|
|
2012-01-23 21:37:11 +00:00
|
|
|
/**
|
|
|
|
* A player has joined the game.
|
|
|
|
*
|
|
|
|
* @param {String}
|
|
|
|
* player Player that joined.
|
|
|
|
*/
|
|
|
|
cah.Game.prototype.playerJoin = function(player) {
|
|
|
|
if (player != cah.nickname) {
|
|
|
|
cah.log.status(player + " has joined the game.");
|
|
|
|
this.refreshGameStatus();
|
|
|
|
} else {
|
|
|
|
cah.log.status("You have joined the game.");
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* A player has left the game.
|
|
|
|
*
|
|
|
|
* @param {String}
|
|
|
|
* player Player that left.
|
|
|
|
*/
|
|
|
|
cah.Game.prototype.playerLeave = function(player) {
|
|
|
|
if (player != cah.nickname) {
|
|
|
|
cah.log.status(player + " has left the game.");
|
|
|
|
this.refreshGameStatus();
|
|
|
|
} else {
|
|
|
|
cah.log.status("You have left the game.");
|
|
|
|
}
|
|
|
|
var scorecard = this.scoreCards_[player];
|
|
|
|
if (scorecard) {
|
|
|
|
$(scorecard.getElement()).remove();
|
|
|
|
}
|
|
|
|
delete this.scoreCards_[player];
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Refresh game scoreboard, etc.
|
|
|
|
*/
|
|
|
|
cah.Game.prototype.refreshGameStatus = function() {
|
|
|
|
cah.Ajax.build(cah.$.AjaxOperation.GET_GAME_INFO).withGameId(this.id_).run();
|
|
|
|
};
|
|
|
|
|
2012-01-25 00:20:43 +00:00
|
|
|
/**
|
|
|
|
* The game state has changed.
|
|
|
|
*
|
|
|
|
* @param {Object}
|
|
|
|
* data Data from server.
|
|
|
|
*/
|
|
|
|
cah.Game.prototype.stateChange = function(data) {
|
|
|
|
this.state_ = data[cah.$.LongPollResponse.GAME_STATE];
|
|
|
|
|
2012-01-27 23:41:57 +00:00
|
|
|
$(".scorecard", this.scoreboardElement_).removeClass("selected");
|
|
|
|
|
2012-01-25 00:20:43 +00:00
|
|
|
switch (this.state_) {
|
|
|
|
case cah.$.GameState.LOBBY:
|
2012-01-27 06:17:36 +00:00
|
|
|
var handCount = this.hand_.length;
|
|
|
|
for ( var i = 0; i < handCount; i++) {
|
|
|
|
this.removeCardFromHand(this.hand_[0]);
|
|
|
|
}
|
|
|
|
this.handSelectedCard_ = null;
|
|
|
|
this.myPlayedCard_ = null;
|
|
|
|
this.judge_ = null;
|
|
|
|
$(".confirm_card", this.element_).attr("disabled", "disabled");
|
|
|
|
$(".game_black_card", this.element_).empty();
|
2012-01-27 23:41:57 +00:00
|
|
|
for ( var index in this.roundCards_) {
|
|
|
|
$(this.roundCards_[index]).off(".round");
|
|
|
|
}
|
|
|
|
this.roundCards_ = {};
|
2012-01-27 06:17:36 +00:00
|
|
|
$(".game_white_cards", this.element_).empty();
|
2012-01-25 00:20:43 +00:00
|
|
|
break;
|
2012-01-27 06:17:36 +00:00
|
|
|
|
2012-01-25 00:20:43 +00:00
|
|
|
case cah.$.GameState.PLAYING:
|
|
|
|
this.refreshGameStatus();
|
|
|
|
this.setBlackCard(data[cah.$.LongPollResponse.BLACK_CARD]);
|
|
|
|
break;
|
2012-01-27 06:17:36 +00:00
|
|
|
|
2012-01-25 00:20:43 +00:00
|
|
|
case cah.$.GameState.JUDGING:
|
2012-01-27 06:17:36 +00:00
|
|
|
$(".game_white_cards", this.element_).empty();
|
|
|
|
this.setRoundWhiteCards(data[cah.$.LongPollResponse.WHITE_CARDS]);
|
2012-01-25 00:20:43 +00:00
|
|
|
break;
|
2012-01-27 06:17:36 +00:00
|
|
|
|
2012-01-25 00:20:43 +00:00
|
|
|
default:
|
|
|
|
cah.log.error("Game " + this.id_ + " changed to unknown state " + this.state_);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2012-01-23 07:58:36 +00:00
|
|
|
// ///////////////////////////////////////////////
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Create a scoreboard panel for a player.
|
|
|
|
*
|
|
|
|
* @param {String}
|
|
|
|
* player Player name.
|
|
|
|
* @constructor
|
|
|
|
*/
|
|
|
|
cah.GameScorePanel = function(player) {
|
|
|
|
/**
|
|
|
|
* Player name.
|
|
|
|
*
|
|
|
|
* @type {String}
|
|
|
|
* @private
|
|
|
|
*/
|
|
|
|
this.player_ = player;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @type {HTMLDivElement}
|
|
|
|
* @private
|
|
|
|
*/
|
|
|
|
this.element_ = $("#scorecard_template").clone()[0];
|
|
|
|
$(this.element_).removeClass("hide");
|
|
|
|
|
|
|
|
/**
|
|
|
|
* The score on this scorecard.
|
|
|
|
*
|
|
|
|
* @type {number}
|
|
|
|
* @private
|
|
|
|
*/
|
|
|
|
this.score_ = 0;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* The status of the player for this scorecard.
|
|
|
|
*
|
|
|
|
* @type {cah.$.GamePlayerStatus}
|
|
|
|
* @private
|
|
|
|
*/
|
|
|
|
this.status_ = cah.$.GamePlayerStatus.IDLE;
|
|
|
|
|
|
|
|
jQuery(".scorecard_player", this.element_).text(player);
|
|
|
|
this.update(this.score_, this.status_);
|
|
|
|
};
|
|
|
|
|
|
|
|
cah.GameScorePanel.prototype.getElement = function() {
|
|
|
|
return this.element_;
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Update the score panel.
|
|
|
|
*
|
|
|
|
* TODO add some color for different statuses
|
|
|
|
*
|
|
|
|
* @param {number}
|
|
|
|
* score The player's score
|
|
|
|
* @param {cah.$.GamePlayerStatus}
|
|
|
|
* status The player's status.
|
|
|
|
*/
|
|
|
|
cah.GameScorePanel.prototype.update = function(score, status) {
|
|
|
|
this.score_ = score;
|
|
|
|
this.status_ = status;
|
2012-01-30 08:35:56 +00:00
|
|
|
$(".scorecard_score", this.element_).text(score);
|
|
|
|
$(".scorecard_status", this.element_).text(cah.$.GamePlayerStatus_msg[status]);
|
|
|
|
$(".scorecard_s", this.element_).text(score == 1 ? "" : "s");
|
2012-01-23 07:58:36 +00:00
|
|
|
};
|
2012-01-24 01:41:02 +00:00
|
|
|
|
2012-01-27 02:07:39 +00:00
|
|
|
/**
|
|
|
|
* @returns {cah.$.GamePlayerStatus} The status of the player represented by this panel.
|
|
|
|
*/
|
|
|
|
cah.GameScorePanel.prototype.getStatus = function() {
|
|
|
|
return this.status_;
|
|
|
|
};
|
|
|
|
|
2012-01-29 07:33:21 +00:00
|
|
|
/**
|
|
|
|
* confirm card as judge without selecting a round card did ... something
|
|
|
|
*
|
|
|
|
* don't always see your card after playing it
|
2012-01-28 01:01:51 +00:00
|
|
|
*/
|