/*****************************************************************************
 * $Id: game_base_pilot.hh,v 1.20 2006/08/03 02:17:21 devel Exp $
 * @file
 * @author	Jim E. Brooks  http://www.jimbrooks.org
 * @brief	Auto-pilot class and AI logic.
 *//*
 * LEGAL:	COPYRIGHT (C) JIM E. BROOKS 2005
 *          THIS SOURCE CODE IS RELEASED UNDER THE TERMS
 *          OF THE GNU GENERAL PUBLIC LICENSE (GPL).
 *****************************************************************************/

#if COMPILING_GAME
#ifndef GAME_BASE_PILOT_HH
#define GAME_BASE_PILOT_HH 1

#include "gfx_machine.hh"

class PilotGame;

////////////////////////////////////////////////////////////////////////////////
/// Class for PURSUE AI.
class PursueAI
{
				PREVENT_COPYING(PursueAI)
public:
				PursueAI( void );
				~PursueAI();
	void		Init( Craft* pursuer, Dyna* target );
	bool		IfActive( void ) { return mTarget != NULL; }
	void		SelectTarget( void );
	void		Tick( void ) { mMachine->Tick(); }	// drive state-machine

private:
	void		TransformTarget( void );
	void		TransformTargetOnce( void );
	fp			GetPursuerManeuverability( uint axis );
	void		DoManeuver( uint axis );
	void		DoManeuver( uint axis, fp degManeuver, fp degTarget );
	void		Rotate( uint axis, fp deg );
	fp			CalcAngle( int ia, int ib );
	fp			CalcAngleRoll( void )	{ return CalcAngle( YY, XX ); }
	fp			CalcAnglePitch( void )	{ return CalcAngle( ZZ, YY ); }
	fp			CalcAngleYaw( void )	{ return CalcAngle( ZZ, XX ); }
	fp			ReCalcAngle( void );

public:
	// Methods invoked indirectly by state-machine:
	bool		IfRoll( void );
	bool		IfPitch( void );
	bool		IfYaw( void );
	bool		IfInlineWithTarget( void );
	bool		Roll( void );
	bool		Pitch( void );
	bool		Yaw( void );
	bool		RollWithTarget( void );
	bool		Step( void );
	bool		AdjustSpeed( void );
	bool		Fire( void );
	bool		CheckTarget( void );

private:
	Craft*			mPursuer;				// don't delete!
	Dyna*			mTarget;				// don't delete!
	Machine*		mMachine;
	int				mTickTransformTarget;	// (SM tick) to avoid calling TransformTarget() unnecessarily
	static const fp	mDegAligned[3];			// angle limit when pursuer is considered aligned with target
	static Vector3	mTargetPos;				// position of target in pursuer's local space
	/// For ReCalcAngle() and saving result.
	struct CalcAngleState
	{
		int16	mArgIa;
		int16	mArgIb;
		fp		mResult;		// resulting angle in degrees
	};
	CalcAngleState	mCalcAngle;
};

////////////////////////////////////////////////////////////////////////////////
/// Pilot class.
/// The pilot class is a state machine that executes fractions of queued maneuvers
/// across multiple frames.
class PilotGame : public Pilot
{
private:
	PREVENT_COPYING(PilotGame)
	typedef Pilot Parent;

public:
	explicit	PilotGame( Craft& owner ) : Pilot(owner) { mProbing = false; }
				~PilotGame() { }
	int			Animate( eAnimate animate );
	bool		IfProbing( void ) { return mProbing; }
	void		SetTarget( Dyna* target ) { mPursueAI.Init( GetOwner(), target ); }
	void		SelectTarget( void ) { mPursueAI.Init( GetOwner(), NULL ); mPursueAI.SelectTarget(); }

private:
	// Pilot::mOwner is Dyna* but a Craft* was certainly stored in mOwner by constructor.
	Craft*		GetOwner( void ) { return static_cast<Craft*>(&mOwner); }

	bool		mProbing;		///< true if pilot is probing (experimenting with) maneuvers
	PursueAI	mPursueAI;
};

// machine prototypes

bool
PursueIfRoll( Machine* machine );

bool
PursueIfPitch( Machine* machine );

bool
PursueIfYaw( Machine* machine );

bool
PursueIfInlineWithTarget( Machine* machine );

bool
PursueRoll( Machine* machine );

bool
PursuePitch( Machine* machine );

bool
PursueYaw( Machine* machine );

bool
PursueRollWithTarget( Machine* machine );

bool
PursueStep( Machine* machine );

bool
PursueAdjustSpeed( Machine* machine );

bool
PursueFire( Machine* machine );

bool
PursueCheckTarget( Machine* machine );

#endif // GAME_BASE_PILOT_HH
#endif // COMPILING_GAME
