/*
Copyright (C) 2002-2003 Victor Luchits

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.
*/

#include "cg_local.h"
#ifdef DEMOCAM
#include "cg_democams.h"
#endif

struct mempool_s *cgamepool;

cg_static_t		cgs;
cg_state_t		cg;

centity_t		cg_entities[MAX_EDICTS];

cvar_t			*cg_noSkins;
cvar_t			*cg_vwep;
cvar_t			*cg_predict;
cvar_t			*cg_showMiss;

cvar_t			*model;// wsw : jal
cvar_t			*skin;
cvar_t			*hand;

cvar_t			*cg_addDecals;

cvar_t			*cg_footSteps;

cvar_t			*cg_gun;
cvar_t			*cg_timedemo;

cvar_t			*cg_thirdPerson;
cvar_t			*cg_thirdPersonAngle;
cvar_t			*cg_thirdPersonRange;

//splitmodels	
cvar_t			*cg_weaponFlashes;
cvar_t			*cg_ejectBrass;	//eject brass-debris
cvar_t			*cg_gunx;
cvar_t			*cg_guny;
cvar_t			*cg_gunz;
cvar_t			*cg_debugPlayerModels;
cvar_t			*cg_debugWeaponModels;
cvar_t			*cg_bobSpeed;
cvar_t			*cg_bobPitch;
cvar_t			*cg_bobYaw;
cvar_t			*cg_bobRoll;

cvar_t			*developer;

// wsw : jal
cvar_t			*cg_handOffset;
cvar_t			*cg_volume_players;
cvar_t			*cg_volume_effects;
cvar_t			*cg_volume_announcer;
cvar_t			*cg_volume_voicechats;
cvar_t			*cg_grenadeTrail;
cvar_t			*cg_rocketTrail;
cvar_t			*cg_bloodTrail;
cvar_t			*cg_showBloodTrail;
cvar_t			*cg_grenadeTrailAlpha;
cvar_t			*cg_rocketTrailAlpha;
cvar_t			*cg_bloodTrailAlpha;
cvar_t			*cg_explosionsAlpha;
cvar_t			*cg_explosionsRingAlpha;
cvar_t			*cg_gibs;
cvar_t			*cg_outlineModels;
cvar_t			*cg_outlineItemsBlack;
cvar_t			*cg_outlinePlayersBlack;
cvar_t			*cg_demo_truePOV;
cvar_t			*cg_fov;
cvar_t			*cg_predictLaserBeam;
cvar_t			*cg_voiceChats;
#ifdef CGAMEGETLIGHTORIGIN
cvar_t			*cg_shadows;
#endif
cvar_t			*cg_showPlayerTrails;
cvar_t			*cg_playerTrailsColor;
cvar_t			*cg_laserBeamSubdivisions;

// wsw : pb
cvar_t			*cg_volume_hitsound;
cvar_t			*cg_autoaction;
cvar_t			*cg_simpleItems;
cvar_t			*cg_simpleItemsSize;
cvar_t			*cg_showObituaries; 	// wsw : pb : where are obituaries printed
cvar_t			*cg_particles;
cvar_t			*cg_showhelp;
cvar_t	        *cg_scoreboardStats;

// wsw : mdr
cvar_t			*cg_damage_kick;
cvar_t			*cg_damage_blend;
cvar_t			*cg_pickup_flash;

// force models
cvar_t			*cg_teamPLAYERSmodel;
cvar_t	        *cg_teamREDmodel;
cvar_t	        *cg_teamBLUEmodel;
cvar_t	        *cg_teamGREENmodel;
cvar_t	        *cg_teamYELLOWmodel;

cvar_t			*cg_teamPLAYERSskin;
cvar_t	        *cg_teamREDskin;
cvar_t	        *cg_teamBLUEskin;
cvar_t	        *cg_teamGREENskin;
cvar_t	        *cg_teamYELLOWskin;

cvar_t			*cg_teamPLAYERScolor;
cvar_t	        *cg_teamREDcolor;
cvar_t	        *cg_teamBLUEcolor;
cvar_t	        *cg_teamGREENcolor;
cvar_t	        *cg_teamYELLOWcolor;

cvar_t	        *cg_forceEnemyTeam;
cvar_t	        *cg_forceMyTeam;

/*
============
CG_Error
============
*/
int CG_API( void ) {
	return CGAME_API_VERSION;
}

/*
============
CG_Error
============
*/
void CG_Error( char *fmt, ... )
{
	char		msg[1024];
	va_list		argptr;

	va_start ( argptr, fmt );
	if( vsprintf (msg, fmt, argptr) > sizeof(msg) )
		trap_Error ( "CG_Error: Buffer overflow" );
	va_end ( argptr );

	trap_Error ( msg );
}

/*
============
CG_Printf
============
*/
void CG_Printf( char *fmt, ... )
{
	char		msg[1024];
	va_list		argptr;

	va_start ( argptr, fmt );
	if( vsprintf (msg, fmt, argptr) > sizeof(msg) )
		trap_Error ( "CG_Print: Buffer overflow" );
	va_end ( argptr );

	trap_Print ( msg );
}

/*
=================
CG_CopyString
=================
*/
char *CG_CopyString( char *in )
{
	char	*out;
	
	out = CG_Malloc( strlen(in) + 1 );
	strcpy( out, in );

	return out;
}
/*
void CG_RegisterForceModels( void ) {
	int rgbcolor;
	int	i;
	char	*s;
	cg_enemyModel->modified = qfalse;
	cg_enemySkin->modified = qfalse;
	cg_enemyColor->modified = qfalse;
	if( strlen(cg_enemyModel->string) ) {
		cgs.enemyPModelInfo = CG_RegisterPlayerModel( va( "models/players/%s", cg_enemyModel->string ) );
		for( i = 0; i < GS_MAX_TEAMS; i++ ) {
			s = GS_TeamSkinName(i);
			if( s != NULL ) {
				cgs.enemySkins[i] = trap_R_RegisterSkinFile( va( "models/players/%s/%s", cg_enemyModel->string, s ) );
			} else {
				cgs.enemySkins[i] = trap_R_RegisterSkinFile( va( "models/players/%s/default", cg_enemyModel->string ) );
			}
			if( !cgs.enemySkins[i] ) // must load all the team skins to be valid
				cgs.enemyPModelInfo = NULL;
		}

		if( cgs.enemyPModelInfo && strlen(cg_enemySkin->string) ) {
			cgs.enemyCustomSkin = trap_R_RegisterSkinFile( va( "models/players/%s/%s", cg_enemyModel->string, cg_enemySkin->string ) );
			if( !cgs.enemyCustomSkin )
				cgs.enemyCustomSkin = trap_R_RegisterSkinFile( va( "models/players/%s/%s", cg_enemyModel->string, "default" ) );

			//always register the color with the skin
			if( cgs.enemyCustomSkin && strlen(cg_enemyColor->string) ) {
				rgbcolor = COM_ReadColorRGBString( cg_enemyColor->string );
				if( rgbcolor == -1 ) {
					rgbcolor = COM_ReadColorRGBString( cg_enemyColor->dvalue );
					if( rgbcolor == -1 ) {
						cgs.enemyCustomSkin = NULL; // didn't work, disable enemySkin
					}
				}
				if( rgbcolor != -1 ) {
					Vector4Set( cgs.enemyColor, COLOR_R(rgbcolor), COLOR_G(rgbcolor), COLOR_B(rgbcolor), 255 );
				}
			}
		}
	} else {
		cgs.enemyPModelInfo = NULL;
		cgs.enemyCustomSkin = NULL;
		for( i = 0; i < GS_MAX_TEAMS; i++ )
			cgs.enemySkins[i] = NULL;
	}

	cg_teamModel->modified = qfalse;
	cg_teamSkin->modified = qfalse;
	cg_teamColor->modified = qfalse;
	// team models
	if( strlen(cg_teamModel->string) ) {
		cgs.teamPModelInfo = CG_RegisterPlayerModel( va( "models/players/%s", cg_teamModel->string ) );
		for( i = 0; i < GS_MAX_TEAMS; i++ ) {
			s = GS_TeamSkinName(i);
			if( s != NULL ) {
				cgs.teamSkins[i] = trap_R_RegisterSkinFile( va( "models/players/%s/%s", cg_teamModel->string, s ) );
			} else {
				cgs.teamSkins[i] = trap_R_RegisterSkinFile( va( "models/players/%s/default", cg_teamModel->string ) );
			}
			if( !cgs.teamSkins[i] ) // must load all the team skins to be valid
				cgs.teamPModelInfo = NULL;
		}

		if( cgs.teamPModelInfo && strlen(cg_teamSkin->string) ) {
			cgs.teamCustomSkin = trap_R_RegisterSkinFile( va( "models/players/%s/%s", cg_teamModel->string, cg_teamSkin->string ) );
			if( !cgs.teamCustomSkin )
				cgs.teamCustomSkin = trap_R_RegisterSkinFile( va( "models/players/%s/%s", cg_teamModel->string, "default" ) );

			//always register the color with the skin
			if( cgs.teamCustomSkin && strlen(cg_teamColor->string) ) {
				rgbcolor = COM_ReadColorRGBString( cg_teamColor->string );
				if( rgbcolor == -1 ) {
					rgbcolor = COM_ReadColorRGBString( cg_teamColor->dvalue );
					if( rgbcolor == -1 ) {
						cgs.teamCustomSkin = NULL;
					}
				}
				if( rgbcolor != -1 ) {
					Vector4Set( cgs.teamColor, COLOR_R(rgbcolor), COLOR_G(rgbcolor), COLOR_B(rgbcolor), 255 );
				}
			}
		}
	} else {
		cgs.teamPModelInfo = NULL;
		cgs.teamCustomSkin = NULL;
		for( i = 0; i < GS_MAX_TEAMS; i++ )
			cgs.teamSkins[i] = NULL;
	}
}
*/
/*
=================
CG_RegisterModels
=================
*/
void CG_RegisterModels( void )
{
	int i;
	char *name;

	name = cgs.configStrings[CS_MODELS+1];
	CG_LoadingString( name );

	trap_R_RegisterWorldModel( name );

	CG_LoadingString( "models" );

	cgs.numWeaponModels = 1;
	Q_strncpyz( cgs.weaponModels[0], "generic/generic.md3", sizeof(cgs.weaponModels[0]) );

	for ( i = 1; i < MAX_MODELS; i++ )
	{
		name = cgs.configStrings[CS_MODELS+i];
		if( !name[0] )
			break;
		if( name[0] == '#' ) {	// special player weapon model
			if ( cgs.numWeaponModels < WEAP_TOTAL ) {
				Q_strncpyz( cgs.weaponModels[cgs.numWeaponModels], name+1, sizeof(cgs.weaponModels[cgs.numWeaponModels]) );
				cgs.numWeaponModels++;
			}
		//splitmodels [start]
		} else if( name[0] == '$' ) {	// indexed pmodel
			cgs.pModelsIndex[i] = CG_RegisterPlayerModel( name+1 );
		//[end]
		} else {
			CG_LoadingFilename( name );
			cgs.modelDraw[i] = CG_RegisterModel( name );	// skelmod
		}
	}

	for( i = 1; i < trap_CM_NumInlineModels (); i++ )
		cgs.inlineModelDraw[i] = CG_RegisterModel( va("*%i", i) );	// skelmod (not needed, but let's keep a style)

	CG_RegisterMediaModels();
	CG_RegisterBasePModel();	// never before registering the weapon models

	// precache forcemodels if defined
	CG_RegisterForceModels();

	// create a tag to offset the weapon models when seen in the world as items
	VectorSet( cgs.weaponItemTag.origin, 0, 0, 0 );
	Matrix_Copy( axis_identity, cgs.weaponItemTag.axis );
	VectorMA( cgs.weaponItemTag.origin, -14, cgs.weaponItemTag.axis[0], cgs.weaponItemTag.origin );
}

/*
=================
CG_RegisterSounds
=================
*/
void CG_RegisterSounds( void )
{
	int i;
	char *name;

	CG_LoadingString( "sounds" );

	for( i = 1; i < MAX_SOUNDS; i++ ) {
		name = cgs.configStrings[CS_SOUNDS+i];

		if( !name[0] )
			break;
		if( name[0] != '*' ) {
			CG_LoadingFilename( name );
			cgs.soundPrecache[i] = trap_S_RegisterSound( name );
		}
	}

	CG_RegisterMediaSounds ();
}

/*
=================
CG_RegisterShaders
=================
*/
void CG_RegisterShaders( void )
{
	int i;
	char *name;

	CG_LoadingString( "images" );

	for( i = 1; i < MAX_IMAGES; i++ ) {
		name = cgs.configStrings[CS_IMAGES+i];
		if( !name[0] )
			break;

		CG_LoadingFilename( name );
		cgs.imagePrecache[i] = trap_R_RegisterPic( name );
	}

	CG_RegisterMediaShaders ();
}

/*
=================
CG_RegisterSkinfiles
=================
*/
void CG_RegisterSkinFiles( void )
{
	int i;
	char *name;

	CG_LoadingString( "skins" );

	for( i = 1; i < MAX_SKINFILES; i++ ) {
		name = cgs.configStrings[CS_SKINFILES+i];
		if( !name[0] )
			break;

		CG_LoadingFilename( name );
		cgs.skinPrecache[i] = trap_R_RegisterSkinFile( name );
	}
}

/*
=================
CG_RegisterClients
=================
*/
void CG_RegisterClients( void )
{
	int i;
	char *name;

	CG_LoadingFilename( "" );

	for( i = 0; i < MAX_CLIENTS; i++ ) {
		name = cgs.configStrings[CS_PLAYERINFOS+i];
		if( !name[0] )
			continue;

		CG_LoadingString( va ("client %i", i) );
		CG_LoadClientInfo( &cgs.clientInfo[i], name, i );
	}
}

/*
=================
CG_RegisterLightStyles
=================
*/
void CG_RegisterLightStyles( void )
{
	int i;
	char *name;

	CG_LoadingFilename( "" );

	for( i = 0; i < MAX_LIGHTSTYLES; i++ ) {
		name = cgs.configStrings[CS_LIGHTS+i];
		if( !name[0] )
			continue;
		CG_SetLightStyle( i );
	}
}

/*
=================
CG_RegisterVariables
=================
*/
void CG_RegisterVariables( void )
{
	cg_noSkins =		trap_Cvar_Get( "cg_noSkins", "0", 0 );
	cg_vwep =			trap_Cvar_Get( "cg_vwep", "1", 0 );
	cg_predict =		trap_Cvar_Get( "cg_predict", "1", 0 );
	cg_showMiss =		trap_Cvar_Get( "cg_showMiss", "0", 0 );
	cg_timedemo =		trap_Cvar_Get( "timedemo", "0", CVAR_CHEAT );

	cg_debugPlayerModels =	trap_Cvar_Get( "cg_debugPlayerModels", "0", CVAR_CHEAT|CVAR_ARCHIVE );
	cg_debugWeaponModels =	trap_Cvar_Get( "cg_debugWeaponModels", "0", CVAR_CHEAT|CVAR_ARCHIVE );

	model =				trap_Cvar_Get( "model", DEFAULT_PLAYERMODEL, CVAR_USERINFO | CVAR_ARCHIVE ); // wsw : jal
	skin =				trap_Cvar_Get( "skin", DEFAULT_PLAYERSKIN, CVAR_USERINFO | CVAR_ARCHIVE );//splitmodels
	hand =				trap_Cvar_Get( "hand", "0", CVAR_USERINFO | CVAR_ARCHIVE );
	cg_fov =			trap_Cvar_Get( "fov", "90", CVAR_USERINFO | CVAR_ARCHIVE );

	cg_addDecals =		trap_Cvar_Get( "cg_decals", "1", CVAR_ARCHIVE );
	cg_footSteps =		trap_Cvar_Get( "cg_footSteps", "1", 0 );
	
	cg_thirdPerson =		trap_Cvar_Get( "cg_thirdPerson", "0", CVAR_CHEAT );
	cg_thirdPersonAngle =	trap_Cvar_Get( "cg_thirdPersonAngle", "0", 0 );
	cg_thirdPersonRange =	trap_Cvar_Get( "cg_thirdPersonRange", "40", 0 );

	//skelmod
	cg_gun =				trap_Cvar_Get( "cg_gun", "1", CVAR_ARCHIVE );
	cg_gunx =				trap_Cvar_Get( "cg_gunx", "0", CVAR_ARCHIVE );
	cg_guny =				trap_Cvar_Get( "cg_guny", "0", CVAR_ARCHIVE );
	cg_gunz =				trap_Cvar_Get( "cg_gunz", "0", CVAR_ARCHIVE );
	cg_bobSpeed =			trap_Cvar_Get( "cg_bobSpeed", "2.5", CVAR_ARCHIVE );
	cg_bobPitch =			trap_Cvar_Get( "cg_bobPitch", "6", CVAR_ARCHIVE );
	cg_bobYaw =				trap_Cvar_Get( "cg_bobYaw", "3", CVAR_ARCHIVE );
	cg_bobRoll =			trap_Cvar_Get( "cg_bobRoll", "6", CVAR_ARCHIVE );
	cg_weaponFlashes =		trap_Cvar_Get( "cg_weaponFlashes", "2", CVAR_ARCHIVE );
	cg_ejectBrass =			trap_Cvar_Get( "cg_ejectBrass", "2", CVAR_ARCHIVE );

	// wsw 
	cg_volume_players =		trap_Cvar_Get( "cg_volume_players", "1.0", CVAR_ARCHIVE );
	cg_volume_effects =		trap_Cvar_Get( "cg_volume_effects", "1.0", CVAR_ARCHIVE );
	cg_volume_announcer = 	trap_Cvar_Get( "cg_volume_announcer", "1.0", CVAR_ARCHIVE );
	cg_volume_hitsound =	trap_Cvar_Get( "cg_volume_hitsound", "1.0", CVAR_ARCHIVE );
	cg_volume_voicechats =	trap_Cvar_Get( "cg_volume_voicechats", "1.0", CVAR_ARCHIVE );
	cg_handOffset =			trap_Cvar_Get( "cg_handOffset", "6", CVAR_ARCHIVE );
	cg_rocketTrail =		trap_Cvar_Get( "cg_rocketTrail", "40", CVAR_ARCHIVE );
	cg_grenadeTrail =		trap_Cvar_Get( "cg_grenadeTrail", "20", CVAR_ARCHIVE );
	cg_bloodTrail =			trap_Cvar_Get( "cg_bloodTrail", "10", CVAR_ARCHIVE );
	cg_showBloodTrail =		trap_Cvar_Get( "cg_showBloodTrail", "1", CVAR_ARCHIVE );
	cg_rocketTrailAlpha =	trap_Cvar_Get( "cg_rocketTrailAlpha", "0.35", CVAR_ARCHIVE );
	cg_grenadeTrailAlpha =	trap_Cvar_Get( "cg_grenadeTrailAlpha", "0.5", CVAR_ARCHIVE );
	cg_bloodTrailAlpha =	trap_Cvar_Get( "cg_bloodTrailAlpha", "1.0", CVAR_ARCHIVE );
	cg_explosionsAlpha =	trap_Cvar_Get( "cg_explosionsAlpha", "0.8", CVAR_ARCHIVE );
	cg_explosionsRingAlpha = trap_Cvar_Get( "cg_explosionsRingAlpha", "0.3", CVAR_ARCHIVE );
	cg_gibs =				trap_Cvar_Get( "cg_gibs", "1", CVAR_ARCHIVE );
	cg_outlineModels =		trap_Cvar_Get( "cg_outlineModels", "1", CVAR_ARCHIVE );
	cg_outlineItemsBlack =	trap_Cvar_Get( "cg_outlineItemsBlack", "1", CVAR_ARCHIVE );
	cg_outlinePlayersBlack =trap_Cvar_Get( "cg_outlinePlayersBlack", "0", CVAR_ARCHIVE );
	cg_demo_truePOV =		trap_Cvar_Get( "cg_demo_truePOV", "0", CVAR_ARCHIVE );
	cg_showObituaries =		trap_Cvar_Get( "cg_showObituaries", "3", CVAR_ARCHIVE );
	cg_autoaction =			trap_Cvar_Get( "cg_autoaction", "0", CVAR_ARCHIVE );
	cg_simpleItems =		trap_Cvar_Get( "cg_simpleItems", "0", CVAR_ARCHIVE );
	cg_simpleItemsSize =	trap_Cvar_Get( "cg_simpleItemsSize", "12", CVAR_ARCHIVE );
	cg_particles =			trap_Cvar_Get( "cg_particles", "1", CVAR_ARCHIVE );
	cg_showhelp =			trap_Cvar_Get( "cg_showhelp", "1", CVAR_ARCHIVE );
	cg_predictLaserBeam =	trap_Cvar_Get( "cg_predictLaserBeam", "1", CVAR_ARCHIVE );
	// only allow trail when watching a demos or in race mode
	cg_showPlayerTrails =	trap_Cvar_Get( "cg_showPlayerTrails", "0", CVAR_ARCHIVE );
	cg_playerTrailsColor=   trap_Cvar_Get( "cg_playerTrailsColor", "0.0 1.0 0.0", CVAR_ARCHIVE);

	cg_damage_kick =		trap_Cvar_Get( "cg_damage_kick", "0", CVAR_ARCHIVE );
	cg_damage_blend =		trap_Cvar_Get( "cg_damage_blend", "1", CVAR_ARCHIVE );
	cg_pickup_flash =		trap_Cvar_Get( "cg_pickup_flash", "1", CVAR_ARCHIVE );
	cg_voiceChats =			trap_Cvar_Get( "cg_voiceChats", "1", CVAR_ARCHIVE );
#ifdef CGAMEGETLIGHTORIGIN
	cg_shadows =			trap_Cvar_Get( "cg_shadows", "1", CVAR_ARCHIVE );
#endif

	cg_laserBeamSubdivisions = trap_Cvar_Get( "cg_laserBeamSubdivisions", "10", CVAR_ARCHIVE );

	cg_scoreboardStats =	trap_Cvar_Get( "cg_scoreboardStats", "1", CVAR_ARCHIVE );

	developer = trap_Cvar_Get( "developer", "0", CVAR_CHEAT );

	//team models
	cg_teamPLAYERSmodel =	trap_Cvar_Get( "cg_teamPLAYERSmodel", "", CVAR_ARCHIVE );
	cg_teamPLAYERSskin =	trap_Cvar_Get( "cg_teamPLAYERSskin", "default", CVAR_ARCHIVE );
	cg_teamPLAYERScolor =	trap_Cvar_Get( "cg_teamPLAYERScolor", "", CVAR_ARCHIVE );
	cg_teamPLAYERSmodel->modified = qtrue;
	cg_teamPLAYERSskin->modified = qtrue;
	cg_teamPLAYERScolor->modified = qtrue;

	cg_teamREDmodel =		trap_Cvar_Get( "cg_teamREDmodel", "", CVAR_ARCHIVE );
	cg_teamREDskin =		trap_Cvar_Get( "cg_teamREDskin", "default", CVAR_ARCHIVE );
	cg_teamREDcolor =		trap_Cvar_Get( "cg_teamREDcolor", DEFAULT_TEAMRED_COLOR, CVAR_ARCHIVE );
	cg_teamREDmodel->modified = qtrue;
	cg_teamREDskin->modified = qtrue;
	cg_teamREDcolor->modified = qtrue;

	cg_teamBLUEmodel =		trap_Cvar_Get( "cg_teamBLUEmodel", "", CVAR_ARCHIVE );
	cg_teamBLUEskin =		trap_Cvar_Get( "cg_teamBLUEskin", "default", CVAR_ARCHIVE );
	cg_teamBLUEcolor =		trap_Cvar_Get( "cg_teamBLUEcolor", DEFAULT_TEAMBLUE_COLOR, CVAR_ARCHIVE );
	cg_teamBLUEmodel->modified = qtrue;
	cg_teamBLUEskin->modified = qtrue;
	cg_teamBLUEcolor->modified = qtrue;

	cg_teamGREENmodel =		trap_Cvar_Get( "cg_teamGREENmodel", "", CVAR_ARCHIVE );
	cg_teamGREENskin =		trap_Cvar_Get( "cg_teamGREENskin", "default", CVAR_ARCHIVE );
	cg_teamGREENcolor =		trap_Cvar_Get( "cg_teamGREENcolor", DEFAULT_TEAMGREEN_COLOR, CVAR_ARCHIVE );
	cg_teamGREENmodel->modified = qtrue;
	cg_teamGREENskin->modified = qtrue;
	cg_teamGREENcolor->modified = qtrue;

	cg_teamYELLOWmodel =	trap_Cvar_Get( "cg_teamYELLOWmodel", "", CVAR_ARCHIVE );
	cg_teamYELLOWskin =		trap_Cvar_Get( "cg_teamYELLOWskin", "default", CVAR_ARCHIVE );
	cg_teamYELLOWcolor =	trap_Cvar_Get( "cg_teamYELLOWcolor", DEFAULT_TEAMYELLOW_COLOR, CVAR_ARCHIVE );
	cg_teamYELLOWmodel->modified = qtrue;
	cg_teamYELLOWskin->modified = qtrue;
	cg_teamYELLOWcolor->modified = qtrue;

	cg_forceEnemyTeam =	trap_Cvar_Get( "cg_forceEnemyTeam", "", CVAR_ARCHIVE );
	cg_forceMyTeam =	trap_Cvar_Get( "cg_forceMyTeam", "", CVAR_ARCHIVE );
	cg_forceEnemyTeam->modified = qtrue;
	cg_forceMyTeam->modified = qtrue;
}

// wsw : jal : [start] gamecommandscompletion
/*
=================
CG_RegisterGameCommands
=================
*/
void CG_RegisterGameCommands( void )
{
	int i;
	char *name;

	CG_LoadingFilename( "" );

	if( cg.demoPlaying )
		return;

	// add game side commands

	for( i = 0; i < MAX_GAMECOMMANDS; i++ ) {
		name = cgs.configStrings[CS_GAMECOMMANDS+i];
		if( !name[0] )
			continue;

		trap_Cmd_AddCommand( name, NULL );
	}

	// add local commands
	trap_Cmd_AddCommand( "weapprev", CG_WeapPrev_f );
	trap_Cmd_AddCommand( "weapnext", CG_WeapNext_f );
	trap_Cmd_AddCommand( "use", CG_Cmd_Use_f );
}

/*
=================
CG_UnregisterGameCommands
=================
*/
void CG_UnregisterGameCommands( void )
{
	int i;
	char *name;

	// remove game commands
	for( i = 0; i < MAX_GAMECOMMANDS; i++ ) {
		name = cgs.configStrings[CS_GAMECOMMANDS+i];
		if( !name[0] )
			continue;

		trap_Cmd_RemoveCommand( name );
	}

	// remove local commands
	trap_Cmd_RemoveCommand( "weapprev" );
	trap_Cmd_RemoveCommand( "weapnext" );
	trap_Cmd_RemoveCommand( "use" );
}
// wsw : jal : [end] gamecommandscompletion

void CG_RegisterDemoCommands( void )
{
	trap_Cmd_AddCommand("score", SCR_DemoToggleScores_f);
#ifdef DEMOCAM
	// [DEMOCAM] democam commands -- PLX
	CG_RegisterDemoCamCommands(); // Cause i'll add commands many time. It is coll if i have to commit only cg_democams.[ch] -- PLX
#endif
}


void CG_UnregisterDemoCommands( void )
{
	trap_Cmd_RemoveCommand("score");
#ifdef DEMOCAM
	// [DEMOCAM] democam commands -- PLX
	CG_UnregisterDemoCamCommands(); // Cause i'll add commands many time. It is coll if i have to commit only cg_democams.[ch] -- PLX
#endif
}

/*
=================
CG_ValidateItemDef
Compares name and tag against the itemlist to make sure cgame and game lists match.
=================
*/
void CG_ValidateItemDef( int tag, char *name )
{
	gitem_t *item;

	item = GS_FindItemByName( name );
	if( !item ) 
		CG_Error( "Client/Server itemlist missmatch (Game and Cgame version/mod differs). Item '%s' not found\n", name );

	if( item->tag != tag ) 
		CG_Error( "Client/Server itemlist missmatch (Game and Cgame version/mod differs).\n" );
}

/*
=================
CG_ValidateItemList
=================
*/
void CG_ValidateItemList( void )
{
	int i;

	for( i = CS_ITEMS; i < CS_ITEMS+MAX_ITEMS; i++ ) {
		if( cgs.configStrings[i][0] )
			CG_ValidateItemDef( i - CS_ITEMS, cgs.configStrings[i] );
	}
}

//=================
//CG_UpdateServerSettings
//=================
void CG_UpdateServerSettings( void ) {
	// if we got the server settings configstring, update our local copy of the data
	if( strlen( cgs.configStrings[CS_SERVERSETTINGS] ) ) {
		char *settings = cgs.configStrings[CS_SERVERSETTINGS];
		cgs.serverRules.has_challengers = atoi( COM_Parse(&settings) );
		cgs.serverRules.maxteams = atoi( COM_Parse(&settings) );
	}
}

//=================
//CG_RegisterConfigStrings
//=================
void CG_RegisterConfigStrings( void )
{
	int i;

	for( i = 0; i < MAX_CONFIGSTRINGS; i++ )
		trap_GetConfigString( i, cgs.configStrings[i], MAX_QPATH );

	// if we got the server settings configstring, update our local copy of the data
	CG_UpdateServerSettings();
}

/*
=================
CG_StartBackgroundTrack
=================
*/
void CG_StartBackgroundTrack( void )
{
	char *string;
	char intro[MAX_QPATH], loop[MAX_QPATH];

	string = cgs.configStrings[CS_AUDIOTRACK];
	Q_strncpyz( intro, COM_Parse( &string ), sizeof( intro ) );
	Q_strncpyz( loop, COM_Parse( &string ), sizeof( loop ) );

	trap_S_StartBackgroundTrack( intro, loop );
}

//=================
//CG_RegisterFonts
//=================
void CG_RegisterFonts( void ) {
	cvar_t	*con_fontSystemSmall = trap_Cvar_Get( "con_fontSystemSmall", DEFAULT_FONT_SMALL, CVAR_ARCHIVE );
	cvar_t	*con_fontSystemMedium = trap_Cvar_Get( "con_fontSystemMedium", DEFAULT_FONT_MEDIUM, CVAR_ARCHIVE );
	cvar_t	*con_fontSystemBig = trap_Cvar_Get( "con_fontSystemBig", DEFAULT_FONT_BIG, CVAR_ARCHIVE );

	cgs.fontSystemSmall = trap_SCR_RegisterFont( con_fontSystemSmall->string );
	if( !cgs.fontSystemSmall ) {
		cgs.fontSystemSmall = trap_SCR_RegisterFont( DEFAULT_FONT_SMALL );
		if( !cgs.fontSystemSmall )
			CG_Error( "Couldn't load default font \"%s\"", DEFAULT_FONT_SMALL );
	}
	cgs.fontSystemMedium = trap_SCR_RegisterFont( con_fontSystemMedium->string );
	if( !cgs.fontSystemMedium )
		cgs.fontSystemMedium = trap_SCR_RegisterFont( DEFAULT_FONT_MEDIUM );

	cgs.fontSystemBig = trap_SCR_RegisterFont( con_fontSystemBig->string );
	if( !cgs.fontSystemBig )
		cgs.fontSystemBig = trap_SCR_RegisterFont( DEFAULT_FONT_BIG );
}

/*
============
CG_Init
============
*/
void CG_Init( int playerNum, int vidWidth, int vidHeight )
{
	cgamepool = CG_MemAllocPool( "CGame" );

	memset( &cg, 0, sizeof(cg_state_t) );
	memset( &cgs, 0, sizeof(cg_static_t) );

	memset( cg_entities, 0, sizeof(cg_entities) );

	// save local player number
	cgs.playerNum = playerNum;

	// save current width and height
	cgs.vidWidth = vidWidth;
	cgs.vidHeight = vidHeight;

	CG_RegisterVariables();
	CG_InitTemporaryBoneposesCache(); // skelmod
	CG_PModelsInit();	//splitmodels

	SCR_Init();

	// get configstrings
	CG_RegisterConfigStrings();

	// register fonts here so loading screen works
	CG_RegisterFonts();
	cgs.shaderWhite = trap_R_RegisterPic( "gfx/ui/white" );

	CG_RegisterLevelShot();

	CG_RegisterModels();
	CG_RegisterSounds();
	CG_RegisterShaders();
	CG_RegisterSkinFiles();
	CG_RegisterClients();
	CG_RegisterGameCommands(); // wsw : jal : gamecommandscompletion
	CG_ValidateItemList();

	CG_LoadStatusBar();

	CG_LoadingString( "-" );	// awaiting snapshot...
	CG_LoadingFilename( "" );

	CG_ClearDecals();
	CG_ClearPolys();	//wsw : jal polys
	CG_ClearEffects();
	CG_ClearLocalEntities();

	CG_RegisterLightStyles();

	// start background track
	CG_StartBackgroundTrack();

	// start up announcer events queue from clean
	CG_ClearAnnouncerEvents();
}

/*
============
CG_Shutdown
============
*/
void CG_Shutdown( void )
{
	SCR_Shutdown ();

	if( cg.demoPlaying )
		CG_UnregisterDemoCommands();
	else
		CG_UnregisterGameCommands(); // wsw : jal : gamecommandscompletion

	CG_MemFreePool ( &cgamepool );
}

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

#ifndef CGAME_HARD_LINKED
// this is only here so the functions in q_shared.c and q_math.c can link
void Sys_Error( char *error, ... )
{
	va_list		argptr;
	char		text[1024];

	va_start (argptr, error);
	vsnprintf (text, sizeof(text), error, argptr);
	va_end (argptr);
	text[sizeof(text)-1] = 0;

	trap_Error (text);
}

void Com_Printf( char *msg, ... )
{
	va_list		argptr;
	char		text[1024];

	va_start (argptr, msg);
	vsnprintf (text, sizeof(text), msg, argptr);
	va_end (argptr);
	text[sizeof(text)-1] = 0;

	trap_Print (text);
}

#endif
