From 315549d87f4e2a55d9d3f646d0961335ecfd9944 Mon Sep 17 00:00:00 2001 From: Andy Janata Date: Sun, 18 Mar 2012 21:20:48 -0700 Subject: [PATCH] game passwords, and display more game information in the lobby list --- WebContent/game.jsp | 13 ++++++-- WebContent/js/cah.ajax.builder.js | 11 +++++++ WebContent/js/cah.constants.js | 6 ++++ WebContent/js/cah.game.js | 16 ++++++++-- WebContent/js/cah.gamelist.js | 32 ++++++++++++++++++- src/net/socialgamer/cah/Constants.java | 9 +++++- src/net/socialgamer/cah/data/Game.java | 26 +++++++++++++-- .../cah/handlers/ChangeGameOptionHandler.java | 8 ++++- .../cah/handlers/GetGameInfoHandler.java | 2 +- .../cah/handlers/JoinGameHandler.java | 8 +++++ 10 files changed, 120 insertions(+), 11 deletions(-) diff --git a/WebContent/game.jsp b/WebContent/game.jsp index 33375be..7d2b4f4 100644 --- a/WebContent/game.jsp +++ b/WebContent/game.jsp @@ -118,10 +118,15 @@ HttpSession hSession = request.getSession(true);
Game ### status -
+
+ Goal: + / Cards: +
Host: host
- Players: host, player1, player2 + Players ( of + ): + host, player1, player2
@@ -292,6 +297,10 @@ HttpSession hSession = request.getSession(true); +
+ + + You must click outside the box to apply the password.
diff --git a/WebContent/js/cah.ajax.builder.js b/WebContent/js/cah.ajax.builder.js index 9fb075f..c881402 100644 --- a/WebContent/js/cah.ajax.builder.js +++ b/WebContent/js/cah.ajax.builder.js @@ -166,6 +166,17 @@ cah.ajax.Builder.prototype.withScoreLimit = function(scoreLimit) { return this; }; +/** + * @param {string} + * password Password field to use in the request. + * @returns {cah.ajax.Builder} This object. + */ +cah.ajax.Builder.prototype.withPassword = function(password) { + this.assertNotExecuted_(); + this.data[cah.$.AjaxRequest.PASSWORD] = password; + return this; +}; + /** * Assert that the request from this builder has not already run. Throws an exception if it has. * diff --git a/WebContent/js/cah.constants.js b/WebContent/js/cah.constants.js index 94de955..c12be91 100644 --- a/WebContent/js/cah.constants.js +++ b/WebContent/js/cah.constants.js @@ -33,6 +33,7 @@ cah.$.AjaxRequest.GAME_ID = "gid"; cah.$.AjaxRequest.CARD_SET = "cs"; cah.$.AjaxRequest.SERIAL = "s"; cah.$.AjaxRequest.PLAYER_LIMIT = "pL"; +cah.$.AjaxRequest.PASSWORD = "pw"; cah.$.AjaxRequest.OP = "o"; cah.$.AjaxRequest.SCORE_LIMIT = "sl"; cah.$.AjaxRequest.NICKNAME = "n"; @@ -92,6 +93,7 @@ cah.$.ErrorCode.NO_SESSION = "ns"; cah.$.ErrorCode.NOT_REGISTERED = "nr"; cah.$.ErrorCode.NOT_JUDGE = "nj"; cah.$.ErrorCode.OP_NOT_SPECIFIED = "ons"; +cah.$.ErrorCode.WRONG_PASSWORD = "wp"; cah.$.ErrorCode.NOT_IN_THAT_GAME = "nitg"; cah.$.ErrorCode.NICK_IN_USE = "niu"; cah.$.ErrorCode.SERVER_ERROR = "serr"; @@ -127,6 +129,7 @@ cah.$.ErrorCode_msg['ig'] = "Invalid game specified."; cah.$.ErrorCode_msg['nns'] = "No nickname specified."; cah.$.ErrorCode_msg['ngh'] = "Only the game host can do that."; cah.$.ErrorCode_msg['serr'] = "An error occured on the server."; +cah.$.ErrorCode_msg['wp'] = "That password is incorrect."; cah.$.ErrorCode_msg['as'] = "The game has already started."; cah.$.ErrorCode_msg['se'] = "Your session has expired. Refresh the page."; cah.$.ErrorCode_msg['in'] = "Nickname must contain only upper and lower case letters, numbers, or underscores, must be 3 to 30 characters long, and must not start with a number."; @@ -145,6 +148,8 @@ cah.$.GameInfo.PLAYERS = "P"; cah.$.GameInfo.CARD_SET = "cs"; cah.$.GameInfo.ID = "gid"; cah.$.GameInfo.PLAYER_LIMIT = "pL"; +cah.$.GameInfo.PASSWORD = "pw"; +cah.$.GameInfo.HAS_PASSWORD = "hp"; cah.$.GameInfo.SCORE_LIMIT = "sl"; cah.$.GamePlayerInfo = function() { @@ -238,6 +243,7 @@ cah.$.LongPollResponse.GAME_STATE = "gs"; cah.$.LongPollResponse.NICKNAME = "n"; cah.$.LongPollResponse.PLAY_TIMER = "Pt"; cah.$.LongPollResponse.MESSAGE = "m"; +cah.$.LongPollResponse.GAME_INFO = "gi"; cah.$.LongPollResponse.ERROR = "e"; cah.$.LongPollResponse.EVENT = "E"; cah.$.LongPollResponse.FROM = "f"; diff --git a/WebContent/js/cah.game.js b/WebContent/js/cah.game.js index 5bf666f..141083b 100644 --- a/WebContent/js/cah.game.js +++ b/WebContent/js/cah.game.js @@ -69,9 +69,13 @@ cah.Game = function(id) { $("#score_limit_template_label", this.optionsElement_).attr("for", "score_limit_" + id); $("#player_limit_template_label", this.optionsElement_).attr("for", "player_limit_" + id); $("#card_set_template_label", this.optionsElement_).attr("for", "card_set_" + id); + $("#game_password_template_label", this.optionsElement_).attr("for", "game_password_" + id); + $("#score_limit_template", this.optionsElement_).attr("id", "score_limit_" + id); $("#player_limit_template", this.optionsElement_).attr("id", "player_limit_" + id); $("#card_set_template", this.optionsElement_).attr("id", "card_set_" + id); + $("#game_password_template", this.optionsElement_).attr("id", "game_password_" + id); + $("label", this.optionsElement_).removeAttr("id"); $(".game_options", this.element_).replaceWith(this.optionsElement_); @@ -231,7 +235,8 @@ cah.Game = function(id) { $("#start_game").click(cah.bind(this, this.startGameClick_)); $(".confirm_card", this.element_).click(cah.bind(this, this.confirmClick_)); $(".game_show_last_round", this.element_).click(cah.bind(this, this.showLastRoundClick_)); - $("select", this.element_).change(cah.bind(this, this.optionChanged_)); + $("select", this.optionsElement_).change(cah.bind(this, this.optionChanged_)); + $("input", this.optionsElement_).blur(cah.bind(this, this.optionChanged_)); $(window).on("resize.game_" + this.id_, cah.bind(this, this.windowResize_)); }; @@ -644,6 +649,8 @@ cah.Game.prototype.updateGameStatus = function(data) { data[cah.$.AjaxResponse.GAME_INFO][cah.$.GameInfo.PLAYER_LIMIT]); $(".card_set", this.optionsElement_).val( data[cah.$.AjaxResponse.GAME_INFO][cah.$.GameInfo.CARD_SET]); + $(".game_password", this.optionsElement_).val( + data[cah.$.AjaxResponse.GAME_INFO][cah.$.GameInfo.PASSWORD]); var playerInfos = data[cah.$.AjaxResponse.PLAYER_INFO]; for ( var index in playerInfos) { @@ -1069,9 +1076,11 @@ cah.Game.prototype.showOptions_ = function() { cah.Game.prototype.updateOptionsEnabled_ = function() { if (this.host_ == cah.nickname) { $("select", this.optionsElement_).removeAttr("disabled"); + $("input", this.optionsElement_).removeAttr("disabled"); $(".options_host_only", this.optionsElement_).addClass("hide"); } else { $("select", this.optionsElement_).attr("disabled", "disabled"); + $("input", this.optionsElement_).attr("disabled", "disabled"); $(".options_host_only", this.optionsElement_).removeClass("hide"); } }; @@ -1086,7 +1095,8 @@ cah.Game.prototype.optionChanged_ = function(e) { cah.Ajax.build(cah.$.AjaxOperation.CHANGE_GAME_OPTIONS).withGameId(this.id_).withScoreLimit( $(".score_limit", this.optionsElement_).val()).withPlayerLimit( $(".player_limit", this.optionsElement_).val()).withCardSet( - $(".card_set", this.optionsElement_).val()).run(); + $(".card_set", this.optionsElement_).val()).withPassword( + $(".game_password", this.optionsElement_).val()).run(); }; /** @@ -1095,7 +1105,7 @@ cah.Game.prototype.optionChanged_ = function(e) { * data Event data from server. */ cah.Game.prototype.optionsChanged = function(data) { - this.refreshGameStatus(); + this.updateGameStatus(data); }; // /////////////////////////////////////////////// diff --git a/WebContent/js/cah.gamelist.js b/WebContent/js/cah.gamelist.js index 785e199..35d1b0b 100644 --- a/WebContent/js/cah.gamelist.js +++ b/WebContent/js/cah.gamelist.js @@ -163,6 +163,14 @@ cah.GameListLobby = function(parentElem, data) { */ this.element_ = $("#gamelist_lobby_template").clone()[0]; + /** + * This game's data. + * + * @type {object} + * @private + */ + this.data_ = data; + this.element_.id = "gamelist_lobby_" + this.id_; $(parentElem).append(this.element_); $(this.element_).removeClass("hide"); @@ -172,13 +180,35 @@ cah.GameListLobby = function(parentElem, data) { var statusMessage = cah.$.GameState_msg[data[cah.$.GameInfo.STATE]]; $(".gamelist_lobby_status", this.element_).text(statusMessage); $(".gamelist_lobby_join", this.element_).click(cah.bind(this, this.joinClick)); + $(".gamelist_lobby_player_count", this.element_).text(data[cah.$.GameInfo.PLAYERS].length); + $(".gamelist_lobby_max_players", this.element_).text(data[cah.$.GameInfo.PLAYER_LIMIT]); + $(".gamelist_lobby_goal", this.element_).text(data[cah.$.GameInfo.SCORE_LIMIT]); + // TODO make this better when we have more card sets + var cardset = "All"; + if (data[cah.$.GameInfo.CARD_SET] == 1) { + cardset = "First Edition"; + } else if (data[cah.$.GameInfo.CARD_SET] == 2) { + cardset = "Second Edition"; + } + $(".gamelist_lobby_cardset", this.element_).text(cardset); + + if (data[cah.$.GameInfo.HAS_PASSWORD]) { + $(".gamelist_lobby_join", this.element_).val("Join\n(Passworded)"); + } }; /** * Event handler for clicking the Join button in a game lobby. */ cah.GameListLobby.prototype.joinClick = function() { - cah.Ajax.build(cah.$.AjaxOperation.JOIN_GAME).withGameId(this.id_).run(); + var password = ""; + if (this.data_[cah.$.GameInfo.HAS_PASSWORD]) { + password = prompt("Enter the game's password."); + if (password == null) { + password = ""; + } + } + cah.Ajax.build(cah.$.AjaxOperation.JOIN_GAME).withGameId(this.id_).withPassword(password).run(); }; /** diff --git a/src/net/socialgamer/cah/Constants.java b/src/net/socialgamer/cah/Constants.java index 1f8d689..237aac8 100644 --- a/src/net/socialgamer/cah/Constants.java +++ b/src/net/socialgamer/cah/Constants.java @@ -180,6 +180,7 @@ public class Constants { MESSAGE("m"), NICKNAME("n"), OP("o"), + PASSWORD("pw"), PLAYER_LIMIT("pL"), SCORE_LIMIT("sl"), SERIAL("s"); @@ -282,7 +283,8 @@ public class Constants { SERVER_ERROR("serr", "An error occured on the server."), SESSION_EXPIRED("se", "Your session has expired. Refresh the page."), TOO_MANY_GAMES("tmg", "There are too many games already in progress. Either join " + - "an existing game, or wait for one to become available."); + "an existing game, or wait for one to become available."), + WRONG_PASSWORD("wp", "That password is incorrect."); private final String code; private final String message; @@ -374,6 +376,8 @@ public class Constants { FROM("f"), @DuplicationAllowed GAME_ID(AjaxResponse.GAME_ID), + @DuplicationAllowed + GAME_INFO(AjaxResponse.GAME_INFO), GAME_STATE("gs"), @DuplicationAllowed HAND(AjaxResponse.HAND), @@ -500,10 +504,13 @@ public class Constants { public enum GameInfo { @DuplicationAllowed CARD_SET(AjaxRequest.CARD_SET), + HAS_PASSWORD("hp"), HOST("H"), @DuplicationAllowed ID(AjaxRequest.GAME_ID), @DuplicationAllowed + PASSWORD(AjaxRequest.PASSWORD), + @DuplicationAllowed PLAYER_LIMIT(AjaxRequest.PLAYER_LIMIT), PLAYERS("P"), @DuplicationAllowed diff --git a/src/net/socialgamer/cah/data/Game.java b/src/net/socialgamer/cah/data/Game.java index 160dadf..f2c0857 100644 --- a/src/net/socialgamer/cah/data/Game.java +++ b/src/net/socialgamer/cah/data/Game.java @@ -122,6 +122,7 @@ public class Game { private final Object nextRoundTimerLock = new Object(); private int scoreGoal = 8; private int cardSet = 2; + private String password = ""; /** * Create a new game. @@ -339,20 +340,37 @@ public class Game { return id; } - public void updateGameSettings(final int scoreLimit, final int playerLimit, final int cardSet1) { + public String getPassword() { + return password; + } + + public void updateGameSettings(final int scoreLimit, final int playerLimit, final int cardSet1, + final String password1) { this.scoreGoal = scoreLimit; this.maxPlayers = playerLimit; this.cardSet = cardSet1; + this.password = password1; final HashMap data = getEventMap(); data.put(LongPollResponse.EVENT, LongPollEvent.GAME_OPTIONS_CHANGED.toString()); + data.put(LongPollResponse.GAME_INFO, getInfo(true)); broadcastToPlayers(MessageType.GAME_EVENT, data); } /** - * @return This game's general information: ID, host, state, player list. + * @return This game's general information: ID, host, state, player list, etc. */ public Map getInfo() { + return getInfo(false); + } + + /** + * @param includePassword + * Include the actual password with the information. This should only be + * sent to people in the game. + * @return This game's general information: ID, host, state, player list, etc. + */ + public Map getInfo(final boolean includePassword) { final Map info = new HashMap(); info.put(GameInfo.ID, id); info.put(GameInfo.HOST, host.toString()); @@ -360,6 +378,10 @@ public class Game { info.put(GameInfo.CARD_SET, cardSet); info.put(GameInfo.PLAYER_LIMIT, maxPlayers); info.put(GameInfo.SCORE_LIMIT, scoreGoal); + if (includePassword) { + info.put(GameInfo.PASSWORD, password); + } + info.put(GameInfo.HAS_PASSWORD, password != null && !password.equals("")); synchronized (players) { final List playerNames = new ArrayList(players.size()); for (final Player player : players) { diff --git a/src/net/socialgamer/cah/handlers/ChangeGameOptionHandler.java b/src/net/socialgamer/cah/handlers/ChangeGameOptionHandler.java index bc8ce3c..532fa93 100644 --- a/src/net/socialgamer/cah/handlers/ChangeGameOptionHandler.java +++ b/src/net/socialgamer/cah/handlers/ChangeGameOptionHandler.java @@ -41,10 +41,16 @@ public class ChangeGameOptionHandler extends GameWithPlayerHandler { final int scoreLimit = Integer.parseInt(request.getParameter(AjaxRequest.SCORE_LIMIT)); final int playerLimit = Integer.parseInt(request.getParameter(AjaxRequest.PLAYER_LIMIT)); final int cardSet = Integer.parseInt(request.getParameter(AjaxRequest.CARD_SET)); - game.updateGameSettings(scoreLimit, playerLimit, cardSet); + String password = request.getParameter(AjaxRequest.PASSWORD); + if (password == null) { + password = ""; + } + game.updateGameSettings(scoreLimit, playerLimit, cardSet, password); } catch (final NumberFormatException nfe) { return error(ErrorCode.BAD_REQUEST); } + + gameManager.broadcastGameListRefresh(); return data; } } diff --git a/src/net/socialgamer/cah/handlers/GetGameInfoHandler.java b/src/net/socialgamer/cah/handlers/GetGameInfoHandler.java index cf15109..b954042 100644 --- a/src/net/socialgamer/cah/handlers/GetGameInfoHandler.java +++ b/src/net/socialgamer/cah/handlers/GetGameInfoHandler.java @@ -58,7 +58,7 @@ public class GetGameInfoHandler extends GameWithPlayerHandler { final HttpSession session, final User user, final Game game) { final Map data = new HashMap(); - data.put(AjaxResponse.GAME_INFO, game.getInfo()); + data.put(AjaxResponse.GAME_INFO, game.getInfo(true)); data.put(AjaxResponse.PLAYER_INFO, game.getAllPlayerInfo()); return data; } diff --git a/src/net/socialgamer/cah/handlers/JoinGameHandler.java b/src/net/socialgamer/cah/handlers/JoinGameHandler.java index 6cbbdb9..9c1ce63 100644 --- a/src/net/socialgamer/cah/handlers/JoinGameHandler.java +++ b/src/net/socialgamer/cah/handlers/JoinGameHandler.java @@ -29,6 +29,7 @@ import java.util.Map; import javax.servlet.http.HttpSession; import net.socialgamer.cah.Constants.AjaxOperation; +import net.socialgamer.cah.Constants.AjaxRequest; import net.socialgamer.cah.Constants.ErrorCode; import net.socialgamer.cah.Constants.ReturnableData; import net.socialgamer.cah.RequestWrapper; @@ -59,6 +60,13 @@ public class JoinGameHandler extends GameHandler { final HttpSession session, final User user, final Game game) { final Map data = new HashMap(); + final String password = request.getParameter(AjaxRequest.PASSWORD); + final String gamePassword = game.getPassword(); + if (gamePassword != null && !gamePassword.equals("")) { + if (password == null || !gamePassword.equals(password)) { + return error(ErrorCode.WRONG_PASSWORD); + } + } try { game.addPlayer(user); } catch (final IllegalStateException e) {