/**
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 org.apache.log4j.Logger;
import de.creepsmash.common.IConstants;
import de.creepsmash.common.messages.client.ExitGameMessage;
import de.creepsmash.common.messages.client.GameMessage;
import de.creepsmash.common.messages.client.LogoutMessage;
import de.creepsmash.common.messages.client.SendMessageMessage;
import de.creepsmash.common.messages.server.MessageMessage;
import de.creepsmash.common.messages.server.PlayerQuitMessage;
import de.creepsmash.server.Client;
/**
* A GameState is used by a Game instance to handle incoming messages and
* "ticks". GameState and its subclasses implement the state pattern as well as
* the related Strategy pattern.
*/
public abstract class GameState {
private Game game;
private static Logger logger = Logger.getLogger(GameState.class);
/**
* Constructor to be called by subclasses.
* @param game the game. Must not be null.
*/
protected GameState(Game game) {
if (game == null) {
throw new IllegalArgumentException("'game' was null");
}
this.game = game;
}
/**
* Returns the game.
* @return the game.
*/
protected Game getGame() {
return this.game;
}
/**
* Called periodically by TickThread when the game is running.
*/
public void tick() {
logger.warn("got tick in state " + toString());
}
/**
* Handle a message (from a client, presumably).
* @param message a message (from a client, presumably).
* @param sender the player who sent the message.
* @return the new GameState.
*/
public abstract GameState consume(GameMessage message, PlayerInGame sender);
/**
* Handle SEND_MESSAGE.
* @param m the message.
*/
protected void handle(SendMessageMessage m) {
Client sender = this.game.getClients().get(m.getClientId()).getClient();
this.game.sendAll(
new MessageMessage(
sender.getUserName(), m.getMessage()));
}
/**
* Handles the ExitGameMessage.
* @param m the message
* @return the new state.
*/
protected GameState handle(ExitGameMessage m) {
Client client = this.game.getClients().get(m.getClientId()).getClient();
return removeClient(client, "EXIT_GAME");
}
/**
* Handle LOGOUT (which may also signal a client disconnect).
* @param m the message.
* @return the new state.
*/
protected GameState handle(LogoutMessage m) {
Client client = this.game.getClients().get(m.getClientId()).getClient();
return removeClient(client, "logged out");
}
/**
* 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) {
logger.info("removing " + client + " from game '" + this.game
+ "' (reason: '" + reason + "')");
this.game.removeClient(client);
if (this.game.getClients().isEmpty()) {
return new TerminatedGameState(this.game);
} else {
this.game.sendAll(new PlayerQuitMessage(client.getUserName(), reason,client.getClientID()));
this.game.gamePlayersChanged();
return this;
}
}
/**
* Set MapID
* @param MapID
* @return the new state.
*/
protected GameState setMapID(int MapID) {
logger.info("set MapID from game '" + this.game
+ "' (MapID: '" + MapID + "')");
this.game.setMapId(MapID);
return this;
}
/**
* Send an error message to the client because we got a message in the wrong
* state.
* @param message the message. Must not be null.
* @param sender the player who sent the message. Must not be null.
*/
protected void wrongStateForMessage(GameMessage message, PlayerInGame sender) {
if (message == null) {
throw new IllegalArgumentException("'message' was null");
}
if (sender == null) {
throw new IllegalArgumentException("'sender' was null");
}
String errorMessage =
"wrong state (" + toString() + ") for message '"
+ message.getMessageString() + "'";
sender.getClient().handleError(IConstants.ErrorType.Error, errorMessage);
}
}