/*
Copyright (C) 1997-2001 Id Software, 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 2
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, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

*/
// client.h -- primary header for client

#include "qcommon.h"
#include "q_list.h"
#include "q_field.h"
#include "uis.h"
#include "ref_public.h"
#include "key_public.h"
#include "snd_public.h"
#include "in_public.h"
#include "cd_public.h"
#include "ui_public.h"

//=============================================================================

typedef struct centity_s {
	entity_state_t	current;
	entity_state_t	prev;			// will always be valid, but might just be a copy of current

	int			serverframe;		// if not current, this ent isn't in the frame

	int			trailcount;			// for diminishing grenade trails
	vec3_t		lerp_origin;		// for trails (variable hz)

	int			fly_stoptime;
} centity_t;

#define MAX_CLIENTWEAPONMODELS		20		// PGM -- upped from 16 to fit the chainfist vwep

typedef struct clientinfo_s {
	char	name[MAX_QPATH];
	char	cinfo[MAX_QPATH];
	qhandle_t skin;
	qhandle_t icon;
	char	iconname[MAX_QPATH];
	qhandle_t model;
	qhandle_t weaponmodel[MAX_CLIENTWEAPONMODELS];
} clientinfo_t;

typedef struct {
	int		realtime;	// time sent, for calculating pings
	int		cmdNumber;	// current cmdNumber for this frame
} client_history_t;

typedef struct {
	qboolean		valid;

	int				serverFrame;
	int				deltaFrame;

	byte			areabits[MAX_MAP_AREAS / 8];
	int				areabytes;

	playerStateEx_t	ps;

	int				numEntityStates;
	int				firstEntityState;
} clientFrame_t;

//
// the client_state_t structure is wiped completely at every
// server map change
//
typedef struct client_state_s {
	int			timeoutcount;

	int			lastTransmitTime;
	int			lastTransmitCmdNumber;

	usercmd_t	cmd;
	usercmd_t	cmds[CMD_BACKUP];	// each mesage will send several old cmds
	int			cmdNumber;
	short		predicted_origins[CMD_BACKUP][3];	// for debug comparing against server
	client_history_t	history[CMD_BACKUP];

	float		predicted_step;				// for stair up smoothing
	int			predicted_step_time;
	int			predicted_step_frame;
	vec3_t		move;

	vec3_t		predicted_origin;	// generated by CL_PredictMovement
	vec3_t		predicted_angles;
	vec3_t		predicted_velocity;
	vec3_t		prediction_error;

	entity_state_t	*solidEntities[MAX_PACKET_ENTITIES];
	int				numSolidEntities;

	entity_state_t	baselines[MAX_EDICTS];

	entity_state_t	entityStates[MAX_PARSE_ENTITIES];
	int				numEntityStates;

	clientFrame_t		frames[UPDATE_BACKUP];
	clientFrame_t		frame;				// received from server
	clientFrame_t		oldframe;
	int			serverTime;
	int			surpressCount;

	int			lastframe;

	// the client maintains its own idea of view angles, which are
	// sent to the server each frame.  It is cleared to 0 upon entering each level.
	// the server sends a delta each frame which is added to the locally
	// tracked view angles to account for standing on rotating objects,
	// and teleport direction changes
	vec3_t		viewangles;

	int			time;			// this is the time value that the client
								// is rendering at.  always <= cls.realtime
	float		lerpfrac;		// between oldframe and frame


	refdef_t	refdef;
	int			lightlevel;

	vec3_t		v_forward, v_right, v_up;	// set when refdef.angles is set

	qboolean	thirdPersonView;

	// predicted values, used for smooth player entity movement in thirdperson view
	vec3_t		playerEntityOrigin;
	vec3_t		playerEntityAngles;
	
	//
	// transient data from server
	//
	char		layout[MAX_STRING_CHARS];		// general 2D overlay
	int			inventory[MAX_ITEMS];

	//
	// non-gameserver infornamtion
	// FIXME: move this cinematic stuff into the cin_t structure
	fileHandle_t cinematic_file;
	int			cinematictime;		// cls.realtime for first cinematic frame
	int			cinematicframe;
	byte   		cinematicpalette[768];
	qboolean	cinematicpalette_active;

	//
	// server state information
	//
	gametype_t		gametype;
	attractLoop_t	attractLoop;		// running the attract loop, any key will menu
	int			servercount;	// server identification for prespawns
	char		gamedir[MAX_QPATH];
	int			clientNum;			// never changed during gameplay, set by serverdata packet
	int			maxclients;
	pmoveParams_t pmp;

	char		configstrings[MAX_CONFIGSTRINGS][MAX_QPATH];
	char		mapname[MAX_QPATH]; // short format - q2dm1, etc

	int				replyTime;
	char			replyString[MAX_STRING_CHARS];

	char		loadingString[MAX_QPATH];

	//
	// locally derived information from server state
	//
	cm_t		cm;

	qhandle_t model_draw[MAX_MODELS];
	cmodel_t *model_clip[MAX_MODELS];

	qhandle_t sound_precache[MAX_SOUNDS];
	qhandle_t image_precache[MAX_IMAGES];

	clientinfo_t	clientinfo[MAX_CLIENTS];
	clientinfo_t	baseclientinfo;

	char	weaponModels[MAX_CLIENTWEAPONMODELS][MAX_QPATH];
	int		numWeaponModels;

	clientinfo_t	*crosshairPlayer;
	int				crosshairTime;
} client_state_t;

extern	client_state_t	cl;

int CL_GetSoundInfo( vec3_t origin, vec3_t forward, vec3_t right, vec3_t up );

/*
==================================================================

the client_static_t structure is persistant through an arbitrary number
of server connections

==================================================================
*/

typedef struct client_static_s {
	connstate_t	state;
	keydest_t	key_dest;

	qboolean	appactive;

	qboolean	ref_initialized;
	qboolean	input_initialized;
	qboolean	ui_initialized;
	//qboolean	cgame_initialized;

	int			userinfo_modified;
	cvar_t		*userinfo_updates[MAX_PACKET_USERINFOS];
// this is set each time a CVAR_USERINFO variable is changed
// so that the client knows to send it to the server

	int			framecount;
	int			realtime;			// always increasing, no clamping, etc
	float		frametime;			// seconds since last frame

	int			measureFramecount;
	int			measureTime;
	int			currentFPS;

// connection information
	netadr_t	serverAddress;
	char		servername[MAX_OSPATH];	// name of server from original connect
	int			connect_time;		// for connection retransmits
	int			connectCount;
	char		messageString[MAX_STRING_CHARS];

	int			quakePort;			// a 16 bit value that allows quake servers
									// to work around address translating routers
	netchan_t	*netchan;
	int			serverProtocol;		// in case we are doing some kind of version hack

	int			challenge;			// from the server to use for connecting

	fileHandle_t	download;			// file transfer from server
	char		downloadtempname[MAX_QPATH];
	char		downloadname[MAX_QPATH];
	int			downloadnumber;
	dltype_t	downloadtype;
	int			downloadpercent;

// demo recording info must be here, so it isn't cleared on level change
	qboolean	demoplayback;
	qboolean	demorecording;
	qboolean	demowaiting;	// don't record until a non-delta message is received
	int			timeDemoStart;
	int			timeDemoFrames;
	fileHandle_t	demofile;
	int				demofileSize;
	int				demofileFrameOffset;
	int             demofilePercent;
} client_static_t;

extern client_static_t	cls;

//=============================================================================

#define NOPART_GRENADE_EXPLOSION	1
#define NOPART_GRENADE_TRAIL		2
#define NOPART_ROCKET_EXPLOSION		4
#define NOPART_ROCKET_TRAIL			8

#define NOEXP_GRENADE		1
#define NOEXP_ROCKET		2

//
// cvars
//
extern	cvar_t	*cl_stereo_separation;
extern	cvar_t	*cl_stereo;

extern	cvar_t	*cl_gun;
extern	cvar_t	*cl_add_blend;
extern	cvar_t	*cl_add_lights;
extern	cvar_t	*cl_add_particles;
extern	cvar_t	*cl_add_entities;
extern	cvar_t	*cl_predict;
extern	cvar_t	*cl_footsteps;
extern	cvar_t	*cl_noskins;
extern	cvar_t	*cl_autoskins;
extern	cvar_t	*cl_kickangles;

extern	cvar_t	*cl_upspeed;
extern	cvar_t	*cl_forwardspeed;
extern	cvar_t	*cl_sidespeed;

extern	cvar_t	*cl_yawspeed;
extern	cvar_t	*cl_pitchspeed;

extern	cvar_t	*cl_run;

extern	cvar_t	*cl_anglespeedkey;

extern	cvar_t	*cl_shownet;
extern	cvar_t	*cl_showmiss;
extern	cvar_t	*cl_showclamp;

extern	cvar_t	*lookspring;
extern	cvar_t	*lookstrafe;
extern	cvar_t	*sensitivity;

extern	cvar_t	*m_pitch;
extern	cvar_t	*m_yaw;
extern	cvar_t	*m_forward;
extern	cvar_t	*m_side;

extern	cvar_t	*freelook;

extern	cvar_t	*cl_vwep;

extern cvar_t	*cl_disable_particles;
extern cvar_t	*cl_disable_explosions;
extern cvar_t	*cl_chat_notify;
extern cvar_t	*cl_chat_beep;
extern cvar_t	*cl_gibs;

extern cvar_t	*cl_demo_local_fov;
extern cvar_t	*cl_thirdperson;
extern cvar_t	*cl_thirdperson_angle;
extern cvar_t	*cl_thirdperson_range;

extern cvar_t	*cl_async;

typedef struct cdlight_s
{
	int		key;				// so entities can reuse same entry
	vec3_t	color;
	vec3_t	origin;
	float	radius;
	float	die;				// stop lighting after this time
	float	decay;				// drop this each second
	float	minlight;			// don't add when contributing less
} cdlight_t;

extern	centity_t	cl_entities[MAX_EDICTS];
extern	cdlight_t	cl_dlights[MAX_DLIGHTS];


//=============================================================================


void CL_AddNetgraph (void);

//ROGUE
typedef struct cl_sustain_s
{
	int			id;
	int			type;
	int			endtime;
	int			nextthink;
	int			thinkinterval;
	vec3_t		org;
	vec3_t		dir;
	int			color;
	int			count;
	int			magnitude;
	void		(*think)(struct cl_sustain_s *self);
} cl_sustain_t;

#define MAX_SUSTAINS		32
void CL_ParticleSteamEffect2(cl_sustain_t *self);

void CL_TeleporterParticles (entity_state_t *ent);
void CL_ParticleEffect (vec3_t org, vec3_t dir, int color, int count);
void CL_ParticleEffect2 (vec3_t org, vec3_t dir, int color, int count);

// RAFAEL
void CL_ParticleEffect3 (vec3_t org, vec3_t dir, int color, int count);


//=================================================

// ========
// PGM
typedef struct cparticle_s
{
	struct cparticle_s	*next;

	float		time;

	vec3_t		org;
	vec3_t		vel;
	vec3_t		accel;
	float		color;
	float		colorvel;
	float		alpha;
	float		alphavel;
	color_t		rgb;
} cparticle_t;


#define	PARTICLE_GRAVITY	40
#define BLASTER_PARTICLE_COLOR		0xe0
// PMM
#define INSTANT_PARTICLE	-10000.0
// PGM
// ========

void CL_ClearEffects (void);
void CL_ClearTEnts (void);
void CL_BlasterTrail (vec3_t start, vec3_t end);
void CL_QuadTrail (vec3_t start, vec3_t end);
void CL_RailTrail (vec3_t start, vec3_t end);
void CL_BubbleTrail (vec3_t start, vec3_t end);
void CL_FlagTrail (vec3_t start, vec3_t end, float color);

// RAFAEL
void CL_IonripperTrail (vec3_t start, vec3_t end);

// ========
// PGM
void CL_BlasterParticles2 (vec3_t org, vec3_t dir, unsigned int color);
void CL_BlasterTrail2 (vec3_t start, vec3_t end);
void CL_DebugTrail (vec3_t start, vec3_t end);
void CL_SmokeTrail (vec3_t start, vec3_t end, int colorStart, int colorRun, int spacing);
void CL_Flashlight (int ent, vec3_t pos);
void CL_ForceWall (vec3_t start, vec3_t end, int color);
void CL_FlameEffects (centity_t *ent, vec3_t origin);
void CL_GenericParticleEffect (vec3_t org, vec3_t dir, int color, int count, int numcolors, int dirspread, float alphavel);
void CL_BubbleTrail2 (vec3_t start, vec3_t end, int dist);
void CL_Heatbeam (vec3_t start, vec3_t end);
void CL_ParticleSteamEffect (vec3_t org, vec3_t dir, int color, int count, int magnitude);
void CL_TrackerTrail (vec3_t start, vec3_t end, int particleColor);
void CL_Tracker_Explode(vec3_t origin);
void CL_TagTrail (vec3_t start, vec3_t end, float color);
void CL_ColorFlash (vec3_t pos, int ent, int intensity, float r, float g, float b);
void CL_Tracker_Shell(vec3_t origin);
void CL_MonsterPlasma_Shell(vec3_t origin);
void CL_ColorExplosionParticles (vec3_t org, int color, int run);
void CL_ParticleSmokeEffect (vec3_t org, vec3_t dir, int color, int count, int magnitude);
void CL_Widowbeamout (cl_sustain_t *self);
void CL_Nukeblast (cl_sustain_t *self);
void CL_WidowSplash (vec3_t org);
// PGM
// ========


void CL_ParseTEnt (void);
void CL_ParseMuzzleFlash (void);
void CL_ParseMuzzleFlash2 (void);
void SmokeAndFlash(vec3_t origin);

void CL_SetLightstyle (int i);

void CL_RunParticles (void);
void CL_RunDLights (void);
void CL_RunLightStyles (void);

void CL_AddEntities (void);
void CL_AddDLights (void);
void CL_AddTEnts (void);
void CL_AddLightStyles (void);

//=================================================

//
// cl_main
//

void CL_Init (void);
void CL_Quit_f (void);
void CL_Disconnect( comErrorType_t type, const char *text );
void CL_Snd_Restart_f (void);
void CL_RequestNextDownload (void);
void CL_CheckForReply( void );
void CL_CheckForPCMD( int level, const char *string );
void CL_RegisterSounds (void);
void CL_ClearState (void);
qboolean CL_SendStatusRequest( char *buffer, int bufferSize );
void CL_RestartFilesystem( void );
void CL_RestartRefresh( void );
void CL_ClientCommand( const char *string );
void CL_UpdateLocalFovSetting( void );
void CL_FillAPI( clientAPI_t *api );

//
// cl_input
//
void CL_RegisterInput( void );
void CL_InitInput( void );
void CL_ShutdownInput( void );
void CL_InputFrame( void );
void CL_InputActivate( qboolean active );
void CL_UpdateCmd( int msec );
void CL_FinalizeCmd( void );
void CL_SendCmd( void );

//
// cl_parse.c
//
qboolean CL_CheckOrDownloadFile( const char *filename );
void CL_ParseServerMessage (void);
void CL_LoadClientinfo (clientinfo_t *ci, char *s, int playerNum);
void CL_ParseClientinfo (int player);
void CL_Download_f (void);
void CL_DeltaFrame( void );

//
// cl_view.c
//
extern	int			gun_frame;
extern	qhandle_t	gun_model;

void V_Init (void);
void V_RenderView( float stereo_separation );
void V_AddEntity (entity_t *ent);
void V_AddParticle( particle_t *p );
void V_AddLight (vec3_t org, float intensity, float r, float g, float b);
void V_AddLightStyle (int style, vec4_t value);
void CL_PrepRefresh (void);

//
// cl_tent.c
//
void CL_RegisterTEntSounds (void);
void CL_RegisterTEntModels (void);
void CL_SmokeAndFlash(vec3_t origin);

#define LASER_FADE_NOT	1
#define LASER_FADE_ALPHA	2
#define LASER_FADE_RGBA		3

typedef struct laser_s {
	entity_t	ent;
	vec3_t		start;
	vec3_t		end;
	int			fadeType;
	qboolean	indexed;
	color_t		color;
	float		width;
	int			lifeTime;
	int			startTime;
} laser_t;

laser_t *CL_AllocLaser( void );


//
// cl_pred.c
//
void CL_PredictMovement (void);
void CL_CheckPredictionError (void);
void CL_BuildSolidList( void );

//
// cl_fx.c
//
cdlight_t *CL_AllocDlight (int key);
void CL_BigTeleportParticles (vec3_t org);
void CL_RocketTrail (vec3_t start, vec3_t end, centity_t *old);
void CL_DiminishingTrail (vec3_t start, vec3_t end, centity_t *old, int flags);
void CL_FlyEffect (centity_t *ent, vec3_t origin);
void CL_BfgParticles (entity_t *ent);
void CL_AddParticles (void);
void CL_EntityEvent (entity_state_t *ent);
// RAFAEL
void CL_TrapParticles (entity_t *ent);

//
// cl_demo.c
//
void CL_InitDemos( void );
void CL_CloseDemoFile( void );
void CL_DemoFrame( int msec );

void CL_WriteDemoMessage( sizebuf_t *msgbuf, int bytesToSkip );
void CL_Stop_f( void );
void CL_Record_f( void );
qboolean CL_GetDemoInfo( const char *path, demoInfo_t *info );


//
// cl_locs.c
//
void LOC_Init( void );
void LOC_LoadLocations( void );
void LOC_FreeLocations( void );
void LOC_UpdateCvars( void );
void LOC_AddLocationsToScene( void );


//
// console.c
//
void Con_Init( void );
void Con_Shutdown( void );
void Con_DrawConsole( void );
void Con_RunConsole( void );
void Con_Print( const char *txt );
void Con_Clear_f( void );
void Con_ClearNotify_f( void );
void Con_ToggleConsole_f (void);
void Con_Close( void );
void Con_AddToNotify( qboolean add );
void Con_SetupDC( void );

void Key_Console( int key );
void Key_Message( int key );
void Char_Console( int key );
void Char_Message( int key );

//
// cl_draw.c
//
void SCR_FreeHUD_f( void );


//
// cl_ref.c
//
void	CL_InitRefresh( void );
void	CL_ShutdownRefresh( void );

extern cvar_t *vid_autorestart;

//
// cl_ui.c
//
void		CL_InitUI( void );
void		CL_ShutdownUI( void );

//
// cl_scrn.c
//

extern cvar_t		*scr_viewsize;
extern cvar_t		*scr_draw2d;

extern cvar_t		*crosshair;
extern qhandle_t	crosshair_pic;
extern int			crosshair_width, crosshair_height;

extern qhandle_t	scr_net;
extern qhandle_t	scr_font;

extern glconfig_t	scr_glconfig;
extern vrect_t		scr_vrect;		// position of render window

extern int			scr_hudWidth;
extern int			scr_hudHeight;

void	SCR_Init (void);
void	SCR_UpdateScreen (void);
void	SCR_SizeUp( void );
void	SCR_SizeDown( void );
void	SCR_CenterPrint( const char *str );
void	SCR_BeginLoadingPlaque( void );
void	SCR_EndLoadingPlaque( void );
void	SCR_DebugGraph ( float value, int color );
void	SCR_TouchPics ( void );
void	SCR_RegisterMedia( void );
void	SCR_RunConsole (void);
void	SCR_ExecuteLayoutString( const char *s );
void	SCR_DrawInventory( void );
void	SCR_DrawPause( void );
void	SCR_DrawNet( void );
void	SCR_DrawCenterString( void );


//
// cl_cin.c
//
void		SCR_PlayCinematic( const char *name );
qboolean	SCR_DrawCinematic( void );
void		SCR_RunCinematic( void );
void		SCR_StopCinematic( void );
void		SCR_FinishCinematic( void );

//
// cl_draw.c
//
void	SCR_InitDraw( void );
void	SCR_Draw2D( void );
void	SCR_LoadingString( const char *string );
float	SCR_FadeAlpha( int startTime, int visTime, int fadeTime );
void	SCR_AddToChatHUD( const char *string );
void	SCR_AddLagometerOutPacketInfo( int size );
void	SCR_AddLagometerPacketInfo( void );
void	SCR_ClearLagometer( void );
void	SCR_ClearChatHUD_f( void );

//
// keys.c
//

void	Key_Init( void );
void	Key_Event( uint32 key, qboolean down, uint32 time );
void	Key_CharEvent( int key );
void	Key_WriteBindings( fileHandle_t f );

qboolean	Key_GetOverstrikeMode( void );
void		Key_SetOverstrikeMode( qboolean overstrike );
keydest_t	Key_GetDest( void );
void		Key_SetDest( keydest_t dest );

qboolean	Key_IsDown( int key );
qboolean	Key_AnyKeyDown( void );
void		Key_ClearStates( void );

char	*Key_KeynumToString ( int keynum );
void	Key_SetBinding( int keynum, const char *binding );
char	*Key_GetBinding( const char *binding );
int		Key_EnumBindings( int key, const char *binding );

void Key_FillAPI( keyAPI_t *api );







