Exemple #1
0
qboolean ShotgunPellet( vec3_t start, vec3_t end, gentity_t *ent ) {
	trace_t		tr;
	int			damage, i, passent;
	gentity_t	*traceEnt;
#ifdef MISSIONPACK
	vec3_t		impactpoint, bouncedir;
#endif
	vec3_t		tr_start, tr_end;

	passent = ent->s.number;
	VectorCopy( start, tr_start );
	VectorCopy( end, tr_end );
	for (i = 0; i < 10; i++) {
		trap_Trace (&tr, tr_start, NULL, NULL, tr_end, passent, MASK_SHOT);
		traceEnt = &g_entities[ tr.entityNum ];

		// send bullet impact
		if (  tr.surfaceFlags & SURF_NOIMPACT ) {
			return qfalse;
		}

		if ( traceEnt->takedamage) {

			/* LQ3A */
			damage = (g_damageShell.integer > 0) ? g_damageShell.integer : 0;
			damage *= s_quadFactor;

#ifdef MISSIONPACK
			if ( traceEnt->client && traceEnt->client->invulnerabilityTime > level.time ) {
				if (G_InvulnerabilityEffect( traceEnt, forward, tr.endpos, impactpoint, bouncedir )) {
					G_BounceProjectile( tr_start, impactpoint, bouncedir, tr_end );
					VectorCopy( impactpoint, tr_start );
					// the player can hit him/herself with the bounced rail
					passent = ENTITYNUM_NONE;
				}
				else {
					VectorCopy( tr.endpos, tr_start );
					passent = traceEnt->s.number;
				}
				continue;
			}
			else {
				G_Damage( traceEnt, ent, ent, forward, tr.endpos,
					damage, 0, MOD_SHOTGUN);
				if( LogAccuracyHit( traceEnt, ent ) ) {
					return qtrue;
				}
			}
#else
			G_Damage( traceEnt, ent, ent, forward, tr.endpos,	damage, 0, MOD_SHOTGUN);
				if( LogAccuracyHit( traceEnt, ent ) ) {
					return qtrue;
				}
#endif
		}
		return qfalse;
	}
	return qfalse;
}
void Weapon_LightningFire( gentity_t *ent ) {
	trace_t		tr;
	vec3_t		end;
#if 1
	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 );

#if 1
		// 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) {
#if 1
			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;
	}
}
void Bullet_Fire (gentity_t *ent, float spread, int damage ) {
	trace_t		tr;
	vec3_t		end;
#if 1
	vec3_t		impactpoint, bouncedir;
#endif
	float		r, f, d;
	float		u;
	gentity_t	*tent;
	gentity_t	*traceEnt;
	int			i, passent;

	vec3_t		forward, right, up;

	AngleVectors (ent->client->ps.viewangles, forward, right, up);
	CalcMuzzlePoint ( ent, forward, right, up, muzzle );
	ent->client->accuracy_shots++;
	f = ((float)(ent->client->accuracy_shots % SPIRAL_SIZE)) / SPIRAL_SIZE; // 0 >= f >= 1
	d = (f+(1/SPIRAL_SIZE)) * 2.0 * M_PI;

	damage *= s_quadFactor;

	//Com_Printf("f: %f, d: %f\n, a: %i", f, d, ent->client->accuracy_shots);

	u = sin(d) * (f * spread);
	r = cos(d) * (f * spread);

	//Com_Printf("end1 : [%f, %f, %f]\n", end[0], end[1], end[2]);

	VectorMA (muzzle, 8192, forward, end);

	//Com_Printf("end2 : [%f, %f, %f]\n", end[0], end[1], end[2]);
	//Com_Printf("right : [%f, %f, %f]\n", right[0], right[1], right[2]);
	VectorMA (end, r, right, end);

	//Com_Printf("end3 : [%f, %f, %f]\n", end[0], end[1], end[2]);
	//Com_Printf("up : [%f, %f, %f]\n", up[0], up[1], up[2]);

	VectorMA (end, u, up, end);

	//Com_Printf("end4 : [%f, %f, %f]\n", end[0], end[1], end[2]);

	passent = ent->s.number;
	for (i = 0; i < 10; i++) {

		trap_Trace (&tr, muzzle, NULL, NULL, end, passent, MASK_SHOT);
		if ( tr.surfaceFlags & SURF_NOIMPACT ) {
			return;
		}

		traceEnt = &g_entities[ tr.entityNum ];

		// snap the endpos to integers, but nudged towards the line
		SnapVectorTowards( tr.endpos, muzzle );

		// send bullet impact
		if ( traceEnt->takedamage && traceEnt->client ) {
			tent = G_TempEntity( tr.endpos, EV_BULLET_HIT_FLESH );
			tent->s.eventParm = traceEnt->s.number;
			if( LogAccuracyHit( traceEnt, ent ) ) {
				ent->client->accuracy_hits++;
			}
		} else {
			tent = G_TempEntity( tr.endpos, EV_BULLET_HIT_WALL );
			tent->s.eventParm = DirToByte( tr.plane.normal );
		}
		tent->s.otherEntityNum = ent->s.number;

		if ( traceEnt->takedamage) {
#if 1
			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 );
					// the player can hit him/herself with the bounced rail
					passent = ENTITYNUM_NONE;
				}
				else {
					VectorCopy( tr.endpos, muzzle );
					passent = traceEnt->s.number;
				}
				continue;
			}
			else {
#endif
				G_Damage( traceEnt, ent, ent, forward, tr.endpos,
					damage, 0, MOD_MACHINEGUN);
#if 1
			}
#endif
		}
		break;
	}
}
Exemple #4
0
void weapon_railgun_fire (gentity_t *ent) {
	vec3_t		end;
#ifdef MISSIONPACK
	vec3_t impactpoint, bouncedir;
#endif
	trace_t		trace;
	gentity_t	*tent;
	gentity_t	*traceEnt;
	int			damage;
	int			i;
	int			hits;
	int			unlinked;
	int			passent;
	gentity_t	*unlinkedEntities[MAX_RAIL_HITS];

    LS_Weapon_Fire_Start(WF_RAIL, ent);


	damage = 100 * s_quadFactor;

	VectorMA (muzzle, 8192, forward, end);

	// trace only against the solids, so the railgun will go through people
	unlinked = 0;
	hits = 0;
	passent = ent->s.number;
	do {
		trap_Trace (&trace, muzzle, NULL, NULL, end, passent, MASK_SHOT );
		if ( trace.entityNum >= ENTITYNUM_MAX_NORMAL ) {
			break;
		}
		traceEnt = &g_entities[ trace.entityNum ];
		if ( traceEnt->takedamage ) {
#ifdef MISSIONPACK
			if ( traceEnt->client && traceEnt->client->invulnerabilityTime > level.time ) {
				if ( G_InvulnerabilityEffect( traceEnt, forward, trace.endpos, impactpoint, bouncedir ) ) {
					G_BounceProjectile( muzzle, impactpoint, bouncedir, end );
					// snap the endpos to integers to save net bandwidth, but nudged towards the line
					SnapVectorTowards( trace.endpos, muzzle );
					// send railgun beam effect
					tent = G_TempEntity( trace.endpos, EV_RAILTRAIL );
					// set player number for custom colors on the railtrail
					tent->s.clientNum = ent->s.clientNum;
					VectorCopy( muzzle, tent->s.origin2 );
					// move origin a bit to come closer to the drawn gun muzzle
					VectorMA( tent->s.origin2, 4, right, tent->s.origin2 );
					VectorMA( tent->s.origin2, -1, up, tent->s.origin2 );
					tent->s.eventParm = 255;	// don't make the explosion at the end
					//
					VectorCopy( impactpoint, muzzle );
					// the player can hit him/herself with the bounced rail
					passent = ENTITYNUM_NONE;
				}
			}
			else {
				if( LogAccuracyHit( traceEnt, ent ) ) {
					hits++;
				}
				G_Damage (traceEnt, ent, ent, forward, trace.endpos, damage, 0, MOD_RAILGUN);
			}
#else
				if( LogAccuracyHit( traceEnt, ent ) ) {
					hits++;
				}
				G_Damage (traceEnt, ent, ent, forward, trace.endpos, damage, 0, MOD_RAILGUN);
#endif
		}
		if ( trace.contents & CONTENTS_SOLID ) {
			break;		// we hit something solid enough to stop the beam
		}
		// unlink this entity, so the next trace will go past it
		trap_UnlinkEntity( traceEnt );
		unlinkedEntities[unlinked] = traceEnt;
		unlinked++;
	} while ( unlinked < MAX_RAIL_HITS );

	// link back in any entities we unlinked
	for ( i = 0 ; i < unlinked ; i++ ) {
		trap_LinkEntity( unlinkedEntities[i] );
	}

	// the final trace endpos will be the terminal point of the rail trail

	// snap the endpos to integers to save net bandwidth, but nudged towards the line
	SnapVectorTowards( trace.endpos, muzzle );

	// send railgun beam effect
	tent = G_TempEntity( trace.endpos, EV_RAILTRAIL );

	// set player number for custom colors on the railtrail
	tent->s.clientNum = ent->s.clientNum;

	VectorCopy( muzzle, tent->s.origin2 );
	// move origin a bit to come closer to the drawn gun muzzle
	VectorMA( tent->s.origin2, 4, right, tent->s.origin2 );
	VectorMA( tent->s.origin2, -1, up, tent->s.origin2 );

	// no explosion at end if SURF_NOIMPACT, but still make the trail
	if ( trace.surfaceFlags & SURF_NOIMPACT ) {
		tent->s.eventParm = 255;	// don't make the explosion at the end
	} else {
		tent->s.eventParm = DirToByte( trace.plane.normal );
	}
	tent->s.clientNum = ent->s.clientNum;

	// give the shooter a reward sound if they have made two railgun hits in a row
	if ( hits == 0 ) {
		// complete miss
		ent->client->accurateCount = 0;
	} else {
		// check for "impressive" reward sound
		ent->client->accurateCount += hits;
		if ( ent->client->accurateCount >= 2 ) {
			ent->client->accurateCount -= 2;
			ent->client->ps.persistant[PERS_IMPRESSIVE_COUNT]++;
			// add the sprite over the player's head
			ent->client->ps.eFlags &= ~(EF_AWARD_IMPRESSIVE | EF_AWARD_EXCELLENT | EF_AWARD_GAUNTLET | EF_AWARD_ASSIST | EF_AWARD_DEFEND | EF_AWARD_CAP );
			ent->client->ps.eFlags |= EF_AWARD_IMPRESSIVE;
			ent->client->rewardTime = level.time + REWARD_SPRITE_TIME;
		}
		ent->client->accuracy_hits++;
	}
    LS_Weapon_Fire_End(WF_RAIL, ent);

}
Exemple #5
0
void Bullet_Fire (gentity_t *ent, float spread, int damage ) {
	trace_t		tr;
	vec3_t		end;
#ifdef MISSIONPACK
	vec3_t		impactpoint, bouncedir;
#endif
	float		r;
	float		u;
	gentity_t	*tent;
	gentity_t	*traceEnt;
	int			i, passent;

	damage *= s_quadFactor;

	r = random() * M_PI * 2.0f;
	u = sin(r) * crandom() * spread * 16;
	r = cos(r) * crandom() * spread * 16;
	VectorMA (muzzle, 8192*16, forward, end);
	VectorMA (end, r, right, end);
	VectorMA (end, u, up, end);

	passent = ent->s.number;
	for (i = 0; i < 10; i++) {

		trap_Trace (&tr, muzzle, NULL, NULL, end, passent, MASK_SHOT);
		if ( tr.surfaceFlags & SURF_NOIMPACT ) {
			return;
		}

		traceEnt = &g_entities[ tr.entityNum ];

		// snap the endpos to integers, but nudged towards the line
		SnapVectorTowards( tr.endpos, muzzle );

		// send bullet impact
		if ( traceEnt->takedamage && traceEnt->client ) {
			tent = G_TempEntity( tr.endpos, EV_BULLET_HIT_FLESH );
			tent->s.eventParm = traceEnt->s.number;
			if( LogAccuracyHit( traceEnt, ent ) ) {
				ent->client->accuracy_hits++;
			}
		} else {
			tent = G_TempEntity( tr.endpos, EV_BULLET_HIT_WALL );
			tent->s.eventParm = DirToByte( tr.plane.normal );
		}
		tent->s.otherEntityNum = ent->s.number;

		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 );
					// the player can hit him/herself with the bounced rail
					passent = ENTITYNUM_NONE;
				}
				else {
					VectorCopy( tr.endpos, muzzle );
					passent = traceEnt->s.number;
				}
				continue;
			}
			else {
#endif
				G_Damage( traceEnt, ent, ent, forward, tr.endpos,
					damage, 0, MOD_MACHINEGUN);
#ifdef MISSIONPACK
			}
#endif
		}
		break;
	}
}
// self is the "parent", the entity that owns the missile (like a player or shooter_*)
qboolean fire_projectile(gentity_t *self, vec3_t start, vec3_t forward,
		vec3_t right, vec3_t up, int projnum, float quadFactor,
		int mod, int splashMod, int handSide)
{
	vec3_t		mins = { -8, -8, -8 };
	vec3_t		maxs = {  8,  8,  8 };
	gentity_t	*bolt;
	vec3_t		dir;
	vec3_t		end;
	int count;
	int spread;
	int damage;
	int splashDamage;
	float splashRadius;
	int range;
	qboolean hitClient;

	if (projnum < 0 || projnum >= BG_NumProjectiles())
	{
		return qfalse;
	}

	// Check if can fire grappling projectile
	if (self && self->player && bg_projectileinfo[projnum].grappling)
	{
#ifdef IOQ3ZTM
#ifdef TURTLEARENA // HOLD_SHURIKEN
		if (handSide == HS_CENTER) // Shuriken holdable item
		{
			if ((self->player->ps.pm_flags & PMF_USE_ITEM_HELD) || self->player->hook) {
				return qfalse;
			}
			self->player->ps.pm_flags |= PMF_USE_ITEM_HELD;
		}
		else
#endif
		{
			if ((self->player->ps.pm_flags & PMF_FIRE_HELD) || self->player->hook) {
				return qfalse;
			}
			self->player->ps.pm_flags |= PMF_FIRE_HELD;
		}
#else
		if (self->player->fireHeld || self->player->hook) {
			return qfalse;
		}
		self->player->fireHeld = qtrue;
#endif
	}

	spread = bg_projectileinfo[projnum].spread;
#if 0 // ZTM: WONTFIX: Only for machinegun
	if (g_gametype.integer == GT_TEAM)
	{
		damage = bg_projectileinfo[projnum].damage * 0.7;
		splashDamage = bg_projectileinfo[projnum].splashDamage * 0.7;
	}
	else
#endif
	{
		damage = bg_projectileinfo[projnum].damage;
		splashDamage = bg_projectileinfo[projnum].splashDamage;
	}
	splashRadius = bg_projectileinfo[projnum].splashRadius;

	if (quadFactor > 1) {
		damage *= quadFactor;
		splashDamage *= quadFactor;
	}

	// Use default kill messages
	// Missile is spawned
	if (mod == MOD_UNKNOWN) {
		mod = MOD_PROJECTILE;
	}
	if (splashMod == MOD_UNKNOWN) {
		splashMod = MOD_PROJECTILE_EXPLOSION;
	}

	range = 0;
	if (bg_projectileinfo[projnum].instantDamage)
	{
		range = bg_projectileinfo[projnum].speed;
	}
	if (!range) {
		// 8192 is used by bullets, railgun, and nails
		// Lightning uses 768
		range = 8192;
	}

	for (count = 0; count < bg_projectileinfo[projnum].numProjectiles; count++ )
	{
		if (spread) // if spread make your own dir.
		{
			float		r, u;

			r = random() * M_PI * 2.0f;
			u = sin(r) * crandom() * spread * 16;
			r = cos(r) * crandom() * spread * 16;
			VectorMA(start, (range * 16), forward, end);
			VectorMA(end, r, right, end);
			VectorMA(end, u, up, end);
			VectorSubtract(end, start, dir);
		}
		else
		{
			VectorMA(start, range, forward, end);
			VectorCopy(forward, dir);
		}

		if (bg_projectileinfo[projnum].flags & PF_USE_GRAVITY)
		{
			// extra vertical velocity
			dir[2] += 0.2f;
		}

		VectorNormalize (dir);

		if (bg_projectileinfo[projnum].instantDamage)
		{
			// Based on Q3's Bullet_Fire
			//    (with extra code from Weapon_LightningFire and weapon_railgun_fire)
			trace_t		tr;
#if defined MISSIONPACK && !defined TURTLEARENA // POWERS
			vec3_t		impactpoint, bouncedir;
#endif
			gentity_t	*tent;
			gentity_t	*traceEnt;
			int			i, passent;
			int			unlinked;
			gentity_t	*unlinkedEntities[10];
			int			hits;

			unlinked = hits = 0;

			// Do a bullet trace instead of spawning a missile.
			passent = self->s.number;
			for (i = 0; i < 10; i++) // 10 for lightning
			{
				trap_Trace (&tr, start, NULL, NULL, end, passent, MASK_SHOT);

#if defined MISSIONPACK && !defined TURTLEARENA // POWERS
				// if not the first trace (the lightning bounced off an invulnerability sphere)
				if (i && bg_projectileinfo[projnum].trailType == PT_LIGHTNING) {
					// add bounced off lightning bolt temp entity
					// the first lightning bolt is a cgame only visual
					//
					tent = G_TempEntity( start, EV_LIGHTNINGBOLT );
					tent->s.weapon = projnum;
					VectorCopy( tr.endpos, end );
					SnapVector( end );
					VectorCopy( end, tent->s.origin2 );
				}
#endif
#if 0 // RAIL
				if ( tr.entityNum >= ENTITYNUM_MAX_NORMAL ) {
					break;
				}
#else // LIGHTNING
				if ( tr.entityNum == ENTITYNUM_NONE ) {
					break;
				}
#endif

				traceEnt = &g_entities[ tr.entityNum ];

				// snap the endpos to integers, but nudged towards the line
				SnapVectorTowards( tr.endpos, start );

				if ( !(tr.surfaceFlags & SURF_NOIMPACT) )
				{
					// send bullet impact
					if ( traceEnt->takedamage && traceEnt->player )
					{
#if 1 // lightning
						tent = G_TempEntity( tr.endpos, EV_MISSILE_HIT );
						tent->s.otherEntityNum = traceEnt->s.number;
						tent->s.eventParm = DirToByte( tr.plane.normal );
						tent->s.playerNum = self->s.number;
#else
						tent = G_TempEntity( tr.endpos, EV_BULLET_HIT_FLESH );
						tent->s.eventParm = traceEnt->s.number;
						tent->s.otherEntityNum = self->s.number;
#endif
						tent->s.weapon = projnum;
					} else if (tr.surfaceFlags & SURF_METALSTEPS) {
						tent = G_TempEntity( tr.endpos, EV_MISSILE_MISS_METAL );
						tent->s.playerNum = self->s.number;
						tent->s.weapon = projnum;
						tent->s.eventParm = DirToByte( tr.plane.normal );
					} else {
#if 1 // lightning
						tent = G_TempEntity( tr.endpos, EV_MISSILE_MISS );
						tent->s.playerNum = self->s.number;
#else
						tent = G_TempEntity( tr.endpos, EV_BULLET_HIT_WALL );
						tent->s.otherEntityNum = self->s.number;
#endif
						tent->s.weapon = projnum;
						tent->s.eventParm = DirToByte( tr.plane.normal );
					}
				}

				if ( traceEnt->takedamage)
				{
#if defined MISSIONPACK && !defined TURTLEARENA // POWERS
					if ( traceEnt->player && traceEnt->player->invulnerabilityTime > level.time )
					{
						if (G_InvulnerabilityEffect( traceEnt, dir, tr.endpos, impactpoint, bouncedir ))
						{
							G_BounceProjectile( start, impactpoint, bouncedir, end );
							if (bg_projectileinfo[projnum].trailType == PT_RAIL)
							{
								// snap the endpos to integers to save net bandwidth, but nudged towards the line
								SnapVectorTowards( tr.endpos, start );
								// send railgun beam effect
								tent = G_TempEntity( tr.endpos, EV_RAILTRAIL );
								// set player number for custom colors on the railtrail
								tent->s.playerNum = self->s.playerNum;
								tent->s.weapon = projnum;
								tent->s.weaponHands = MAX_HANDS; // Don't attach to player's gun
								VectorCopy( start, tent->s.origin2 );
								// move origin a bit to come closer to the drawn gun muzzle
								VectorMA( tent->s.origin2, 4, right, tent->s.origin2 );
								VectorMA( tent->s.origin2, -1, up, tent->s.origin2 );
								tent->s.eventParm = 255;	// don't make the explosion at the end
							}
							VectorCopy( impactpoint, start );
#if 1 // lightning
							VectorSubtract( end, impactpoint, dir );
							VectorNormalize(dir);
#endif
							// the player can hit him/herself with the bounced rail
							passent = ENTITYNUM_NONE;
						}
						else
						{
							VectorCopy( tr.endpos, start );
							passent = traceEnt->s.number;
						}
						if (bg_projectileinfo[projnum].trailType != PT_RAIL) {
							continue;
						}
					}
					else
#endif
					{
						G_Damage( traceEnt, self, self,
#if 1 // ZTM: Knockback in direction projectile was moving
							dir,
#else
							forward,
#endif
							tr.endpos,
							damage,
							0, mod);

						hitClient = LogAccuracyHit( traceEnt, self );

						// Splash damage!
						if (G_RadiusDamage(tr.endpos, self, self, damage, splashRadius, traceEnt, splashMod)) {
							hitClient = qtrue;
						}

						if( hitClient ) {
							hits++;
						}
					}
				}

				// weapon_railgun_fire
				if (bg_projectileinfo[projnum].maxHits > 1) {
					if ( tr.contents & CONTENTS_SOLID ) {
						break;		// we hit something solid enough to stop the beam
					}

					// unlink this entity, so the next trace will go past it
					trap_UnlinkEntity( traceEnt );
					unlinkedEntities[unlinked] = traceEnt;
					unlinked++;

					if (i+1 >= bg_projectileinfo[projnum].maxHits) {
						break;
					}
				} else {
					break;
				}
			}

			// link back in any entities we unlinked
			for ( i = 0 ; i < unlinked ; i++ ) {
				trap_LinkEntity( unlinkedEntities[i] );
			}

			if (self && self->player) {
#ifndef TURTLEARENA // AWARDS
				if (bg_projectileinfo[projnum].maxHits > 1) {
					// give the shooter a reward sound if they have made two railgun hits in a row
					if ( hits == 0 ) {
						// complete miss
						self->player->accurateCount = 0;
					} else {
						// check for "impressive" reward sound
						self->player->accurateCount += hits;
						if ( self->player->accurateCount >= 2 ) {
							self->player->accurateCount -= 2;
							self->player->ps.persistant[PERS_IMPRESSIVE_COUNT]++;
							// add the sprite over the player's head
#ifdef IOQ3ZTM
							self->player->ps.eFlags &= ~EF_AWARD_BITS;
#else
							self->player->ps.eFlags &= ~(EF_AWARD_IMPRESSIVE | EF_AWARD_EXCELLENT | EF_AWARD_GAUNTLET | EF_AWARD_ASSIST | EF_AWARD_DEFEND | EF_AWARD_CAP );
#endif
							self->player->ps.eFlags |= EF_AWARD_IMPRESSIVE;
							self->player->rewardTime = level.time + REWARD_SPRITE_TIME;
						}
						self->player->accuracy_hits++;
					}
				}
				else
#endif
				if (hits) {
					self->player->accuracy_hits++;
				}
			}

			// From weapon_railgun_fire
			if (bg_projectileinfo[projnum].trailType == PT_RAIL)
			{
				gentity_t	*tent;

				// the final trace endpos will be the terminal point of the rail trail

				// snap the endpos to integers to save net bandwidth, but nudged towards the line
				SnapVectorTowards( tr.endpos, start );

				// send railgun beam effect
				tent = G_TempEntity( tr.endpos, EV_RAILTRAIL );

				// set player number for custom colors on the railtrail
				tent->s.playerNum = self->s.playerNum;

				// Set projectile number
				tent->s.weapon = projnum;

				// ZTM: NOTE: This could be a problem if multiple hands use the same handSide.
				tent->s.weaponHands = MAX_HANDS;
				if (self->player) {
					for (i = 0; i < MAX_HANDS; i++)
					{
						if (self->player->pers.playercfg.handSide[i] == handSide) {
							tent->s.weaponHands = i;
							break;
						}
					}
				}

				VectorCopy( start, tent->s.origin2 );
				// move origin a bit to come closer to the drawn gun muzzle
				if (handSide == HS_RIGHT)
					VectorMA( tent->s.origin2, 4, right, tent->s.origin2 );
				else if (handSide == HS_LEFT)
					VectorMA( tent->s.origin2, -4, right, tent->s.origin2 );
				VectorMA( tent->s.origin2, -1, up, tent->s.origin2 );
			}
			continue;
		}

		bolt = G_Spawn();
		bolt->classname = bg_projectileinfo[projnum].name;
		if (self && self->player && bg_projectileinfo[projnum].grappling)
		{
			if (bg_projectileinfo[projnum].timetolive == -1)
				bolt->nextthink = -1;
			else
				bolt->nextthink = level.time + bg_projectileinfo[projnum].timetolive;

			bolt->think = Weapon_HookFree;

			self->player->hook = bolt;
		}
		else if (bg_projectileinfo[projnum].homing)
		{
			bolt->nextthink = level.time + bg_projectileinfo[projnum].homing;
			bolt->think = G_HomingMissile;
		}
		else
		{
			if (bg_projectileinfo[projnum].timetolive == -1)
				bolt->nextthink = -1;
			else
				bolt->nextthink = level.time + bg_projectileinfo[projnum].timetolive;

			if (bg_projectileinfo[projnum].fallToGround)
				bolt->think = G_MissileFall; // Just fall out of air.
			else
				bolt->think = G_ExplodeMissile;
		}
		bolt->s.eType = ET_MISSILE;
		bolt->r.svFlags = SVF_USE_CURRENT_ORIGIN;
		bolt->s.weapon = projnum;
		if (self) {
			bolt->r.ownerNum = self->s.number;
		} else {
			bolt->r.ownerNum = ENTITYNUM_WORLD;
		}
		bolt->parent = self;
		// grapple
		bolt->s.otherEntityNum = bolt->r.ownerNum; // use to match beam in client

		if (!bg_projectileinfo[projnum].damageAttacker) {
			bolt->flags |= FL_MISSILE_NO_DAMAGE_PARENT;
		}

		bolt->damage = damage;
		bolt->splashDamage = splashDamage;
		bolt->splashRadius = splashRadius;

		bolt->methodOfDeath = mod;
		bolt->splashMethodOfDeath = splashMod;

		bolt->clipmask = MASK_SHOT;
		bolt->target_ent = NULL;

		VectorCopy( start, bolt->s.pos.trBase );

		bolt->s.pos.trTime = level.time - MISSILE_PRESTEP_TIME; // move a bit on the very first frame
		G_SetMissileVelocity(bolt, dir, projnum);

		VectorCopy (start, bolt->r.currentOrigin);

		if (bg_projectileinfo[projnum].bounceType == PB_FULL)
			bolt->s.eFlags = EF_BOUNCE;
		else if (bg_projectileinfo[projnum].bounceType == PB_HALF)
			bolt->s.eFlags = EF_BOUNCE_HALF;

		if (bg_projectileinfo[projnum].flags & PF_USE_GRAVITY)
			bolt->s.pos.trType = TR_GRAVITY;

		// Limit bounces
		bolt->s.modelindex2 = bg_projectileinfo[projnum].maxBounces;

		// ZTM: Shootable missiles, taken from XREAL
		if (bg_projectileinfo[projnum].shootable)
		{
			// Make the projectile shootable
			bolt->s.contents = CONTENTS_SHOOTABLE;
			VectorCopy(mins, bolt->s.mins);
			VectorCopy(maxs, bolt->s.maxs);
			bolt->takedamage = qtrue;
			bolt->health = bg_projectileinfo[projnum].damage;

			if (bg_projectileinfo[projnum].fallToGround)
				bolt->die = G_MissileFall_Die;
			else
				bolt->die = G_Missile_Die;
		}

		// Save handSide in missile
		bolt->s.weaponHands = handSide;

		if (self && self->player)
		{
			// Taken from Q3's fire_prox;
			// ZTM: Used by prox mines so that if that player changes teams the mines
			//        don't "change" teams as well (or something...).
			bolt->s.team = self->player->sess.sessionTeam;
		}
		else
		{
			bolt->s.team = TEAM_FREE;
		}

		// Needed for stickOnImpact and grappling projectiles
		vectoangles( forward, bolt->s.angles );
	}

	return qtrue;
}
Exemple #7
0
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 );

// eser - lightning discharge
	if (trap_PointContents (muzzle, -1) & MASK_WATER)
	{
		int zaps;
		gentity_t *tent;

		zaps = ent->client->ps.ammo[WP_LIGHTNING];	// determines size/power of discharge
		if (!zaps) return;	// prevents any subsequent frames causing second discharge + error
		zaps++;		// pmove does an ammo[gun]--, so we must compensate
		SnapVectorTowards (muzzle, ent->s.origin);	// save bandwidth

		tent = G_TempEntity (muzzle, EV_LIGHTNING_DISCHARGE);
		tent->s.eventParm = zaps;				// duration / size of explosion graphic

        ent->client->ps.ammo[WP_LIGHTNING] = 0;		// drain ent's lightning count
		if (G_RadiusDamage (muzzle, ent, damage * zaps, (damage * zaps) + 16, NULL, MOD_LIGHTNING_DISCHARGE, qtrue))
			ent->client->accuracy_hits++;

		return;
	}
// eser - lightning discharge


		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;
			}
#endif
			if( LogAccuracyHit( traceEnt, ent ) ) {
				ent->client->accuracy_hits++;
			}
			G_Damage( traceEnt, ent, ent, forward, tr.endpos, damage, 0, MOD_LIGHTNING);
		}

		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;
		} else if ( !( tr.surfaceFlags & SURF_NOIMPACT ) ) {
			tent = G_TempEntity( tr.endpos, EV_MISSILE_MISS );
			tent->s.eventParm = DirToByte( tr.plane.normal );
		}

		break;
	}
}
Exemple #8
0
void Bullet_Fire (gentity_t *ent, float spread, int damage, int mod ) {
	trace_t		tr;
	vec3_t		end;
#ifdef MISSIONPACK
	vec3_t		impactpoint, bouncedir;
#endif
	float		r;
	float		u;
	gentity_t	*tent;
	gentity_t	*traceEnt;
	int			i, passent;

	damage *= s_quadFactor;

//unlagged - attack prediction #2
	if ( g_unlagged.integer ) {
		// we have to use something now that the client knows in advance
		int	seed = ent->client->attackTime % 256;

		// this has to match what's on the client
		r = Q_random(&seed) * M_PI * 2.0f;
		u = sin(r) * Q_crandom(&seed) * spread * 16;
		r = cos(r) * Q_crandom(&seed) * spread * 16;
	} else {
		r = random() * M_PI * 2.0f;
		u = sin(r) * crandom() * spread * 16;
		r = cos(r) * crandom() * spread * 16;
	}
//-unlagged - attack prediction #2

	VectorMA (muzzle, 8192*16, forward, end);
	VectorMA (end, r, right, end);
	VectorMA (end, u, up, end);

	passent = ent->s.number;
	for (i = 0; i < 10; i++) {

//unlagged - backward reconciliation #2
		// backward-reconcile the other clients
		if ( g_unlagged.integer )
			G_DoTimeShiftFor( ent );
//-unlagged - backward reconciliation #2

		trap_Trace (&tr, muzzle, NULL, NULL, end, passent, MASK_SHOT);

//unlagged - backward reconciliation #2
		// put them back
		if ( g_unlagged.integer )
			G_UndoTimeShiftFor( ent );
//-unlagged - backward reconciliation #2

		if ( tr.surfaceFlags & SURF_NOIMPACT ) {
			return;
		}

		traceEnt = &g_entities[ tr.entityNum ];

		// snap the endpos to integers, but nudged towards the line
		SnapVectorTowards( tr.endpos, muzzle );

		// send bullet impact
		if ( traceEnt->takedamage && traceEnt->client ) {
			tent = G_TempEntity( tr.endpos, EV_BULLET_HIT_FLESH );
			tent->s.eventParm = traceEnt->s.number;
//unlagged - attack prediction #2
			// we need the client number to determine whether or not to
			// suppress this event
			if ( g_unlagged.integer )
				tent->s.clientNum = ent->s.clientNum;
//-unlagged - attack prediction #2
			if( LogAccuracyHit( traceEnt, ent ) ) {
				ent->client->accuracy_hits++;
			}
		} else {
			tent = G_TempEntity( tr.endpos, EV_BULLET_HIT_WALL );
			tent->s.eventParm = DirToByte( tr.plane.normal );
//unlagged - attack prediction #2
			// we need the client number to determine whether or not to
			// suppress this event
			if ( g_unlagged.integer )
				tent->s.clientNum = ent->s.clientNum;
//-unlagged - attack prediction #2
		}
		tent->s.otherEntityNum = ent->s.number;

		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 );
					// the player can hit him/herself with the bounced rail
					passent = ENTITYNUM_NONE;
				}
				else {
					VectorCopy( tr.endpos, muzzle );
					passent = traceEnt->s.number;
				}
				continue;
			}
			else {
#endif
				G_Damage( traceEnt, ent, ent, forward, tr.endpos,
					damage, DAMAGE_COMBAT, mod);
#ifdef MISSIONPACK
			}
#endif
		}
		break;
	}
}