DOOM-3-BFG

DOOM 3 BFG Edition
Log | Files | Refs

Weapon.cpp (118141B)


      1 /*
      2 ===========================================================================
      3 
      4 Doom 3 BFG Edition GPL Source Code
      5 Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company. 
      6 
      7 This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").  
      8 
      9 Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
     10 it under the terms of the GNU General Public License as published by
     11 the Free Software Foundation, either version 3 of the License, or
     12 (at your option) any later version.
     13 
     14 Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
     15 but WITHOUT ANY WARRANTY; without even the implied warranty of
     16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     17 GNU General Public License for more details.
     18 
     19 You should have received a copy of the GNU General Public License
     20 along with Doom 3 BFG Edition Source Code.  If not, see <http://www.gnu.org/licenses/>.
     21 
     22 In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code.  If not, please request a copy in writing from id Software at the address below.
     23 
     24 If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
     25 
     26 ===========================================================================
     27 */
     28 
     29 #include "../idlib/precompiled.h"
     30 #pragma hdrstop
     31 
     32 #include "Game_local.h"
     33 #include "PredictedValue_impl.h"
     34 
     35 /***********************************************************************
     36 
     37   idWeapon  
     38 	
     39 ***********************************************************************/
     40 
     41 //
     42 // event defs
     43 //
     44 const idEventDef EV_Weapon_Clear( "<clear>" );
     45 const idEventDef EV_Weapon_GetOwner( "getOwner", NULL, 'e' );
     46 const idEventDef EV_Weapon_Next( "nextWeapon" );
     47 const idEventDef EV_Weapon_State( "weaponState", "sd" );
     48 const idEventDef EV_Weapon_UseAmmo( "useAmmo", "d" );
     49 const idEventDef EV_Weapon_AddToClip( "addToClip", "d" );
     50 const idEventDef EV_Weapon_AmmoInClip( "ammoInClip", NULL, 'f' );
     51 const idEventDef EV_Weapon_AmmoAvailable( "ammoAvailable", NULL, 'f' );
     52 const idEventDef EV_Weapon_TotalAmmoCount( "totalAmmoCount", NULL, 'f' );
     53 const idEventDef EV_Weapon_ClipSize( "clipSize", NULL, 'f' );
     54 const idEventDef EV_Weapon_WeaponOutOfAmmo( "weaponOutOfAmmo" );
     55 const idEventDef EV_Weapon_WeaponReady( "weaponReady" );
     56 const idEventDef EV_Weapon_WeaponReloading( "weaponReloading" );
     57 const idEventDef EV_Weapon_WeaponHolstered( "weaponHolstered" );
     58 const idEventDef EV_Weapon_WeaponRising( "weaponRising" );
     59 const idEventDef EV_Weapon_WeaponLowering( "weaponLowering" );
     60 const idEventDef EV_Weapon_Flashlight( "flashlight", "d" );
     61 const idEventDef EV_Weapon_LaunchProjectiles( "launchProjectiles", "dffff" );
     62 const idEventDef EV_Weapon_CreateProjectile( "createProjectile", NULL, 'e' );
     63 const idEventDef EV_Weapon_EjectBrass( "ejectBrass" );
     64 const idEventDef EV_Weapon_Melee( "melee", NULL, 'd' );
     65 const idEventDef EV_Weapon_GetWorldModel( "getWorldModel", NULL, 'e' );
     66 const idEventDef EV_Weapon_AllowDrop( "allowDrop", "d" );
     67 const idEventDef EV_Weapon_AutoReload( "autoReload", NULL, 'f' );
     68 const idEventDef EV_Weapon_NetReload( "netReload" );
     69 const idEventDef EV_Weapon_IsInvisible( "isInvisible", NULL, 'f' );
     70 const idEventDef EV_Weapon_NetEndReload( "netEndReload" );
     71 const idEventDef EV_Weapon_GrabberHasTarget( "grabberHasTarget", NULL, 'd' );
     72 const idEventDef EV_Weapon_Grabber( "grabber", "d" );
     73 const idEventDef EV_Weapon_Grabber_SetGrabDistance( "grabberGrabDistance", "f" );
     74 const idEventDef EV_Weapon_LaunchProjectilesEllipse( "launchProjectilesEllipse", "dffff" );
     75 const idEventDef EV_Weapon_LaunchPowerup( "launchPowerup", "sfd" );
     76 const idEventDef EV_Weapon_StartWeaponSmoke( "startWeaponSmoke" );
     77 const idEventDef EV_Weapon_StopWeaponSmoke( "stopWeaponSmoke" );
     78 const idEventDef EV_Weapon_StartWeaponParticle( "startWeaponParticle", "s" );
     79 const idEventDef EV_Weapon_StopWeaponParticle( "stopWeaponParticle", "s" );
     80 const idEventDef EV_Weapon_StartWeaponLight( "startWeaponLight", "s" );
     81 const idEventDef EV_Weapon_StopWeaponLight( "stopWeaponLight", "s" );
     82 
     83 //
     84 // class def
     85 //
     86 CLASS_DECLARATION( idAnimatedEntity, idWeapon )
     87 	EVENT( EV_Weapon_Clear,						idWeapon::Event_Clear )
     88 	EVENT( EV_Weapon_GetOwner,					idWeapon::Event_GetOwner )
     89 	EVENT( EV_Weapon_State,						idWeapon::Event_WeaponState )
     90 	EVENT( EV_Weapon_WeaponReady,				idWeapon::Event_WeaponReady )
     91 	EVENT( EV_Weapon_WeaponOutOfAmmo,			idWeapon::Event_WeaponOutOfAmmo )
     92 	EVENT( EV_Weapon_WeaponReloading,			idWeapon::Event_WeaponReloading )
     93 	EVENT( EV_Weapon_WeaponHolstered,			idWeapon::Event_WeaponHolstered )
     94 	EVENT( EV_Weapon_WeaponRising,				idWeapon::Event_WeaponRising )
     95 	EVENT( EV_Weapon_WeaponLowering,			idWeapon::Event_WeaponLowering )
     96 	EVENT( EV_Weapon_UseAmmo,					idWeapon::Event_UseAmmo )
     97 	EVENT( EV_Weapon_AddToClip,					idWeapon::Event_AddToClip )
     98 	EVENT( EV_Weapon_AmmoInClip,				idWeapon::Event_AmmoInClip )
     99 	EVENT( EV_Weapon_AmmoAvailable,				idWeapon::Event_AmmoAvailable )
    100 	EVENT( EV_Weapon_TotalAmmoCount,			idWeapon::Event_TotalAmmoCount )
    101 	EVENT( EV_Weapon_ClipSize,					idWeapon::Event_ClipSize )
    102 	EVENT( AI_PlayAnim,							idWeapon::Event_PlayAnim )
    103 	EVENT( AI_PlayCycle,						idWeapon::Event_PlayCycle )
    104 	EVENT( AI_SetBlendFrames,					idWeapon::Event_SetBlendFrames )
    105 	EVENT( AI_GetBlendFrames,					idWeapon::Event_GetBlendFrames )
    106 	EVENT( AI_AnimDone,							idWeapon::Event_AnimDone )
    107 	EVENT( EV_Weapon_Next,						idWeapon::Event_Next )
    108 	EVENT( EV_SetSkin,							idWeapon::Event_SetSkin )
    109 	EVENT( EV_Weapon_Flashlight,				idWeapon::Event_Flashlight )
    110 	EVENT( EV_Light_GetLightParm,				idWeapon::Event_GetLightParm )
    111 	EVENT( EV_Light_SetLightParm,				idWeapon::Event_SetLightParm )
    112 	EVENT( EV_Light_SetLightParms,				idWeapon::Event_SetLightParms )
    113 	EVENT( EV_Weapon_LaunchProjectiles,			idWeapon::Event_LaunchProjectiles )
    114 	EVENT( EV_Weapon_CreateProjectile,			idWeapon::Event_CreateProjectile )
    115 	EVENT( EV_Weapon_EjectBrass,				idWeapon::Event_EjectBrass )
    116 	EVENT( EV_Weapon_Melee,						idWeapon::Event_Melee )
    117 	EVENT( EV_Weapon_GetWorldModel,				idWeapon::Event_GetWorldModel )
    118 	EVENT( EV_Weapon_AllowDrop,					idWeapon::Event_AllowDrop )
    119 	EVENT( EV_Weapon_AutoReload,				idWeapon::Event_AutoReload )
    120 	EVENT( EV_Weapon_NetReload,					idWeapon::Event_NetReload )
    121 	EVENT( EV_Weapon_IsInvisible,				idWeapon::Event_IsInvisible )
    122 	EVENT( EV_Weapon_NetEndReload,				idWeapon::Event_NetEndReload )
    123 	EVENT( EV_Weapon_Grabber,					idWeapon::Event_Grabber )
    124 	EVENT( EV_Weapon_GrabberHasTarget,			idWeapon::Event_GrabberHasTarget )
    125 	EVENT( EV_Weapon_Grabber_SetGrabDistance,	idWeapon::Event_GrabberSetGrabDistance )
    126 	EVENT( EV_Weapon_LaunchProjectilesEllipse,	idWeapon::Event_LaunchProjectilesEllipse )
    127 	EVENT( EV_Weapon_LaunchPowerup,				idWeapon::Event_LaunchPowerup )
    128 	EVENT( EV_Weapon_StartWeaponSmoke,			idWeapon::Event_StartWeaponSmoke )
    129 	EVENT( EV_Weapon_StopWeaponSmoke,			idWeapon::Event_StopWeaponSmoke )
    130 	EVENT( EV_Weapon_StartWeaponParticle,		idWeapon::Event_StartWeaponParticle )
    131 	EVENT( EV_Weapon_StopWeaponParticle,		idWeapon::Event_StopWeaponParticle )
    132 	EVENT( EV_Weapon_StartWeaponLight,			idWeapon::Event_StartWeaponLight )
    133 	EVENT( EV_Weapon_StopWeaponLight,			idWeapon::Event_StopWeaponLight )
    134 END_CLASS
    135 
    136 
    137 idCVar cg_projectile_clientAuthoritative_maxCatchup( "cg_projectile_clientAuthoritative_maxCatchup", "500", CVAR_INTEGER, "" );
    138 
    139 idCVar g_useWeaponDepthHack( "g_useWeaponDepthHack", "1", CVAR_BOOL, "Crunch z depth on weapons" );
    140 
    141 idCVar g_weaponShadows( "g_weaponShadows", "0", CVAR_BOOL | CVAR_ARCHIVE, "Cast shadows from weapons" );
    142 
    143 extern idCVar cg_predictedSpawn_debug;
    144 
    145 /***********************************************************************
    146 
    147 	init
    148 
    149 ***********************************************************************/
    150 
    151 /*
    152 ================
    153 idWeapon::idWeapon()
    154 ================
    155 */
    156 idWeapon::idWeapon() {
    157 	owner					= NULL;
    158 	worldModel				= NULL;
    159 	weaponDef				= NULL;
    160 	thread					= NULL;
    161 
    162 	memset( &guiLight, 0, sizeof( guiLight ) );
    163 	memset( &muzzleFlash, 0, sizeof( muzzleFlash ) );
    164 	memset( &worldMuzzleFlash, 0, sizeof( worldMuzzleFlash ) );
    165 	memset( &nozzleGlow, 0, sizeof( nozzleGlow ) );
    166 
    167 	muzzleFlashEnd			= 0;
    168 	flashColor				= vec3_origin;
    169 	muzzleFlashHandle		= -1;
    170 	worldMuzzleFlashHandle	= -1;
    171 	guiLightHandle			= -1;
    172 	nozzleGlowHandle		= -1;
    173 	modelDefHandle			= -1;
    174 	grabberState			= -1;
    175 
    176 	berserk					= 2;
    177 	brassDelay				= 0;
    178 
    179 	allowDrop				= true;
    180 	isPlayerFlashlight		= false;
    181 
    182 	fraccos = 0.0f;
    183 	fraccos2 = 0.0f;
    184 
    185 	Clear();
    186 
    187 	fl.networkSync = true;
    188 }
    189 
    190 /*
    191 ================
    192 idWeapon::~idWeapon()
    193 ================
    194 */
    195 idWeapon::~idWeapon() {
    196 	Clear();
    197 	delete worldModel.GetEntity();
    198 }
    199 
    200 
    201 /*
    202 ================
    203 idWeapon::Spawn
    204 ================
    205 */
    206 void idWeapon::Spawn() {
    207 	if ( !common->IsClient() ) {
    208 		// setup the world model
    209 		worldModel = static_cast< idAnimatedEntity * >( gameLocal.SpawnEntityType( idAnimatedEntity::Type, NULL ) );
    210 		worldModel.GetEntity()->fl.networkSync = true;
    211 	}
    212 
    213 	if ( 1 /*!common->IsMultiplayer()*/ ) {
    214 		grabber.Initialize();
    215 	}
    216 
    217 	thread = new idThread();
    218 	thread->ManualDelete();
    219 	thread->ManualControl();
    220 }
    221 
    222 /*
    223 ================
    224 idWeapon::SetOwner
    225 
    226 Only called at player spawn time, not each weapon switch
    227 ================
    228 */
    229 void idWeapon::SetOwner( idPlayer *_owner ) {
    230 	assert( !owner );
    231 	owner = _owner;
    232 	SetName( va( "%s_weapon", owner->name.c_str() ) );
    233 
    234 	if ( worldModel.GetEntity() ) {
    235 		worldModel.GetEntity()->SetName( va( "%s_weapon_worldmodel", owner->name.c_str() ) );
    236 	}
    237 }
    238 
    239 /*
    240 ================
    241 idWeapon::SetFlashlightOwner
    242 
    243 Only called at player spawn time, not each weapon switch
    244 ================
    245 */
    246 void idWeapon::SetFlashlightOwner( idPlayer *_owner ) {
    247 	assert( !owner );
    248 	owner = _owner;
    249 	SetName( va( "%s_weapon_flashlight", owner->name.c_str() ) );
    250 
    251 	if ( worldModel.GetEntity() ) {
    252 		worldModel.GetEntity()->SetName( va( "%s_weapon_flashlight_worldmodel", owner->name.c_str() ) );
    253 	}
    254 }
    255 
    256 /*
    257 ================
    258 idWeapon::ShouldConstructScriptObjectAtSpawn
    259 
    260 Called during idEntity::Spawn to see if it should construct the script object or not.
    261 Overridden by subclasses that need to spawn the script object themselves.
    262 ================
    263 */
    264 bool idWeapon::ShouldConstructScriptObjectAtSpawn() const {
    265 	return false;
    266 }
    267 
    268 /*
    269 ================
    270 idWeapon::CacheWeapon
    271 ================
    272 */
    273 void idWeapon::CacheWeapon( const char *weaponName ) {
    274 	const idDeclEntityDef *weaponDef;
    275 	const char *brassDefName;
    276 	const char *clipModelName;
    277 	idTraceModel trm;
    278 	const char *guiName;
    279 
    280 	weaponDef = gameLocal.FindEntityDef( weaponName, false );
    281 	if ( !weaponDef ) {
    282 		return;
    283 	}
    284 
    285 	// precache the brass collision model
    286 	brassDefName = weaponDef->dict.GetString( "def_ejectBrass" );
    287 	if ( brassDefName[0] ) {
    288 		const idDeclEntityDef *brassDef = gameLocal.FindEntityDef( brassDefName, false );
    289 		if ( brassDef ) {
    290 			brassDef->dict.GetString( "clipmodel", "", &clipModelName );
    291 			if ( !clipModelName[0] ) {
    292 				clipModelName = brassDef->dict.GetString( "model" );		// use the visual model
    293 			}
    294 			// load the trace model
    295 			collisionModelManager->TrmFromModel( clipModelName, trm );
    296 		}
    297 	}
    298 
    299 	guiName = weaponDef->dict.GetString( "gui" );
    300 	if ( guiName[0] ) {
    301 		uiManager->FindGui( guiName, true, false, true );
    302 	}
    303 }
    304 
    305 /*
    306 ================
    307 idWeapon::Save
    308 ================
    309 */
    310 void idWeapon::Save( idSaveGame *savefile ) const {
    311 
    312 	savefile->WriteInt( status );
    313 	savefile->WriteObject( thread );
    314 	savefile->WriteString( state );
    315 	savefile->WriteString( idealState );
    316 	savefile->WriteInt( animBlendFrames );
    317 	savefile->WriteInt( animDoneTime );
    318 	savefile->WriteBool( isLinked );
    319 
    320 	savefile->WriteObject( owner );
    321 	worldModel.Save( savefile );
    322 
    323 	savefile->WriteInt( hideTime );
    324 	savefile->WriteFloat( hideDistance );
    325 	savefile->WriteInt( hideStartTime );
    326 	savefile->WriteFloat( hideStart );
    327 	savefile->WriteFloat( hideEnd );
    328 	savefile->WriteFloat( hideOffset );
    329 	savefile->WriteBool( hide );
    330 	savefile->WriteBool( disabled );
    331 
    332 	savefile->WriteInt( berserk );
    333 
    334 	savefile->WriteVec3( playerViewOrigin );
    335 	savefile->WriteMat3( playerViewAxis );
    336 
    337 	savefile->WriteVec3( viewWeaponOrigin );
    338 	savefile->WriteMat3( viewWeaponAxis );
    339 
    340 	savefile->WriteVec3( muzzleOrigin );
    341 	savefile->WriteMat3( muzzleAxis );
    342 
    343 	savefile->WriteVec3( pushVelocity );
    344 
    345 	savefile->WriteString( weaponDef->GetName() );
    346 	savefile->WriteFloat( meleeDistance );
    347 	savefile->WriteString( meleeDefName );
    348 	savefile->WriteInt( brassDelay );
    349 	savefile->WriteString( icon );
    350 	savefile->WriteString( pdaIcon );
    351 	savefile->WriteString( displayName );
    352 	savefile->WriteString( itemDesc );
    353 
    354 	savefile->WriteInt( guiLightHandle );
    355 	savefile->WriteRenderLight( guiLight );
    356 
    357 	savefile->WriteInt( muzzleFlashHandle );
    358 	savefile->WriteRenderLight( muzzleFlash );
    359 
    360 	savefile->WriteInt( worldMuzzleFlashHandle );
    361 	savefile->WriteRenderLight( worldMuzzleFlash );
    362 
    363 	savefile->WriteVec3( flashColor );
    364 	savefile->WriteInt( muzzleFlashEnd );
    365 	savefile->WriteInt( flashTime );
    366 
    367 	savefile->WriteBool( lightOn );
    368 	savefile->WriteBool( silent_fire );
    369 
    370 	savefile->WriteInt( kick_endtime );
    371 	savefile->WriteInt( muzzle_kick_time );
    372 	savefile->WriteInt( muzzle_kick_maxtime );
    373 	savefile->WriteAngles( muzzle_kick_angles );
    374 	savefile->WriteVec3( muzzle_kick_offset );
    375 
    376 	savefile->WriteInt( ammoType );
    377 	savefile->WriteInt( ammoRequired );
    378 	savefile->WriteInt( clipSize );
    379 	savefile->WriteInt( ammoClip.Get() );
    380 	savefile->WriteInt( lowAmmo );
    381 	savefile->WriteBool( powerAmmo );
    382 
    383 	// savegames <= 17
    384 	savefile->WriteInt( 0 );
    385 
    386 	savefile->WriteInt( zoomFov );
    387 
    388 	savefile->WriteJoint( barrelJointView );
    389 	savefile->WriteJoint( flashJointView );
    390 	savefile->WriteJoint( ejectJointView );
    391 	savefile->WriteJoint( guiLightJointView );
    392 	savefile->WriteJoint( ventLightJointView );
    393 
    394 	savefile->WriteJoint( flashJointWorld );
    395 	savefile->WriteJoint( barrelJointWorld );
    396 	savefile->WriteJoint( ejectJointWorld );
    397 
    398 	savefile->WriteBool( hasBloodSplat );
    399 
    400 	savefile->WriteSoundShader( sndHum );
    401 
    402 	savefile->WriteParticle( weaponSmoke );
    403 	savefile->WriteInt( weaponSmokeStartTime );
    404 	savefile->WriteBool( continuousSmoke );
    405 	savefile->WriteParticle( strikeSmoke );
    406 	savefile->WriteInt( strikeSmokeStartTime );
    407 	savefile->WriteVec3( strikePos );
    408 	savefile->WriteMat3( strikeAxis );
    409 	savefile->WriteInt( nextStrikeFx );
    410 
    411 	savefile->WriteBool( nozzleFx );
    412 	savefile->WriteInt( nozzleFxFade );
    413 
    414 	savefile->WriteInt( lastAttack );
    415 
    416 	savefile->WriteInt( nozzleGlowHandle );
    417 	savefile->WriteRenderLight( nozzleGlow );
    418 
    419 	savefile->WriteVec3( nozzleGlowColor );
    420 	savefile->WriteMaterial( nozzleGlowShader );
    421 	savefile->WriteFloat( nozzleGlowRadius );
    422 
    423 	savefile->WriteInt( weaponAngleOffsetAverages );
    424 	savefile->WriteFloat( weaponAngleOffsetScale );
    425 	savefile->WriteFloat( weaponAngleOffsetMax );
    426 	savefile->WriteFloat( weaponOffsetTime );
    427 	savefile->WriteFloat( weaponOffsetScale );
    428 
    429 	savefile->WriteBool( allowDrop );
    430 	savefile->WriteObject( projectileEnt );
    431 
    432 	savefile->WriteStaticObject( grabber );
    433 	savefile->WriteInt( grabberState );
    434 
    435 	savefile->WriteJoint ( smokeJointView );
    436 
    437 	savefile->WriteInt(weaponParticles.Num());
    438 	for(int i = 0; i < weaponParticles.Num(); i++) {
    439 		WeaponParticle_t* part = weaponParticles.GetIndex(i);
    440 		savefile->WriteString( part->name );
    441 		savefile->WriteString( part->particlename );
    442 		savefile->WriteBool( part->active );
    443 		savefile->WriteInt( part->startTime );
    444 		savefile->WriteJoint( part->joint );
    445 		savefile->WriteBool( part->smoke );
    446 		if(!part->smoke) {
    447 			savefile->WriteObject(part->emitter);
    448 		}
    449 	}
    450 	savefile->WriteInt(weaponLights.Num());
    451 	for(int i = 0; i < weaponLights.Num(); i++) {
    452 		WeaponLight_t* light = weaponLights.GetIndex(i);
    453 		savefile->WriteString( light->name );
    454 		savefile->WriteBool( light->active );
    455 		savefile->WriteInt( light->startTime );
    456 		savefile->WriteJoint( light->joint );
    457 		savefile->WriteInt( light->lightHandle );
    458 		savefile->WriteRenderLight( light->light );
    459 	}
    460 
    461 }
    462 
    463 /*
    464 ================
    465 idWeapon::Restore
    466 ================
    467 */
    468 void idWeapon::Restore( idRestoreGame *savefile ) {
    469 
    470 	savefile->ReadInt( (int &)status );
    471 	savefile->ReadObject( reinterpret_cast<idClass *&>( thread ) );
    472 	savefile->ReadString( state );
    473 	savefile->ReadString( idealState );
    474 	savefile->ReadInt( animBlendFrames );
    475 	savefile->ReadInt( animDoneTime );
    476 	savefile->ReadBool( isLinked );
    477 
    478 	// Re-link script fields
    479 	WEAPON_ATTACK.LinkTo(		scriptObject, "WEAPON_ATTACK" );
    480 	WEAPON_RELOAD.LinkTo(		scriptObject, "WEAPON_RELOAD" );
    481 	WEAPON_NETRELOAD.LinkTo(	scriptObject, "WEAPON_NETRELOAD" );
    482 	WEAPON_NETENDRELOAD.LinkTo(	scriptObject, "WEAPON_NETENDRELOAD" );
    483 	WEAPON_NETFIRING.LinkTo(	scriptObject, "WEAPON_NETFIRING" );
    484 	WEAPON_RAISEWEAPON.LinkTo(	scriptObject, "WEAPON_RAISEWEAPON" );
    485 	WEAPON_LOWERWEAPON.LinkTo(	scriptObject, "WEAPON_LOWERWEAPON" );
    486 
    487 	savefile->ReadObject( reinterpret_cast<idClass *&>( owner ) );
    488 	worldModel.Restore( savefile );
    489 
    490 	savefile->ReadInt( hideTime );
    491 	savefile->ReadFloat( hideDistance );
    492 	savefile->ReadInt( hideStartTime );
    493 	savefile->ReadFloat( hideStart );
    494 	savefile->ReadFloat( hideEnd );
    495 	savefile->ReadFloat( hideOffset );
    496 	savefile->ReadBool( hide );
    497 	savefile->ReadBool( disabled );
    498 
    499 	savefile->ReadInt( berserk );
    500 
    501 	savefile->ReadVec3( playerViewOrigin );
    502 	savefile->ReadMat3( playerViewAxis );
    503 
    504 	savefile->ReadVec3( viewWeaponOrigin );
    505 	savefile->ReadMat3( viewWeaponAxis );
    506 
    507 	savefile->ReadVec3( muzzleOrigin );
    508 	savefile->ReadMat3( muzzleAxis );
    509 
    510 	savefile->ReadVec3( pushVelocity );
    511 
    512 	idStr objectname;
    513 	savefile->ReadString( objectname );
    514 	weaponDef = gameLocal.FindEntityDef( objectname );
    515 	meleeDef = gameLocal.FindEntityDef( weaponDef->dict.GetString( "def_melee" ), false );
    516 
    517 	const idDeclEntityDef *projectileDef = gameLocal.FindEntityDef( weaponDef->dict.GetString( "def_projectile" ), false );
    518 	if ( projectileDef ) {
    519 		projectileDict = projectileDef->dict;
    520 	} else {
    521 		projectileDict.Clear();
    522 	}
    523 
    524 	const idDeclEntityDef *brassDef = gameLocal.FindEntityDef( weaponDef->dict.GetString( "def_ejectBrass" ), false );
    525 	if ( brassDef ) {
    526 		brassDict = brassDef->dict;
    527 	} else {
    528 		brassDict.Clear();
    529 	}
    530 
    531 	savefile->ReadFloat( meleeDistance );
    532 	savefile->ReadString( meleeDefName );
    533 	savefile->ReadInt( brassDelay );
    534 	savefile->ReadString( icon );
    535 	savefile->ReadString( pdaIcon );
    536 	savefile->ReadString( displayName );
    537 	savefile->ReadString( itemDesc );
    538 
    539 	savefile->ReadInt( guiLightHandle );
    540 	savefile->ReadRenderLight( guiLight );
    541 	if ( guiLightHandle >= 0 ) {
    542 		guiLightHandle = gameRenderWorld->AddLightDef( &guiLight );
    543 	}
    544 
    545 	savefile->ReadInt( muzzleFlashHandle );
    546 	savefile->ReadRenderLight( muzzleFlash );
    547 	if ( muzzleFlashHandle >= 0 ) {
    548 		muzzleFlashHandle = gameRenderWorld->AddLightDef( &muzzleFlash );
    549 	}
    550 
    551 	savefile->ReadInt( worldMuzzleFlashHandle );
    552 	savefile->ReadRenderLight( worldMuzzleFlash );
    553 	if ( worldMuzzleFlashHandle >= 0 ) {
    554 		worldMuzzleFlashHandle = gameRenderWorld->AddLightDef( &worldMuzzleFlash );
    555 	}
    556 
    557 	savefile->ReadVec3( flashColor );
    558 	savefile->ReadInt( muzzleFlashEnd );
    559 	savefile->ReadInt( flashTime );
    560 
    561 	savefile->ReadBool( lightOn );
    562 	savefile->ReadBool( silent_fire );
    563 
    564 	savefile->ReadInt( kick_endtime );
    565 	savefile->ReadInt( muzzle_kick_time );
    566 	savefile->ReadInt( muzzle_kick_maxtime );
    567 	savefile->ReadAngles( muzzle_kick_angles );
    568 	savefile->ReadVec3( muzzle_kick_offset );
    569 
    570 	savefile->ReadInt( (int &)ammoType );
    571 	savefile->ReadInt( ammoRequired );
    572 	savefile->ReadInt( clipSize );
    573 	
    574 	int savedAmmoClip = 0;
    575 	savefile->ReadInt( savedAmmoClip );
    576 	ammoClip = savedAmmoClip;
    577 
    578 	savefile->ReadInt( lowAmmo );
    579 	savefile->ReadBool( powerAmmo );
    580 
    581 	// savegame versions <= 17
    582 	int foo;
    583 	savefile->ReadInt( foo );
    584 
    585 	savefile->ReadInt( zoomFov );
    586 
    587 	savefile->ReadJoint( barrelJointView );
    588 	savefile->ReadJoint( flashJointView );
    589 	savefile->ReadJoint( ejectJointView );
    590 	savefile->ReadJoint( guiLightJointView );
    591 	savefile->ReadJoint( ventLightJointView );
    592 
    593 	savefile->ReadJoint( flashJointWorld );
    594 	savefile->ReadJoint( barrelJointWorld );
    595 	savefile->ReadJoint( ejectJointWorld );
    596 
    597 	savefile->ReadBool( hasBloodSplat );
    598 
    599 	savefile->ReadSoundShader( sndHum );
    600 
    601 	savefile->ReadParticle( weaponSmoke );
    602 	savefile->ReadInt( weaponSmokeStartTime );
    603 	savefile->ReadBool( continuousSmoke );
    604 	savefile->ReadParticle( strikeSmoke );
    605 	savefile->ReadInt( strikeSmokeStartTime );
    606 	savefile->ReadVec3( strikePos );
    607 	savefile->ReadMat3( strikeAxis );
    608 	savefile->ReadInt( nextStrikeFx );
    609 
    610 	savefile->ReadBool( nozzleFx );
    611 	savefile->ReadInt( nozzleFxFade );
    612 
    613 	savefile->ReadInt( lastAttack );
    614 
    615 	savefile->ReadInt( nozzleGlowHandle );
    616 	savefile->ReadRenderLight( nozzleGlow );
    617 	if ( nozzleGlowHandle >= 0 ) {
    618 		nozzleGlowHandle = gameRenderWorld->AddLightDef( &nozzleGlow );
    619 	}
    620 
    621 	savefile->ReadVec3( nozzleGlowColor );
    622 	savefile->ReadMaterial( nozzleGlowShader );
    623 	savefile->ReadFloat( nozzleGlowRadius );
    624 
    625 	savefile->ReadInt( weaponAngleOffsetAverages );
    626 	savefile->ReadFloat( weaponAngleOffsetScale );
    627 	savefile->ReadFloat( weaponAngleOffsetMax );
    628 	savefile->ReadFloat( weaponOffsetTime );
    629 	savefile->ReadFloat( weaponOffsetScale );
    630 
    631 	savefile->ReadBool( allowDrop );
    632 	savefile->ReadObject( reinterpret_cast<idClass *&>( projectileEnt ) );
    633 
    634 	savefile->ReadStaticObject( grabber );
    635 	savefile->ReadInt( grabberState );
    636 
    637 	savefile->ReadJoint ( smokeJointView );
    638 
    639 	int particleCount;
    640 	savefile->ReadInt( particleCount );
    641 	for(int i = 0; i < particleCount; i++) {
    642 		WeaponParticle_t newParticle;
    643 		memset(&newParticle, 0, sizeof(newParticle));
    644 
    645 		idStr name, particlename;
    646 		savefile->ReadString( name );
    647 		savefile->ReadString( particlename );
    648 
    649 		strcpy( newParticle.name, name.c_str() );
    650 		strcpy( newParticle.particlename, particlename.c_str() );
    651 
    652 		savefile->ReadBool( newParticle.active );
    653 		savefile->ReadInt( newParticle.startTime );
    654 		savefile->ReadJoint( newParticle.joint );
    655 		savefile->ReadBool( newParticle.smoke );
    656 		if(newParticle.smoke) {
    657 			newParticle.particle = static_cast<const idDeclParticle *>( declManager->FindType( DECL_PARTICLE, particlename, false ) );
    658 		} else {
    659 			savefile->ReadObject(reinterpret_cast<idClass *&>(newParticle.emitter));
    660 		}
    661 
    662 		weaponParticles.Set(newParticle.name, newParticle);
    663 	}
    664 
    665 	int lightCount;
    666 	savefile->ReadInt( lightCount );
    667 	for(int i = 0; i < lightCount; i++) {
    668 		WeaponLight_t newLight;
    669 		memset(&newLight, 0, sizeof(newLight));
    670 		
    671 		idStr name;
    672 		savefile->ReadString( name );
    673 		strcpy( newLight.name, name.c_str() );
    674 
    675 		savefile->ReadBool( newLight.active );
    676 		savefile->ReadInt( newLight.startTime );
    677 		savefile->ReadJoint( newLight.joint );
    678 		savefile->ReadInt( newLight.lightHandle );
    679 		savefile->ReadRenderLight( newLight.light );
    680 		if ( newLight.lightHandle >= 0 ) {
    681 			newLight.lightHandle = gameRenderWorld->AddLightDef( &newLight.light );
    682 		}
    683 		weaponLights.Set(newLight.name, newLight);
    684 	}
    685 }
    686 
    687 /***********************************************************************
    688 
    689 	Weapon definition management
    690 
    691 ***********************************************************************/
    692 
    693 /*
    694 ================
    695 idWeapon::Clear
    696 ================
    697 */
    698 void idWeapon::Clear() {
    699 	CancelEvents( &EV_Weapon_Clear );
    700 
    701 	DeconstructScriptObject();
    702 	scriptObject.Free();
    703 
    704 	WEAPON_ATTACK.Unlink();
    705 	WEAPON_RELOAD.Unlink();
    706 	WEAPON_NETRELOAD.Unlink();
    707 	WEAPON_NETENDRELOAD.Unlink();
    708 	WEAPON_NETFIRING.Unlink();
    709 	WEAPON_RAISEWEAPON.Unlink();
    710 	WEAPON_LOWERWEAPON.Unlink();
    711 
    712 	if ( muzzleFlashHandle != -1 ) {
    713 		gameRenderWorld->FreeLightDef( muzzleFlashHandle );
    714 		muzzleFlashHandle = -1;
    715 	}
    716 	if ( muzzleFlashHandle != -1 ) {
    717 		gameRenderWorld->FreeLightDef( muzzleFlashHandle );
    718 		muzzleFlashHandle = -1;
    719 	}
    720 	if ( worldMuzzleFlashHandle != -1 ) {
    721 		gameRenderWorld->FreeLightDef( worldMuzzleFlashHandle );
    722 		worldMuzzleFlashHandle = -1;
    723 	}
    724 	if ( guiLightHandle != -1 ) {
    725 		gameRenderWorld->FreeLightDef( guiLightHandle );
    726 		guiLightHandle = -1;
    727 	}
    728 	if ( nozzleGlowHandle != -1 ) {
    729 		gameRenderWorld->FreeLightDef( nozzleGlowHandle );
    730 		nozzleGlowHandle = -1;
    731 	}
    732 
    733 	memset( &renderEntity, 0, sizeof( renderEntity ) );
    734 	renderEntity.entityNum	= entityNumber;
    735 
    736 	renderEntity.noShadow		= true;
    737 	renderEntity.noSelfShadow	= true;
    738 	renderEntity.customSkin		= NULL;
    739 
    740 	// set default shader parms
    741 	renderEntity.shaderParms[ SHADERPARM_RED ]	= 1.0f;
    742 	renderEntity.shaderParms[ SHADERPARM_GREEN ]= 1.0f;
    743 	renderEntity.shaderParms[ SHADERPARM_BLUE ]	= 1.0f;
    744 	renderEntity.shaderParms[3] = 1.0f;
    745 	renderEntity.shaderParms[ SHADERPARM_TIMEOFFSET ] = 0.0f;
    746 	renderEntity.shaderParms[5] = 0.0f;
    747 	renderEntity.shaderParms[6] = 0.0f;
    748 	renderEntity.shaderParms[7] = 0.0f;
    749 
    750 	if ( refSound.referenceSound ) {
    751 		refSound.referenceSound->Free( true );
    752 	}
    753 	memset( &refSound, 0, sizeof( refSound_t ) );
    754 	
    755 	// setting diversity to 0 results in no random sound.  -1 indicates random.
    756 	refSound.diversity = -1.0f;
    757 
    758 	if ( owner ) {
    759 		// don't spatialize the weapon sounds
    760 		refSound.listenerId = owner->GetListenerId();
    761 	}
    762 
    763 	// clear out the sounds from our spawnargs since we'll copy them from the weapon def
    764 	const idKeyValue *kv = spawnArgs.MatchPrefix( "snd_" );
    765 	while( kv ) {
    766 		spawnArgs.Delete( kv->GetKey() );
    767 		kv = spawnArgs.MatchPrefix( "snd_" );
    768 	}
    769 
    770 	hideTime		= 300;
    771 	hideDistance	= -15.0f;
    772 	hideStartTime	= gameLocal.time - hideTime;
    773 	hideStart		= 0.0f;
    774 	hideEnd			= 0.0f;
    775 	hideOffset		= 0.0f;
    776 	hide			= false;
    777 	disabled		= false;
    778 
    779 	weaponSmoke		= NULL;
    780 	weaponSmokeStartTime = 0;
    781 	continuousSmoke = false;
    782 	strikeSmoke		= NULL;
    783 	strikeSmokeStartTime = 0;
    784 	strikePos.Zero();
    785 	strikeAxis = mat3_identity;
    786 	nextStrikeFx = 0;
    787 
    788 	icon			= "";
    789 	pdaIcon			= "";
    790 	displayName		= "";
    791 	itemDesc		= "";
    792 
    793 	playerViewAxis.Identity();
    794 	playerViewOrigin.Zero();
    795 	viewWeaponAxis.Identity();
    796 	viewWeaponOrigin.Zero();
    797 	muzzleAxis.Identity();
    798 	muzzleOrigin.Zero();
    799 	pushVelocity.Zero();
    800 
    801 	status			= WP_HOLSTERED;
    802 	state			= "";
    803 	idealState		= "";
    804 	animBlendFrames	= 0;
    805 	animDoneTime	= 0;
    806 
    807 	projectileDict.Clear();
    808 	meleeDef		= NULL;
    809 	meleeDefName	= "";
    810 	meleeDistance	= 0.0f;
    811 	brassDict.Clear();
    812 
    813 	flashTime		= 250;
    814 	lightOn			= false;
    815 	silent_fire		= false;
    816 
    817 	grabberState	= -1;
    818 	grabber.Update( owner, true );
    819 
    820 	ammoType		= 0;
    821 	ammoRequired	= 0;
    822 	ammoClip		= 0;
    823 	clipSize		= 0;
    824 	lowAmmo			= 0;
    825 	powerAmmo		= false;
    826 
    827 	kick_endtime		= 0;
    828 	muzzle_kick_time	= 0;
    829 	muzzle_kick_maxtime	= 0;
    830 	muzzle_kick_angles.Zero();
    831 	muzzle_kick_offset.Zero();
    832 
    833 	zoomFov = 90;
    834 
    835 	barrelJointView		= INVALID_JOINT;
    836 	flashJointView		= INVALID_JOINT;
    837 	ejectJointView		= INVALID_JOINT;
    838 	guiLightJointView	= INVALID_JOINT;
    839 	ventLightJointView	= INVALID_JOINT;
    840 
    841 	barrelJointWorld	= INVALID_JOINT;
    842 	flashJointWorld		= INVALID_JOINT;
    843 	ejectJointWorld		= INVALID_JOINT;
    844 
    845 	smokeJointView		= INVALID_JOINT;
    846 
    847 	//Clean up the weapon particles
    848 	for(int i = 0; i < weaponParticles.Num(); i++) {
    849 		WeaponParticle_t* part = weaponParticles.GetIndex(i);
    850 		if(!part->smoke) {
    851 			if ( part->emitter != NULL ) {
    852 				//Destroy the emitters
    853 				part->emitter->PostEventMS(&EV_Remove, 0 );
    854 			}
    855 		}
    856 	}
    857 	weaponParticles.Clear();
    858 
    859 	//Clean up the weapon lights
    860 	for(int i = 0; i < weaponLights.Num(); i++) {
    861 		WeaponLight_t* light = weaponLights.GetIndex(i);
    862 		if ( light->lightHandle != -1 ) {
    863 			gameRenderWorld->FreeLightDef( light->lightHandle );
    864 		}
    865 	}
    866 	weaponLights.Clear();
    867 
    868 	hasBloodSplat		= false;
    869 	nozzleFx			= false;
    870 	nozzleFxFade		= 1500;
    871 	lastAttack			= 0;
    872 	nozzleGlowHandle	= -1;
    873 	nozzleGlowShader	= NULL;
    874 	nozzleGlowRadius	= 10;
    875 	nozzleGlowColor.Zero();
    876 
    877 	weaponAngleOffsetAverages	= 0;
    878 	weaponAngleOffsetScale		= 0.0f;
    879 	weaponAngleOffsetMax		= 0.0f;
    880 	weaponOffsetTime			= 0.0f;
    881 	weaponOffsetScale			= 0.0f;
    882 
    883 	allowDrop			= true;
    884 
    885 	animator.ClearAllAnims( gameLocal.time, 0 );
    886 	FreeModelDef();
    887 
    888 	sndHum				= NULL;
    889 
    890 	isLinked			= false;
    891 	projectileEnt		= NULL;
    892 
    893 	isFiring			= false;
    894 }
    895 
    896 /*
    897 ================
    898 idWeapon::InitWorldModel
    899 ================
    900 */
    901 void idWeapon::InitWorldModel( const idDeclEntityDef *def ) {
    902 	idEntity *ent;
    903 
    904 	ent = worldModel.GetEntity();
    905 
    906 	assert( ent );
    907 	assert( def );
    908 
    909 	const char *model = def->dict.GetString( "model_world" );
    910 	const char *attach = def->dict.GetString( "joint_attach" );
    911 
    912 	ent->SetSkin( NULL );
    913 	if ( model[0] && attach[0] ) {
    914 		ent->Show();
    915 		ent->SetModel( model );
    916 		if ( ent->GetAnimator()->ModelDef() ) {
    917 			ent->SetSkin( ent->GetAnimator()->ModelDef()->GetDefaultSkin() );
    918 		}
    919 		ent->GetPhysics()->SetContents( 0 );
    920 		ent->GetPhysics()->SetClipModel( NULL, 1.0f );
    921 		ent->BindToJoint( owner, attach, true );
    922 		ent->GetPhysics()->SetOrigin( vec3_origin );
    923 		ent->GetPhysics()->SetAxis( mat3_identity );
    924 
    925 		// We don't want to interpolate the world model of weapons, let them
    926 		// just bind normally to the player's joint and be driven by the player's
    927 		// animation so that the weapon and the player don't appear out of sync.
    928 		ent->SetUseClientInterpolation( false );
    929 
    930 		// supress model in player views, but allow it in mirrors and remote views
    931 		renderEntity_t *worldModelRenderEntity = ent->GetRenderEntity();
    932 		if ( worldModelRenderEntity ) {
    933 			worldModelRenderEntity->suppressSurfaceInViewID = owner->entityNumber+1;
    934 			worldModelRenderEntity->suppressShadowInViewID = owner->entityNumber+1;
    935 			worldModelRenderEntity->suppressShadowInLightID = LIGHTID_VIEW_MUZZLE_FLASH + owner->entityNumber;
    936 		}
    937 	} else {
    938 		ent->SetModel( "" );
    939 		ent->Hide();
    940 	}
    941 
    942 	flashJointWorld = ent->GetAnimator()->GetJointHandle( "flash" );
    943 	barrelJointWorld = ent->GetAnimator()->GetJointHandle( "muzzle" );
    944 	ejectJointWorld = ent->GetAnimator()->GetJointHandle( "eject" );
    945 }
    946 
    947 /*
    948 ================
    949 idWeapon::GetWeaponDef
    950 ================
    951 */
    952 void idWeapon::GetWeaponDef( const char *objectname, int ammoinclip ) {
    953 	const char *shader;
    954 	const char *objectType;
    955 	const char *vmodel;
    956 	const char *guiName;
    957 	const char *projectileName;
    958 	const char *brassDefName;
    959 	const char *smokeName;
    960 	int			ammoAvail;
    961 
    962 	Clear();
    963 
    964 	if ( !objectname || !objectname[ 0 ] ) {
    965 		return;
    966 	}
    967 
    968 	assert( owner );
    969 
    970 	weaponDef			= gameLocal.FindEntityDef( objectname );
    971 
    972 	ammoType			= GetAmmoNumForName( weaponDef->dict.GetString( "ammoType" ) );
    973 	ammoRequired		= weaponDef->dict.GetInt( "ammoRequired" );
    974 	clipSize			= weaponDef->dict.GetInt( "clipSize" );
    975 	lowAmmo				= weaponDef->dict.GetInt( "lowAmmo" );
    976 
    977 	icon				= weaponDef->dict.GetString( "icon" );
    978 	pdaIcon				= weaponDef->dict.GetString( "pdaIcon" );
    979 	displayName			= weaponDef->dict.GetString( "display_name" );
    980 	itemDesc			= weaponDef->dict.GetString( "inv_desc" );
    981 
    982 	silent_fire			= weaponDef->dict.GetBool( "silent_fire" );
    983 	powerAmmo			= weaponDef->dict.GetBool( "powerAmmo" );
    984 
    985 	muzzle_kick_time	= SEC2MS( weaponDef->dict.GetFloat( "muzzle_kick_time" ) );
    986 	muzzle_kick_maxtime	= SEC2MS( weaponDef->dict.GetFloat( "muzzle_kick_maxtime" ) );
    987 	muzzle_kick_angles	= weaponDef->dict.GetAngles( "muzzle_kick_angles" );
    988 	muzzle_kick_offset	= weaponDef->dict.GetVector( "muzzle_kick_offset" );
    989 
    990 	hideTime			= SEC2MS( weaponDef->dict.GetFloat( "hide_time", "0.3" ) );
    991 	hideDistance		= weaponDef->dict.GetFloat( "hide_distance", "-15" );
    992 
    993 	// muzzle smoke
    994 	smokeName = weaponDef->dict.GetString( "smoke_muzzle" );
    995 	if ( *smokeName != '\0' ) {
    996 		weaponSmoke = static_cast<const idDeclParticle *>( declManager->FindType( DECL_PARTICLE, smokeName ) );
    997 	} else {
    998 		weaponSmoke = NULL;
    999 	}
   1000 	continuousSmoke = weaponDef->dict.GetBool( "continuousSmoke" );
   1001 	weaponSmokeStartTime = ( continuousSmoke ) ? gameLocal.time : 0;
   1002 
   1003 	smokeName = weaponDef->dict.GetString( "smoke_strike" );
   1004 	if ( *smokeName != '\0' ) {
   1005 		strikeSmoke = static_cast<const idDeclParticle *>( declManager->FindType( DECL_PARTICLE, smokeName ) );
   1006 	} else {
   1007 		strikeSmoke = NULL;
   1008 	}
   1009 	strikeSmokeStartTime = 0;
   1010 	strikePos.Zero();
   1011 	strikeAxis = mat3_identity;
   1012 	nextStrikeFx = 0;
   1013 
   1014 	// setup gui light
   1015 	memset( &guiLight, 0, sizeof( guiLight ) );
   1016 	const char *guiLightShader = weaponDef->dict.GetString( "mtr_guiLightShader" );
   1017 	if ( *guiLightShader != '\0' ) {
   1018 		guiLight.shader = declManager->FindMaterial( guiLightShader, false );
   1019 		guiLight.lightRadius[0] = guiLight.lightRadius[1] = guiLight.lightRadius[2] = 3;
   1020 		guiLight.pointLight = true;
   1021 	}
   1022 
   1023 	// setup the view model
   1024 	vmodel = weaponDef->dict.GetString( "model_view" );
   1025 	SetModel( vmodel );
   1026 
   1027 	// setup the world model
   1028 	InitWorldModel( weaponDef );
   1029 
   1030 	// copy the sounds from the weapon view model def into out spawnargs
   1031 	const idKeyValue *kv = weaponDef->dict.MatchPrefix( "snd_" );
   1032 	while( kv ) {
   1033 		spawnArgs.Set( kv->GetKey(), kv->GetValue() );
   1034 		kv = weaponDef->dict.MatchPrefix( "snd_", kv );
   1035 	}
   1036 
   1037 	// find some joints in the model for locating effects
   1038 	barrelJointView = animator.GetJointHandle( "barrel" );
   1039 	flashJointView = animator.GetJointHandle( "flash" );
   1040 	ejectJointView = animator.GetJointHandle( "eject" );
   1041 	guiLightJointView = animator.GetJointHandle( "guiLight" );
   1042 	ventLightJointView = animator.GetJointHandle( "ventLight" );
   1043 
   1044 	idStr smokeJoint = weaponDef->dict.GetString("smoke_joint");
   1045 	if(smokeJoint.Length() > 0) {
   1046 		smokeJointView = animator.GetJointHandle( smokeJoint );
   1047 	} else {
   1048 		smokeJointView = INVALID_JOINT;
   1049 	}
   1050 
   1051 	// get the projectile
   1052 	projectileDict.Clear();
   1053 
   1054 	projectileName = weaponDef->dict.GetString( "def_projectile" );
   1055 	if ( projectileName[0] != '\0' ) {
   1056 		const idDeclEntityDef *projectileDef = gameLocal.FindEntityDef( projectileName, false );
   1057 		if ( !projectileDef ) {
   1058 			gameLocal.Warning( "Unknown projectile '%s' in weapon '%s'", projectileName, objectname );
   1059 		} else {
   1060 			const char *spawnclass = projectileDef->dict.GetString( "spawnclass" );
   1061 			idTypeInfo *cls = idClass::GetClass( spawnclass );
   1062 			if ( !cls || !cls->IsType( idProjectile::Type ) ) {
   1063 				gameLocal.Warning( "Invalid spawnclass '%s' on projectile '%s' (used by weapon '%s')", spawnclass, projectileName, objectname );
   1064 			} else {
   1065 				projectileDict = projectileDef->dict;
   1066 			}
   1067 		}
   1068 	}
   1069 
   1070 	// set up muzzleflash render light
   1071 	const idMaterial*flashShader;
   1072 	idVec3			flashTarget;
   1073 	idVec3			flashUp;
   1074 	idVec3			flashRight;
   1075 	float			flashRadius;
   1076 	bool			flashPointLight;
   1077 
   1078 	weaponDef->dict.GetString( "mtr_flashShader", "", &shader );
   1079 	flashShader = declManager->FindMaterial( shader, false );
   1080 	flashPointLight = weaponDef->dict.GetBool( "flashPointLight", "1" );
   1081 	weaponDef->dict.GetVector( "flashColor", "0 0 0", flashColor );
   1082 	flashRadius		= (float)weaponDef->dict.GetInt( "flashRadius" );	// if 0, no light will spawn
   1083 	flashTime		= SEC2MS( weaponDef->dict.GetFloat( "flashTime", "0.25" ) );
   1084 	flashTarget		= weaponDef->dict.GetVector( "flashTarget" );
   1085 	flashUp			= weaponDef->dict.GetVector( "flashUp" );
   1086 	flashRight		= weaponDef->dict.GetVector( "flashRight" );
   1087 
   1088 	memset( &muzzleFlash, 0, sizeof( muzzleFlash ) );
   1089 	muzzleFlash.lightId = LIGHTID_VIEW_MUZZLE_FLASH + owner->entityNumber;
   1090 	muzzleFlash.allowLightInViewID = owner->entityNumber+1;
   1091 
   1092 	// the weapon lights will only be in first person
   1093 	guiLight.allowLightInViewID = owner->entityNumber+1;
   1094 	nozzleGlow.allowLightInViewID = owner->entityNumber+1;
   1095 
   1096 	muzzleFlash.pointLight								= flashPointLight;
   1097 	muzzleFlash.shader									= flashShader;
   1098 	muzzleFlash.shaderParms[ SHADERPARM_RED ]			= flashColor[0];
   1099 	muzzleFlash.shaderParms[ SHADERPARM_GREEN ]			= flashColor[1];
   1100 	muzzleFlash.shaderParms[ SHADERPARM_BLUE ]			= flashColor[2];
   1101 	muzzleFlash.shaderParms[ SHADERPARM_TIMESCALE ]		= 1.0f;
   1102 
   1103 	muzzleFlash.lightRadius[0]							= flashRadius;
   1104 	muzzleFlash.lightRadius[1]							= flashRadius;
   1105 	muzzleFlash.lightRadius[2]							= flashRadius;
   1106 
   1107 	if ( !flashPointLight ) {
   1108 		muzzleFlash.target								= flashTarget;
   1109 		muzzleFlash.up									= flashUp;
   1110 		muzzleFlash.right								= flashRight;
   1111 		muzzleFlash.end									= flashTarget;
   1112 	}
   1113 
   1114 	// the world muzzle flash is the same, just positioned differently
   1115 	worldMuzzleFlash = muzzleFlash;
   1116 	worldMuzzleFlash.suppressLightInViewID = owner->entityNumber+1;
   1117 	worldMuzzleFlash.allowLightInViewID = 0;
   1118 	worldMuzzleFlash.lightId = LIGHTID_WORLD_MUZZLE_FLASH + owner->entityNumber;
   1119 
   1120 	//-----------------------------------
   1121 
   1122 	nozzleFx			= weaponDef->dict.GetBool("nozzleFx");
   1123 	nozzleFxFade		= weaponDef->dict.GetInt("nozzleFxFade", "1500");
   1124 	nozzleGlowColor		= weaponDef->dict.GetVector("nozzleGlowColor", "1 1 1");
   1125 	nozzleGlowRadius	= weaponDef->dict.GetFloat("nozzleGlowRadius", "10");
   1126 	weaponDef->dict.GetString( "mtr_nozzleGlowShader", "", &shader );
   1127 	nozzleGlowShader = declManager->FindMaterial( shader, false );
   1128 
   1129 	// get the melee damage def
   1130 	meleeDistance = weaponDef->dict.GetFloat( "melee_distance" );
   1131 	meleeDefName = weaponDef->dict.GetString( "def_melee" );
   1132 	if ( meleeDefName.Length() ) {
   1133 		meleeDef = gameLocal.FindEntityDef( meleeDefName, false );
   1134 		if ( !meleeDef ) {
   1135 			gameLocal.Error( "Unknown melee '%s'", meleeDefName.c_str() );
   1136 		}
   1137 	}
   1138 
   1139 	// get the brass def
   1140 	brassDict.Clear();
   1141 	brassDelay = weaponDef->dict.GetInt( "ejectBrassDelay", "0" );
   1142 	brassDefName = weaponDef->dict.GetString( "def_ejectBrass" );
   1143 
   1144 	if ( brassDefName[0] ) {
   1145 		const idDeclEntityDef *brassDef = gameLocal.FindEntityDef( brassDefName, false );
   1146 		if ( !brassDef ) {
   1147 			gameLocal.Warning( "Unknown brass '%s'", brassDefName );
   1148 		} else {
   1149 			brassDict = brassDef->dict;
   1150 		}
   1151 	}
   1152 
   1153 	if ( ( ammoType < 0 ) || ( ammoType >= AMMO_NUMTYPES ) ) {
   1154 		gameLocal.Warning( "Unknown ammotype in object '%s'", objectname );
   1155 	}
   1156 
   1157 	ammoClip = ammoinclip;
   1158 	if ( ( ammoClip.Get() < 0 ) || ( ammoClip.Get() > clipSize ) ) {
   1159 		// first time using this weapon so have it fully loaded to start
   1160 		ammoClip = clipSize;
   1161 		ammoAvail = owner->inventory.HasAmmo( ammoType, ammoRequired );
   1162 		if ( ammoClip.Get() > ammoAvail ) {
   1163 			ammoClip = ammoAvail;
   1164 		}
   1165 		//In D3XP we use ammo as soon as it is moved into the clip. This allows for weapons that share ammo
   1166 		owner->inventory.UseAmmo( ammoType, ammoClip.Get() );
   1167 	}
   1168 
   1169 	renderEntity.gui[ 0 ] = NULL;
   1170 	guiName = weaponDef->dict.GetString( "gui" );
   1171 	if ( guiName[0] ) {
   1172 		renderEntity.gui[ 0 ] = uiManager->FindGui( guiName, true, false, true );
   1173 	}
   1174 
   1175 	zoomFov = weaponDef->dict.GetInt( "zoomFov", "70" );
   1176 	berserk = weaponDef->dict.GetInt( "berserk", "2" );
   1177 
   1178 	weaponAngleOffsetAverages = weaponDef->dict.GetInt( "weaponAngleOffsetAverages", "10" );
   1179 	weaponAngleOffsetScale = weaponDef->dict.GetFloat( "weaponAngleOffsetScale", "0.25" );
   1180 	weaponAngleOffsetMax = weaponDef->dict.GetFloat( "weaponAngleOffsetMax", "10" );
   1181 
   1182 	weaponOffsetTime = weaponDef->dict.GetFloat( "weaponOffsetTime", "400" );
   1183 	weaponOffsetScale = weaponDef->dict.GetFloat( "weaponOffsetScale", "0.005" );
   1184 
   1185 	if ( !weaponDef->dict.GetString( "weapon_scriptobject", NULL, &objectType ) ) {
   1186 		gameLocal.Error( "No 'weapon_scriptobject' set on '%s'.", objectname );
   1187 	}
   1188 	
   1189 	// setup script object
   1190 	if ( !scriptObject.SetType( objectType ) ) {
   1191 		gameLocal.Error( "Script object '%s' not found on weapon '%s'.", objectType, objectname );
   1192 	}
   1193 
   1194 	WEAPON_ATTACK.LinkTo(		scriptObject, "WEAPON_ATTACK" );
   1195 	WEAPON_RELOAD.LinkTo(		scriptObject, "WEAPON_RELOAD" );
   1196 	WEAPON_NETRELOAD.LinkTo(	scriptObject, "WEAPON_NETRELOAD" );
   1197 	WEAPON_NETENDRELOAD.LinkTo(	scriptObject, "WEAPON_NETENDRELOAD" );
   1198 	WEAPON_NETFIRING.LinkTo(	scriptObject, "WEAPON_NETFIRING" );
   1199 	WEAPON_RAISEWEAPON.LinkTo(	scriptObject, "WEAPON_RAISEWEAPON" );
   1200 	WEAPON_LOWERWEAPON.LinkTo(	scriptObject, "WEAPON_LOWERWEAPON" );
   1201 
   1202 	spawnArgs = weaponDef->dict;
   1203 
   1204 	shader = spawnArgs.GetString( "snd_hum" );
   1205 	if ( shader && *shader ) {
   1206 		sndHum = declManager->FindSound( shader );
   1207 		StartSoundShader( sndHum, SND_CHANNEL_BODY, 0, false, NULL );
   1208 	}
   1209 
   1210 	isLinked = true;
   1211 
   1212 	// call script object's constructor
   1213 	ConstructScriptObject();
   1214 
   1215 	// make sure we have the correct skin
   1216 	UpdateSkin();
   1217 
   1218 	idEntity *ent = worldModel.GetEntity();
   1219 	DetermineTimeGroup( weaponDef->dict.GetBool( "slowmo", "0" ) );
   1220 	if ( ent ) {
   1221 		ent->DetermineTimeGroup( weaponDef->dict.GetBool( "slowmo", "0" ) );
   1222 	}
   1223 
   1224 	//Initialize the particles
   1225 	if ( !common->IsMultiplayer() ) {
   1226 
   1227 		const idKeyValue *pkv = weaponDef->dict.MatchPrefix( "weapon_particle", NULL );
   1228 		while( pkv ) {
   1229 			WeaponParticle_t newParticle;
   1230 			memset( &newParticle, 0, sizeof( newParticle ) );
   1231 
   1232 			idStr name = pkv->GetValue();
   1233 
   1234 			strcpy(newParticle.name, name.c_str());
   1235 
   1236 			idStr jointName = weaponDef->dict.GetString(va("%s_joint", name.c_str()));
   1237 			newParticle.joint = animator.GetJointHandle(jointName.c_str());
   1238 			newParticle.smoke = weaponDef->dict.GetBool(va("%s_smoke", name.c_str()));
   1239 			newParticle.active = false;
   1240 			newParticle.startTime = 0;
   1241 
   1242 			idStr particle = weaponDef->dict.GetString(va("%s_particle", name.c_str()));
   1243 			strcpy(newParticle.particlename, particle.c_str());
   1244 
   1245 			if(newParticle.smoke) {
   1246 				newParticle.particle = static_cast<const idDeclParticle *>( declManager->FindType( DECL_PARTICLE, particle, false ) );
   1247 			} else {
   1248 				idDict args;
   1249 
   1250 				const idDeclEntityDef *emitterDef = gameLocal.FindEntityDef( "func_emitter", false );
   1251 				args = emitterDef->dict;
   1252 				args.Set("model", particle.c_str());
   1253 				args.SetBool("start_off", true);
   1254 
   1255 				idEntity* ent;
   1256 				gameLocal.SpawnEntityDef(args, &ent, false);
   1257 				newParticle.emitter = (idFuncEmitter*)ent;
   1258 
   1259 				if ( newParticle.emitter != NULL ) {
   1260 					newParticle.emitter->BecomeActive(TH_THINK);
   1261 				}
   1262 			}
   1263 
   1264 			weaponParticles.Set(name.c_str(), newParticle);
   1265 
   1266 			pkv = weaponDef->dict.MatchPrefix( "weapon_particle", pkv );
   1267 		}
   1268 
   1269 		const idKeyValue *lkv = weaponDef->dict.MatchPrefix( "weapon_light", NULL );
   1270 		while( lkv ) {
   1271 			WeaponLight_t newLight;
   1272 			memset( &newLight, 0, sizeof( newLight ) );
   1273 
   1274 			newLight.lightHandle = -1;
   1275 			newLight.active = false;
   1276 			newLight.startTime = 0;
   1277 
   1278 			idStr name = lkv->GetValue();
   1279 			strcpy(newLight.name, name.c_str());
   1280 
   1281 			idStr jointName = weaponDef->dict.GetString(va("%s_joint", name.c_str()));
   1282 			newLight.joint = animator.GetJointHandle(jointName.c_str());
   1283 
   1284 			idStr shader = weaponDef->dict.GetString(va("%s_shader", name.c_str()));
   1285 			newLight.light.shader = declManager->FindMaterial( shader, false );
   1286 
   1287 			float radius = weaponDef->dict.GetFloat(va("%s_radius", name.c_str()));
   1288 			newLight.light.lightRadius[0] = newLight.light.lightRadius[1] = newLight.light.lightRadius[2] = radius;
   1289 			newLight.light.pointLight = true;
   1290 			newLight.light.noShadows = true;
   1291 
   1292 			newLight.light.allowLightInViewID = owner->entityNumber+1;
   1293 
   1294 			weaponLights.Set(name.c_str(), newLight);
   1295 
   1296 			lkv = weaponDef->dict.MatchPrefix( "weapon_light", lkv );
   1297 		}
   1298 	}
   1299 }
   1300 
   1301 /***********************************************************************
   1302 
   1303 	GUIs
   1304 
   1305 ***********************************************************************/
   1306 
   1307 /*
   1308 ================
   1309 idWeapon::Icon
   1310 ================
   1311 */
   1312 const char *idWeapon::Icon() const {
   1313 	return icon;
   1314 }
   1315 
   1316 /*
   1317 ================
   1318 idWeapon::PdaIcon
   1319 ================
   1320 */
   1321 const char *idWeapon::PdaIcon() const {
   1322 	return pdaIcon;
   1323 }
   1324 
   1325 /*
   1326 ================
   1327 idWeapon::DisplayName
   1328 ================
   1329 */
   1330 const char * idWeapon::DisplayName() const {
   1331 	return idLocalization::GetString( displayName );
   1332 }
   1333 
   1334 /*
   1335 ================
   1336 idWeapon::Description
   1337 ================
   1338 */
   1339 const char * idWeapon::Description() const {
   1340 	return idLocalization::GetString( itemDesc );
   1341 }
   1342 
   1343 /*
   1344 ================
   1345 idWeapon::UpdateGUI
   1346 ================
   1347 */
   1348 void idWeapon::UpdateGUI() {
   1349 	if ( !renderEntity.gui[ 0 ] ) {
   1350 		return;
   1351 	}
   1352 	
   1353 	if ( status == WP_HOLSTERED ) {
   1354 		return;
   1355 	}
   1356 
   1357 	if ( owner->weaponGone ) {
   1358 		// dropping weapons was implemented wierd, so we have to not update the gui when it happens or we'll get a negative ammo count
   1359 		return;
   1360 	}
   1361 
   1362 	if ( !owner->IsLocallyControlled() ) {
   1363 		// if updating the hud for a followed client
   1364 		if ( gameLocal.GetLocalClientNum() >= 0 && gameLocal.entities[ gameLocal.GetLocalClientNum() ] && gameLocal.entities[ gameLocal.GetLocalClientNum() ]->IsType( idPlayer::Type ) ) {
   1365 			idPlayer *p = static_cast< idPlayer * >( gameLocal.entities[ gameLocal.GetLocalClientNum() ] );
   1366 			if ( !p->spectating || p->spectator != owner->entityNumber ) {
   1367 				return;
   1368 			}
   1369 		} else {
   1370 			return;
   1371 		}
   1372 	}
   1373 
   1374 	int inclip = AmmoInClip();
   1375 	int ammoamount = AmmoAvailable();
   1376 
   1377 	if ( ammoamount < 0 ) {
   1378 		// show infinite ammo
   1379 		renderEntity.gui[ 0 ]->SetStateString( "player_ammo", "" );
   1380 	} else {
   1381 		// show remaining ammo
   1382 		renderEntity.gui[ 0 ]->SetStateString( "player_totalammo", va( "%i", ammoamount) );
   1383 		renderEntity.gui[ 0 ]->SetStateString( "player_ammo", ClipSize() ? va( "%i", inclip ) : "--" );
   1384 		renderEntity.gui[ 0 ]->SetStateString( "player_clips", ClipSize() ? va("%i", ammoamount / ClipSize()) : "--" );
   1385 
   1386 		renderEntity.gui[ 0 ]->SetStateString( "player_allammo", va( "%i/%i", inclip, ammoamount ) );
   1387 	}
   1388 	renderEntity.gui[ 0 ]->SetStateBool( "player_ammo_empty", ( ammoamount == 0 ) );
   1389 	renderEntity.gui[ 0 ]->SetStateBool( "player_clip_empty", ( inclip == 0 ) );
   1390 	renderEntity.gui[ 0 ]->SetStateBool( "player_clip_low", ( inclip <= lowAmmo ) );
   1391 
   1392 	//Let the HUD know the total amount of ammo regardless of the ammo required value
   1393 	renderEntity.gui[ 0 ]->SetStateString( "player_ammo_count", va("%i", AmmoCount()));
   1394 
   1395 	//Grabber Gui Info
   1396 	renderEntity.gui[ 0 ]->SetStateString( "grabber_state", va("%i", grabberState));
   1397 }
   1398 
   1399 /***********************************************************************
   1400 
   1401 	Model and muzzleflash
   1402 
   1403 ***********************************************************************/
   1404 
   1405 /*
   1406 ================
   1407 idWeapon::UpdateFlashPosition
   1408 ================
   1409 */
   1410 void idWeapon::UpdateFlashPosition() {
   1411 	// the flash has an explicit joint for locating it
   1412 	GetGlobalJointTransform( true, flashJointView, muzzleFlash.origin, muzzleFlash.axis );
   1413 
   1414 	if ( isPlayerFlashlight ) {
   1415 		static float pscale = 2.0f;
   1416 		static float yscale = 0.25f;
   1417 
   1418 // 		static idVec3 baseAdjustPos = vec3_zero;	//idVec3( 0.0f, 10.0f, 0.0f );
   1419 // 		idVec3 adjustPos = baseAdjustPos;
   1420 //		muzzleFlash.origin += adjustPos.x * muzzleFlash.axis[1] + adjustPos.y * muzzleFlash.axis[0] + adjustPos.z * muzzleFlash.axis[2];
   1421  		muzzleFlash.origin += owner->GetViewBob();
   1422 
   1423 //		static idAngles baseAdjustAng = ang_zero;	//idAngles( 0.0f, 10.0f, 0.0f );
   1424 		idAngles adjustAng = /*baseAdjustAng +*/ idAngles( fraccos * yscale, 0.0f, fraccos2 * pscale );
   1425 		idAngles bobAngles = owner->GetViewBobAngles();
   1426 		SwapValues( bobAngles.pitch, bobAngles.roll );
   1427 		adjustAng += bobAngles * 3.0f;
   1428 		muzzleFlash.axis = adjustAng.ToMat3() * muzzleFlash.axis /** adjustAng.ToMat3()*/;
   1429 	}
   1430 
   1431 	// if the desired point is inside or very close to a wall, back it up until it is clear
   1432 	idVec3	start = muzzleFlash.origin - playerViewAxis[0] * 16;
   1433 	idVec3	end = muzzleFlash.origin + playerViewAxis[0] * 8;
   1434 	trace_t	tr;
   1435 	gameLocal.clip.TracePoint( tr, start, end, MASK_SHOT_RENDERMODEL, owner );
   1436 	// be at least 8 units away from a solid
   1437 	muzzleFlash.origin = tr.endpos - playerViewAxis[0] * 8;
   1438 
   1439 	muzzleFlash.noShadows = !g_weaponShadows.GetBool();
   1440 
   1441 	// put the world muzzle flash on the end of the joint, no matter what
   1442 	GetGlobalJointTransform( false, flashJointWorld, worldMuzzleFlash.origin, worldMuzzleFlash.axis );
   1443 }
   1444 
   1445 /*
   1446 ================
   1447 idWeapon::MuzzleFlashLight
   1448 ================
   1449 */
   1450 void idWeapon::MuzzleFlashLight() {
   1451 	
   1452 	if ( !lightOn && ( !g_muzzleFlash.GetBool() || !muzzleFlash.lightRadius[0] ) ) {
   1453 		return;
   1454 	}
   1455 
   1456 	if ( flashJointView == INVALID_JOINT ) {
   1457 		return;
   1458 	}
   1459 
   1460 	UpdateFlashPosition();
   1461 
   1462 	// these will be different each fire
   1463 	muzzleFlash.shaderParms[ SHADERPARM_TIMEOFFSET ]	= -MS2SEC( gameLocal.time );
   1464 	muzzleFlash.shaderParms[ SHADERPARM_DIVERSITY ]		= renderEntity.shaderParms[ SHADERPARM_DIVERSITY ];
   1465 
   1466 	worldMuzzleFlash.shaderParms[ SHADERPARM_TIMEOFFSET ]	= -MS2SEC( gameLocal.time );
   1467 	worldMuzzleFlash.shaderParms[ SHADERPARM_DIVERSITY ]	= renderEntity.shaderParms[ SHADERPARM_DIVERSITY ];
   1468 
   1469 	// the light will be removed at this time
   1470 	muzzleFlashEnd = gameLocal.time + flashTime;
   1471 
   1472 	if ( muzzleFlashHandle != -1 ) {
   1473 		gameRenderWorld->UpdateLightDef( muzzleFlashHandle, &muzzleFlash );
   1474 		gameRenderWorld->UpdateLightDef( worldMuzzleFlashHandle, &worldMuzzleFlash );
   1475 	} else {
   1476 		muzzleFlashHandle = gameRenderWorld->AddLightDef( &muzzleFlash );
   1477 		worldMuzzleFlashHandle = gameRenderWorld->AddLightDef( &worldMuzzleFlash );
   1478 	}
   1479 }
   1480 
   1481 /*
   1482 ================
   1483 idWeapon::UpdateSkin
   1484 ================
   1485 */
   1486 bool idWeapon::UpdateSkin() {
   1487 	const function_t *func;
   1488 
   1489 	if ( !isLinked ) {
   1490 		return false;
   1491 	}
   1492 
   1493 	func = scriptObject.GetFunction( "UpdateSkin" );
   1494 	if ( !func ) {
   1495 		common->Warning( "Can't find function 'UpdateSkin' in object '%s'", scriptObject.GetTypeName() );
   1496 		return false;
   1497 	}
   1498 	
   1499 	// use the frameCommandThread since it's safe to use outside of framecommands
   1500 	gameLocal.frameCommandThread->CallFunction( this, func, true );
   1501 	gameLocal.frameCommandThread->Execute();
   1502 
   1503 	return true;
   1504 }
   1505 
   1506 
   1507 /*
   1508 ================
   1509 idWeapon::FlashlightOn
   1510 ================
   1511 */
   1512 void idWeapon::FlashlightOn() {
   1513 	const function_t *func;
   1514 
   1515 	if ( !isLinked ) {
   1516 		return;
   1517 	}
   1518 
   1519 	func = scriptObject.GetFunction( "TurnOn" );
   1520 	if ( !func ) {
   1521 		common->Warning( "Can't find function 'TurnOn' in object '%s'", scriptObject.GetTypeName() );
   1522 		return;
   1523 	}
   1524 
   1525 	// use the frameCommandThread since it's safe to use outside of framecommands
   1526 	gameLocal.frameCommandThread->CallFunction( this, func, true );
   1527 	gameLocal.frameCommandThread->Execute();
   1528 
   1529 	return;
   1530 }
   1531 
   1532 
   1533 /*
   1534 ================
   1535 idWeapon::FlashlightOff
   1536 ================
   1537 */
   1538 void idWeapon::FlashlightOff() {
   1539 	const function_t *func;
   1540 
   1541 	if ( !isLinked ) {
   1542 		return;
   1543 	}
   1544 
   1545 	func = scriptObject.GetFunction( "TurnOff" );
   1546 	if ( !func ) {
   1547 		common->Warning( "Can't find function 'TurnOff' in object '%s'", scriptObject.GetTypeName() );
   1548 		return;
   1549 	}
   1550 
   1551 	// use the frameCommandThread since it's safe to use outside of framecommands
   1552 	gameLocal.frameCommandThread->CallFunction( this, func, true );
   1553 	gameLocal.frameCommandThread->Execute();
   1554 
   1555 	return;
   1556 }
   1557 
   1558 /*
   1559 ================
   1560 idWeapon::SetModel
   1561 ================
   1562 */
   1563 void idWeapon::SetModel( const char *modelname ) {
   1564 	assert( modelname );
   1565 
   1566 	if ( modelDefHandle >= 0 ) {
   1567 		gameRenderWorld->RemoveDecals( modelDefHandle );
   1568 	}
   1569 
   1570 	renderEntity.hModel = animator.SetModel( modelname );
   1571 	if ( renderEntity.hModel ) {
   1572 		renderEntity.customSkin = animator.ModelDef()->GetDefaultSkin();
   1573 		animator.GetJoints( &renderEntity.numJoints, &renderEntity.joints );
   1574 	} else {
   1575 		renderEntity.customSkin = NULL;
   1576 		renderEntity.callback = NULL;
   1577 		renderEntity.numJoints = 0;
   1578 		renderEntity.joints = NULL;
   1579 	}
   1580 
   1581 	// hide the model until an animation is played
   1582 	Hide();
   1583 }
   1584 
   1585 /*
   1586 ================
   1587 idWeapon::GetGlobalJointTransform
   1588 
   1589 This returns the offset and axis of a weapon bone in world space, suitable for attaching models or lights
   1590 ================
   1591 */
   1592 bool idWeapon::GetGlobalJointTransform( bool viewModel, const jointHandle_t jointHandle, idVec3 &offset, idMat3 &axis ) {
   1593 	if ( viewModel ) {
   1594 		// view model
   1595 		if ( animator.GetJointTransform( jointHandle, gameLocal.time, offset, axis ) ) {
   1596 			offset = offset * viewWeaponAxis + viewWeaponOrigin;
   1597 			axis = axis * viewWeaponAxis;
   1598 			return true;
   1599 		}
   1600 	} else {
   1601 		// world model
   1602 		if ( worldModel.GetEntity() && worldModel.GetEntity()->GetAnimator()->GetJointTransform( jointHandle, gameLocal.time, offset, axis ) ) {
   1603 			offset = worldModel.GetEntity()->GetPhysics()->GetOrigin() + offset * worldModel.GetEntity()->GetPhysics()->GetAxis();
   1604 			axis = axis * worldModel.GetEntity()->GetPhysics()->GetAxis();
   1605 			return true;
   1606 		}
   1607 	}
   1608 	offset = viewWeaponOrigin;
   1609 	axis = viewWeaponAxis;
   1610 	return false;
   1611 }
   1612 
   1613 /*
   1614 ================
   1615 idWeapon::SetPushVelocity
   1616 ================
   1617 */
   1618 void idWeapon::SetPushVelocity( const idVec3 &pushVelocity ) {
   1619 	this->pushVelocity = pushVelocity;
   1620 }
   1621 
   1622 
   1623 /***********************************************************************
   1624 
   1625 	State control/player interface
   1626 
   1627 ***********************************************************************/
   1628 
   1629 /*
   1630 ================
   1631 idWeapon::Think
   1632 ================
   1633 */
   1634 void idWeapon::Think() {
   1635 	// do nothing because the present is called from the player through PresentWeapon
   1636 }
   1637 
   1638 /*
   1639 ================
   1640 idWeapon::Raise
   1641 ================
   1642 */
   1643 void idWeapon::Raise() {
   1644 	if ( isLinked ) {
   1645 		WEAPON_RAISEWEAPON = true;
   1646 	}
   1647 }
   1648 
   1649 /*
   1650 ================
   1651 idWeapon::PutAway
   1652 ================
   1653 */
   1654 void idWeapon::PutAway() {
   1655 	hasBloodSplat = false;
   1656 	if ( isLinked ) {
   1657 		WEAPON_LOWERWEAPON = true;
   1658 	}
   1659 }
   1660 
   1661 /*
   1662 ================
   1663 idWeapon::Reload
   1664 NOTE: this is only for impulse-triggered reload, auto reload is scripted
   1665 ================
   1666 */
   1667 void idWeapon::Reload() {
   1668 	if ( isLinked ) {
   1669 		WEAPON_RELOAD = true;
   1670 	}
   1671 }
   1672 
   1673 /*
   1674 ================
   1675 idWeapon::LowerWeapon
   1676 ================
   1677 */
   1678 void idWeapon::LowerWeapon() {
   1679 	if ( !hide ) {
   1680 		hideStart	= 0.0f;
   1681 		hideEnd		= hideDistance;
   1682 		if ( gameLocal.time - hideStartTime < hideTime ) {
   1683 			hideStartTime = gameLocal.time - ( hideTime - ( gameLocal.time - hideStartTime ) );
   1684 		} else {
   1685 			hideStartTime = gameLocal.time;
   1686 		}
   1687 		hide = true;
   1688 	}
   1689 }
   1690 
   1691 /*
   1692 ================
   1693 idWeapon::RaiseWeapon
   1694 ================
   1695 */
   1696 void idWeapon::RaiseWeapon() {
   1697 	Show();
   1698 
   1699 	if ( hide ) {
   1700 		hideStart	= hideDistance;
   1701 		hideEnd		= 0.0f;
   1702 		if ( gameLocal.time - hideStartTime < hideTime ) {
   1703 			hideStartTime = gameLocal.time - ( hideTime - ( gameLocal.time - hideStartTime ) );
   1704 		} else {
   1705 			hideStartTime = gameLocal.time;
   1706 		}
   1707 		hide = false;
   1708 	}
   1709 }
   1710 
   1711 /*
   1712 ================
   1713 idWeapon::HideWeapon
   1714 ================
   1715 */
   1716 void idWeapon::HideWeapon() {
   1717 	Hide();
   1718 	if ( worldModel.GetEntity() ) {
   1719 		worldModel.GetEntity()->Hide();
   1720 	}
   1721 	muzzleFlashEnd = 0;
   1722 }
   1723 
   1724 /*
   1725 ================
   1726 idWeapon::ShowWeapon
   1727 ================
   1728 */
   1729 void idWeapon::ShowWeapon() {
   1730 	Show();
   1731 	if ( worldModel.GetEntity() ) {
   1732 		worldModel.GetEntity()->Show();
   1733 	}
   1734 	if ( lightOn ) {
   1735 		MuzzleFlashLight();
   1736 	}
   1737 }
   1738 
   1739 /*
   1740 ================
   1741 idWeapon::HideWorldModel
   1742 ================
   1743 */
   1744 void idWeapon::HideWorldModel() {
   1745 	if ( worldModel.GetEntity() ) {
   1746 		worldModel.GetEntity()->Hide();
   1747 	}
   1748 }
   1749 
   1750 /*
   1751 ================
   1752 idWeapon::ShowWorldModel
   1753 ================
   1754 */
   1755 void idWeapon::ShowWorldModel() {
   1756 	if ( worldModel.GetEntity() ) {
   1757 		worldModel.GetEntity()->Show();
   1758 	}
   1759 }
   1760 
   1761 /*
   1762 ================
   1763 idWeapon::OwnerDied
   1764 ================
   1765 */
   1766 void idWeapon::OwnerDied() {
   1767 	if ( isLinked ) {
   1768 		SetState( "OwnerDied", 0 );
   1769 		thread->Execute();
   1770 
   1771 		// Update the grabber effects
   1772 		if ( /*!common->IsMultiplayer() &&*/ grabberState != -1 ) {
   1773 			grabber.Update( owner, hide );
   1774 		}
   1775 	}
   1776 
   1777 	Hide();
   1778 	if ( worldModel.GetEntity() ) {
   1779 		worldModel.GetEntity()->Hide();
   1780 	}
   1781 
   1782 	// don't clear the weapon immediately since the owner might have killed himself by firing the weapon
   1783 	// within the current stack frame
   1784 	PostEventMS( &EV_Weapon_Clear, 0 );
   1785 }
   1786 
   1787 /*
   1788 ================
   1789 idWeapon::BeginAttack
   1790 ================
   1791 */
   1792 void idWeapon::BeginAttack() {	
   1793 	if ( status != WP_OUTOFAMMO ) {
   1794 		lastAttack = gameLocal.time;
   1795 	}
   1796 
   1797 	if ( !isLinked ) {
   1798 		return;
   1799 	}
   1800 
   1801 	if ( !WEAPON_ATTACK ) {
   1802 		if ( sndHum && grabberState == -1 ) {	// _D3XP :: don't stop grabber hum
   1803 			StopSound( SND_CHANNEL_BODY, false );
   1804 		}
   1805 	}
   1806 	WEAPON_ATTACK = true;
   1807 }
   1808 
   1809 /*
   1810 ================
   1811 idWeapon::EndAttack
   1812 ================
   1813 */
   1814 void idWeapon::EndAttack() {
   1815 	if ( !WEAPON_ATTACK.IsLinked() ) {
   1816 		return;
   1817 	}
   1818 	if ( WEAPON_ATTACK ) {
   1819 		WEAPON_ATTACK = false;
   1820 		if ( sndHum && grabberState == -1 ) {	// _D3XP :: don't stop grabber hum
   1821 			StartSoundShader( sndHum, SND_CHANNEL_BODY, 0, false, NULL );
   1822 		}
   1823 	}
   1824 }
   1825 
   1826 /*
   1827 ================
   1828 idWeapon::isReady
   1829 ================
   1830 */
   1831 bool idWeapon::IsReady() const {
   1832 	return !hide && !IsHidden() && ( ( status == WP_RELOAD ) || ( status == WP_READY ) || ( status == WP_OUTOFAMMO ) );
   1833 }
   1834 
   1835 /*
   1836 ================
   1837 idWeapon::IsReloading
   1838 ================
   1839 */
   1840 bool idWeapon::IsReloading() const {
   1841 	return ( status == WP_RELOAD );
   1842 }
   1843 
   1844 /*
   1845 ================
   1846 idWeapon::IsHolstered
   1847 ================
   1848 */
   1849 bool idWeapon::IsHolstered() const {
   1850 	return ( status == WP_HOLSTERED );
   1851 }
   1852 
   1853 /*
   1854 ================
   1855 idWeapon::ShowCrosshair
   1856 ================
   1857 */
   1858 bool idWeapon::ShowCrosshair() const {
   1859 // JDC: this code would never function as written, I'm assuming they wanted the following behavior
   1860 //	return !( state == idStr( WP_RISING ) || state == idStr( WP_LOWERING ) || state == idStr( WP_HOLSTERED ) );
   1861 	return !( status == WP_RISING || status == WP_LOWERING || status == WP_HOLSTERED || status == WP_RELOAD );
   1862 }
   1863 
   1864 /*
   1865 =====================
   1866 idWeapon::CanDrop
   1867 =====================
   1868 */
   1869 bool idWeapon::CanDrop() const {
   1870 	if ( !weaponDef || !worldModel.GetEntity() ) {
   1871 		return false;
   1872 	}
   1873 	const char *classname = weaponDef->dict.GetString( "def_dropItem" );
   1874 	if ( !classname[ 0 ] ) {
   1875 		return false;
   1876 	}
   1877 	return true;
   1878 }
   1879 
   1880 /*
   1881 ================
   1882 idWeapon::WeaponStolen
   1883 ================
   1884 */
   1885 void idWeapon::WeaponStolen() {
   1886 	assert( !common->IsClient() );
   1887 	if ( projectileEnt ) {
   1888 		if ( isLinked ) {
   1889 			SetState( "WeaponStolen", 0 );
   1890 			thread->Execute();
   1891 		}
   1892 		projectileEnt = NULL;
   1893 	}
   1894 
   1895 	// set to holstered so we can switch weapons right away
   1896 	status = WP_HOLSTERED;
   1897 
   1898 	HideWeapon();
   1899 }
   1900 
   1901 /*
   1902 =====================
   1903 idWeapon::DropItem
   1904 =====================
   1905 */
   1906 idEntity * idWeapon::DropItem( const idVec3 &velocity, int activateDelay, int removeDelay, bool died ) {
   1907 	if ( !weaponDef || !worldModel.GetEntity() ) {
   1908 		return NULL;
   1909 	}
   1910 	if ( !allowDrop ) {
   1911 		return NULL;
   1912 	}
   1913 	const char *classname = weaponDef->dict.GetString( "def_dropItem" );
   1914 	if ( !classname[0] ) {
   1915 		return NULL;
   1916 	}
   1917 	StopSound( SND_CHANNEL_BODY, true );
   1918 	StopSound( SND_CHANNEL_BODY3, true );
   1919 
   1920 	return idMoveableItem::DropItem( classname, worldModel.GetEntity()->GetPhysics()->GetOrigin(), worldModel.GetEntity()->GetPhysics()->GetAxis(), velocity, activateDelay, removeDelay );
   1921 }
   1922 
   1923 /***********************************************************************
   1924 
   1925 	Script state management
   1926 
   1927 ***********************************************************************/
   1928 
   1929 /*
   1930 =====================
   1931 idWeapon::SetState
   1932 =====================
   1933 */
   1934 void idWeapon::SetState( const char *statename, int blendFrames ) {
   1935 	const function_t *func;
   1936 
   1937 	if ( !isLinked ) {
   1938 		return;
   1939 	}
   1940 
   1941 	func = scriptObject.GetFunction( statename );
   1942 	if ( !func ) {
   1943 		assert( 0 );
   1944 		gameLocal.Error( "Can't find function '%s' in object '%s'", statename, scriptObject.GetTypeName() );
   1945 	}
   1946 
   1947 	thread->CallFunction( this, func, true );
   1948 	state = statename;
   1949 
   1950 	animBlendFrames = blendFrames;
   1951 	if ( g_debugWeapon.GetBool() ) {
   1952 		gameLocal.Printf( "%d: weapon state : %s\n", gameLocal.time, statename );
   1953 	}
   1954 
   1955 	idealState = "";
   1956 }
   1957 
   1958 
   1959 /***********************************************************************
   1960 
   1961 	Particles/Effects
   1962 
   1963 ***********************************************************************/
   1964 
   1965 /*
   1966 ================
   1967 idWeapon::UpdateNozzelFx
   1968 ================
   1969 */
   1970 void idWeapon::UpdateNozzleFx() {
   1971 	if ( !nozzleFx ) {
   1972 		return;
   1973 	}
   1974 
   1975 	//
   1976 	// shader parms
   1977 	//
   1978 	int la = gameLocal.time - lastAttack + 1;
   1979 	float s = 1.0f;
   1980 	float l = 0.0f;
   1981 	if ( la < nozzleFxFade ) {
   1982 		s = ((float)la / nozzleFxFade);
   1983 		l = 1.0f - s;
   1984 	}
   1985 	renderEntity.shaderParms[5] = s;
   1986 	renderEntity.shaderParms[6] = l;
   1987 
   1988 	if ( ventLightJointView == INVALID_JOINT ) {
   1989 		return;
   1990 	}
   1991 
   1992 	//
   1993 	// vent light
   1994 	//
   1995 	if ( nozzleGlowHandle == -1 ) {
   1996 		memset(&nozzleGlow, 0, sizeof(nozzleGlow));
   1997 		if ( owner ) {
   1998 			nozzleGlow.allowLightInViewID = owner->entityNumber+1;
   1999 		}
   2000 		nozzleGlow.pointLight = true;
   2001 		nozzleGlow.noShadows = true;
   2002 		nozzleGlow.lightRadius.x = nozzleGlowRadius;
   2003 		nozzleGlow.lightRadius.y = nozzleGlowRadius;
   2004 		nozzleGlow.lightRadius.z = nozzleGlowRadius;
   2005 		nozzleGlow.shader = nozzleGlowShader;
   2006 		nozzleGlow.shaderParms[ SHADERPARM_TIMESCALE ]	= 1.0f;
   2007 		nozzleGlow.shaderParms[ SHADERPARM_TIMEOFFSET ]	= -MS2SEC( gameLocal.time );
   2008 		GetGlobalJointTransform( true, ventLightJointView, nozzleGlow.origin, nozzleGlow.axis );
   2009 		nozzleGlowHandle = gameRenderWorld->AddLightDef(&nozzleGlow);
   2010 	}
   2011 
   2012 	GetGlobalJointTransform( true, ventLightJointView, nozzleGlow.origin, nozzleGlow.axis );
   2013 
   2014 	nozzleGlow.shaderParms[ SHADERPARM_RED ] = nozzleGlowColor.x * s;
   2015 	nozzleGlow.shaderParms[ SHADERPARM_GREEN ] = nozzleGlowColor.y * s;
   2016 	nozzleGlow.shaderParms[ SHADERPARM_BLUE ] = nozzleGlowColor.z * s;
   2017 	gameRenderWorld->UpdateLightDef(nozzleGlowHandle, &nozzleGlow);
   2018 }
   2019 
   2020 
   2021 /*
   2022 ================
   2023 idWeapon::BloodSplat
   2024 ================
   2025 */
   2026 bool idWeapon::BloodSplat( float size ) {
   2027 	float s, c;
   2028 	idMat3 localAxis, axistemp;
   2029 	idVec3 localOrigin, normal;
   2030 
   2031 	if ( hasBloodSplat ) {
   2032 		return true;
   2033 	}
   2034 
   2035 	hasBloodSplat = true;
   2036 
   2037 	if ( modelDefHandle < 0 ) {
   2038 		return false;
   2039 	}
   2040 
   2041 	if ( !GetGlobalJointTransform( true, ejectJointView, localOrigin, localAxis ) ) {
   2042 		return false;
   2043 	}
   2044 
   2045 	localOrigin[0] += gameLocal.random.RandomFloat() * -10.0f;
   2046 	localOrigin[1] += gameLocal.random.RandomFloat() * 1.0f;
   2047 	localOrigin[2] += gameLocal.random.RandomFloat() * -2.0f;
   2048 
   2049 	normal = idVec3( gameLocal.random.CRandomFloat(), -gameLocal.random.RandomFloat(), -1 );
   2050 	normal.Normalize();
   2051 
   2052 	idMath::SinCos16( gameLocal.random.RandomFloat() * idMath::TWO_PI, s, c );
   2053 
   2054 	localAxis[2] = -normal;
   2055 	localAxis[2].NormalVectors( axistemp[0], axistemp[1] );
   2056 	localAxis[0] = axistemp[ 0 ] * c + axistemp[ 1 ] * -s;
   2057 	localAxis[1] = axistemp[ 0 ] * -s + axistemp[ 1 ] * -c;
   2058 
   2059 	localAxis[0] *= 1.0f / size;
   2060 	localAxis[1] *= 1.0f / size;
   2061 
   2062 	idPlane		localPlane[2];
   2063 
   2064 	localPlane[0] = localAxis[0];
   2065 	localPlane[0][3] = -(localOrigin * localAxis[0]) + 0.5f;
   2066 
   2067 	localPlane[1] = localAxis[1];
   2068 	localPlane[1][3] = -(localOrigin * localAxis[1]) + 0.5f;
   2069 
   2070 	const idMaterial *mtr = declManager->FindMaterial( "textures/decals/duffysplatgun" );
   2071 
   2072 	gameRenderWorld->ProjectOverlay( modelDefHandle, localPlane, mtr, gameLocal.slow.time );
   2073 
   2074 	return true;
   2075 }
   2076 
   2077 
   2078 /***********************************************************************
   2079 
   2080 	Visual presentation
   2081 
   2082 ***********************************************************************/
   2083 
   2084 /*
   2085 ================
   2086 idWeapon::MuzzleRise
   2087 
   2088 The machinegun and chaingun will incrementally back up as they are being fired
   2089 ================
   2090 */
   2091 void idWeapon::MuzzleRise( idVec3 &origin, idMat3 &axis ) {
   2092 	int			time;
   2093 	float		amount;
   2094 	idAngles	ang;
   2095 	idVec3		offset;
   2096 
   2097 	time = kick_endtime - gameLocal.time;
   2098 	if ( time <= 0 ) {
   2099 		return;
   2100 	}
   2101 
   2102 	if ( muzzle_kick_maxtime <= 0 ) {
   2103 		return;
   2104 	}
   2105 
   2106 	if ( time > muzzle_kick_maxtime ) {
   2107 		time = muzzle_kick_maxtime;
   2108 	}
   2109 	
   2110 	amount = ( float )time / ( float )muzzle_kick_maxtime;
   2111 	ang		= muzzle_kick_angles * amount;
   2112 	offset	= muzzle_kick_offset * amount;
   2113 
   2114 	origin = origin - axis * offset;
   2115 	axis = ang.ToMat3() * axis;
   2116 }
   2117 
   2118 /*
   2119 ================
   2120 idWeapon::ConstructScriptObject
   2121 
   2122 Called during idEntity::Spawn.  Calls the constructor on the script object.
   2123 Can be overridden by subclasses when a thread doesn't need to be allocated.
   2124 ================
   2125 */
   2126 idThread *idWeapon::ConstructScriptObject() {
   2127 	const function_t *constructor;
   2128 
   2129 	thread->EndThread();
   2130 
   2131 	// call script object's constructor
   2132 	constructor = scriptObject.GetConstructor();
   2133 	if ( !constructor ) {
   2134 		gameLocal.Error( "Missing constructor on '%s' for weapon", scriptObject.GetTypeName() );
   2135 	}
   2136 
   2137 	// init the script object's data
   2138 	scriptObject.ClearObject();
   2139 	thread->CallFunction( this, constructor, true );
   2140 	thread->Execute();
   2141 
   2142 	return thread;
   2143 }
   2144 
   2145 /*
   2146 ================
   2147 idWeapon::DeconstructScriptObject
   2148 
   2149 Called during idEntity::~idEntity.  Calls the destructor on the script object.
   2150 Can be overridden by subclasses when a thread doesn't need to be allocated.
   2151 Not called during idGameLocal::MapShutdown.
   2152 ================
   2153 */
   2154 void idWeapon::DeconstructScriptObject() {
   2155 	const function_t *destructor;
   2156 
   2157 	if ( !thread ) {
   2158 		return;
   2159 	}
   2160 	
   2161 	// don't bother calling the script object's destructor on map shutdown
   2162 	if ( gameLocal.GameState() == GAMESTATE_SHUTDOWN ) {
   2163 		return;
   2164 	}
   2165 
   2166 	thread->EndThread();
   2167 
   2168 	// call script object's destructor
   2169 	destructor = scriptObject.GetDestructor();
   2170 	if ( destructor ) {
   2171 		// start a thread that will run immediately and end
   2172 		thread->CallFunction( this, destructor, true );
   2173 		thread->Execute();
   2174 		thread->EndThread();
   2175 	}
   2176 
   2177 	// clear out the object's memory
   2178 	scriptObject.ClearObject();
   2179 }
   2180 
   2181 /*
   2182 ================
   2183 idWeapon::UpdateScript
   2184 ================
   2185 */
   2186 void idWeapon::UpdateScript() {
   2187 	int	count;
   2188 
   2189 	if ( !isLinked ) {
   2190 		return;
   2191 	}
   2192 
   2193 	// only update the script on new frames
   2194 	if ( !gameLocal.isNewFrame ) {
   2195 		return;
   2196 	}
   2197 
   2198 	if ( idealState.Length() ) {
   2199 		SetState( idealState, animBlendFrames );
   2200 	}
   2201 
   2202 	// update script state, which may call Event_LaunchProjectiles, among other things
   2203 	count = 10;
   2204 	while( ( thread->Execute() || idealState.Length() ) && count-- ) {
   2205 		// happens for weapons with no clip (like grenades)
   2206 		if ( idealState.Length() ) {
   2207 			SetState( idealState, animBlendFrames );
   2208 		}
   2209 	}
   2210 
   2211 	WEAPON_RELOAD = false;
   2212 }
   2213 
   2214 /*
   2215 ================
   2216 idWeapon::AlertMonsters
   2217 ================
   2218 */
   2219 void idWeapon::AlertMonsters() {
   2220 	trace_t	tr;
   2221 	idEntity *ent;
   2222 	idVec3 end = muzzleFlash.origin + muzzleFlash.axis * muzzleFlash.target;
   2223 
   2224 	gameLocal.clip.TracePoint( tr, muzzleFlash.origin, end, CONTENTS_OPAQUE | MASK_SHOT_RENDERMODEL | CONTENTS_FLASHLIGHT_TRIGGER, owner );
   2225 	if ( g_debugWeapon.GetBool() ) {
   2226 		gameRenderWorld->DebugLine( colorYellow, muzzleFlash.origin, end, 0 );
   2227 		gameRenderWorld->DebugArrow( colorGreen, muzzleFlash.origin, tr.endpos, 2, 0 );
   2228 	}
   2229 
   2230 	if ( tr.fraction < 1.0f ) {
   2231 		ent = gameLocal.GetTraceEntity( tr );
   2232 		if ( ent->IsType( idAI::Type ) ) {
   2233 			static_cast<idAI *>( ent )->TouchedByFlashlight( owner );
   2234 		} else if ( ent->IsType( idTrigger::Type ) ) {
   2235 			ent->Signal( SIG_TOUCH );
   2236 			ent->ProcessEvent( &EV_Touch, owner, &tr );
   2237 		}
   2238 	}
   2239 
   2240 	// jitter the trace to try to catch cases where a trace down the center doesn't hit the monster
   2241 	end += muzzleFlash.axis * muzzleFlash.right * idMath::Sin16( MS2SEC( gameLocal.time ) * 31.34f );
   2242 	end += muzzleFlash.axis * muzzleFlash.up * idMath::Sin16( MS2SEC( gameLocal.time ) * 12.17f );
   2243 	gameLocal.clip.TracePoint( tr, muzzleFlash.origin, end, CONTENTS_OPAQUE | MASK_SHOT_RENDERMODEL | CONTENTS_FLASHLIGHT_TRIGGER, owner );
   2244 	if ( g_debugWeapon.GetBool() ) {
   2245 		gameRenderWorld->DebugLine( colorYellow, muzzleFlash.origin, end, 0 );
   2246 		gameRenderWorld->DebugArrow( colorGreen, muzzleFlash.origin, tr.endpos, 2, 0 );
   2247 	}
   2248 
   2249 	if ( tr.fraction < 1.0f ) {
   2250 		ent = gameLocal.GetTraceEntity( tr );
   2251 		if ( ent->IsType( idAI::Type ) ) {
   2252 			static_cast<idAI *>( ent )->TouchedByFlashlight( owner );
   2253 		} else if ( ent->IsType( idTrigger::Type ) ) {
   2254 			ent->Signal( SIG_TOUCH );
   2255 			ent->ProcessEvent( &EV_Touch, owner, &tr );
   2256 		}
   2257 	}
   2258 }
   2259 
   2260 /*
   2261 ================
   2262 idWeapon::GetMuzzlePositionWithHacks
   2263 
   2264 Some weapons that have a barrel joint either have it pointing in the wrong
   2265 direction (rocket launcher), or don't animate it properly (pistol).
   2266 
   2267 For good 3D TV / head mounted display work, we need to display a laser sight
   2268 in the world.
   2269 
   2270 Fixing the animated meshes would be ideal, but hacking it in code is
   2271 the pragmatic move right now.
   2272 
   2273 Returns false for hands, grenades, and chainsaw.
   2274 ================
   2275 */
   2276 bool idWeapon::GetMuzzlePositionWithHacks( idVec3 & origin, idMat3 & axis ) {
   2277 	// I couldn't find a simple enum to identify the weapons that need
   2278 	// workaround hacks...
   2279 	const idStr & weaponIconName = pdaIcon;
   2280 
   2281 	origin = playerViewOrigin;
   2282 	axis = playerViewAxis;
   2283 	
   2284 	if ( weaponIconName == "guis/assets/hud/icons/grenade_new.tga" ) {
   2285 		return false;
   2286 	}
   2287 
   2288 	if ( weaponIconName == "guis/assets/hud/icons/chainsaw_new.tga" ) {
   2289 		return false;
   2290 	}
   2291 
   2292 	if ( weaponIconName == "guis/assets/hud/icons/soul_cube.tga" ) {
   2293 		return false;
   2294 	}
   2295 
   2296 	if ( barrelJointView != INVALID_JOINT ) {
   2297 		GetGlobalJointTransform( true, barrelJointView, origin, axis );
   2298 	} else if ( guiLightJointView != INVALID_JOINT ) {
   2299 		GetGlobalJointTransform( true, guiLightJointView, origin, axis );
   2300 	} else {
   2301 		return false;
   2302 	}
   2303 
   2304 	// get better axis joints for weapons where the barrelJointView isn't
   2305 	// animated properly
   2306 	idVec3	discardedOrigin;
   2307 	if ( weaponIconName == "guis/assets/hud/icons/pistol_new.tga" ) {
   2308 		// muzzle doesn't animate during firing, Bod does
   2309 		const jointHandle_t bodJoint = animator.GetJointHandle( "Bod" );
   2310 		GetGlobalJointTransform( true, bodJoint, discardedOrigin, axis );
   2311 	}
   2312 	if ( weaponIconName == "guis/assets/hud/icons/rocketlauncher_new.tga" ) {
   2313 		// joint doesn't point straight, so rotate it
   2314 		std::swap( axis[0], axis[2] );
   2315 	}
   2316 	if ( weaponIconName == "guis/assets/hud/icons/shotgun_new.tga" ) {
   2317 		// joint doesn't point straight, so rotate it
   2318 		const jointHandle_t bodJoint = animator.GetJointHandle( "trigger" );
   2319 		GetGlobalJointTransform( true, bodJoint, discardedOrigin, axis );
   2320 		std::swap( axis[0], axis[2] );
   2321 		axis[0] = -axis[0];
   2322 	}
   2323 	
   2324 	// we probably should fix the above hacks above that are based on texture names above at some
   2325 	// point
   2326 	if ( weaponDef != NULL ) {
   2327 		if ( ( idStr::Icmp( "weapon_shotgun_double", weaponDef->GetName() ) == 0 ) || ( idStr::Icmp( "weapon_shotgun_double_mp", weaponDef->GetName() ) == 0 ) ) {
   2328 			// joint doesn't point straight, so rotate it
   2329 			std::swap( axis[0], axis[2] );
   2330 		} else if ( idStr::Icmp( "weapon_grabber", weaponDef->GetName() ) == 0 ) {
   2331 			idVec3 forward = axis[0];
   2332 			forward.Normalize();
   2333 			const float scaleOffset = 4.0f;
   2334 			forward *= scaleOffset;
   2335 			origin += forward;
   2336 		}
   2337 	}
   2338 	
   2339 	return true;
   2340 }
   2341 
   2342 /*
   2343 ================
   2344 idWeapon::PresentWeapon
   2345 ================
   2346 */
   2347 void idWeapon::PresentWeapon( bool showViewModel ) {
   2348 	playerViewOrigin = owner->firstPersonViewOrigin;
   2349 	playerViewAxis = owner->firstPersonViewAxis;
   2350 
   2351 	if ( isPlayerFlashlight ) {
   2352 		viewWeaponOrigin = playerViewOrigin;
   2353 		viewWeaponAxis = playerViewAxis;
   2354 
   2355 		fraccos = cos( ( gameLocal.framenum & 255 ) / 127.0f * idMath::PI );
   2356 
   2357 		static unsigned int divisor = 32;
   2358 		unsigned int val = ( gameLocal.framenum + gameLocal.framenum / divisor ) & 255;
   2359 		fraccos2 = cos( val / 127.0f * idMath::PI );
   2360 
   2361 		static idVec3 baseAdjustPos = idVec3( -8.0f, -20.0f, -10.0f );		// rt, fwd, up
   2362 		static float pscale = 0.5f;
   2363 		static float yscale = 0.125f;
   2364 		idVec3 adjustPos = baseAdjustPos;// + ( idVec3( fraccos, 0.0f, fraccos2 ) * scale );
   2365 		viewWeaponOrigin += adjustPos.x * viewWeaponAxis[1] + adjustPos.y * viewWeaponAxis[0] + adjustPos.z * viewWeaponAxis[2];
   2366 //		viewWeaponOrigin += owner->viewBob;
   2367 
   2368 		static idAngles baseAdjustAng = idAngles( 88.0f, 10.0f, 0.0f );		//
   2369 		idAngles adjustAng = baseAdjustAng + idAngles( fraccos * pscale, fraccos2 * yscale, 0.0f );
   2370 //		adjustAng += owner->GetViewBobAngles();
   2371 		viewWeaponAxis = adjustAng.ToMat3() * viewWeaponAxis;
   2372 	} else {
   2373 		// calculate weapon position based on player movement bobbing
   2374 		owner->CalculateViewWeaponPos( viewWeaponOrigin, viewWeaponAxis );
   2375 
   2376 		// hide offset is for dropping the gun when approaching a GUI or NPC
   2377 		// This is simpler to manage than doing the weapon put-away animation
   2378 		if ( gameLocal.time - hideStartTime < hideTime ) {		
   2379 			float frac = ( float )( gameLocal.time - hideStartTime ) / ( float )hideTime;
   2380 			if ( hideStart < hideEnd ) {
   2381 				frac = 1.0f - frac;
   2382 				frac = 1.0f - frac * frac;
   2383 			} else {
   2384 				frac = frac * frac;
   2385 			}
   2386 			hideOffset = hideStart + ( hideEnd - hideStart ) * frac;
   2387 		} else {
   2388 			hideOffset = hideEnd;
   2389 			if ( hide && disabled ) {
   2390 				Hide();
   2391 			}
   2392 		}
   2393 		viewWeaponOrigin += hideOffset * viewWeaponAxis[ 2 ];
   2394 
   2395 		// kick up based on repeat firing
   2396 		MuzzleRise( viewWeaponOrigin, viewWeaponAxis );
   2397 	}
   2398 
   2399 	// set the physics position and orientation
   2400 	GetPhysics()->SetOrigin( viewWeaponOrigin );
   2401 	GetPhysics()->SetAxis( viewWeaponAxis );
   2402 	UpdateVisuals();
   2403 
   2404 	// update the weapon script
   2405 	UpdateScript();
   2406 
   2407 	UpdateGUI();
   2408 
   2409 	// update animation
   2410 	UpdateAnimation();
   2411 
   2412 	// only show the surface in player view
   2413 	renderEntity.allowSurfaceInViewID = owner->entityNumber+1;
   2414 
   2415 	// crunch the depth range so it never pokes into walls this breaks the machine gun gui
   2416 	renderEntity.weaponDepthHack = g_useWeaponDepthHack.GetBool();
   2417 
   2418 	// present the model
   2419 	if ( showViewModel ) {
   2420 		Present();
   2421 	} else {
   2422 		FreeModelDef();
   2423 	}
   2424 
   2425 	if ( worldModel.GetEntity() && worldModel.GetEntity()->GetRenderEntity() ) {
   2426 		// deal with the third-person visible world model
   2427 		// don't show shadows of the world model in first person
   2428 		if ( common->IsMultiplayer() || g_showPlayerShadow.GetBool() || pm_thirdPerson.GetBool() ) {
   2429 			worldModel.GetEntity()->GetRenderEntity()->suppressShadowInViewID	= 0;
   2430 		} else {
   2431 			worldModel.GetEntity()->GetRenderEntity()->suppressShadowInViewID	= owner->entityNumber+1;
   2432 			worldModel.GetEntity()->GetRenderEntity()->suppressShadowInLightID = LIGHTID_VIEW_MUZZLE_FLASH + owner->entityNumber;
   2433 		}
   2434 	}
   2435 
   2436 	if ( nozzleFx ) {
   2437 		UpdateNozzleFx();
   2438 	}
   2439 
   2440 	// muzzle smoke
   2441 	if ( showViewModel && !disabled && weaponSmoke && ( weaponSmokeStartTime != 0 ) ) {
   2442 		// use the barrel joint if available
   2443 
   2444 		if(smokeJointView != INVALID_JOINT) {
   2445 			GetGlobalJointTransform( true, smokeJointView, muzzleOrigin, muzzleAxis );
   2446 		} else if (barrelJointView != INVALID_JOINT) {
   2447 			GetGlobalJointTransform( true, barrelJointView, muzzleOrigin, muzzleAxis );
   2448 		} else {
   2449 			// default to going straight out the view
   2450 			muzzleOrigin = playerViewOrigin;
   2451 			muzzleAxis = playerViewAxis;
   2452 		}
   2453 		// spit out a particle
   2454 		if ( !gameLocal.smokeParticles->EmitSmoke( weaponSmoke, weaponSmokeStartTime, gameLocal.random.RandomFloat(), muzzleOrigin, muzzleAxis, timeGroup /*_D3XP*/ ) ) {
   2455 			weaponSmokeStartTime = ( continuousSmoke ) ? gameLocal.time : 0;
   2456 		}
   2457 	}
   2458 
   2459 	if ( showViewModel && strikeSmoke && strikeSmokeStartTime != 0 ) {
   2460 		// spit out a particle
   2461 		if ( !gameLocal.smokeParticles->EmitSmoke( strikeSmoke, strikeSmokeStartTime, gameLocal.random.RandomFloat(), strikePos, strikeAxis, timeGroup /*_D3XP*/ ) ) {
   2462 			strikeSmokeStartTime = 0;
   2463 		}
   2464 	}
   2465 
   2466 	if ( showViewModel && !hide ) {
   2467 
   2468 		for( int i = 0; i < weaponParticles.Num(); i++ ) {
   2469 			WeaponParticle_t* part = weaponParticles.GetIndex(i);
   2470 
   2471 			if(part->active) {
   2472 				if(part->smoke) {
   2473 					if(part->joint != INVALID_JOINT) {
   2474 						GetGlobalJointTransform( true, part->joint, muzzleOrigin, muzzleAxis );
   2475 					} else {
   2476 						// default to going straight out the view
   2477 						muzzleOrigin = playerViewOrigin;
   2478 						muzzleAxis = playerViewAxis;
   2479 					}
   2480 					if ( !gameLocal.smokeParticles->EmitSmoke( part->particle, part->startTime, gameLocal.random.RandomFloat(), muzzleOrigin, muzzleAxis, timeGroup /*_D3XP*/ ) ) {
   2481 						part->active = false;	// all done
   2482 						part->startTime = 0;
   2483 					}
   2484 				} else {
   2485 					if ( part->emitter != NULL ) {
   2486 						//Manually update the position of the emitter so it follows the weapon
   2487 						renderEntity_t* rendEnt = part->emitter->GetRenderEntity();
   2488 						GetGlobalJointTransform( true, part->joint, rendEnt->origin, rendEnt->axis );
   2489 
   2490 						if ( part->emitter->GetModelDefHandle() != -1 ) {
   2491 							gameRenderWorld->UpdateEntityDef( part->emitter->GetModelDefHandle(), rendEnt );
   2492 						}
   2493 					}
   2494 				}
   2495 			}
   2496 		}
   2497 
   2498 		for(int i = 0; i < weaponLights.Num(); i++) {
   2499 			WeaponLight_t* light = weaponLights.GetIndex(i);
   2500 
   2501 			if(light->active) {
   2502 
   2503 				GetGlobalJointTransform( true, light->joint, light->light.origin, light->light.axis );
   2504 				if ( ( light->lightHandle != -1 ) ) {
   2505 					gameRenderWorld->UpdateLightDef( light->lightHandle, &light->light );
   2506 				} else {
   2507 					light->lightHandle = gameRenderWorld->AddLightDef( &light->light );
   2508 				}
   2509 			}
   2510 		}
   2511 	}
   2512 
   2513 	// Update the grabber effects
   2514 	if ( grabberState != -1 ) {
   2515 		grabberState = grabber.Update( owner, hide );
   2516 	}
   2517 
   2518 	// remove the muzzle flash light when it's done
   2519 	if ( ( !lightOn && ( gameLocal.time >= muzzleFlashEnd ) ) || IsHidden() ) {
   2520 		if ( muzzleFlashHandle != -1 ) {
   2521 			gameRenderWorld->FreeLightDef( muzzleFlashHandle );
   2522 			muzzleFlashHandle = -1;
   2523 		}
   2524 		if ( worldMuzzleFlashHandle != -1 ) {
   2525 			gameRenderWorld->FreeLightDef( worldMuzzleFlashHandle );
   2526 			worldMuzzleFlashHandle = -1;
   2527 		}
   2528 	}
   2529 
   2530 	// update the muzzle flash light, so it moves with the gun
   2531 	if ( muzzleFlashHandle != -1 ) {
   2532 		UpdateFlashPosition();
   2533 		gameRenderWorld->UpdateLightDef( muzzleFlashHandle, &muzzleFlash );
   2534 		gameRenderWorld->UpdateLightDef( worldMuzzleFlashHandle, &worldMuzzleFlash );
   2535 
   2536 		// wake up monsters with the flashlight
   2537 		if ( !common->IsMultiplayer() && lightOn && !owner->fl.notarget ) {
   2538 			AlertMonsters();
   2539 		}
   2540 	}
   2541 
   2542 	// update the gui light
   2543 	if ( guiLight.lightRadius[0] && guiLightJointView != INVALID_JOINT ) {
   2544 		GetGlobalJointTransform( true, guiLightJointView, guiLight.origin, guiLight.axis );
   2545 
   2546 		if ( ( guiLightHandle != -1 ) ) {
   2547 			gameRenderWorld->UpdateLightDef( guiLightHandle, &guiLight );
   2548 		} else {
   2549 			guiLightHandle = gameRenderWorld->AddLightDef( &guiLight );
   2550 		}
   2551 	}
   2552 
   2553 	if ( status != WP_READY && sndHum ) {
   2554 		StopSound( SND_CHANNEL_BODY, false );
   2555 	}
   2556 
   2557 	UpdateSound();
   2558 
   2559 	// constant rumble...
   2560 	float highMagnitude = weaponDef->dict.GetFloat( "controllerConstantShakeHighMag" );
   2561 	int highDuration = weaponDef->dict.GetInt( "controllerConstantShakeHighTime" );
   2562 	float lowMagnitude = weaponDef->dict.GetFloat( "controllerConstantShakeLowMag" );
   2563 	int lowDuration = weaponDef->dict.GetInt( "controllerConstantShakeLowTime" );
   2564 
   2565 	if( owner->IsLocallyControlled() ) {
   2566 		owner->SetControllerShake( highMagnitude, highDuration, lowMagnitude, lowDuration );
   2567 	}
   2568 }
   2569 
   2570 /*
   2571 ================
   2572 idWeapon::RemoveMuzzleFlashlight
   2573 ================
   2574 */
   2575 void idWeapon::RemoveMuzzleFlashlight() {
   2576 	if ( muzzleFlashHandle != -1 ) {
   2577 		gameRenderWorld->FreeLightDef( muzzleFlashHandle );
   2578 		muzzleFlashHandle = -1;
   2579 	}
   2580 	if ( worldMuzzleFlashHandle != -1 ) {
   2581 		gameRenderWorld->FreeLightDef( worldMuzzleFlashHandle );
   2582 		worldMuzzleFlashHandle = -1;
   2583 	}
   2584 }
   2585 
   2586 /*
   2587 ================
   2588 idWeapon::EnterCinematic
   2589 ================
   2590 */
   2591 void idWeapon::EnterCinematic() {
   2592 	StopSound( SND_CHANNEL_ANY, false );
   2593 
   2594 	if ( isLinked ) {
   2595 		SetState( "EnterCinematic", 0 );
   2596 		thread->Execute();
   2597 
   2598 		WEAPON_ATTACK		= false;
   2599 		WEAPON_RELOAD		= false;
   2600 		WEAPON_NETRELOAD	= false;
   2601 		WEAPON_NETENDRELOAD	= false;
   2602 		WEAPON_NETFIRING	= false;
   2603 		WEAPON_RAISEWEAPON	= false;
   2604 		WEAPON_LOWERWEAPON	= false;
   2605 
   2606 		grabber.Update( this->GetOwner(), true );
   2607 	}
   2608 
   2609 	disabled = true;
   2610 
   2611 	LowerWeapon();
   2612 }
   2613 
   2614 /*
   2615 ================
   2616 idWeapon::ExitCinematic
   2617 ================
   2618 */
   2619 void idWeapon::ExitCinematic() {
   2620 	disabled = false;
   2621 
   2622 	if ( isLinked ) {
   2623 		SetState( "ExitCinematic", 0 );
   2624 		thread->Execute();
   2625 	}
   2626 
   2627 	RaiseWeapon();
   2628 }
   2629 
   2630 /*
   2631 ================
   2632 idWeapon::NetCatchup
   2633 ================
   2634 */
   2635 void idWeapon::NetCatchup() {
   2636 	if ( isLinked ) {
   2637 		SetState( "NetCatchup", 0 );
   2638 		thread->Execute();
   2639 	}
   2640 }
   2641 
   2642 /*
   2643 ================
   2644 idWeapon::GetZoomFov
   2645 ================
   2646 */
   2647 int	idWeapon::GetZoomFov() {
   2648 	return zoomFov;
   2649 }
   2650 
   2651 /*
   2652 ================
   2653 idWeapon::GetWeaponAngleOffsets
   2654 ================
   2655 */
   2656 void idWeapon::GetWeaponAngleOffsets( int *average, float *scale, float *max ) {
   2657 	*average = weaponAngleOffsetAverages;
   2658 	*scale = weaponAngleOffsetScale;
   2659 	*max = weaponAngleOffsetMax;
   2660 }
   2661 
   2662 /*
   2663 ================
   2664 idWeapon::GetWeaponTimeOffsets
   2665 ================
   2666 */
   2667 void idWeapon::GetWeaponTimeOffsets( float *time, float *scale ) {
   2668 	*time = weaponOffsetTime;
   2669 	*scale = weaponOffsetScale;
   2670 }
   2671 
   2672 
   2673 /***********************************************************************
   2674 
   2675 	Ammo
   2676 
   2677 ***********************************************************************/
   2678 
   2679 /*
   2680 ================
   2681 idWeapon::GetAmmoNumForName
   2682 ================
   2683 */
   2684 ammo_t idWeapon::GetAmmoNumForName( const char *ammoname ) {
   2685 	int num;
   2686 	const idDict *ammoDict;
   2687 
   2688 	assert( ammoname );
   2689 
   2690 	ammoDict = gameLocal.FindEntityDefDict( "ammo_types", false );
   2691 	if ( ammoDict == NULL ) {
   2692 		gameLocal.Error( "Could not find entity definition for 'ammo_types'\n" );
   2693 		return 0;
   2694 	}
   2695 
   2696 	if ( !ammoname[ 0 ] ) {
   2697 		return 0;
   2698 	}
   2699 
   2700 	if ( !ammoDict->GetInt( ammoname, "-1", num ) ) {
   2701 
   2702 	}
   2703 
   2704 	if ( ( num < 0 ) || ( num >= AMMO_NUMTYPES ) ) {
   2705 		gameLocal.Warning( "Ammo type '%s' value out of range.  Maximum ammo types is %d.\n", ammoname, AMMO_NUMTYPES );
   2706 		num = 0;
   2707 	}
   2708 
   2709 	return ( ammo_t )num;
   2710 }
   2711 
   2712 /*
   2713 ================
   2714 idWeapon::GetAmmoNameForNum
   2715 ================
   2716 */
   2717 const char *idWeapon::GetAmmoNameForNum( ammo_t ammonum ) {
   2718 	int i;
   2719 	int num;
   2720 	const idDict *ammoDict;
   2721 	const idKeyValue *kv;
   2722 	char text[ 32 ];
   2723 
   2724 	ammoDict = gameLocal.FindEntityDefDict( "ammo_types", false );
   2725 	if ( ammoDict == NULL ) {
   2726 		gameLocal.Error( "Could not find entity definition for 'ammo_types'\n" );
   2727 		return NULL;
   2728 	}
   2729 
   2730 	sprintf( text, "%d", ammonum );
   2731 
   2732 	num = ammoDict->GetNumKeyVals();
   2733 	for( i = 0; i < num; i++ ) {
   2734 		kv = ammoDict->GetKeyVal( i );
   2735 		if ( kv->GetValue() == text ) {
   2736 			return kv->GetKey();
   2737 		}
   2738 	}
   2739 
   2740 	return NULL;
   2741 }
   2742 
   2743 /*
   2744 ================
   2745 idWeapon::GetAmmoPickupNameForNum
   2746 ================
   2747 */
   2748 const char *idWeapon::GetAmmoPickupNameForNum( ammo_t ammonum ) {
   2749 	int i;
   2750 	int num;
   2751 	const idDict *ammoDict;
   2752 	const idKeyValue *kv;
   2753 
   2754 	ammoDict = gameLocal.FindEntityDefDict( "ammo_names", false );
   2755 	if ( !ammoDict ) {
   2756 		gameLocal.Error( "Could not find entity definition for 'ammo_names'\n" );
   2757 	}
   2758 
   2759 	const char *name = GetAmmoNameForNum( ammonum );
   2760 
   2761 	if ( name != NULL && *name != NULL ) {
   2762 		num = ammoDict->GetNumKeyVals();
   2763 		for( i = 0; i < num; i++ ) {
   2764 			kv = ammoDict->GetKeyVal( i );
   2765 			if ( idStr::Icmp( kv->GetKey(), name) == 0 ) {
   2766 				return kv->GetValue();
   2767 			}
   2768 		}
   2769 	}
   2770 
   2771 	return "";
   2772 }
   2773 
   2774 /*
   2775 ================
   2776 idWeapon::AmmoAvailable
   2777 ================
   2778 */
   2779 int idWeapon::AmmoAvailable() const {
   2780 	if ( owner ) {
   2781 		return owner->inventory.HasAmmo( ammoType, ammoRequired );
   2782 	} else {
   2783 		if ( g_infiniteAmmo.GetBool() ) {
   2784 			return 10;	// arbitrary number, just so whatever's calling thinks there's sufficient ammo...
   2785 		} else {
   2786 			return 0;
   2787 		}
   2788 	}
   2789 }
   2790 
   2791 /*
   2792 ================
   2793 idWeapon::AmmoInClip
   2794 ================
   2795 */
   2796 int idWeapon::AmmoInClip() const {
   2797 	return ammoClip.Get();
   2798 }
   2799 
   2800 /*
   2801 ================
   2802 idWeapon::ResetAmmoClip
   2803 ================
   2804 */
   2805 void idWeapon::ResetAmmoClip() {
   2806 	ammoClip = -1;
   2807 }
   2808 
   2809 /*
   2810 ================
   2811 idWeapon::GetAmmoType
   2812 ================
   2813 */
   2814 ammo_t idWeapon::GetAmmoType() const {
   2815 	return ammoType;
   2816 }
   2817 
   2818 /*
   2819 ================
   2820 idWeapon::ClipSize
   2821 ================
   2822 */
   2823 int	idWeapon::ClipSize() const {
   2824 	return clipSize;
   2825 }
   2826 
   2827 /*
   2828 ================
   2829 idWeapon::LowAmmo
   2830 ================
   2831 */
   2832 int	idWeapon::LowAmmo() const {
   2833 	return lowAmmo;
   2834 }
   2835 
   2836 /*
   2837 ================
   2838 idWeapon::AmmoRequired
   2839 ================
   2840 */
   2841 int	idWeapon::AmmoRequired() const {
   2842 	return ammoRequired;
   2843 }
   2844 
   2845 /*
   2846 ================
   2847 idWeapon::GetGrabberState
   2848 
   2849 Returns the current grabberState
   2850 ================
   2851 */
   2852 int idWeapon::GetGrabberState() const {
   2853 
   2854 	return grabberState;
   2855 }
   2856 
   2857 /*
   2858 ================
   2859 idWeapon::AmmoCount
   2860 
   2861 Returns the total number of rounds regardless of the required ammo
   2862 ================
   2863 */
   2864 int idWeapon::AmmoCount() const {
   2865 
   2866 	if ( owner ) {
   2867 		return owner->inventory.HasAmmo( ammoType, 1 );
   2868 	} else {
   2869 		return 0;
   2870 	}
   2871 }
   2872 
   2873 /*
   2874 ================
   2875 idWeapon::WriteToSnapshot
   2876 ================
   2877 */
   2878 void idWeapon::WriteToSnapshot( idBitMsg &msg ) const {
   2879 	msg.WriteBits( ammoClip.Get(), ASYNC_PLAYER_INV_CLIP_BITS );
   2880 	msg.WriteBits( worldModel.GetSpawnId(), 32 );
   2881 	msg.WriteBits( lightOn, 1 );
   2882 	msg.WriteBits( isFiring ? 1 : 0, 1 );
   2883 }
   2884 
   2885 /*
   2886 ================
   2887 idWeapon::ReadFromSnapshot
   2888 ================
   2889 */
   2890 void idWeapon::ReadFromSnapshot( const idBitMsg &msg ) {	
   2891 	const int snapshotAmmoClip = msg.ReadBits( ASYNC_PLAYER_INV_CLIP_BITS );
   2892 	worldModel.SetSpawnId( msg.ReadBits( 32 ) );
   2893 	const bool snapshotLightOn = msg.ReadBits( 1 ) != 0;
   2894 	isFiring = msg.ReadBits( 1 ) != 0;
   2895 
   2896 	// Local clients predict the ammo in the clip. Only use the ammo cpunt from the snapshot for local clients
   2897 	// if the server has processed the same usercmd in which we predicted the ammo count.
   2898 	if ( owner != NULL ) {
   2899 		ammoClip.UpdateFromSnapshot( snapshotAmmoClip, owner->GetEntityNumber() );
   2900 	}
   2901 
   2902 	// WEAPON_NETFIRING is only turned on for other clients we're predicting. not for local client
   2903 	if ( owner && !owner->IsLocallyControlled() && WEAPON_NETFIRING.IsLinked() ) {
   2904 
   2905 		// immediately go to the firing state so we don't skip fire animations
   2906 		if ( !WEAPON_NETFIRING && isFiring ) {
   2907 			idealState = "Fire";
   2908 		}
   2909 
   2910         // immediately switch back to idle
   2911         if ( WEAPON_NETFIRING && !isFiring ) {
   2912             idealState = "Idle";
   2913         }
   2914 
   2915 		WEAPON_NETFIRING = isFiring;
   2916 		WEAPON_ATTACK = isFiring;
   2917 	}
   2918 
   2919 	// Only update the flashlight state if it has changed, and if this isn't the local player.
   2920 	// The local player sets their flashlight immediately for responsiveness.
   2921 	if ( owner != NULL && !owner->IsLocallyControlled() && lightOn != snapshotLightOn ) {
   2922 		if ( snapshotLightOn ) {
   2923 			FlashlightOn();
   2924 		} else {
   2925 			FlashlightOff();
   2926 		}
   2927 	}
   2928 }
   2929 
   2930 /*
   2931 ================
   2932 idWeapon::ClientReceiveEvent
   2933 ================
   2934 */
   2935 bool idWeapon::ClientReceiveEvent( int event, int time, const idBitMsg &msg ) {
   2936 
   2937 	switch( event ) {
   2938 		case EVENT_RELOAD: {
   2939 			// Local clients predict reloads, only process this event for remote clients.
   2940 			if ( owner != NULL && !owner->IsLocallyControlled() && ( gameLocal.time - time < 1000 ) ) {
   2941 				if ( WEAPON_NETRELOAD.IsLinked() ) {
   2942 					WEAPON_NETRELOAD = true;
   2943 					WEAPON_NETENDRELOAD = false;
   2944 				}
   2945 			}
   2946 			return true;
   2947 		}
   2948 		case EVENT_ENDRELOAD: {
   2949 			// Local clients predict reloads, only process this event for remote clients.
   2950 			if ( owner != NULL && !owner->IsLocallyControlled() && WEAPON_NETENDRELOAD.IsLinked() ) {
   2951 				WEAPON_NETENDRELOAD = true;
   2952 			}
   2953 			return true;
   2954 		}
   2955 		case EVENT_CHANGESKIN: {
   2956 			int index = gameLocal.ClientRemapDecl( DECL_SKIN, msg.ReadLong() );
   2957 			renderEntity.customSkin = ( index != -1 ) ? static_cast<const idDeclSkin *>( declManager->DeclByIndex( DECL_SKIN, index ) ) : NULL;
   2958 			UpdateVisuals();
   2959 			if ( worldModel.GetEntity() ) {
   2960 				worldModel.GetEntity()->SetSkin( renderEntity.customSkin );
   2961 			}
   2962 			return true;
   2963 		}
   2964 		default: {
   2965 			return idEntity::ClientReceiveEvent( event, time, msg );
   2966 		}
   2967 	}
   2968 }
   2969 
   2970 /***********************************************************************
   2971 
   2972 	Script events
   2973 
   2974 ***********************************************************************/
   2975 
   2976 /*
   2977 ===============
   2978 idWeapon::Event_Clear
   2979 ===============
   2980 */
   2981 void idWeapon::Event_Clear() {
   2982 	Clear();
   2983 }
   2984 
   2985 /*
   2986 ===============
   2987 idWeapon::Event_GetOwner
   2988 ===============
   2989 */
   2990 void idWeapon::Event_GetOwner() {
   2991 	idThread::ReturnEntity( owner );
   2992 }
   2993 
   2994 /*
   2995 ===============
   2996 idWeapon::Event_WeaponState
   2997 ===============
   2998 */
   2999 void idWeapon::Event_WeaponState( const char *statename, int blendFrames ) {
   3000 	const function_t *func;
   3001 
   3002 	func = scriptObject.GetFunction( statename );
   3003 	if ( !func ) {
   3004 		assert( 0 );
   3005 		gameLocal.Error( "Can't find function '%s' in object '%s'", statename, scriptObject.GetTypeName() );
   3006 	}
   3007 
   3008 	idealState = statename;
   3009 
   3010 	// HACK, Fixes reload animation on player not playing on second reload ( on non local client players, and only with host viewing. )
   3011 	if( common->IsMultiplayer() && strcmp( weaponDef->GetName(), "weapon_shotgun_double_mp" ) == 0 ) {
   3012 		if( strcmp( statename, "Reload" ) != 0 ) {
   3013 			if( status ==  WP_RELOAD ) {
   3014 				status =  WP_READY;
   3015 			}
   3016 		}
   3017 	}
   3018 
   3019 	if ( !idealState.Icmp( "Fire" ) ) {
   3020 		isFiring = true;
   3021 	} else {
   3022 		isFiring = false;
   3023 	}
   3024 
   3025 	animBlendFrames = blendFrames;
   3026 	thread->DoneProcessing();
   3027 }
   3028 
   3029 /*
   3030 ===============
   3031 idWeapon::Event_WeaponReady
   3032 ===============
   3033 */
   3034 void idWeapon::Event_WeaponReady() {
   3035 	status = WP_READY;
   3036 	idLib::PrintfIf( g_debugWeapon.GetBool(), "Weapon Status WP_READY \n" );
   3037 	if ( isLinked ) {
   3038 		WEAPON_RAISEWEAPON = false;
   3039 	}
   3040 	if ( sndHum ) {
   3041 		StartSoundShader( sndHum, SND_CHANNEL_BODY, 0, false, NULL );
   3042 	}
   3043 
   3044 }
   3045 
   3046 /*
   3047 ===============
   3048 idWeapon::Event_WeaponOutOfAmmo
   3049 ===============
   3050 */
   3051 void idWeapon::Event_WeaponOutOfAmmo() {
   3052 	status = WP_OUTOFAMMO;
   3053 	idLib::PrintfIf( g_debugWeapon.GetBool(), "Weapon Status WP_OUTOFAMMO \n" );
   3054 	if ( isLinked ) {
   3055 		WEAPON_RAISEWEAPON = false;
   3056 	}
   3057 }
   3058 
   3059 /*
   3060 ===============
   3061 idWeapon::Event_WeaponReloading
   3062 ===============
   3063 */
   3064 void idWeapon::Event_WeaponReloading() {
   3065 	status = WP_RELOAD;
   3066 	idLib::PrintfIf( g_debugWeapon.GetBool(), "Weapon Status WP_RELOAD \n" );
   3067 }
   3068 
   3069 /*
   3070 ===============
   3071 idWeapon::Event_WeaponHolstered
   3072 ===============
   3073 */
   3074 void idWeapon::Event_WeaponHolstered() {
   3075 	status = WP_HOLSTERED;
   3076 	idLib::PrintfIf( g_debugWeapon.GetBool(), "Weapon Status WP_HOLSTERED \n" );
   3077 	if ( isLinked ) {
   3078 		WEAPON_LOWERWEAPON = false;
   3079 	}
   3080 }
   3081 
   3082 /*
   3083 ===============
   3084 idWeapon::Event_WeaponRising
   3085 ===============
   3086 */
   3087 void idWeapon::Event_WeaponRising() {
   3088 	status = WP_RISING;
   3089 	idLib::PrintfIf( g_debugWeapon.GetBool(), "Weapon Status WP_RISING \n" );
   3090 	if ( isLinked ) {
   3091 		WEAPON_LOWERWEAPON = false;
   3092 	}
   3093 	owner->WeaponRisingCallback();
   3094 }
   3095 
   3096 /*
   3097 ===============
   3098 idWeapon::Event_WeaponLowering
   3099 ===============
   3100 */
   3101 void idWeapon::Event_WeaponLowering() {
   3102 	status = WP_LOWERING;
   3103 	idLib::PrintfIf( g_debugWeapon.GetBool(), "Weapon Status WP_LOWERING \n" );
   3104 	if ( isLinked ) {
   3105 		WEAPON_RAISEWEAPON = false;
   3106 	}
   3107 	owner->WeaponLoweringCallback();
   3108 }
   3109 
   3110 /*
   3111 ===============
   3112 idWeapon::Event_UseAmmo
   3113 ===============
   3114 */
   3115 void idWeapon::Event_UseAmmo( int amount ) {
   3116 	if ( owner == NULL || ( common->IsClient() && !owner->IsLocallyControlled() ) ) {
   3117 		return;
   3118 	}
   3119 
   3120 	owner->inventory.UseAmmo( ammoType, ( powerAmmo ) ? amount : ( amount * ammoRequired ) );
   3121 	if ( clipSize && ammoRequired ) {
   3122 		ammoClip -= powerAmmo ? amount : ( amount * ammoRequired );
   3123 		if ( ammoClip.Get() < 0 ) {
   3124 			ammoClip = 0;
   3125 		}
   3126 	}
   3127 }
   3128 
   3129 /*
   3130 ===============
   3131 idWeapon::Event_AddToClip
   3132 ===============
   3133 */
   3134 void idWeapon::Event_AddToClip( int amount ) {
   3135 	int ammoAvail;
   3136 
   3137 	if ( owner == NULL || ( common->IsClient() && !owner->IsLocallyControlled() ) ) {
   3138 		return;
   3139 	}
   3140 
   3141 	int oldAmmo = ammoClip.Get();
   3142 	ammoAvail = owner->inventory.HasAmmo( ammoType, ammoRequired ) + AmmoInClip();
   3143 
   3144 	ammoClip += amount;
   3145 	if ( ammoClip.Get() > clipSize ) {
   3146 		ammoClip = clipSize;
   3147 	}
   3148 
   3149 
   3150 	if ( ammoClip.Get() > ammoAvail ) {
   3151 		ammoClip = ammoAvail;
   3152 	}
   3153 
   3154 	// for shared ammo we need to use the ammo when it is moved into the clip
   3155 	int usedAmmo = ammoClip.Get() - oldAmmo;
   3156 	owner->inventory.UseAmmo(ammoType, usedAmmo);
   3157 }
   3158 
   3159 /*
   3160 ===============
   3161 idWeapon::Event_AmmoInClip
   3162 ===============
   3163 */
   3164 void idWeapon::Event_AmmoInClip() {
   3165 	int ammo = AmmoInClip();
   3166 	idThread::ReturnFloat( ammo );	
   3167 }
   3168 
   3169 /*
   3170 ===============
   3171 idWeapon::Event_AmmoAvailable
   3172 ===============
   3173 */
   3174 void idWeapon::Event_AmmoAvailable() {
   3175 	int ammoAvail = owner->inventory.HasAmmo( ammoType, ammoRequired );
   3176 	ammoAvail += AmmoInClip();
   3177 
   3178 	idThread::ReturnFloat( ammoAvail );
   3179 }
   3180 
   3181 /*
   3182 ===============
   3183 idWeapon::Event_TotalAmmoCount
   3184 ===============
   3185 */
   3186 void idWeapon::Event_TotalAmmoCount() {
   3187 	int ammoAvail = owner->inventory.HasAmmo( ammoType, 1 );
   3188 	idThread::ReturnFloat( ammoAvail );
   3189 }
   3190 
   3191 /*
   3192 ===============
   3193 idWeapon::Event_ClipSize
   3194 ===============
   3195 */
   3196 void idWeapon::Event_ClipSize() {
   3197 	idThread::ReturnFloat( clipSize );	
   3198 }
   3199 
   3200 /*
   3201 ===============
   3202 idWeapon::Event_AutoReload
   3203 ===============
   3204 */
   3205 void idWeapon::Event_AutoReload() {
   3206 	assert( owner );
   3207 	
   3208 	if ( common->IsClient() && owner != NULL && !owner->IsLocallyControlled() ) {
   3209 		idThread::ReturnFloat( 0.0f );
   3210 		return;
   3211 	}
   3212 
   3213 	idLobbyBase & lobby = session->GetActingGameStateLobbyBase();
   3214 	lobbyUserID_t & lobbyUserID = gameLocal.lobbyUserIDs[owner->entityNumber];
   3215 	idThread::ReturnFloat( lobby.GetLobbyUserWeaponAutoReload( lobbyUserID ) );
   3216 }
   3217 
   3218 /*
   3219 ===============
   3220 idWeapon::Event_NetReload
   3221 ===============
   3222 */
   3223 void idWeapon::Event_NetReload() {
   3224 	assert( owner );
   3225 	if ( common->IsServer() ) {
   3226 		ServerSendEvent( EVENT_RELOAD, NULL, false );
   3227 	}
   3228 }
   3229 
   3230 /*
   3231 ===============
   3232 idWeapon::Event_NetEndReload
   3233 ===============
   3234 */
   3235 void idWeapon::Event_NetEndReload() {
   3236 	assert( owner );
   3237 	if ( common->IsServer() ) {
   3238 		ServerSendEvent( EVENT_ENDRELOAD, NULL, false );
   3239 	}
   3240 }
   3241 
   3242 /*
   3243 ===============
   3244 idWeapon::Event_PlayAnim
   3245 ===============
   3246 */
   3247 void idWeapon::Event_PlayAnim( int channel, const char *animname ) {
   3248 	int anim;
   3249 	
   3250 	anim = animator.GetAnim( animname );
   3251 	if ( !anim ) {
   3252 		gameLocal.Warning( "missing '%s' animation on '%s' (%s)", animname, name.c_str(), GetEntityDefName() );
   3253 		animator.Clear( channel, gameLocal.time, FRAME2MS( animBlendFrames ) );
   3254 		animDoneTime = 0;
   3255 	} else {
   3256 		if ( !( owner && owner->GetInfluenceLevel() ) ) {
   3257 			Show();
   3258 		}
   3259 		animator.PlayAnim( channel, anim, gameLocal.time, FRAME2MS( animBlendFrames ) );
   3260 		animDoneTime = animator.CurrentAnim( channel )->GetEndTime();
   3261 		if ( worldModel.GetEntity() ) {
   3262 			anim = worldModel.GetEntity()->GetAnimator()->GetAnim( animname );
   3263 			if ( anim ) {
   3264 				worldModel.GetEntity()->GetAnimator()->PlayAnim( channel, anim, gameLocal.time, FRAME2MS( animBlendFrames ) );
   3265 			}
   3266 		}
   3267 	}
   3268 	animBlendFrames = 0;
   3269 	idThread::ReturnInt( 0 );
   3270 }
   3271 
   3272 /*
   3273 ===============
   3274 idWeapon::Event_PlayCycle
   3275 ===============
   3276 */
   3277 void idWeapon::Event_PlayCycle( int channel, const char *animname ) {
   3278 	int anim;
   3279 
   3280 	anim = animator.GetAnim( animname );
   3281 	if ( !anim ) {
   3282 		gameLocal.Warning( "missing '%s' animation on '%s' (%s)", animname, name.c_str(), GetEntityDefName() );
   3283 		animator.Clear( channel, gameLocal.time, FRAME2MS( animBlendFrames ) );
   3284 		animDoneTime = 0;
   3285 	} else {
   3286 		if ( !( owner && owner->GetInfluenceLevel() ) ) {
   3287 			Show();
   3288 		}
   3289 		animator.CycleAnim( channel, anim, gameLocal.time, FRAME2MS( animBlendFrames ) );
   3290 		animDoneTime = animator.CurrentAnim( channel )->GetEndTime();
   3291 		if ( worldModel.GetEntity() ) {
   3292 			anim = worldModel.GetEntity()->GetAnimator()->GetAnim( animname );
   3293 			worldModel.GetEntity()->GetAnimator()->CycleAnim( channel, anim, gameLocal.time, FRAME2MS( animBlendFrames ) );
   3294 		}
   3295 	}
   3296 	animBlendFrames = 0;
   3297 	idThread::ReturnInt( 0 );
   3298 }
   3299 
   3300 /*
   3301 ===============
   3302 idWeapon::Event_AnimDone
   3303 ===============
   3304 */
   3305 void idWeapon::Event_AnimDone( int channel, int blendFrames ) {
   3306 	if ( animDoneTime - FRAME2MS( blendFrames ) <= gameLocal.time ) {
   3307 		idThread::ReturnInt( true );
   3308 	} else {
   3309 		idThread::ReturnInt( false );
   3310 	}
   3311 }
   3312 
   3313 /*
   3314 ===============
   3315 idWeapon::Event_SetBlendFrames
   3316 ===============
   3317 */
   3318 void idWeapon::Event_SetBlendFrames( int channel, int blendFrames ) {
   3319 	animBlendFrames = blendFrames;
   3320 }
   3321 
   3322 /*
   3323 ===============
   3324 idWeapon::Event_GetBlendFrames
   3325 ===============
   3326 */
   3327 void idWeapon::Event_GetBlendFrames( int channel ) {
   3328 	idThread::ReturnInt( animBlendFrames );
   3329 }
   3330 
   3331 /*
   3332 ================
   3333 idWeapon::Event_Next
   3334 ================
   3335 */
   3336 void idWeapon::Event_Next() {
   3337 	// change to another weapon if possible
   3338 	owner->NextBestWeapon();
   3339 }
   3340 
   3341 /*
   3342 ================
   3343 idWeapon::Event_SetSkin
   3344 ================
   3345 */
   3346 void idWeapon::Event_SetSkin( const char *skinname ) {
   3347 	const idDeclSkin *skinDecl = NULL;
   3348 	if ( !skinname || !skinname[ 0 ] ) {
   3349 		skinDecl = NULL;
   3350 	} else {
   3351 		skinDecl = declManager->FindSkin( skinname );
   3352 	}
   3353 
   3354 	// Don't update if the skin hasn't changed.
   3355 	if ( renderEntity.customSkin == skinDecl && worldModel.GetEntity() != NULL && worldModel.GetEntity()->GetSkin() == skinDecl ) {
   3356 		return;
   3357 	}
   3358 
   3359 	renderEntity.customSkin = skinDecl;
   3360 	UpdateVisuals();
   3361 
   3362 	if ( worldModel.GetEntity() ) {
   3363 		worldModel.GetEntity()->SetSkin( skinDecl );
   3364 	}
   3365 
   3366 	// Hack, don't send message if flashlight, because clients process the flashlight instantly.
   3367 	if ( common->IsServer() && !isPlayerFlashlight ) {
   3368 		idBitMsg			msg;
   3369 		byte				msgBuf[MAX_EVENT_PARAM_SIZE];
   3370 
   3371 		msg.InitWrite( msgBuf, sizeof( msgBuf ) );
   3372 		msg.WriteLong( ( skinDecl != NULL ) ? gameLocal.ServerRemapDecl( -1, DECL_SKIN, skinDecl->Index() ) : -1 );
   3373 		ServerSendEvent( EVENT_CHANGESKIN, &msg, false );
   3374 	}
   3375 }
   3376 
   3377 /*
   3378 ================
   3379 idWeapon::Event_Flashlight
   3380 ================
   3381 */
   3382 void idWeapon::Event_Flashlight( int enable ) {
   3383 	if ( enable ) {
   3384 		lightOn = true;
   3385 		MuzzleFlashLight();
   3386 	} else {
   3387 		lightOn = false;
   3388 		muzzleFlashEnd = 0;
   3389 	}
   3390 }
   3391 
   3392 /*
   3393 ================
   3394 idWeapon::Event_GetLightParm
   3395 ================
   3396 */
   3397 void idWeapon::Event_GetLightParm( int parmnum ) {
   3398 	if ( ( parmnum < 0 ) || ( parmnum >= MAX_ENTITY_SHADER_PARMS ) ) {
   3399 		gameLocal.Error( "shader parm index (%d) out of range", parmnum );
   3400 		return;
   3401 	}
   3402 
   3403 	idThread::ReturnFloat( muzzleFlash.shaderParms[ parmnum ] );
   3404 }
   3405 
   3406 /*
   3407 ================
   3408 idWeapon::Event_SetLightParm
   3409 ================
   3410 */
   3411 void idWeapon::Event_SetLightParm( int parmnum, float value ) {
   3412 	if ( ( parmnum < 0 ) || ( parmnum >= MAX_ENTITY_SHADER_PARMS ) ) {
   3413 		gameLocal.Error( "shader parm index (%d) out of range", parmnum );
   3414 		return;
   3415 	}
   3416 
   3417 	muzzleFlash.shaderParms[ parmnum ]		= value;
   3418 	worldMuzzleFlash.shaderParms[ parmnum ]	= value;
   3419 	UpdateVisuals();
   3420 }
   3421 
   3422 /*
   3423 ================
   3424 idWeapon::Event_SetLightParms
   3425 ================
   3426 */
   3427 void idWeapon::Event_SetLightParms( float parm0, float parm1, float parm2, float parm3 ) {
   3428 	muzzleFlash.shaderParms[ SHADERPARM_RED ]			= parm0;
   3429 	muzzleFlash.shaderParms[ SHADERPARM_GREEN ]			= parm1;
   3430 	muzzleFlash.shaderParms[ SHADERPARM_BLUE ]			= parm2;
   3431 	muzzleFlash.shaderParms[ SHADERPARM_ALPHA ]			= parm3;
   3432 
   3433 	worldMuzzleFlash.shaderParms[ SHADERPARM_RED ]		= parm0;
   3434 	worldMuzzleFlash.shaderParms[ SHADERPARM_GREEN ]	= parm1;
   3435 	worldMuzzleFlash.shaderParms[ SHADERPARM_BLUE ]		= parm2;
   3436 	worldMuzzleFlash.shaderParms[ SHADERPARM_ALPHA ]	= parm3;
   3437 
   3438 	UpdateVisuals();
   3439 }
   3440 
   3441 /*
   3442 ================
   3443 idWeapon::Event_Grabber
   3444 ================
   3445 */
   3446 void idWeapon::Event_Grabber( int enable ) {
   3447 	if ( enable ) {
   3448 		grabberState = 0;
   3449 	} else {
   3450 		grabberState = -1;
   3451 	}
   3452 }
   3453 
   3454 /*
   3455 ================
   3456 idWeapon::Event_GrabberHasTarget
   3457 ================
   3458 */
   3459 void idWeapon::Event_GrabberHasTarget() {
   3460 	idThread::ReturnInt( grabberState );
   3461 }
   3462 
   3463 /*
   3464 ================
   3465 idWeapon::Event_GrabberSetGrabDistance
   3466 ================
   3467 */
   3468 void idWeapon::Event_GrabberSetGrabDistance( float dist ) {
   3469 
   3470 	grabber.SetDragDistance( dist );
   3471 }
   3472 
   3473 /*
   3474 ================
   3475 idWeapon::Event_CreateProjectile
   3476 ================
   3477 */
   3478 void idWeapon::Event_CreateProjectile() {
   3479 	if ( !common->IsClient() ) {
   3480 		projectileEnt = NULL;
   3481 		gameLocal.SpawnEntityDef( projectileDict, &projectileEnt, false );
   3482 		if ( projectileEnt ) {
   3483 			projectileEnt->SetOrigin( GetPhysics()->GetOrigin() );
   3484 			projectileEnt->Bind( owner, false );
   3485 			projectileEnt->Hide();
   3486 		}
   3487 		idThread::ReturnEntity( projectileEnt );
   3488 	} else {
   3489 		idThread::ReturnEntity( NULL );
   3490 	}
   3491 }
   3492 
   3493 /*
   3494 ================
   3495 idWeapon::GetProjectileLaunchOriginAndAxis
   3496 ================
   3497 */
   3498 void idWeapon::GetProjectileLaunchOriginAndAxis( idVec3 & origin, idMat3 & axis ) {
   3499 	assert( owner != NULL );
   3500 	
   3501 	// calculate the muzzle position
   3502 	if ( barrelJointView != INVALID_JOINT && projectileDict.GetBool( "launchFromBarrel" ) ) {
   3503 		// there is an explicit joint for the muzzle
   3504 		// GetGlobalJointTransform( true, barrelJointView, muzzleOrigin, muzzleAxis );
   3505 		GetMuzzlePositionWithHacks( origin, axis );
   3506 	} else {
   3507 		// go straight out of the view
   3508 		origin = playerViewOrigin;
   3509 		axis = playerViewAxis;
   3510 	}
   3511 
   3512 	axis = playerViewAxis;	// Fix for plasma rifle not firing correctly on initial shot of a burst fire
   3513 }
   3514 
   3515 /*
   3516 ================
   3517 idWeapon::Event_LaunchProjectiles
   3518 ================
   3519 */
   3520 void idWeapon::Event_LaunchProjectiles( int num_projectiles, float spread, float fuseOffset, float launchPower, float dmgPower ) {
   3521 	idProjectile	*proj;
   3522 	idEntity		*ent;
   3523 	int				i;
   3524 	idVec3			dir;
   3525 	float			ang;
   3526 	float			spin;
   3527 	float			distance;
   3528 	trace_t			tr;
   3529 	idVec3			start;
   3530 	idVec3			muzzle_pos;
   3531 	idBounds		ownerBounds, projBounds;
   3532 
   3533 	assert( owner != NULL );
   3534 
   3535 	if ( IsHidden() ) {
   3536 		return;
   3537 	}
   3538 
   3539 	if ( !projectileDict.GetNumKeyVals() ) {
   3540 		const char *classname = weaponDef->dict.GetString( "classname" );
   3541 		gameLocal.Warning( "No projectile defined on '%s'", classname );
   3542 		return;
   3543 	}
   3544 
   3545 	// Predict clip ammo on locally controlled MP clients.
   3546 	if ( common->IsServer() || owner->IsLocallyControlled() ) {
   3547 		if ( ( clipSize != 0 ) && ( ammoClip.Get() <= 0 ) ) {
   3548 			return;
   3549 		}
   3550 
   3551 		// if this is a power ammo weapon ( currently only the bfg ) then make sure 
   3552 		// we only fire as much power as available in each clip
   3553 		if ( powerAmmo ) {
   3554 			// power comes in as a float from zero to max
   3555 			// if we use this on more than the bfg will need to define the max
   3556 			// in the .def as opposed to just in the script so proper calcs
   3557 			// can be done here. 
   3558 			dmgPower = ( int )dmgPower + 1;
   3559 			if ( dmgPower > ammoClip.Get() ) {
   3560 				dmgPower = ammoClip.Get();
   3561 			}
   3562 		}
   3563 
   3564 		if(clipSize == 0) {
   3565 			//Weapons with a clip size of 0 launch straight from inventory without moving to a clip
   3566 
   3567 			//In D3XP we used the ammo when the ammo was moved into the clip so we don't want to
   3568 			//use it now.
   3569 			owner->inventory.UseAmmo( ammoType, ( powerAmmo ) ? dmgPower : ammoRequired );
   3570 		}
   3571 
   3572 		if ( clipSize && ammoRequired && !g_infiniteAmmo.GetBool() ) {
   3573 			ammoClip -= powerAmmo ? dmgPower : ammoRequired;
   3574 		}
   3575 	}
   3576 
   3577 	if ( !silent_fire ) {
   3578 		// wake up nearby monsters
   3579 		gameLocal.AlertAI( owner );
   3580 	}
   3581 
   3582 	// set the shader parm to the time of last projectile firing,
   3583 	// which the gun material shaders can reference for single shot barrel glows, etc
   3584 	renderEntity.shaderParms[ SHADERPARM_DIVERSITY ]	= gameLocal.random.CRandomFloat();
   3585 	renderEntity.shaderParms[ SHADERPARM_TIMEOFFSET ]	= -MS2SEC( gameLocal.realClientTime );
   3586 
   3587 	if ( worldModel.GetEntity() ) {
   3588 		worldModel.GetEntity()->SetShaderParm( SHADERPARM_DIVERSITY, renderEntity.shaderParms[ SHADERPARM_DIVERSITY ] );
   3589 		worldModel.GetEntity()->SetShaderParm( SHADERPARM_TIMEOFFSET, renderEntity.shaderParms[ SHADERPARM_TIMEOFFSET ] );
   3590 	}
   3591 
   3592 	// calculate the muzzle position
   3593 	GetProjectileLaunchOriginAndAxis( muzzleOrigin, muzzleAxis );
   3594 
   3595 	// add some to the kick time, incrementally moving repeat firing weapons back
   3596 	if ( kick_endtime < gameLocal.realClientTime ) {
   3597 		kick_endtime = gameLocal.realClientTime;
   3598 	}
   3599 	kick_endtime += muzzle_kick_time;
   3600 	if ( kick_endtime > gameLocal.realClientTime + muzzle_kick_maxtime ) {
   3601 		kick_endtime = gameLocal.realClientTime + muzzle_kick_maxtime;
   3602 	}
   3603 
   3604 	// "Predict" damage effects on clients by just spawning a local projectile that deals no damage. Used only
   3605 	// for sound & visual effects. Damage will be handled through reliable messages to the host.
   3606 	const bool isHitscan = projectileDict.GetBool( "net_instanthit" );
   3607 	const bool attackerIsLocal = owner->IsLocallyControlled();
   3608 	const bool actuallySpawnProjectile = common->IsServer() || attackerIsLocal || isHitscan;
   3609 
   3610 	if ( actuallySpawnProjectile ) {
   3611 		
   3612 		ownerBounds = owner->GetPhysics()->GetAbsBounds();
   3613 
   3614 		owner->AddProjectilesFired( num_projectiles );
   3615 
   3616 		float spreadRad = DEG2RAD( spread );
   3617 		for( i = 0; i < num_projectiles; i++ ) {
   3618 			ang = idMath::Sin( spreadRad * gameLocal.random.RandomFloat() );
   3619 			spin = (float)DEG2RAD( 360.0f ) * gameLocal.random.RandomFloat();
   3620 			dir = muzzleAxis[ 0 ] + muzzleAxis[ 2 ] * ( ang * idMath::Sin( spin ) ) - muzzleAxis[ 1 ] * ( ang * idMath::Cos( spin ) );
   3621 			dir.Normalize();
   3622 
   3623 			if ( projectileEnt ) {
   3624 				ent = projectileEnt;
   3625 				ent->Show();
   3626 				ent->Unbind();
   3627 				projectileEnt = NULL;
   3628 			} else {
   3629 				if ( common->IsClient() ) {
   3630 					// This is predicted on a client, don't replicate.
   3631 					// Must be set before spawn, so that the entity can be spawned into the correct area of the entities array.
   3632 					projectileDict.SetBool( "net_skip_replication", true );
   3633 				} else {
   3634 					projectileDict.SetBool( "net_skip_replication", false );
   3635 				}
   3636 				gameLocal.SpawnEntityDef( projectileDict, &ent, false );
   3637 			}
   3638 
   3639 			if ( ent == NULL || !ent->IsType( idProjectile::Type ) ) {
   3640 				const char *projectileName = weaponDef->dict.GetString( "def_projectile" );
   3641 				gameLocal.Error( "'%s' is not an idProjectile", projectileName );
   3642 				return;
   3643 			}
   3644 
   3645 			int predictedKey = idEntity::INVALID_PREDICTION_KEY;
   3646 
   3647 			if ( projectileDict.GetBool( "net_instanthit" ) ) {
   3648 				// don't synchronize this on top of the already predicted effect
   3649 				ent->fl.networkSync = false;
   3650 			} else if ( owner != NULL ) {
   3651 				// Set the prediction key only for non-instanthit projectiles. 
   3652 				if ( common->IsClient() ) {
   3653 					owner->IncrementFireCount();	
   3654 				}
   3655 				predictedKey = gameLocal.GeneratePredictionKey( this, owner, -1 );
   3656 				ent->SetPredictedKey( predictedKey );
   3657 			}
   3658 
   3659 			proj = static_cast<idProjectile *>(ent);
   3660 			proj->Create( owner, muzzleOrigin, dir );
   3661 
   3662 			projBounds = proj->GetPhysics()->GetBounds().Rotate( proj->GetPhysics()->GetAxis() );
   3663 
   3664 			// make sure the projectile starts inside the bounding box of the owner
   3665 			if ( i == 0 ) {
   3666 				muzzle_pos = muzzleOrigin + muzzleAxis[ 0 ] * 2.0f;
   3667 				if ( ( ownerBounds - projBounds).RayIntersection( muzzle_pos, muzzleAxis[0], distance ) ) {
   3668 					start = muzzle_pos + distance * muzzleAxis[0];
   3669 				} else {
   3670 					start = ownerBounds.GetCenter();
   3671 				}
   3672 				gameLocal.clip.Translation( tr, start, muzzle_pos, proj->GetPhysics()->GetClipModel(), proj->GetPhysics()->GetClipModel()->GetAxis(), MASK_SHOT_RENDERMODEL, owner );
   3673 				muzzle_pos = tr.endpos;
   3674 			}
   3675 
   3676 			// If this is the server simulating a remote client, the client has spawned the projectile in the past.
   3677 			// The server will catch-up the projectile so that its position will be as if the projectile had spawned
   3678 			// when the client fired it.
   3679 			if ( common->IsServer() && owner != NULL && !owner->IsLocallyControlled() && !projectileDict.GetBool( "net_instanthit" ) ) {
   3680 				int serverTimeOnClient = owner->usercmd.serverGameMilliseconds;
   3681 
   3682 				int delta = idMath::ClampInt( 0, cg_projectile_clientAuthoritative_maxCatchup.GetInteger(), gameLocal.GetServerGameTimeMs() - serverTimeOnClient );
   3683 
   3684 				int startTime = gameLocal.GetServerGameTimeMs() - delta;
   3685 
   3686 				proj->Launch( muzzle_pos, dir, pushVelocity, fuseOffset, launchPower, dmgPower );
   3687 
   3688 				// predictively spawned, but no need to simulate - was needed for correct processing of client mines when spawned on the server (because we're futzing with the clip models)
   3689 				proj->QueueToSimulate( startTime );
   3690 
   3691 				if ( cg_predictedSpawn_debug.GetBool() ) {
   3692 					idLib::Printf( "Spawning throw item projectile for player %d. PredictiveKey: %d \n", owner->GetEntityNumber(), predictedKey );
   3693 				}
   3694 			} else {
   3695 				// Normal launch
   3696 				proj->Launch( muzzle_pos, dir, pushVelocity, fuseOffset, launchPower, dmgPower );
   3697 			}
   3698 		}
   3699 
   3700 		// toss the brass
   3701 		if ( brassDelay >= 0 ) {
   3702 			PostEventMS( &EV_Weapon_EjectBrass, brassDelay );
   3703 		}
   3704 	}
   3705 
   3706 	// add the light for the muzzleflash
   3707 	if ( !lightOn ) {
   3708 		MuzzleFlashLight();
   3709 	}
   3710 
   3711 	owner->WeaponFireFeedback( &weaponDef->dict );
   3712 
   3713 	// reset muzzle smoke
   3714 	weaponSmokeStartTime = gameLocal.realClientTime;
   3715 }
   3716 
   3717 /*
   3718 ================
   3719 idWeapon::Event_LaunchProjectilesEllipse
   3720 ================
   3721 */
   3722 void idWeapon::Event_LaunchProjectilesEllipse( int num_projectiles, float spreada, float spreadb, float fuseOffset, float power ) {
   3723 	idProjectile	*proj;
   3724 	idEntity		*ent;
   3725 	int				i;
   3726 	idVec3			dir;
   3727 	float			anga, angb;
   3728 	float			spin;
   3729 	float			distance;
   3730 	trace_t			tr;
   3731 	idVec3			start;
   3732 	idVec3			muzzle_pos;
   3733 	idBounds		ownerBounds, projBounds;
   3734 
   3735 	if ( IsHidden() ) {
   3736 		return;
   3737 	}
   3738 
   3739 	if ( !projectileDict.GetNumKeyVals() ) {
   3740 		const char *classname = weaponDef->dict.GetString( "classname" );
   3741 		gameLocal.Warning( "No projectile defined on '%s'", classname );
   3742 		return;
   3743 	}
   3744 
   3745 	// avoid all ammo considerations on a client
   3746 	if ( !common->IsClient() ) {
   3747 		if ( ( clipSize != 0 ) && ( ammoClip.Get() <= 0 ) ) {
   3748 			return;
   3749 		}
   3750 
   3751 		if( clipSize == 0 ) {
   3752 			//Weapons with a clip size of 0 launch strait from inventory without moving to a clip
   3753 			owner->inventory.UseAmmo( ammoType, ammoRequired );
   3754 		}
   3755 
   3756 		if ( clipSize && ammoRequired ) {
   3757 			ammoClip -= ammoRequired;
   3758 		}
   3759 
   3760 		if ( !silent_fire ) {
   3761 			// wake up nearby monsters
   3762 			gameLocal.AlertAI( owner );
   3763 		}
   3764 
   3765 	}
   3766 
   3767 	// set the shader parm to the time of last projectile firing,
   3768 	// which the gun material shaders can reference for single shot barrel glows, etc
   3769 	renderEntity.shaderParms[ SHADERPARM_DIVERSITY ]	= gameLocal.random.CRandomFloat();
   3770 	renderEntity.shaderParms[ SHADERPARM_TIMEOFFSET ]	= -MS2SEC( gameLocal.time );
   3771 
   3772 	if ( worldModel.GetEntity() ) {
   3773 		worldModel.GetEntity()->SetShaderParm( SHADERPARM_DIVERSITY, renderEntity.shaderParms[ SHADERPARM_DIVERSITY ] );
   3774 		worldModel.GetEntity()->SetShaderParm( SHADERPARM_TIMEOFFSET, renderEntity.shaderParms[ SHADERPARM_TIMEOFFSET ] );
   3775 	}
   3776 
   3777 	// calculate the muzzle position
   3778 	if ( barrelJointView != INVALID_JOINT && projectileDict.GetBool( "launchFromBarrel" ) ) {
   3779 		// there is an explicit joint for the muzzle
   3780 		GetGlobalJointTransform( true, barrelJointView, muzzleOrigin, muzzleAxis );
   3781 	} else {
   3782 		// go straight out of the view
   3783 		muzzleOrigin = playerViewOrigin;
   3784 		muzzleAxis = playerViewAxis;
   3785 	}
   3786 
   3787 	// add some to the kick time, incrementally moving repeat firing weapons back
   3788 	if ( kick_endtime < gameLocal.time ) {
   3789 		kick_endtime = gameLocal.time;
   3790 	}
   3791 	kick_endtime += muzzle_kick_time;
   3792 	if ( kick_endtime > gameLocal.time + muzzle_kick_maxtime ) {
   3793 		kick_endtime = gameLocal.time + muzzle_kick_maxtime;
   3794 	}
   3795 
   3796 	if ( !common->IsClient() ) {
   3797 		ownerBounds = owner->GetPhysics()->GetAbsBounds();
   3798 
   3799 		owner->AddProjectilesFired( num_projectiles );
   3800 
   3801 		float spreadRadA = DEG2RAD( spreada );
   3802 		float spreadRadB = DEG2RAD( spreadb );
   3803 
   3804 		for( i = 0; i < num_projectiles; i++ ) {
   3805 			//Ellipse Form
   3806 			spin = (float)DEG2RAD( 360.0f ) * gameLocal.random.RandomFloat();
   3807 			anga = idMath::Sin(spreadRadA * gameLocal.random.RandomFloat());
   3808 			angb = idMath::Sin(spreadRadB * gameLocal.random.RandomFloat());
   3809 			dir = playerViewAxis[ 0 ] + playerViewAxis[ 2 ] * ( angb*idMath::Sin( spin ) ) - playerViewAxis[ 1 ] * ( anga*idMath::Cos( spin ) );
   3810 			dir.Normalize();
   3811 
   3812 			gameLocal.SpawnEntityDef( projectileDict, &ent );
   3813 			if ( ent == NULL || !ent->IsType( idProjectile::Type ) ) {
   3814 				const char *projectileName = weaponDef->dict.GetString( "def_projectile" );
   3815 				gameLocal.Error( "'%s' is not an idProjectile", projectileName );
   3816 				return;
   3817 			}
   3818 
   3819 			proj = static_cast<idProjectile *>(ent);
   3820 			proj->Create( owner, muzzleOrigin, dir );
   3821 
   3822 			projBounds = proj->GetPhysics()->GetBounds().Rotate( proj->GetPhysics()->GetAxis() );
   3823 
   3824 			// make sure the projectile starts inside the bounding box of the owner
   3825 			if ( i == 0 ) {
   3826 				muzzle_pos = muzzleOrigin + playerViewAxis[ 0 ] * 2.0f;
   3827 				if ( ( ownerBounds - projBounds).RayIntersection( muzzle_pos, playerViewAxis[0], distance ) ) {
   3828 					start = muzzle_pos + distance * playerViewAxis[0];
   3829 				}
   3830 				else {
   3831 					start = ownerBounds.GetCenter();
   3832 				}
   3833 				gameLocal.clip.Translation( tr, start, muzzle_pos, proj->GetPhysics()->GetClipModel(), proj->GetPhysics()->GetClipModel()->GetAxis(), MASK_SHOT_RENDERMODEL, owner );
   3834 				muzzle_pos = tr.endpos;
   3835 			}
   3836 
   3837 			proj->Launch( muzzle_pos, dir, pushVelocity, fuseOffset, power );
   3838 		}
   3839 
   3840 		// toss the brass
   3841 		if( brassDelay >= 0 ) {
   3842 			PostEventMS( &EV_Weapon_EjectBrass, brassDelay );
   3843 		}
   3844 	}
   3845 
   3846 	// add the light for the muzzleflash
   3847 	if ( !lightOn ) {
   3848 		MuzzleFlashLight();
   3849 	}
   3850 
   3851 	owner->WeaponFireFeedback( &weaponDef->dict );
   3852 
   3853 	// reset muzzle smoke
   3854 	weaponSmokeStartTime = gameLocal.time;
   3855 
   3856 }
   3857 
   3858 /** 
   3859 * Gives the player a powerup as if it were a weapon shot. It will use the ammo amount specified
   3860 * as ammoRequired.
   3861 */
   3862 void idWeapon::Event_LaunchPowerup( const char* powerup, float duration, int useAmmo ) {
   3863 
   3864 	if ( IsHidden() ) {
   3865 		return; 
   3866 	}
   3867 
   3868 	// check if we're out of ammo
   3869 	if(useAmmo) {
   3870 		int ammoAvail = owner->inventory.HasAmmo( ammoType, ammoRequired );
   3871 		if ( !ammoAvail ) {
   3872 			return;
   3873 		}
   3874 		owner->inventory.UseAmmo( ammoType, ammoRequired );
   3875 	}
   3876 
   3877 	// set the shader parm to the time of last projectile firing,
   3878 	// which the gun material shaders can reference for single shot barrel glows, etc
   3879 	renderEntity.shaderParms[ SHADERPARM_DIVERSITY ]	= gameLocal.random.CRandomFloat();
   3880 	renderEntity.shaderParms[ SHADERPARM_TIMEOFFSET ]	= -MS2SEC( gameLocal.time );
   3881 
   3882 	if ( worldModel.GetEntity() ) {
   3883 		worldModel.GetEntity()->SetShaderParm( SHADERPARM_DIVERSITY, renderEntity.shaderParms[ SHADERPARM_DIVERSITY ] );
   3884 		worldModel.GetEntity()->SetShaderParm( SHADERPARM_TIMEOFFSET, renderEntity.shaderParms[ SHADERPARM_TIMEOFFSET ] );
   3885 	}
   3886 
   3887 	// add the light for the muzzleflash
   3888 	if ( !lightOn ) {
   3889 		MuzzleFlashLight();
   3890 	}
   3891 
   3892 	owner->Give(powerup, va("%f", duration), ITEM_GIVE_FEEDBACK | ITEM_GIVE_UPDATE_STATE | ITEM_GIVE_FROM_WEAPON );
   3893 
   3894 
   3895 }
   3896 
   3897 void idWeapon::Event_StartWeaponSmoke() {
   3898 
   3899 	// reset muzzle smoke
   3900 	weaponSmokeStartTime = gameLocal.time;
   3901 }
   3902 
   3903 void idWeapon::Event_StopWeaponSmoke() {
   3904 
   3905 	// reset muzzle smoke
   3906 	weaponSmokeStartTime = 0;
   3907 }
   3908 
   3909 void idWeapon::Event_StartWeaponParticle( const char* name) {
   3910 	WeaponParticle_t* part;
   3911 	weaponParticles.Get(name, &part);
   3912 	if(part) {
   3913 		part->active = true;
   3914 		part->startTime = gameLocal.time;
   3915 
   3916 		//Toggle the emitter
   3917 		if( !part->smoke && part->emitter != NULL ) {
   3918 			part->emitter->Show();
   3919 			part->emitter->PostEventMS(&EV_Activate, 0, this);
   3920 		}
   3921 	}
   3922 }
   3923 
   3924 void idWeapon::Event_StopWeaponParticle( const char* name) {
   3925 	WeaponParticle_t* part;
   3926 	weaponParticles.Get(name, &part);
   3927 	if(part) {
   3928 		part->active = false;
   3929 		part->startTime = 0;
   3930 
   3931 		//Toggle the emitter
   3932 		if(!part->smoke) {
   3933 			if ( part->emitter != NULL ) {
   3934 				part->emitter->Hide();
   3935 				part->emitter->PostEventMS(&EV_Activate, 0, this);
   3936 			}
   3937 		}
   3938 	}
   3939 }
   3940 
   3941 void idWeapon::Event_StartWeaponLight( const char* name) {
   3942 	WeaponLight_t* light;
   3943 	weaponLights.Get(name, &light);
   3944 	if(light) {
   3945 		light->active = true;
   3946 		light->startTime = gameLocal.time;
   3947 	}
   3948 }
   3949 
   3950 void idWeapon::Event_StopWeaponLight( const char* name) {
   3951 	WeaponLight_t* light;
   3952 	weaponLights.Get(name, &light);
   3953 	if(light) {
   3954 		light->active = false;
   3955 		light->startTime = 0;
   3956 		if(light->lightHandle != -1) {
   3957 			gameRenderWorld->FreeLightDef( light->lightHandle );
   3958 			light->lightHandle = -1;
   3959 		}
   3960 	}
   3961 }
   3962 /*
   3963 =====================
   3964 idWeapon::Event_Melee
   3965 =====================
   3966 */
   3967 void idWeapon::Event_Melee() {
   3968 	idEntity	*ent;
   3969 	trace_t		tr;
   3970 
   3971 	if ( weaponDef == NULL ) {
   3972 		gameLocal.Error( "No weaponDef on '%s'", this->GetName() );
   3973 		return;
   3974 	}
   3975 
   3976 	if ( meleeDef == NULL ) {
   3977 		gameLocal.Error( "No meleeDef on '%s'", weaponDef->dict.GetString( "classname" ) );
   3978 		return;
   3979 	}
   3980 
   3981 	if ( !common->IsClient() ) {
   3982 		idVec3 start = playerViewOrigin;
   3983 		idVec3 end = start + playerViewAxis[0] * ( meleeDistance * owner->PowerUpModifier( MELEE_DISTANCE ) );
   3984 		gameLocal.clip.TracePoint( tr, start, end, MASK_SHOT_RENDERMODEL, owner );
   3985 		if ( tr.fraction < 1.0f ) {
   3986 			ent = gameLocal.GetTraceEntity( tr );
   3987 		} else {
   3988 			ent = NULL;
   3989 		}
   3990 
   3991 		if ( g_debugWeapon.GetBool() ) {
   3992 			gameRenderWorld->DebugLine( colorYellow, start, end, 100 );
   3993 			if ( ent != NULL ) {
   3994 				gameRenderWorld->DebugBounds( colorRed, ent->GetPhysics()->GetBounds(), ent->GetPhysics()->GetOrigin(), 100 );
   3995 			}
   3996 		}
   3997 
   3998 		bool hit = false;
   3999 		const char *hitSound = meleeDef->dict.GetString( "snd_miss" );
   4000 
   4001 		if ( ent != NULL ) {
   4002 
   4003 			float push = meleeDef->dict.GetFloat( "push" );
   4004 			idVec3 impulse = -push * owner->PowerUpModifier( SPEED ) * tr.c.normal;
   4005 
   4006 			if ( gameLocal.world->spawnArgs.GetBool( "no_Weapons" ) && ( ent->IsType( idActor::Type ) || ent->IsType( idAFAttachment::Type) ) ) {
   4007 				idThread::ReturnInt( 0 );
   4008 				return;
   4009 			}
   4010 
   4011 			ent->ApplyImpulse( this, tr.c.id, tr.c.point, impulse );
   4012 
   4013 			// weapon stealing - do this before damaging so weapons are not dropped twice
   4014 			if ( common->IsMultiplayer()
   4015 				&& weaponDef->dict.GetBool( "stealing" )
   4016 				&& ent->IsType( idPlayer::Type )
   4017 				&& !owner->PowerUpActive( BERSERK )
   4018 				&& ( (gameLocal.gameType != GAME_TDM ) || gameLocal.serverInfo.GetBool( "si_teamDamage" ) || ( owner->team != static_cast< idPlayer * >( ent )->team ) )
   4019 				) {
   4020                 
   4021                 if ( !gameLocal.mpGame.IsGametypeFlagBased() ) {
   4022 					owner->StealWeapon( static_cast< idPlayer * >( ent ) );
   4023 				}
   4024 			}
   4025 
   4026 			if ( ent->fl.takedamage ) {
   4027 				idVec3 kickDir, globalKickDir;
   4028 				meleeDef->dict.GetVector( "kickDir", "0 0 0", kickDir );
   4029 				globalKickDir = muzzleAxis * kickDir;
   4030 				//Adjust the melee powerup modifier for the invulnerability boss fight
   4031 				float mod = owner->PowerUpModifier( MELEE_DAMAGE );
   4032 				if(!strcmp(ent->GetEntityDefName(), "monster_hunter_invul")) {
   4033 					//Only do a quater of the damage mod
   4034 					mod *= 0.25f;
   4035 				}
   4036 				ent->Damage( owner, owner, globalKickDir, meleeDefName, mod, tr.c.id );
   4037 				hit = true;
   4038 			}
   4039 
   4040 			if ( weaponDef->dict.GetBool( "impact_damage_effect" ) ) {
   4041 
   4042 				if ( ent->spawnArgs.GetBool( "bleed" ) ) {
   4043 
   4044 					hitSound = meleeDef->dict.GetString( owner->PowerUpActive( BERSERK ) ? "snd_hit_berserk" : "snd_hit" );
   4045 
   4046 					ent->AddDamageEffect( tr, impulse, meleeDef->dict.GetString( "classname" ) );
   4047 
   4048 				} else {
   4049 
   4050 					int type = tr.c.material->GetSurfaceType();
   4051 					if ( type == SURFTYPE_NONE ) {
   4052 						type = GetDefaultSurfaceType();
   4053 					}
   4054 
   4055 					const char *materialType = gameLocal.sufaceTypeNames[ type ];
   4056 
   4057 					// start impact sound based on material type
   4058 					hitSound = meleeDef->dict.GetString( va( "snd_%s", materialType ) );
   4059 					if ( *hitSound == '\0' ) {
   4060 						hitSound = meleeDef->dict.GetString( "snd_metal" );
   4061 					}
   4062 
   4063 					if ( gameLocal.time > nextStrikeFx ) {
   4064 						const char *decal;
   4065 						// project decal
   4066 						decal = weaponDef->dict.GetString( "mtr_strike" );
   4067 						if ( decal != NULL && *decal != NULL ) {
   4068 							gameLocal.ProjectDecal( tr.c.point, -tr.c.normal, 8.0f, true, 6.0, decal );
   4069 						}
   4070 						nextStrikeFx = gameLocal.time + 200;
   4071 					} else {
   4072 						hitSound = "";
   4073 					}
   4074 
   4075 					strikeSmokeStartTime = gameLocal.time;
   4076 					strikePos = tr.c.point;
   4077 					strikeAxis = -tr.endAxis;
   4078 				}
   4079 			}
   4080 		}
   4081 
   4082 		if ( *hitSound != '\0' ) {
   4083 			const idSoundShader *snd = declManager->FindSound( hitSound );
   4084 			StartSoundShader( snd, SND_CHANNEL_BODY2, 0, true, NULL );
   4085 		}
   4086 
   4087 		idThread::ReturnInt( hit );
   4088 		owner->WeaponFireFeedback( &weaponDef->dict );
   4089 		return;
   4090 	}
   4091 
   4092 	idThread::ReturnInt( 0 );
   4093 	owner->WeaponFireFeedback( &weaponDef->dict );
   4094 }
   4095 
   4096 /*
   4097 =====================
   4098 idWeapon::Event_GetWorldModel
   4099 =====================
   4100 */
   4101 void idWeapon::Event_GetWorldModel() {
   4102 	idThread::ReturnEntity( worldModel.GetEntity() );
   4103 }
   4104 
   4105 /*
   4106 =====================
   4107 idWeapon::Event_AllowDrop
   4108 =====================
   4109 */
   4110 void idWeapon::Event_AllowDrop( int allow ) {
   4111 	if ( allow ) {
   4112 		allowDrop = true;
   4113 	} else {
   4114 		allowDrop = false;
   4115 	}
   4116 }
   4117 
   4118 /*
   4119 ================
   4120 idWeapon::Event_EjectBrass
   4121 
   4122 Toss a shell model out from the breach if the bone is present
   4123 ================
   4124 */
   4125 void idWeapon::Event_EjectBrass() {
   4126 	if ( !g_showBrass.GetBool() || !owner->CanShowWeaponViewmodel() ) {
   4127 		return;
   4128 	}
   4129 
   4130 	if ( ejectJointView == INVALID_JOINT || !brassDict.GetNumKeyVals() ) {
   4131 		return;
   4132 	}
   4133 
   4134 	if ( common->IsClient() ) {
   4135 		return;
   4136 	}
   4137 
   4138 	idMat3 axis;
   4139 	idVec3 origin, linear_velocity, angular_velocity;
   4140 	idEntity *ent;
   4141 
   4142 	if ( !GetGlobalJointTransform( true, ejectJointView, origin, axis ) ) {
   4143 		return;
   4144 	}
   4145 
   4146 	gameLocal.SpawnEntityDef( brassDict, &ent, false );
   4147 	if ( !ent || !ent->IsType( idDebris::Type ) ) {
   4148 		gameLocal.Error( "'%s' is not an idDebris", weaponDef ? weaponDef->dict.GetString( "def_ejectBrass" ) : "def_ejectBrass" );
   4149 	}
   4150 	idDebris *debris = static_cast<idDebris *>(ent);
   4151 	debris->Create( owner, origin, axis );
   4152 	debris->Launch();
   4153 
   4154 	linear_velocity = 40 * ( playerViewAxis[0] + playerViewAxis[1] + playerViewAxis[2] );
   4155 	angular_velocity.Set( 10 * gameLocal.random.CRandomFloat(), 10 * gameLocal.random.CRandomFloat(), 10 * gameLocal.random.CRandomFloat() );
   4156 
   4157 	debris->GetPhysics()->SetLinearVelocity( linear_velocity );
   4158 	debris->GetPhysics()->SetAngularVelocity( angular_velocity );
   4159 }
   4160 
   4161 /*
   4162 ===============
   4163 idWeapon::Event_IsInvisible
   4164 ===============
   4165 */
   4166 void idWeapon::Event_IsInvisible() {
   4167 	if ( !owner ) {
   4168 		idThread::ReturnFloat( 0 );
   4169 		return;
   4170 	}
   4171 	idThread::ReturnFloat( owner->PowerUpActive( INVISIBILITY ) ? 1 : 0 );
   4172 }
   4173 
   4174 /*
   4175 ===============
   4176 idWeapon::ClientThink
   4177 ===============
   4178 */
   4179 void idWeapon::ClientThink( const int curTime, const float fraction, const bool predict ) {
   4180 	UpdateAnimation();	
   4181 }
   4182 
   4183 /*
   4184 ===============
   4185 idWeapon::ClientPredictionThink
   4186 ===============
   4187 */
   4188 void idWeapon::ClientPredictionThink() {
   4189 	UpdateAnimation();	
   4190 }
   4191 
   4192 
   4193 void idWeapon::ForceAmmoInClip() {
   4194 	ammoClip = clipSize;
   4195 }