//-----------------------------------------------------------------------------
//
//  $Logfile:: /Source/cl_sincmds.c                                           $
// $Revision:: 4                                                              $
//   $Author:: Burgermac                                                      $
//     $Date:: 8/8/01 7:37 PM                                                 $
//
// Copyright (C) 1998 by Ritual Entertainment, Inc.
// All rights reserved.
//
// This source is may not be distributed and/or modified without
// expressly written permission by Ritual Entertainment, Inc.
//
// DESCRIPTION:
// Sin Client Command processor
//

#include "client.h"
#include "alias.h"

entity_t * current_entity = NULL;
static vec3_t cl_tm_forward;
static vec3_t cl_tm_right;
static vec3_t cl_tm_up;
static vec3_t cl_x_axis = { 1, 0, 0 };
static vec3_t cl_y_axis = { 0, -1, 0 };
static vec3_t cl_z_axis = { 0, 0, 1 };
extern cvar_t         *precache;

#define CHECK_ARGS( num, command ) \
	if ( ( argc - argnum < num ) ) \
	{ \
		Com_Error( ERR_DROP, "CL_CMDS_TempModel: Error in sin command %s.  Expecting %d args.\n", command, num ); \
	}

/*
=================
CL_CMDS_TempModel
=================
*/
static void CL_CMDS_TempModel( entity_t * ent, int argnum, int argc, const char **argv, int flags )
{
	char modelname[128];
	char bouncesound[128];
	vec3_t vel;
	int i;
	float time;
	float random_percent;
	float minscale=0;
	qboolean random_active;

	time = 0.1f;
	random_active = false;
	random_percent = 0; /* silence compiler */
	bouncesound[0] = 0;
	VectorClear(vel);
	// get model name
	strcpy(modelname, argv[argnum++]);
	// get the rest

	while (argnum < argc)
	{
		if ( !Q_stricmp( argv[argnum], "origin" ) )
		{
			vec3_t offset;
			argnum++;

			CHECK_ARGS( 3, "origin" );

			offset[0] = Sinatof( argv[argnum++] );
			offset[1] = Sinatof( argv[argnum++] );
			offset[2] = Sinatof( argv[argnum++] );
			for( i = 0; i < 3; i++ )
			{
				ent->origin[i] += (cl_tm_forward[i] * offset[0]) - (cl_tm_right[i] * offset[1]) + (cl_tm_up[i] * offset[2]);
			}
		}
		else if ( !Q_stricmp( argv[argnum], "randorigin" ) )
		{
			vec3_t offset;
			float amount;
			argnum++;

			CHECK_ARGS( 1, "randorigin" );

			amount = Sinatof( argv[argnum++] );

			offset[0] = amount * crand();
			offset[1] = amount * crand();
			offset[2] = amount * crand();
			for( i = 0; i < 3; i++ )
			{
				ent->origin[i] += (cl_tm_forward[i] * offset[0]) - (cl_tm_right[i] * offset[1]) + (cl_tm_up[i] * offset[2]);
			}
		}
		// added for rain. Only offsets origin in the xy plane
		else if ( !Q_stricmp( argv[argnum], "randxyorigin" ) )
		{
//			vec3_t offset;
			float amount;
			argnum++;

			CHECK_ARGS( 1, "randxyorigin" );

			amount = Sinatof( argv[argnum++] );

//			offset[0] = amount * crand();
//			offset[1] = amount * crand();
//			offset[2] = amount * crand();
//			for( i = 0; i < 3; i++ )
//			{
//				ent->origin[i] += (cl_tm_forward[i] * offset[0]) - (cl_tm_right[i] * offset[1]) + (cl_tm_up[i] * offset[2]);
//			}
			ent->origin[0] += amount * crand();
			ent->origin[1] += amount * crand();
		}
		else if ( !Q_stricmp( argv[argnum], "absangles" ) )
		{
			argnum++;

			CHECK_ARGS( 3, "absangles" );

			ent->angles[0] = Sinatof( argv[argnum++] );
			ent->angles[1] = Sinatof( argv[argnum++] );
			ent->angles[2] = Sinatof( argv[argnum++] );
		}
		else if ( !Q_stricmp( argv[argnum], "angles" ) )
		{
			argnum++;

			CHECK_ARGS( 3, "angles" );

			ent->angles[0] += Sinatof( argv[argnum++] );
			ent->angles[1] += Sinatof( argv[argnum++] );
			ent->angles[2] += Sinatof( argv[argnum++] );
		}
		else if ( !Q_stricmp( argv[argnum], "anim" ) )
		{
			argnum++;

			CHECK_ARGS( 1, "anim" );

			ent->anim = atol( argv[argnum++] );
		}
		else if ( !Q_stricmp( argv[argnum], "frame" ) )
		{
			argnum++;

			CHECK_ARGS( 1, "frame" );

			ent->frame = atol( argv[argnum++] );
		}
		else if ( !Q_stricmp( argv[argnum], "randframe" ) )
		{
			argnum++;
			ent->frame = (int)rand();
		}
		else if ( !Q_stricmp( argv[argnum], "time" ) )
		{
			argnum++;

			CHECK_ARGS( 1, "time" );

			time = Sinatof( argv[argnum++] );
		}
		else if ( !Q_stricmp( argv[argnum], "scale" ) )
		{
			argnum++;

			CHECK_ARGS( 1, "scale" );

			if ( ent->parent )
				ent->scale = Sinatof( argv[argnum++] );
			else
				ent->scale *= Sinatof( argv[argnum++] );
		}
		else if ( !Q_stricmp( argv[argnum], "minscale" ) )
		{
			argnum++;

			CHECK_ARGS( 1, "minscale" );
			minscale = Sinatof( argv[argnum++] );
		}
		else if ( !Q_stricmp( argv[argnum], "minscale" ) )
		{
			argnum++;

			CHECK_ARGS( 1, "scale" );

			if ( ent->parent )
				ent->scale = Sinatof( argv[argnum++] );
			else
				ent->scale *= Sinatof( argv[argnum++] );
		}
		else if ( !Q_stricmp( argv[argnum], "randscale" ) )
		{
			float lower, upper, scale;
			argnum++;

			CHECK_ARGS( 2, "randscale" );

			lower = Sinatof( argv[argnum++] );
			upper = Sinatof( argv[argnum++] );

			scale = lower + ( ( upper-lower ) * frand() );

			if ( ent->parent )
				ent->scale = scale;
			else
				ent->scale *= scale;
		}
		else if ( !Q_stricmp( argv[argnum], "randroll" ) )
		{
			argnum++;
			ent->angles[2] = (180.0f * crand()) + 180.0f;
		}
		else if ( !Q_stricmp( argv[argnum], "randomroll" ) )
		{
			argnum++;
			flags |= TEMPMODEL_RANDOM_ROLL;
		}
		else if ( !Q_stricmp( argv[argnum], "randompitch" ) )
		{
			argnum++;
			flags |= TEMPMODEL_RANDOM_PITCH;
		}
		else if ( !Q_stricmp( argv[argnum], "randomyaw" ) )
		{
			argnum++;
			flags |= TEMPMODEL_RANDOM_YAW;
		}
		else if ( !Q_stricmp( argv[argnum], "animate" ) )
		{
			argnum++;
			flags |= TEMPMODEL_AUTO_ANIMATE;
		}
		else if ( !Q_stricmp( argv[argnum], "frame" ) )
		{
			argnum++;
			CHECK_ARGS( 1, "frame" );

			ent->frame = atoi( argv[argnum++] );
		}
		else if ( !Q_stricmp( argv[argnum], "fast" ) )
		{
			argnum++;
			if ( random_active )
			{
				random_active = false;
				if ( CL_Random( 1 ) > random_percent )
					continue;
			}
			flags |= TEMPMODEL_ANIMATE_FAST;
		}
		else if ( !Q_stricmp( argv[argnum], "animateonce" ) )
		{
			argnum++;
			if ( random_active )
			{
				random_active = false;
				if ( CL_Random( 1 ) > random_percent )
					continue;
			}
			flags |= TEMPMODEL_ANIMATE_ONCE;
		}
		else if ( !Q_stricmp( argv[argnum], "alphafade" ) )
		{
			argnum++;
			flags |= TEMPMODEL_ALPHAFADE;
		}
		else if ( !Q_stricmp( argv[argnum], "scaleanim" ) )
		{
			argnum++;
			flags |= TEMPMODEL_ANIMATE_SCALE;
		}
		else if ( !Q_stricmp( argv[argnum], "bounce" ) )
		{
			argnum++;
			flags |= TEMPMODEL_BOUNCE;
			flags |= TEMPMODEL_USE_PHYSICS;
		}
		else if ( !Q_stricmp( argv[argnum], "bouncesound" ) )
		{
			argnum++;

			CHECK_ARGS( 1, "bouncesound" );

			strcpy( bouncesound, argv[argnum] );
			argnum++;
		}
		else if ( !Q_stricmp( argv[argnum], "physics" ) )
		{
			argnum++;
			flags |= TEMPMODEL_USE_PHYSICS;
		}
		else if ( !Q_stricmp( argv[argnum], "forwardvel" ) )
		{
			float factor;
			argnum++;

			CHECK_ARGS( 1, "forwardvel" );

			factor = Sinatof( argv[argnum++] );
			for( i = 0; i < 3; i++ )
			{
				vel[i]= (cl_tm_forward[i] * factor);
			}
		}
		else if ( !Q_stricmp( argv[argnum], "vel" ) )
		{
			vec3_t offset;
			argnum++;

			CHECK_ARGS( 3, "vel" );

			offset[0] = Sinatof( argv[argnum++] );
			offset[1] = Sinatof( argv[argnum++] );
			offset[2] = Sinatof( argv[argnum++] );
			for( i = 0; i < 3; i++ )
			{
				vel[i]= (cl_tm_forward[i] * offset[0]) - (cl_tm_right[i] * offset[1]) + (cl_tm_up[i] * offset[2]);
			}
		}
		else if ( !Q_stricmp( argv[argnum], "randvel" ) )
		{
			vec3_t offset;
			argnum++;

			CHECK_ARGS( 3, "randvel" );

			// Adds onto existing velocity
			offset[0] = Sinatof( argv[argnum++] ) * crand();
			offset[1] = Sinatof( argv[argnum++] ) * crand();
			offset[2] = Sinatof( argv[argnum++] ) * frand();
			for( i = 0; i < 3; i++ )
			{
				vel[i] += (cl_tm_forward[i] * offset[0]) - (cl_tm_right[i] * offset[1]) + (cl_tm_up[i] * offset[2]);
			}
		}
		else if ( !Q_stricmp( argv[argnum], "absrandvel" ) )
		{
			vec3_t offset;
			argnum++;

			CHECK_ARGS( 3, "absrandvel" );

			offset[0] = Sinatof( argv[argnum++] ) * frand();
			offset[1] = Sinatof( argv[argnum++] ) * frand();
			offset[2] = Sinatof( argv[argnum++] ) * frand();
			for( i = 0; i < 3; i++ )
			{
				vel[i] = offset[i];
			}
		}
		else if ( !Q_stricmp( argv[argnum], "detail" ) )
		{
			argnum++;
			if (!cl_add_detailmodels->value)
				return;
			else
				ent->flags |= RF_DETAIL;
		}
		else if ( !Q_stricmp( argv[argnum], "randomspawn" ) )
		{
			float percent;
			argnum++;

			CHECK_ARGS( 1, "randomspawn" );

			percent = Sinatof( argv[argnum++] );
			if ( CL_Random( 1 ) > percent )
				return;
		}
		else if ( !Q_stricmp( argv[argnum], "touchdie" ) )
		{
			argnum++;
			if ( random_active )
			{
				random_active = false;
				if ( CL_Random( 1 ) > random_percent )
					continue;
			}
			flags |= TEMPMODEL_TOUCH_DIE;
		}
		else if ( !Q_stricmp( argv[argnum], "touchdie_nofade" ) )
		{
			argnum++;
			if ( random_active )
			{
				random_active = false;
				if ( CL_Random( 1 ) > random_percent )
					continue;
			}
			flags |= TEMPMODEL_TOUCH_DIE_NO_FADE;
		}
		else if ( !Q_stricmp( argv[argnum], "lerp" ) )
		{
			argnum++;
			flags |= TEMPMODEL_LERP;
		}
		else if ( !Q_stricmp( argv[argnum], "framelerp" ) )
		{
			argnum++;
			flags |= TEMPMODEL_FRAMELERP;
		}
		else if ( !Q_stricmp( argv[argnum], "invertpitch" ) )
		{
			argnum++;
			ent->angles[PITCH] = -ent->angles[PITCH];
		}
		else if ( !Q_stricmp( argv[argnum], "random" ) )
		{
			argnum++;

			CHECK_ARGS( 1, "random" );

			random_percent = Sinatof( argv[argnum++] );
			random_active = true;
		}
		else if ( !Q_stricmp( argv[argnum], "water" ) )
		{
			int contents;
			qboolean waterOn;
			argnum++;

			CHECK_ARGS( 1, "water" );

			waterOn  = atoi( argv[argnum++] );
			contents = CL_PMpointcontents ( ent->origin );

			if ( waterOn && !( contents & MASK_WATER ) )
				return;
			if ( !waterOn &&  ( contents & MASK_WATER ) )
				return;
		}
		else
		{
			Com_DPrintf(DEVELOPER_MSG_SINCMDS, "CL_CMDS_ProcessCommands::attach: unrecognized command %s\n", argv[argnum]);
			argnum++;
		}
	}
	ent->model = re.RegisterModel( modelname );
	if (!ent->model)
	{
		Com_DPrintf(DEVELOPER_MSG_SINCMDS, "CL_CMDS_ProcessCommands::attach: model was not found.\n");
		return;
	}
	AnglesToMat( ent->angles, ent->mat );
	//
	// make sure alpha we be picked up
	//
	if (flags & TEMPMODEL_ALPHAFADE)
		ent->flags |= RF_TRANSLUCENT;
	CL_TempmodelEffect( ent, 0, ent->scale, time, vel, bouncesound, flags, minscale );
}

static void IntitializeCoordinateSystemForModel( entity_t *ent,float *scale,vec3_t trans[],vec3_t offset )
{
	int defhandle;
	int i;

	if ( current_entity->parent )
	{
		entity_t * parent;

		parent = V_FindEntity( current_entity->parent );

		if (!parent)
		{
			Com_DPrintf(DEVELOPER_MSG_SINMDL, "InitializeCoordinateSystemForModel: parent not found.\n");
			return;
		}

		defhandle = re.SINMDL_GetDefHandle( parent->model );
		if (defhandle < 0)
		{
			Com_DPrintf(DEVELOPER_MSG_SINMDL, "InitializeCoordinateSystemForModel: trying to get handle of non-sinmdl model.\n");
			return;
		}
		if (!SINMDL_GetBoneTransform
			(
				defhandle, current_entity->bone.group_num, current_entity->bone.tri_num, current_entity->bone.orientation,
				parent->anim, parent->frame, parent->scale, trans, offset
			)
		    )
		{
			Com_DPrintf(DEVELOPER_MSG_SINMDL, "InitializeCoordinateSystemForModel: GetBoneTransform failed.\n");
			return;
		}
		// get the pos in the parents transform space
		MatrixTransformVector( offset, parent->mat, ent->origin );
		VectorAdd( ent->origin, parent->origin, ent->origin );

		VectorCopy( current_entity->angles, ent->angles );
		VectorCopy( current_entity->angles, offset );
		offset[PITCH] = -offset[PITCH];
		AnglesToMat( offset, trans );
		VectorCopy( trans[0], cl_tm_forward );
		VectorCopy( trans[1], cl_tm_right );
		VectorCopy( trans[2], cl_tm_up );
		*scale = parent->scale;
	}
	else
	{
		// initalize variables
		VectorCopy( current_entity->angles, ent->angles );
		for( i = 0; i < 3; i++ )
		{
			ent->origin[i] = current_entity->oldorigin[i] + cl.lerpfrac *
					  (current_entity->origin[i] - current_entity->oldorigin[i]);
		}
		VectorCopy( current_entity->mat[0], cl_tm_forward );
		VectorCopy( current_entity->mat[1], cl_tm_right );
		VectorCopy( current_entity->mat[2], cl_tm_up );
		*scale = 1.0f;
	}
}

/*
=================
CL_CMDS_ProcessCommands
=================
*/
void CL_CMDS_ProcessCommands( int entnum, int defhandle, int argc, const char **argv )
{
	int argnum;
	qboolean use_model;

	argnum = 0;
	if ( defhandle >= 0 )
	{
		use_model = true;
	}
	else
	{
		use_model = false;
	}
	while ( argnum < argc )
	{
		if ( !Q_stricmp( argv[argnum], "server" ) )
		{
			//
			// we don't process server commands
			//
			if ( Q_stricmp( argv[argnum+1], "aliascache" ) )
				return;
			argnum++;
			continue;
// modified to correct caching of sounds for models that are spawned into a map
		}
		else if ( !Q_stricmp( argv[argnum], "client" ) )
		{
			argnum++;
			continue;
		}
		else if ( !Q_stricmp( argv[argnum], "aliasprefix" ) )
		{
			return;
		}
		else if (
			( !Q_stricmp( argv[argnum], "playsound" ) ) ||
			( !Q_stricmp( argv[argnum], "localsound" ) ) ||
			( !Q_stricmp( argv[argnum], "randomsound" ) )
			)
		{
			int i;
			char name[64];
			float volume;
			int channel;
			int attenuation;
			float pitch;
			float timeofs;
			float fadetime;
			int flags;
			struct sfx_s * sound;
			qboolean random;

			random = false;
			if ( !Q_stricmp( argv[argnum], "randomsound" ) )
				random = true;
			if ( !Q_stricmp( argv[argnum], "localsound" ) )
			{
				random = true;
				if ( entnum != cl.playernum+1 )
					return;
			}
			argnum++;
			//
			// set defaults
			//
			name[0] = 0;
			volume = 1.0f;
			channel = CHAN_WEAPON;
			attenuation = ATTN_NORM;
			pitch = 1.0f;
			timeofs = 0;
			fadetime = 0;
			flags = SOUND_SYNCH;
			for ( i = argnum; i < argc; i++ )
			{
				switch (i-argnum)
				{
				case 0:
				{
					const char * realname;
					if ( random )
					{
						if ( use_model )
						{
							realname = SINMDL_Alias_FindRandom( defhandle, argv[i] );
						}
						else
						{
							realname = Alias_FindRandom( argv[i] );
						}
						if ( realname )
							strcpy( name, realname );
					}
					else
						strcpy( name, argv[i] );
				}
				break;
				case 1:
					volume = Sinatof( argv[i] );
					break;
				case 2:
					channel = atol( argv[i] );
					break;
				case 3:
					attenuation = atol( argv[i] );
					break;
				case 4:
					pitch = Sinatof( argv[i] );
					break;
				case 5:
					timeofs = Sinatof( argv[i] );
					break;
				case 6:
					fadetime = Sinatof( argv[i] );
					break;
				case 7:
					flags = atol( argv[i] );
					break;
				default:
					break;
				}
			}
			sound = NULL;
			if (name[0])
				sound = S_RegisterSound ( name );
			if ( sound )
				S_StartSoundEx( NULL, entnum, channel, sound, volume, attenuation, timeofs, pitch, fadetime, 0, NULL, flags );

			return;
		}
		else if ( !Q_stricmp( argv[argnum], "footstep" ) )
		{
			if (entnum)
			{
				centity_t   *ent;

				ent = &cl_entities[entnum];
				CL_FootStep( ent );
			}
			return;
		}
		else if ( !Q_stricmp( argv[argnum], "aliascache" ) )
		{
			char alias[128];
			char realname[128];
			float weight;
			int length;
			if ( (argc - argnum) > 3 )
			{
				strcpy( alias, argv[argnum + 1] );
				strcpy( realname, argv[argnum + 2] );
				weight = Sinatof( argv[argnum + 3] );
				length = (int)strlen( realname );
				if ( (length > 4) && ( !Q_stricmp( &realname[length-4], ".wav" ) ) )
				{
					if ( use_model )
					{
						SINMDL_Alias_Add( defhandle, alias, realname, weight );
					}
					else
					{
						Alias_Add( alias, realname, weight );
					}
					if ( precache->value )
						S_RegisterSound( realname );
				}
				else
				{
					if ( use_model )
						SINMDL_Alias_Add( defhandle, alias, realname, weight );
					else
						Alias_Add( alias, realname, weight );
				}
			}
			else if ( (argc - argnum) > 2 )
			{
				strcpy( alias, argv[argnum + 1] );
				strcpy( realname, argv[argnum + 2] );
				weight = 1;
				length = (int)strlen( realname );
				if ( (length > 4) && ( !Q_stricmp( &realname[length-4], ".wav" ) ) )
				{
					if ( use_model )
					{
						SINMDL_Alias_Add( defhandle, alias, realname, weight );
					}
					else
					{
						Alias_Add( alias, realname, weight );
					}
					if ( precache && precache->value )
						S_RegisterSound( realname );
				}
				else
				{
					if ( use_model )
						SINMDL_Alias_Add( defhandle, alias, realname, weight );
					else
						Alias_Add( alias, realname, weight );
				}
			}
			else
			{
				Com_DPrintf(DEVELOPER_MSG_SINCMDS, "CL_CMDS_ProcessCommands: malformed 'aliascache' command\n");
			}
			return;
		}
		else if ( !Q_stricmp( argv[argnum], "alias" ) )
		{
			char alias[128];
			char realname[128];
			float weight;
			if ( (argc - argnum) > 3 )
			{
				strcpy( alias, argv[argnum + 1] );
				strcpy( realname, argv[argnum + 2] );
				weight = Sinatof( argv[argnum + 3] );
				if ( use_model )
					SINMDL_Alias_Add( defhandle, alias, realname, weight );
				else
					Alias_Add( alias, realname, weight );
			}
			else if ( (argc - argnum) > 2 )
			{
				strcpy( alias, argv[argnum + 1] );
				strcpy( realname, argv[argnum + 2] );
				weight = 1;
				if ( use_model )
					SINMDL_Alias_Add( defhandle, alias, realname, weight );
				else
					Alias_Add( alias, realname, weight );
			}
			else
			{
				Com_DPrintf(DEVELOPER_MSG_SINCMDS, "CL_CMDS_ProcessCommands: malformed 'alias' command\n");
			}
			return;
		}
		else if ( !Q_stricmp( argv[argnum], "attach" ) )
		{
			//
			// all brackets are optional
			// attach <bone name> <model name> [origin <origin>] [angles <angles>] [anim <anim>] [frame <frame>] [scale <scale>]
			//
			entity_t ent;
			const char * bonename;
			int defhandle;

			// make sure this is valid
			if (!current_entity)
				return;

			if ( (argc - argnum) < 3 )
			{
				Com_DPrintf(DEVELOPER_MSG_SINCMDS, "CL_CMDS_ProcessCommands: attach invalid number of arguments\n");
				return;
			}

			//
			// clean up the structure
			//
			memset( &ent, 0, sizeof(entity_t) );

			// skip over "attach"
			argnum++;

			defhandle = re.SINMDL_GetDefHandle( current_entity->model );
			if (defhandle < 0)
			{
				Com_DPrintf(DEVELOPER_MSG_SINCMDS, "CL_CMDS_ProcessCommands: attach, trying to get handle of non-sinmdl model.\n");
				return;
			}

			// get bonename
			bonename = argv[argnum++];

			if (!SINMDL_GetBoneInfo
				(
					defhandle,
					bonename,
					&ent.bone.group_num,
					&ent.bone.tri_num,
					ent.bone.orientation
				)
			    )
			{
				Com_DPrintf(DEVELOPER_MSG_SINCMDS, "CL_CMDS_ProcessCommands: attach, GetBoneInfo failed.\n");
				return;
			}
			// initalize variables
			VectorClear( ent.origin );
			VectorClear( ent.angles );
			ent.anim = 0;
			ent.frame = 0;
			ent.scale = current_entity->scale;
			ent.alpha = 1.0f;
			ent.flags = current_entity->flags;
			//
			// link it to our parent
			//
			ent.parent = current_entity->real_entity_number;
			ent.real_entity_number = MAGIC_UNUSED_NUMBER;
			VectorCopy( cl_x_axis, cl_tm_forward );
			VectorCopy( cl_y_axis, cl_tm_right );
			VectorCopy( cl_z_axis, cl_tm_up );
			CL_CMDS_TempModel( &ent, argnum, argc, argv, 0 );
			return;
		}
		else if ( !Q_stricmp( argv[argnum], "bonespawnparticle" ) )
		{
			cparticle_t *p;
			const char  *bonename;
			int i,j;
			float scale;
			vec3_t trans[3];
			vec3_t offset;
			entity_t ent;
			int lightstyle=120;
			int count=1;
			extern cparticle_t    *active_particles, *free_particles;
			float gravity=0;
			float velocity=0;
			float randoffset=0;
			qboolean overbright=false;
			qboolean randstyle=false;
			qboolean firetype=false;
			int partsize=1;
			int partgrow=0;
			float forwardvel = 0;
			float rightvel = 0;
			float upvel = 0;

			// make sure this is valid
			if (!current_entity)
				return;

			// Check args
			if ( (argc - argnum) < 3 )
			{
				Com_DPrintf(DEVELOPER_MSG_SINCMDS, "CL_CMDS_ProcessCommands: bonespawnparticle invalid number of arguments\n");
				return;
			}

			// skip over "bonespawnparticle"
			argnum++;

			memset( &ent, 0, sizeof(entity_t) );

			IntitializeCoordinateSystemForModel( &ent, &scale, trans, offset );

			defhandle = re.SINMDL_GetDefHandle( current_entity->model );
			if (defhandle < 0)
			{
				Com_DPrintf(DEVELOPER_MSG_SINCMDS, "CL_CMDS_ProcessCommands: bonespawnparticle, trying to get handle of non-sinmdl model.\n");
				return;
			}

			// get bonename
			bonename = argv[argnum++];

			if (!SINMDL_GetBoneInfo
				(
					defhandle,
					bonename,
					&ent.bone.group_num,
					&ent.bone.tri_num,
					ent.bone.orientation
				)
			    )
			{
				Com_DPrintf(DEVELOPER_MSG_SINCMDS, "CL_CMDS_ProcessCommands: bonespawnparticle, GetBoneInfo failed.\n");
				return;
			}

			if (!SINMDL_GetBoneTransform
				(
					defhandle, ent.bone.group_num, ent.bone.tri_num, ent.bone.orientation, current_entity->anim, current_entity->frame,
					current_entity->scale * scale, trans, offset
				)
			    )
			{
				Com_DPrintf(DEVELOPER_MSG_SINCMDS, "CL_CMDS_ProcessCommands: bonespawnparticle, GetBoneTransform failed.\n");
				return;
			}
			// if it is a weapon, we need to prescale it
			if ( current_entity->flags & RF_WEAPONMODEL )
			{
				VectorScale( offset, 0.3f, offset );
				switch( (int)hand->value )
				{
				case 1:
					VectorNegate( cl_tm_right, cl_tm_right );
					break;
				case 2:
					return;
				}
			}

			// Calculate the origin
			for( i = 0; i < 3; i++ )
			{
				ent.origin[i] += (cl_tm_forward[i] * offset[0]) + (cl_tm_right[i] * offset[1])
										+ (cl_tm_up[i] * offset[2]);
			}

			while (argnum < argc)
			{
				if ( !Q_stricmp( argv[argnum], "lightstyle" ) )
				{
					argnum++;
					CHECK_ARGS( 1, "lightstyle" );
					lightstyle = atoi( argv[argnum++] );
				}
				else if ( !Q_stricmp( argv[argnum], "randstyle" ) )
				{
					argnum++;
					randstyle = true;
				}
				else if ( !Q_stricmp( argv[argnum], "count" ) )
				{
					argnum++;
					CHECK_ARGS( 1, "count" );
					count = atoi( argv[argnum++] );
				}
				else if ( !Q_stricmp( argv[argnum], "velocity" ) )
				{
					argnum++;
					CHECK_ARGS( 1, "velocity" );
					velocity = Sinatof( argv[argnum++] );
				}
				else if ( !Q_stricmp( argv[argnum], "gravity" ) )
				{
					argnum++;
					CHECK_ARGS( 1, "gravity" );
					gravity = Sinatof( argv[argnum++] );
				}
				else if ( !Q_stricmp( argv[argnum], "randoffset" ) )
				{
					argnum++;
					CHECK_ARGS( 1, "randoffset" );
					randoffset = Sinatof( argv[argnum++] );
				}
				else if ( !Q_stricmp( argv[argnum], "overbright" ) )
				{
					argnum++;
					overbright = true;
				}
				else if ( !Q_stricmp( argv[argnum], "fire" ) )
				{
					argnum++;
					firetype = true;
				}
				else if ( !Q_stricmp( argv[argnum], "size" ) )
				{
					argnum++;
					CHECK_ARGS( 1, "size" );
					partsize = atoi( argv[argnum++] );
					if(partsize < 1)
					{
						partsize = 1;
					}
					else if(partsize > 255)
					{
						partsize = 255;
					}
				}
				else if ( !Q_stricmp( argv[argnum], "growrate" ) )
				{
					argnum++;
					CHECK_ARGS( 1, "growrate" );
					partgrow = atoi( argv[argnum++] );
					if(partgrow < -128)
					{
						partgrow = -128;
					}
					else if(partgrow > 127)
					{
						partgrow = 127;
					}
				}
				else if ( !Q_stricmp( argv[argnum], "forwardvel" ) )
				{
					argnum++;
					CHECK_ARGS( 1, "forwardvel" );
					forwardvel = Sinatof( argv[argnum++] );
				}
				else if ( !Q_stricmp( argv[argnum], "rightvel" ) )
				{
					argnum++;
					CHECK_ARGS( 1, "rightvel" );
					rightvel = Sinatof( argv[argnum++] );
				}
				else if ( !Q_stricmp( argv[argnum], "upvel" ) )
				{
					argnum++;
					CHECK_ARGS( 1, "upvel" );
					upvel = Sinatof( argv[argnum++] );
				}
				else
				{
					Com_DPrintf(DEVELOPER_MSG_SINCMDS, "CL_CMDS_ProcessCommands::bonespawnparticle: unrecognized command %s\n", argv[argnum]);
					argnum++;
				}
			}

			for (i=0; i<count; i++)
			{
				if (!free_particles)
					return;
				p = free_particles;
				free_particles = p->next;
				p->next = active_particles;
				active_particles = p;

				p->time        = cl.time;
				p->lightstyle  = lightstyle;

				for (j=0; j<3; j++)
				{
					p->org[j] = ent.origin[j] + crand() * randoffset;
					p->vel[j] = crand() * velocity;
					if(forwardvel)
						p->vel[j] += cl_tm_forward[j]*forwardvel;
					if(rightvel)
						p->vel[j] += cl_tm_right[j]*rightvel;
					if(upvel)
						p->vel[j] += cl_tm_up[j]*upvel;
				}
				p->accel[0] = p->accel[1] = 0;
				p->accel[2] = gravity;
				p->flags = 0;
				if ( overbright )
					p->flags |= PARTICLE_OVERBRIGHT;
				if ( randstyle )
					p->flags |= PARTICLE_RANDOM;
				if ( firetype )
					p->flags |= PARTICLE_FIRE;
				p->size = partsize;
				p->growrate = partgrow;
			}
		}
		else if ( !Q_stricmp( argv[argnum], "spawnparticle" ) )
		{
			cparticle_t *p;
			int i,j;
			entity_t ent;
			int lightstyle=120;
			int count=1;
			extern cparticle_t *active_particles, *free_particles;
			float gravity=0;
			float velocity=0;
			float randoffset=0;
			qboolean overbright=false;
			qboolean randstyle=false;
			float unused1;
			vec3_t unused2[3];
			vec3_t unused3;

			// make sure this is valid
			if (!current_entity)
				return;

			// Check args
			if ( (argc - argnum) < 3 )
			{
				Com_DPrintf(DEVELOPER_MSG_SINCMDS, "CL_CMDS_ProcessCommands: spawnparticle invalid number of arguments\n");
				return;
			}

			// skip over "spawnparticle"
			argnum++;

			memset( &ent, 0, sizeof(entity_t) );

			IntitializeCoordinateSystemForModel( &ent, &unused1, unused2, unused3 );

			while (argnum < argc)
			{
				if ( !Q_stricmp( argv[argnum], "lightstyle" ) )
				{
					argnum++;
					CHECK_ARGS( 1, "lightstyle" );
					lightstyle = atoi( argv[argnum++] );
				}
				else if ( !Q_stricmp( argv[argnum], "randstyle" ) )
				{
					argnum++;
					randstyle = true;
				}
				else if ( !Q_stricmp( argv[argnum], "count" ) )
				{
					argnum++;
					CHECK_ARGS( 1, "count" );
					count = atoi( argv[argnum++] );
				}
				else if ( !Q_stricmp( argv[argnum], "velocity" ) )
				{
					argnum++;
					CHECK_ARGS( 1, "velocity" );
					velocity = Sinatof( argv[argnum++] );
				}
				else if ( !Q_stricmp( argv[argnum], "gravity" ) )
				{
					argnum++;
					CHECK_ARGS( 1, "gravity" );
					gravity = Sinatof( argv[argnum++] );
				}
				else if ( !Q_stricmp( argv[argnum], "randoffset" ) )
				{
					argnum++;
					CHECK_ARGS( 1, "randoffset" );
					randoffset = Sinatof( argv[argnum++] );
				}
				else if ( !Q_stricmp( argv[argnum], "overbright" ) )
				{
					argnum++;
					overbright = true;
				}
				else
				{
					Com_DPrintf(DEVELOPER_MSG_SINCMDS, "CL_CMDS_ProcessCommands::spawnparticle: unrecognized command %s\n", argv[argnum]);
					argnum++;
				}
			}

			for (i=0; i<count; i++)
			{
				if (!free_particles)
					return;
				p = free_particles;
				free_particles = p->next;
				p->next = active_particles;
				active_particles = p;

				p->time        = cl.time;
				p->lightstyle  = lightstyle;

				for (j=0; j<3; j++)
				{
					p->org[j] = ent.origin[j] + crand() * randoffset;
					p->vel[j] = crand() * velocity;
				}
				p->accel[0] = p->accel[1] = 0;
				p->accel[2] = gravity;
				p->flags = 0;
				if ( overbright )
					p->flags |= PARTICLE_OVERBRIGHT;
				if ( randstyle )
					p->flags |= PARTICLE_RANDOM;
			}
		}
		else if ( !Q_stricmp( argv[argnum], "bonespawn" ) )
		{
			//
			// all brackets are optional
			// bonespawn <bone name> <model name> [origin <origin>] [angles <angles>] [anim <anim>] [frame <frame>] [scale <scale>]
			//
			entity_t ent;
			const char  *bonename;
			int i;
			float scale;
			vec3_t trans[3];
			vec3_t offset;

			// make sure this is valid
			if (!current_entity)
				return;

			// Check args
			if ( (argc - argnum) < 3 )
			{
				Com_DPrintf(DEVELOPER_MSG_SINCMDS, "CL_CMDS_ProcessCommands: bonespawn invalid number of arguments\n");
				return;
			}

			//
			// clean up the structure
			//
			memset( &ent, 0, sizeof(entity_t) );

			// skip over "bonespawn"
			argnum++;

			IntitializeCoordinateSystemForModel( &ent, &scale, trans, offset );

			defhandle = re.SINMDL_GetDefHandle( current_entity->model );
			if (defhandle < 0)
			{
				Com_DPrintf(DEVELOPER_MSG_SINCMDS, "CL_CMDS_ProcessCommands: bonespawn, trying to get handle of non-sinmdl model.\n");
				return;
			}

			// get bonename
			bonename = argv[argnum++];

			if (!SINMDL_GetBoneInfo
				(
					defhandle,
					bonename,
					&ent.bone.group_num,
					&ent.bone.tri_num,
					ent.bone.orientation
				)
			    )
			{
				Com_DPrintf(DEVELOPER_MSG_SINCMDS, "CL_CMDS_ProcessCommands: bonespawn, GetBoneInfo failed.\n");
				return;
			}

			if (!SINMDL_GetBoneTransform
				(
					defhandle, ent.bone.group_num, ent.bone.tri_num, ent.bone.orientation, current_entity->anim, current_entity->frame,
					current_entity->scale * scale, trans, offset
				)
			    )
			{
				Com_DPrintf(DEVELOPER_MSG_SINCMDS, "CL_CMDS_ProcessCommands: bonespawn, GetBoneTransform failed.\n");
				return;
			}
			// if it is a weapon, we need to prescale it
			if ( current_entity->flags & RF_WEAPONMODEL )
			{
				VectorScale( offset, 0.3f, offset );
				switch( (int)hand->value )
				{
				case 1:
					VectorNegate( cl_tm_right, cl_tm_right );
					break;
				case 2:
					break;
				}
			}

			for( i = 0; i < 3; i++ )
			{
				ent.origin[i] += (cl_tm_forward[i] * offset[0]) + (cl_tm_right[i] * offset[1])
										+ (cl_tm_up[i] * offset[2]);
			}

			// initalize variables
			ent.anim = 0;
			ent.frame = 0;
			ent.scale = current_entity->scale * scale;
			ent.alpha = 1.0f;
			ent.flags = current_entity->flags;
			ent.flags &= ~RF_WEAPONMODEL;
			ent.parent = 0;
			ent.real_entity_number = MAGIC_UNUSED_NUMBER;
			CL_CMDS_TempModel( &ent, argnum, argc, argv, 0 );
			return;
		}
		else if ( !Q_stricmp( argv[argnum], "shootbeam" ) )
		{
			entity_t ent;
			const char     *bonename;
			int i;
			float scale;
			vec3_t trans[3];
			vec3_t offset;
			struct model_t *model;
			float alpha=1.0;
			int flags=0;
			float length=1024;
			float life=30;
			float min_offset = 1;
			float max_offset = 25;
			int overlap=0;

			// make sure this is valid
			if (!current_entity)
				return;

			// Check args
			if ( (argc - argnum) < 3 )
			{
				Com_DPrintf(DEVELOPER_MSG_SINCMDS, "CL_CMDS_ProcessCommands: shootbeam invalid number of arguments\n");
				return;
			}

			//
			// clean up the structure
			//
			memset( &ent, 0, sizeof(entity_t) );

			// skip over "shootbeam"
			argnum++;

			IntitializeCoordinateSystemForModel( &ent, &scale, trans, offset );

			defhandle = re.SINMDL_GetDefHandle( current_entity->model );
			if (defhandle < 0)
			{
				Com_DPrintf(DEVELOPER_MSG_SINCMDS, "CL_CMDS_ProcessCommands: bonespawn, trying to get handle of non-sinmdl model.\n");
				return;
			}

			// get bonename
			bonename = argv[argnum++];

			if (!SINMDL_GetBoneInfo
				(
					defhandle,
					bonename,
					&ent.bone.group_num,
					&ent.bone.tri_num,
					ent.bone.orientation
				)
			    )
			{
				Com_DPrintf(DEVELOPER_MSG_SINCMDS, "CL_CMDS_ProcessCommands: bonespawn, GetBoneInfo failed.\n");
				return;
			}

			if (!SINMDL_GetBoneTransform
				(
					defhandle, ent.bone.group_num, ent.bone.tri_num, ent.bone.orientation, current_entity->anim, current_entity->frame,
					current_entity->scale * scale, trans, offset
				)
			    )
			{
				Com_DPrintf(DEVELOPER_MSG_SINCMDS, "CL_CMDS_ProcessCommands: bonespawn, GetBoneTransform failed.\n");
				return;
			}
			// if it is a weapon, we need to prescale it
			if ( current_entity->flags & RF_WEAPONMODEL )
			{
				VectorScale( offset, 0.3f, offset );
				switch( (int)hand->value )
				{
				case 1:
					VectorNegate( cl_tm_right, cl_tm_right );
					break;
				}
			}

			for( i = 0; i < 3; i++ )
			{
				ent.origin[i] += (cl_tm_forward[i] * offset[0]) + (cl_tm_right[i] * offset[1])
										+ (cl_tm_up[i] * offset[2]);
			}

			model = re.RegisterModel( argv[argnum++] );

			if (!model)
			{
				Com_DPrintf(DEVELOPER_MSG_SINCMDS, "CL_CMDS_ProcessCommands::shootbeam: model was not found.\n");
				return;
			}

			while (argnum < argc)
			{
				if ( !Q_stricmp( argv[argnum], "lightning" ) )
				{
					argnum++;
					flags |= BEAM_LIGHTNING_EFFECT;
				}
				else if ( !Q_stricmp( argv[argnum], "length" ) )
				{
					argnum++;
					CHECK_ARGS( 1, "length" );
					length = Sinatof( argv[argnum++] );
				}
				else if ( !Q_stricmp( argv[argnum], "randomalpha" ) )
				{
					argnum++;
					flags |= BEAM_RANDOM_ALPHA;
				}
				else if ( !Q_stricmp( argv[argnum], "alpha" ) )
				{
					argnum++;
					CHECK_ARGS( 1, "alpha" );
					alpha = Sinatof( argv[argnum++] );
				}
				else if ( !Q_stricmp( argv[argnum], "scale" ) )
				{
					argnum++;
					CHECK_ARGS( 1, "scale" );
					scale = Sinatof( argv[argnum] );
				}
				else if ( !Q_stricmp( argv[argnum], "animate" ) )
				{
					argnum++;
					flags |= BEAM_AUTO_ANIMATE;
				}
				else if ( !Q_stricmp( argv[argnum], "roll" ) )
				{
					argnum++;
					flags |= BEAM_ROLL;
				}
				else if ( !Q_stricmp( argv[argnum], "randomframe" ) )
				{
					argnum++;
					flags |= BEAM_ANIMATE_RANDOM_START;
				}
				else if ( !Q_stricmp( argv[argnum], "life" ) )
				{
					argnum++;
					CHECK_ARGS( 1, "life" );
					life = Sinatof( argv[argnum++] );
				}
				else if ( !Q_stricmp( argv[argnum], "minoffset" ) )
				{
					argnum++;
					CHECK_ARGS( 1, "minoffset" );
					min_offset = Sinatof( argv[argnum++] );
				}
				else if ( !Q_stricmp( argv[argnum], "maxoffset" ) )
				{
					argnum++;
					CHECK_ARGS( 1, "maxoffset" );
					max_offset = Sinatof( argv[argnum++] );
				}
				else if ( !Q_stricmp( argv[argnum], "overlap" ) )
				{
					argnum++;
					CHECK_ARGS( 1, "overlap" );
					overlap = atoi( argv[argnum++] );
				}
				else
				{
					Com_DPrintf(DEVELOPER_MSG_SINCMDS, "CL_CMDS_ProcessCommands::shootbeam: unrecognized command %s\n", argv[argnum]);
					argnum++;
				}
			}
			CL_CreateBeam( ent.origin, cl_tm_forward, &cl_entities[entnum], model, alpha, scale, flags, length, life, true, false, NULL, min_offset, max_offset, overlap );
			return;
		}
		else if ( !Q_stricmp( argv[argnum], "spawn" ) )
		{
			//
			// all brackets are optional
			// spawn <model name> [origin <origin>] [angles <angles>] [anim <anim>] [frame <frame>] [scale <scale>]
			//
			entity_t ent;
			float unused1;
			vec3_t unused2[3];
			vec3_t unused3;
			// make sure this is valid
			if (!current_entity)
				return;

			if ( (argc - argnum) < 2 )
			{
				Com_DPrintf(DEVELOPER_MSG_SINCMDS, "CL_CMDS_ProcessCommands: spawn invalid number of arguments\n");
				return;
			}

			//
			// clean up the structure
			//
			memset( &ent, 0, sizeof(entity_t) );

			// skip over "spawn"
			argnum++;

			IntitializeCoordinateSystemForModel( &ent, &unused1, unused2, unused3 );

			ent.anim = 0;
			ent.frame = 0;
			ent.scale = current_entity->scale;
			ent.alpha = 1.0f;
			ent.flags = current_entity->flags;
			ent.flags &= ~RF_WEAPONMODEL;
			ent.flags &= ~RF_DONTDRAW;
			ent.parent = 0;
			ent.real_entity_number = MAGIC_UNUSED_NUMBER;
			CL_CMDS_TempModel( &ent, argnum, argc, argv, 0 );
			return;
		}
		else if ( !Q_stricmp( argv[argnum], "cachemodel" ) )
		{
			if ( !precache->value )
				return;
			if ( (argc - argnum) > 1 )
			{
				char mname[128];

				strcpy( mname, argv[argnum + 1] );
				re.RegisterModel( mname );
			}
			else
			{
				Com_DPrintf(DEVELOPER_MSG_SINCMDS, "CL_CMDS_ProcessCommands: malformed 'cachemodel' command\n");
			}
			return;
		}
		else if ( !Q_stricmp( argv[argnum], "shootbullets" ) )
		{
			//
			// do a client side bullet hole effect
			//
			centity_t  *ent;
			vec3_t spread;
			int num;
			float distance;

			if ( (argc - argnum) < 6 )
			{
				Com_DPrintf(DEVELOPER_MSG_SINCMDS, "CL_CMDS_ProcessCommands: shootbullets - invalid number of arguments\n");
				return;
			}

			ent = &cl_entities[entnum];
			num = atoi( argv[1] );
			spread[0] = Sinatof( argv[2] );
			spread[1] = Sinatof( argv[3] );
			spread[2] = Sinatof( argv[4] );
			distance  = Sinatof( argv[5] );
			CL_ShootBullets( ent, num, spread, distance );
			return;
		}
		else if ( !Q_stricmp( argv[argnum], "dlight" ) )
		{
			//
			// do a client side dynamic light
			//
			centity_t  *ent;
			float r,g,b,radius,decay,life;

			if ((argc - argnum) < 11)
			{
				Com_DPrintf(DEVELOPER_MSG_SINCMDS, "CL_CMDS_ProcessCommands: dlight - invalid number of arguments\n");
				return;
			}

			ent = &cl_entities[entnum];
			r      = Sinatof(argv[1]);
			r     += CL_Random(Sinatof(argv[2]));
			g      = Sinatof(argv[3]);
			g     += CL_Random(Sinatof(argv[4]));
			b      = Sinatof(argv[5]);
			b     += CL_Random(Sinatof(argv[6]));
			radius = Sinatof(argv[7]);
			radius+= CL_Random(Sinatof(argv[8]));
			life   = Sinatof(argv[9]);
			decay  = Sinatof(argv[10]);
			CL_TempdlightEffect( ent->current.origin, r, g, b, radius, life, decay );
			return;
		}
		else if ( !Q_stricmp( argv[argnum], "explosion" ) )
		{
			centity_t  *ent;
			float scale;
			//
			// do a client side explosion
			//
			if ( (argc - argnum) < 2 )
			{
				Com_DPrintf(DEVELOPER_MSG_SINCMDS, "CL_CMDS_ProcessCommands: explosion - invalid number of arguments\n");
				return;
			}

			ent   = &cl_entities[entnum];
			scale = Sinatof( argv[1] );
			TempExplosion( ent->current.origin, scale );
			return;
		}
		else if ( !Q_stricmp( argv[argnum], "shootspawn" ) )
		{
			// Spawn something at the end of the shot.

		}
		else if ( !Q_stricmp( argv[argnum], "pstream" ) )
		{
			centity_t   *ent;
			int lightstyle=120;
			int flags=0;
			float velocity=0;
			int density=1;
			float gravity=0;
			float randoffset=0;
			qboolean shockwave=false;

			//
			// do a client side particle stream effect
			//
			ent = &cl_entities[entnum];

			// skip over "pstream"
			argnum++;

			while (argnum < argc)
			{
				if ( !Q_stricmp( argv[argnum], "lightstyle" ) )
				{
					argnum++;
					CHECK_ARGS( 1, "lightstyle" );
					lightstyle = atoi( argv[argnum++] );
				}
				else if ( !Q_stricmp( argv[argnum], "shockwave" ) )
				{
					argnum++;
					shockwave = true;
				}
				else if ( !Q_stricmp( argv[argnum], "randstyle" ) )
				{
					argnum++;
					flags |= PARTICLE_RANDOM;
				}
				else if ( !Q_stricmp( argv[argnum], "density" ) )
				{
					argnum++;
					CHECK_ARGS( 1, "density" );
					density = atoi( argv[argnum++] );
				}
				else if ( !Q_stricmp( argv[argnum], "velocity" ) )
				{
					argnum++;
					CHECK_ARGS( 1, "velocity" );
					velocity = Sinatof( argv[argnum++] );
				}
				else if ( !Q_stricmp( argv[argnum], "gravity" ) )
				{
					argnum++;
					CHECK_ARGS( 1, "gravity" );
					gravity = Sinatof( argv[argnum++] );
				}
				else if ( !Q_stricmp( argv[argnum], "randoffset" ) )
				{
					argnum++;
					CHECK_ARGS( 1, "randoffset" );
					randoffset = Sinatof( argv[argnum++] );
				}
				else if ( !Q_stricmp( argv[argnum], "overbright" ) )
				{
					argnum++;
					flags |= PARTICLE_OVERBRIGHT;
				}
				else if ( !Q_stricmp( argv[argnum], "random" ) )
				{
					argnum++;
					flags |= PARTICLE_RANDOM;
				}
				else
				{
					Com_DPrintf(DEVELOPER_MSG_SINCMDS, "CL_CMDS_ProcessCommands::pstream: unrecognized command %s\n", argv[argnum]);
					argnum++;
				}
			}
			CL_ParticleStream( ent, lightstyle, density, velocity, randoffset, gravity, flags, shockwave );
			return;
		}
		else if ( !Q_stricmp( argv[argnum], "end" ) )
		{
			//
			// script end command, ignore
			//
			return;
		}
		else
		{
			Com_DPrintf(DEVELOPER_MSG_SINCMDS, "CL_CMDS_ProcessCommands: unrecognized command %s\n", argv[argnum]);
			return;
		}
	}
}

/*
=================
CL_CMDS_ProcessFile
=================
*/
void CL_CMDS_ProcessFile( const char * filename )
{
#define MAX_CMD_ARGS 24
#define MAX_CMD_ARG_LENGTH 128
	char args[MAX_CMD_ARGS][MAX_CMD_ARG_LENGTH];
	char *argv[MAX_CMD_ARGS];
	int numargs;
	int i;
	void *buffer;
	const char *workbuf;
	char com_token[MAX_STRING_CHARS];

	Com_DPrintf(DEVELOPER_MSG_SINCMDS, "CL_CMDS_ProcessFile: ");
	if ( FS_LoadFile( filename, &buffer ) == -1 )
		return;

	Com_DPrintf(DEVELOPER_MSG_SINCMDS, "%s\n", filename);

	workbuf = (const char *) buffer;

	for ( i = 0; i < MAX_CMD_ARGS; i++ )
	{
		argv[i] = &args[i][0];
	}

	while ( 1 )
	{
		numargs = 0;
		// grab each line as we go
		strcpy( com_token, COM_GetToken( &workbuf, true ) );
		if (!com_token[0])
			break;
		strcpy( args[numargs++], com_token );
		// get the rest of the line
		while( 1 )
		{
			strcpy( com_token, COM_GetToken( &workbuf, false ) );
			if (!com_token[0])
				break;
			if (strlen( com_token ) >= MAX_CMD_ARG_LENGTH)
			{
				Com_DPrintf(DEVELOPER_MSG_SINCMDS, "CL_CMDS_ProcessFile: argument too long, truncating in %s.\n", filename);
				com_token[MAX_CMD_ARG_LENGTH - 1] = 0;
			}
			strcpy( args[numargs++], com_token );
		}
		if (numargs)
			CL_CMDS_ProcessCommands( 0, -1, numargs, (const char **)argv );
	}
	FS_FreeFile( buffer );
}
/*
=================
CL_PrintDefAnimCommands
=================
*/
static void CL_PrintDefAnimCommands( int defhandle, const char * anim )
{
	int i, j, k, animnum, numframes;
	sinmdl_cmd_t * cmds;

	animnum = SINMDL_Anim_NumForName( defhandle, anim );
	if ( animnum < 0 )
	{
		Com_Printf( "PrintCommands: anim %s could not be found.\n", anim );
		return;
	}
	numframes = SINMDL_Anim_NumFrames( defhandle, animnum );
	Com_Printf( "   Server Commands\n\n" );
	for ( i = 0; i < numframes; i++ )
	{
		cmds = SINMDL_Frame_Commands_Server( defhandle, animnum, i );
		if ( cmds && cmds->num_cmds )
		{
			for ( j = 0; j < cmds->num_cmds; j++ )
			{
				Com_Printf( "   Frame %d: ", i );
				for ( k = 0; k < cmds->cmds[j].num_args; k++ )
				{
					Com_Printf( "%s ", cmds->cmds[j].args[k] );
				}
				Com_Printf( "\n" );
			}
		}
	}
	Com_Printf( "\n   Client Commands\n\n" );
	for ( i = 0; i < numframes; i++ )
	{
		cmds = SINMDL_Frame_Commands_Client( defhandle, animnum, i );
		if ( cmds && cmds->num_cmds )
		{
			for ( j = 0; j < cmds->num_cmds; j++ )
			{
				Com_Printf( "   Frame %d: ", i );
				for ( k = 0; k < cmds->cmds[j].num_args; k++ )
				{
					Com_Printf( "%s ", cmds->cmds[j].args[k] );
				}
				Com_Printf( "\n" );
			}
		}
	}
}

/*
=================
CL_PrintDefCommands
=================
*/
void CL_PrintDefCommands( void )
{
	const char *model;
	const char *anim;
	int defhandle;
	int i, numanims;

	if (Cmd_Argc() != 3)
	{
		Com_Printf ( "usage: printcommands <model> <anim>\n" );
		return;
	}

	model = Cmd_Argv( 1 );
	anim = Cmd_Argv( 2 );
	defhandle = re.SINMDL_GetDefHandle( re.RegisterModel( model ) );
	if ( defhandle < 0 )
	{
		Com_Printf( "PrintCommands: could not find model %s.\n", model );
		return;
	}
	if ( !Q_stricmp( anim, "all" ) )
	{
		numanims = SINMDL_NumAnims( defhandle );
		for ( i = 0; i < numanims; i++ )
		{
			anim = SINMDL_Anim_NameForNum( defhandle, i );
			Com_Printf( "   Model: %s Anim: %s\n\n", model, anim );
			CL_PrintDefAnimCommands( defhandle, anim );
			Com_Printf( "--------------------------------------------------\n" );
		}
	}
	else
	{
		Com_Printf( "   Model: %s Anim: %s\n\n", model, anim );
		CL_PrintDefAnimCommands( defhandle, anim );
	}
}
