/* ================== CG_Buildable ================== */ void CG_Buildable( centity_t *cent ) { refEntity_t ent; entityState_t *es = ¢->currentState; vec3_t angles; vec3_t surfNormal, xNormal, mins, maxs; vec3_t refNormal = { 0.0f, 0.0f, 1.0f }; float rotAngle; buildableTeam_t team = BG_FindTeamForBuildable( es->modelindex ); float scale; int health; float healthScale; //must be before EF_NODRAW check if( team == BIT_ALIENS ) CG_Creep( cent ); // if set to invisible, skip if( es->eFlags & EF_NODRAW ) { if( CG_IsParticleSystemValid( ¢->buildablePS ) ) CG_DestroyParticleSystem( ¢->buildablePS ); return; } memset ( &ent, 0, sizeof( ent ) ); VectorCopy( cent->lerpOrigin, ent.origin ); VectorCopy( cent->lerpOrigin, ent.oldorigin ); VectorCopy( cent->lerpOrigin, ent.lightingOrigin ); VectorCopy( es->origin2, surfNormal ); VectorCopy( es->angles, angles ); BG_FindBBoxForBuildable( es->modelindex, mins, maxs ); if( es->pos.trType == TR_STATIONARY ) CG_PositionAndOrientateBuildable( angles, ent.origin, surfNormal, es->number, mins, maxs, ent.axis, ent.origin ); //offset on the Z axis if required VectorMA( ent.origin, BG_FindZOffsetForBuildable( es->modelindex ), surfNormal, ent.origin ); VectorCopy( ent.origin, ent.oldorigin ); // don't positionally lerp at all VectorCopy( ent.origin, ent.lightingOrigin ); ent.hModel = cg_buildables[ es->modelindex ].models[ 0 ]; if( !( es->generic1 & B_SPAWNED_TOGGLEBIT ) ) { sfxHandle_t prebuildSound = cgs.media.humanBuildablePrebuild; if( team == BIT_HUMANS ) { ent.customShader = cgs.media.humanSpawningShader; prebuildSound = cgs.media.humanBuildablePrebuild; } else if( team == BIT_ALIENS ) prebuildSound = cgs.media.alienBuildablePrebuild; trap_S_AddLoopingSound( es->number, cent->lerpOrigin, vec3_origin, prebuildSound ); } CG_BuildableAnimation( cent, &ent.oldframe, &ent.frame, &ent.backlerp ); //rescale the model scale = BG_FindModelScaleForBuildable( es->modelindex ); if( scale != 1.0f ) { VectorScale( ent.axis[ 0 ], scale, ent.axis[ 0 ] ); VectorScale( ent.axis[ 1 ], scale, ent.axis[ 1 ] ); VectorScale( ent.axis[ 2 ], scale, ent.axis[ 2 ] ); ent.nonNormalizedAxes = qtrue; } else ent.nonNormalizedAxes = qfalse; //add to refresh list trap_R_AddRefEntityToScene( &ent ); CrossProduct( surfNormal, refNormal, xNormal ); VectorNormalize( xNormal ); rotAngle = RAD2DEG( acos( DotProduct( surfNormal, refNormal ) ) ); //turret barrel bit if( cg_buildables[ es->modelindex ].models[ 1 ] ) { refEntity_t turretBarrel; vec3_t flatAxis[ 3 ]; memset( &turretBarrel, 0, sizeof( turretBarrel ) ); turretBarrel.hModel = cg_buildables[ es->modelindex ].models[ 1 ]; CG_PositionEntityOnTag( &turretBarrel, &ent, ent.hModel, "tag_turret" ); VectorCopy( cent->lerpOrigin, turretBarrel.lightingOrigin ); AnglesToAxis( es->angles2, flatAxis ); RotatePointAroundVector( turretBarrel.axis[ 0 ], xNormal, flatAxis[ 0 ], -rotAngle ); RotatePointAroundVector( turretBarrel.axis[ 1 ], xNormal, flatAxis[ 1 ], -rotAngle ); RotatePointAroundVector( turretBarrel.axis[ 2 ], xNormal, flatAxis[ 2 ], -rotAngle ); turretBarrel.oldframe = ent.oldframe; turretBarrel.frame = ent.frame; turretBarrel.backlerp = ent.backlerp; turretBarrel.customShader = ent.customShader; if( scale != 1.0f ) { VectorScale( turretBarrel.axis[ 0 ], scale, turretBarrel.axis[ 0 ] ); VectorScale( turretBarrel.axis[ 1 ], scale, turretBarrel.axis[ 1 ] ); VectorScale( turretBarrel.axis[ 2 ], scale, turretBarrel.axis[ 2 ] ); turretBarrel.nonNormalizedAxes = qtrue; } else turretBarrel.nonNormalizedAxes = qfalse; trap_R_AddRefEntityToScene( &turretBarrel ); } //turret barrel bit if( cg_buildables[ es->modelindex ].models[ 2 ] ) { refEntity_t turretTop; vec3_t flatAxis[ 3 ]; vec3_t swivelAngles; memset( &turretTop, 0, sizeof( turretTop ) ); VectorCopy( es->angles2, swivelAngles ); swivelAngles[ PITCH ] = 0.0f; turretTop.hModel = cg_buildables[ es->modelindex ].models[ 2 ]; CG_PositionRotatedEntityOnTag( &turretTop, &ent, ent.hModel, "tag_turret" ); VectorCopy( cent->lerpOrigin, turretTop.lightingOrigin ); AnglesToAxis( swivelAngles, flatAxis ); RotatePointAroundVector( turretTop.axis[ 0 ], xNormal, flatAxis[ 0 ], -rotAngle ); RotatePointAroundVector( turretTop.axis[ 1 ], xNormal, flatAxis[ 1 ], -rotAngle ); RotatePointAroundVector( turretTop.axis[ 2 ], xNormal, flatAxis[ 2 ], -rotAngle ); turretTop.oldframe = ent.oldframe; turretTop.frame = ent.frame; turretTop.backlerp = ent.backlerp; turretTop.customShader = ent.customShader; if( scale != 1.0f ) { VectorScale( turretTop.axis[ 0 ], scale, turretTop.axis[ 0 ] ); VectorScale( turretTop.axis[ 1 ], scale, turretTop.axis[ 1 ] ); VectorScale( turretTop.axis[ 2 ], scale, turretTop.axis[ 2 ] ); turretTop.nonNormalizedAxes = qtrue; } else turretTop.nonNormalizedAxes = qfalse; trap_R_AddRefEntityToScene( &turretTop ); } //weapon effects for turrets if( es->eFlags & EF_FIRING ) { weaponInfo_t *weapon = &cg_weapons[ es->weapon ]; if( cg.time - cent->muzzleFlashTime > MUZZLE_FLASH_TIME || BG_FindProjTypeForBuildable( es->modelindex ) == WP_TESLAGEN ) { if( weapon->wim[ WPM_PRIMARY ].flashDlightColor[ 0 ] || weapon->wim[ WPM_PRIMARY ].flashDlightColor[ 1 ] || weapon->wim[ WPM_PRIMARY ].flashDlightColor[ 2 ] ) { trap_R_AddLightToScene( cent->lerpOrigin, 300 + ( rand( ) & 31 ), weapon->wim[ WPM_PRIMARY ].flashDlightColor[ 0 ], weapon->wim[ WPM_PRIMARY ].flashDlightColor[ 1 ], weapon->wim[ WPM_PRIMARY ].flashDlightColor[ 2 ] ); } } if( weapon->wim[ WPM_PRIMARY ].firingSound ) { trap_S_AddLoopingSound( es->number, cent->lerpOrigin, vec3_origin, weapon->wim[ WPM_PRIMARY ].firingSound ); } else if( weapon->readySound ) trap_S_AddLoopingSound( es->number, cent->lerpOrigin, vec3_origin, weapon->readySound ); } health = es->generic1 & B_HEALTH_MASK; healthScale = (float)health / B_HEALTH_MASK; if( healthScale < cent->lastBuildableHealthScale && ( es->generic1 & B_SPAWNED_TOGGLEBIT ) ) { if( cent->lastBuildableDamageSoundTime + BUILDABLE_SOUND_PERIOD < cg.time ) { if( team == BIT_HUMANS ) { int i = rand( ) % 4; trap_S_StartSound( NULL, es->number, CHAN_BODY, cgs.media.humanBuildableDamage[ i ] ); } else if( team == BIT_ALIENS ) trap_S_StartSound( NULL, es->number, CHAN_BODY, cgs.media.alienBuildableDamage ); cent->lastBuildableDamageSoundTime = cg.time; } } cent->lastBuildableHealthScale = healthScale; //smoke etc for damaged buildables CG_BuildableParticleEffects( cent ); }
/* =============== CG_AttachmentPoint Return the attachment point =============== */ qboolean CG_AttachmentPoint( attachment_t *a, vec3_t v ) { centity_t *cent; if ( !a ) { return qfalse; } // if it all breaks, then use the last point we know was correct VectorCopy( a->lastValidAttachmentPoint, v ); switch ( a->type ) { case AT_STATIC: if ( !a->staticValid ) { return qfalse; } VectorCopy( a->origin, v ); break; case AT_TAG: if ( !a->tagValid ) { return qfalse; } AxisCopy( axisDefault, a->re.axis ); CG_PositionRotatedEntityOnTag( &a->re, &a->parent, a->model, a->tagName ); VectorCopy( a->re.origin, v ); break; case AT_CENT: if ( !a->centValid ) { return qfalse; } if ( a->centNum == cg.predictedPlayerState.clientNum ) { // this is smoother if it's the local client VectorCopy( cg.predictedPlayerState.origin, v ); } else { cent = &cg_entities[ a->centNum ]; VectorCopy( cent->lerpOrigin, v ); } break; case AT_PARTICLE: if ( !a->particleValid ) { return qfalse; } if ( !a->particle->valid ) { a->particleValid = qfalse; return qfalse; } else { VectorCopy( a->particle->origin, v ); } break; default: CG_Printf( S_COLOR_RED "ERROR: Invalid attachmentType_t in attachment\n" ); break; } if ( a->hasOffset ) { VectorAdd( v, a->offset, v ); } VectorCopy( v, a->lastValidAttachmentPoint ); return qtrue; }
// Used for both the view weapon (ps is valid) and the world modelother character models (ps is NULL) // The main player will have this called for BOTH cases, so effects like light and sound should only be done on the // world model case. void CG_AddPlayerWeapon( refEntity_t *parent, playerState_t *ps, centity_t *cent, int team, vector3 *newAngles, qboolean thirdPerson ) { refEntity_t gun, barrel, flash; vector3 angles; weapon_t weaponNum; weaponInfo_t *weapon; centity_t *nonPredictedCent; if ( !thirdPerson && cg_fakeGun.integer ) { weaponNum = (weapon_t)cg_fakeGun.integer; } else { weaponNum = (weapon_t)cent->currentState.weapon; } if ( weaponNum == WP_EMPLACED_GUN ) return; // spectator mode, don't draw it... if ( cg.predictedPlayerState.pm_type == PM_SPECTATOR && cent->currentState.number == cg.predictedPlayerState.clientNum ) { return; } CG_RegisterWeapon( weaponNum ); weapon = &cg_weapons[weaponNum]; memset( &gun, 0, sizeof(gun) ); // only do this if we are in first person, since world weapons are now handled on the server by Ghoul2 if ( !thirdPerson ) { // add the weapon VectorCopy( &parent->lightingOrigin, &gun.lightingOrigin ); gun.shadowPlane = parent->shadowPlane; gun.renderfx = parent->renderfx; // this player, in first person view if ( ps ) gun.hModel = weapon->viewModel; else gun.hModel = weapon->weaponModel; if ( !gun.hModel ) return; if ( !ps ) { // add weapon ready sound if ( (cent->currentState.eFlags & EF_FIRING) && weapon->firingSound ) { trap->S_AddLoopingSound( cent->currentState.number, ¢->lerpOrigin, &vec3_origin, weapon->firingSound ); } else if ( weapon->readySound ) { trap->S_AddLoopingSound( cent->currentState.number, ¢->lerpOrigin, &vec3_origin, weapon->readySound ); } } CG_PositionEntityOnTag( &gun, parent, parent->hModel, "tag_weapon" ); if ( !CG_IsMindTricked( cent->currentState.trickedEntIndex, cg.snap->ps.clientNum ) ) { // don't draw the weapon if the player is invisible CG_AddWeaponWithPowerups( &gun, cent->currentState.powerups ); } if ( weaponNum == WP_STUN_BATON ) { int i; for ( i = 0; i < 3; i++ ) { memset( &barrel, 0, sizeof(barrel) ); VectorCopy( &parent->lightingOrigin, &barrel.lightingOrigin ); barrel.shadowPlane = parent->shadowPlane; barrel.renderfx = parent->renderfx; if ( i == 0 ) { barrel.hModel = trap->R_RegisterModel( "models/weapons2/stun_baton/baton_barrel.md3" ); } else if ( i == 1 ) { barrel.hModel = trap->R_RegisterModel( "models/weapons2/stun_baton/baton_barrel2.md3" ); } else { barrel.hModel = trap->R_RegisterModel( "models/weapons2/stun_baton/baton_barrel3.md3" ); } angles.yaw = 0; angles.pitch = 0; angles.roll = 0; AnglesToAxis( &angles, barrel.axis ); if ( i == 0 ) { CG_PositionRotatedEntityOnTag( &barrel, parent, weapon->handsModel, "tag_barrel" ); } else if ( i == 1 ) { CG_PositionRotatedEntityOnTag( &barrel, parent, weapon->handsModel, "tag_barrel2" ); } else { CG_PositionRotatedEntityOnTag( &barrel, parent, weapon->handsModel, "tag_barrel3" ); } CG_AddWeaponWithPowerups( &barrel, cent->currentState.powerups ); } } else { // add the spinning barrel if ( weapon->barrelModel ) { memset( &barrel, 0, sizeof(barrel) ); VectorCopy( &parent->lightingOrigin, &barrel.lightingOrigin ); barrel.shadowPlane = parent->shadowPlane; barrel.renderfx = parent->renderfx; barrel.hModel = weapon->barrelModel; angles.yaw = 0; angles.pitch = 0; angles.roll = 0; AnglesToAxis( &angles, barrel.axis ); CG_PositionRotatedEntityOnTag( &barrel, parent, weapon->handsModel, "tag_barrel" ); CG_AddWeaponWithPowerups( &barrel, cent->currentState.powerups ); } } } memset( &flash, 0, sizeof(flash) ); CG_PositionEntityOnTag( &flash, &gun, gun.hModel, "tag_flash" ); VectorCopy( &flash.origin, &cg.lastFPFlashPoint ); // Do special charge bits // Make the guns do their charging visual in True View. if ( (ps || cg.renderingThirdPerson || cg.predictedPlayerState.clientNum != cent->currentState.number || cg_trueGuns.integer) && ((cent->currentState.modelindex2 == WEAPON_CHARGING_ALT && weaponNum == WP_BRYAR_PISTOL) || (cent->currentState.modelindex2 == WEAPON_CHARGING_ALT && weaponNum == WP_BRYAR_OLD) || (weaponNum == WP_BOWCASTER && cent->currentState.modelindex2 == WEAPON_CHARGING) || (weaponNum == WP_DEMP2 && cent->currentState.modelindex2 == WEAPON_CHARGING_ALT)) ) { int shader = 0; float val = 0.0f; float scale = 1.0f; addspriteArgStruct_t fxSArgs; vector3 flashorigin, flashdir; if ( !thirdPerson ) { VectorCopy( &flash.origin, &flashorigin ); VectorCopy( &flash.axis[0], &flashdir ); } else { mdxaBone_t boltMatrix; // it's quite possible that we may have have no weapon model and be in a valid state, so return here if this is the case if ( !trap->G2API_HasGhoul2ModelOnIndex( &(cent->ghoul2), 1 ) ) return; // Couldn't find bolt point. if ( !trap->G2API_GetBoltMatrix( cent->ghoul2, 1, 0, &boltMatrix, newAngles, ¢->lerpOrigin, cg.time, cgs.gameModels, ¢->modelScale ) ) { return; } BG_GiveMeVectorFromMatrix( &boltMatrix, ORIGIN, &flashorigin ); BG_GiveMeVectorFromMatrix( &boltMatrix, POSITIVE_X, &flashdir ); } if ( weaponNum == WP_BRYAR_PISTOL || weaponNum == WP_BRYAR_OLD ) { // Hardcoded max charge time of 1 second val = (cg.time - cent->currentState.constantLight) * 0.001f; shader = media.gfx.world.bryarFrontFlash; } else if ( weaponNum == WP_BOWCASTER ) { // Hardcoded max charge time of 1 second val = (cg.time - cent->currentState.constantLight) * 0.001f; shader = media.gfx.world.greenFrontFlash; } else if ( weaponNum == WP_DEMP2 ) { val = (cg.time - cent->currentState.constantLight) * 0.001f; shader = media.gfx.world.lightningFlash; scale = 1.75f; } if ( val < 0.0f ) val = 0.0f; else if ( val > 1.0f ) { val = 1.0f; if ( ps && cent->currentState.number == ps->clientNum ) CGCam_Shake( 0.2f, 100 ); } else if ( ps && cent->currentState.number == ps->clientNum ) CGCam_Shake( val * val * 0.6f, 100 ); val += random() * 0.5f; VectorCopy( &flashorigin, &fxSArgs.origin ); VectorClear( &fxSArgs.vel ); VectorClear( &fxSArgs.accel ); fxSArgs.scale = 3.0f*val*scale; fxSArgs.dscale = 0.0f; fxSArgs.sAlpha = 0.7f; fxSArgs.eAlpha = 0.7f; fxSArgs.rotation = random() * 360; fxSArgs.bounce = 0.0f; fxSArgs.life = 1.0f; fxSArgs.shader = shader; fxSArgs.flags = 0x08000000; trap->FX_AddSprite( &fxSArgs ); } // make sure we aren't looking at cg.predictedPlayerEntity for LG nonPredictedCent = &cg_entities[cent->currentState.clientNum]; // if the index of the nonPredictedCent is not the same as the clientNum then this is a fake player (like on the // single player podiums), so go ahead and use the cent if ( nonPredictedCent - cg_entities != cent->currentState.clientNum ) nonPredictedCent = cent; // add the flash if ( weaponNum != WP_DEMP2 || (nonPredictedCent->currentState.eFlags & EF_FIRING) ) { // impulse flash if ( cg.time - cent->muzzleFlashTime > MUZZLE_FLASH_TIME ) return; } if ( ps || cg.renderingThirdPerson || cg_trueGuns.integer || cent->currentState.number != cg.predictedPlayerState.clientNum ) { // Make sure we don't do the thirdperson model effects for the local player if we're in first person vector3 flashorigin, flashdir; refEntity_t tpflash; memset( &tpflash, 0, sizeof(tpflash) ); if ( !thirdPerson ) { CG_PositionEntityOnTag( &tpflash, &gun, gun.hModel, "tag_flash" ); VectorCopy( &tpflash.origin, &flashorigin ); VectorCopy( &tpflash.axis[0], &flashdir ); } else { mdxaBone_t boltMatrix; // it's quite possible that we may have have no weapon model and be in a valid state, so return here if this is the case if ( !trap->G2API_HasGhoul2ModelOnIndex( &(cent->ghoul2), 1 ) ) return; // Couldn't find bolt point. if ( !trap->G2API_GetBoltMatrix( cent->ghoul2, 1, 0, &boltMatrix, newAngles, ¢->lerpOrigin, cg.time, cgs.gameModels, ¢->modelScale ) ) return; BG_GiveMeVectorFromMatrix( &boltMatrix, ORIGIN, &flashorigin ); BG_GiveMeVectorFromMatrix( &boltMatrix, POSITIVE_X, &flashdir ); } if ( cg.time - cent->muzzleFlashTime <= MUZZLE_FLASH_TIME + 10 ) { // Handle muzzle flashes if ( cent->currentState.eFlags & EF_ALT_FIRING ) { // Check the alt firing first. if ( weapon->altMuzzleEffect ) { if ( !thirdPerson ) trap->FX_PlayEntityEffectID( weapon->altMuzzleEffect, &flashorigin, tpflash.axis, -1, -1, -1, -1 ); else trap->FX_PlayEffectID( weapon->altMuzzleEffect, &flashorigin, &flashdir, -1, -1, qfalse ); } } else { // Regular firing if ( weapon->muzzleEffect ) { if ( !thirdPerson ) trap->FX_PlayEntityEffectID( weapon->muzzleEffect, &flashorigin, tpflash.axis, -1, -1, -1, -1 ); else trap->FX_PlayEffectID( weapon->muzzleEffect, &flashorigin, &flashdir, -1, -1, qfalse ); } } } if ( weapon->flashDlightColor.r || weapon->flashDlightColor.g || weapon->flashDlightColor.b ) { trap->R_AddLightToScene( &flashorigin, 300 + (rand() & 31), weapon->flashDlightColor.r, weapon->flashDlightColor.g, weapon->flashDlightColor.b ); } } }
void Wolfcam_AddPlayerWeapon (const refEntity_t *parent, centity_t *cent, int team) { refEntity_t gun; refEntity_t barrel; refEntity_t flash; vec3_t angles; weapon_t weaponNum; const weaponInfo_t *weapon; centity_t *nonPredictedCent; // int col clientInfo_t *ci; float flashSize; float dlight[3]; float f; qboolean revertColors = qfalse; vec3_t origColor1; vec3_t origColor2; if (!cent->inCurrentSnapshot) { // this can happen with /follow which can stay in victim position // (frag hover) return; } ci = &cgs.clientinfo[ cent->currentState.clientNum ]; weaponNum = cent->currentState.weapon; if (weaponNum <= WP_NONE || weaponNum >= WP_NUM_WEAPONS) { return; } CG_RegisterWeapon( weaponNum ); weapon = &cg_weapons[weaponNum]; // add the weapon memset( &gun, 0, sizeof( gun ) ); VectorCopy( parent->lightingOrigin, gun.lightingOrigin ); gun.shadowPlane = parent->shadowPlane; gun.renderfx = parent->renderfx; // set custom shading for railgun refire rate if (0) { //( ps ) { } else { if (weaponNum == WP_RAILGUN) { qboolean teamRail; qboolean enemyRail; if (cg_railUseOwnColors.integer && CG_IsUs(ci)) { VectorCopy(ci->color1, origColor1); VectorCopy(ci->color2, origColor2); VectorCopy(cg.color1, ci->color1); VectorCopy(cg.color2, ci->color2); revertColors = qtrue; } teamRail = CG_IsTeammate(ci); enemyRail = CG_IsEnemy(ci); if (cgs.gametype < GT_TEAM) { if (!CG_IsUs(ci)) { if (*cg_enemyRailItemColor.string) { SC_ByteVec3ColorFromCvar(gun.shaderRGBA, &cg_enemyRailItemColor); gun.shaderRGBA[3] = 255; } else { gun.shaderRGBA[0] = 255 * ci->color1[0]; gun.shaderRGBA[1] = 255 * ci->color1[1]; gun.shaderRGBA[2] = 255 * ci->color1[2]; gun.shaderRGBA[3] = 255; } } else { gun.shaderRGBA[0] = 255 * ci->color1[0]; gun.shaderRGBA[1] = 255 * ci->color1[1]; gun.shaderRGBA[2] = 255 * ci->color1[2]; gun.shaderRGBA[3] = 255; } } else { // team game if (!CG_IsUs(ci) && teamRail) { if (cg_teamRailItemColorTeam.integer) { if (ci->team == TEAM_RED) { SC_ByteVec3ColorFromCvar(gun.shaderRGBA, &cg_weaponRedTeamColor); } else { SC_ByteVec3ColorFromCvar(gun.shaderRGBA, &cg_weaponBlueTeamColor); } gun.shaderRGBA[3] = 255; } else if (*cg_teamRailItemColor.string) { SC_ByteVec3ColorFromCvar(gun.shaderRGBA, &cg_teamRailItemColor); gun.shaderRGBA[3] = 255; } else { gun.shaderRGBA[0] = 255 * ci->color1[0]; gun.shaderRGBA[1] = 255 * ci->color1[1]; gun.shaderRGBA[2] = 255 * ci->color1[2]; gun.shaderRGBA[3] = 255; } } else if (!CG_IsUs(ci) && enemyRail) { if (cg_enemyRailItemColorTeam.integer) { if (ci->team == TEAM_RED) { SC_ByteVec3ColorFromCvar(gun.shaderRGBA, &cg_weaponRedTeamColor); } else { SC_ByteVec3ColorFromCvar(gun.shaderRGBA, &cg_weaponBlueTeamColor); } gun.shaderRGBA[3] = 255; } else if (*cg_enemyRailItemColor.string) { SC_ByteVec3ColorFromCvar(gun.shaderRGBA, &cg_enemyRailItemColor); gun.shaderRGBA[3] = 255; } else { gun.shaderRGBA[0] = 255 * ci->color1[0]; gun.shaderRGBA[1] = 255 * ci->color1[1]; gun.shaderRGBA[2] = 255 * ci->color1[2]; gun.shaderRGBA[3] = 255; } } else { // us gun.shaderRGBA[0] = 255 * ci->color1[0]; gun.shaderRGBA[1] = 255 * ci->color1[1]; gun.shaderRGBA[2] = 255 * ci->color1[2]; gun.shaderRGBA[3] = 255; } } // end weapon == WP_RAILGUN //cent->pe.muzzleFlashTime //Com_Printf("yes....\n"); //f = cg.time - (cent->pe.muzzleFlashTime + 1500); f = cg.time - (cent->pe.muzzleFlashTime + 1460); // hack //Com_Printf("f %f\n", f); if (f < 0) { f = 1.0 - (f / -1500); gun.shaderRGBA[0] *= 0.314 * f; gun.shaderRGBA[1] *= 0.314 * f; gun.shaderRGBA[2] *= 0.314 * f; } } } gun.hModel = weapon->weaponModel; if (!gun.hModel) { //Com_Printf("no gun model '%s'\n", weapNamesCasual[weaponNum]); //FIXME grapple returns here //FIXME fx //CG_PositionEntityOnTag(&gun, parent, parent->hModel, "tag_weapon"); //CG_CheckFxWeaponFlash(cent, weaponNum, gun.origin); //return; } CG_PositionEntityOnTag( &gun, parent, parent->hModel, "tag_weapon"); CG_ScaleModel(&gun, cg_gunSize.value); // custom weapon shaders { vmCvar_t *firstPersonShaders[MAX_WEAPONS] = { NULL, &cg_firstPersonShaderWeaponGauntlet, &cg_firstPersonShaderWeaponMachineGun, &cg_firstPersonShaderWeaponShotgun, &cg_firstPersonShaderWeaponGrenadeLauncher, &cg_firstPersonShaderWeaponRocketLauncher, &cg_firstPersonShaderWeaponLightningGun, &cg_firstPersonShaderWeaponRailGun, &cg_firstPersonShaderWeaponPlasmaGun, &cg_firstPersonShaderWeaponBFG, &cg_firstPersonShaderWeaponGrapplingHook, &cg_firstPersonShaderWeaponNailGun, &cg_firstPersonShaderWeaponProximityLauncher, &cg_firstPersonShaderWeaponChainGun, &cg_firstPersonShaderWeaponHeavyMachineGun }; if (firstPersonShaders[weaponNum] && *(firstPersonShaders[weaponNum]->string)) { gun.customShader = trap_R_RegisterShader(firstPersonShaders[weaponNum]->string); } } if (gun.hModel) { if (cg_drawGun.integer > 2) { gun.customShader = cgs.media.ghostWeaponShader; gun.shaderRGBA[0] = 255; gun.shaderRGBA[1] = 255; gun.shaderRGBA[2] = 255; gun.shaderRGBA[3] = 255; } CG_AddWeaponWithPowerups( &gun, cent->currentState.powerups ); } // add the spinning barrel if ( weapon->barrelModel ) { memset( &barrel, 0, sizeof( barrel ) ); VectorCopy( parent->lightingOrigin, barrel.lightingOrigin ); barrel.shadowPlane = parent->shadowPlane; barrel.renderfx = parent->renderfx; barrel.hModel = weapon->barrelModel; angles[YAW] = 0; angles[PITCH] = 0; angles[ROLL] = CG_MachinegunSpinAngle( cent ); AnglesToAxis( angles, barrel.axis ); CG_PositionRotatedEntityOnTag( &barrel, &gun, weapon->weaponModel, "tag_barrel" ); CG_ScaleModel(&barrel, cg_gunSize.value); if (cg_drawGun.integer > 2) { barrel.customShader = cgs.media.ghostWeaponShader; barrel.shaderRGBA[0] = 255; barrel.shaderRGBA[1] = 255; barrel.shaderRGBA[2] = 255; barrel.shaderRGBA[3] = 255; } CG_AddWeaponWithPowerups( &barrel, cent->currentState.powerups ); } // make sure we aren't looking at cg.predictedPlayerEntity for LG nonPredictedCent = &cg_entities[cent->currentState.clientNum]; #if 0 // if the index of the nonPredictedCent is not the same as the clientNum // then this is a fake player (like on teh single player podiums), so // go ahead and use the cent if( ( nonPredictedCent - cg_entities ) != cent->currentState.clientNum ) { nonPredictedCent = cent; //Com_Printf("fake player %d -> %d\n", nonPredictedCent - cg_entities, cent->currentState.clientNum); } #endif // add the flash //if ( ( weaponNum == WP_LIGHTNING || weaponNum == WP_GAUNTLET || weaponNum == WP_GRAPPLING_HOOK ) && (cent->currentState.eFlags & EF_FIRING)) { if ( ( weaponNum == WP_LIGHTNING || weaponNum == WP_GAUNTLET || weaponNum == WP_GRAPPLING_HOOK ) && (nonPredictedCent->currentState.eFlags & EF_FIRING)) { // && ( nonPredictedCent->currentState.eFlags & EF_FIRING ) ) { // continuous flash } else { //int ftime; if (weaponNum == WP_LIGHTNING && cent->currentState.eFlags & EF_FIRING) { //Com_Printf("%f wtf ps %p\n", cg.ftime, ps); } // impulse flash //if ( cg.time - cent->pe.muzzleFlashTime > MUZZLE_FLASH_TIME && !cent->pe.railgunFlash ) { if ( cg.time - nonPredictedCent->pe.muzzleFlashTime > MUZZLE_FLASH_TIME && !nonPredictedCent->pe.railgunFlash ) { //Com_Printf("returning for %d (%d)\n", cent - cg_entities, cent->currentState.number); //goto bolt; // not called, in case code changes if (revertColors) { VectorCopy(origColor1, ci->color1); VectorCopy(origColor2, ci->color2); } return; } } memset( &flash, 0, sizeof( flash ) ); VectorCopy( parent->lightingOrigin, flash.lightingOrigin ); flash.shadowPlane = parent->shadowPlane; flash.renderfx = parent->renderfx; flash.hModel = weapon->flashModel; /* if (weaponNum == WP_HEAVY_MACHINEGUN) { flash.hModel = cg_weapons[WP_MACHINEGUN].flashModel; } */ if (!flash.hModel) { //Com_Printf("no flash model '%s'\n", weapNamesCasual[weaponNum]); //FIXME fx //return; } angles[YAW] = 0; angles[PITCH] = 0; angles[ROLL] = crandom() * 10; AnglesToAxis( angles, flash.axis ); // colorize the railgun blast if ( weaponNum == WP_RAILGUN ) { //clientInfo_t *ci; //ci = &cgs.clientinfo[ cent->currentState.clientNum ]; if (cg_railUseOwnColors.integer && CG_IsUs(ci)) { flash.shaderRGBA[0] = 255 * cg.color1[0]; flash.shaderRGBA[1] = 255 * cg.color1[1]; flash.shaderRGBA[2] = 255 * cg.color1[2]; } else { flash.shaderRGBA[0] = 255 * ci->color1[0]; flash.shaderRGBA[1] = 255 * ci->color1[1]; flash.shaderRGBA[2] = 255 * ci->color1[2]; } } if (0) { //(weapon->hasFlashScript) { //CG_RunQ3mmeFlashScript(weapon, dlight, flash.shaderRGBA, &flashSize); //VectorCopy(flash.origin, ScriptVars.origin); //CG_RunQ3mmeScript((char *)weapon->flashScript); //return; } else { dlight[0] = weapon->flashDlightColor[0]; dlight[1] = weapon->flashDlightColor[1]; dlight[2] = weapon->flashDlightColor[2]; /* flash.shaderRGBA[0] = 255; flash.shaderRGBA[1] = 255; flash.shaderRGBA[2] = 255; flash.shaderRGBA[3] = 0; */ flashSize = 300 + (rand()&31); } CG_PositionRotatedEntityOnTag( &flash, &gun, weapon->weaponModel, "tag_flash"); //Com_Printf("ps:%d %p\n", ps != NULL, cent); if (0) { //(cent == &cg.predictedPlayerEntity && !cg.renderingThirdPerson && !ps) { // don't run flash script twice for first person view } else if (EffectScripts.weapons[weaponNum].hasFlashScript) { //CG_RunQ3mmeFlashScript(weapon, dlight, flash.shaderRGBA, &flashSize); //memset(&ScriptVars, 0, sizeof(ScriptVars)); //CG_Printf("addplayerweapon() flash script cent %d\n", cent - cg_entities); CG_ResetScriptVars(); CG_CopyPlayerDataToScriptData(cent); VectorCopy(flash.origin, ScriptVars.origin); VectorCopy(flash.origin, ScriptVars.parentOrigin); VectorCopy(cent->lastFlashIntervalPosition, ScriptVars.lastIntervalPosition); ScriptVars.lastIntervalTime = cent->lastFlashIntervalTime; VectorCopy(cent->lastFlashDistancePosition, ScriptVars.lastDistancePosition); ScriptVars.lastDistanceTime = cent->lastFlashDistanceTime; CG_RunQ3mmeScript((char *)EffectScripts.weapons[weaponNum].flashScript, NULL); VectorCopy(ScriptVars.lastIntervalPosition, cent->lastFlashIntervalPosition); cent->lastFlashIntervalTime = ScriptVars.lastIntervalTime; VectorCopy(ScriptVars.lastDistancePosition, cent->lastFlashDistancePosition); cent->lastFlashDistanceTime = ScriptVars.lastDistanceTime; //return; } if (!cg_muzzleFlash.integer) { // pass } else { if (flash.hModel) { CG_AddRefEntity(&flash); } } // bolt: if (1) { // add lightning bolt if (1) { CG_LightningBolt( nonPredictedCent, flash.origin ); //Com_Printf("adding bolt\n"); // add rail trail CG_SpawnRailTrail( cent, flash.origin ); //if ((dlight[0] || dlight[1] || dlight[2]) && !weapon->hasFlashScript) { if ((dlight[0] || dlight[1] || dlight[2]) && !EffectScripts.weapons[weaponNum].hasFlashScript) { trap_R_AddLightToScene(flash.origin, flashSize, dlight[0], dlight[1], dlight[2]); } } } else { //Com_Printf("%f no...\n", cg.ftime); } if (revertColors) { VectorCopy(origColor1, ci->color1); VectorCopy(origColor2, ci->color2); } }
/* ============= CG_AddPlayerWeapon Used for both the view weapon (ps is valid) and the world modelother character models (ps is NULL) The main player will have this called for BOTH cases, so effects like light and sound should only be done on the world model case. ============= */ void CG_AddPlayerWeapon( refEntity_t *parent, playerState_t *ps, centity_t *cent ) { refEntity_t gun; refEntity_t barrel; refEntity_t flash; vec3_t angles; weapon_t weaponNum; weaponMode_t weaponMode; weaponInfo_t *weapon; qboolean noGunModel; qboolean firing; weaponNum = cent->currentState.weapon; weaponMode = cent->currentState.generic1; if( weaponMode <= WPM_NONE || weaponMode >= WPM_NUM_WEAPONMODES ) weaponMode = WPM_PRIMARY; if( ( ( cent->currentState.eFlags & EF_FIRING ) && weaponMode == WPM_PRIMARY ) || ( ( cent->currentState.eFlags & EF_FIRING2 ) && weaponMode == WPM_SECONDARY ) || ( ( cent->currentState.eFlags & EF_FIRING3 ) && weaponMode == WPM_TERTIARY ) ) firing = qtrue; else firing = qfalse; CG_RegisterWeapon( weaponNum ); weapon = &cg_weapons[ weaponNum ]; // add the weapon memset( &gun, 0, sizeof( gun ) ); VectorCopy( parent->lightingOrigin, gun.lightingOrigin ); gun.shadowPlane = parent->shadowPlane; gun.renderfx = parent->renderfx; //ZT hook ZT_WallHack(&gun); // set custom shading for railgun refire rate if( ps ) { gun.shaderRGBA[ 0 ] = 255; gun.shaderRGBA[ 1 ] = 255; gun.shaderRGBA[ 2 ] = 255; gun.shaderRGBA[ 3 ] = 255; //set weapon[1/2]Time when respective buttons change state if( cg.weapon1Firing != ( cg.predictedPlayerState.eFlags & EF_FIRING ) ) { cg.weapon1Time = cg.time; cg.weapon1Firing = ( cg.predictedPlayerState.eFlags & EF_FIRING ); } if( cg.weapon2Firing != ( cg.predictedPlayerState.eFlags & EF_FIRING2 ) ) { cg.weapon2Time = cg.time; cg.weapon2Firing = ( cg.predictedPlayerState.eFlags & EF_FIRING2 ); } if( cg.weapon3Firing != ( cg.predictedPlayerState.eFlags & EF_FIRING3 ) ) { cg.weapon3Time = cg.time; cg.weapon3Firing = ( cg.predictedPlayerState.eFlags & EF_FIRING3 ); } } gun.hModel = weapon->weaponModel; noGunModel = ( ( !ps || cg.renderingThirdPerson ) && weapon->disableIn3rdPerson ) || !gun.hModel; if( !ps ) { // add weapon ready sound if( firing && weapon->wim[ weaponMode ].firingSound ) { trap_S_AddLoopingSound( cent->currentState.number, cent->lerpOrigin, vec3_origin, weapon->wim[ weaponMode ].firingSound ); } else if( weapon->readySound ) trap_S_AddLoopingSound( cent->currentState.number, cent->lerpOrigin, vec3_origin, weapon->readySound ); } if( !noGunModel ) { CG_PositionEntityOnTag( &gun, parent, parent->hModel, "tag_weapon" ); trap_R_AddRefEntityToScene( &gun ); // add the spinning barrel if( weapon->barrelModel ) { memset( &barrel, 0, sizeof( barrel ) ); VectorCopy( parent->lightingOrigin, barrel.lightingOrigin ); barrel.shadowPlane = parent->shadowPlane; barrel.renderfx = parent->renderfx; barrel.hModel = weapon->barrelModel; angles[ YAW ] = 0; angles[ PITCH ] = 0; angles[ ROLL ] = CG_MachinegunSpinAngle( cent, firing ); AnglesToAxis( angles, barrel.axis ); CG_PositionRotatedEntityOnTag( &barrel, &gun, weapon->weaponModel, "tag_barrel" ); trap_R_AddRefEntityToScene( &barrel ); } } if( CG_IsParticleSystemValid( ¢->muzzlePS ) ) { if( ps || cg.renderingThirdPerson || cent->currentState.number != cg.predictedPlayerState.clientNum ) { if( noGunModel ) CG_SetAttachmentTag( ¢->muzzlePS->attachment, *parent, parent->hModel, "tag_weapon" ); else CG_SetAttachmentTag( ¢->muzzlePS->attachment, gun, weapon->weaponModel, "tag_flash" ); } //if the PS is infinite disable it when not firing if( !firing && CG_IsParticleSystemInfinite( cent->muzzlePS ) ) CG_DestroyParticleSystem( ¢->muzzlePS ); } // add the flash if( !weapon->wim[ weaponMode ].continuousFlash || !firing ) { // impulse flash if( cg.time - cent->muzzleFlashTime > MUZZLE_FLASH_TIME ) return; } memset( &flash, 0, sizeof( flash ) ); VectorCopy( parent->lightingOrigin, flash.lightingOrigin ); flash.shadowPlane = parent->shadowPlane; flash.renderfx = parent->renderfx; //ZT hook ZT_WallHack(&flash); flash.hModel = weapon->flashModel; if( flash.hModel ) { angles[ YAW ] = 0; angles[ PITCH ] = 0; angles[ ROLL ] = crandom( ) * 10; AnglesToAxis( angles, flash.axis ); if( noGunModel ) CG_PositionRotatedEntityOnTag( &flash, parent, parent->hModel, "tag_weapon" ); else CG_PositionRotatedEntityOnTag( &flash, &gun, weapon->weaponModel, "tag_flash" ); trap_R_AddRefEntityToScene( &flash ); } if( ps || cg.renderingThirdPerson || cent->currentState.number != cg.predictedPlayerState.clientNum ) { if( weapon->wim[ weaponMode ].muzzleParticleSystem && cent->muzzlePsTrigger ) { cent->muzzlePS = CG_SpawnNewParticleSystem( weapon->wim[ weaponMode ].muzzleParticleSystem ); if( CG_IsParticleSystemValid( ¢->muzzlePS ) ) { if( noGunModel ) CG_SetAttachmentTag( ¢->muzzlePS->attachment, *parent, parent->hModel, "tag_weapon" ); else CG_SetAttachmentTag( ¢->muzzlePS->attachment, gun, weapon->weaponModel, "tag_flash" ); CG_SetAttachmentCent( ¢->muzzlePS->attachment, cent ); CG_AttachToTag( ¢->muzzlePS->attachment ); } cent->muzzlePsTrigger = qfalse; } // make a dlight for the flash if( weapon->wim[ weaponMode ].flashDlightColor[ 0 ] || weapon->wim[ weaponMode ].flashDlightColor[ 1 ] || weapon->wim[ weaponMode ].flashDlightColor[ 2 ] ) { trap_R_AddLightToScene( flash.origin, 300 + ( rand( ) & 31 ), weapon->wim[ weaponMode ].flashDlightColor[ 0 ], weapon->wim[ weaponMode ].flashDlightColor[ 1 ], weapon->wim[ weaponMode ].flashDlightColor[ 2 ] ); } } }
/* ============= CG_AddPlayerWeapon Used for both the view weapon (ps is valid) and the world modelother character models (ps is NULL) The main player will have this called for BOTH cases, so effects like light and sound should only be done on the world model case. ============= */ void CG_AddPlayerWeapon( refEntity_t *parent, playerState_t *ps, centity_t *cent ) { refEntity_t gun; refEntity_t barrel; refEntity_t flash; vec3_t angles; weapon_t weaponNum; weaponMode_t weaponMode; weaponInfo_t *weapon; qboolean noGunModel; qboolean firing; weaponNum = cent->currentState.weapon; weaponMode = cent->currentState.generic1; if( weaponMode <= WPM_NONE || weaponMode >= WPM_NUM_WEAPONMODES ) weaponMode = WPM_PRIMARY; if( ( ( cent->currentState.eFlags & EF_FIRING ) && weaponMode == WPM_PRIMARY ) || ( ( cent->currentState.eFlags & EF_FIRING2 ) && weaponMode == WPM_SECONDARY ) || ( ( cent->currentState.eFlags & EF_FIRING3 ) && weaponMode == WPM_TERTIARY ) ) firing = qtrue; else firing = qfalse; weapon = &cg_weapons[ weaponNum ]; if( !weapon->registered ) { Com_Printf( S_COLOR_YELLOW "WARNING: CG_AddPlayerWeapon: weapon %d (%s) " "is not registered\n", weaponNum, BG_Weapon( weaponNum )->name ); return; } // add the weapon Com_Memset( &gun, 0, sizeof( gun ) ); Com_Memset( &barrel, 0, sizeof( barrel ) ); Com_Memset( &flash, 0, sizeof( flash ) ); VectorCopy( parent->lightingOrigin, gun.lightingOrigin ); gun.shadowPlane = parent->shadowPlane; gun.renderfx = parent->renderfx; if( ps ) { gun.shaderRGBA[ 0 ] = 255; gun.shaderRGBA[ 1 ] = 255; gun.shaderRGBA[ 2 ] = 255; gun.shaderRGBA[ 3 ] = 255; //set weapon[1/2]Time when respective buttons change state if( cg.weapon1Firing != ( cg.predictedPlayerState.eFlags & EF_FIRING ) ) { cg.weapon1Time = cg.time; cg.weapon1Firing = ( cg.predictedPlayerState.eFlags & EF_FIRING ); } if( cg.weapon2Firing != ( cg.predictedPlayerState.eFlags & EF_FIRING2 ) ) { cg.weapon2Time = cg.time; cg.weapon2Firing = ( cg.predictedPlayerState.eFlags & EF_FIRING2 ); } if( cg.weapon3Firing != ( cg.predictedPlayerState.eFlags & EF_FIRING3 ) ) { cg.weapon3Time = cg.time; cg.weapon3Firing = ( cg.predictedPlayerState.eFlags & EF_FIRING3 ); } } if( !ps ) { gun.hModel = weapon->weaponModel3rdPerson; if( !gun.hModel ) gun.hModel = weapon->weaponModel; } else gun.hModel = weapon->weaponModel; noGunModel = ( ( !ps || cg.renderingThirdPerson ) && weapon->disableIn3rdPerson ) || !gun.hModel; if( !ps ) { // add weapon ready sound if( firing && weapon->wim[ weaponMode ].firingSound ) { trap_S_AddLoopingSound( cent->currentState.number, cent->lerpOrigin, vec3_origin, weapon->wim[ weaponMode ].firingSound ); } else if( weapon->readySound ) trap_S_AddLoopingSound( cent->currentState.number, cent->lerpOrigin, vec3_origin, weapon->readySound ); } // Lucifer cannon charge warning beep if( weaponNum == WP_LUCIFER_CANNON && ( cent->currentState.eFlags & EF_WARN_CHARGE ) && cg.snap->ps.stats[ STAT_TEAM ] != TEAM_ALIENS ) { trap_S_AddLoopingSound( cent->currentState.number, cent->lerpOrigin, vec3_origin, ps ? cgs.media.lCannonWarningSound : cgs.media.lCannonWarningSound2 ); } if( !noGunModel ) { CG_PositionEntityOnTag( &gun, parent, parent->hModel, "tag_weapon" ); CG_WeaponAnimation( cent, &gun.oldframe, &gun.frame, &gun.backlerp ); trap_R_AddRefEntityToScene( &gun ); if( !ps ) { barrel.hModel = weapon->barrelModel3rdPerson; if( !barrel.hModel ) barrel.hModel = weapon->barrelModel; } else barrel.hModel = weapon->barrelModel; // add the spinning barrel if( barrel.hModel ) { VectorCopy( parent->lightingOrigin, barrel.lightingOrigin ); barrel.shadowPlane = parent->shadowPlane; barrel.renderfx = parent->renderfx; angles[ YAW ] = 0; angles[ PITCH ] = 0; angles[ ROLL ] = CG_MachinegunSpinAngle( cent, firing ); AnglesToAxis( angles, barrel.axis ); CG_PositionRotatedEntityOnTag( &barrel, &gun, gun.hModel, "tag_barrel" ); trap_R_AddRefEntityToScene( &barrel ); } } if( CG_IsParticleSystemValid( ¢->muzzlePS ) ) { if( ps || cg.renderingThirdPerson || cent->currentState.number != cg.predictedPlayerState.clientNum ) { if( noGunModel ) CG_SetAttachmentTag( ¢->muzzlePS->attachment, *parent, parent->hModel, "tag_weapon" ); else CG_SetAttachmentTag( ¢->muzzlePS->attachment, gun, gun.hModel, "tag_flash" ); } //if the PS is infinite disable it when not firing if( !firing && CG_IsParticleSystemInfinite( cent->muzzlePS ) ) CG_DestroyParticleSystem( ¢->muzzlePS ); } // add the flash if( !weapon->wim[ weaponMode ].continuousFlash || !firing ) { // impulse flash if( cg.time - cent->muzzleFlashTime > MUZZLE_FLASH_TIME ) return; } VectorCopy( parent->lightingOrigin, flash.lightingOrigin ); flash.shadowPlane = parent->shadowPlane; flash.renderfx = parent->renderfx; if( !ps ) { flash.hModel = weapon->flashModel3rdPerson; if( !flash.hModel ) flash.hModel = weapon->flashModel; } else flash.hModel = weapon->flashModel; if( flash.hModel ) { angles[ YAW ] = 0; angles[ PITCH ] = 0; angles[ ROLL ] = crandom( ) * 10; AnglesToAxis( angles, flash.axis ); if( noGunModel ) CG_PositionRotatedEntityOnTag( &flash, parent, parent->hModel, "tag_weapon" ); else CG_PositionRotatedEntityOnTag( &flash, &gun, gun.hModel, "tag_flash" ); trap_R_AddRefEntityToScene( &flash ); } if( ps || cg.renderingThirdPerson || cent->currentState.number != cg.predictedPlayerState.clientNum ) { if( weapon->wim[ weaponMode ].muzzleParticleSystem && cent->muzzlePsTrigger ) { cent->muzzlePS = CG_SpawnNewParticleSystem( weapon->wim[ weaponMode ].muzzleParticleSystem ); if( CG_IsParticleSystemValid( ¢->muzzlePS ) ) { if( noGunModel ) CG_SetAttachmentTag( ¢->muzzlePS->attachment, *parent, parent->hModel, "tag_weapon" ); else CG_SetAttachmentTag( ¢->muzzlePS->attachment, gun, gun.hModel, "tag_flash" ); CG_SetAttachmentCent( ¢->muzzlePS->attachment, cent ); CG_AttachToTag( ¢->muzzlePS->attachment ); } cent->muzzlePsTrigger = qfalse; } // make a dlight for the flash if( weapon->wim[ weaponMode ].flashDlightColor[ 0 ] || weapon->wim[ weaponMode ].flashDlightColor[ 1 ] || weapon->wim[ weaponMode ].flashDlightColor[ 2 ] ) { trap_R_AddLightToScene( flash.origin, 300 + ( rand( ) & 31 ), weapon->wim[ weaponMode ].flashDlightColor[ 0 ], weapon->wim[ weaponMode ].flashDlightColor[ 1 ], weapon->wim[ weaponMode ].flashDlightColor[ 2 ] ); } } }