📄 cg_weapons.c
字号:
mark = cgs.media.burnMarkShader;
radius = 64;
light = 300;
isSprite = qtrue;
break;
case WP_ROCKET_LAUNCHER:
mod = cgs.media.dishFlashModel;
shader = cgs.media.rocketExplosionShader;
sfx = cgs.media.sfx_rockexp;
mark = cgs.media.burnMarkShader;
radius = 64;
light = 300;
isSprite = qtrue;
duration = 1000;
lightColor[0] = 1;
lightColor[1] = 0.75;
lightColor[2] = 0.0;
if (cg_oldRocket.integer == 0) {
// explosion sprite animation
VectorMA( origin, 24, dir, sprOrg );
VectorScale( dir, 64, sprVel );
CG_ParticleExplosion( "explode1", sprOrg, sprVel, 1400, 20, 30 );
}
break;
case WP_RAILGUN:
mod = cgs.media.ringFlashModel;
shader = cgs.media.railExplosionShader;
sfx = cgs.media.sfx_plasmaexp;
mark = cgs.media.energyMarkShader;
radius = 24;
break;
case WP_PLASMAGUN:
mod = cgs.media.ringFlashModel;
shader = cgs.media.plasmaExplosionShader;
sfx = cgs.media.sfx_plasmaexp;
mark = cgs.media.energyMarkShader;
radius = 16;
break;
case WP_BFG:
mod = cgs.media.dishFlashModel;
shader = cgs.media.bfgExplosionShader;
sfx = cgs.media.sfx_rockexp;
mark = cgs.media.burnMarkShader;
radius = 32;
isSprite = qtrue;
break;
case WP_SHOTGUN:
mod = cgs.media.bulletFlashModel;
shader = cgs.media.bulletExplosionShader;
mark = cgs.media.bulletMarkShader;
sfx = 0;
radius = 4;
break;
#ifdef MISSIONPACK
case WP_CHAINGUN:
mod = cgs.media.bulletFlashModel;
if( soundType == IMPACTSOUND_FLESH ) {
sfx = cgs.media.sfx_chghitflesh;
} else if( soundType == IMPACTSOUND_METAL ) {
sfx = cgs.media.sfx_chghitmetal;
} else {
sfx = cgs.media.sfx_chghit;
}
mark = cgs.media.bulletMarkShader;
r = rand() & 3;
if ( r < 2 ) {
sfx = cgs.media.sfx_ric1;
} else if ( r == 2 ) {
sfx = cgs.media.sfx_ric2;
} else {
sfx = cgs.media.sfx_ric3;
}
radius = 8;
break;
#endif
case WP_MACHINEGUN:
mod = cgs.media.bulletFlashModel;
shader = cgs.media.bulletExplosionShader;
mark = cgs.media.bulletMarkShader;
r = rand() & 3;
if ( r == 0 ) {
sfx = cgs.media.sfx_ric1;
} else if ( r == 1 ) {
sfx = cgs.media.sfx_ric2;
} else {
sfx = cgs.media.sfx_ric3;
}
radius = 8;
break;
}
if ( sfx ) {
trap_S_StartSound( origin, ENTITYNUM_WORLD, CHAN_AUTO, sfx );
}
//
// create the explosion
//
if ( mod ) {
le = CG_MakeExplosion( origin, dir,
mod, shader,
duration, isSprite );
le->light = light;
VectorCopy( lightColor, le->lightColor );
if ( weapon == WP_RAILGUN ) {
// colorize with client color
VectorCopy( cgs.clientinfo[clientNum].color1, le->color );
}
}
//
// impact mark
//
alphaFade = (mark == cgs.media.energyMarkShader); // plasma fades alpha, all others fade color
if ( weapon == WP_RAILGUN ) {
float *color;
// colorize with client color
color = cgs.clientinfo[clientNum].color2;
CG_ImpactMark( mark, origin, dir, random()*360, color[0],color[1], color[2],1, alphaFade, radius, qfalse );
} else {
CG_ImpactMark( mark, origin, dir, random()*360, 1,1,1,1, alphaFade, radius, qfalse );
}
}
/*
=================
CG_MissileHitPlayer
=================
*/
void CG_MissileHitPlayer( int weapon, vec3_t origin, vec3_t dir, int entityNum ) {
CG_Bleed( origin, entityNum );
// some weapons will make an explosion with the blood, while
// others will just make the blood
switch ( weapon ) {
case WP_GRENADE_LAUNCHER:
case WP_ROCKET_LAUNCHER:
#ifdef MISSIONPACK
case WP_NAILGUN:
case WP_CHAINGUN:
case WP_PROX_LAUNCHER:
#endif
CG_MissileHitWall( weapon, 0, origin, dir, IMPACTSOUND_FLESH );
break;
default:
break;
}
}
/*
============================================================================
SHOTGUN TRACING
============================================================================
*/
/*
================
CG_ShotgunPellet
================
*/
static void CG_ShotgunPellet( vec3_t start, vec3_t end, int skipNum ) {
trace_t tr;
int sourceContentType, destContentType;
CG_Trace( &tr, start, NULL, NULL, end, skipNum, MASK_SHOT );
sourceContentType = trap_CM_PointContents( start, 0 );
destContentType = trap_CM_PointContents( tr.endpos, 0 );
// FIXME: should probably move this cruft into CG_BubbleTrail
if ( sourceContentType == destContentType ) {
if ( sourceContentType & CONTENTS_WATER ) {
CG_BubbleTrail( start, tr.endpos, 32 );
}
} else if ( sourceContentType & CONTENTS_WATER ) {
trace_t trace;
trap_CM_BoxTrace( &trace, end, start, NULL, NULL, 0, CONTENTS_WATER );
CG_BubbleTrail( start, trace.endpos, 32 );
} else if ( destContentType & CONTENTS_WATER ) {
trace_t trace;
trap_CM_BoxTrace( &trace, start, end, NULL, NULL, 0, CONTENTS_WATER );
CG_BubbleTrail( tr.endpos, trace.endpos, 32 );
}
if ( tr.surfaceFlags & SURF_NOIMPACT ) {
return;
}
if ( cg_entities[tr.entityNum].currentState.eType == ET_PLAYER ) {
CG_MissileHitPlayer( WP_SHOTGUN, tr.endpos, tr.plane.normal, tr.entityNum );
} else {
if ( tr.surfaceFlags & SURF_NOIMPACT ) {
// SURF_NOIMPACT will not make a flame puff or a mark
return;
}
if ( tr.surfaceFlags & SURF_METALSTEPS ) {
CG_MissileHitWall( WP_SHOTGUN, 0, tr.endpos, tr.plane.normal, IMPACTSOUND_METAL );
} else {
CG_MissileHitWall( WP_SHOTGUN, 0, tr.endpos, tr.plane.normal, IMPACTSOUND_DEFAULT );
}
}
}
/*
================
CG_ShotgunPattern
Perform the same traces the server did to locate the
hit splashes
================
*/
static void CG_ShotgunPattern( vec3_t origin, vec3_t origin2, int seed, int otherEntNum ) {
int i;
float r, u;
vec3_t end;
vec3_t forward, right, up;
// derive the right and up vectors from the forward vector, because
// the client won't have any other information
VectorNormalize2( origin2, forward );
PerpendicularVector( right, forward );
CrossProduct( forward, right, up );
// generate the "random" spread pattern
for ( i = 0 ; i < DEFAULT_SHOTGUN_COUNT ; i++ ) {
r = Q_crandom( &seed ) * DEFAULT_SHOTGUN_SPREAD * 16;
u = Q_crandom( &seed ) * DEFAULT_SHOTGUN_SPREAD * 16;
VectorMA( origin, 8192 * 16, forward, end);
VectorMA (end, r, right, end);
VectorMA (end, u, up, end);
CG_ShotgunPellet( origin, end, otherEntNum );
}
}
/*
==============
CG_ShotgunFire
==============
*/
void CG_ShotgunFire( entityState_t *es ) {
vec3_t v;
int contents;
VectorSubtract( es->origin2, es->pos.trBase, v );
VectorNormalize( v );
VectorScale( v, 32, v );
VectorAdd( es->pos.trBase, v, v );
if ( cgs.glconfig.hardwareType != GLHW_RAGEPRO ) {
// ragepro can't alpha fade, so don't even bother with smoke
vec3_t up;
contents = trap_CM_PointContents( es->pos.trBase, 0 );
if ( !( contents & CONTENTS_WATER ) ) {
VectorSet( up, 0, 0, 8 );
CG_SmokePuff( v, up, 32, 1, 1, 1, 0.33f, 900, cg.time, 0, LEF_PUFF_DONT_SCALE, cgs.media.shotgunSmokePuffShader );
}
}
CG_ShotgunPattern( es->pos.trBase, es->origin2, es->eventParm, es->otherEntityNum );
}
/*
============================================================================
BULLETS
============================================================================
*/
/*
===============
CG_Tracer
===============
*/
void CG_Tracer( vec3_t source, vec3_t dest ) {
vec3_t forward, right;
polyVert_t verts[4];
vec3_t line;
float len, begin, end;
vec3_t start, finish;
vec3_t midpoint;
// tracer
VectorSubtract( dest, source, forward );
len = VectorNormalize( forward );
// start at least a little ways from the muzzle
if ( len < 100 ) {
return;
}
begin = 50 + random() * (len - 60);
end = begin + cg_tracerLength.value;
if ( end > len ) {
end = len;
}
VectorMA( source, begin, forward, start );
VectorMA( source, end, forward, finish );
line[0] = DotProduct( forward, cg.refdef.viewaxis[1] );
line[1] = DotProduct( forward, cg.refdef.viewaxis[2] );
VectorScale( cg.refdef.viewaxis[1], line[1], right );
VectorMA( right, -line[0], cg.refdef.viewaxis[2], right );
VectorNormalize( right );
VectorMA( finish, cg_tracerWidth.value, right, verts[0].xyz );
verts[0].st[0] = 0;
verts[0].st[1] = 1;
verts[0].modulate[0] = 255;
verts[0].modulate[1] = 255;
verts[0].modulate[2] = 255;
verts[0].modulate[3] = 255;
VectorMA( finish, -cg_tracerWidth.value, right, verts[1].xyz );
verts[1].st[0] = 1;
verts[1].st[1] = 0;
verts[1].modulate[0] = 255;
verts[1].modulate[1] = 255;
verts[1].modulate[2] = 255;
verts[1].modulate[3] = 255;
VectorMA( start, -cg_tracerWidth.value, right, verts[2].xyz );
verts[2].st[0] = 1;
verts[2].st[1] = 1;
verts[2].modulate[0] = 255;
verts[2].modulate[1] = 255;
verts[2].modulate[2] = 255;
verts[2].modulate[3] = 255;
VectorMA( start, cg_tracerWidth.value, right, verts[3].xyz );
verts[3].st[0] = 0;
verts[3].st[1] = 0;
verts[3].modulate[0] = 255;
verts[3].modulate[1] = 255;
verts[3].modulate[2] = 255;
verts[3].modulate[3] = 255;
trap_R_AddPolyToScene( cgs.media.tracerShader, 4, verts );
midpoint[0] = ( start[0] + finish[0] ) * 0.5;
midpoint[1] = ( start[1] + finish[1] ) * 0.5;
midpoint[2] = ( start[2] + finish[2] ) * 0.5;
// add the tracer sound
trap_S_StartSound( midpoint, ENTITYNUM_WORLD, CHAN_AUTO, cgs.media.tracerSound );
}
/*
======================
CG_CalcMuzzlePoint
======================
*/
static qboolean CG_CalcMuzzlePoint( int entityNum, vec3_t muzzle ) {
vec3_t forward;
centity_t *cent;
int anim;
if ( entityNum == cg.snap->ps.clientNum ) {
VectorCopy( cg.snap->ps.origin, muzzle );
muzzle[2] += cg.snap->ps.viewheight;
AngleVectors( cg.snap->ps.viewangles, forward, NULL, NULL );
VectorMA( muzzle, 14, forward, muzzle );
return qtrue;
}
cent = &cg_entities[entityNum];
if ( !cent->currentValid ) {
return qfalse;
}
VectorCopy( cent->currentState.pos.trBase, muzzle );
AngleVectors( cent->currentState.apos.trBase, forward, NULL, NULL );
anim = cent->currentState.legsAnim & ~ANIM_TOGGLEBIT;
if ( anim == LEGS_WALKCR || anim == LEGS_IDLECR ) {
muzzle[2] += CROUCH_VIEWHEIGHT;
} else {
muzzle[2] += DEFAULT_VIEWHEIGHT;
}
VectorMA( muzzle, 14, forward, muzzle );
return qtrue;
}
/*
======================
CG_Bullet
Renders bullet effects.
======================
*/
void CG_Bullet( vec3_t end, int sourceEntityNum, vec3_t normal, qboolean flesh, int fleshEntityNum ) {
trace_t trace;
int sourceContentType, destContentType;
vec3_t start;
// if the shooter is currently valid, calc a source point and possibly
// do trail effects
if ( sourceEntityNum >= 0 && cg_tracerChance.value > 0 ) {
if ( CG_CalcMuzzlePoint( sourceEntityNum, start ) ) {
sourceContentType = trap_CM_PointContents( start, 0 );
destContentType = trap_CM_PointContents( end, 0 );
// do a complete bubble trail if necessary
if ( ( sourceContentType == destContentType ) && ( sourceContentType & CONTENTS_WATER ) ) {
CG_BubbleTrail( start, end, 32 );
}
// bubble trail from water into air
else if ( ( sourceContentType & CONTENTS_WATER ) ) {
trap_CM_BoxTrace( &trace, end, start, NULL, NULL, 0, CONTENTS_WATER );
CG_BubbleTrail( start, trace.endpos, 32 );
}
// bubble trail from air into water
else if ( ( destContentType & CONTENTS_WATER ) ) {
trap_CM_BoxTrace( &trace, start, end, NULL, NULL, 0, CONTENTS_WATER );
CG_BubbleTrail( trace.endpos, end, 32 );
}
// draw a tracer
if ( random() < cg_tracerChance.value ) {
CG_Tracer( start, end );
}
}
}
// impact splash and mark
if ( flesh ) {
CG_Bleed( end, fleshEntityNum );
} else {
CG_MissileHitWall( WP_MACHINEGUN, 0, end, normal, IMPACTSOUND_DEFAULT );
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -