📄 cg_weapons.c
字号:
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
This file is part of Quake III Arena source code.
Quake III Arena source code is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.
Quake III Arena source code is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Foobar; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
//
// cg_weapons.c -- events and effects dealing with weapons
#include "cg_local.h"
/*
==========================
CG_MachineGunEjectBrass
==========================
*/
static void CG_MachineGunEjectBrass( centity_t *cent ) {
localEntity_t *le;
refEntity_t *re;
vec3_t velocity, xvelocity;
vec3_t offset, xoffset;
float waterScale = 1.0f;
vec3_t v[3];
if ( cg_brassTime.integer <= 0 ) {
return;
}
le = CG_AllocLocalEntity();
re = &le->refEntity;
velocity[0] = 0;
velocity[1] = -50 + 40 * crandom();
velocity[2] = 100 + 50 * crandom();
le->leType = LE_FRAGMENT;
le->startTime = cg.time;
le->endTime = le->startTime + cg_brassTime.integer + ( cg_brassTime.integer / 4 ) * random();
le->pos.trType = TR_GRAVITY;
le->pos.trTime = cg.time - (rand()&15);
AnglesToAxis( cent->lerpAngles, v );
offset[0] = 8;
offset[1] = -4;
offset[2] = 24;
xoffset[0] = offset[0] * v[0][0] + offset[1] * v[1][0] + offset[2] * v[2][0];
xoffset[1] = offset[0] * v[0][1] + offset[1] * v[1][1] + offset[2] * v[2][1];
xoffset[2] = offset[0] * v[0][2] + offset[1] * v[1][2] + offset[2] * v[2][2];
VectorAdd( cent->lerpOrigin, xoffset, re->origin );
VectorCopy( re->origin, le->pos.trBase );
if ( CG_PointContents( re->origin, -1 ) & CONTENTS_WATER ) {
waterScale = 0.10f;
}
xvelocity[0] = velocity[0] * v[0][0] + velocity[1] * v[1][0] + velocity[2] * v[2][0];
xvelocity[1] = velocity[0] * v[0][1] + velocity[1] * v[1][1] + velocity[2] * v[2][1];
xvelocity[2] = velocity[0] * v[0][2] + velocity[1] * v[1][2] + velocity[2] * v[2][2];
VectorScale( xvelocity, waterScale, le->pos.trDelta );
AxisCopy( axisDefault, re->axis );
re->hModel = cgs.media.machinegunBrassModel;
le->bounceFactor = 0.4 * waterScale;
le->angles.trType = TR_LINEAR;
le->angles.trTime = cg.time;
le->angles.trBase[0] = rand()&31;
le->angles.trBase[1] = rand()&31;
le->angles.trBase[2] = rand()&31;
le->angles.trDelta[0] = 2;
le->angles.trDelta[1] = 1;
le->angles.trDelta[2] = 0;
le->leFlags = LEF_TUMBLE;
le->leBounceSoundType = LEBS_BRASS;
le->leMarkType = LEMT_NONE;
}
/*
==========================
CG_ShotgunEjectBrass
==========================
*/
static void CG_ShotgunEjectBrass( centity_t *cent ) {
localEntity_t *le;
refEntity_t *re;
vec3_t velocity, xvelocity;
vec3_t offset, xoffset;
vec3_t v[3];
int i;
if ( cg_brassTime.integer <= 0 ) {
return;
}
for ( i = 0; i < 2; i++ ) {
float waterScale = 1.0f;
le = CG_AllocLocalEntity();
re = &le->refEntity;
velocity[0] = 60 + 60 * crandom();
if ( i == 0 ) {
velocity[1] = 40 + 10 * crandom();
} else {
velocity[1] = -40 + 10 * crandom();
}
velocity[2] = 100 + 50 * crandom();
le->leType = LE_FRAGMENT;
le->startTime = cg.time;
le->endTime = le->startTime + cg_brassTime.integer*3 + cg_brassTime.integer * random();
le->pos.trType = TR_GRAVITY;
le->pos.trTime = cg.time;
AnglesToAxis( cent->lerpAngles, v );
offset[0] = 8;
offset[1] = 0;
offset[2] = 24;
xoffset[0] = offset[0] * v[0][0] + offset[1] * v[1][0] + offset[2] * v[2][0];
xoffset[1] = offset[0] * v[0][1] + offset[1] * v[1][1] + offset[2] * v[2][1];
xoffset[2] = offset[0] * v[0][2] + offset[1] * v[1][2] + offset[2] * v[2][2];
VectorAdd( cent->lerpOrigin, xoffset, re->origin );
VectorCopy( re->origin, le->pos.trBase );
if ( CG_PointContents( re->origin, -1 ) & CONTENTS_WATER ) {
waterScale = 0.10f;
}
xvelocity[0] = velocity[0] * v[0][0] + velocity[1] * v[1][0] + velocity[2] * v[2][0];
xvelocity[1] = velocity[0] * v[0][1] + velocity[1] * v[1][1] + velocity[2] * v[2][1];
xvelocity[2] = velocity[0] * v[0][2] + velocity[1] * v[1][2] + velocity[2] * v[2][2];
VectorScale( xvelocity, waterScale, le->pos.trDelta );
AxisCopy( axisDefault, re->axis );
re->hModel = cgs.media.shotgunBrassModel;
le->bounceFactor = 0.3f;
le->angles.trType = TR_LINEAR;
le->angles.trTime = cg.time;
le->angles.trBase[0] = rand()&31;
le->angles.trBase[1] = rand()&31;
le->angles.trBase[2] = rand()&31;
le->angles.trDelta[0] = 1;
le->angles.trDelta[1] = 0.5;
le->angles.trDelta[2] = 0;
le->leFlags = LEF_TUMBLE;
le->leBounceSoundType = LEBS_BRASS;
le->leMarkType = LEMT_NONE;
}
}
#ifdef MISSIONPACK
/*
==========================
CG_NailgunEjectBrass
==========================
*/
static void CG_NailgunEjectBrass( centity_t *cent ) {
localEntity_t *smoke;
vec3_t origin;
vec3_t v[3];
vec3_t offset;
vec3_t xoffset;
vec3_t up;
AnglesToAxis( cent->lerpAngles, v );
offset[0] = 0;
offset[1] = -12;
offset[2] = 24;
xoffset[0] = offset[0] * v[0][0] + offset[1] * v[1][0] + offset[2] * v[2][0];
xoffset[1] = offset[0] * v[0][1] + offset[1] * v[1][1] + offset[2] * v[2][1];
xoffset[2] = offset[0] * v[0][2] + offset[1] * v[1][2] + offset[2] * v[2][2];
VectorAdd( cent->lerpOrigin, xoffset, origin );
VectorSet( up, 0, 0, 64 );
smoke = CG_SmokePuff( origin, up, 32, 1, 1, 1, 0.33f, 700, cg.time, 0, 0, cgs.media.smokePuffShader );
// use the optimized local entity add
smoke->leType = LE_SCALE_FADE;
}
#endif
/*
==========================
CG_RailTrail
==========================
*/
void CG_RailTrail (clientInfo_t *ci, vec3_t start, vec3_t end) {
vec3_t axis[36], move, move2, next_move, vec, temp;
float len;
int i, j, skip;
localEntity_t *le;
refEntity_t *re;
#define RADIUS 4
#define ROTATION 1
#define SPACING 5
start[2] -= 4;
VectorCopy (start, move);
VectorSubtract (end, start, vec);
len = VectorNormalize (vec);
PerpendicularVector(temp, vec);
for (i = 0 ; i < 36; i++) {
RotatePointAroundVector(axis[i], vec, temp, i * 10);//banshee 2.4 was 10
}
le = CG_AllocLocalEntity();
re = &le->refEntity;
le->leType = LE_FADE_RGB;
le->startTime = cg.time;
le->endTime = cg.time + cg_railTrailTime.value;
le->lifeRate = 1.0 / (le->endTime - le->startTime);
re->shaderTime = cg.time / 1000.0f;
re->reType = RT_RAIL_CORE;
re->customShader = cgs.media.railCoreShader;
VectorCopy(start, re->origin);
VectorCopy(end, re->oldorigin);
re->shaderRGBA[0] = ci->color1[0] * 255;
re->shaderRGBA[1] = ci->color1[1] * 255;
re->shaderRGBA[2] = ci->color1[2] * 255;
re->shaderRGBA[3] = 255;
le->color[0] = ci->color1[0] * 0.75;
le->color[1] = ci->color1[1] * 0.75;
le->color[2] = ci->color1[2] * 0.75;
le->color[3] = 1.0f;
AxisClear( re->axis );
VectorMA(move, 20, vec, move);
VectorCopy(move, next_move);
VectorScale (vec, SPACING, vec);
if (cg_oldRail.integer != 0) {
// nudge down a bit so it isn't exactly in center
re->origin[2] -= 8;
re->oldorigin[2] -= 8;
return;
}
skip = -1;
j = 18;
for (i = 0; i < len; i += SPACING) {
if (i != skip) {
skip = i + SPACING;
le = CG_AllocLocalEntity();
re = &le->refEntity;
le->leFlags = LEF_PUFF_DONT_SCALE;
le->leType = LE_MOVE_SCALE_FADE;
le->startTime = cg.time;
le->endTime = cg.time + (i>>1) + 600;
le->lifeRate = 1.0 / (le->endTime - le->startTime);
re->shaderTime = cg.time / 1000.0f;
re->reType = RT_SPRITE;
re->radius = 1.1f;
re->customShader = cgs.media.railRingsShader;
re->shaderRGBA[0] = ci->color2[0] * 255;
re->shaderRGBA[1] = ci->color2[1] * 255;
re->shaderRGBA[2] = ci->color2[2] * 255;
re->shaderRGBA[3] = 255;
le->color[0] = ci->color2[0] * 0.75;
le->color[1] = ci->color2[1] * 0.75;
le->color[2] = ci->color2[2] * 0.75;
le->color[3] = 1.0f;
le->pos.trType = TR_LINEAR;
le->pos.trTime = cg.time;
VectorCopy( move, move2);
VectorMA(move2, RADIUS , axis[j], move2);
VectorCopy(move2, le->pos.trBase);
le->pos.trDelta[0] = axis[j][0]*6;
le->pos.trDelta[1] = axis[j][1]*6;
le->pos.trDelta[2] = axis[j][2]*6;
}
VectorAdd (move, vec, move);
j = j + ROTATION < 36 ? j + ROTATION : (j + ROTATION) % 36;
}
}
/*
==========================
CG_RocketTrail
==========================
*/
static void CG_RocketTrail( centity_t *ent, const weaponInfo_t *wi ) {
int step;
vec3_t origin, lastPos;
int t;
int startTime, contents;
int lastContents;
entityState_t *es;
vec3_t up;
localEntity_t *smoke;
if ( cg_noProjectileTrail.integer ) {
return;
}
up[0] = 0;
up[1] = 0;
up[2] = 0;
step = 50;
es = &ent->currentState;
startTime = ent->trailTime;
t = step * ( (startTime + step) / step );
BG_EvaluateTrajectory( &es->pos, cg.time, origin );
contents = CG_PointContents( origin, -1 );
// if object (e.g. grenade) is stationary, don't toss up smoke
if ( es->pos.trType == TR_STATIONARY ) {
ent->trailTime = cg.time;
return;
}
BG_EvaluateTrajectory( &es->pos, ent->trailTime, lastPos );
lastContents = CG_PointContents( lastPos, -1 );
ent->trailTime = cg.time;
if ( contents & ( CONTENTS_WATER | CONTENTS_SLIME | CONTENTS_LAVA ) ) {
if ( contents & lastContents & CONTENTS_WATER ) {
CG_BubbleTrail( lastPos, origin, 8 );
}
return;
}
for ( ; t <= ent->trailTime ; t += step ) {
BG_EvaluateTrajectory( &es->pos, t, lastPos );
smoke = CG_SmokePuff( lastPos, up,
wi->trailRadius,
1, 1, 1, 0.33f,
wi->wiTrailTime,
t,
0,
0,
cgs.media.smokePuffShader );
// use the optimized local entity add
smoke->leType = LE_SCALE_FADE;
}
}
#ifdef MISSIONPACK
/*
==========================
CG_NailTrail
==========================
*/
static void CG_NailTrail( centity_t *ent, const weaponInfo_t *wi ) {
int step;
vec3_t origin, lastPos;
int t;
int startTime, contents;
int lastContents;
entityState_t *es;
vec3_t up;
localEntity_t *smoke;
if ( cg_noProjectileTrail.integer ) {
return;
}
up[0] = 0;
up[1] = 0;
up[2] = 0;
step = 50;
es = &ent->currentState;
startTime = ent->trailTime;
t = step * ( (startTime + step) / step );
BG_EvaluateTrajectory( &es->pos, cg.time, origin );
contents = CG_PointContents( origin, -1 );
// if object (e.g. grenade) is stationary, don't toss up smoke
if ( es->pos.trType == TR_STATIONARY ) {
ent->trailTime = cg.time;
return;
}
BG_EvaluateTrajectory( &es->pos, ent->trailTime, lastPos );
lastContents = CG_PointContents( lastPos, -1 );
ent->trailTime = cg.time;
if ( contents & ( CONTENTS_WATER | CONTENTS_SLIME | CONTENTS_LAVA ) ) {
if ( contents & lastContents & CONTENTS_WATER ) {
CG_BubbleTrail( lastPos, origin, 8 );
}
return;
}
for ( ; t <= ent->trailTime ; t += step ) {
BG_EvaluateTrajectory( &es->pos, t, lastPos );
smoke = CG_SmokePuff( lastPos, up,
wi->trailRadius,
1, 1, 1, 0.33f,
wi->wiTrailTime,
t,
0,
0,
cgs.media.nailPuffShader );
// use the optimized local entity add
smoke->leType = LE_SCALE_FADE;
}
}
#endif
/*
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -