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();
#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;
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;
grid[coordinates.X, coordinates.Y] = true;
}
return grid;
}
}
#endregion
#region Public Methods
public bool IsCellOpen(Point point)
{
if (!State.Map.IsCellOpen(point)) return false;
foreach (IEntity entity in State.Entities)
{
if (entity.Coordinates == point) return false;
}
return true;
}
public Game()
{
mDisplay = new Display(this);
}
public void LoadContent(ContentManager contentManager)
{
mContentManager = contentManager;
mDisplay.LoadContent(contentManager);
}
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.Map = mContentManager.Load