/*
**	Command & Conquer Renegade(tm)
**	Copyright 2025 Electronic Arts Inc.
**
**	This program is free software: you can redistribute it and/or modify
**	it under the terms of the GNU General Public License as published by
**	the Free Software Foundation, either version 3 of the License, or
**	(at your option) any later version.
**
**	This program is distributed in the hope that it will be useful,
**	but WITHOUT ANY WARRANTY; without even the implied warranty of
**	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
**	GNU General Public License for more details.
**
**	You should have received a copy of the GNU General Public License
**	along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

/*********************************************************************************************** 
 ***                            Confidential - Westwood Studios                              *** 
 *********************************************************************************************** 
 *                                                                                             * 
 *                 Project Name : Commando                                                     * 
 *                                                                                             * 
 *                     $Archive:: /Commando/Code/Combat/soldier.h                             $* 
 *                                                                                             * 
 *                      $Author:: Byon_g                                                      $* 
 *                                                                                             * 
 *                     $Modtime:: 3/29/02 1:41p                                               $* 
 *                                                                                             * 
 *                    $Revision:: 192                                                         $* 
 *                                                                                             * 
 *---------------------------------------------------------------------------------------------* 
 * Functions:                                                                                  * 
 * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */

#ifndef	SOLDIER_H
#define	SOLDIER_H

#ifndef	ALWAYS_H
	#include "always.h"
#endif

#ifndef SMARTGAMEOBJ_H
	#include "smartgameobj.h"
#endif

#ifndef HUMANSTATE_H
	#include "humanstate.h"
#endif

#ifndef	WWSTRING_H
	#include "wwstring.h"
#endif

#ifndef	__DIALOGUE_HE
	#include "dialogue.h"
#endif


struct TransitionCompletionDataStruct;
class	PrivateTimerClass;
class DynamicSpeechAnimClass;
class	TransitionEffectClass;
class PersistantSurfaceEmitterClass;

//const int NO_FLAG = -1;


/*
**
*/
typedef enum {
	SOLDIER_INNATE_EVENT_ENEMY_SEEN 		=	1 << 0,
	SOLDIER_INNATE_EVENT_FOOTSTEP_HEARD	=	1 << 1,
	SOLDIER_INNATE_EVENT_GUNSHOT_HEARD	=	1 << 2,
	SOLDIER_INNATE_EVENT_BULLET_HEARD 	=	1 << 3,
	SOLDIER_INNATE_ACTIONS					=	1 << 4,
} SoldierInnateEvents;



/*
** SoldierGameObjDef - Defintion class for a SoldierGameObj
*/
class SoldierGameObjDef : public SmartGameObjDef
{
public:
	SoldierGameObjDef( void );

	virtual uint32								Get_Class_ID( void ) const;
	virtual PersistClass *					Create( void ) const ;
	virtual bool								Save( ChunkSaveClass &csave );
	virtual bool								Load( ChunkLoadClass &cload );
	virtual const PersistFactoryClass &	Get_Factory( void ) const;

	DialogueClass *							Get_Dialog_List( void )			{ return DialogList; }

	DECLARE_EDITABLE( SoldierGameObjDef, SmartGameObjDef );

protected:
	float											TurnRate;
	float											JumpVelocity;
	float											SkeletonHeight;
	float											SkeletonWidth;
	bool											UseInnateBehavior;
	float											InnateAggressiveness;
	float											InnateTakeCoverProbability;
	bool											InnateIsStationary;
	DialogueClass								DialogList[DIALOG_MAX];
	StringClass									FirstPersonHands;
	int											HumanAnimOverrideDefID;
	int											HumanLoiterCollectionDefID;
	int											DeathSoundPresetID;

	friend	class								SoldierGameObj;
	friend	class								SoldierObserverClass;
};


/*
**
*/
class SoldierGameObj : public SmartGameObj {

public:
	SoldierGameObj();
	virtual	~SoldierGameObj();

	// Definitions
	virtual	void	Init( void );
	void	Init( const SoldierGameObjDef & definition );
	void	Copy_Settings( const SoldierGameObjDef & definition );
	void	Re_Init( const SoldierGameObjDef & definition );
	const SoldierGameObjDef & Get_Definition( void ) const ;

	// Save / Load / Construction Factory
	virtual	bool	Save( ChunkSaveClass & csave );
	virtual	bool	Load( ChunkLoadClass & cload );
	virtual	void	On_Post_Load( void );
	virtual	const	PersistFactoryClass & Get_Factory( void ) const;

	// Physics
	HumanPhysClass	*	Peek_Human_Phys( void ) const;

	// Think
	virtual	void	Think( void );
	virtual	void	Post_Think( void );
	//virtual	void	Think_Pathfind( void );

	// Control
	virtual	void	Set_Control_Owner(int control_owner);
	virtual	void	Generate_Control( void );
	virtual	void	Apply_Control( void );

	// Damage
	virtual	void	Apply_Damage( const OffenseObjectClass & damager, float scale = 1.0f, int alternate_skin = -1 );
   virtual	void	Apply_Damage_Extended( const OffenseObjectClass & offense, float scale = 1.0f,
			const	Vector3 & direction = Vector3( 0,0,0 ), const char * collision_box_name = NULL );
	virtual	void	Completely_Damaged( const OffenseObjectClass & damager ) {}
	virtual CollisionReactionType	Collision_Occurred( const CollisionEventClass & event );
	virtual	Vector3	Get_Bullseye_Position( void );

	// Turret
	virtual bool	Is_Turreted( void )					{ return false; }

	// Weapons
	virtual bool	Set_Targeting( const Vector3 & pos, bool do_tilt = true  );
	float		Get_Weapon_Height( void );
	float		Get_Weapon_Length( void );
	virtual const Matrix3D &Get_Muzzle( int index = 0 );

	bool		Detonate_C4( void )							{ return DetonateC4; }

   // Display
	virtual void Set_Weapon_Model( const char *model_name );
	virtual void Set_Weapon_Animation( const char *anim_name );
	virtual void	Start_Transition_Animation( const char * anim_name, TransitionCompletionDataStruct * completion_data );
	virtual	void	Set_Animation( const char *animation_name, bool looping = true, float frame_offset = 0.0f );
	virtual	void	Set_Blended_Animation( const char *animation_name, bool looping = true, float frame_offset = 0.0f, bool play_backwards = false );

	void	Handle_Legs( void );

	// Ladders
	void	Exit_Ladder( void );
	void	Enter_Ladder( bool top );

	// Network support
   virtual	void	Import_State_Cs( BitStreamClass & packet );
   virtual	void	Export_State_Cs( BitStreamClass & packet );
	void				Interpret_Sc_Position_Data(const Vector3 & sc_position);
	void				Interpret_Sc_State_Data(HumanStateClass::HumanStateType state, 
							int sub_state, LPCSTR trans_name, const Vector3 & velocity, const Vector3 & sc_position);
	int				Tally_Vis_Visible_Soldiers(void);
	bool				Is_In_Elevator(void);

	virtual void	Export_Creation( BitStreamClass &packet );
	virtual void	Import_Creation( BitStreamClass &packet );
	virtual void	Export_Rare( BitStreamClass &packet );
	virtual void	Import_Rare( BitStreamClass &packet );
	virtual void	Export_Occasional( BitStreamClass &packet );
	virtual void	Import_Occasional( BitStreamClass &packet );
   virtual void	Export_Frequent( BitStreamClass & packet );
   virtual void	Import_Frequent( BitStreamClass & packet );


	bool				Is_Dead( void )			{ return Get_State() == HumanStateClass::DEATH; }
	bool				Is_Destroyed( void )		{ return Get_State() == HumanStateClass::DESTROY; }
	bool				Is_Upright( void )		{ return Get_State() == HumanStateClass::UPRIGHT; }
	bool				Is_Wounded( void )		{ return Get_State() == HumanStateClass::WOUNDED; }
	bool				In_Transition( void )	{ return Get_State() == HumanStateClass::TRANSITION; }
	bool				Is_Airborne( void )		{ return Get_State() == HumanStateClass::AIRBORNE; }
	bool				Is_Crouched( void )		{ return HumanState.Get_State_Flag( HumanStateClass::CROUCHED_FLAG ); }
	bool				Is_Sniping( void )		{ return HumanState.Get_State_Flag( HumanStateClass::SNIPING_FLAG ); }
	bool				Is_Slow( void )			{ return (Get_Sub_State() & HumanStateClass::SUB_STATE_SLOW) != 0; }
	bool				Is_On_Ladder( void )		{ return Get_State() == HumanStateClass::LADDER; }
	bool				Is_State_Locked( void )	{ return HumanState.Is_Locked(); }
	bool				Is_In_Vehicle( void )	{ return Get_State() == HumanStateClass::IN_VEHICLE; }

	void				Reset_Loiter_Delay( void )				{ HumanState.Reset_Loiter_Delay(); }
	void				Set_Loiters_Allowed( bool allowed )	{ HumanState.Set_Loiters_Allowed( allowed ); }

	virtual	void	Get_Information( StringClass & string );
	//virtual	void	Get_Extended_Information( StringClass & description );
	virtual void	Get_Description(StringClass & description);

	void		Toggle_Fly_Mode( void );			// Fly mode (for debugging/screen shots)

	// Object Motion
	virtual float		Get_Max_Speed( void );
	virtual void 		Set_Max_Speed( float speed );
	virtual float		Get_Turn_Rate( void );

	// Vehicles
	void					Enter_Vehicle( VehicleGameObj * vehicle, const char * anim_name );
	void					Exit_Vehicle( void );
	void					Exit_Destroyed_Vehicle( int seat_num, const Vector3 & vehicle_pos );
	bool					Is_Permitted_To_Enter_Vehicle( void );
	VehicleGameObj	*	Get_Vehicle( void )			{ return Vehicle; }
	VehicleGameObj	*	Get_Profile_Vehicle( void );				// HACK
	bool					Use_Ladder_View( void );

	StringClass			Get_Animation_Name( void )		{ return AnimationName; }
	const char *		Get_State_Name( void )		{ return HumanState.Get_State_Name(); }
	HumanStateClass	* Get_Human_State( void )			{ return &HumanState; }

	void					Set_Model(const char *model_name);

	// Type identification
	virtual SoldierGameObj		*As_SoldierGameObj()		{ return this; };

	// Velocity
	void              Get_Velocity(Vector3 & vel);
   void              Set_Velocity(Vector3 & vel);

   void              Give_All_Weapons(void);

	bool					Can_See(SoldierGameObj * p_soldier);

	// Rendering
	void					Adjust_Skeleton( float height, float width );

	/*
	// Capture The Flag
	void					Set_Ctf_Team_Flag(int team);
	int					Get_Ctf_Team_Flag(void) {return CtfTeamFlag;}
	*/

	// Head Looking
	void					Look_At( const Vector3 & pos, float time )	{ HeadLookTarget = pos; HeadLookDuration = time; HeadLookAngle = Vector3(0,0,0); }
	void					Update_Look_At( const Vector3 & pos )			{ HeadLookTarget = pos; }
	void					Cancel_Look_At( void )								{ HeadLookDuration = 0.001F; }
	void					Look_Random( float time );
	bool					Is_Looking( void )									{ return (HeadLookDuration > 0); }
	virtual Matrix3D	Get_Look_Transform(void);

	// Head and facing
	void					Lock_Facing( PhysicalGameObj * game_obj, bool turn_body );

	// Innate Disabling
	void					Innate_Enable( int bits = 0xFFFFFFFF )	{ InnateEnableBits |= bits; }
	void					Innate_Disable( int bits = 0xFFFFFFFF )	{ InnateEnableBits &= ~bits; }
	bool					Is_Innate_Enabled( int bits = 0xFFFFFFFF )	{ return (InnateEnableBits & bits) != 0; }

	//static void			Set_Precision(void);

	// Dialog support
	void					Say_Dialogue( int dialog_id );
	static float		Say_Dynamic_Dialogue( int text_id, SoldierGameObj *speaker = NULL, AudibleSoundClass **sound_obj_to_return = NULL );
	void					Stop_Current_Speech( void );
	RenderObjClass *	Find_Head_Model( void );
	void					Prepare_Speech_Framework( void );


	//
	//	"Ghost" support.  "Ghosts" are soldier's who have their collision turned off
	// so they can walk through other soldiers.
	//
	void					Enable_Ghost_Collision( bool onoff );
	bool					Is_Soldier_Blocked( const Vector3 &curr_pos );
	bool					Is_Safe_To_Disable_Ghost_Collision( const Vector3 &curr_pos );
	

	//
	// Speech support
	//
	DynamicSpeechAnimClass *Get_Facial_Anim (void) { return SpeechAnim; }
	void							Set_Emot_Icon (const char *model_name, float duration );

	// Innate AI access
	SoldierObserverClass	*	Get_Innate_Controller( void );
	SoldierAIState		Get_AI_State( void ) const					{ return AIState; }
	void					Set_AI_State( SoldierAIState state );

	// Innate observer access
	void							Set_Innate_Observer( SoldierObserverClass * observer )	{ InnateObserver = observer; }
	SoldierObserverClass *	Get_Innate_Observer( void )	{ return InnateObserver; }
	void							Clear_Innate_Observer( void )	{ InnateObserver = NULL; }

	const char * Get_First_Person_Hands_Model_Name( void );

	void					Perturb_Position(float max_perturb = 5);

	int					Get_Key_Ring( void ) const		{ return KeyRing; }
	void					Give_Key( int key_number )		{ KeyRing |= (1 << key_number); }
	void					Remove_Key( int key_number )	{ KeyRing &= ~(1 << key_number); }
	bool					Has_Key( int key_number )		{ return ((1 << key_number) & KeyRing) != 0; }

	virtual bool		Wants_Powerups( void )							{ return Is_Human_Controlled(); }
	virtual bool		Allow_Special_Damage_State_Lock( void )	{ return (Is_Human_Controlled() == false); }

	virtual	bool	Is_Visible( void )						{ return IsVisible; }
				void	Set_Is_Visible( bool visible )		{ IsVisible = visible; }	

	//
	//	Static debug support
	//
	static void			Enable_Ghost_Collision_Debug_Display (bool onoff)	{ DisplayDebugBoxForGhostCollision = onoff; }
	static bool			Is_Ghost_Collision_Debug_Display_Enabled (void)		{ return DisplayDebugBoxForGhostCollision; }

	virtual	bool		Is_Targetable( void ) const;

	// Stealth
	virtual float		Get_Stealth_Fade_Distance(void) const;

protected:
	RenderObjClass		*	WeaponRenderModel;
	RenderObjClass		*	BackWeaponRenderModel;
	RenderObjClass		*	BackFlagRenderModel;

	AnimControlClass	*	WeaponAnimControl;
	bool						DetonateC4;
	TransitionCompletionDataStruct *	TransitionCompletionData;
	StringClass				AnimationName;
	VehicleGameObj		*	Vehicle;
	HumanStateClass		HumanState;
	float						LegFacing;		// Direction the legs are facing
	bool						SyncLegs;		// Are we in the process of syncing the legs?
	bool						LastLegMode;
	int						KeyRing;
	bool						IsUsingGhostCollision;

	DialogueClass			DialogList[DIALOG_MAX];
	AudibleSoundClass *	CurrentSpeech;

	// Head Look
	float						HeadLookDuration;
	Vector3					HeadRotation;
	Vector3					HeadLookTarget;
	Vector3					HeadLookAngle;
	float						HeadLookAngleTimer;

	HumanStateClass::HumanStateType 	Get_State( void )			{ return HumanState.Get_State(); }
	int										Get_Sub_State( void )	{ return HumanState.Get_Sub_State(); }

	void						Update_Locked_Facing( void );
	void						Update_Back_Gun( void );
	void						Set_Back_Weapon_Model( const char *model_name );
	// Move below to public?
	void						Set_Back_Flag_Model( const char *model_name, const Vector3 & tint = Vector3(0, 0, 0) );

	int						Get_Ouch_Type( const	Vector3 & direction, const char * collision_box_name ) { return HumanState.Get_Ouch_Type( direction, collision_box_name ); }
	bool						Internal_Set_Targeting( const Vector3 & pos, bool do_tilt = true  );

	ArmorWarheadManager::SpecialDamageType			SpecialDamageMode;
	float						SpecialDamageTimer;
	GameObjReference			SpecialDamageDamager;
	TransitionEffectClass * SpecialDamageEffect;
	void						Set_Special_Damage_Mode( ArmorWarheadManager::SpecialDamageType mode, ArmedGameObj * damager = NULL );

	TransitionEffectClass * HealingEffect;

	void						Handle_Head_look( void );

	//int						CtfTeamFlag; // Capture The Flag - use NO_FLAG for no flag

	GameObjReference		FacingObject;
	bool						FacingAllowBodyTurn;

	int						InnateEnableBits;
	SoldierObserverClass *InnateObserver;
	SoldierAIState			AIState;	
	
	DynamicSpeechAnimClass *SpeechAnim;
	float						GenerateIdleFacialAnimTimer;
	RenderObjClass *		HeadModel;
	RenderObjClass *		EmotIconModel;
	float						EmotIconTimer;	

	bool						InFlyMode;
	bool						IsVisible;

	bool						LadderUpMask;
	bool						LadderDownMask;

	float						ReloadingTilt;	

	bool						WeaponChanged;

	PersistantSurfaceEmitterClass * WaterWake;

	// Soldiers maintain all RenderObjs they have created for later use and saving
	// This is used for weapon models
	DynamicVectorClass<RenderObjClass*>	RenderObjList;
	void						Add_RenderObj( RenderObjClass * obj );
	RenderObjClass *		Find_RenderObj( const char * name );
	void						Reset_RenderObjs( void );

	void						Update_Healing_Effect( void );


	//
	//	Static debug support
	//
	static bool				DisplayDebugBoxForGhostCollision;

	int						Check(void);

};

#endif	//	SOLDIER_H

