package clueless.model;
import java.util.Vector;
import clueless.controller.GameController;
import clueless.events.MessageEvent;
import clueless.events.MessageEventListener;
import clueless.messaging.DrawPawnsMessage;
import clueless.messaging.MoveMessage;
import clueless.model.Character.CharacterName;
import clueless.model.Location;
import clueless.model.Player;
import clueless.model.Room.RoomName;
import clueless.model.Hallway.HallwayName;
import clueless.model.Location.LocationType;
import clueless.model.decks.CharacterCard;
import clueless.model.decks.CharacterDeck;
import clueless.model.decks.LocationCard;
import clueless.model.decks.LocationDeck;
import clueless.model.decks.WeaponCard;
import clueless.model.decks.WeaponDeck;
import clueless.view.BoardView;
/**
* GameModel
*
* Class handles requests from controller and maintains game state
*
* @author C. Crook
*/
public class Game extends AbstractModel implements MessageEventListener{
private static final long serialVersionUID = 3031364463542107885L;
/** Represents winning combo of weapon/character/location */
private transient CaseFile caseFile;
/** Keep track of proposed theories */
private Vector<Theory> theoriesSuggested;
/** Holds array of items representing board state */
private Vector<GamePiece> gamePieces;
/** Deck containing all possible character cards, including their states */
private transient CharacterDeck characterDeck;
/** Deck containing all possible weapon cards, including their states */
private transient WeaponDeck weaponDeck;
/** Deck containing all possible location cards, including their states */
private transient LocationDeck roomDeck;
/** Collection of players currently in game */
private Vector<Player> players;
/** Collection of board spaces currently in game */
private Vector<Location> spaces;
/** Reference to controller */
private transient GameController controller;
/**
* Base constructor that instantiates game state variables.
*/
public Game(GameController controller)
{
this.controller = controller;
controller.addModel(this);
controller.addMessageEventListener(this);
//initialize other game variables
players = new Vector<Player>();
spaces = new Vector<Location>();
characterDeck = new CharacterDeck(controller);
weaponDeck = new WeaponDeck(controller);
roomDeck = new LocationDeck(controller);
gamePieces = new Vector<GamePiece>();
theoriesSuggested = new Vector<Theory>();
caseFile = new CaseFile((CharacterCard) characterDeck.getNextCard(),
(WeaponCard) weaponDeck.getNextCard(),
(LocationCard) roomDeck.getNextCard());
buildBoardSpaces();
}
/**
* Game constructor for when player initiates new game
* @param firstPlayer Player initiating game
*/
public Game(GameController controller, Player firstPlayer) {
//call basic constructor
this(controller);
players.add(firstPlayer);
}
/**
* Adds player to the current games
* @param playerToAdd Player to add to the game.
*/
public void joinGame(Player playerToAdd){
players.add(playerToAdd);
}
/**
* Removes player from game
* @param playerToRemove Player to remove from game.
*/
public void leaveGame(Player playerToRemove){
players.remove(playerToRemove);
//check number of players in game and dispose of object if it is zero
}
/**
* Gets number of players currently in the game.
* @return Number of players currently in game.
*/
public int getNumberOfPlayers()
{
return players.size();
}
/**
* Gets games pieces in game.
* @return Set of all gamepieces
*/
public Vector<GamePiece> getGamePieces()
{
return gamePieces;
}
/**
* @return the set of all location models.
*/
public Vector<Location> getSpaces(){
return this.spaces;
}
/**
* Gets list of players currently in game.
* @return Players currently in game.
*/
public Vector<Player> getPlayers()
{
return players;
}
/**
* Instantiates all board spaces
*/
public void buildBoardSpaces() {
for (RoomName room : RoomName.values())
spaces.add(new Room(room));
for (HallwayName hall : HallwayName.values())
spaces.add(new Hallway(hall));
}
/**
* Builds a Vector of all Locations that are Valid Moves for the given location
* @param location to test
* @return Vector of Locations on the board (to highlight or use for error checking)
*/
public Vector<Location> getValidMoves(Location location) {
Vector<Location> validMoves = new Vector<Location>();
/** Check every space for validity -- if true, add to validMoves */
for (Location space : spaces) {
// Checks for legal move and that (if hallway) space is empty
if ((space.isValidMove(location)) && (space.isVacant()))
validMoves.add(space);
}
return validMoves;
}
/**
* Sets the CharacterName assigned to a Player
* @param player
* @param character
*/
public void setPlayerCharacter(Player player, CharacterName character) {
for (int i = 0; i < getNumberOfPlayers(); i++) {
if (players.get(i).getUUID().equals(player.getUUID())) {
Player temp = players.get(i);
temp.setCharacter(character);
players.set(i, temp);
}
}
}
/**
* Gets theories that have already been suggested by various players.
* @return Theories already suggested
*/
public Vector<Theory> getSuggestedTheories()
{
return theoriesSuggested;
}
/**
* Keep track of suggestions that have been made
* @param suggestion Suggestion that has been made
*/
public void addSuggestedTheory(Theory suggestion)
{
theoriesSuggested.add(suggestion);
}
/**
* Returns secret case file containing the winning combo of location/weapon/character.
* @return Theory that represents winning combination.
*/
public CaseFile getCaseFile()
{
return caseFile;
}
/**
* Set the winning combo case file for game initialization
* @param caseFile
*/
public void setCaseFile(CaseFile caseFile)
{
this.caseFile = caseFile;
}
/**
* Tell the controller to deal the cards using the decks in this game object
*/
public void dealCards()
{
try {
this.controller.dealCards(characterDeck, weaponDeck, roomDeck);
} catch (Exception e) {
e.printStackTrace();
System.err.println("Failed to deal cards.");
}
}
@Override
public void handleMessageEvent(MessageEvent event) {
if(event.getMessage() != null){
if(event.getMessage() instanceof DrawPawnsMessage)
{
// All characters have been chosen. Set their default locations.
DrawPawnsMessage msg = (DrawPawnsMessage)event.getMessage();
Vector<Player> players = this.getPlayers();
for(CharacterName name : msg.getNames()){
HallwayName hallwy = BoardView.getDefaultHall(name);
for(Player player : players){
if(player.getCharacter() == name){
for(Location space: this.spaces){
if(space.type == LocationType.HALLWAY_TYPE){
if(((Hallway)space).getHallwayName() == hallwy){
((Hallway)space).setPlayer(player); // add the player to the location
space.setCharacterName(player.getCharacter());
}
}
}
}
}
}
}else if(event.getMessage() instanceof MoveMessage){
MoveMessage msg = (MoveMessage)event.getMessage();
// Update the spaces
for(Location space : this.getSpaces()){
boolean isNewLoc = false;
boolean isOldLoc = false;
if(space.getLocationType()==LocationType.HALLWAY_TYPE){
if(msg.getOldLocation().getLocationType()==LocationType.HALLWAY_TYPE){
if(((Hallway)space).getHallwayName() == ((Hallway)msg.getOldLocation()).getHallwayName()){
isOldLoc = true;
}
}
if(msg.getNewLocation().getLocationType()==LocationType.HALLWAY_TYPE){
if(((Hallway)space).getHallwayName() == ((Hallway)msg.getNewLocation()).getHallwayName()){
isNewLoc = true;
}
}
}else if (space.getLocationType()==LocationType.ROOM_TYPE){
if(msg.getOldLocation().getLocationType()==LocationType.ROOM_TYPE){
if(((Room)space).getRoomName() == ((Room)msg.getOldLocation()).getRoomName()){
isOldLoc = true;
}
}
if(msg.getNewLocation().getLocationType()==LocationType.ROOM_TYPE){
if(((Room)space).getRoomName() == ((Room)msg.getNewLocation()).getRoomName()){
isNewLoc = true;
}
}
}
if(isOldLoc){
space.setCharacterName(null);
space.setPlayer(null);
}
if(isNewLoc){
space.setCharacterName(msg.getCharacterName());
// Now figure our which player should go there
for(Player player : this.players){
if(player.getCharacter() == msg.getCharacterName()){
space.setPlayer(player);
}
}
}
isOldLoc = false;
isNewLoc = false;
}
}
}
}
}