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

*/

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

						 - SPLITMODELS -

==========================================================================
*/
// - Adding the weapon models in split pieces
// by Jalisk0

#include "cg_local.h"


//======================================================================
//						weaponinfo Registering
//======================================================================

weaponinfo_t	cg_pWeaponModelInfos[WEAP_TOTAL];

static char *wmPartSufix[] = { "", "_expansion", "_barrel", "_flash", "_hand", NULL };

/*
===============
CG_vWeap_ParseAnimationScript

script:
0 = first frame
1 = lastframe/number of frames
2 = looping frames
3 = frame time

keywords: 
  "islastframe":Will read the second value of each animation as lastframe (usually means numframes)
  "rotationscale": value witch will scale the barrel rotation speed 
===============
*/
qboolean CG_vWeap_ParseAnimationScript( weaponinfo_t *weaponinfo, char *filename )
{
	qbyte		*buf;
	char		*ptr, *token;
	int			rounder, counter, i;
	qboolean	debug = qtrue;
	qboolean	islastframe = qfalse;
	int			anim_data[4][VWEAP_MAXANIMS];
	int			length, filenum;
	
	rounder = 0;
	counter = 1; //reseve 0 for 'no animation'

	weaponinfo->rotationscale = 1;//default

	if( !cg_debugWeaponModels->integer )
		debug = qfalse;

	// load the file
	length = trap_FS_FOpenFile( filename, &filenum, FS_READ );
	if( length == -1 )
		return qfalse;
	if( !length ) {
		trap_FS_FCloseFile( filenum );
		return qfalse;
	}
	buf = CG_Malloc( length + 1 );
	trap_FS_Read( buf, length, filenum );
	trap_FS_FCloseFile( filenum );

	
	if( !buf ) {
		CG_Free( buf );
		return qfalse;
	}
	
	if( debug )
		CG_Printf( "%sLoading weapon animation script:%s%s\n", S_COLOR_BLUE, filename, S_COLOR_WHITE );

	//proceed
	ptr = ( char * )buf;
	while( ptr )
	{
		token = COM_ParseExt( &ptr, qtrue );
		if( !token )
			break;
		
		//see if it is keyword or number
		if( *token < '0' || *token > '9' ) {
			
			//islastframe
			if( !Q_stricmp (token, "islastframe") ) 
			{
				islastframe = qtrue;
				if( debug )
					CG_Printf( "%sScript: Second value is read as lastframe%s\n", S_COLOR_BLUE, S_COLOR_WHITE );

				//islastframe
			} else if( !Q_stricmp(token, "rotationscale") ) 
			{
				if( debug )
					CG_Printf( "%sScript: rotation scale:%s", S_COLOR_BLUE, S_COLOR_WHITE );

				token = COM_ParseExt( &ptr, qfalse );
				weaponinfo->rotationscale = (float)atoi(token);

				if( debug )
					CG_Printf( "%s%f%s\n", S_COLOR_BLUE, weaponinfo->rotationscale, S_COLOR_WHITE );

			} else if( token[0] && debug )
				CG_Printf( "%signored: %s%s\n", S_COLOR_YELLOW, token, S_COLOR_WHITE );
			
		} else {
			
			//frame & animation values
			i = (int)atoi(token);
			if( debug ) {
				if( rounder == 0 )
					CG_Printf( "%sScript: %s", S_COLOR_BLUE, S_COLOR_WHITE );
				CG_Printf( "%s%i - %s", S_COLOR_BLUE, i, S_COLOR_WHITE );
			}
			anim_data[rounder][counter] = i;
			rounder++;
			if( rounder > 3 ){
				rounder = 0;
				if( debug )
					CG_Printf( "%s anim: %i%s\n", S_COLOR_BLUE, counter, S_COLOR_WHITE );
				counter++;
			}
		}
	}
	
	CG_Free( buf );

	if( counter < VWEAP_MAXANIMS )
	{
		CG_Printf( "%sERROR: incomplete WEAPON script: %s - Using default%s\n", S_COLOR_YELLOW, filename, S_COLOR_WHITE );
		return qfalse;
	}

	//reorganize to make my life easier
	for( i=0 ; i<VWEAP_MAXANIMS ; i++ )
	{
		weaponinfo->firstframe[i] = anim_data[0][i];

		if( islastframe )
			weaponinfo->lastframe[i] = anim_data[1][i];
		else
			weaponinfo->lastframe[i] = ((anim_data[0][i]) + (anim_data[1][i]));
		
		weaponinfo->loopingframes[i] = anim_data[2][i];
		
		if( anim_data[3][i] < 10 )//never allow less than 10 fps
			anim_data[3][i] = 10;
		
		weaponinfo->frametime[i] = 1000/anim_data[3][i];
	}

	return qtrue;
}

/*
===============
CG_LoadHandAnimations
===============
*/
void CG_CreateHandDefaultAnimations( weaponinfo_t *weaponinfo )
{
	int defaultfps = 15;

	weaponinfo->rotationscale = 1;//default

	//default Q3 hand
/*	weaponinfo->firstframe[VWEAP_STANDBY] = 0;
	weaponinfo->lastframe[VWEAP_STANDBY] = 0;
	weaponinfo->loopingframes[VWEAP_STANDBY] = 1;
	weaponinfo->frametime[VWEAP_STANDBY] = 1000/defaultfps;

	weaponinfo->firstframe[VWEAP_ATTACK] = 1;//attack animation (1-5)
	weaponinfo->lastframe[VWEAP_ATTACK] = 5;
	weaponinfo->loopingframes[VWEAP_ATTACK] = 0;
	weaponinfo->frametime[VWEAP_ATTACK] = 1000/defaultfps;

	weaponinfo->firstframe[VWEAP_ATTACK2_HOLD] = 0;
	weaponinfo->lastframe[VWEAP_ATTACK2_HOLD] = 0;
	weaponinfo->loopingframes[VWEAP_ATTACK2_HOLD] = 1;
	weaponinfo->frametime[VWEAP_ATTACK2_HOLD] = 1000/defaultfps;

	weaponinfo->firstframe[VWEAP_ATTACK2_RELEASE] = 0;
	weaponinfo->lastframe[VWEAP_ATTACK2_RELEASE] = 0;
	weaponinfo->loopingframes[VWEAP_ATTACK2_RELEASE] = 1;
	weaponinfo->frametime[VWEAP_ATTACK2_RELEASE] = 1000/defaultfps;

	weaponinfo->firstframe[VWEAP_RELOAD] = 0;
	weaponinfo->lastframe[VWEAP_RELOAD] = 0;
	weaponinfo->loopingframes[VWEAP_RELOAD] = 1;
	weaponinfo->frametime[VWEAP_RELOAD] = 1000/defaultfps;

	weaponinfo->firstframe[VWEAP_WEAPDOWN] = 6;//flipout animation (6-10)
	weaponinfo->lastframe[VWEAP_WEAPDOWN] = 10;
	weaponinfo->loopingframes[VWEAP_WEAPDOWN] = 1;
	weaponinfo->frametime[VWEAP_WEAPDOWN] = 1000/defaultfps;

	weaponinfo->firstframe[VWEAP_WEAPONUP] = 11;//flipin animation(11-15)
	weaponinfo->lastframe[VWEAP_WEAPONUP] = 15;
	weaponinfo->loopingframes[VWEAP_WEAPONUP] = 0;
	weaponinfo->frametime[VWEAP_WEAPONUP] = 1000/defaultfps;
*/
	// default wsw hand
	weaponinfo->firstframe[VWEAP_STANDBY] = 0;
	weaponinfo->lastframe[VWEAP_STANDBY] = 0;
	weaponinfo->loopingframes[VWEAP_STANDBY] = 1;
	weaponinfo->frametime[VWEAP_STANDBY] = 1000/defaultfps;

	weaponinfo->firstframe[VWEAP_ATTACK_WEAK] = 1;//attack animation (1-5)
	weaponinfo->lastframe[VWEAP_ATTACK_WEAK] = 5;
	weaponinfo->loopingframes[VWEAP_ATTACK_WEAK] = 0;
	weaponinfo->frametime[VWEAP_ATTACK_WEAK] = 1000/defaultfps;

	weaponinfo->firstframe[VWEAP_ATTACK_STRONG] = 0;
	weaponinfo->lastframe[VWEAP_ATTACK_STRONG] = 0;
	weaponinfo->loopingframes[VWEAP_ATTACK_STRONG] = 1;
	weaponinfo->frametime[VWEAP_ATTACK_STRONG] = 1000/defaultfps;

	weaponinfo->firstframe[VWEAP_WEAPDOWN] = 0;
	weaponinfo->lastframe[VWEAP_WEAPDOWN] = 0;
	weaponinfo->loopingframes[VWEAP_WEAPDOWN] = 1;
	weaponinfo->frametime[VWEAP_WEAPDOWN] = 1000/defaultfps;

	weaponinfo->firstframe[VWEAP_WEAPONUP] = 6;//flipout animation (6-10)
	weaponinfo->lastframe[VWEAP_WEAPONUP] = 10;
	weaponinfo->loopingframes[VWEAP_WEAPONUP] = 1;
	weaponinfo->frametime[VWEAP_WEAPONUP] = 1000/defaultfps;

	return;
}

/*
===============
CG_BuildProjectionOrigin
 store the orientation_t closer to the tag_flash we can create,
 or create one using an offset we consider acceptable.
 NOTE: This tag will ignore weapon models animations. You'd have to 
 do it in realtime to use it with animations. Or be careful on not
 moving the weapon too much
===============
*/
static void CG_BuildProjectionOrigin( weaponinfo_t *weaponinfo )
{
	orientation_t	tag, tag_barrel;
	static entity_t	ent;

	if( !weaponinfo )
		return;

	if( weaponinfo->model[WEAPON] ) {
		
		// assign the model to an entity_t, so we can build boneposes
		memset( &ent, 0, sizeof(ent) );
		ent.rtype = RT_MODEL;
		ent.scale = 1.0f;
		ent.model = weaponinfo->model[WEAPON];
		CG_SetBoneposesForTemporaryEntity( &ent ); // assigns and builds the skeleton so we can use grabtag
		
		// try getting the tag_flash from the weapon model
		if( CG_GrabTag( &weaponinfo->tag_projectionsource, &ent, "tag_flash" ) )
			return; // succesfully

		// if it didn't work, try getting it from the barrel model
		if( CG_GrabTag( &tag_barrel, &ent, "tag_barrel" ) && weaponinfo->model[BARREL] ) {
			// assign the model to an entity_t, so we can build boneposes
			memset( &ent, 0, sizeof(ent) );
			ent.rtype = RT_MODEL;
			ent.scale = 1.0f;
			ent.model = weaponinfo->model[BARREL];
			CG_SetBoneposesForTemporaryEntity( &ent );
			if( CG_GrabTag( &tag, &ent, "tag_flash" ) && weaponinfo->model[BARREL]) {
				VectorCopy( vec3_origin, weaponinfo->tag_projectionsource.origin );
				Matrix_Identity( weaponinfo->tag_projectionsource.axis );
				CG_MoveToTag( weaponinfo->tag_projectionsource.origin,
					weaponinfo->tag_projectionsource.axis,
					tag_barrel.origin,
					tag_barrel.axis,
					tag.origin,
					tag.axis );
				return; // succesfully
			}
		}
	} 
	
	// doesn't have a weapon model, or the weapon model doesn't have a tag
	VectorSet( weaponinfo->tag_projectionsource.origin, 16, 0, 8 );
	Matrix_Identity( weaponinfo->tag_projectionsource.axis );
}

/*
===============
CG_WeaponModelUpdateRegistration
===============
*/
qboolean CG_WeaponModelUpdateRegistration( weaponinfo_t *weaponinfo, char *filename )
{
	int 			p;
	char			scratch[MAX_QPATH];

	for( p = 0; p < WEAPMODEL_PARTS; p++ )
	{
		//md3
		if( !weaponinfo->model[p] ) 
		{		
			Q_snprintfz( scratch, sizeof(scratch), "models/v_weapons/%s%s.md3", filename, wmPartSufix[p] );
			weaponinfo->model[p] = CG_RegisterModel( scratch );	// skelmod
		}
		//skm
		if( !weaponinfo->model[p] ) 
		{		
			Q_snprintfz( scratch, sizeof(scratch), "models/v_weapons/%s%s.skm", filename, wmPartSufix[p] );
			weaponinfo->model[p] = CG_RegisterModel( scratch );	// skelmod
		}
		//md2
		if( !weaponinfo->model[p] ) 
		{		
			Q_snprintfz( scratch, sizeof(scratch), "models/v_weapons/%s%s.md2", filename, wmPartSufix[p] );
			weaponinfo->model[p] = CG_RegisterModel( scratch );	// skelmod
		}
	}

	//load failed
	if( !weaponinfo->model[HAND] )
	{
		weaponinfo->name[0] = 0;
		for( p = 0; p < WEAPMODEL_PARTS; p++ )
			weaponinfo->model[p] = NULL;
		
		return qfalse;
	}

	//Load animation script for the hand model
	Q_snprintfz( scratch, sizeof(scratch), "models/v_weapons/%s.cfg", filename );

	if( !CG_vWeap_ParseAnimationScript( weaponinfo, scratch ) )
		CG_CreateHandDefaultAnimations( weaponinfo );

	//create a tag_projection from tag_flash, to possition fire effects
	CG_BuildProjectionOrigin( weaponinfo );
	Vector4Set( weaponinfo->outlineColor, 0, 0, 0, 1 );

	if( cg_debugWeaponModels->integer )
		CG_Printf( "%sWEAPmodel: Loaded successful%s\n", S_COLOR_BLUE, S_COLOR_WHITE );

	Q_strncpyz( weaponinfo->name, filename, sizeof(weaponinfo->name) );

	return qtrue;
}

/*
===============
CG_FindWeaponModelSpot

  Stored names format is without extension, like this: "rocketl/rocketl"
===============
*/
struct weaponinfo_s *CG_FindWeaponModelSpot( char *filename )
{
	int 			i;
	int				freespot = -1;


	for( i = 0; i < WEAP_TOTAL; i++ )
	{
		if( cg_pWeaponModelInfos[i].inuse == qtrue )
		{
			if( !Q_stricmp(cg_pWeaponModelInfos[i].name, filename) )//found it
			{
				if( cg_debugWeaponModels->integer )
					CG_Printf( "WEAPModel: found at spot %i: %s\n", i, filename );

				return &cg_pWeaponModelInfos[i];
			}
		}
		else if( freespot < 0 )
			freespot = i;
	}

	if( freespot < 0 )
		CG_Error( "%sCG_FindWeaponModelSpot: Couldn't find a free weaponinfo spot%s", S_COLOR_RED, S_COLOR_WHITE );

	//we have a free spot
	if( cg_debugWeaponModels->integer )
		CG_Printf( "WEAPmodel: assigned free spot %i for weaponinfo %s\n", freespot, filename );

	return &cg_pWeaponModelInfos[freespot];
}

/*
===============
CG_RegisterWeaponModel
===============
*/
struct weaponinfo_s *CG_RegisterWeaponModel( char *cgs_name, int weaponTag )
{
	char			filename[MAX_QPATH];
	weaponinfo_t	*weaponinfo;

	Q_strncpyz( filename, cgs_name, sizeof(filename) );
	COM_StripExtension( filename );

	weaponinfo = CG_FindWeaponModelSpot( filename );

	if( weaponinfo->inuse == qtrue )
		return weaponinfo;

	weaponinfo->inuse = CG_WeaponModelUpdateRegistration( weaponinfo, filename );
	if( !weaponinfo->inuse )
	{
		if( cg_debugWeaponModels->integer )
			CG_Printf( "%sWEAPmodel: Failed:%s%s\n", S_COLOR_YELLOW, filename, S_COLOR_WHITE );

		return NULL;
	}

	// find the item for this weapon and try to assign the outline color
	if( weaponTag ) {
		gitem_t *item = GS_FindItemByTag( weaponTag );
		if( item ) {
			if( item->color && strlen(item->color) > 1 ) {
				CG_SetOutlineColor( weaponinfo->outlineColor, color_table[ColorIndex(item->color[1])] );
			}
		}
	}

	return weaponinfo;
}


/*
===============
CG_CreateWeaponZeroModel

  we can't allow NULL weaponmodels to be passed to the viewweapon.
  They will produce crashes because the lack of animation script. 
  We need to have at least one weaponinfo with a script to be used
  as a replacement, so, weapon 0 will have the animation script 
  even if the registration failed
===============
*/
struct weaponinfo_s *CG_CreateWeaponZeroModel( char *filename )
{
	weaponinfo_t	*weaponinfo;

	COM_StripExtension( filename );

	weaponinfo = CG_FindWeaponModelSpot( filename );

	if( weaponinfo->inuse == qtrue )
		return weaponinfo;

	if( cg_debugWeaponModels->integer )
		CG_Printf( "%sWEAPmodel: Failed to load generic weapon. Creatin fake one%s\n", S_COLOR_YELLOW, S_COLOR_WHITE );

	CG_CreateHandDefaultAnimations( weaponinfo );
	Vector4Set( weaponinfo->outlineColor, 0, 0, 0, 255 );
	weaponinfo->inuse = qtrue;

	Q_strncpyz( weaponinfo->name, filename, sizeof(weaponinfo->name) );

	return weaponinfo;//no checks
}


//======================================================================
//							weapons
//======================================================================

/*
===============
CG_GetWeaponFromClientIndex

  Each clientinfo stores and array of weaponmodels for every weapon.
  This function returns the requested one

  I don't use baseClientInfo replacements because all them point
  to the same struct now.

  Each pmodel stores a pointer to the active weapon, so there's no
  need to call this function to access the pmodelinfo weapon, but for
  accessing the other weapons in the client index
===============
*/
struct weaponinfo_s *CG_GetWeaponFromPModelIndex( pmodel_t *pmodel, int currentweapon )
{
	weaponinfo_t	*weaponinfo;

	if( !cg_vwep->integer || (currentweapon > WEAP_TOTAL - 1) )
		currentweapon = WEAP_NONE;

	if( pmodel && pmodel->pmodelinfo ) {
		weaponinfo = pmodel->pmodelinfo->weaponIndex[currentweapon];
	} else {
		weaponinfo = cgs.basePModelInfo->weaponIndex[currentweapon];
	}
	if( !weaponinfo )
		weaponinfo = cgs.basePModelInfo->weaponIndex[WEAP_NONE];
	return weaponinfo;
}

/*
===============
CG_AddWeaponOnTag

  Add weapon model(s) positioned at the tag
===============
*/
void CG_AddWeaponOnTag( entity_t *ent, orientation_t *tag, pweapon_t *pweapon, int effects, orientation_t *projectionSource )
{
	entity_t		weapon;

	//don't try without base model
	if( !ent->model || !pweapon->weaponInfo )
		return;

	//don't try without a tag
	if( !tag )
		return;

	//weapon
	memset( &weapon, 0, sizeof(weapon) );
	weapon.scale = ent->scale;
	weapon.flags = ent->flags;
	weapon.frame = 0;
	weapon.oldframe = 0;
	weapon.model = pweapon->weaponInfo->model[WEAPON];
	
	CG_PlaceModelOnTag( &weapon, ent, tag );
	
	VectorCopy( weapon.origin, weapon.oldorigin );
	VectorCopy( weapon.origin, weapon.lightingOrigin );

	CG_AddEntityToScene( &weapon );	// skelmod

	if( !weapon.model )
		return;

	if( cg_outlineItemsBlack->integer ) {
		CG_AddColoredOutLineEffect( &weapon, effects, 0, 0, 0, 255 );
	} else {
		CG_AddColoredOutLineEffect( &weapon, effects, 
			pweapon->weaponInfo->outlineColor[0], 
			pweapon->weaponInfo->outlineColor[1], 
			pweapon->weaponInfo->outlineColor[2], 
			pweapon->weaponInfo->outlineColor[3] );
	}
	CG_AddShellEffects( &weapon, effects );
	//CG_AddColorShell( &weapon, renderfx );

	// update projection source
	if( projectionSource != NULL ) {
		VectorCopy( vec3_origin, projectionSource->origin );
		Matrix_Copy( axis_identity, projectionSource->axis );
		CG_MoveToTag( projectionSource->origin, projectionSource->axis,
			weapon.origin, weapon.axis,
			pweapon->weaponInfo->tag_projectionsource.origin,
			pweapon->weaponInfo->tag_projectionsource.axis );
	}

	//barrel
	if( pweapon->weaponInfo->model[EXPANSION] )
	{
		if( CG_GrabTag( tag, &weapon, "tag_expansion" ) )
		{
			entity_t	expansion;
			memset( &expansion, 0, sizeof(expansion) );
			expansion.model = pweapon->weaponInfo->model[EXPANSION];
			expansion.scale = ent->scale;
			expansion.flags = ent->flags;
			expansion.frame = 0;
			expansion.oldframe = 0;

			CG_PlaceModelOnTag( &expansion, &weapon, tag );
			
			CG_AddEntityToScene( &expansion );	// skelmod

			if( cg_outlineItemsBlack->integer ) {
				CG_AddColoredOutLineEffect( &expansion, effects, 0, 0, 0, 255 );
			} else {
				CG_AddColoredOutLineEffect( &expansion, effects, 
					pweapon->weaponInfo->outlineColor[0], 
					pweapon->weaponInfo->outlineColor[1], 
					pweapon->weaponInfo->outlineColor[2], 
					pweapon->weaponInfo->outlineColor[3] );
			}

			CG_AddShellEffects( &expansion, effects );
			//CG_AddColorShell( &expansion, renderfx );
		}
	}

	// barrel
	if( pweapon->weaponInfo->model[BARREL] )
	{
		if( CG_GrabTag( tag, &weapon, "tag_barrel" ) )
		{
			float scaledTime;

			entity_t	barrel;
			memset( &barrel, 0, sizeof(barrel) );
			barrel.model = pweapon->weaponInfo->model[BARREL];
			barrel.scale = ent->scale;
			barrel.flags = ent->flags;
			barrel.frame = 0;
			barrel.oldframe = 0;

			// rotation
			scaledTime = cg.frameTime*100; // not precise, but enough

			pweapon->rotationSpeed += scaledTime*((pweapon->flashtime > cg.time) * (pweapon->rotationSpeed < 8));
			pweapon->rotationSpeed -= scaledTime/15;
			if( pweapon->rotationSpeed < 0 )
				pweapon->rotationSpeed = 0.0f;

			pweapon->angles[2] += scaledTime * pweapon->rotationSpeed * pweapon->weaponInfo->rotationscale;
			if( pweapon->angles[2] > 360 )
				pweapon->angles[2] -= 360;

			AnglesToAxis( pweapon->angles, barrel.axis );

			// barrel requires special tagging
			CG_PlaceRotatedModelOnTag( &barrel, &weapon, tag );
			
			CG_AddEntityToScene( &barrel );	// skelmod

			if( cg_outlineItemsBlack->integer ) {
				CG_AddColoredOutLineEffect( &barrel, effects, 0, 0, 0, 255 );
			} else {
				CG_AddColoredOutLineEffect( &barrel, effects, 
					pweapon->weaponInfo->outlineColor[0], 
					pweapon->weaponInfo->outlineColor[1], 
					pweapon->weaponInfo->outlineColor[2], 
					pweapon->weaponInfo->outlineColor[3] );
			}
			CG_AddShellEffects( &barrel, effects );
			//CG_AddColorShell( &barrel, renderfx );
		}
	}

	if( !(effects & EF_WEAPON_POWERING) )
		pweapon->powering_timestamp = cg.time;
	
	// if viewermodel don't bother adding the flash, it casts no shadow
	if( ent->flags & RF_VIEWERMODEL )
		return;

	// flash
	if( !CG_GrabTag( tag, &weapon, "tag_flash" ) )
		return;

	if( pweapon->flashtime < cg.time && !(effects & EF_WEAPON_POWERING) ) 
		return;

	if( pweapon->weaponInfo->model[FLASH] )
	{
		entity_t	flash;
		memset( &flash, 0, sizeof(flash) );
		flash.model = pweapon->weaponInfo->model[FLASH];
		flash.scale = ent->scale;
		flash.flags = ent->flags | RF_NOSHADOW;
		flash.frame = 0;
		flash.oldframe = 0;

		if( effects & EF_WEAPON_POWERING )
			flash.scale = 0.001 * (cg.time - pweapon->powering_timestamp);
		
		CG_PlaceModelOnTag( &flash, &weapon, tag );
		if( effects & EF_WEAPON_POWERING )
			CG_AddLightToScene( flash.origin, 10 + 40 * flash.scale, 1, 1, 0, NULL );
		
		CG_AddEntityToScene( &flash );	// skelmod
	}
}
