diff --git a/WebContent/game.jsp b/WebContent/game.jsp
index 9a49550..9ff2f79 100644
--- a/WebContent/game.jsp
+++ b/WebContent/game.jsp
@@ -258,12 +258,12 @@ HttpSession hSession = request.getSession(true);
- Only the game host can change options.
+ Only the game host can change options.
Game options:
-
diff --git a/WebContent/js/cah.ajax.builder.js b/WebContent/js/cah.ajax.builder.js
index 3919831..9fb075f 100644
--- a/WebContent/js/cah.ajax.builder.js
+++ b/WebContent/js/cah.ajax.builder.js
@@ -133,6 +133,39 @@ cah.ajax.Builder.prototype.withCardId = function(cardId) {
return this;
};
+/**
+ * @param {number}
+ * cardSet Card set field to use in the request.
+ * @returns {cah.ajax.Builder} This object.
+ */
+cah.ajax.Builder.prototype.withCardSet = function(cardSet) {
+ this.assertNotExecuted_();
+ this.data[cah.$.AjaxRequest.CARD_SET] = cardSet;
+ return this;
+};
+
+/**
+ * @param {number}
+ * playerLimit Player limit field to use in the request.
+ * @returns {cah.ajax.Builder} This object.
+ */
+cah.ajax.Builder.prototype.withPlayerLimit = function(playerLimit) {
+ this.assertNotExecuted_();
+ this.data[cah.$.AjaxRequest.PLAYER_LIMIT] = playerLimit;
+ return this;
+};
+
+/**
+ * @param {number}
+ * scoreLimit Score limit field to use in the request.
+ * @returns {cah.ajax.Builder} This object.
+ */
+cah.ajax.Builder.prototype.withScoreLimit = function(scoreLimit) {
+ this.assertNotExecuted_();
+ this.data[cah.$.AjaxRequest.SCORE_LIMIT] = scoreLimit;
+ 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.ajax.handlers.js b/WebContent/js/cah.ajax.handlers.js
index 8fd69bd..3fb7c59 100644
--- a/WebContent/js/cah.ajax.handlers.js
+++ b/WebContent/js/cah.ajax.handlers.js
@@ -161,3 +161,7 @@ cah.ajax.SuccessHandlers[cah.$.AjaxOperation.PLAY_CARD] = function(data, req) {
cah.ajax.SuccessHandlers[cah.$.AjaxOperation.JUDGE_SELECT] = function(data) {
// pass?
};
+
+cah.ajax.SuccessHandlers[cah.$.AjaxOperation.CHANGE_GAME_OPTIONS] = function(data) {
+ // pass
+};
diff --git a/WebContent/js/cah.constants.js b/WebContent/js/cah.constants.js
index d3cfc81..8aa583f 100644
--- a/WebContent/js/cah.constants.js
+++ b/WebContent/js/cah.constants.js
@@ -11,6 +11,7 @@ cah.$.AjaxOperation.FIRST_LOAD = "fl";
cah.$.AjaxOperation.JUDGE_SELECT = "js";
cah.$.AjaxOperation.LOG_OUT = "lo";
cah.$.AjaxOperation.GAME_LIST = "ggl";
+cah.$.AjaxOperation.CHANGE_GAME_OPTIONS = "cgo";
cah.$.AjaxOperation.GET_GAME_INFO = "ggi";
cah.$.AjaxOperation.PLAY_CARD = "pc";
cah.$.AjaxOperation.CREATE_GAME = "cg";
@@ -29,8 +30,11 @@ cah.$.AjaxRequest.prototype.dummyForAutocomplete = undefined;
cah.$.AjaxRequest.MESSAGE = "m";
cah.$.AjaxRequest.CARD_ID = "cid";
cah.$.AjaxRequest.GAME_ID = "gid";
+cah.$.AjaxRequest.CARD_SET = "cs";
cah.$.AjaxRequest.SERIAL = "s";
+cah.$.AjaxRequest.PLAYER_LIMIT = "pL";
cah.$.AjaxRequest.OP = "o";
+cah.$.AjaxRequest.SCORE_LIMIT = "sl";
cah.$.AjaxRequest.NICKNAME = "n";
cah.$.AjaxResponse = function() {
@@ -138,7 +142,10 @@ cah.$.GameInfo.prototype.dummyForAutocomplete = undefined;
cah.$.GameInfo.HOST = "H";
cah.$.GameInfo.STATE = "S";
cah.$.GameInfo.PLAYERS = "P";
+cah.$.GameInfo.CARD_SET = "cs";
cah.$.GameInfo.ID = "gid";
+cah.$.GameInfo.PLAYER_LIMIT = "pL";
+cah.$.GameInfo.SCORE_LIMIT = "sl";
cah.$.GamePlayerInfo = function() {
// Dummy constructor to make Eclipse auto-complete.
@@ -204,6 +211,7 @@ cah.$.LongPollEvent.GAME_PLAYER_INFO_CHANGE = "gpic";
cah.$.LongPollEvent.GAME_BLACK_RESHUFFLE = "gbr";
cah.$.LongPollEvent.GAME_WHITE_RESHUFFLE = "gwr";
cah.$.LongPollEvent.GAME_STATE_CHANGE = "gsc";
+cah.$.LongPollEvent.GAME_OPTIONS_CHANGED = "goc";
cah.$.LongPollEvent.PLAYER_LEAVE = "pl";
cah.$.LongPollEvent.CHAT = "c";
cah.$.LongPollEvent.HAND_DEAL = "hd";
diff --git a/WebContent/js/cah.game.js b/WebContent/js/cah.game.js
index fef74d9..2b572d8 100644
--- a/WebContent/js/cah.game.js
+++ b/WebContent/js/cah.game.js
@@ -68,13 +68,12 @@ cah.Game = function(id) {
this.optionsElement_.id = "game_options_" + id;
$("#score_limit_template_label", this.optionsElement_).attr("for", "score_limit_" + id);
$("#player_limit_template_label", this.optionsElement_).attr("for", "player_limit_" + id);
- $("#version_template_label", this.optionsElement_).attr("for", "version_" + id);
+ $("#card_set_template_label", this.optionsElement_).attr("for", "card_set_" + id);
$("#score_limit_template", this.optionsElement_).attr("id", "score_limit_" + id);
$("#player_limit_template", this.optionsElement_).attr("id", "player_limit_" + id);
- $("#version_template", this.optionsElement_).attr("id", "version_" + id);
+ $("#card_set_template", this.optionsElement_).attr("id", "card_set_" + id);
$("label", this.optionsElement_).removeAttr("id");
$(".game_options", this.element_).replaceWith(this.optionsElement_);
- this.hideOptions_();
/**
* The nickname of the host of this game.
@@ -232,6 +231,7 @@ 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_));
$(window).on("resize.game_" + this.id_, cah.bind(this, this.windowResize_));
};
@@ -638,6 +638,13 @@ cah.Game.prototype.updateGameStatus = function(data) {
$(".game_white_cards", this.element_).empty();
}
+ $(".score_limit", this.optionsElement_).val(
+ data[cah.$.AjaxResponse.GAME_INFO][cah.$.GameInfo.SCORE_LIMIT]);
+ $(".player_limit", this.optionsElement_).val(
+ data[cah.$.AjaxResponse.GAME_INFO][cah.$.GameInfo.PLAYER_LIMIT]);
+ $(".card_set", this.optionsElement_).val(
+ data[cah.$.AjaxResponse.GAME_INFO][cah.$.GameInfo.CARD_SET]);
+
var playerInfos = data[cah.$.AjaxResponse.PLAYER_INFO];
for ( var index in playerInfos) {
this.updateUserStatus(playerInfos[index]);
@@ -990,14 +997,24 @@ cah.Game.prototype.stateChange = function(data) {
}
};
+/**
+ * Hide the options panel.
+ *
+ * @private
+ */
+cah.Game.prototype.hideOptions_ = function() {
+ $(".game_options", this.element_).addClass("hide");
+ $(".game_right_side", this.element_).removeClass("hide");
+};
+
/**
* Show the options panel. Enables or disables the controls based on whether we are the host.
*
* @private
*/
cah.Game.prototype.showOptions_ = function() {
- // $(".game_options", this.element_).removeClass("hide");
- // $(".game_right_side", this.element_).addClass("hide");
+ $(".game_options", this.element_).removeClass("hide");
+ $(".game_right_side", this.element_).addClass("hide");
this.updateOptionsEnabled_();
};
@@ -1009,19 +1026,33 @@ cah.Game.prototype.showOptions_ = function() {
cah.Game.prototype.updateOptionsEnabled_ = function() {
if (this.host_ == cah.nickname) {
$("select", this.optionsElement_).removeAttr("disabled");
+ $(".options_host_only", this.optionsElement_).addClass("hide");
} else {
$("select", this.optionsElement_).attr("disabled", "disabled");
+ $(".options_host_only", this.optionsElement_).removeClass("hide");
}
};
/**
- * Hide the options panel.
+ * Event handler for changing an option.
*
+ * @param e
* @private
*/
-cah.Game.prototype.hideOptions_ = function() {
- $(".game_options", this.element_).addClass("hide");
- $(".game_right_side", this.element_).removeClass("hide");
+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();
+};
+
+/**
+ *
+ * @param {object}
+ * data Event data from server.
+ */
+cah.Game.prototype.optionsChanged = function(data) {
+ this.refreshGameStatus();
};
// ///////////////////////////////////////////////
diff --git a/WebContent/js/cah.longpoll.handlers.js b/WebContent/js/cah.longpoll.handlers.js
index 3653bf1..89fee7e 100644
--- a/WebContent/js/cah.longpoll.handlers.js
+++ b/WebContent/js/cah.longpoll.handlers.js
@@ -128,6 +128,11 @@ cah.longpoll.EventHandlers[cah.$.LongPollEvent.GAME_JUDGE_LEFT] = function(data)
cah.longpoll.EventHandlers.__gameEvent(data, cah.Game.prototype.judgeLeft, "", "judge left");
};
+cah.longpoll.EventHandlers[cah.$.LongPollEvent.GAME_OPTIONS_CHANGED] = function(data) {
+ cah.longpoll.EventHandlers.__gameEvent(data, cah.Game.prototype.optionsChanged, data,
+ "options changed");
+};
+
/**
* Helper for event handlers for game events.
*
diff --git a/src/net/socialgamer/cah/Constants.java b/src/net/socialgamer/cah/Constants.java
index 13891ad..c2d37a6 100644
--- a/src/net/socialgamer/cah/Constants.java
+++ b/src/net/socialgamer/cah/Constants.java
@@ -136,6 +136,7 @@ public class Constants {
*/
public enum AjaxOperation {
ADMIN_SET_VERBOSE_LOG("svl"),
+ CHANGE_GAME_OPTIONS("cgo"),
CHAT("c"),
CREATE_GAME("cg"),
FIRST_LOAD("fl"),
@@ -174,10 +175,13 @@ public class Constants {
*/
public enum AjaxRequest {
CARD_ID("cid"),
+ CARD_SET("cs"),
GAME_ID("gid"),
MESSAGE("m"),
NICKNAME("n"),
OP("o"),
+ PLAYER_LIMIT("pL"),
+ SCORE_LIMIT("sl"),
SERIAL("s");
private final String field;
@@ -314,6 +318,7 @@ public class Constants {
GAME_BLACK_RESHUFFLE("gbr"),
GAME_JUDGE_LEFT("gjl"),
GAME_LIST_REFRESH("glr"),
+ GAME_OPTIONS_CHANGED("goc"),
GAME_PLAYER_INFO_CHANGE("gpic"),
GAME_PLAYER_JOIN("gpj"),
GAME_PLAYER_LEAVE("gpl"),
@@ -487,10 +492,16 @@ public class Constants {
* Fields for information about a game.
*/
public enum GameInfo {
+ @DuplicationAllowed
+ CARD_SET(AjaxRequest.CARD_SET),
HOST("H"),
@DuplicationAllowed
ID(AjaxRequest.GAME_ID),
+ @DuplicationAllowed
+ PLAYER_LIMIT(AjaxRequest.PLAYER_LIMIT),
PLAYERS("P"),
+ @DuplicationAllowed
+ SCORE_LIMIT(AjaxRequest.SCORE_LIMIT),
STATE("S");
private final String key;
diff --git a/src/net/socialgamer/cah/data/Game.java b/src/net/socialgamer/cah/data/Game.java
index 3f8e85d..6594c76 100644
--- a/src/net/socialgamer/cah/data/Game.java
+++ b/src/net/socialgamer/cah/data/Game.java
@@ -91,15 +91,13 @@ public class Game {
private final Object blackCardLock = new Object();
private WhiteDeck whiteDeck;
private GameState state;
- // TODO make this host-configurable
- private final int maxPlayers = 10;
+ private int maxPlayers = 10;
private int judgeIndex = 0;
- // TODO also need to configure this
private final static int ROUND_INTERMISSION = 8 * 1000;
private Timer nextRoundTimer;
private final Object nextRoundTimerLock = new Object();
- // TODO host config
- private final int scoreGoal = 8;
+ private int scoreGoal = 8;
+ private int cardSet = 0;
/**
* Create a new game.
@@ -303,6 +301,16 @@ public class Game {
return id;
}
+ public void updateGameSettings(final int scoreLimit, final int playerLimit, final int cardSet1) {
+ this.scoreGoal = scoreLimit;
+ this.maxPlayers = playerLimit;
+ this.cardSet = cardSet1;
+
+ final HashMap data = getEventMap();
+ data.put(LongPollResponse.EVENT, LongPollEvent.GAME_OPTIONS_CHANGED.toString());
+ broadcastToPlayers(MessageType.GAME_EVENT, data);
+ }
+
/**
* @return This game's general information: ID, host, state, player list.
*/
@@ -311,6 +319,9 @@ public class Game {
info.put(GameInfo.ID, id);
info.put(GameInfo.HOST, host.toString());
info.put(GameInfo.STATE, state.toString());
+ info.put(GameInfo.CARD_SET, cardSet);
+ info.put(GameInfo.PLAYER_LIMIT, maxPlayers);
+ info.put(GameInfo.SCORE_LIMIT, scoreGoal);
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
new file mode 100644
index 0000000..bc8ce3c
--- /dev/null
+++ b/src/net/socialgamer/cah/handlers/ChangeGameOptionHandler.java
@@ -0,0 +1,51 @@
+package net.socialgamer.cah.handlers;
+
+import java.util.HashMap;
+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.GameState;
+import net.socialgamer.cah.Constants.ReturnableData;
+import net.socialgamer.cah.RequestWrapper;
+import net.socialgamer.cah.data.Game;
+import net.socialgamer.cah.data.GameManager;
+import net.socialgamer.cah.data.User;
+
+import com.google.inject.Inject;
+
+
+public class ChangeGameOptionHandler extends GameWithPlayerHandler {
+
+ public static final String OP = AjaxOperation.CHANGE_GAME_OPTIONS.toString();
+
+ @Inject
+ public ChangeGameOptionHandler(final GameManager gameManager) {
+ super(gameManager);
+ }
+
+ @Override
+ public Map handleWithUserInGame(final RequestWrapper request,
+ final HttpSession session, final User user, final Game game) {
+ final Map data = new HashMap();
+
+ if (game.getHost() != user) {
+ return error(ErrorCode.NOT_GAME_HOST);
+ } else if (game.getState() != GameState.LOBBY) {
+ return error(ErrorCode.ALREADY_STARTED);
+ } else {
+ try {
+ 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);
+ } catch (final NumberFormatException nfe) {
+ return error(ErrorCode.BAD_REQUEST);
+ }
+ return data;
+ }
+ }
+}
diff --git a/src/net/socialgamer/cah/handlers/Handlers.java b/src/net/socialgamer/cah/handlers/Handlers.java
index 968ddfc..2c4128f 100644
--- a/src/net/socialgamer/cah/handlers/Handlers.java
+++ b/src/net/socialgamer/cah/handlers/Handlers.java
@@ -11,6 +11,7 @@ public class Handlers {
static {
LIST = new HashMap>();
LIST.put(AdminSetVerboseLog.OP, AdminSetVerboseLog.class);
+ LIST.put(ChangeGameOptionHandler.OP, ChangeGameOptionHandler.class);
LIST.put(ChatHandler.OP, ChatHandler.class);
LIST.put(CreateGameHandler.OP, CreateGameHandler.class);
LIST.put(FirstLoadHandler.OP, FirstLoadHandler.class);