/**
Creep Smash, a multiplayer towerdefence game
created as a project at the Hochschule fuer
Technik Stuttgart (University of Applied Science)
http://www.hft-stuttgart.de
Copyright (C) 2008 by
* Andreas Wittig
* Bernd Hietler
* Christoph Fritz
* Fabian Kessel
* Levin Fritz
* Nikolaj Langner
* Philipp Schulte-Hubbert
* Robert Rapczynski
* Ron Trautsch
* Sven Supper
http://creepsmash.sf.net/
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
**/
package de.creepsmash.server.game;
import java.util.LinkedList;
import java.util.List;
import org.apache.log4j.Logger;
import de.creepsmash.common.IConstants;
import de.creepsmash.common.IConstants.ResponseType;
import de.creepsmash.common.messages.client.BuildCreepMessage;
import de.creepsmash.common.messages.client.BuildTowerMessage;
import de.creepsmash.common.messages.client.ExitGameMessage;
import de.creepsmash.common.messages.client.GameMessage;
import de.creepsmash.common.messages.client.GameOverMessage;
import de.creepsmash.common.messages.client.KickPlayerRequestMessage;
import de.creepsmash.common.messages.client.LogoutMessage;
import de.creepsmash.common.messages.client.SellTowerMessage;
import de.creepsmash.common.messages.client.SendMessageMessage;
import de.creepsmash.common.messages.client.StartGameRequestMessage;
import de.creepsmash.common.messages.client.UpgradeTowerMessage;
import de.creepsmash.common.messages.server.KickPlayerResponseMessage;
import de.creepsmash.common.messages.server.KickedMessage;
import de.creepsmash.common.messages.server.StartGameMessage;
import de.creepsmash.common.messages.server.StartGameResponseMessage;
import de.creepsmash.server.Client;
/**
* GameState for a game that has not yet started.
*/
public class WaitingGameState extends GameState {
private Client creator;
private static Logger logger = Logger.getLogger(WaitingGameState.class);
/**
* Creates a new one, initially with zero players.
* @param game the game. Must not be null.
* @param creator the client who created the game.
*/
public WaitingGameState(Game game, Client creator) {
super(game);
this.creator = creator;
}
/**
* Handle a message (from a client, presumably).
* @param message the message. Must not be null.
* @param sender the player who sent the message. Must not be null.
* @return the new state
*/
public GameState consume(GameMessage message, PlayerInGame sender) {
if (message == null) {
throw new IllegalArgumentException("'message' was null!");
}
if (sender == null) {
throw new IllegalArgumentException("'sender' was null!");
}
if (message instanceof StartGameRequestMessage) {
return handle((StartGameRequestMessage) message, sender);
} else if (message instanceof KickPlayerRequestMessage) {
return handle((KickPlayerRequestMessage) message, sender);
} else if (message instanceof ExitGameMessage) {
return handle((ExitGameMessage) message);
} else if (message instanceof SendMessageMessage) {
handle((SendMessageMessage) message);
} else if (message instanceof LogoutMessage) {
return handle((LogoutMessage) message);
} else if (message instanceof BuildTowerMessage
|| message instanceof UpgradeTowerMessage
|| message instanceof SellTowerMessage
|| message instanceof BuildCreepMessage
|| message instanceof GameOverMessage) {
wrongStateForMessage(message, sender);
} else {
logger.error("cannot handle message: " + message);
}
if (getGame().getClients().isEmpty()) {
return new TerminatedGameState(getGame());
}
return this;
}
/**
* Handles the StartGameRequestMessage.
* @param m the message
* @param sender the player who sent the message.
* @return the new state
*/
private GameState handle(StartGameRequestMessage m, PlayerInGame sender) {
Client client = sender.getClient();
if (getGame().getClients().size() < 2) {
logger.info(
client + " tried to start game, but there aren't enough players");
client.send(new StartGameResponseMessage(ResponseType.failed));
return this;
} else {
client.send(new StartGameResponseMessage(ResponseType.ok));
logger.info("players before shuffle: "
+ createStartGameMessage(getGame().getClients(),getGame().getMapId()));
PlayerList players = getGame().getClients();
players.shuffle();
getGame().setClients(players);
logger.info("players after shuffle: "
+ createStartGameMessage(getGame().getClients(),getGame().getMapId()));
//Zufalls Map bestimmen
if (getGame().getMapId() == 0){
int zufall = (int) ((Math.random()*IConstants.Map.values().length)+1);
super.setMapID(zufall);
}
getGame().sendAll(createStartGameMessage(getGame().getClients(),getGame().getMapId()));
return new RunningGameState(getGame());
}
}
/**
* Creates a StartGameMessage with the current list of players.
* @param players the game's players
* @return a StartGameMessage.
*/
private StartGameMessage createStartGameMessage(PlayerList players, int MapID) {
StartGameMessage m = new StartGameMessage();
List<Integer> list = new LinkedList<Integer>();
for (PlayerInGame player : players) {
list.add(player.getClient().getClientID());
}
m.setPlayers(list);
m.setMapID(MapID);
return m;
}
/**
* Handles the KickPlayerRequestMessage.
* @param m the message
* @param sender the player who sent the message.
* @return the new state.
*/
private GameState handle(KickPlayerRequestMessage m, PlayerInGame sender) {
String playerName = m.getPlayerName();
Client client = sender.getClient();
PlayerInGame kicked = getGame().getClients().get(playerName);
if (kicked == null) {
logger.warn("cannot find player '" + playerName + "'");
client.send(new KickPlayerResponseMessage(ResponseType.failed));
return this;
} else {
Client kickedClient = kicked.getClient();
logger.info("kicking " + kickedClient + " from game '" + getGame() + "'");
client.send(new KickPlayerResponseMessage(ResponseType.ok));
kickedClient.send(new KickedMessage());
return removeClient(kickedClient, "kicked");
}
}
/**
* Remove client from the game.
* @param client the client. Must not be null.
* @param reason a short string to be used in PLAYER_QUIT messages. Must not
* be null.
* @return the new state.
*/
protected GameState removeClient(Client client, String reason) {
if (client == this.creator) {
Game game = getGame();
logger.info("game " + game
+ ": creator left the game, kicking out all players");
PlayerList playerList = game.getClients();
for (PlayerInGame p : playerList) {
Client c = p.getClient();
if (c != client) {
try {
c.send(new KickedMessage());
} catch(Exception e) {
logger.warn("Error with sending KickedMessage: " + e.getMessage());
}
}
}
game.setClients(new PlayerList());
return new TerminatedGameState(game);
} else {
return super.removeClient(client, reason);
}
}
/**
* Returns a string identifying this state.
* @return "waiting"
*/
public String toString() {
return "waiting";
}
}