#ifndef __CRAWLER_H__
#define __CRAWLER_H__

#include "g_local.h"
#include "actor.h"
#include "specialfx.h"
#include "weapon.h"
#include "ceilingsteering.h"

//===============================================================
// crawler weapon

class CrawlerGoo : public Projectile
{
public:
	CLASS_PROTOTYPE( CrawlerGoo );

	CrawlerGoo();

	void Setup( Entity *owner, Vector pos, Vector vel );
	void FadeOut( Event *ev );
	void GooTouch( Event *ev );
};

class CrawlerWeapon : public Weapon
{
public:
	CLASS_PROTOTYPE( CrawlerWeapon );

	CrawlerWeapon();
	virtual void Shoot( Event *ev );
};

//===============================================================
// da crawler

class Crawler : public Actor
{
public:
	qboolean onceiling;
	qboolean likesceiling; // true if he'd rather be on the ceiling
	int ceilingheight;

	void JumpToCeilingEvent( Event *ev );
	void OrientToCeilingEvent( Event *ev );

	void LikesCeilingEvent( Event *ev );
	void LikesFloorEvent( Event *ev );
	void CeilingHeightEvent( Event *ev );

	void IfOnCeilingEvent( Event *ev );
	void IfOnFloorEvent( Event *ev );
	void IfCeilingOKEvent( Event *ev );

	CLASS_PROTOTYPE( Crawler );

	Crawler();
	void IdleEvent( Event *ev );
	void Pain( Event *ev );
	void Dead( Event *ev );
	void Killed( Event *ev );
	qboolean CanMoveTo( Vector pos );
	virtual qboolean CanShootFrom( Vector pos, Entity *ent, qboolean usecurrentangles );

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

inline void Crawler::Archive( Archiver &arc )
{
	Actor::Archive( arc );

	arc.WriteBoolean( onceiling );
	arc.WriteBoolean( likesceiling );
	arc.WriteInteger( ceilingheight );
}

inline void Crawler::Unarchive( Archiver &arc )
{
	Actor::Unarchive( arc );

	onceiling = arc.ReadBoolean();
	likesceiling = arc.ReadBoolean();
	ceilingheight = arc.ReadInteger();
}

//===============================================================
// crawler behaiviors

class JumpToCeiling : public Behavior
{
private:
//	float						nexttwitch;
//	str						anim;
	float jumpchance;

public:
	CLASS_PROTOTYPE( JumpToCeiling );

	JumpToCeiling();
	void                        SetArgs( Event *ev );
	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 JumpToCeiling::Archive( Archiver &arc )
{
	Behavior::Archive( arc );

//	arc.WriteFloat( nexttwitch );
//	arc.WriteString( anim );
	arc.WriteFloat( jumpchance );
}

inline void JumpToCeiling::Unarchive( Archiver &arc )
{
	Behavior::Unarchive( arc );

	jumpchance = arc.ReadFloat();
}

class CrawlerFindEnemy : public Behavior
{
private:
	str anim;
	str ceilinganim;
	Chase chase;
	CeilingChase ceilingchase;
	int state;
	float nextsearch;
	PathNodePtr lastSearchNode;
	Vector lastSearchPos;
	qboolean lastceilingstate;

public:
	CLASS_PROTOTYPE( CrawlerFindEnemy );

	PathNode                    *FindClosestSightNode( Actor &self );
	void SetArgs( Event *ev );
	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 CrawlerFindEnemy::Archive( Archiver &arc )
{
	Behavior::Archive( arc );

	arc.WriteString( anim );
	arc.WriteString( ceilinganim );
	arc.WriteObject( &chase );
	arc.WriteObject( &ceilingchase );
	arc.WriteInteger( state );
	arc.WriteFloat( nextsearch );
	arc.WriteSafePointer( lastSearchNode );
	arc.WriteVector( lastSearchPos );
	arc.WriteBoolean( lastceilingstate );
}

inline void CrawlerFindEnemy::Unarchive( Archiver &arc )
{
	Behavior::Unarchive( arc );

	arc.ReadString( &anim );
	arc.ReadString( &ceilinganim );
	arc.ReadObject( &chase );
	arc.ReadObject( &ceilingchase );
	state = arc.ReadInteger();
	nextsearch = arc.ReadFloat();
	arc.ReadSafePointer( &lastSearchNode );
	arc.ReadVector( &lastSearchPos );
	lastceilingstate = arc.ReadBoolean();
}

class CrawlerIdle : public Behavior
{
private:
	float nexttwitch;
	str anim;
	str ceilinganim;
	qboolean lastceilingstate;

public:
	CLASS_PROTOTYPE( CrawlerIdle );

	void SetArgs( Event *ev );
	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 CrawlerIdle::Archive( Archiver &arc )
{
	Behavior::Archive( arc );

	arc.WriteFloat( nexttwitch );
	arc.WriteString( anim );
	arc.WriteString( ceilinganim );
	arc.WriteBoolean( lastceilingstate );
}

inline void CrawlerIdle::Unarchive( Archiver &arc )
{
	Behavior::Unarchive( arc );

	nexttwitch = arc.ReadFloat();
	arc.ReadString( &anim );
	arc.ReadString( &ceilinganim );
	lastceilingstate = arc.ReadBoolean();
}

class CrawlerStrafeTo : public Behavior
{
private:
	Vector goal;
	Seek seek;
	int fail;
	qboolean lastceilingstate;

public:
	CLASS_PROTOTYPE( CrawlerStrafeTo );

	void ShowInfo( Actor &self );
	void SetArgs( Event *ev );
	void Begin( Actor &self );
	qboolean Evaluate( Actor &self );
	void End( Actor &self );
	virtual void Archive( Archiver &arc );
	virtual void Unarchive( Archiver &arc );
};

inline void CrawlerStrafeTo::Archive( Archiver &arc )
{
	Behavior::Archive( arc );

	arc.WriteVector( goal );
	arc.WriteObject( &seek );
	arc.WriteInteger( fail );
	arc.WriteBoolean( lastceilingstate );
}

inline void CrawlerStrafeTo::Unarchive( Archiver &arc )
{
	Behavior::Unarchive( arc );

	arc.ReadVector( &goal );
	arc.ReadObject( &seek );
	fail = arc.ReadInteger();
	lastceilingstate = arc.ReadBoolean();
}

class CeilingStrafeAttack : public Behavior
{
private:
	int state;
	TurnTo turn;

public:

	CLASS_PROTOTYPE( CeilingStrafeAttack );

	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 CeilingStrafeAttack::Archive( Archiver &arc )
{
	Behavior::Archive( arc );

	arc.WriteInteger( state );
	arc.WriteObject( &turn );
}

inline void CeilingStrafeAttack::Unarchive( Archiver &arc )
{
	Behavior::Unarchive( arc );

	state = arc.ReadInteger();
	arc.ReadObject( &turn );
}

#endif /* crawler.h */
