using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
namespace CarFire
{
///
/// Container class for the whole state of the game.
///
public class GameState
{
#region Public Properties
public long FrameNumber { get { return mFrameNumber; } }
public long Checksum { get { return mChecksum; } }
public int NumberOfPlayers { get { return mNumberOfPlayers; } }
public Map Map;
public List Entities = new List();
public List mProjectiles = new List();
public Player[] mCharacters;
public Display mDisplay;
#endregion
#region Public Methods
///
/// Construct a game state container with the number of players.
///
/// Number of players.
public GameState(int numPlayers)
{
mNumberOfPlayers = numPlayers;
mFrameNumber = 0;
mCharacters = new Player[numPlayers];
mIsGameOver = new bool[numPlayers];
mIsTerminated = new bool[numPlayers];
mMouseLocation = new Point[numPlayers];
mMouseButton = new bool[numPlayers];
mKeysDown = new List[numPlayers];
for (int i = 0; i < numPlayers; i++) mKeysDown[i] = new List();
mKeypressCount = new int[numPlayers];
mElapsedTime = 0;
mChecksum = 0;
}
///
/// Should be called by the Game class to advance the state
/// to the next frame.
///
/// The inputs that occurred to be
/// applied this coming frame.
/// Milliseconds; used for the checksum.
public void AdvanceFrame(NextInputs inputs, long milliseconds)
{
mFrameNumber++;
mElapsedTime += milliseconds;
for (int player = 0; player < NumberOfPlayers; player++)
{
if (inputs.IsMousePressedChanged[player])
{
mMouseButton[player] = inputs.MousePressed[player];
}
if (inputs.IsMouseLocationChanged[player])
{
mMouseLocation[player] = inputs.MouseLocation[player];
}
foreach (Keys k in inputs.KeysPressed[player])
{
if (!mKeysDown[player].Contains(k))
{
mKeysDown[player].Add(k);
mKeypressCount[player]++;
}
}
foreach (Keys k in inputs.KeysReleased[player]) mKeysDown[player].Remove(k);
}
ComputeChecksum();
}
///
/// Get the mouse location for a player.
///
/// Player Number.
/// Mouse location.
public Point GetMouseLocation(int playerNum)
{
return mMouseLocation[playerNum];
}
///
/// Get the mouse button state for a player.
///
/// Player number.
/// Mouse button state..
public bool GetMouseButton(int playerNum)
{
return mMouseButton[playerNum];
}
///
/// Get the keyboard state for a player.
///
/// Player number.
/// Keyboard state.
public List GetKeysDown(int playerNum)
{
return mKeysDown[playerNum];
}
#endregion
#region Private Methods
// Calculates a checksum for debugging network synchronization issues.
long ComputeChecksum()
{
mChecksum += FrameNumber;
for (int i = 0; i < NumberOfPlayers; i++)
{
mChecksum = mChecksum + mKeypressCount[i];
mChecksum = mChecksum * 3 + (mIsGameOver[i] ? 1 : 2);
mChecksum = mChecksum * 3 + (mIsTerminated[i] ? 1 : 2);
foreach (Keys k in mKeysDown[i])
mChecksum = mChecksum * 257 + (int)k;
mChecksum = mChecksum * 25789 + mMouseLocation[i].X * 259 + mMouseLocation[i].Y + 375;
mChecksum = mChecksum * 3 + (mMouseButton[i] ? 1 : 2);
}
mChecksum += mElapsedTime;
return mChecksum;
}
#endregion
#region Private Variables
int mNumberOfPlayers;
public Point[] mMouseLocation;
public bool[] mMouseButton;
public List[] mKeysDown;
long mFrameNumber;
bool[] mIsGameOver;
bool[] mIsTerminated;
int[] mKeypressCount;
long mElapsedTime;
long mChecksum;
#endregion
}
///
/// Container class for all the inputs for a single frame.
///
public class NextInputs
{
public List[] KeysPressed;
public List[] KeysReleased;
public Point[] MouseLocation;
public bool[] IsMouseLocationChanged;
public bool[] MousePressed;
public bool[] IsMousePressedChanged;
public NextInputs(int numPlayers)
{
KeysPressed = new List[numPlayers];
KeysReleased = new List[numPlayers];
IsMouseLocationChanged = new bool[numPlayers];
MousePressed = new bool[numPlayers];
IsMousePressedChanged = new bool[numPlayers];
for (int i = 0; i < numPlayers; i++) KeysPressed[i] = new List();
for (int i = 0; i < numPlayers; i++) KeysReleased[i] = new List();
}
}
///
/// The big kahuna.
///
public class Game : IDeterministicGame
{
#region Public Properties
///
/// Get the content manager associated with this game.
///
public ContentManager ContentManager { get { return mContentManager; } }
///
/// Get the state.
///
public GameState State;
public bool[,] Grid
{
get
{
bool[,] grid = State.Map.Grid;
foreach (IEntity entity in State.Entities)
{
Point coordinates = entity.Coordinates;
if (State.Map.IsCellOpen(coordinates)) grid[coordinates.X, coordinates.Y] = false;
}
return grid;
}
}
#endregion
#region Public Methods
public IEntity GetEntityAtCoordinates(Point point)
{
foreach (IEntity entity in State.Entities)
{
if (entity.Coordinates == point) return entity;
}
return null;
}
public Player GetPlayerAtCoordinates(Point point)
{
foreach (Player player in State.mCharacters)
{
if (player != null && player.Coordinates == point) return player;
}
return null;
}
public bool IsCellOpen(Point point)
{
if (!State.Map.IsCellOpen(point)) return false;
if (GetEntityAtCoordinates(point) != null) return false;
return true;
}
public Game()
{
}
///
/// This method should be called whenever the players want to move to a new map.
/// Not implemented yet. Need some way to get next map.
///
public void startNewMap()
{
//TODO somehow get next map
State.Entities.Clear();
//State.Map = State.Map.getNextMap();
for (int i = 0; i < State.mCharacters.Length; i++)
{
State.mCharacters[i].Coordinates = State.Map.GetStartingPositionForPlayer(i + 1);
}
State.Entities = State.Map.GetAllEntities(this);
}
public void LoadContent(ContentManager contentManager)
{
mContentManager = contentManager;
menu = mContentManager.Load("menuFont");
}
public void UnloadContent()
{
}
private int GetPlayerNumber(Object playerIdentifier)
{
for (int i = 0; i < mPlayerIdentifiers.Length; i++)
{
if (mPlayerIdentifiers[i] == playerIdentifier) return i;
}
throw new Exception("Illegal player identifier" + playerIdentifier);
}
public Vector2 PreferredScreenSize
{
get { return new Vector2(800, 600); }
}
public int MinimumSupportedPlayers
{
get { return 1; }
}
public int MaximumSupportedPlayers
{
get { return 4; }
}
public void ResetGame(object[] playerIdentifiers, object thisPlayer)
{
int numPlayers = playerIdentifiers.Count();
mPlayerIdentifiers = new object[numPlayers];
for (int i = 0; i < numPlayers; i++) mPlayerIdentifiers[i] = playerIdentifiers[i];
mThisPlayerID = GetPlayerNumber(thisPlayer);
State = new GameState(numPlayers);
mInputs = new NextInputs(numPlayers);
State.mDisplay = new Display(this);
State.mDisplay.LoadContent(mContentManager);
Texture2D mapTiles = mContentManager.Load("graphics/wallAndFloorTilesNoEdgeScale");
Tilemap tilemap = new Tilemap(mapTiles, 10, 7);
tilemap.SetTile(' ', new Point(4, 5));
tilemap.SetTile('`', new Point(0, 1));
tilemap.SetTile('~', new Point(1, 1));
tilemap.SetTile('!', new Point(3, 1));
tilemap.SetTile('@', new Point(4, 1));
tilemap.SetTile('#', new Point(5, 1));
tilemap.SetTile('$', new Point(6, 1));
tilemap.SetTile('%', new Point(8, 1));
tilemap.SetTile('^', new Point(9, 1));
tilemap.SetTile('&', new Point(0, 2));
tilemap.SetTile('=', new Point(1, 2));
tilemap.SetTile('*', new Point(2, 2));
tilemap.SetTile('(', new Point(4, 2));
tilemap.SetTile(')', new Point(0, 3));
tilemap.SetTile('_', new Point(2, 3));
tilemap.SetTile('-', new Point(9, 3));
tilemap.SetTile(',', new Point(1, 4));
tilemap.SetTile('+', new Point(2, 4));
tilemap.SetTile('[', new Point(3, 4));
tilemap.SetTile(']', new Point(4, 4));
tilemap.SetTile('{', new Point(5, 4));
tilemap.SetTile('}', new Point(6, 4));
tilemap.SetTile('\\', new Point(8, 4));
tilemap.SetTile('|', new Point(9, 4));
tilemap.SetTile(';', new Point(0, 5));
tilemap.SetTile(':', new Point(1, 5));
tilemap.SetTile('\'', new Point(2, 5));
tilemap.SetTile('"', new Point(3, 5));
tilemap.SetTile('.', new Point(5, 5));
tilemap.SetTile('<', new Point(6, 5));
tilemap.SetTile('>', new Point(7, 5));
tilemap.SetTile('/', new Point(8, 5));
tilemap.SetTile('?', new Point(9, 5));
State.Map = mContentManager.Load