//-----------------------------------------------------------------------------
//
//  $Logfile:: /game/steering.h                                               $
// $Revision:: 2                                                              $
//   $Author:: Burgermac                                                      $
//     $Date:: 12/27/00 6:50 PM                                               $
//
// Copyright (C) 1998 by Ritual Entertainment, Inc.
// All rights reserved.
//
// This source may not be distributed and/or modified without
// expressly written permission by Ritual Entertainment, Inc.
//
// DESCRIPTION:
// Steering behaviors for AI.
//

#ifndef __STEERING_H__
#define __STEERING_H__

#include "g_local.h"
#include "entity.h"
#include "path.h"

class Actor;

class Steering : public Listener
{
public:
	Vector steeringforce;
	Vector origin;
	Vector movedir;
	float maxspeed;

	CLASS_PROTOTYPE( Steering );

	Steering();

	virtual void         ShowInfo( Actor& self );
	virtual void            Begin( Actor& self );
	virtual qboolean        Evaluate( Actor& self );
	virtual void            End( Actor& self );

	void                        ResetForces( void );
	void                        SetPosition( Vector pos );
	void                        SetDir( Vector dir );
	void                        SetMaxSpeed( float speed );

	virtual void            DrawForces( void );
	virtual void         Archive( Archiver& arc );
	virtual void         Unarchive( Archiver& arc );
};

inline void Steering::Archive( Archiver& arc )
{
	Listener::Archive( arc );

	arc.WriteVector( steeringforce );
	arc.WriteVector( origin );
	arc.WriteVector( movedir );
	arc.WriteFloat( maxspeed );
}

inline void Steering::Unarchive( Archiver& arc )
{
	Listener::Unarchive( arc );

	arc.ReadVector( &steeringforce );
	arc.ReadVector( &origin );
	arc.ReadVector( &movedir );
	maxspeed = arc.ReadFloat();
}

class Seek : public Steering
{
protected:
	Vector targetposition;
	Vector targetvelocity;

public:
	CLASS_PROTOTYPE( Seek );

	Seek();
	void                        SetTargetPosition( Vector pos );
	void                        SetTargetVelocity( Vector vel );
	void                 ShowInfo( Actor& self );
	qboolean                    Evaluate( Actor& self );
	virtual void         Archive( Archiver& arc );
	virtual void         Unarchive( Archiver& arc );
};

inline void Seek::Archive( Archiver& arc )
{
	Steering::Archive( arc );

	arc.WriteVector( targetposition );
	arc.WriteVector( targetvelocity );
}

inline void Seek::Unarchive( Archiver& arc )
{
	Steering::Unarchive( arc );

	arc.ReadVector( &targetposition );
	arc.ReadVector( &targetvelocity );
}

class ObstacleAvoidance : public Steering
{
protected:
	qboolean avoidwalls;

public:
	CLASS_PROTOTYPE( ObstacleAvoidance );

	ObstacleAvoidance();
	void AvoidWalls( qboolean );
	void                 ShowInfo( Actor& self );
	qboolean                    Evaluate( Actor& self );
	virtual void         Archive( Archiver& arc );
	virtual void         Unarchive( Archiver& arc );
};

inline void ObstacleAvoidance::Archive( Archiver& arc )
{
	Steering::Archive( arc );

	arc.WriteBoolean( avoidwalls );
}

inline void ObstacleAvoidance::Unarchive( Archiver& arc )
{
	Steering::Unarchive( arc );

	avoidwalls = arc.ReadBoolean();
}

class ObstacleAvoidance2 : public Steering
{
protected:
	qboolean avoidwalls;

public:
	CLASS_PROTOTYPE( ObstacleAvoidance2 );

	ObstacleAvoidance2();
	void AvoidWalls( qboolean );
	void                 ShowInfo( Actor& self );
	qboolean                    Evaluate( Actor& self );
	virtual void         Archive( Archiver& arc );
	virtual void         Unarchive( Archiver& arc );
};

inline void ObstacleAvoidance2::Archive( Archiver& arc )
{
	Steering::Archive( arc );

	arc.WriteBoolean( avoidwalls );
}

inline void ObstacleAvoidance2::Unarchive( Archiver& arc )
{
	Steering::Unarchive( arc );

	avoidwalls = arc.ReadBoolean();
}

class FollowPath : public Steering
{
protected:
	PathPtr path;
	Seek seek;
	PathNodePtr currentNode;

	void                 FindCurrentNode( Actor& self );

public:
	CLASS_PROTOTYPE( FollowPath );

	FollowPath();
	~FollowPath();
	void                        SetPath( Path* newpath );
	Path*                       SetPath( Actor& self, Vector from, Vector to );
	qboolean                    DoneWithPath( Actor& self );
	void                 ShowInfo( Actor& self );
	void                        Begin( Actor& self );
	qboolean                    Evaluate( Actor& self );
	void                        End( Actor& self );
	virtual void            DrawForces( void );
	virtual void         Archive( Archiver& arc );
	virtual void         Unarchive( Archiver& arc );
};

inline void FollowPath::Archive( Archiver& arc )
{
	Steering::Archive( arc );

	arc.WriteSafePointer( path );
	arc.WriteObject( &seek );
	arc.WriteSafePointer( currentNode );
}

inline void FollowPath::Unarchive( Archiver& arc )
{
	Steering::Unarchive( arc );

	arc.ReadSafePointer( &path );
	arc.ReadObject( &seek );
	arc.ReadSafePointer( &currentNode );
}

class Turn : public Steering
{
private:
	Seek seek;
	EntityPtr ent;
	Vector dir;
	float yaw;
	int mode;

public:
	CLASS_PROTOTYPE( Turn );

	Turn();
	void                        SetDirection( float yaw );
	void                        SetTarget( Entity* ent );
	void                 ShowInfo( Actor& self );
	void                        Begin( Actor& self );
	qboolean                    Evaluate( Actor& self );
	void                        End( Actor& self );
	virtual void         Archive( Archiver& arc );
	virtual void         Unarchive( Archiver& arc );
};

inline void Turn::Archive( Archiver& arc )
{
	Steering::Archive( arc );

	arc.WriteObject( &seek );
	arc.WriteSafePointer( ent );
	arc.WriteVector( dir );
	arc.WriteFloat( yaw );
	arc.WriteInteger( mode );
}

inline void Turn::Unarchive( Archiver& arc )
{
	Steering::Unarchive( arc );

	arc.ReadObject( &seek );
	arc.ReadSafePointer( &ent );
	arc.ReadVector( &dir );
	yaw = arc.ReadFloat();
	mode = arc.ReadInteger();
}

class Chase : public Steering
{
private:
	Seek seek;
	FollowPath follow;
	float nextpathtime;
	PathPtr path;
	Vector goal;
	EntityPtr goalent;
	PathNodePtr goalnode;
	ObstacleAvoidance avoid;
	float avoidtime;
	qboolean usegoal;
	float newpathrate;

	Vector wanderstart;
	int wander;
	float wandertime;
	Turn turnto;
	str anim;
	int stuck;
	Vector avoidvec;

public:
	CLASS_PROTOTYPE( Chase );

	Chase();
	void                        SetPath( Path* newpath );
	void                        SetGoalPos( Vector pos );
	void                        SetGoal( PathNode* node );
	void                        SetTarget( Entity* ent );
	void                 SetPathRate( float rate );
	void                 ShowInfo( Actor& self );
	Vector               ChooseRandomDirection( Actor& self );
	void                        Begin( Actor& self );
	qboolean                    Evaluate( Actor& self );
	void                        End( Actor& self );
	virtual void         Archive( Archiver& arc );
	virtual void         Unarchive( Archiver& arc );
};

inline void Chase::Archive( Archiver& arc )
{
	Steering::Archive( arc );

	arc.WriteObject( &seek );
	arc.WriteObject( &follow );
	arc.WriteFloat( nextpathtime );
	arc.WriteSafePointer( path );
	arc.WriteVector( goal );
	arc.WriteSafePointer( goalent );
	arc.WriteSafePointer( goalnode );
	arc.WriteObject( &avoid );
	arc.WriteFloat( avoidtime );
	arc.WriteBoolean( usegoal );
	arc.WriteFloat( newpathrate );
	arc.WriteVector( wanderstart );
	arc.WriteInteger( wander );
	arc.WriteFloat( wandertime );
	arc.WriteObject( &turnto );
	arc.WriteString( anim );
	arc.WriteInteger( stuck );
	arc.WriteVector( avoidvec );
}

inline void Chase::Unarchive( Archiver& arc )
{
	Steering::Unarchive( arc );

	arc.ReadObject( &seek );
	arc.ReadObject( &follow );
	nextpathtime = arc.ReadFloat();
	arc.ReadSafePointer( &path );
	arc.ReadVector( &goal );
	arc.ReadSafePointer( &goalent );
	arc.ReadSafePointer( &goalnode );
	arc.ReadObject( &avoid );
	avoidtime = arc.ReadFloat();
	usegoal = arc.ReadBoolean();
	newpathrate = arc.ReadFloat();
	arc.ReadVector( &wanderstart );
	wander = arc.ReadInteger();
	wandertime = arc.ReadFloat();
	arc.ReadObject( &turnto );
	arc.ReadString( &anim );
	stuck = arc.ReadInteger();
	arc.ReadVector( &avoidvec );
}

#endif /* steering.h */
