/*****************************************************************************
 * $Id: game_base_class.hh,v 1.27 2006/08/10 03:18:58 devel Exp $
 * @file
 * @author	Jim E. Brooks  http://www.jimbrooks.org
 * @brief	Game base class.
 * @remarks	Moving this out of the main header file solved header dependencies.
 *//*
 * LEGAL:	COPYRIGHT (C) 2004 JIM E. BROOKS
 *          THIS SOURCE CODE IS RELEASED UNDER THE TERMS
 *          OF THE GNU GENERAL PUBLIC LICENSE (GPL).
 *****************************************************************************/

#ifndef GAME_BASE_CLASS_HH
#define GAME_BASE_CLASS_HH 1

// Rule: Don't put any #includes!
#include "game_base_tracer.hh" // an exception to the rule, needed by Dlist<Tracer> member

////////////////////////////////////////////////////////////////////////////////
/// @brief Game class.
/// @remarks Game object construction and starting a game are separated as a Game object
/// is needed early in program initialization before the game starts.
class Game
{
PREVENT_COPYING(Game)
// Interface:
public:						Game( void );
public:		virtual			~Game();
protected:	int				Init( int argc, char** argv, const string& appname );
public:		virtual void	Cmdarg( int argc, char** argv );
public:		virtual void	Start( void );
public:		virtual void	End( void );
private:	void			SelfChecks( void );
public:		virtual void	ResetScene( void ) = 0;
public:		virtual int		Animate( void );
public:		virtual void	Tick( void );
public:		void			PollInput( void );
public:		virtual bool	IfEasterEgg( void ) { return false; }
public:		virtual bool	IfRude( void ) { return false; }

// Initialization:
private:	void			StartStopListeners( bool start );

// Much joystick functionality is common to all game modules,
// but keyboard assignments are considered game-specific.

// Keyboard:
protected:	virtual bool	IfAnyKeyPressed( void ) = 0;
protected:	virtual void	PollKeyboard( void ) = 0;
protected:	virtual int		Keyboard( Dyna& dyna, const KeyEvent& keyEvent ) = 0;
protected:	virtual int		KeyboardSpecial( Dyna& dyna, const KeyEvent& keyEvent ) = 0;

// Joystick:
// (GameJoystick object)

// Configuration:
protected:	virtual bool	SaveState( bool saveView ) = 0;
protected:	virtual bool	LoadState( void ) = 0;
protected:	bool			SaveStateBase( bool saveView, ConfigFile& config );
protected:	bool			LoadStateBase( bool loadView, ConfigFile& config );
protected:	virtual ConfigFile&	GetConfigFile( void ) = 0;
protected:	ConfigFile& 		GetConfigFileBase( const string& appname );
protected:	virtual void	CloseConfigFile( void );
protected:	string			GetInstallDir( const string& execName, char** argv );

// Misc:
public:		virtual bool	IfTexturing( void ) { return mTexturing; }
public:		virtual void	SetTexturing( bool f ) { mTexturing = f; }
public:		const Matrix&	GetPlayerMatrix( void );
public:		void			SetPlayer( int n ) { mPlayer = n==1 ? mPlayer1 : mPlayer2; }
public:		CraftPtrc		GetPlayerCraft( void ) { return mPlayer == mPlayer1 ? mPlayer1Craft : mPlayer2Craft; }
public:		bool			IsFriendlyCraft( const Craft& craft ) { return &craft == mPlayer1Craft || &craft == mPlayer2Craft; }
public:		Percent			GetControlResponse( void );
public:		void			IncControlResponse( int dir );
public:		void			SetControlResponse( Dyna& dyna, Percent n );
public:		const vector<string>& GetTextureDirVec( void ) { return mTextureDirVec; }
public:		bool			IfCollisions( void ) { return mCollisions; }
public:		void			EnableCollisions( bool f ) { mCollisions = f; gEng.EnableCollisions( f ); }
public:		void			ToggleCollisions( void ) { EnableCollisions( ! mCollisions ) ; }
#if DEBUG
protected:	virtual void	EndDebug( void );
#endif

// Data members:
private:	bool			mCollisions;			///< NOTE: Use EnableCollisions() to inform engine!!
protected:	bool			mTexturing;				///< true if texturing is enabled
public:		bool			mDemoMode;
public:		Percent 		mControlResponseEye;	///< access using ControlResponse() functions
public:		Percent			mControlResponseChase;	///< 0 means default, not 0%
protected:	string			mConfigFilename;		///< empty unless -config <fname> was passed (ConfigFile chooses filename if empty)
protected:	string			mCwd;
public:		Dlist<Craft>	mCraftDlist;
public:		Dlist<DynaModel> mDynaModelTargetDlist;	///< only DynaModels which are targets (collidable/explosive)
public:		Dlist<Tracer>	mTracerDlist;
public:		CraftPtr		mPlayer;				///< current/active player
public:		CraftPtr		mPlayer1Craft;
public:		CraftPtr		mPlayer2Craft;
protected:	CraftPtr		mPlayer1;
protected:	CraftPtr		mPlayer2;
protected:	DynaConfigState mEyeConfigState;
protected:	vector<string>	mTextureDirVec;			///< directories have trailing slash
protected:	InputQueue		mInputQueue;			///< keyboard/joystick input queue
protected:	int				mDefaultWindowWidth;
protected:	int				mDefaultWindowHeight;
#if STATS && COMPILING_GAME
public:		GameStats		mStatsBase;
#endif

protected:
	////////////////////////////////////////////////////////////////////////////////
	/// @brief Command-line args.
	/// Only those args whose values are needed after initialization are defined.
	/// The base Game class and derived Game classes have separate Cmdarg objects.
	struct GameCmdarg
	{
		GameCmdarg( void )
		{
			mArgc = 0;
			mArgv = NULL;
			mArgv0 = "";

			mJoy = \
			mJoyAxis3 = \
			mJoyCalibration = \
			mCollisions = false;
		}
		int		mArgc;
		char**	mArgv;
		string	mArgv0;
		bool	mJoy;
		bool	mJoyAxis3;
		bool	mJoyCalibration;
		bool	mCollisions;
	};
	GameCmdarg	mCmdargBase;

#define GAME_BASE_LISTENERS_FRIEND 1
#include "game_base_listeners.hh"
#undef  GAME_BASE_LISTENERS_FRIEND

friend class GameJoystick;
};

////////////////////////////////////////////////////////////////////////////////
/// @brief Game base event nexus.
/// @remarks The base game module broadcasts events out to listener functions in other modules.
/// Using this event mechanism helps make it modular.
class GameBaseEvents
{
	PREVENT_COPYING(GameBaseEvents)
public:
	GameBaseEvents( void ) { }
	~GameBaseEvents() { }
public:
	Event<void>			mPrintStats;
	Event<eJoyButton>	mJoystickButton;
};
extern GameBaseEvents gGameBaseEvent;

#endif // GAME_BASE_CLASS_HH
