deal cards to players when the game starts
This commit is contained in:
parent
44dcc45c48
commit
c73ce88646
|
@ -159,7 +159,7 @@ span.debug {
|
|||
bottom: 0px;
|
||||
*/
|
||||
font-family: Arial, Verdana, san-serif;
|
||||
font-size: 16pt;
|
||||
font-size: 18pt;
|
||||
float: left;
|
||||
|
||||
-webkit-user-select: none;
|
||||
|
|
|
@ -37,7 +37,7 @@
|
|||
<span id="nickbox_error" class="error"></span>
|
||||
</div>
|
||||
|
||||
<div id="canvas">
|
||||
<div id="canvas" class="hide">
|
||||
<div id="menubar">
|
||||
<div id="menubar_left">
|
||||
<input type="button" id="refresh_games" class="hide" value="Refresh Games" />
|
||||
|
|
|
@ -54,6 +54,7 @@ cah.ajax.ErrorHandlers[cah.$.AjaxOperation.FIRST_LOAD] = function(data) {
|
|||
*/
|
||||
cah.ajax.after_registered = function() {
|
||||
cah.log.debug("done registering");
|
||||
$("#canvas").show();
|
||||
// TODO once there are channels, this needs to specify the global channel
|
||||
cah.Ajax.build(cah.$.AjaxOperation.NAMES).run();
|
||||
cah.GameList.instance.show();
|
||||
|
@ -100,3 +101,7 @@ cah.ajax.SuccessHandlers[cah.$.AjaxOperation.LEAVE_GAME] = function(data) {
|
|||
// This will get updated when the server fires a refresh event
|
||||
cah.GameList.instance.show();
|
||||
};
|
||||
|
||||
cah.ajax.SuccessHandlers[cah.$.AjaxOperation.START_GAME] = function(data) {
|
||||
// pass
|
||||
};
|
||||
|
|
|
@ -216,16 +216,3 @@ cah.card.WhiteCard.prototype.getFaceUp_ = function() {
|
|||
$(temp).removeClass("hide");
|
||||
return temp;
|
||||
};
|
||||
|
||||
// $(document).ready(function() {
|
||||
// var card = new cah.card.BlackCard();
|
||||
// $("#canvas").append(card.getElement());
|
||||
//
|
||||
// var card2 = new cah.card.BlackCard(true);
|
||||
// // card2.setText("black card");
|
||||
// $("#canvas").append(card2.getElement());
|
||||
//
|
||||
// var card3 = new cah.card.WhiteCard(true);
|
||||
// card3.setText("white card");
|
||||
// $("#canvas").append(card3.getElement());
|
||||
// });
|
||||
|
|
|
@ -6,6 +6,7 @@ cah.$.AjaxOperation = function() {
|
|||
// pass
|
||||
};
|
||||
cah.$.AjaxOperation.prototype.dummy = undefined;
|
||||
cah.$.AjaxOperation.START_GAME = "start_game";
|
||||
cah.$.AjaxOperation.FIRST_LOAD = "firstload";
|
||||
cah.$.AjaxOperation.LOG_OUT = "logout";
|
||||
cah.$.AjaxOperation.GAME_LIST = "games";
|
||||
|
@ -58,6 +59,7 @@ cah.$.ErrorCode = function() {
|
|||
cah.$.ErrorCode.prototype.dummy = undefined;
|
||||
cah.$.ErrorCode.TOO_MANY_GAMES = "too_many_games";
|
||||
cah.$.ErrorCode.INVALID_NICK = "invalid_nick";
|
||||
cah.$.ErrorCode.NOT_GAME_HOST = "not_game_host";
|
||||
cah.$.ErrorCode.BAD_REQUEST = "bad_req";
|
||||
cah.$.ErrorCode.CANNOT_JOIN_ANOTHER_GAME = "cannot_join_another_game";
|
||||
cah.$.ErrorCode.NO_GAME_SPECIFIED = "no_game_spec";
|
||||
|
@ -66,6 +68,7 @@ cah.$.ErrorCode.MESSAGE_TOO_LONG = "msg_too_long";
|
|||
cah.$.ErrorCode.BAD_OP = "bad_op";
|
||||
cah.$.ErrorCode.NO_SESSION = "no_session";
|
||||
cah.$.ErrorCode.NOT_REGISTERED = "not_registered";
|
||||
cah.$.ErrorCode.NOT_ENOUGH_PLAYERS = "not_enough_players";
|
||||
cah.$.ErrorCode.INVALID_GAME = "invalid_game";
|
||||
cah.$.ErrorCode.OP_NOT_SPECIFIED = "op_not_spec";
|
||||
cah.$.ErrorCode.NO_MSG_SPECIFIED = "no_msg_spec";
|
||||
|
@ -76,6 +79,7 @@ cah.$.ErrorCode_msg = {};
|
|||
cah.$.ErrorCode_msg['bad_op'] = "Invalid operation.";
|
||||
cah.$.ErrorCode_msg['not_registered'] = "Not registered. Refresh the page.";
|
||||
cah.$.ErrorCode_msg['msg_too_long'] = "Messages cannot be longer than 200 characters.";
|
||||
cah.$.ErrorCode_msg['not_enough_players'] = "There are not enough players to start the game.";
|
||||
cah.$.ErrorCode_msg['session_expired'] = "Your session has expired. Refresh the page.";
|
||||
cah.$.ErrorCode_msg['invalid_game'] = "Invalid game specified.";
|
||||
cah.$.ErrorCode_msg['no_game_spec'] = "No game specified.";
|
||||
|
@ -85,6 +89,7 @@ cah.$.ErrorCode_msg['too_many_games'] = "There are too many games already in pro
|
|||
cah.$.ErrorCode_msg['no_nick_spec'] = "No nickname specified.";
|
||||
cah.$.ErrorCode_msg['no_session'] = "Session not detected. Make sure you have cookies enabled.";
|
||||
cah.$.ErrorCode_msg['nick_in_use'] = "Nickname is already in use.";
|
||||
cah.$.ErrorCode_msg['not_game_host'] = "Only the game host can do that.";
|
||||
cah.$.ErrorCode_msg['bad_req'] = "Bad request.";
|
||||
cah.$.ErrorCode_msg['cannot_join_another_game'] = "You cannot join another game.";
|
||||
cah.$.ErrorCode_msg['op_not_spec'] = "Operation not specified.";
|
||||
|
@ -127,9 +132,13 @@ cah.$.GameState = function() {
|
|||
// pass
|
||||
};
|
||||
cah.$.GameState.prototype.dummy = undefined;
|
||||
cah.$.GameState.PLAYING = "playing";
|
||||
cah.$.GameState.LOBBY = "lobby";
|
||||
cah.$.GameState.JUDGING = "judging";
|
||||
cah.$.GameState.DEALING = "dealing";
|
||||
cah.$.GameState_msg = {};
|
||||
cah.$.GameState_msg['playing'] = "In Progress";
|
||||
cah.$.GameState_msg['judging'] = "In Progress";
|
||||
cah.$.GameState_msg['lobby'] = "Joinable (Not Started)";
|
||||
cah.$.GameState_msg['dealing'] = "Dealing";
|
||||
|
||||
|
@ -143,6 +152,7 @@ cah.$.LongPollEvent.GAME_PLAYER_LEAVE = "game_player_leave";
|
|||
cah.$.LongPollEvent.NEW_PLAYER = "new_player";
|
||||
cah.$.LongPollEvent.PLAYER_LEAVE = "player_leave";
|
||||
cah.$.LongPollEvent.GAME_PLAYER_JOIN = "game_player_join";
|
||||
cah.$.LongPollEvent.HAND_DEAL = "hand_deal";
|
||||
cah.$.LongPollEvent.CHAT = "chat";
|
||||
|
||||
cah.$.LongPollResponse = function() {
|
||||
|
@ -152,6 +162,7 @@ cah.$.LongPollResponse.prototype.dummy = undefined;
|
|||
cah.$.LongPollResponse.MESSAGE = "message";
|
||||
cah.$.LongPollResponse.REASON = "reason";
|
||||
cah.$.LongPollResponse.GAME_ID = "game_id";
|
||||
cah.$.LongPollResponse.HAND = "hand";
|
||||
cah.$.LongPollResponse.FROM = "from";
|
||||
cah.$.LongPollResponse.EVENT = "event";
|
||||
cah.$.LongPollResponse.ERROR = "error";
|
||||
|
@ -166,3 +177,10 @@ cah.$.ReconnectNextAction.prototype.dummy = undefined;
|
|||
cah.$.ReconnectNextAction.GAME = "game";
|
||||
cah.$.ReconnectNextAction.NONE = "none";
|
||||
|
||||
cah.$.WhiteCardData = function() {
|
||||
// pass
|
||||
};
|
||||
cah.$.WhiteCardData.prototype.dummy = undefined;
|
||||
cah.$.WhiteCardData.TEXT = "text";
|
||||
cah.$.WhiteCardData.ID = "id";
|
||||
|
||||
|
|
|
@ -28,6 +28,7 @@ cah.Game = function(id) {
|
|||
* @private
|
||||
*/
|
||||
this.element_ = $("#game_template").clone()[0];
|
||||
this.element_.id = "game_" + id;
|
||||
$(this.element_).removeClass("hide");
|
||||
|
||||
/**
|
||||
|
@ -37,6 +38,7 @@ cah.Game = function(id) {
|
|||
* @private
|
||||
*/
|
||||
this.scoreboardElement_ = $("#scoreboard_template").clone()[0];
|
||||
this.scoreboardElement_.id = "scoreboard_" + id;
|
||||
$(this.scoreboardElement_).removeClass("hide");
|
||||
|
||||
/**
|
||||
|
@ -80,6 +82,21 @@ cah.Game.prototype.getElement = function() {
|
|||
return this.element_;
|
||||
};
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Add a card to the player's hand.
|
||||
*
|
||||
|
@ -150,6 +167,8 @@ cah.Game.prototype.updateGameStatus = function(data) {
|
|||
* @private
|
||||
*/
|
||||
cah.Game.prototype.leaveGameClick_ = function() {
|
||||
// TODO make sure everything cleans up right, I got an error when I tried to start a different
|
||||
// game after leaving one
|
||||
cah.Ajax.build(cah.$.AjaxOperation.LEAVE_GAME).withGameId(this.id_).run();
|
||||
};
|
||||
|
||||
|
@ -159,7 +178,7 @@ cah.Game.prototype.leaveGameClick_ = function() {
|
|||
* @private
|
||||
*/
|
||||
cah.Game.prototype.startGameClick_ = function() {
|
||||
// TODO
|
||||
cah.Ajax.build(cah.$.AjaxOperation.START_GAME).withGameId(this.id_).run();
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -289,14 +308,3 @@ cah.GameScorePanel.prototype.update = function(score, status) {
|
|||
jQuery(".scorecard_score", this.element_).text(score);
|
||||
jQuery(".scorecard_status", this.element_).text(cah.$.GamePlayerStatus_msg[status]);
|
||||
};
|
||||
|
||||
// $(document).ready(function() {
|
||||
// var game = new cah.Game(0);
|
||||
// $("#main_holder").append(game.getElement());
|
||||
//
|
||||
// for ( var i = 0; i < 10; i++) {
|
||||
// var card = new cah.card.WhiteCard(true);
|
||||
// card.setText("This is card " + i);
|
||||
// game.dealtCard(card);
|
||||
// }
|
||||
// });
|
||||
|
|
|
@ -69,3 +69,13 @@ cah.longpoll.EventHandlers[cah.$.LongPollEvent.GAME_PLAYER_LEAVE] = function(dat
|
|||
cah.log.error("Received player leave event for unknown game id " + gameId);
|
||||
}
|
||||
};
|
||||
|
||||
cah.longpoll.EventHandlers[cah.$.LongPollEvent.HAND_DEAL] = function(data) {
|
||||
var gameId = data[cah.$.LongPollResponse.GAME_ID];
|
||||
var game = cah.currentGames[gameId];
|
||||
if (game) {
|
||||
game.dealtCards(data[cah.$.LongPollResponse.HAND]);
|
||||
} else {
|
||||
cah.log.error("Received dealt cards for unknown game id " + gameId);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -61,7 +61,8 @@ public class Constants {
|
|||
LEAVE_GAME("leave_game"),
|
||||
LOG_OUT("logout"),
|
||||
NAMES("names"),
|
||||
REGISTER("register");
|
||||
REGISTER("register"),
|
||||
START_GAME("start_game");
|
||||
|
||||
private final String op;
|
||||
|
||||
|
@ -135,6 +136,8 @@ public class Constants {
|
|||
NO_MSG_SPECIFIED("no_msg_spec", "No message specified."),
|
||||
NO_NICK_SPECIFIED("no_nick_spec", "No nickname specified."),
|
||||
NO_SESSION("no_session", "Session not detected. Make sure you have cookies enabled."),
|
||||
NOT_ENOUGH_PLAYERS("not_enough_players", "There are not enough players to start the game."),
|
||||
NOT_GAME_HOST("not_game_host", "Only the game host can do that."),
|
||||
NOT_REGISTERED("not_registered", "Not registered. Refresh the page."),
|
||||
OP_NOT_SPECIFIED("op_not_spec", "Operation not specified."),
|
||||
SESSION_EXPIRED("session_expired", "Your session has expired. Refresh the page."),
|
||||
|
@ -171,6 +174,7 @@ public class Constants {
|
|||
GAME_PLAYER_JOIN("game_player_join"),
|
||||
GAME_PLAYER_LEAVE("game_player_leave"),
|
||||
GAME_REFRESH("game_refresh"),
|
||||
HAND_DEAL("hand_deal"),
|
||||
NEW_PLAYER("new_player"),
|
||||
NOOP("noop"),
|
||||
PLAYER_LEAVE("player_leave");
|
||||
|
@ -193,6 +197,7 @@ public class Constants {
|
|||
EVENT("event"),
|
||||
FROM("from"),
|
||||
GAME_ID("game_id"),
|
||||
HAND("hand"),
|
||||
MESSAGE("message"),
|
||||
NICKNAME("nickname"),
|
||||
REASON("reason"),
|
||||
|
@ -214,9 +219,27 @@ public class Constants {
|
|||
public static final String USER = "user";
|
||||
}
|
||||
|
||||
public enum WhiteCardData {
|
||||
ID("id"),
|
||||
TEXT("text");
|
||||
|
||||
private final String key;
|
||||
|
||||
WhiteCardData(final String key) {
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return key;
|
||||
}
|
||||
}
|
||||
|
||||
public enum GameState implements Localizable {
|
||||
DEALING("dealing", "Dealing"),
|
||||
LOBBY("lobby", "Joinable (Not Started)");
|
||||
JUDGING("judging", "In Progress"),
|
||||
LOBBY("lobby", "Joinable (Not Started)"),
|
||||
PLAYING("playing", "In Progress");
|
||||
|
||||
private final String state;
|
||||
private final String message;
|
||||
|
|
|
@ -3,6 +3,7 @@ package net.socialgamer.cah.data;
|
|||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
|
@ -13,12 +14,34 @@ import net.socialgamer.cah.Constants.GameState;
|
|||
import net.socialgamer.cah.Constants.LongPollEvent;
|
||||
import net.socialgamer.cah.Constants.LongPollResponse;
|
||||
import net.socialgamer.cah.Constants.ReturnableData;
|
||||
import net.socialgamer.cah.Constants.WhiteCardData;
|
||||
import net.socialgamer.cah.data.GameManager.GameId;
|
||||
import net.socialgamer.cah.data.QueuedMessage.MessageType;
|
||||
import net.socialgamer.cah.db.WhiteCard;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
|
||||
|
||||
/**
|
||||
* Game data and logic class. Games are simple finite state machines, with 3 states that wait for
|
||||
* user input, and 3 transient states that it quickly passes through on the way back to a waiting
|
||||
* state:
|
||||
*
|
||||
* ......Lobby.----------->.Dealing.(transient).-------->.Playing
|
||||
* .......^........................^.........................|....................
|
||||
* .......|.v----.Win.(transient).<+------.Judging.<---------+....................
|
||||
* .....Reset.(transient)
|
||||
*
|
||||
* Lobby is the default state. When the game host sends a start game event, the game moves to the
|
||||
* Dealing state, where it deals out cards to every player and automatically moves into the Playing
|
||||
* state. After all players have played a card, the game moves to Judging and waits for the judge to
|
||||
* pick a card. The game either moves to Win, if a player reached the win goal, or Dealing
|
||||
* otherwise. Win moves through Reset to reset the game back to default state. The game also
|
||||
* immediately moves through Reset at any point there are fewer than 3 players in the game.
|
||||
*
|
||||
*
|
||||
* @author ajanata
|
||||
*/
|
||||
public class Game {
|
||||
private final int id;
|
||||
private final List<Player> players = new ArrayList<Player>(10);
|
||||
|
@ -28,6 +51,8 @@ public class Game {
|
|||
private BlackDeck blackDeck;
|
||||
private WhiteDeck whiteDeck;
|
||||
private GameState state;
|
||||
// TODO make this work with "draw x" cards. probably will not actually be done here.
|
||||
private final int currentHandSize = 10;
|
||||
// TODO make this host-configurable
|
||||
private final int maxPlayers = 10;
|
||||
|
||||
|
@ -174,9 +199,59 @@ public class Game {
|
|||
return info;
|
||||
}
|
||||
|
||||
public void start() {
|
||||
/**
|
||||
* Start the game, if there are at least 3 players present. This does not do any access checking!
|
||||
*
|
||||
* @return True if the game is started. Would only be false if there aren't enough players, or the
|
||||
* game is already started, but hopefully clients would prevent that from happening!
|
||||
*/
|
||||
public boolean start() {
|
||||
if (state != GameState.LOBBY) {
|
||||
return false;
|
||||
}
|
||||
synchronized (players) {
|
||||
if (players.size() >= 3) {
|
||||
blackDeck = new BlackDeck();
|
||||
whiteDeck = new WhiteDeck();
|
||||
dealState();
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void dealState() {
|
||||
state = GameState.DEALING;
|
||||
// TODO deal
|
||||
synchronized (players) {
|
||||
for (final Player player : players) {
|
||||
final List<WhiteCard> hand = player.getHand();
|
||||
final List<WhiteCard> newCards = new LinkedList<WhiteCard>();
|
||||
while (hand.size() < currentHandSize) {
|
||||
final WhiteCard card = whiteDeck.getNextCard();
|
||||
hand.add(card);
|
||||
newCards.add(card);
|
||||
}
|
||||
sendDealtCardsToPlayer(player, newCards);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void sendDealtCardsToPlayer(final Player player, final List<WhiteCard> cards) {
|
||||
final Map<ReturnableData, Object> data = new HashMap<ReturnableData, Object>();
|
||||
data.put(LongPollResponse.EVENT, LongPollEvent.HAND_DEAL.toString());
|
||||
data.put(LongPollResponse.GAME_ID, id);
|
||||
final List<Map<WhiteCardData, Object>> cardData =
|
||||
new ArrayList<Map<WhiteCardData, Object>>(cards.size());
|
||||
for (final WhiteCard card : cards) {
|
||||
final Map<WhiteCardData, Object> thisCard = new HashMap<WhiteCardData, Object>();
|
||||
thisCard.put(WhiteCardData.ID, card.getId());
|
||||
thisCard.put(WhiteCardData.TEXT, card.getText());
|
||||
cardData.add(thisCard);
|
||||
}
|
||||
data.put(LongPollResponse.HAND, cardData);
|
||||
final QueuedMessage qm = new QueuedMessage(MessageType.GAME_EVENT, data);
|
||||
player.getUser().enqueueMessage(qm);
|
||||
}
|
||||
|
||||
private List<User> playersToUsers() {
|
||||
|
|
|
@ -28,6 +28,9 @@ public class Player {
|
|||
score++;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The backing object for the player's hand (i.e., it can be modified).
|
||||
*/
|
||||
public List<WhiteCard> getHand() {
|
||||
return hand;
|
||||
}
|
||||
|
|
|
@ -20,5 +20,6 @@ public class Handlers {
|
|||
LIST.put(LogoutHandler.OP, LogoutHandler.class);
|
||||
LIST.put(NamesHandler.OP, NamesHandler.class);
|
||||
LIST.put(RegisterHandler.OP, RegisterHandler.class);
|
||||
LIST.put(StartGameHandler.OP, StartGameHandler.class);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
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.ErrorCode;
|
||||
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 StartGameHandler extends GameHandler {
|
||||
|
||||
public static final String OP = AjaxOperation.START_GAME.toString();
|
||||
|
||||
@Inject
|
||||
public StartGameHandler(final GameManager gameManager) {
|
||||
super(gameManager);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<ReturnableData, Object> handle(final RequestWrapper request,
|
||||
final HttpSession session, final User user,
|
||||
final Game game) {
|
||||
final Map<ReturnableData, Object> data = new HashMap<ReturnableData, Object>();
|
||||
|
||||
if (game.getHost() != user) {
|
||||
return error(ErrorCode.NOT_GAME_HOST);
|
||||
}
|
||||
if (!game.start()) {
|
||||
return error(ErrorCode.NOT_ENOUGH_PLAYERS);
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue