📄 g_weapon.c
字号:
if (!ent->client->fireHeld && !ent->client->hook)
fire_grapple (ent, muzzle, forward);
ent->client->fireHeld = qtrue;
}
void Weapon_HookFree (gentity_t *ent)
{
ent->parent->client->hook = NULL;
ent->parent->client->ps.pm_flags &= ~PMF_GRAPPLE_PULL;
G_FreeEntity( ent );
}
void Weapon_HookThink (gentity_t *ent)
{
if (ent->enemy) {
vec3_t v, oldorigin;
VectorCopy(ent->r.currentOrigin, oldorigin);
v[0] = ent->enemy->r.currentOrigin[0] + (ent->enemy->r.mins[0] + ent->enemy->r.maxs[0]) * 0.5;
v[1] = ent->enemy->r.currentOrigin[1] + (ent->enemy->r.mins[1] + ent->enemy->r.maxs[1]) * 0.5;
v[2] = ent->enemy->r.currentOrigin[2] + (ent->enemy->r.mins[2] + ent->enemy->r.maxs[2]) * 0.5;
SnapVectorTowards( v, oldorigin ); // save net bandwidth
G_SetOrigin( ent, v );
}
VectorCopy( ent->r.currentOrigin, ent->parent->client->ps.grapplePoint);
}
/*
======================================================================
LIGHTNING GUN
======================================================================
*/
void Weapon_LightningFire( gentity_t *ent ) {
trace_t tr;
vec3_t end;
#ifdef MISSIONPACK
vec3_t impactpoint, bouncedir;
#endif
gentity_t *traceEnt, *tent;
int damage, i, passent;
damage = 8 * s_quadFactor;
passent = ent->s.number;
for (i = 0; i < 10; i++) {
VectorMA( muzzle, LIGHTNING_RANGE, forward, end );
trap_Trace( &tr, muzzle, NULL, NULL, end, passent, MASK_SHOT );
#ifdef MISSIONPACK
// if not the first trace (the lightning bounced of an invulnerability sphere)
if (i) {
// add bounced off lightning bolt temp entity
// the first lightning bolt is a cgame only visual
//
tent = G_TempEntity( muzzle, EV_LIGHTNINGBOLT );
VectorCopy( tr.endpos, end );
SnapVector( end );
VectorCopy( end, tent->s.origin2 );
}
#endif
if ( tr.entityNum == ENTITYNUM_NONE ) {
return;
}
traceEnt = &g_entities[ tr.entityNum ];
if ( traceEnt->takedamage) {
#ifdef MISSIONPACK
if ( traceEnt->client && traceEnt->client->invulnerabilityTime > level.time ) {
if (G_InvulnerabilityEffect( traceEnt, forward, tr.endpos, impactpoint, bouncedir )) {
G_BounceProjectile( muzzle, impactpoint, bouncedir, end );
VectorCopy( impactpoint, muzzle );
VectorSubtract( end, impactpoint, forward );
VectorNormalize(forward);
// the player can hit him/herself with the bounced lightning
passent = ENTITYNUM_NONE;
}
else {
VectorCopy( tr.endpos, muzzle );
passent = traceEnt->s.number;
}
continue;
}
else {
G_Damage( traceEnt, ent, ent, forward, tr.endpos,
damage, 0, MOD_LIGHTNING);
}
#else
G_Damage( traceEnt, ent, ent, forward, tr.endpos,
damage, 0, MOD_LIGHTNING);
#endif
}
if ( traceEnt->takedamage && traceEnt->client ) {
tent = G_TempEntity( tr.endpos, EV_MISSILE_HIT );
tent->s.otherEntityNum = traceEnt->s.number;
tent->s.eventParm = DirToByte( tr.plane.normal );
tent->s.weapon = ent->s.weapon;
if( LogAccuracyHit( traceEnt, ent ) ) {
ent->client->accuracy_hits++;
}
} else if ( !( tr.surfaceFlags & SURF_NOIMPACT ) ) {
tent = G_TempEntity( tr.endpos, EV_MISSILE_MISS );
tent->s.eventParm = DirToByte( tr.plane.normal );
}
break;
}
}
#ifdef MISSIONPACK
/*
======================================================================
NAILGUN
======================================================================
*/
void Weapon_Nailgun_Fire (gentity_t *ent) {
gentity_t *m;
int count;
for( count = 0; count < NUM_NAILSHOTS; count++ ) {
m = fire_nail (ent, muzzle, forward, right, up );
m->damage *= s_quadFactor;
m->splashDamage *= s_quadFactor;
}
// VectorAdd( m->s.pos.trDelta, ent->client->ps.velocity, m->s.pos.trDelta ); // "real" physics
}
/*
======================================================================
PROXIMITY MINE LAUNCHER
======================================================================
*/
void weapon_proxlauncher_fire (gentity_t *ent) {
gentity_t *m;
// extra vertical velocity
forward[2] += 0.2f;
VectorNormalize( forward );
m = fire_prox (ent, muzzle, forward);
m->damage *= s_quadFactor;
m->splashDamage *= s_quadFactor;
// VectorAdd( m->s.pos.trDelta, ent->client->ps.velocity, m->s.pos.trDelta ); // "real" physics
}
#endif
//======================================================================
/*
===============
LogAccuracyHit
===============
*/
qboolean LogAccuracyHit( gentity_t *target, gentity_t *attacker ) {
if( !target->takedamage ) {
return qfalse;
}
if ( target == attacker ) {
return qfalse;
}
if( !target->client ) {
return qfalse;
}
if( !attacker->client ) {
return qfalse;
}
if( target->client->ps.stats[STAT_HEALTH] <= 0 ) {
return qfalse;
}
if ( OnSameTeam( target, attacker ) ) {
return qfalse;
}
return qtrue;
}
/*
===============
CalcMuzzlePoint
set muzzle location relative to pivoting eye
===============
*/
void CalcMuzzlePoint ( gentity_t *ent, vec3_t forward, vec3_t right, vec3_t up, vec3_t muzzlePoint ) {
VectorCopy( ent->s.pos.trBase, muzzlePoint );
muzzlePoint[2] += ent->client->ps.viewheight;
VectorMA( muzzlePoint, 14, forward, muzzlePoint );
// snap to integer coordinates for more efficient network bandwidth usage
SnapVector( muzzlePoint );
}
/*
===============
CalcMuzzlePointOrigin
set muzzle location relative to pivoting eye
===============
*/
void CalcMuzzlePointOrigin ( gentity_t *ent, vec3_t origin, vec3_t forward, vec3_t right, vec3_t up, vec3_t muzzlePoint ) {
VectorCopy( ent->s.pos.trBase, muzzlePoint );
muzzlePoint[2] += ent->client->ps.viewheight;
VectorMA( muzzlePoint, 14, forward, muzzlePoint );
// snap to integer coordinates for more efficient network bandwidth usage
SnapVector( muzzlePoint );
}
/*
===============
FireWeapon
===============
*/
void FireWeapon( gentity_t *ent ) {
if (ent->client->ps.powerups[PW_QUAD] ) {
s_quadFactor = g_quadfactor.value;
} else {
s_quadFactor = 1;
}
#ifdef MISSIONPACK
if( ent->client->persistantPowerup && ent->client->persistantPowerup->item && ent->client->persistantPowerup->item->giTag == PW_DOUBLER ) {
s_quadFactor *= 2;
}
#endif
// track shots taken for accuracy tracking. Grapple is not a weapon and gauntet is just not tracked
if( ent->s.weapon != WP_GRAPPLING_HOOK && ent->s.weapon != WP_GAUNTLET ) {
#ifdef MISSIONPACK
if( ent->s.weapon == WP_NAILGUN ) {
ent->client->accuracy_shots += NUM_NAILSHOTS;
} else {
ent->client->accuracy_shots++;
}
#else
ent->client->accuracy_shots++;
#endif
}
// set aiming directions
AngleVectors (ent->client->ps.viewangles, forward, right, up);
CalcMuzzlePointOrigin ( ent, ent->client->oldOrigin, forward, right, up, muzzle );
// fire the specific weapon
switch( ent->s.weapon ) {
case WP_GAUNTLET:
Weapon_Gauntlet( ent );
break;
case WP_LIGHTNING:
Weapon_LightningFire( ent );
break;
case WP_SHOTGUN:
weapon_supershotgun_fire( ent );
break;
case WP_MACHINEGUN:
if ( g_gametype.integer != GT_TEAM ) {
Bullet_Fire( ent, MACHINEGUN_SPREAD, MACHINEGUN_DAMAGE );
} else {
Bullet_Fire( ent, MACHINEGUN_SPREAD, MACHINEGUN_TEAM_DAMAGE );
}
break;
case WP_GRENADE_LAUNCHER:
weapon_grenadelauncher_fire( ent );
break;
case WP_ROCKET_LAUNCHER:
Weapon_RocketLauncher_Fire( ent );
break;
case WP_PLASMAGUN:
Weapon_Plasmagun_Fire( ent );
break;
case WP_RAILGUN:
weapon_railgun_fire( ent );
break;
case WP_BFG:
BFG_Fire( ent );
break;
case WP_GRAPPLING_HOOK:
Weapon_GrapplingHook_Fire( ent );
break;
#ifdef MISSIONPACK
case WP_NAILGUN:
Weapon_Nailgun_Fire( ent );
break;
case WP_PROX_LAUNCHER:
weapon_proxlauncher_fire( ent );
break;
case WP_CHAINGUN:
Bullet_Fire( ent, CHAINGUN_SPREAD, MACHINEGUN_DAMAGE );
break;
#endif
default:
// FIXME G_Error( "Bad ent->s.weapon" );
break;
}
}
#ifdef MISSIONPACK
/*
===============
KamikazeRadiusDamage
===============
*/
static void KamikazeRadiusDamage( vec3_t origin, gentity_t *attacker, float damage, float radius ) {
float dist;
gentity_t *ent;
int entityList[MAX_GENTITIES];
int numListedEntities;
vec3_t mins, maxs;
vec3_t v;
vec3_t dir;
int i, e;
if ( radius < 1 ) {
radius = 1;
}
for ( i = 0 ; i < 3 ; i++ ) {
mins[i] = origin[i] - radius;
maxs[i] = origin[i] + radius;
}
numListedEntities = trap_EntitiesInBox( mins, maxs, entityList, MAX_GENTITIES );
for ( e = 0 ; e < numListedEntities ; e++ ) {
ent = &g_entities[entityList[ e ]];
if (!ent->takedamage) {
continue;
}
// dont hit things we have already hit
if( ent->kamikazeTime > level.time ) {
continue;
}
// find the distance from the edge of the bounding box
for ( i = 0 ; i < 3 ; i++ ) {
if ( origin[i] < ent->r.absmin[i] ) {
v[i] = ent->r.absmin[i] - origin[i];
} else if ( origin[i] > ent->r.absmax[i] ) {
v[i] = origin[i] - ent->r.absmax[i];
} else {
v[i] = 0;
}
}
dist = VectorLength( v );
if ( dist >= radius ) {
continue;
}
// if( CanDamage (ent, origin) ) {
VectorSubtract (ent->r.currentOrigin, origin, dir);
// push the center of mass higher than the origin so players
// get knocked into the air more
dir[2] += 24;
G_Damage( ent, NULL, attacker, dir, origin, damage, DAMAGE_RADIUS|DAMAGE_NO_TEAM_PROTECTION, MOD_KAMIKAZE );
ent->kamikazeTime = level.time + 3000;
// }
}
}
/*
===============
KamikazeShockWave
===============
*/
static void KamikazeShockWave( vec3_t origin, gentity_t *attacker, float damage, float push, float radius ) {
float dist;
gentity_t *ent;
int entityList[MAX_GENTITIES];
int numListedEntities;
vec3_t mins, maxs;
vec3_t v;
vec3_t dir;
int i, e;
if ( radius < 1 )
radius = 1;
for ( i = 0 ; i < 3 ; i++ ) {
mins[i] = origin[i] - radius;
maxs[i] = origin[i] + radius;
}
numListedEntities = trap_EntitiesInBox( mins, maxs, entityList, MAX_GENTITIES );
for ( e = 0 ; e < numListedEntities ; e++ ) {
ent = &g_entities[entityList[ e ]];
// dont hit things we have already hit
if( ent->kamikazeShockTime > level.time ) {
continue;
}
// find the distance from the edge of the bounding box
for ( i = 0 ; i < 3 ; i++ ) {
if ( origin[i] < ent->r.absmin[i] ) {
v[i] = ent->r.absmin[i] - origin[i];
} else if ( origin[i] > ent->r.absmax[i] ) {
v[i] = origin[i] - ent->r.absmax[i];
} else {
v[i] = 0;
}
}
dist = VectorLength( v );
if ( dist >= radius ) {
continue;
}
// if( CanDamage (ent, origin) ) {
VectorSubtract (ent->r.currentOrigin, origin, dir);
dir[2] += 24;
G_Damage( ent, NULL, attacker, dir, origin, damage, DAMAGE_RADIUS|DAMAGE_NO_TEAM_PROTECTION, MOD_KAMIKAZE );
//
dir[2] = 0;
VectorNormalize(dir);
if ( ent->client ) {
ent->client->ps.velocity[0] = dir[0] * push;
ent->client->ps.velocity[1] = dir[1] * push;
ent->client->ps.velocity[2] = 100;
}
ent->kamikazeShockTime = level.time + 3000;
// }
}
}
/*
===============
KamikazeDamage
===============
*/
static void KamikazeDamage( gentity_t *self ) {
int i;
float t;
gentity_t *ent;
vec3_t newangles;
self->count += 100;
if (self->count >= KAMI_SHOCKWAVE_STARTTIME) {
// shockwave push back
t = self->count - KAMI_SHOCKWAVE_STARTTIME;
KamikazeShockWave(self->s.pos.trBase, self->activator, 25, 400, (int) (float) t * KAMI_SHOCKWAVE_MAXRADIUS / (KAMI_SHOCKWAVE_ENDTIME - KAMI_SHOCKWAVE_STARTTIME) );
}
//
if (self->count >= KAMI_EXPLODE_STARTTIME) {
// do our damage
t = self->count - KAMI_EXPLODE_STARTTIME;
KamikazeRadiusDamage( self->s.pos.trBase, self->activator, 400, (int) (float) t * KAMI_BOOMSPHERE_MAXRADIUS / (KAMI_IMPLODE_STARTTIME - KAMI_EXPLODE_STARTTIME) );
}
// either cycle or kill self
if( self->count >= KAMI_SHOCKWAVE_ENDTIME ) {
G_FreeEntity( self );
return;
}
self->nextthink = level.time + 100;
// add earth quake effect
newangles[0] = crandom() * 2;
newangles[1] = crandom() * 2;
newangles[2] = 0;
for (i = 0; i < MAX_CLIENTS; i++)
{
ent = &g_entities[i];
if (!ent->inuse)
continue;
if (!ent->client)
continue;
if (ent->client->ps.groundEntityNum != ENTITYNUM_NONE) {
ent->client->ps.velocity[0] += crandom() * 120;
ent->client->ps.velocity[1] += crandom() * 120;
ent->client->ps.velocity[2] = 30 + random() * 25;
}
ent->client->ps.delta_angles[0] += ANGLE2SHORT(newangles[0] - self->movedir[0]);
ent->client->ps.delta_angles[1] += ANGLE2SHORT(newangles[1] - self->movedir[1]);
ent->client->ps.delta_angles[2] += ANGLE2SHORT(newangles[2] - self->movedir[2]);
}
VectorCopy(newangles, self->movedir);
}
/*
===============
G_StartKamikaze
===============
*/
void G_StartKamikaze( gentity_t *ent ) {
gentity_t *explosion;
gentity_t *te;
vec3_t snapped;
// start up the explosion logic
explosion = G_Spawn();
explosion->s.eType = ET_EVENTS + EV_KAMIKAZE;
explosion->eventTime = level.time;
if ( ent->client ) {
VectorCopy( ent->s.pos.trBase, snapped );
}
else {
VectorCopy( ent->activator->s.pos.trBase, snapped );
}
SnapVector( snapped ); // save network bandwidth
G_SetOrigin( explosion, snapped );
explosion->classname = "kamikaze";
explosion->s.pos.trType = TR_STATIONARY;
explosion->kamikazeTime = level.time;
explosion->think = KamikazeDamage;
explosion->nextthink = level.time + 100;
explosion->count = 0;
VectorClear(explosion->movedir);
trap_LinkEntity( explosion );
if (ent->client) {
//
explosion->activator = ent;
//
ent->s.eFlags &= ~EF_KAMIKAZE;
// nuke the guy that used it
G_Damage( ent, ent, ent, NULL, NULL, 100000, DAMAGE_NO_PROTECTION, MOD_KAMIKAZE );
}
else {
if ( !strcmp(ent->activator->classname, "bodyque") ) {
explosion->activator = &g_entities[ent->activator->r.ownerNum];
}
else {
explosion->activator = ent->activator;
}
}
// play global sound at all clients
te = G_TempEntity(snapped, EV_GLOBAL_TEAM_SOUND );
te->r.svFlags |= SVF_BROADCAST;
te->s.eventParm = GTS_KAMIKAZE;
}
#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -