Exemplo n.º 1
0
static void MissileImpact( gentity_t *ent, trace_t *trace )
{
	int       dirAsByte, impactFlags;
	const missileAttributes_t *ma = BG_Missile( ent->s.modelindex );
	gentity_t *hitEnt   = &g_entities[ trace->entityNum ];
	gentity_t *attacker = &g_entities[ ent->r.ownerNum ];

	// Returns whether damage and hit effects should be done and played.
	std::function<int(gentity_t*, trace_t*, gentity_t*)> impactFunc;

	// Check for bounce.
	if ( ent->s.eFlags & ( EF_BOUNCE | EF_BOUNCE_HALF ) &&
	     !HasComponents<HealthComponent>(*hitEnt->entity) )
	{
		BounceMissile( ent, trace );

		if ( !( ent->s.eFlags & EF_NO_BOUNCE_SOUND ) )
		{
			G_AddEvent( ent, EV_GRENADE_BOUNCE, 0 );
		}

		return;
	}

	// Call missile specific impact functions.
	switch( ent->s.modelindex )
	{
		case MIS_GRENADE:      impactFunc = ImpactGrenade;     break;
		case MIS_FIREBOMB:     impactFunc = ImpactGrenade;     break;
		case MIS_FLAMER:       impactFunc = ImpactFlamer;      break;
		case MIS_FIREBOMB_SUB: impactFunc = ImpactFirebombSub; break;
		case MIS_LOCKBLOB:     impactFunc = ImpactLockblock;   break;
		case MIS_SLOWBLOB:     impactFunc = ImpactSlowblob;    break;
		case MIS_HIVE:         impactFunc = ImpactHive;        break;
		default:               impactFunc = DefaultImpactFunc; break;
	}

	impactFlags = impactFunc( ent, trace, hitEnt );

	// Deal impact damage.
	if ( !( impactFlags & MIF_NO_DAMAGE ) )
	{
		if ( ent->damage && G_Alive( hitEnt ) )
		{
			vec3_t dir;

			BG_EvaluateTrajectoryDelta( &ent->s.pos, level.time, dir );

			if ( VectorNormalize( dir ) == 0 )
			{
				dir[ 2 ] = 1; // stepped on a grenade
			}

			int dflags = 0;
			if ( !ma->doLocationalDamage ) dflags |= DAMAGE_NO_LOCDAMAGE;
			if ( ma->doKnockback )         dflags |= DAMAGE_KNOCKBACK;

			hitEnt->entity->Damage(ent->damage * MissileTimeDmgMod(ent), attacker,
			                       Vec3::Load(trace->endpos), Vec3::Load(dir), dflags,
			                       (meansOfDeath_t)ent->methodOfDeath);
		}

		// splash damage (doesn't apply to person directly hit)
		if ( ent->splashDamage )
		{
			G_RadiusDamage( trace->endpos, ent->parent,
			                ent->splashDamage * MissileTimeSplashDmgMod( ent ),
			                ent->splashRadius, hitEnt, ( ma->doKnockback ? DAMAGE_KNOCKBACK : 0 ),
			                ent->splashMethodOfDeath );
		}
	}

	// Play hit effects and remove the missile.
	if ( !( impactFlags & MIF_NO_EFFECT ) )
	{
		// Use either the trajectory direction or the surface normal for the hit event.
		if ( ma->impactFlightDirection )
		{
			vec3_t trajDir;
			BG_EvaluateTrajectoryDelta( &ent->s.pos, level.time, trajDir );
			VectorNormalize( trajDir );
			dirAsByte = DirToByte( trajDir );
		}
		else
		{
			dirAsByte = DirToByte( trace->plane.normal );
		}

		// Add hit event.
		if ( HasComponents<HealthComponent>(*hitEnt->entity) )
		{
			G_AddEvent( ent, EV_MISSILE_HIT_ENTITY, dirAsByte );

			ent->s.otherEntityNum = hitEnt->s.number;
		}
		else if ( trace->surfaceFlags & SURF_METAL )
		{
			G_AddEvent( ent, EV_MISSILE_HIT_METAL, dirAsByte );
		}
		else
		{
			G_AddEvent( ent, EV_MISSILE_HIT_ENVIRONMENT, dirAsByte );
		}

		ent->freeAfterEvent = true;

		// HACK: Change over to a general entity at the point of impact.
		ent->s.eType = ET_GENERAL;

		// Prevent map models from appearing at impact point.
		ent->s.modelindex = 0;

		// Save net bandwith.
		G_SnapVectorTowards( trace->endpos, ent->s.pos.trBase );

		G_SetOrigin( ent, trace->endpos );

		trap_LinkEntity( ent );
	}
	// If no impact happened, check if we should continue or free ourselves.
	else if ( !( impactFlags & MIF_NO_FREE ) )
	{
		G_FreeEntity( ent );
	}
}
Exemplo n.º 2
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];

	damage = 100 * s_quadFactor;

	VectorMA (g_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, g_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( g_muzzle, impactpoint, bouncedir, end );
					// snap the endpos to integers to save net bandwidth, but nudged towards the line
					SnapVectorTowards( trace.endpos, g_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( g_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, g_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, g_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( g_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++;
	}

}
Exemplo n.º 3
0
void W_Fire_Electrobolt_FullInstant( edict_t *self, vec3_t start, vec3_t dir, float maxdamage, float mindamage, int maxknockback, int minknockback, int stun, int range, int minDamageRange, int mod, int timeDelta ) {
	vec3_t from, end;
	trace_t tr;
	edict_t *ignore, *event, *hit;
	int hit_movetype;
	int mask;
	bool missed = true;
	int dmgflags = 0;

#define FULL_DAMAGE_RANGE g_projectile_prestep->value

	if( GS_Instagib() ) {
		maxdamage = mindamage = 9999;
	}

	VectorMA( start, range, dir, end );
	VectorCopy( start, from );

	ignore = self;
	hit = NULL;

	mask = MASK_SHOT;
	if( GS_RaceGametype() ) {
		mask = MASK_SOLID;
	}

	clamp_high( mindamage, maxdamage );
	clamp_high( minknockback, maxknockback );
	clamp_high( minDamageRange, range );

	if( minDamageRange <= FULL_DAMAGE_RANGE ) {
		minDamageRange = FULL_DAMAGE_RANGE + 1;
	}

	if( range <= FULL_DAMAGE_RANGE + 1 ) {
		range = FULL_DAMAGE_RANGE + 1;
	}

	tr.ent = -1;
	while( ignore ) {
		G_Trace4D( &tr, from, NULL, NULL, end, ignore, mask, timeDelta );

		VectorCopy( tr.endpos, from );
		ignore = NULL;

		if( tr.ent == -1 ) {
			break;
		}

		// some entity was touched
		hit = &game.edicts[tr.ent];
		hit_movetype = hit->movetype; // backup the original movetype as the entity may "die"
		if( hit == world ) { // stop dead if hit the world
			break;
		}

		// allow trail to go through BBOX entities (players, gibs, etc)
		if( !ISBRUSHMODEL( hit->s.modelindex ) ) {
			ignore = hit;
		}

		if( ( hit != self ) && ( hit->takedamage ) ) {
			float frac, damage, knockback, dist;

			dist = DistanceFast( tr.endpos, start );
			if( dist <= FULL_DAMAGE_RANGE ) {
				frac = 0.0f;
			} else {
				frac = ( dist - FULL_DAMAGE_RANGE ) / (float)( minDamageRange - FULL_DAMAGE_RANGE );
				clamp( frac, 0.0f, 1.0f );
			}

			damage = maxdamage - ( ( maxdamage - mindamage ) * frac );
			knockback = maxknockback - ( ( maxknockback - minknockback ) * frac );

			G_Damage( hit, self, self, dir, dir, tr.endpos, damage, knockback, stun, dmgflags, mod );

			// spawn a impact event on each damaged ent
			event = G_SpawnEvent( EV_BOLT_EXPLOSION, DirToByte( tr.plane.normal ), tr.endpos );
			event->s.firemode = FIRE_MODE_STRONG;
			if( hit->r.client ) {
				missed = false;
			}
		}

		if( hit_movetype == MOVETYPE_NONE || hit_movetype == MOVETYPE_PUSH ) {
			break;
		}
	}

	if( missed && self->r.client ) {
		G_AwardPlayerMissedElectrobolt( self, mod );
	}

	// send the weapon fire effect
	event = G_SpawnEvent( EV_ELECTROTRAIL, ENTNUM( self ), start );
	VectorScale( dir, 1024, event->s.origin2 );
	event->s.firemode = FIRE_MODE_STRONG;

#undef FULL_DAMAGE_RANGE
}
Exemplo n.º 4
0
void G_ExplodeIntoNails(gentity_t * ent)
{
	float           angle, angle2;
	vec3_t          forward, forward2, up;
	vec3_t          nailForward, nailRight, nailUp;
	vec3_t          dir;
	vec3_t          origin;

	BG_EvaluateTrajectory(&ent->s.pos, level.time, origin);
	SnapVector(origin);
	G_SetOrigin(ent, origin);

	// we don't have a valid direction, so just point straight up
	dir[0] = dir[1] = 0;
	dir[2] = 1;

	// Tr3B: don't change the entity type because it is required by the EV_PROJECTILE_* events
	// the ent->freeAfterEvent = qtrue; will do the same effect
	//ent->s.eType = ET_GENERAL;

	G_AddEvent(ent, EV_PROJECTILE_MISS, DirToByte(dir));

	ent->freeAfterEvent = qtrue;

	// splash damage
	if(ent->splashDamage)
	{
		if(G_RadiusDamage(ent->r.currentOrigin, ent->parent, ent->splashDamage, ent->splashRadius, ent, ent->splashMethodOfDeath))
		{
			g_entities[ent->r.ownerNum].client->accuracy_hits++;
		}
	}

	// create orthogonal vector to main direction
	PerpendicularVector(dir, forward);
	//VectorScale(forward, 40, forward);

	origin[2] += 10;

	// spread nails in all directions
	for(angle = 0; angle < 360; angle += 60.0f)
	{
		RotatePointAroundVector(forward2, dir, forward, angle);

		for(angle2 = 0; angle2 < 360; angle2 += 60.0f)
		{
			RotatePointAroundVector(up, forward, dir, angle2);

			VectorAdd(forward2, up, nailForward);
			VectorNormalize(nailForward);

			PerpendicularVector(nailRight, nailForward);
			CrossProduct(nailForward, nailRight, nailUp);
#if 1
			fire_gravnail(ent, origin, nailForward, nailRight, nailUp);
#else
			VectorAdd(forward2, dir, forward2);
			fire_clustergrenade(ent, origin, forward2);
#endif
		}
	}

	trap_LinkEntity(ent);
}
Exemplo n.º 5
0
void MSG_WriteDir( msg_t *msg, vec3_t dir )
{
	MSG_WriteByte( msg, dir ? DirToByte( dir ) : 0 );
}
Exemplo n.º 6
0
/*
================
G_MissileImpact

================
*/
void G_MissileImpact( gentity_t *ent, trace_t *trace )
{
    gentity_t   *other, *attacker;
    qboolean    returnAfterDamage = qfalse;
    vec3_t      dir;

    other = &g_entities[ trace->entityNum ];
    attacker = &g_entities[ ent->r.ownerNum ];

    // check for bounce
    if( !other->takedamage &&
            ( ent->s.eFlags & ( EF_BOUNCE | EF_BOUNCE_HALF ) ) && strcmp( ent->classname, "acidbomb" ) )//ROTAXfun pokud je to acidbomba, pouzije vlastni zvuk a ne granatovej
    {
        G_BounceMissile( ent, trace );

        //only play a sound if requested
        if( !( ent->s.eFlags & EF_NO_BOUNCE_SOUND ) )
            G_AddEvent( ent, EV_GRENADE_BOUNCE, 0 );

        return;
    }

    if( !strcmp( ent->classname, "grenade" ) )
    {
        //grenade doesn't explode on impact
        G_BounceMissile( ent, trace );

        //only play a sound if requested
        if( !( ent->s.eFlags & EF_NO_BOUNCE_SOUND ) )
            G_AddEvent( ent, EV_GRENADE_BOUNCE, 0 );

        return;
    }
    else if( !strcmp( ent->classname, "mine" ) )//ROTAXfun
    {
        //grenade doesn't explode on impact
        G_BounceMissile( ent, trace );

        //only play a sound if requested
        if( !( ent->s.eFlags & EF_NO_BOUNCE_SOUND ) )
            G_AddEvent( ent, EV_GRENADE_BOUNCE, 0 );

        return;
    }
    else if( !strcmp( ent->classname, "flare" ) )//ROTAXfun
    {
        //grenade doesn't explode on impact
        G_BounceMissile( ent, trace );

        //only play a sound if requested
        if( !( ent->s.eFlags & EF_NO_BOUNCE_SOUND ) )
            G_AddEvent( ent, EV_GRENADE_BOUNCE, 0 );

        return;
    }
    else if( !strcmp( ent->classname, "lockblob" ) )
    {
        if( other->client && other->client->ps.stats[ STAT_TEAM ] == TEAM_HUMANS )
        {
            other->client->ps.stats[ STAT_STATE ] |= SS_BLOBLOCKED;
            other->client->lastLockTime = level.time;
            AngleVectors( other->client->ps.viewangles, dir, NULL, NULL );
            other->client->ps.stats[ STAT_VIEWLOCK ] = DirToByte( dir );
        }
    }
    else if( !strcmp( ent->classname, "slowblob" ) )
    {
        if( other->client && other->client->ps.stats[ STAT_TEAM ] == TEAM_HUMANS )
        {
            other->client->ps.stats[ STAT_STATE ] |= SS_SLOWLOCKED;
            other->client->lastSlowTime = level.time;
            AngleVectors( other->client->ps.viewangles, dir, NULL, NULL );
            other->client->ps.stats[ STAT_VIEWLOCK ] = DirToByte( dir );
        }
    }
    else if( !strcmp( ent->classname, "acidbomb" ) )//ROTAXfun
    {
        //bomb doesn't explode on impact
        G_BounceMissile( ent, trace );

        //only play a sound if requested
        if( !( ent->s.eFlags & EF_NO_BOUNCE_SOUND ) )
            G_AddEvent( ent, EV_ACIDBOMB_BOUNCE, 0 );

        return;
    }
    else if( !strcmp( ent->classname, "hive" ) )
    {
        if( other->s.eType == ET_BUILDABLE && other->s.modelindex == BA_A_HIVE )
        {
            if( !ent->parent )
                G_Printf( S_COLOR_YELLOW "WARNING: hive entity has no parent in G_MissileImpact\n" );
            else
                ent->parent->active = qfalse;

            G_FreeEntity( ent );
            return;
        }
        else
        {
            //prevent collision with the client when returning
            ent->r.ownerNum = other->s.number;

            ent->think = G_ExplodeMissile;
            ent->nextthink = level.time + FRAMETIME;

            //only damage humans
            if( other->client && other->client->ps.stats[ STAT_TEAM ] == TEAM_HUMANS )
                returnAfterDamage = qtrue;
            else
                return;
        }
    }
    else if ( other->s.eType == ET_BUILDABLE && other->s.modelindex == BA_A_BAMBOO && ( !strcmp( ent->classname, "lcannon" ) || !strcmp( ent->classname, "pulse" ) ) )//ROTAXfun (bamboo + luci, prifle)
    {
        G_BounceMissile( ent, trace );

        return;
    }

    // impact damage
    if( other->takedamage )
    {
        // FIXME: wrong damage direction?
        if( ent->damage )
        {
            vec3_t  velocity;

            BG_EvaluateTrajectoryDelta( &ent->s.pos, level.time, velocity );
            if( VectorLength( velocity ) == 0 )
                velocity[ 2 ] = 1;  // stepped on a grenade

            G_Damage( other, ent, attacker, velocity, ent->s.origin, ent->damage,
                      DAMAGE_NO_LOCDAMAGE, ent->methodOfDeath );
        }
    }

    if( returnAfterDamage )
        return;

    // is it cheaper in bandwidth to just remove this ent and create a new
    // one, rather than changing the missile into the explosion?

    if( other->takedamage &&
            ( other->s.eType == ET_PLAYER || other->s.eType == ET_BUILDABLE ) )
    {
        G_AddEvent( ent, EV_MISSILE_HIT, DirToByte( trace->plane.normal ) );
        ent->s.otherEntityNum = other->s.number;
    }
    else if( trace->surfaceFlags & SURF_METALSTEPS )
        G_AddEvent( ent, EV_MISSILE_MISS_METAL, DirToByte( trace->plane.normal ) );
    else
        G_AddEvent( ent, EV_MISSILE_MISS, DirToByte( trace->plane.normal ) );

    ent->freeAfterEvent = qtrue;

    // change over to a normal entity right at the point of impact
    ent->s.eType = ET_GENERAL;

    SnapVectorTowards( trace->endpos, ent->s.pos.trBase );  // save net bandwidth

    G_SetOrigin( ent, trace->endpos );

    // splash damage (doesn't apply to person directly hit)
    if( ent->splashDamage )
        G_RadiusDamage( trace->endpos, ent->parent, ent->splashDamage, ent->splashRadius,
                        other, ent->splashMethodOfDeath );

    trap_LinkEntity( ent );
}
Exemplo n.º 7
0
/*
================
G_MissileImpact

================
*/
void G_MissileImpact( gentity_t *ent, trace_t *trace )
{
	gentity_t *other, *attacker;
	qboolean  returnAfterDamage = qfalse;
	vec3_t    dir;
	float     power;

	other = &g_entities[ trace->entityNum ];
	attacker = &g_entities[ ent->r.ownerNum ];

	// check for bounce
	if ( !other->takedamage &&
	     ( ent->s.eFlags & ( EF_BOUNCE | EF_BOUNCE_HALF ) ) )
	{
		G_BounceMissile( ent, trace );

		//only play a sound if requested
		if ( !( ent->s.eFlags & EF_NO_BOUNCE_SOUND ) )
		{
			G_AddEvent( ent, EV_GRENADE_BOUNCE, 0 );
		}

		return;
	}

	if ( !strcmp( ent->classname, "grenade" ) )
	{
		//grenade doesn't explode on impact
		G_BounceMissile( ent, trace );

		//only play a sound if requested
		if ( !( ent->s.eFlags & EF_NO_BOUNCE_SOUND ) )
		{
			G_AddEvent( ent, EV_GRENADE_BOUNCE, 0 );
		}

		return;
	}
	else if ( !strcmp( ent->classname, "lockblob" ) )
	{
		if ( other->client && other->client->ps.stats[ STAT_TEAM ] == TEAM_HUMANS )
		{
			other->client->ps.stats[ STAT_STATE ] |= SS_BLOBLOCKED;
			other->client->lastLockTime = level.time;
			AngleVectors( other->client->ps.viewangles, dir, NULL, NULL );
			other->client->ps.stats[ STAT_VIEWLOCK ] = DirToByte( dir );
		}
	}
	else if ( !strcmp( ent->classname, "slowblob" ) )
	{
		if ( other->client && other->client->ps.stats[ STAT_TEAM ] == TEAM_HUMANS )
		{
			other->client->ps.stats[ STAT_STATE ] |= SS_SLOWLOCKED;
			other->client->lastSlowTime = level.time;
			AngleVectors( other->client->ps.viewangles, dir, NULL, NULL );
			other->client->ps.stats[ STAT_VIEWLOCK ] = DirToByte( dir );
		}
	}
	else if ( !strcmp( ent->classname, "hive" ) )
	{
		if ( other->s.eType == ET_BUILDABLE && other->s.modelindex == BA_A_HIVE )
		{
			if ( !ent->parent )
			{
				G_Printf( S_WARNING "hive entity has no parent in G_MissileImpact\n" );
			}
			else
			{
				ent->parent->active = qfalse;
			}

			G_FreeEntity( ent );
			return;
		}
		else
		{
			//prevent collision with the client when returning
			ent->r.ownerNum = other->s.number;

			ent->think = G_ExplodeMissile;
			ent->nextthink = level.time + FRAMETIME;

			//only damage humans
			if ( other->client && other->client->ps.stats[ STAT_TEAM ] == TEAM_HUMANS )
			{
				returnAfterDamage = qtrue;
			}
			else
			{
				return;
			}
		}
	}

	power = G_DoMissileTimePowerReduce( ent );

	// impact damage
	if ( other->takedamage )
	{
		// FIXME: wrong damage direction?
		if ( ent->damage )
		{
			vec3_t dir;

			BG_EvaluateTrajectoryDelta( &ent->s.pos, level.time, dir );

			if ( VectorNormalize( dir ) == 0 )
			{
				dir[ 2 ] = 1; // stepped on a grenade
			}

			G_Damage( other, ent, attacker, dir, ent->s.origin, ent->damage * power,
			          DAMAGE_NO_LOCDAMAGE, ent->methodOfDeath );
		}
	}

	if ( returnAfterDamage )
	{
		return;
	}

	// is it cheaper in bandwidth to just remove this ent and create a new
	// one, rather than changing the missile into the explosion?

	if ( other->takedamage &&
	     ( other->s.eType == ET_PLAYER || other->s.eType == ET_BUILDABLE ) )
	{
		G_AddEvent( ent, EV_MISSILE_HIT, DirToByte( trace->plane.normal ) );
		ent->s.otherEntityNum = other->s.number;
	}
	else if ( trace->surfaceFlags & SURF_METAL )
	{
		G_AddEvent( ent, EV_MISSILE_MISS_METAL, DirToByte( trace->plane.normal ) );
	}
	else
	{
		G_AddEvent( ent, EV_MISSILE_MISS, DirToByte( trace->plane.normal ) );
	}

	ent->freeAfterEvent = qtrue;

	// change over to a general entity right at the point of impact
	ent->s.eType = ET_GENERAL;

	SnapVectorTowards( trace->endpos, ent->s.pos.trBase );  // save net bandwidth

	G_SetOrigin( ent, trace->endpos );

	// splash damage (doesn't apply to person directly hit)
	if ( ent->splashDamage )
	{
		G_RadiusDamage( trace->endpos, ent->parent, ent->splashDamage * power, ent->splashRadius,
		                other, ent->splashMethodOfDeath );
	}

	trap_LinkEntity( ent );
}
Exemplo n.º 8
0
void fire_lead( gentity_t *self, vec3_t start, vec3_t dir, int damage ) {

	trace_t tr;
	vec3_t end;
	gentity_t       *tent;
	gentity_t       *traceEnt;
	vec3_t forward, right, up;
	vec3_t angles;
	float r, u;
	qboolean anti_tank_enable = qfalse;

	r = crandom() * self->random;
	u = crandom() * self->random;

	vectoangles( dir, angles );
	AngleVectors( angles, forward, right, up );

	VectorMA( start, 8192, forward, end );
	VectorMA( end, r, right, end );
	VectorMA( end, u, up, end );

	trap_Trace( &tr, start, NULL, NULL, end, self->s.number, 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, start );

	// send bullet impact
	if ( traceEnt->takedamage && traceEnt->client ) {
		tent = G_TempEntity( tr.endpos, EV_BULLET_HIT_FLESH );
		tent->s.eventParm = traceEnt->s.number;
	} else {
		// Ridah, bullet impact should reflect off surface
		vec3_t reflect;
		float dot;

		tent = G_TempEntity( tr.endpos, EV_BULLET_HIT_WALL );

		dot = DotProduct( forward, tr.plane.normal );
		VectorMA( forward, -2 * dot, tr.plane.normal, reflect );
		VectorNormalize( reflect );

		tent->s.eventParm = DirToByte( reflect );
		// done.
	}
	tent->s.otherEntityNum = self->s.number;

	if ( traceEnt->takedamage ) {

		if ( self->s.weapon == WP_SNIPER
			 && traceEnt->s.eType == ET_MOVER
			 && traceEnt->aiName[0] ) {
			anti_tank_enable = qtrue;
		}

		if ( anti_tank_enable ) {
			self->s.weapon = WP_ROCKET_LAUNCHER;
		}

		G_Damage( traceEnt, self, self, forward, tr.endpos,
				  damage, 0, MOD_MACHINEGUN );

		if ( anti_tank_enable ) {
			self->s.weapon = WP_SNIPER;
		}

	}

}
Exemplo n.º 9
0
/*
================
G_MissileImpact
	impactDamage is how much damage the impact will do to func_explosives
================
*/
void G_MissileImpact( gentity_t *ent, trace_t *trace, int impactDamage ) {
	gentity_t       *other;
	qboolean hitClient = qfalse;
	vec3_t velocity;
	int etype;

	other = &g_entities[trace->entityNum];

	// handle func_explosives
	if ( other->classname && Q_stricmp( other->classname, "func_explosive" ) == 0 ) {
		// the damage is sufficient to "break" the ent (health == 0 is non-breakable)
		if ( other->health && impactDamage >= other->health ) {
			// check for other->takedamage needs to be inside the health check since it is
			// likely that, if successfully destroyed by the missile, in the next runmissile()
			// update takedamage would be set to '0' and the func_explosive would not be
			// removed yet, causing a bounce.
			if ( other->takedamage ) {
				BG_EvaluateTrajectoryDelta( &ent->s.pos, level.time, velocity );
				G_Damage( other, ent, &g_entities[ent->r.ownerNum], velocity, ent->s.origin, impactDamage, 0, ent->methodOfDeath );
			}

			// its possible of the func_explosive not to die from this and it
			// should reflect the missile or explode it not vanish into oblivion
			if ( other->health <= 0 ) {
				return;
			}
		}
	}

	// check for bounce
	if ( !other->takedamage &&
		 ( ent->s.eFlags & ( EF_BOUNCE | EF_BOUNCE_HALF ) ) ) {
		G_BounceMissile( ent, trace );
		// JPW NERVE -- spotter White Phosphorous rounds shouldn't bounce noise
		if ( !Q_stricmp( ent->classname,"WP" ) ) {
			return;
		}
		// jpw
		if ( !Q_stricmp( ent->classname, "flamebarrel" ) ) {
			G_AddEvent( ent, EV_FLAMEBARREL_BOUNCE, 0 );
		} else {
			G_AddEvent( ent, EV_GRENADE_BOUNCE, 0 );
		}
		return;
	}

	if ( other->takedamage && ent->s.density == 1 ) {
		G_ExplodeMissilePoisonGas( ent );
		return;
	}

	// impact damage
	if ( other->takedamage ) {
		if ( ent->damage ) {

			if ( LogAccuracyHit( other, &g_entities[ent->r.ownerNum] ) ) {
				if ( g_entities[ent->r.ownerNum].client ) {
					g_entities[ent->r.ownerNum].client->ps.persistant[PERS_ACCURACY_HITS]++;
				}
				hitClient = qtrue;
			}
			BG_EvaluateTrajectoryDelta( &ent->s.pos, level.time, velocity );
			if ( VectorLength( velocity ) == 0 ) {
				velocity[2] = 1;    // stepped on a grenade
			}
			G_Damage( other, ent, &g_entities[ent->r.ownerNum], velocity,
					  ent->s.origin, ent->damage,
					  0, ent->methodOfDeath );
		} else    // if no damage value, then this is a splash damage grenade only
		{
			G_BounceMissile( ent, trace );
			return;
		}
	}

	// is it cheaper in bandwidth to just remove this ent and create a new
	// one, rather than changing the missile into the explosion?

	if ( other->takedamage && other->client ) {
		G_AddEvent( ent, EV_MISSILE_HIT, DirToByte( trace->plane.normal ) );
		ent->s.otherEntityNum = other->s.number;
	} else {
		// Ridah, try projecting it in the direction it came from, for better decals
		vec3_t dir;
		BG_EvaluateTrajectoryDelta( &ent->s.pos, level.time, dir );
		BG_GetMarkDir( dir, trace->plane.normal, dir );
		G_AddEvent( ent, EV_MISSILE_MISS, DirToByte( dir ) );
	}

	ent->freeAfterEvent = qtrue;

	// change over to a normal entity right at the point of impact
	etype = ent->s.eType;
	ent->s.eType = ET_GENERAL;

	SnapVectorTowards( trace->endpos, ent->s.pos.trBase );  // save net bandwidth

	G_SetOrigin( ent, trace->endpos );

	// splash damage (doesn't apply to person directly hit)
	if ( ent->splashDamage ) {
		if ( G_RadiusDamage( trace->endpos, ent->parent, ent->splashDamage, ent->splashRadius,
							 other, ent->splashMethodOfDeath ) ) {
			if ( !hitClient && g_entities[ent->r.ownerNum].client ) {
				g_entities[ent->r.ownerNum].client->ps.persistant[PERS_ACCURACY_HITS]++;
			}
		}
	}

	trap_LinkEntity( ent );
}
Exemplo n.º 10
0
/*
===============
CheckPounceAttack
===============
*/
qboolean CheckPounceAttack( gentity_t *ent )
{
  trace_t   tr;
  vec3_t    end;
  gentity_t *tent;
  gentity_t *traceEnt;
  int       damage;
  vec3_t    mins, maxs;

  VectorSet( mins, -LEVEL3_POUNCE_WIDTH, -LEVEL3_POUNCE_WIDTH, -LEVEL3_POUNCE_WIDTH );
  VectorSet( maxs, LEVEL3_POUNCE_WIDTH, LEVEL3_POUNCE_WIDTH, LEVEL3_POUNCE_WIDTH );

  if( !ent->client->allowedToPounce )
    return qfalse;

  if( ent->client->ps.groundEntityNum != ENTITYNUM_NONE )
  {
    ent->client->allowedToPounce = qfalse;
    return qfalse;
  }

  if( ent->client->ps.weaponTime )
    return qfalse;

  // set aiming directions
  AngleVectors( ent->client->ps.viewangles, forward, right, up );

  CalcMuzzlePoint( ent, forward, right, up, muzzle );

  VectorMA( muzzle, LEVEL3_POUNCE_RANGE, forward, end );

  trap_Trace( &tr, ent->s.origin, mins, maxs, end, ent->s.number, MASK_SHOT );

  //miss
  if( tr.fraction >= 1.0 )
    return qfalse;

  if( tr.surfaceFlags & SURF_NOIMPACT )
    return qfalse;

  traceEnt = &g_entities[ tr.entityNum ];

  // send blood impact
  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;
    tent->s.generic1 = ent->s.generic1; //weaponMode
  }

  if( !traceEnt->takedamage )
    return qfalse;

  damage = (int)( ( (float)ent->client->pouncePayload / (float)LEVEL3_POUNCE_SPEED ) * LEVEL3_POUNCE_DMG );

  G_Damage( traceEnt, ent, ent, forward, tr.endpos, damage,
      DAMAGE_NO_KNOCKBACK|DAMAGE_NO_LOCDAMAGE, MOD_LEVEL3_POUNCE );

  ent->client->ps.weaponTime += LEVEL3_POUNCE_TIME;
  ent->client->allowedToPounce = qfalse;

  return qtrue;
}
Exemplo n.º 11
0
/*
===============
CheckVenomAttack
===============
*/
qboolean CheckVenomAttack( gentity_t *ent )
{
  trace_t   tr;
  vec3_t    end;
  gentity_t *tent;
  gentity_t *traceEnt;
  vec3_t    mins, maxs;
  int       damage = LEVEL0_BITE_DMG;

  VectorSet( mins, -LEVEL0_BITE_WIDTH, -LEVEL0_BITE_WIDTH, -LEVEL0_BITE_WIDTH );
  VectorSet( maxs, LEVEL0_BITE_WIDTH, LEVEL0_BITE_WIDTH, LEVEL0_BITE_WIDTH );

  // set aiming directions
  AngleVectors( ent->client->ps.viewangles, forward, right, up );

  CalcMuzzlePoint( ent, forward, right, up, muzzle );

  VectorMA( muzzle, LEVEL0_BITE_RANGE, forward, end );

  trap_Trace( &tr, muzzle, mins, maxs, end, ent->s.number, MASK_SHOT );

  if( tr.surfaceFlags & SURF_NOIMPACT )
    return qfalse;

  traceEnt = &g_entities[ tr.entityNum ];

  if( !traceEnt->takedamage )
    return qfalse;

  if( !traceEnt->client && !traceEnt->s.eType == ET_BUILDABLE )
    return qfalse;

  //allow bites to work against defensive buildables only
  if( traceEnt->s.eType == ET_BUILDABLE )
  {
    if( traceEnt->s.modelindex != BA_H_MGTURRET &&
        traceEnt->s.modelindex != BA_H_TESLAGEN )
      return qfalse;

    //hackery
    damage *= 0.5f;
  }

  if( traceEnt->client )
  {
    if( traceEnt->client->ps.stats[ STAT_PTEAM ] == PTE_ALIENS )
      return qfalse;
    if( traceEnt->client->ps.stats[ STAT_HEALTH ] <= 0 )
      return qfalse;
  }

  // send blood impact
  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;
    tent->s.generic1 = ent->s.generic1; //weaponMode
  }

  G_Damage( traceEnt, ent, ent, forward, tr.endpos, damage, DAMAGE_NO_KNOCKBACK, MOD_LEVEL0_BITE );

  return qtrue;
}
Exemplo n.º 12
0
void G_MissileImpact( gentity_t *ent, trace_t *trace ) {
	gentity_t		*other;
	qboolean		hitClient = qfalse;
	qboolean		isKnockedSaber = qfalse;

	other = &g_entities[trace->entityNum];

	// check for bounce
	if ( !other->takedamage &&
		(ent->bounceCount > 0 || ent->bounceCount == -5) &&
		( ent->flags & ( FL_BOUNCE | FL_BOUNCE_HALF ) ) ) {
		int originalBounceCount = ent->bounceCount;
		G_BounceMissile( ent, trace );
		if ( originalBounceCount != ent->bounceCount )
		{
		    G_GrenadeBounceEvent ((const gentity_t *)ent);
		}
		return;
	}
	else if (ent->neverFree && ent->s.weapon == WP_SABER && (ent->flags & FL_BOUNCE_HALF))
	{ //this is a knocked-away saber
		if (ent->bounceCount > 0 || ent->bounceCount == -5)
		{
		    	int originalBounceCount = ent->bounceCount;
		    	G_BounceMissile( ent, trace );
		    	G_GrenadeBounceEvent ((const gentity_t *)ent);
		    	if ( originalBounceCount != ent->bounceCount )
	        	{
	            		G_GrenadeBounceEvent ((const gentity_t *)ent);
	        	}
			return;
		}

		isKnockedSaber = qtrue;
	}
	
	// I would glom onto the FL_BOUNCE code section above, but don't feel like risking breaking something else
	if ( (!other->takedamage && (ent->bounceCount > 0 || ent->bounceCount == -5) && ( ent->flags&(FL_BOUNCE_SHRAPNEL) ) ) || ((trace->surfaceFlags&SURF_FORCEFIELD)&&!ent->splashDamage&&!ent->splashRadius&&(ent->bounceCount > 0 || ent->bounceCount == -5)) ) 
	{
		G_BounceMissile( ent, trace );

		if ( ent->bounceCount < 1 )
		{
			ent->flags &= ~FL_BOUNCE_SHRAPNEL;
		}
		return;
	}

	/*
	if ( !other->takedamage && ent->s.weapon == WP_THERMAL && !ent->alt_fire )
	{//rolling thermal det - FIXME: make this an eFlag like bounce & stick!!!
		//G_BounceRollMissile( ent, trace );
		if ( ent->owner && ent->owner->s.number == 0 ) 
		{
			G_MissileAddAlerts( ent );
		}
		//gi.linkentity( ent );
		return;
	}
	*/

	if ((other->r.contents & CONTENTS_LIGHTSABER) && !isKnockedSaber)
	{ //hit this person's saber, so..
		gentity_t *otherOwner = &g_entities[other->r.ownerNum];

		if (otherOwner->takedamage && otherOwner->client && otherOwner->client->ps.duelInProgress &&
			otherOwner->client->ps.duelIndex != ent->r.ownerNum)
		{
			goto killProj;
		}
	}
	else if (!isKnockedSaber)
	{
		if (other->takedamage && other->client && other->client->ps.duelInProgress &&
			other->client->ps.duelIndex != ent->r.ownerNum)
		{
			goto killProj;
		}
	}

	if (other->flags & FL_DMG_BY_HEAVY_WEAP_ONLY)
	{
		if (ent->methodOfDeath != MOD_REPEATER_ALT &&
			ent->methodOfDeath != MOD_ROCKET &&
			ent->methodOfDeath != MOD_FLECHETTE_ALT_SPLASH &&
			ent->methodOfDeath != MOD_ROCKET_HOMING &&
			ent->methodOfDeath != MOD_THERMAL &&
			ent->methodOfDeath != MOD_THERMAL_SPLASH &&
			ent->methodOfDeath != MOD_TRIP_MINE_SPLASH &&
			ent->methodOfDeath != MOD_TIMED_MINE_SPLASH &&
			ent->methodOfDeath != MOD_DET_PACK_SPLASH &&
			ent->methodOfDeath != MOD_VEHICLE &&
			ent->methodOfDeath != MOD_CONC &&
			ent->methodOfDeath != MOD_CONC_ALT &&
			ent->methodOfDeath != MOD_SABER &&
			ent->methodOfDeath != MOD_TURBLAST)
		{
			vec3_t fwd;

			if (trace)
			{
				VectorCopy(trace->plane.normal, fwd);
			}
			else
			{ //oh well
				AngleVectors(other->r.currentAngles, fwd, NULL, NULL);
			}

			G_DeflectMissile(other, ent, fwd);
			G_MissileBounceEffect(ent, ent->r.currentOrigin, fwd);
			return;
		}
	}

	if ((other->flags & FL_SHIELDED) &&
		ent->s.weapon != WP_ROCKET_LAUNCHER &&
		ent->s.weapon != WP_THERMAL &&
		ent->s.weapon != WP_TRIP_MINE &&
		ent->s.weapon != WP_DET_PACK &&
		ent->s.weapon != WP_EMPLACED_GUN &&
		ent->methodOfDeath != MOD_REPEATER_ALT &&
		ent->methodOfDeath != MOD_FLECHETTE_ALT_SPLASH && 
		ent->methodOfDeath != MOD_TURBLAST &&
		ent->methodOfDeath != MOD_VEHICLE &&
		ent->methodOfDeath != MOD_CONC &&
		ent->methodOfDeath != MOD_CONC_ALT &&
		!(ent->dflags&DAMAGE_HEAVY_WEAP_CLASS) )
	{// entity is shielded
		vec3_t fwd;

		if (other->client)
		{
			AngleVectors(other->client->ps.viewangles, fwd, NULL, NULL);
		}
		else
		{
			AngleVectors(other->r.currentAngles, fwd, NULL, NULL);
		}

		G_DeflectMissile(other, ent, fwd);
		G_MissileBounceEffect(ent, ent->r.currentOrigin, fwd);
		return;
	}

	// SABERFIXME: make this based on .wpn file? some conc rifles should be able to be deflected...
	if (other->takedamage && other->client &&
		ent->s.weapon != WP_ROCKET_LAUNCHER &&
		ent->s.weapon != WP_THERMAL &&
		ent->s.weapon != WP_TRIP_MINE &&
		ent->s.weapon != WP_DET_PACK &&
		ent->methodOfDeath != MOD_REPEATER_ALT &&
		ent->methodOfDeath != MOD_FLECHETTE_ALT_SPLASH &&
		ent->methodOfDeath != MOD_CONC &&
		ent->methodOfDeath != MOD_CONC_ALT &&
		other->client->saberBlockDebounce < level.time &&
		!isKnockedSaber &&
		WP_SaberCanBlock(other, ent->r.currentOrigin, 0, 0, qtrue, 0))
	{ //only block one projectile per 200ms (to prevent giant swarms of projectiles being blocked)
		vec3_t fwd;
		gentity_t *te;
		int otherDefLevel = other->client->ps.fd.forcePowerLevel[FP_SABER_DEFENSE];

		te = G_TempEntity( ent->r.currentOrigin, EV_SABER_BLOCK );
		VectorCopy(ent->r.currentOrigin, te->s.origin);
		VectorCopy(trace->plane.normal, te->s.angles);
		te->s.eventParm = 0;
		te->s.weapon = 0;//saberNum
		te->s.legsAnim = 0;//bladeNum

		/*if (other->client->ps.velocity[2] > 0 ||
			other->client->pers.cmd.forwardmove ||
			other->client->pers.cmd.rightmove)
			*/
		if (other->client->ps.velocity[2] > 0 ||
			other->client->pers.cmd.forwardmove < 0) //now we only do it if jumping or running backward. Should be able to full-on charge.
		{
			otherDefLevel -= 1;
			if (otherDefLevel < 0)
			{
				otherDefLevel = 0;
			}
		}

		AngleVectors(other->client->ps.viewangles, fwd, NULL, NULL);
		// SABERFIXME: Don't make this force based. This code is ugly as f**k anyway
		other->client->saberBlockDebounce = level.time + (350 - (otherDefLevel*100)); //200;

		//For jedi AI
		other->client->ps.saberEventFlags |= SEF_DEFLECTED;
		if ( other->client->ps.saberActionFlags & (1 << SAF_BLOCKING) && !(other->client->ps.saberActionFlags & ( 1 << SAF_PROJBLOCKING) ) )
		{
			goto killProj;
 		}
		else if ( other->client->ps.saberActionFlags & SAF_PROJBLOCKING )
		{
			JKG_SaberDeflectMissile(other, ent, fwd);
			other->client->saberProjBlockTime += 500; // give them a little bit of leeway --eez
		}
		return;
	}
	else if ((other->r.contents & CONTENTS_LIGHTSABER) && !isKnockedSaber)
	{ //hit this person's saber, so..
		gentity_t *otherOwner = &g_entities[other->r.ownerNum];

		if (otherOwner->takedamage && otherOwner->client &&
			ent->s.weapon != WP_ROCKET_LAUNCHER &&
			ent->s.weapon != WP_THERMAL &&
			ent->s.weapon != WP_TRIP_MINE &&
			ent->s.weapon != WP_DET_PACK &&
			ent->methodOfDeath != MOD_REPEATER_ALT &&
			ent->methodOfDeath != MOD_FLECHETTE_ALT_SPLASH &&
			ent->methodOfDeath != MOD_CONC &&
			ent->methodOfDeath != MOD_CONC_ALT /*&&
			otherOwner->client->ps.saberBlockTime < level.time*/)
		{ //for now still deflect even if saberBlockTime >= level.time because it hit the actual saber
			vec3_t fwd;
			gentity_t *te;
			int otherDefLevel = otherOwner->client->ps.fd.forcePowerLevel[FP_SABER_DEFENSE];

			//in this case, deflect it even if we can't actually block it because it hit our saber
			//WP_SaberCanBlock(otherOwner, ent->r.currentOrigin, 0, 0, qtrue, 0);
			if (otherOwner->client && otherOwner->client->ps.weaponTime <= 0)
			{
				WP_SaberBlockNonRandom(otherOwner, NULL, ent->r.currentOrigin, qtrue);		// <-- ??? --eez
			}

			te = G_TempEntity( ent->r.currentOrigin, EV_SABER_BLOCK );
			VectorCopy(ent->r.currentOrigin, te->s.origin);
			VectorCopy(trace->plane.normal, te->s.angles);
			te->s.eventParm = 0;
			te->s.weapon = 0;//saberNum
			te->s.legsAnim = 0;//bladeNum

			/*if (otherOwner->client->ps.velocity[2] > 0 ||
				otherOwner->client->pers.cmd.forwardmove ||
				otherOwner->client->pers.cmd.rightmove)*/
			if (otherOwner->client->ps.velocity[2] > 0 ||
				otherOwner->client->pers.cmd.forwardmove < 0) //now we only do it if jumping or running backward. Should be able to full-on charge.
			{
				otherDefLevel -= 1;
				if (otherDefLevel < 0)
				{
					otherDefLevel = 0;
				}
			}

			AngleVectors(otherOwner->client->ps.viewangles, fwd, NULL, NULL);
			otherOwner->client->saberBlockDebounce = level.time + (350 - (otherDefLevel*100));//200;

			//For jedi AI
			otherOwner->client->ps.saberEventFlags |= SEF_DEFLECTED;

			// um...this code is a lil messed up, so i'll replace it with my own --eez
			if ( otherOwner->client->ps.saberActionFlags & (1 << SAF_BLOCKING) && !(otherOwner->client->ps.saberActionFlags & ( 1 << SAF_PROJBLOCKING )) )
			{
				goto killProj;
 			}
			else if ( otherOwner->client->ps.saberActionFlags & ( 1 << SAF_PROJBLOCKING ) )
			{
				// SABERFIXME: Write new function for this
				JKG_SaberDeflectMissile(otherOwner, ent, fwd);
				otherOwner->client->saberProjBlockTime += 500; // give them a little bit of leeway --eez
			}

			return;
		}
	}

	if( ent->genericValue10 )	// nerf this check in order to make grenade bouncing work --eez
	{
		vec3_t fwd;

		if (other->client)
		{
			AngleVectors(other->client->ps.viewangles, fwd, NULL, NULL);
		}
		else
		{
			AngleVectors(other->r.currentAngles, fwd, NULL, NULL);
		}
		VectorScale(ent->s.pos.trDelta, 0.2, ent->s.pos.trDelta);
		G_Damage(other, ent, ent->parent, fwd, ent->s.origin, ent->genericValue9, 0, MOD_THERMAL);
		G_DeflectMissile(other, ent, fwd);
		//G_MissileBounceEffect(ent, ent->r.currentOrigin, fwd);
		return;
	}

	// check for sticking
	if ( !other->takedamage && ( ent->s.eFlags & EF_MISSILE_STICK ) ) 
	{
		laserTrapStick( ent, trace->endpos, trace->plane.normal );
		G_AddEvent( ent, EV_MISSILE_STICK, 0 );
		return;
	}

	// impact damage
	if (other->takedamage && !isKnockedSaber) {
		// FIXME: wrong damage direction?
		weaponData_t *weapon = GetWeaponData (ent->s.weapon, ent->s.weaponVariation);
		weaponFireModeStats_t *fireMode = &weapon->firemodes[ent->s.firingMode];
		
		if ( ent->damage || fireMode->damageTypeHandle || fireMode->secondaryDmgHandle ) {
			vec3_t	velocity;

			hitClient = qtrue;
			BG_EvaluateTrajectoryDelta( &ent->s.pos, level.time, velocity );
			if ( VectorLength( velocity ) == 0 ) {
				velocity[2] = 1;	// stepped on a grenade
			}

            if ( fireMode->damageTypeHandle )
            {
                JKG_DoDamage (fireMode->damageTypeHandle, other, ent, &g_entities[ent->r.ownerNum], velocity, ent->r.currentOrigin, 0, ent->methodOfDeath);
            }
            else if ( ent->damage )
            {
                G_Damage (other, ent, &g_entities[ent->r.ownerNum], velocity, ent->r.currentOrigin, ent->damage, 0, ent->methodOfDeath);
            }
            
            if ( fireMode->secondaryDmgHandle )
            {
                JKG_DoDamage (fireMode->secondaryDmgHandle, other, ent, &g_entities[ent->r.ownerNum], velocity, ent->r.currentOrigin, 0, ent->methodOfDeath);
            }

			if (other->client)
			{ //What I'm wondering is why this isn't in the NPC pain funcs. But this is what SP does, so whatever.
				class_t	npc_class = other->client->NPC_class;

				// If we are a robot and we aren't currently doing the full body electricity...
				if ( npc_class == CLASS_SEEKER || npc_class == CLASS_PROBE || npc_class == CLASS_MOUSE ||
					   npc_class == CLASS_GONK || npc_class == CLASS_R2D2 || npc_class == CLASS_R5D2 || npc_class == CLASS_REMOTE ||
					   npc_class == CLASS_MARK1 || npc_class == CLASS_MARK2 || //npc_class == CLASS_PROTOCOL ||//no protocol, looks odd
					   npc_class == CLASS_INTERROGATOR || npc_class == CLASS_ATST || npc_class == CLASS_SENTRY )
				{
					// special droid only behaviors
					if ( other->client->ps.electrifyTime < level.time + 100 )
					{
						// ... do the effect for a split second for some more feedback
						other->client->ps.electrifyTime = level.time + 450;
					}
					//FIXME: throw some sparks off droids,too
				}
			}
		}
	}
killProj:
	// is it cheaper in bandwidth to just remove this ent and create a new
	// one, rather than changing the missile into the explosion?

	if ( other->takedamage && other->client && !isKnockedSaber ) {
		{
			G_AddEvent( ent, EV_MISSILE_HIT, DirToByte( trace->plane.normal ) );
			ent->s.otherEntityNum = other->s.number;
		}
	} else if( trace->surfaceFlags & SURF_METALSTEPS ) {
		G_AddEvent( ent, EV_MISSILE_MISS_METAL, DirToByte( trace->plane.normal ) );
	} else if (ent->s.weapon != G2_MODEL_PART && !isKnockedSaber) {
		G_AddEvent( ent, EV_MISSILE_MISS, DirToByte( trace->plane.normal ) );
	}

	if (!isKnockedSaber)
	{
		ent->freeAfterEvent = qtrue;

		// change over to a normal entity right at the point of impact
		ent->s.eType = ET_GENERAL;
	}

	SnapVectorTowards( trace->endpos, ent->s.pos.trBase );	// save net bandwidth

	G_SetOrigin( ent, trace->endpos );

	ent->takedamage = qfalse;

	if (ent->s.weapon == G2_MODEL_PART)
	{
		ent->freeAfterEvent = qfalse; //it will free itself
	}

	if(ent->splashRadius && ent->splashDamage && !ent->genericValue10)
	{
		G_RadiusDamage(trace->endpos, &g_entities[ent->r.ownerNum], ent->splashDamage, ent->splashRadius, NULL, ent, ent->methodOfDeath);
	}

	trap->LinkEntity( (sharedEntity_t *)ent );
}
Exemplo n.º 13
0
void G_MissileImpact( gentity_t *ent, trace_t *trace ) {
    gentity_t		*other;
    qboolean		hitClient = qfalse;
    qboolean		isKnockedSaber = qfalse;

    other = &g_entities[trace->entityNum];

    // check for bounce
    if ( !other->takedamage &&
            (ent->bounceCount > 0 || ent->bounceCount == -5) &&
            ( ent->flags & ( FL_BOUNCE | FL_BOUNCE_HALF ) ) ) {
        G_BounceMissile( ent, trace );
        G_AddEvent( ent, EV_GRENADE_BOUNCE, 0 );
        return;
    }
    else if (ent->neverFree && ent->s.weapon == WP_SABER && (ent->flags & FL_BOUNCE_HALF))
    {   //this is a knocked-away saber
        if (ent->bounceCount > 0 || ent->bounceCount == -5)
        {
            G_BounceMissile( ent, trace );
            G_AddEvent( ent, EV_GRENADE_BOUNCE, 0 );
            return;
        }

        isKnockedSaber = qtrue;
    }

    // I would glom onto the FL_BOUNCE code section above, but don't feel like risking breaking something else
    if ( (!other->takedamage && (ent->bounceCount > 0 || ent->bounceCount == -5) && ( ent->flags&(FL_BOUNCE_SHRAPNEL) ) ) || ((trace->surfaceFlags&SURF_FORCEFIELD)&&!ent->splashDamage&&!ent->splashRadius&&(ent->bounceCount > 0 || ent->bounceCount == -5)) )
    {
        G_BounceMissile( ent, trace );

        if ( ent->bounceCount < 1 )
        {
            ent->flags &= ~FL_BOUNCE_SHRAPNEL;
        }
        return;
    }

    /*
    if ( !other->takedamage && ent->s.weapon == WP_THERMAL && !ent->alt_fire )
    {//rolling thermal det - FIXME: make this an eFlag like bounce & stick!!!
    	//G_BounceRollMissile( ent, trace );
    	if ( ent->owner && ent->owner->s.number == 0 )
    	{
    		G_MissileAddAlerts( ent );
    	}
    	//gi.linkentity( ent );
    	return;
    }
    */

    if ((other->r.contents & CONTENTS_LIGHTSABER) && !isKnockedSaber)
    {   //hit this person's saber, so..
        gentity_t *otherOwner = &g_entities[other->r.ownerNum];

        if (otherOwner->takedamage && otherOwner->client && otherOwner->client->ps.duelInProgress &&
                otherOwner->client->ps.duelIndex != ent->r.ownerNum)
        {
            goto killProj;
        }
    }
    else if (!isKnockedSaber)
    {
        if (other->takedamage && other->client && other->client->ps.duelInProgress &&
                other->client->ps.duelIndex != ent->r.ownerNum)
        {
            goto killProj;
        }
    }

    if (other->flags & FL_DMG_BY_HEAVY_WEAP_ONLY)
    {
        if (ent->methodOfDeath != MOD_REPEATER_ALT &&
                ent->methodOfDeath != MOD_ROCKET &&
                ent->methodOfDeath != MOD_FLECHETTE_ALT_SPLASH &&
                ent->methodOfDeath != MOD_ROCKET_HOMING &&
                ent->methodOfDeath != MOD_THERMAL &&
                ent->methodOfDeath != MOD_THERMAL_SPLASH &&
                ent->methodOfDeath != MOD_TRIP_MINE_SPLASH &&
                ent->methodOfDeath != MOD_TIMED_MINE_SPLASH &&
                ent->methodOfDeath != MOD_DET_PACK_SPLASH &&
                ent->methodOfDeath != MOD_VEHICLE &&
                ent->methodOfDeath != MOD_CONC &&
                ent->methodOfDeath != MOD_CONC_ALT &&
                ent->methodOfDeath != MOD_SABER &&
                ent->methodOfDeath != MOD_TURBLAST)
        {
            vec3_t fwd;

            if (trace)
            {
                VectorCopy(trace->plane.normal, fwd);
            }
            else
            {   //oh well
                AngleVectors(other->r.currentAngles, fwd, NULL, NULL);
            }

            G_DeflectMissile(other, ent, fwd);
            G_MissileBounceEffect(ent, ent->r.currentOrigin, fwd);
            return;
        }
    }

    if ((other->flags & FL_SHIELDED) &&
            ent->s.weapon != WP_ROCKET_LAUNCHER &&
            ent->s.weapon != WP_THERMAL &&
            ent->s.weapon != WP_TRIP_MINE &&
            ent->s.weapon != WP_DET_PACK &&
            ent->s.weapon != WP_DEMP2 &&
            ent->s.weapon != WP_EMPLACED_GUN &&
            ent->methodOfDeath != MOD_REPEATER_ALT &&
            ent->methodOfDeath != MOD_FLECHETTE_ALT_SPLASH &&
            ent->methodOfDeath != MOD_TURBLAST &&
            ent->methodOfDeath != MOD_VEHICLE &&
            ent->methodOfDeath != MOD_CONC &&
            ent->methodOfDeath != MOD_CONC_ALT &&
            !(ent->dflags&DAMAGE_HEAVY_WEAP_CLASS) )
    {
        vec3_t fwd;

        if (other->client)
        {
            AngleVectors(other->client->ps.viewangles, fwd, NULL, NULL);
        }
        else
        {
            AngleVectors(other->r.currentAngles, fwd, NULL, NULL);
        }

        G_DeflectMissile(other, ent, fwd);
        G_MissileBounceEffect(ent, ent->r.currentOrigin, fwd);
        return;
    }

    if (other->takedamage && other->client &&
            ent->s.weapon != WP_ROCKET_LAUNCHER &&
            ent->s.weapon != WP_THERMAL &&
            ent->s.weapon != WP_TRIP_MINE &&
            ent->s.weapon != WP_DET_PACK &&
            ent->s.weapon != WP_DEMP2 &&
            ent->methodOfDeath != MOD_REPEATER_ALT &&
            ent->methodOfDeath != MOD_FLECHETTE_ALT_SPLASH &&
            ent->methodOfDeath != MOD_CONC &&
            ent->methodOfDeath != MOD_CONC_ALT &&
            other->client->ps.saberBlockTime < level.time &&
            !isKnockedSaber &&
            WP_SaberCanBlock(other, ent->r.currentOrigin, 0, 0, qtrue, 0))
    {   //only block one projectile per 200ms (to prevent giant swarms of projectiles being blocked)
        vec3_t fwd;
        gentity_t *te;
        int otherDefLevel = other->client->ps.fd.forcePowerLevel[FP_SABER_DEFENSE];

        te = G_TempEntity( ent->r.currentOrigin, EV_SABER_BLOCK );
        VectorCopy(ent->r.currentOrigin, te->s.origin);
        VectorCopy(trace->plane.normal, te->s.angles);
        te->s.eventParm = 0;

        /*if (other->client->ps.velocity[2] > 0 ||
        	other->client->pers.cmd.forwardmove ||
        	other->client->pers.cmd.rightmove)
        	*/
        if (other->client->ps.velocity[2] > 0 ||
                other->client->pers.cmd.forwardmove < 0) //now we only do it if jumping or running backward. Should be able to full-on charge.
        {
            otherDefLevel -= 1;
            if (otherDefLevel < 0)
            {
                otherDefLevel = 0;
            }
        }

        AngleVectors(other->client->ps.viewangles, fwd, NULL, NULL);
        if (otherDefLevel == FORCE_LEVEL_1)
        {
            //if def is only level 1, instead of deflecting the shot it should just die here
        }
        else if (otherDefLevel == FORCE_LEVEL_2)
        {
            G_DeflectMissile(other, ent, fwd);
        }
        else
        {
            G_ReflectMissile(other, ent, fwd);
        }
        other->client->ps.saberBlockTime = level.time + (350 - (otherDefLevel*100)); //200;

        //For jedi AI
        other->client->ps.saberEventFlags |= SEF_DEFLECTED;

        if (otherDefLevel == FORCE_LEVEL_3)
        {
            other->client->ps.saberBlockTime = 0; //^_^
        }

        if (otherDefLevel == FORCE_LEVEL_1)
        {
            goto killProj;
        }
        return;
    }
    else if ((other->r.contents & CONTENTS_LIGHTSABER) && !isKnockedSaber)
    {   //hit this person's saber, so..
        gentity_t *otherOwner = &g_entities[other->r.ownerNum];

        if (otherOwner->takedamage && otherOwner->client &&
                ent->s.weapon != WP_ROCKET_LAUNCHER &&
                ent->s.weapon != WP_THERMAL &&
                ent->s.weapon != WP_TRIP_MINE &&
                ent->s.weapon != WP_DET_PACK &&
                ent->s.weapon != WP_DEMP2 &&
                ent->methodOfDeath != MOD_REPEATER_ALT &&
                ent->methodOfDeath != MOD_FLECHETTE_ALT_SPLASH &&
                ent->methodOfDeath != MOD_CONC &&
                ent->methodOfDeath != MOD_CONC_ALT /*&&
			otherOwner->client->ps.saberBlockTime < level.time*/)
        {   //for now still deflect even if saberBlockTime >= level.time because it hit the actual saber
            vec3_t fwd;
            gentity_t *te;
            int otherDefLevel = otherOwner->client->ps.fd.forcePowerLevel[FP_SABER_DEFENSE];

            //in this case, deflect it even if we can't actually block it because it hit our saber
            //WP_SaberCanBlock(otherOwner, ent->r.currentOrigin, 0, 0, qtrue, 0);
            if (otherOwner->client && otherOwner->client->ps.weaponTime <= 0)
            {
                WP_SaberBlockNonRandom(otherOwner, ent->r.currentOrigin, qtrue);
            }

            te = G_TempEntity( ent->r.currentOrigin, EV_SABER_BLOCK );
            VectorCopy(ent->r.currentOrigin, te->s.origin);
            VectorCopy(trace->plane.normal, te->s.angles);
            te->s.eventParm = 0;

            /*if (otherOwner->client->ps.velocity[2] > 0 ||
            	otherOwner->client->pers.cmd.forwardmove ||
            	otherOwner->client->pers.cmd.rightmove)*/
            if (otherOwner->client->ps.velocity[2] > 0 ||
                    otherOwner->client->pers.cmd.forwardmove < 0) //now we only do it if jumping or running backward. Should be able to full-on charge.
            {
                otherDefLevel -= 1;
                if (otherDefLevel < 0)
                {
                    otherDefLevel = 0;
                }
            }

            AngleVectors(otherOwner->client->ps.viewangles, fwd, NULL, NULL);

            if (otherDefLevel == FORCE_LEVEL_1)
            {
                //if def is only level 1, instead of deflecting the shot it should just die here
            }
            else if (otherDefLevel == FORCE_LEVEL_2)
            {
                G_DeflectMissile(otherOwner, ent, fwd);
            }
            else
            {
                G_ReflectMissile(otherOwner, ent, fwd);
            }
            otherOwner->client->ps.saberBlockTime = level.time + (350 - (otherDefLevel*100));//200;

            //For jedi AI
            otherOwner->client->ps.saberEventFlags |= SEF_DEFLECTED;

            if (otherDefLevel == FORCE_LEVEL_3)
            {
                otherOwner->client->ps.saberBlockTime = 0; //^_^
            }

            if (otherDefLevel == FORCE_LEVEL_1)
            {
                goto killProj;
            }
            return;
        }
    }

    // check for sticking
    if ( !other->takedamage && ( ent->s.eFlags & EF_MISSILE_STICK ) )
    {
        laserTrapStick( ent, trace->endpos, trace->plane.normal );
        G_AddEvent( ent, EV_MISSILE_STICK, 0 );
        return;
    }

    // impact damage
    if (other->takedamage && !isKnockedSaber) {
        // FIXME: wrong damage direction?
        if ( ent->damage ) {
            vec3_t	velocity;
            qboolean didDmg = qfalse;

            if( LogAccuracyHit( other, &g_entities[ent->r.ownerNum] ) ) {
                g_entities[ent->r.ownerNum].client->accuracy_hits++;
                hitClient = qtrue;
            }
            BG_EvaluateTrajectoryDelta( &ent->s.pos, level.time, velocity );
            if ( VectorLength( velocity ) == 0 ) {
                velocity[2] = 1;	// stepped on a grenade
            }

            if (ent->s.weapon == WP_BOWCASTER || ent->s.weapon == WP_FLECHETTE ||
                    ent->s.weapon == WP_ROCKET_LAUNCHER)
            {
                if (ent->s.weapon == WP_FLECHETTE && (ent->s.eFlags & EF_ALT_FIRING))
                {
                    ent->think(ent);
                }
                else
                {
                    G_Damage (other, ent, &g_entities[ent->r.ownerNum], velocity,
                              /*ent->s.origin*/ent->r.currentOrigin, ent->damage,
                              DAMAGE_HALF_ABSORB, ent->methodOfDeath);
                    didDmg = qtrue;
                }
            }
            else
            {
                G_Damage (other, ent, &g_entities[ent->r.ownerNum], velocity,
                          /*ent->s.origin*/ent->r.currentOrigin, ent->damage,
                          0, ent->methodOfDeath);
                didDmg = qtrue;
            }

            if (didDmg && other && other->client)
            {   //What I'm wondering is why this isn't in the NPC pain funcs. But this is what SP does, so whatever.
                class_t	npc_class = other->client->NPC_class;

                // If we are a robot and we aren't currently doing the full body electricity...
                if ( npc_class == CLASS_SEEKER || npc_class == CLASS_PROBE || npc_class == CLASS_MOUSE ||
                        npc_class == CLASS_GONK || npc_class == CLASS_R2D2 || npc_class == CLASS_R5D2 || npc_class == CLASS_REMOTE ||
                        npc_class == CLASS_MARK1 || npc_class == CLASS_MARK2 || //npc_class == CLASS_PROTOCOL ||//no protocol, looks odd
                        npc_class == CLASS_INTERROGATOR || npc_class == CLASS_ATST || npc_class == CLASS_SENTRY )
                {
                    // special droid only behaviors
                    if ( other->client->ps.electrifyTime < level.time + 100 )
                    {
                        // ... do the effect for a split second for some more feedback
                        other->client->ps.electrifyTime = level.time + 450;
                    }
                    //FIXME: throw some sparks off droids,too
                }
            }
        }

        if ( ent->s.weapon == WP_DEMP2 )
        {   //a hit with demp2 decloaks people, disables ships
            if ( other && other->client && other->client->NPC_class == CLASS_VEHICLE )
            {   //hit a vehicle
                if ( other->m_pVehicle //valid vehicle ent
                        && other->m_pVehicle->m_pVehicleInfo//valid stats
                        && (other->m_pVehicle->m_pVehicleInfo->type == VH_SPEEDER//always affect speeders
                            ||(other->m_pVehicle->m_pVehicleInfo->type == VH_FIGHTER && ent->classname && Q_stricmp("vehicle_proj", ent->classname ) == 0) )//only vehicle ion weapons affect a fighter in this manner
                        && !FighterIsLanded( other->m_pVehicle , &other->client->ps )//not landed
                        && !(other->spawnflags&2) )//and not suspended
                {   //vehicles hit by "ion cannons" lose control
                    if ( other->client->ps.electrifyTime > level.time )
                    {   //add onto it
                        //FIXME: extern the length of the "out of control" time?
                        other->client->ps.electrifyTime += Q_irand(200,500);
                        if ( other->client->ps.electrifyTime > level.time + 4000 )
                        {   //cap it
                            other->client->ps.electrifyTime = level.time + 4000;
                        }
                    }
                    else
                    {   //start it
                        //FIXME: extern the length of the "out of control" time?
                        other->client->ps.electrifyTime = level.time + Q_irand(200,500);
                    }
                }
            }
            else if ( other && other->client && other->client->ps.powerups[PW_CLOAKED] )
            {
                Jedi_Decloak( other );
                if ( ent->methodOfDeath == MOD_DEMP2_ALT )
                {   //direct hit with alt disables cloak forever
                    //permanently disable the saboteur's cloak
                    other->client->cloakToggleTime = Q3_INFINITE;
                }
                else
                {   //temp disable
                    other->client->cloakToggleTime = level.time + Q_irand( 3000, 10000 );
                }
            }
        }
    }
killProj:
    // is it cheaper in bandwidth to just remove this ent and create a new
    // one, rather than changing the missile into the explosion?

    if ( other->takedamage && other->client && !isKnockedSaber ) {
        G_AddEvent( ent, EV_MISSILE_HIT, DirToByte( trace->plane.normal ) );
        ent->s.otherEntityNum = other->s.number;
    } else if( trace->surfaceFlags & SURF_METALSTEPS ) {
        G_AddEvent( ent, EV_MISSILE_MISS_METAL, DirToByte( trace->plane.normal ) );
    } else if (ent->s.weapon != G2_MODEL_PART && !isKnockedSaber) {
        G_AddEvent( ent, EV_MISSILE_MISS, DirToByte( trace->plane.normal ) );
    }

    if (!isKnockedSaber)
    {
        ent->freeAfterEvent = qtrue;

        // change over to a normal entity right at the point of impact
        ent->s.eType = ET_GENERAL;
    }

    SnapVectorTowards( trace->endpos, ent->s.pos.trBase );	// save net bandwidth

    G_SetOrigin( ent, trace->endpos );

    ent->takedamage = qfalse;
    // splash damage (doesn't apply to person directly hit)
    if ( ent->splashDamage ) {
        if( G_RadiusDamage( trace->endpos, ent->parent, ent->splashDamage, ent->splashRadius,
                            other, ent, ent->splashMethodOfDeath ) ) {
            if( !hitClient
                    && g_entities[ent->r.ownerNum].client ) {
                g_entities[ent->r.ownerNum].client->accuracy_hits++;
            }
        }
    }

    if (ent->s.weapon == G2_MODEL_PART)
    {
        ent->freeAfterEvent = qfalse; //it will free itself
    }

    trap_LinkEntity( ent );
}
Exemplo n.º 14
0
//QUAKED target_laser (0 .5 0) (-8 -8 -8) (8 8 8) START_ON RED GREEN BLUE YELLOW ORANGE FAT
//When triggered, fires a laser.  You can either set a target or a direction.
//-------- KEYS --------
//angles: alternate "pitch, yaw, roll" angles method of aiming laser (default 0 0 0).
//target : point this to a target_position entity to set the laser's aiming direction.
//targetname : the activating trigger points to this.
//notsingle : when set to 1, entity will not spawn in Single Player mode
//notfree : when set to 1, entity will not spawn in "Free for all" and "Tournament" modes.
//notduel : when set to 1, entity will not spawn in "Teamplay" and "CTF" modes. (jal: todo)
//notteam : when set to 1, entity will not spawn in "Teamplay" and "CTF" modes.
//-------- SPAWNFLAGS --------
//START_ON : when set, the laser will start on in the game.
//RED :
//GREEN : BLUE :
//YELLOW :
//ORANGE :
//FAT :
static void target_laser_think( edict_t *self )
{
	edict_t	*ignore;
	vec3_t start;
	vec3_t end;
	trace_t	tr;
	vec3_t point;
	vec3_t last_movedir;
	int count;

	// our lifetime has expired
	if( self->delay && ( self->wait * 1000 < level.time ) )
	{
		if( self->r.owner && self->r.owner->use )
			G_CallUse( self->r.owner, self, self->activator );

		G_FreeEdict( self );
		return;
	}

	if( self->spawnflags & 0x80000000 )
		count = 8;
	else
		count = 4;

	if( self->enemy )
	{
		VectorCopy( self->moveinfo.movedir, last_movedir );
		VectorMA( self->enemy->r.absmin, 0.5, self->enemy->r.size, point );
		VectorSubtract( point, self->s.origin, self->moveinfo.movedir );
		VectorNormalize( self->moveinfo.movedir );
		if( !VectorCompare( self->moveinfo.movedir, last_movedir ) )
			self->spawnflags |= 0x80000000;
	}

	ignore = self;
	VectorCopy( self->s.origin, start );
	VectorMA( start, 2048, self->moveinfo.movedir, end );
	VectorClear( tr.endpos ); // shut up compiler
	while( 1 )
	{
		G_Trace( &tr, start, NULL, NULL, end, ignore, MASK_SHOT );
		if( tr.fraction == 1 )
			break;

		// hurt it if we can
		if( ( game.edicts[tr.ent].takedamage ) && !( game.edicts[tr.ent].flags & FL_IMMUNE_LASER ) )
		{
			if( game.edicts[tr.ent].r.client && self->activator->r.client )
			{
				if( !GS_TeamBasedGametype() ||
					game.edicts[tr.ent].s.team != self->activator->s.team )
					G_Damage( &game.edicts[tr.ent], self, self->activator, self->moveinfo.movedir, self->moveinfo.movedir, tr.endpos, self->dmg, 1, 0, 0, self->count );
			}
			else
			{
				G_Damage( &game.edicts[tr.ent], self, self->activator, self->moveinfo.movedir, self->moveinfo.movedir, tr.endpos, self->dmg, 1, 0, 0, self->count );
			}
		}

		// if we hit something that's not a monster or player or is immune to lasers, we're done
		if( !game.edicts[tr.ent].r.client )
		{
			if( self->spawnflags & 0x80000000 )
			{
				edict_t *event;

				self->spawnflags &= ~0x80000000;

				event = G_SpawnEvent( EV_LASER_SPARKS, DirToByte( tr.plane.normal ), tr.endpos );
				event->s.eventCount = count;
				event->s.colorRGBA = self->s.colorRGBA;
			}
			break;
		}

		ignore = &game.edicts[tr.ent];
		VectorCopy( tr.endpos, start );
	}

	VectorCopy( tr.endpos, self->s.origin2 );
	G_SetBoundsForSpanEntity( self, 8 );

	GClip_LinkEntity( self );

	self->nextThink = level.time + 1;
}
Exemplo n.º 15
0
static void SendMeleeHitEvent( gentity_t *attacker, gentity_t *target, trace_t *tr )
{
	gentity_t *event;
	vec3_t    normal, origin;
	float     mag, radius;

	if ( !attacker->client )
	{
		return;
	}

	if ( target->health <= 0 )
	{
		return;
	}

	if ( tr )
	{
		VectorSubtract( tr->endpos, target->s.origin, normal );
	}
	else
	{
		VectorSubtract( attacker->client->ps.origin, target->s.origin, normal );
	}

	// Normalize the horizontal components of the vector difference to the "radius" of the bounding box
	mag = sqrt( normal[ 0 ] * normal[ 0 ] + normal[ 1 ] * normal[ 1 ] );
	radius = target->r.maxs[ 0 ] * 1.21f;

	if ( mag > radius )
	{
		normal[ 0 ] = normal[ 0 ] / mag * radius;
		normal[ 1 ] = normal[ 1 ] / mag * radius;
	}

	// Clamp origin to be within bounding box vertically
	if ( normal[ 2 ] > target->r.maxs[ 2 ] )
	{
		normal[ 2 ] = target->r.maxs[ 2 ];
	}

	if ( normal[ 2 ] < target->r.mins[ 2 ] )
	{
		normal[ 2 ] = target->r.mins[ 2 ];
	}

	VectorAdd( target->s.origin, normal, origin );
	VectorNegate( normal, normal );
	VectorNormalize( normal );

	event = G_NewTempEntity( origin, EV_WEAPON_HIT_ENTITY );

	// normal
	event->s.eventParm = DirToByte( normal );

	// victim
	event->s.otherEntityNum = target->s.number;

	// attacker
	event->s.otherEntityNum2 = attacker->s.number;

	// weapon
	event->s.weapon = attacker->s.weapon;

	// weapon mode
	event->s.generic1 = attacker->s.generic1;
}
Exemplo n.º 16
0
/*
================
G_ExplodeMissile

Explode a missile without an impact
================
*/
void G_ExplodeMissile( gentity_t *ent ) {
	vec3_t dir;
	vec3_t origin;
	qboolean small = qfalse;
	qboolean zombiespit = qfalse;
	int etype;

	BG_EvaluateTrajectory( &ent->s.pos, level.time, origin );
	SnapVector( origin );
	G_SetOrigin( ent, origin );

	// we don't have a valid direction, so just point straight up
	dir[0] = dir[1] = 0;
	dir[2] = 1;

	etype = ent->s.eType;

	ent->s.eType = ET_GENERAL;

	if ( !Q_stricmp( ent->classname, "props_explosion" ) ) {
		G_AddEvent( ent, EV_MISSILE_MISS_SMALL, DirToByte( dir ) );
		small = qtrue;
	}
// JPW NERVE
	else if ( !Q_stricmp( ent->classname, "air strike" ) ) {
		G_AddEvent( ent, EV_MISSILE_MISS_LARGE, DirToByte( dir ) );
		small = qfalse;
	}
// jpw
	else if ( !Q_stricmp( ent->classname, "props_explosion_large" ) ) {
		G_AddEvent( ent, EV_MISSILE_MISS_LARGE, DirToByte( dir ) );
		small = qfalse;
	} else if ( !Q_stricmp( ent->classname, "zombiespit" ) )      {
		G_AddEvent( ent, EV_SPIT_MISS, DirToByte( dir ) );
		zombiespit = qtrue;
	} else if ( !Q_stricmp( ent->classname, "flamebarrel" ) )      {
		ent->freeAfterEvent = qtrue;
		trap_LinkEntity( ent );
		return;
	} else {
		G_AddEvent( ent, EV_MISSILE_MISS, DirToByte( dir ) );
	}

	ent->freeAfterEvent = qtrue;

	// splash damage
	if ( ent->splashDamage ) {
		if ( G_RadiusDamage( ent->r.currentOrigin, ent->parent, ent->splashDamage, ent->splashRadius, ent, ent->splashMethodOfDeath ) ) {    //----(SA)
			if ( g_entities[ent->r.ownerNum].client ) {
				g_entities[ent->r.ownerNum].client->ps.persistant[PERS_ACCURACY_HITS]++;
			}
		}
	}

	trap_LinkEntity( ent );

	if ( etype == ET_MISSILE ) {
		// DHM - Nerve :: ... in single player anyway
		if ( g_gametype.integer == GT_SINGLE_PLAYER ) {
			if ( ent->s.weapon == WP_VENOM_FULL ) { // no default impact smoke
				zombiespit = qtrue;
			} else if ( ent->s.weapon == WP_DYNAMITE || ent->s.weapon == WP_DYNAMITE2 ) {
//				// shot heard round the world...
				gentity_t *player;
				player = AICast_FindEntityForName( "player" );
				Concussive_fx( player->r.currentOrigin );
			}
		}
// JPW NERVE -- big nasty dynamite scoring section
		else {
			if ( g_gametype.integer >= GT_WOLF ) {
				if ( ent->s.weapon == WP_DYNAMITE ) { // do some scoring
// check if dynamite is in trigger_objective_info field
					vec3_t mins, maxs;
					//static vec3_t	range = { 18, 18, 18 }; // NOTE can use this to massage throw distance outside trigger field // TTimo unused
					int i,num,touch[MAX_GENTITIES];
					gentity_t   *hit;

					// NERVE - SMF - made this the actual bounding box of dynamite instead of range
					VectorAdd( ent->r.currentOrigin, ent->r.mins, mins );
					VectorAdd( ent->r.currentOrigin, ent->r.maxs, maxs );
					num = trap_EntitiesInBox( mins, maxs, touch, MAX_GENTITIES );
					VectorAdd( ent->r.currentOrigin, ent->r.mins, mins );
					VectorAdd( ent->r.currentOrigin, ent->r.maxs, maxs );

					for ( i = 0 ; i < num ; i++ ) {
						hit = &g_entities[touch[i]];
						if ( !hit->target ) {
							continue;
						}

						if ( !( hit->r.contents & CONTENTS_TRIGGER ) ) {
							continue;
						}
						if ( !strcmp( hit->classname,"trigger_objective_info" ) ) {
							if ( !( hit->spawnflags & ( AXIS_OBJECTIVE | ALLIED_OBJECTIVE ) ) ) {
								continue;
							}

							if ( ( ( hit->spawnflags & AXIS_OBJECTIVE ) && ( ent->s.teamNum == TEAM_BLUE ) ) ||
								 ( ( hit->spawnflags & ALLIED_OBJECTIVE ) && ( ent->s.teamNum == TEAM_RED ) ) ) {
								G_UseTargets( hit,ent );
								hit->think = G_FreeEntity;
								hit->nextthink = level.time + FRAMETIME;

								if ( ent->parent->client ) {
									if ( ent->s.teamNum == ent->parent->client->sess.sessionTeam ) { // make sure player hasn't changed teams -- per atvi req
										AddScore( ent->parent, hit->accuracy ); // set from map, see g_trigger
									}
								}
							}
						}
					}
				}
			}
			// give big weapons the shakey shakey
			if ( ent->s.weapon == WP_DYNAMITE || ent->s.weapon == WP_PANZERFAUST || ent->s.weapon == WP_GRENADE_LAUNCHER ||
				 ent->s.weapon == WP_GRENADE_PINEAPPLE || ent->s.weapon == WP_ROCKET_LAUNCHER || ent->s.weapon == WP_MORTAR ||
				 ent->s.weapon == WP_ARTY ) {
				Ground_Shaker( ent->r.currentOrigin, ent->splashDamage * 4 );
			}
			return;
		}
// jpw
	}


	if ( !zombiespit ) {
		gentity_t *Msmoke;

		Msmoke = G_Spawn();
		VectorCopy( ent->r.currentOrigin, Msmoke->s.origin );
		if ( small ) {
			Msmoke->s.density = 1;
		}
		Msmoke->think = M_think;
		Msmoke->nextthink = level.time + FRAMETIME;

		if ( ent->parent && !Q_stricmp( ent->parent->classname, "props_flamebarrel" ) ) {
			Msmoke->health = 10;
		} else {
			Msmoke->health = 5;
		}

		Concussive_fx( Msmoke->s.origin );
	}
}
Exemplo n.º 17
0
/*
* G_EdictsAddSnapEffects
* add effects based on accumulated info along the server frame
*/
static void G_SnapEntities( void )
{
	edict_t *ent;
	int i;
	vec3_t dir, origin;

	for( i = 0, ent = &game.edicts[0]; i < game.numentities; i++, ent++ )
	{
		if( !ent->r.inuse || ( ent->r.svflags & SVF_NOCLIENT ) )
			continue;

		if( ent->s.type == ET_PARTICLES ) // particles use a special configuration
		{
			ent->s.frame = ent->particlesInfo.speed;
			ent->s.modelindex = ent->particlesInfo.shaderIndex;
			ent->s.modelindex2 = ent->particlesInfo.spread;
			ent->s.counterNum = ent->particlesInfo.time;
			ent->s.weapon = ent->particlesInfo.frequency;

			ent->s.effects = ent->particlesInfo.size & 0xFF;
			if( ent->particlesInfo.spherical )
				ent->s.effects |= ( 1<<8 );
			if( ent->particlesInfo.bounce )
				ent->s.effects |= ( 1<<9 );
			if( ent->particlesInfo.gravity )
				ent->s.effects |= ( 1<<10 );
			if( ent->particlesInfo.expandEffect )
				ent->s.effects |= ( 1<<11 );
			if( ent->particlesInfo.shrinkEffect )
				ent->s.effects |= ( 1<<11 );

			GClip_LinkEntity( ent );

			continue;
		}

		if( ent->s.type == ET_PLAYER || ent->s.type == ET_CORPSE )
		{
			// this is pretty hackish. We exploit the fact that 0.5 servers *do not* transmit
			// origin2/old_origin for ET_PLAYER/ET_CORPSE entities, and we use it for sending the player velocity
			if( !G_ISGHOSTING( ent ) )
			{
				ent->r.svflags |= SVF_TRANSMITORIGIN2;
				VectorCopy( ent->velocity, ent->s.origin2 );
			}
			else
				ent->r.svflags &= ~SVF_TRANSMITORIGIN2;
		}

		if( ISEVENTENTITY( ent ) || G_ISGHOSTING( ent ) || !ent->takedamage )
			continue;

		// types which can have accumulated damage effects
		if( ( ent->s.type == ET_GENERIC || ent->s.type == ET_PLAYER || ent->s.type == ET_CORPSE ) ) // doors don't bleed
		{
			// Until we get a proper damage saved effect, we accumulate both into the blood fx
			// so, at least, we don't send 2 entities where we can send one
			ent->snap.damage_taken += ent->snap.damage_saved;
			//ent->snap.damage_saved = 0;

			//spawn accumulated damage
			if( ent->snap.damage_taken && !( ent->flags & FL_GODMODE ) && HEALTH_TO_INT( ent->health ) > 0 )
			{
				edict_t *event;
				float damage = ent->snap.damage_taken;
				if( damage > 120 )
					damage = 120;

				VectorCopy( ent->snap.damage_dir, dir );
				VectorNormalize( dir );
				VectorAdd( ent->s.origin, ent->snap.damage_at, origin );

				if( ent->s.type == ET_PLAYER || ent->s.type == ET_CORPSE )
				{
					event = G_SpawnEvent( EV_BLOOD, DirToByte( dir ), origin );
					event->s.damage = HEALTH_TO_INT( damage );
					event->s.ownerNum = i; // set owner

					// ET_PLAYERS can also spawn sound events
					if( ent->s.type == ET_PLAYER )
					{
						// play an apropriate pain sound
						if( level.time >= ent->pain_debounce_time )
						{
							// see if it should pain for a FALL or for damage received
							if( ent->snap.damage_fall )
							{
								ent->pain_debounce_time = level.time + 200;
							}
							else if( !G_IsDead( ent ) )
							{
								if( ent->r.client->ps.inventory[POWERUP_SHELL] > 0 )
									G_AddEvent( ent, EV_PAIN, PAIN_WARSHELL, true );
								else if( ent->health <= 20 )
									G_AddEvent( ent, EV_PAIN, PAIN_20, true );
								else if( ent->health <= 35 )
									G_AddEvent( ent, EV_PAIN, PAIN_30, true );
								else if( ent->health <= 60 )
									G_AddEvent( ent, EV_PAIN, PAIN_60, true );
								else
									G_AddEvent( ent, EV_PAIN, PAIN_100, true );

								ent->pain_debounce_time = level.time + 400;
							}
						}
					}
				}
				else
				{
					event = G_SpawnEvent( EV_SPARKS, DirToByte( dir ), origin );
					event->s.damage = HEALTH_TO_INT( damage );
				}
			}
		}
	}
}
Exemplo n.º 18
0
void G_MissileImpact( gentity_t *ent, trace_t *trace ) {
	gentity_t		*other;
	qboolean		hitClient = qfalse;
	other = &g_entities[trace->entityNum];

	// check for bounce
	if ( !other->takedamage &&
		(ent->bounceCount > 0 || ent->bounceCount == -5) &&
		( ent->flags & ( FL_BOUNCE | FL_BOUNCE_HALF ) ) ) {
		G_BounceMissile( ent, trace );
	//	G_AddEvent( ent, EV_GRENADE_BOUNCE, 0 );
		return;
	}

	if ( other->s.eType == ET_MISSILE && ent->s.weapon == WP_QUANTIZER && other->s.weapon == WP_MORTAR )
	{//Quantizer can deflect mortar shots :3
		G_DeflectMissile( ent, other, &ent->s.pos.trDelta );
		other->r.ownerNum = ent->r.ownerNum;
		G_FreeEntity( ent );
		return;
	}

	// impact damage
	if (other->takedamage) {
		// FIXME: wrong damage direction?
		if ( ent->damage ) {
			vector3	velocity;

			if( LogAccuracyHit( other, &g_entities[ent->r.ownerNum] ) ) {
				g_entities[ent->r.ownerNum].client->accuracy_hits++;
				hitClient = qtrue;
			}
			BG_EvaluateTrajectoryDelta( &ent->s.pos, level.time, &velocity );
			if ( VectorLength( &velocity ) == 0 ) {
				velocity.z = 1;	// stepped on a grenade
			}
			//Raz: The inflictor is the missile, for direct hits from quantizer/RLauncher/etc
			G_Damage( other, ent, &g_entities[ent->r.ownerNum], ent, NULL/*velocity*/, &ent->s.origin, ent->damage, 0, ent->methodOfDeath );
		}
	}

	// is it cheaper in bandwidth to just remove this ent and create a new
	// one, rather than changing the missile into the explosion?

	if ( other->takedamage && other->client ) {
		G_AddEvent( ent, EV_MISSILE_HIT, DirToByte( &trace->plane.normal ) );
		ent->s.otherEntityNum = other->s.number;
	} else if( trace->surfaceFlags & SURF_METALSTEPS ) {
		G_AddEvent( ent, EV_MISSILE_MISS_METAL, DirToByte( &trace->plane.normal ) );
	} else {
		G_AddEvent( ent, EV_MISSILE_MISS, DirToByte( &trace->plane.normal ) );
	}

	ent->freeAfterEvent = qtrue;

	// change over to a normal entity right at the point of impact
	ent->s.eType = ET_GENERAL;

	VectorSnapTowards( &trace->endpos, &ent->s.pos.trBase );	// save net bandwidth

	G_SetOrigin( ent, &trace->endpos );

	// splash damage (doesn't apply to person directly hit)
#if 0
	if ( ent->splashDamage ) {
		if( G_RadiusDamage( trace->endpos, ent->parent, ent->splashDamage, ent->splashRadius, 
			other, ent->splashMethodOfDeath ) ) {
			if( !hitClient ) {
				g_entities[ent->r.ownerNum].client->accuracy_hits++;
			}
		}
	}
#else
	//QtZ
	if ( (ent->splashDamage || ent->splashRadius)
		&& G_RadiusDamage( &trace->endpos, ent->parent, (float)ent->splashDamage, (float)ent->splashRadius, other, ent, ent->splashMethodOfDeath )
		&& !hitClient && g_entities[ent->r.ownerNum].client )
		g_entities[ent->r.ownerNum].client->accuracy_hits++;
#endif

	trap->SV_LinkEntity( (sharedEntity_t *)ent );
}
Exemplo n.º 19
0
void G_MissileImpacted( gentity_t *ent, gentity_t *other, vec3_t impactPos, vec3_t normal, int hitLoc=HL_NONE )
{
	// impact damage
	if ( other->takedamage )
	{
		// FIXME: wrong damage direction?
		if ( ent->damage )
		{
			vec3_t	velocity;

			EvaluateTrajectoryDelta( &ent->s.pos, level.time, velocity );
			if ( VectorLength( velocity ) == 0 )
			{
				velocity[2] = 1;	// stepped on a grenade
			}

			int damage = ent->damage;

			if( other->client )
			{
				class_t	npc_class = other->client->NPC_class;

				// If we are a robot and we aren't currently doing the full body electricity...
				if ( npc_class == CLASS_SEEKER || npc_class == CLASS_PROBE || npc_class == CLASS_MOUSE ||
					   npc_class == CLASS_GONK || npc_class == CLASS_R2D2 || npc_class == CLASS_R5D2 || npc_class == CLASS_REMOTE ||
					   npc_class == CLASS_MARK1 || npc_class == CLASS_MARK2 || //npc_class == CLASS_PROTOCOL ||//no protocol, looks odd
					   npc_class == CLASS_INTERROGATOR || npc_class == CLASS_ATST || npc_class == CLASS_SENTRY )
				{
					// special droid only behaviors
					if ( other->client->ps.powerups[PW_SHOCKED] < level.time + 100 )
					{
						// ... do the effect for a split second for some more feedback
						other->s.powerups |= ( 1 << PW_SHOCKED );
						other->client->ps.powerups[PW_SHOCKED] = level.time + 450;
					}
					//FIXME: throw some sparks off droids,too
				}
			}

			G_Damage( other, ent, ent->owner, velocity,
					impactPos, damage,
					ent->dflags, ent->methodOfDeath, hitLoc);

			if ( ent->s.weapon == WP_DEMP2 )
			{//a hit with demp2 decloaks saboteurs
				if ( other && other->client && other->client->NPC_class == CLASS_SABOTEUR )
				{//FIXME: make this disabled cloak hold for some amount of time?
					Saboteur_Decloak( other, Q_irand( 3000, 10000 ) );
					if ( ent->methodOfDeath == MOD_DEMP2_ALT )
					{//direct hit with alt disabled cloak forever
						if ( other->NPC )
						{//permanently disable the saboteur's cloak
							other->NPC->aiFlags &= ~NPCAI_SHIELDS;
						}
					}
				}
			}
		}
	}

	// is it cheaper in bandwidth to just remove this ent and create a new
	// one, rather than changing the missile into the explosion?
	//G_FreeEntity(ent);

	if ( (other->takedamage && other->client ) || (ent->s.weapon == WP_FLECHETTE && other->contents&CONTENTS_LIGHTSABER) )
	{
		G_AddEvent( ent, EV_MISSILE_HIT, DirToByte( normal ) );
		ent->s.otherEntityNum = other->s.number;
	}
	else
	{
		G_AddEvent( ent, EV_MISSILE_MISS, DirToByte( normal ) );
		ent->s.otherEntityNum = other->s.number;
	}

	VectorCopy( normal, ent->pos1 );

	if ( ent->owner )//&& ent->owner->s.number == 0 )
	{
		//Add the event
		AddSoundEvent( ent->owner, ent->currentOrigin, 256, AEL_SUSPICIOUS, qfalse, qtrue );
		AddSightEvent( ent->owner, ent->currentOrigin, 512, AEL_DISCOVERED, 75 );
	}

	ent->freeAfterEvent = qtrue;

	// change over to a normal entity right at the point of impact
	ent->s.eType = ET_GENERAL;

	//SnapVectorTowards( trace->endpos, ent->s.pos.trBase );	// save net bandwidth
	VectorCopy( impactPos, ent->s.pos.trBase );

	G_SetOrigin( ent, impactPos );

	// splash damage (doesn't apply to person directly hit)
	if ( ent->splashDamage )
	{
		G_RadiusDamage( impactPos, ent->owner, ent->splashDamage, ent->splashRadius,
			other, ent->splashMethodOfDeath );
	}

	if ( ent->s.weapon == WP_NOGHRI_STICK )
	{
		G_SpawnNoghriGasCloud( ent );
	}

	gi.linkentity( ent );
}
Exemplo n.º 20
0
/*
===============
CheckGrabAttack
===============
*/
void CheckGrabAttack( gentity_t *ent )
{
	trace_t   tr;
	vec3_t    end, dir;
	gentity_t *traceEnt;

	// set aiming directions
	AngleVectors( ent->client->ps.viewangles, forward, right, up );

	CalcMuzzlePoint( ent, forward, right, up, muzzle );

	if ( ent->client->ps.weapon == WP_ALEVEL1 )
	{
		VectorMA( muzzle, LEVEL1_GRAB_RANGE, forward, end );
	}
	else if ( ent->client->ps.weapon == WP_ALEVEL1_UPG )
	{
		VectorMA( muzzle, LEVEL1_GRAB_U_RANGE, forward, end );
	}

	trap_Trace( &tr, muzzle, NULL, NULL, end, ent->s.number, MASK_SHOT );

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

	traceEnt = &g_entities[ tr.entityNum ];

	if ( !traceEnt->takedamage )
	{
		return;
	}

	if ( traceEnt->client )
	{
		if ( traceEnt->client->ps.stats[ STAT_TEAM ] == TEAM_ALIENS )
		{
			return;
		}

		if ( traceEnt->client->ps.stats[ STAT_HEALTH ] <= 0 )
		{
			return;
		}

		if ( !( traceEnt->client->ps.stats[ STAT_STATE ] & SS_GRABBED ) )
		{
			AngleVectors( traceEnt->client->ps.viewangles, dir, NULL, NULL );
			traceEnt->client->ps.stats[ STAT_VIEWLOCK ] = DirToByte( dir );

			//event for client side grab effect
			G_AddPredictableEvent( ent, EV_LEV1_GRAB, 0 );
		}

		traceEnt->client->ps.stats[ STAT_STATE ] |= SS_GRABBED;

		if ( ent->client->ps.weapon == WP_ALEVEL1 )
		{
			traceEnt->client->grabExpiryTime = level.time + LEVEL1_GRAB_TIME;

			// Update the last combat time.
			ent->client->lastCombatTime = level.time + LEVEL1_GRAB_TIME;
			traceEnt->client->lastCombatTime = level.time + LEVEL1_GRAB_TIME;
		}
		else if ( ent->client->ps.weapon == WP_ALEVEL1_UPG )
		{
			traceEnt->client->grabExpiryTime = level.time + LEVEL1_GRAB_U_TIME;

			// Update the last combat time.
			ent->client->lastCombatTime = level.time + LEVEL1_GRAB_TIME;
			traceEnt->client->lastCombatTime = level.time + LEVEL1_GRAB_TIME;
		}
	}
}
/*
===========
ClientSpawn

Called every time a client is placed fresh in the world:
after the first ClientBegin, and after each respawn
Initializes all non-persistant parts of playerState
============
*/
void ClientSpawn( gentity_t *ent, gentity_t *spawn, vec3_t origin, vec3_t angles )
{
  int                 index;
  vec3_t              spawn_origin, spawn_angles;
  gclient_t           *client;
  int                 i;
  clientPersistant_t  saved;
  clientSession_t     savedSess;
  int                 persistant[ MAX_PERSISTANT ];
  gentity_t           *spawnPoint = NULL;
  int                 flags;
  int                 savedPing;
  int                 teamLocal;
  int                 eventSequence;
  char                userinfo[ MAX_INFO_STRING ];
  vec3_t              up = { 0.0f, 0.0f, 1.0f };
  int                 maxAmmo, maxClips;
  weapon_t            weapon;


  index = ent - g_entities;
  client = ent->client;

  teamLocal = client->pers.teamSelection;

  // only start client if chosen a class and joined a team
  if( client->pers.classSelection == PCL_NONE && teamLocal == TEAM_NONE )
    client->sess.spectatorState = SPECTATOR_FREE;
  else if( client->pers.classSelection == PCL_NONE )
    client->sess.spectatorState = SPECTATOR_LOCKED;

  if( origin != NULL )
    VectorCopy( origin, spawn_origin );

  if( angles != NULL )
    VectorCopy( angles, spawn_angles );

  // find a spawn point
  // do it before setting health back up, so farthest
  // ranging doesn't count this client
  if( client->sess.spectatorState != SPECTATOR_NOT )
  {
    if( teamLocal == TEAM_NONE )
      spawnPoint = SelectSpectatorSpawnPoint( spawn_origin, spawn_angles );
    else if( teamLocal == TEAM_ALIENS )
      spawnPoint = SelectAlienLockSpawnPoint( spawn_origin, spawn_angles );
    else if( teamLocal == TEAM_HUMANS )
      spawnPoint = SelectHumanLockSpawnPoint( spawn_origin, spawn_angles );
  }
  else
  {
    if( spawn == NULL )
    {
      G_Error( "ClientSpawn: spawn is NULL\n" );
      return;
    }

    spawnPoint = spawn;

    if( ent != spawn )
    {
      //start spawn animation on spawnPoint
      G_SetBuildableAnim( spawnPoint, BANIM_SPAWN1, qtrue );

      if( spawnPoint->buildableTeam == TEAM_ALIENS )
        spawnPoint->clientSpawnTime = ALIEN_SPAWN_REPEAT_TIME;
      else if( spawnPoint->buildableTeam == TEAM_HUMANS )
        spawnPoint->clientSpawnTime = HUMAN_SPAWN_REPEAT_TIME;
    }
  }

  // toggle the teleport bit so the client knows to not lerp
  flags = ent->client->ps.eFlags & ( EF_TELEPORT_BIT | EF_VOTED | EF_TEAMVOTED );
  flags ^= EF_TELEPORT_BIT;
  G_UnlaggedClear( ent );

  // clear everything but the persistant data

  saved = client->pers;
  savedSess = client->sess;
  savedPing = client->ps.ping;

  for( i = 0; i < MAX_PERSISTANT; i++ )
    persistant[ i ] = client->ps.persistant[ i ];

  eventSequence = client->ps.eventSequence;
  memset( client, 0, sizeof( *client ) );

  client->pers = saved;
  client->sess = savedSess;
  client->ps.ping = savedPing;
  client->lastkilled_client = -1;

  for( i = 0; i < MAX_PERSISTANT; i++ )
    client->ps.persistant[ i ] = persistant[ i ];

  client->ps.eventSequence = eventSequence;

  // increment the spawncount so the client will detect the respawn
  client->ps.persistant[ PERS_SPAWN_COUNT ]++;
  client->ps.persistant[ PERS_SPECSTATE ] = client->sess.spectatorState;

  client->airOutTime = level.time + 12000;

  trap_GetUserinfo( index, userinfo, sizeof( userinfo ) );
  client->ps.eFlags = flags;

  //Com_Printf( "ent->client->pers->pclass = %i\n", ent->client->pers.classSelection );

  ent->s.groundEntityNum = ENTITYNUM_NONE;
  ent->client = &level.clients[ index ];
  ent->takedamage = qtrue;
  ent->inuse = qtrue;
  ent->classname = "player";
  ent->r.contents = CONTENTS_BODY;
  ent->clipmask = MASK_PLAYERSOLID;
  ent->die = player_die;
  ent->waterlevel = 0;
  ent->watertype = 0;
  ent->flags = 0;

  // calculate each client's acceleration
  ent->evaluateAcceleration = qtrue;

  client->ps.stats[ STAT_WEAPONS ] = 0;
  client->ps.stats[ STAT_WEAPONS2 ] = 0;
  client->ps.stats[ STAT_SLOTS ] = 0;

  client->ps.eFlags = flags;
  client->ps.clientNum = index;

  BG_ClassBoundingBox( ent->client->pers.classSelection, ent->r.mins, ent->r.maxs, NULL, NULL, NULL );

  if( client->sess.spectatorState == SPECTATOR_NOT )
    client->pers.maxHealth = client->ps.stats[ STAT_MAX_HEALTH ] =
      BG_Class( ent->client->pers.classSelection )->health;
  else
    client->pers.maxHealth = client->ps.stats[ STAT_MAX_HEALTH ] = 100;

  // clear entity values
  if( ent->client->pers.classSelection == PCL_HUMAN )
  {
    BG_AddWeaponToInventory( WP_BLASTER, client->ps.stats );
    BG_AddUpgradeToInventory( UP_MEDKIT, client->ps.stats );
    weapon = client->pers.humanItemSelection;
  }
  else if( client->sess.spectatorState == SPECTATOR_NOT )
    weapon = BG_Class( ent->client->pers.classSelection )->startWeapon;
  else
    weapon = WP_NONE;

  maxAmmo = BG_Weapon( weapon )->maxAmmo;
  maxClips = BG_Weapon( weapon )->maxClips;
  BG_AddWeaponToInventory( weapon, client->ps.stats );
  client->ps.ammo = maxAmmo;
  client->ps.clips = maxClips;

  ent->client->ps.stats[ STAT_CLASS ] = ent->client->pers.classSelection;
  ent->client->ps.stats[ STAT_TEAM ] = ent->client->pers.teamSelection;

  ent->client->ps.stats[ STAT_BUILDABLE ] = BA_NONE;
  ent->client->ps.stats[ STAT_STATE ] = 0;
  VectorSet( ent->client->ps.grapplePoint, 0.0f, 0.0f, 1.0f );

  // health will count down towards max_health
  ent->health = client->ps.stats[ STAT_HEALTH ] = client->ps.stats[ STAT_MAX_HEALTH ]; //* 1.25;

  //if evolving scale health
  if( ent == spawn )
  {
    ent->health *= ent->client->pers.evolveHealthFraction;
    client->ps.stats[ STAT_HEALTH ] *= ent->client->pers.evolveHealthFraction;
  }

  //clear the credits array
  for( i = 0; i < MAX_CLIENTS; i++ )
    ent->credits[ i ] = 0;

  client->ps.stats[ STAT_STAMINA ] = MAX_STAMINA;

  G_SetOrigin( ent, spawn_origin );
  VectorCopy( spawn_origin, client->ps.origin );

#define UP_VEL  150.0f
#define F_VEL   50.0f

  //give aliens some spawn velocity
  if( client->sess.spectatorState == SPECTATOR_NOT &&
      client->ps.stats[ STAT_TEAM ] == TEAM_ALIENS )
  {
    if( ent == spawn )
    {
      //evolution particle system
      G_AddPredictableEvent( ent, EV_ALIEN_EVOLVE, DirToByte( up ) );
    }
    else
    {
      spawn_angles[ YAW ] += 180.0f;
      AngleNormalize360( spawn_angles[ YAW ] );

      if( spawnPoint->s.origin2[ 2 ] > 0.0f )
      {
        vec3_t  forward, dir;

        AngleVectors( spawn_angles, forward, NULL, NULL );
        VectorScale( forward, F_VEL, forward );
        VectorAdd( spawnPoint->s.origin2, forward, dir );
        VectorNormalize( dir );

        VectorScale( dir, UP_VEL, client->ps.velocity );
      }

      G_AddPredictableEvent( ent, EV_PLAYER_RESPAWN, 0 );
    }
  }
  else if( client->sess.spectatorState == SPECTATOR_NOT &&
           client->ps.stats[ STAT_TEAM ] == TEAM_HUMANS )
  {
    spawn_angles[ YAW ] += 180.0f;
    AngleNormalize360( spawn_angles[ YAW ] );
  }

  // the respawned flag will be cleared after the attack and jump keys come up
  client->ps.pm_flags |= PMF_RESPAWNED;

  trap_GetUsercmd( client - level.clients, &ent->client->pers.cmd );
  SetClientViewAngle( ent, spawn_angles );

  if( !( client->sess.spectatorState != SPECTATOR_NOT ) )
  {
    trap_LinkEntity( ent );

    // force the base weapon up
    client->ps.weapon = WP_NONE;
    client->ps.weaponstate = WEAPON_READY;
  }

  // don't allow full run speed for a bit
  client->ps.pm_flags |= PMF_TIME_KNOCKBACK;
  client->ps.pm_time = 100;

  client->respawnTime = level.time;
  client->lastKillTime = level.time;

  client->inactivityTime = level.time + g_inactivity.integer * 1000;
  client->latched_buttons = 0;

  // set default animations
  client->ps.torsoAnim = TORSO_STAND;
  client->ps.legsAnim = LEGS_IDLE;

  if( level.intermissiontime )
    MoveClientToIntermission( ent );
  else
  {
    // fire the targets of the spawn point
    if( !spawn )
      G_UseTargets( spawnPoint, ent );

    // select the highest weapon number available, after any
    // spawn given items have fired
    client->ps.weapon = 1;

    for( i = WP_NUM_WEAPONS - 1; i > 0 ; i-- )
    {
      if( BG_InventoryContainsWeapon( i, client->ps.stats ) )
      {
        client->ps.weapon = i;
        break;
      }
    }
  }

  // run a client frame to drop exactly to the floor,
  // initialize animations and other things
  client->ps.commandTime = level.time - 100;
  ent->client->pers.cmd.serverTime = level.time;
  ClientThink( ent-g_entities );

  // positively link the client, even if the command times are weird
  if( client->sess.spectatorState == SPECTATOR_NOT )
  {
    BG_PlayerStateToEntityState( &client->ps, &ent->s, qtrue );
    VectorCopy( ent->client->ps.origin, ent->r.currentOrigin );
    trap_LinkEntity( ent );
  }

  // must do this here so the number of active clients is calculated
  CalculateRanks( );

  // run the presend to set anything else
  ClientEndFrame( ent );

  // clear entity state values
  BG_PlayerStateToEntityState( &client->ps, &ent->s, qtrue );
}
Exemplo n.º 22
0
void WP_GrenadeBlow(gentity_t*self)
{
	if(Q_stricmp(self->classname,"emp_grenade")==0
		||Q_stricmp(self->classname,"cryoban_grenade")==0
		||Q_stricmp(self->classname,"flash_grenade")==0)
	{
		vec3_t	dir={0,0,1};
		int entitys[1024];
		vec3_t mins,maxs,v;
		int num=0,i=0,dist=0,mpDamage=7;
		int e=0;
		gentity_t*ent;
		for ( i = 0 ; i < 3 ; i++ ) 
		{
			mins[i] = self->r.currentOrigin[i] - TD_SPLASH_RAD / 2;
			maxs[i] = self->r.currentOrigin[i] + TD_SPLASH_RAD / 2;
		}
		num = trap_EntitiesInBox(mins,maxs,entitys,MAX_GENTITIES);
		for ( i = 0 ; i < num ; i++ ) 
		{
			ent = &g_entities[entitys[ i ]];
			if (ent == self)
				continue;
			if (!ent->takedamage)
				continue;
			if(!ent->inuse || !ent->client)
				continue;

			// find the distance from the edge of the bounding box
			for ( e = 0 ; e < 3 ; e++ ) {
				if ( self->r.currentOrigin[e] < ent->r.absmin[e] ) {
					v[e] = ent->r.absmin[e] - self->r.currentOrigin[e];
				} else if ( self->r.currentOrigin[e] > ent->r.absmax[e] ) {
					v[e] = self->r.currentOrigin[e] - ent->r.absmax[e];
				} else {
					v[e] = 0;
				}
			}

			dist = VectorLength( v );
			if ( dist >= TD_SPLASH_RAD ) {
				continue;
			}

			if(Q_stricmp(self->classname,"cryoban_grenade") == 0)
				G_AddEvent(ent, EV_CRYOBAN, DirToByte(dir));

			if(Q_stricmp(self->classname,"emp_grenade")==0)
			{
				int shield = Q_irand(25,50);
				int ammo = Q_irand(15,30);
				G_DodgeDrain(ent, self, 15);//15 for nau
				ent->client->ps.saberAttackChainCount += mpDamage;
				if(ent->client->ps.stats[STAT_ARMOR]-shield >= 0)
					ent->client->ps.stats[STAT_ARMOR]-=shield;
				else
					ent->client->ps.stats[STAT_ARMOR]=0;

				if(ent->client->ps.ammo[weaponData[ent->client->ps.weapon].ammoIndex]-ammo >= 0)
					ent->client->ps.ammo[weaponData[ent->client->ps.weapon].ammoIndex]-=ammo;
				else
					ent->client->ps.ammo[weaponData[ent->client->ps.weapon].ammoIndex]=0;

				if(Q_stricmp(ent->classname,"item_seeker")==0||Q_stricmp(ent->classname,"item_sentry_gun")==0)
				{
					G_Damage( ent, ent, ent, NULL, NULL, 999, 0, MOD_UNKNOWN );
				}
				ent->client->ps.electrifyTime = level.time + Q_irand( 300, 800 );
			}
			else if(Q_stricmp(self->classname,"cryoban_grenade")==0)
			{
				ent->client->frozenTime = level.time+FROZEN_TIME;
				ent->client->ps.userInt3 |= (1 << FLAG_FROZEN);
				ent->client->ps.userInt1 |= LOCK_UP;
				ent->client->ps.userInt1 |= LOCK_DOWN;
				ent->client->ps.userInt1 |= LOCK_RIGHT;
				ent->client->ps.userInt1 |= LOCK_LEFT;
				ent->client->viewLockTime = level.time+FROZEN_TIME;
				ent->client->ps.legsTimer = ent->client->ps.torsoTimer=level.time+FROZEN_TIME;
				G_SetAnim(ent, NULL, SETANIM_BOTH, WeaponReadyAnim[ent->client->ps.weapon], SETANIM_FLAG_OVERRIDE | SETANIM_FLAG_HOLD, 100);
			}
			else if(Q_stricmp(self->classname,"flash_grenade")==0)
				G_AddEvent( ent, EV_FLASHGRENADE, DirToByte( dir ) );
		}
		self->s.eType = ET_GENERAL;
		if(Q_stricmp(self->classname,"emp_grenade") == 0)
			G_AddEvent( self, EV_EMPGRENADE, DirToByte( dir ) );
		else if(Q_stricmp(self->classname,"cryoban_grenade") == 0)
			G_AddEvent( self, EV_CRYOBAN_EXPLODE, DirToByte( dir ) );
		self->freeAfterEvent = qtrue;
	}
	else if(Q_stricmp(self->classname,"smoke_grenade")==0)
	{
		vec3_t	dir={0,0,1};

			G_AddEvent( self, EV_SMOKEGRENADE, DirToByte( dir ) );
		self->freeAfterEvent = qtrue;
	}
	else
	{
		self->think = G_FreeEntity;
		self->nextthink = level.time;
	}
}
Exemplo n.º 23
0
/*
================
G_MissileImpact
================
*/
void G_MissileImpact(gentity_t * ent, trace_t * trace)
{
	gentity_t      *other;
	qboolean        hitClient = qfalse;

#ifdef MISSIONPACK
	vec3_t          forward, impactpoint, bouncedir;
	int             eFlags;
#endif
	other = &g_entities[trace->entityNum];

	// check for bounce
	if(!other->takedamage && (ent->s.eFlags & (EF_BOUNCE | EF_BOUNCE_HALF)))
	{
		G_BounceMissile(ent, trace);
		G_AddEvent(ent, EV_GRENADE_BOUNCE, 0);
		return;
	}

	if(ent->s.weapon == WP_FLAK_CANNON && ent->s.eType == ET_PROJECTILE2)
	{
		G_ExplodeIntoNails(ent);
		return;
	}

#ifdef MISSIONPACK
	if(other->takedamage)
	{
		if(ent->s.weapon != WP_PROX_LAUNCHER)
		{
			if(other->client && other->client->invulnerabilityTime > level.time)
			{
				//
				VectorCopy(ent->s.pos.trDelta, forward);
				VectorNormalize(forward);

				if(G_InvulnerabilityEffect(other, forward, ent->s.pos.trBase, impactpoint, bouncedir))
				{
					VectorCopy(bouncedir, trace->plane.normal);
					eFlags = ent->s.eFlags & EF_BOUNCE_HALF;
					ent->s.eFlags &= ~EF_BOUNCE_HALF;
					G_BounceMissile(ent, trace);
					ent->s.eFlags |= eFlags;
				}
				ent->target_ent = other;
				return;
			}
		}
	}
#endif
	// impact damage
	if(other->takedamage)
	{
		// FIXME: wrong damage direction?
		if(ent->damage)
		{
			vec3_t          velocity;

			if(LogAccuracyHit(other, &g_entities[ent->r.ownerNum]))
			{
				g_entities[ent->r.ownerNum].client->accuracy_hits++;
				hitClient = qtrue;
			}
			BG_EvaluateTrajectoryDelta(&ent->s.pos, level.time, velocity);
			if(VectorLength(velocity) == 0)
			{
				velocity[2] = 1;	// stepped on a grenade
			}

			G_Damage(other, ent, &g_entities[ent->r.ownerNum], velocity, ent->s.origin, ent->damage, 0, ent->methodOfDeath);
		}
	}

#ifdef MISSIONPACK
	if(ent->s.weapon == WP_PROX_LAUNCHER)
	{
		if(ent->s.pos.trType != TR_GRAVITY)
		{
			return;
		}

		// if it's a player, stick it on to them (flag them and remove this entity)
		if(other->s.eType == ET_PLAYER && other->health > 0)
		{
			ProximityMine_Player(ent, other);
			return;
		}

		SnapVectorTowards(trace->endpos, ent->s.pos.trBase);
		G_SetOrigin(ent, trace->endpos);
		ent->s.pos.trType = TR_STATIONARY;
		VectorClear(ent->s.pos.trDelta);

		G_AddEvent(ent, EV_PROXIMITY_MINE_STICK, trace->surfaceFlags);

		ent->think = ProximityMine_Activate;
		ent->nextthink = level.time + 2000;

		VectorToAngles(trace->plane.normal, ent->s.angles);
		ent->s.angles[0] += 90;

		// link the prox mine to the other entity
		ent->enemy = other;
		ent->die = ProximityMine_Die;
		VectorCopy(trace->plane.normal, ent->movedir);
		VectorSet(ent->r.mins, -4, -4, -4);
		VectorSet(ent->r.maxs, 4, 4, 4);
		trap_LinkEntity(ent);

		return;
	}
#endif

	if(!strcmp(ent->classname, "hook"))
	{
		gentity_t      *nent;
		vec3_t          v;

		nent = G_Spawn();
		if(other->takedamage && other->client)
		{

			G_AddEvent(nent, EV_PROJECTILE_HIT, DirToByte(trace->plane.normal));
			nent->s.otherEntityNum = other->s.number;

			ent->enemy = other;

			v[0] = other->r.currentOrigin[0] + (other->r.mins[0] + other->r.maxs[0]) * 0.5;
			v[1] = other->r.currentOrigin[1] + (other->r.mins[1] + other->r.maxs[1]) * 0.5;
			v[2] = other->r.currentOrigin[2] + (other->r.mins[2] + other->r.maxs[2]) * 0.5;

			SnapVectorTowards(v, ent->s.pos.trBase);	// save net bandwidth
		}
		else
		{
			VectorCopy(trace->endpos, v);
			G_AddEvent(nent, EV_PROJECTILE_MISS, DirToByte(trace->plane.normal));
			ent->enemy = NULL;
		}

		SnapVectorTowards(v, ent->s.pos.trBase);	// save net bandwidth

		nent->freeAfterEvent = qtrue;
		// change over to a normal entity right at the point of impact
		nent->s.eType = ET_GENERAL;
		ent->s.eType = ET_GRAPPLE;

		G_SetOrigin(ent, v);
		G_SetOrigin(nent, v);

		ent->think = Weapon_HookThink;
		ent->nextthink = level.time + FRAMETIME;

		ent->parent->client->ps.pm_flags |= PMF_GRAPPLE_PULL;
		VectorCopy(ent->r.currentOrigin, ent->parent->client->ps.grapplePoint);

		trap_LinkEntity(ent);
		trap_LinkEntity(nent);

		return;
	}

	// is it cheaper in bandwidth to just remove this ent and create a new
	// one, rather than changing the missile into the explosion?

	if(other->takedamage && other->client)
	{
		G_AddEvent(ent, EV_PROJECTILE_HIT, DirToByte(trace->plane.normal));
		ent->s.otherEntityNum = other->s.number;
	}
	else if(trace->surfaceFlags & SURF_METALSTEPS)
	{
		G_AddEvent(ent, EV_PROJECTILE_MISS_METAL, DirToByte(trace->plane.normal));
	}
	else
	{
		G_AddEvent(ent, EV_PROJECTILE_MISS, DirToByte(trace->plane.normal));
	}

	ent->freeAfterEvent = qtrue;

	// change over to a normal entity right at the point of impact
	ent->s.eType = ET_GENERAL;

	SnapVectorTowards(trace->endpos, ent->s.pos.trBase);	// save net bandwidth

	G_SetOrigin(ent, trace->endpos);

	// splash damage (doesn't apply to person directly hit)
	if(ent->splashDamage)
	{
		if(G_RadiusDamage(trace->endpos, ent->parent, ent->splashDamage, ent->splashRadius, other, ent->splashMethodOfDeath))
		{
			if(!hitClient)
			{
				g_entities[ent->r.ownerNum].client->accuracy_hits++;
			}
		}
	}

	trap_LinkEntity(ent);
}
Exemplo n.º 24
0
/*
================
G_MissileImpact
================
*/
void G_MissileImpact( gentity_t *ent, trace_t *trace ) {
	gentity_t		*other;
	qboolean		hitPlayer = qfalse;
#if defined MISSIONPACK && !defined TURTLEARENA // POWERS
	vec3_t			forward, impactpoint, bouncedir;
	int				eFlags;
#endif
#ifdef TA_WEAPSYS
	qboolean damagedOther = qfalse;
#endif
	other = &g_entities[trace->entityNum];

#if defined MISSIONPACK && !defined TURTLEARENA // POWERS
	if ( other->takedamage ) {
#ifdef TA_WEAPSYS
		if ( !bg_projectileinfo[ent->s.weapon].stickOnImpact )
#else
		if ( ent->s.weapon != WP_PROX_LAUNCHER )
#endif
		{
			if ( other->player && other->player->invulnerabilityTime > level.time ) {
				//
				VectorCopy( ent->s.pos.trDelta, forward );
				VectorNormalize( forward );
				if (G_InvulnerabilityEffect( other, forward, ent->s.pos.trBase, impactpoint, bouncedir )) {
					VectorCopy( bouncedir, trace->plane.normal );
					eFlags = ent->s.eFlags & EF_BOUNCE_HALF;
					ent->s.eFlags &= ~EF_BOUNCE_HALF;
					G_BounceMissile( ent, trace );
					ent->s.eFlags |= eFlags;
				}
				ent->target_ent = other;
				return;
			}
		}
	}
#endif
	// impact damage
	if (other->takedamage
#ifdef TA_WEAPSYS // stickOnImpact only damages once
		&& !(ent->count & 2)
#endif
		)
	{
		// FIXME: wrong damage direction?
		if ( ent->damage ) {
			vec3_t	velocity;

			if( LogAccuracyHit( other, &g_entities[ent->r.ownerNum] ) ) {
				g_entities[ent->r.ownerNum].player->accuracy_hits++;
				hitPlayer = qtrue;
			}
			BG_EvaluateTrajectoryDelta( &ent->s.pos, level.time, velocity );
			if ( VectorLength( velocity ) == 0 ) {
#ifdef IOQ3ZTM
				VectorCopy(trace->plane.normal, velocity);
#else
				velocity[2] = 1;	// stepped on a grenade
#endif
			}
#ifdef TA_WEAPSYS
			damagedOther = G_Damage (other, ent, &g_entities[ent->r.ownerNum], velocity,
				ent->s.origin, ent->damage,
				0, ent->methodOfDeath);
#else
			G_Damage (other, ent, &g_entities[ent->r.ownerNum], velocity,
				ent->s.origin, ent->damage, 
				0, ent->methodOfDeath);
#endif
		}
	}

	// check for bounce
	if (
#ifdef TA_WEAPSYS
		!damagedOther &&
#else
		!other->takedamage &&
#endif
		( ent->s.eFlags & ( EF_BOUNCE | EF_BOUNCE_HALF ) ) ) {
		G_BounceMissile( ent, trace );
#ifdef TA_WEAPSYS // Bounce missiles
		// Die on Nth bounce
		if (ent->s.modelindex2 > 0)
		{
			ent->s.modelindex2--;
			if (ent->s.modelindex2 == 0)
			{
				// Kill missile
				G_ExplodeMissile( ent );
				return;
			}
		}
		G_AddEvent( ent, EV_PROJECTILE_BOUNCE, DirToByte( trace->plane.normal ) );
		ent->s.time2 = trace->surfaceFlags; // surface
#else
		G_AddEvent( ent, EV_GRENADE_BOUNCE, 0 );
#endif
		return;
	}

#ifdef TA_WEAPSYS
	if (bg_projectileinfo[ent->s.weapon].stickOnImpact != PSOI_NONE) {
		vec3_t dir;

#ifndef TURTLEARENA
		// if it's a player, stick it on to them (flag them and remove this entity)
		if( bg_projectileinfo[ent->s.weapon].explosionType == PE_PROX &&
			other->s.eType == ET_PLAYER && other->health > 0 )
		{
			ProximityMine_Player( ent, other );
			return;
		}
#endif

		if (ent->count & 2) {
			// Already stuck to wall
			return;
		}
		ent->count |= 2;

		// Don't stick to players or obelisk
		if (other->s.eType == ET_PLAYER
#ifdef MISSIONPACK
			|| (other->pain == ObeliskPain)
#endif
			)
		{
			goto missileExplode;
		}

		// Don't stick to the entity that this missile just killed or other missiles
		if ((damagedOther && other->health <= 0) || other->s.eType == ET_MISSILE)
		{
			// Don't remove projectile if it doesn't explode.
			if (bg_projectileinfo[ent->s.weapon].explosionType == PE_NONE)
			{
				ent->s.pos.trType = TR_GRAVITY;
				ent->count &= ~2;
				return;
			}
			else
			{
				goto missileExplode;
			}
		}

		if (bg_projectileinfo[ent->s.weapon].shootable)
			VectorMA(trace->endpos, -8, trace->plane.normal, trace->endpos);

		SnapVectorTowards( trace->endpos, ent->s.pos.trBase );
		G_SetOrigin( ent, trace->endpos );

		if (bg_projectileinfo[ent->s.weapon].stickOnImpact == PSOI_KEEP_ANGLES) {
#if 0
			// convert direction of travel into axis
			if ( VectorNormalize2( ent->s.pos.trDelta, dir ) == 0 ) {
				dir[2] = 1;
			}

			// Set the angles
			vectoangles( dir, ent->s.angles );
#else
			VectorCopy(trace->plane.normal, dir);
#endif
		} else {
			VectorCopy(trace->plane.normal, dir);
			vectoangles( dir, ent->s.angles );

			switch (bg_projectileinfo[ent->s.weapon].stickOnImpact)
			{
				case PSOI_ANGLE_270:
					ent->s.angles[0] += 270;
					break;
				case PSOI_ANGLE_180:
					ent->s.angles[0] += 180;
					break;
				case PSOI_ANGLE_90:
					// Maybe this is good for prox mines, but doesn't look good on my
					//   rocket or shuirkens...
					ent->s.angles[0] += 90;
					break;
				case PSOI_ANGLE_0:
					break;
			}
		}

		// Save direction
		VectorCopy(dir, ent->s.angles2);

		ent->s.pos.trType = TR_STATIONARY;
		VectorClear( ent->s.pos.trDelta );

		G_AddEvent( ent, EV_PROJECTILE_STICK, DirToByte(trace->plane.normal) );
		ent->s.time2 = trace->surfaceFlags; // surface

		if (bg_projectileinfo[ent->s.weapon].explosionType == PE_PROX)
		{
			// When a BREAKABLE ET_MOVER is killed it drops the projectiles stuck to it,
			//   so don't setup the prox mine when it impact a surface if it already hit been setup.
			if (ent->die != ProximityMine_Die)
			{
				ent->think = ProximityMine_Activate;
				ent->nextthink = level.time + 2000;
				ent->die = ProximityMine_Die;
			}
		}
		else
		{
			ent->die = G_Missile_Die;
		}

		// link the prox mine to the other entity
		ent->enemy = other;
		VectorCopy(dir, ent->movedir);
		VectorSet(ent->s.mins, -4, -4, -4);
		VectorSet(ent->s.maxs, 4, 4, 4);
		trap_LinkEntity(ent);

		return;
	}
#elif defined MISSIONPACK
	if( ent->s.weapon == WP_PROX_LAUNCHER ) {
		if( ent->s.pos.trType != TR_GRAVITY ) {
			return;
		}

		// if it's a player, stick it on to them (flag them and remove this entity)
		if( other->s.eType == ET_PLAYER && other->health > 0 ) {
			ProximityMine_Player( ent, other );
			return;
		}

		SnapVectorTowards( trace->endpos, ent->s.pos.trBase );
		G_SetOrigin( ent, trace->endpos );
		ent->s.pos.trType = TR_STATIONARY;
		VectorClear( ent->s.pos.trDelta );

		G_AddEvent( ent, EV_PROXIMITY_MINE_STICK, trace->surfaceFlags );

		ent->think = ProximityMine_Activate;
		ent->nextthink = level.time + 2000;

		vectoangles( trace->plane.normal, ent->s.angles );
		ent->s.angles[0] += 90;

		// link the prox mine to the other entity
		ent->enemy = other;
		ent->die = ProximityMine_Die;
		VectorCopy(trace->plane.normal, ent->movedir);
		VectorSet(ent->s.mins, -4, -4, -4);
		VectorSet(ent->s.maxs, 4, 4, 4);
		trap_LinkEntity(ent);

		return;
	}
#endif

#ifdef TA_WEAPSYS
	if (bg_projectileinfo[ent->s.weapon].grappling)
#else
	if (!strcmp(ent->classname, "hook"))
#endif
	{
		gentity_t *nent;
		vec3_t v;

		nent = G_Spawn();
		if ( other->takedamage && other->player ) {

			G_AddEvent( nent, EV_MISSILE_HIT, DirToByte( trace->plane.normal ) );
			nent->s.otherEntityNum = other->s.number;

			v[0] = other->r.currentOrigin[0] + (other->s.mins[0] + other->s.maxs[0]) * 0.5;
			v[1] = other->r.currentOrigin[1] + (other->s.mins[1] + other->s.maxs[1]) * 0.5;
			v[2] = other->r.currentOrigin[2] + (other->s.mins[2] + other->s.maxs[2]) * 0.5;
		} else {
			VectorCopy(trace->endpos, v);
			G_AddEvent( nent, EV_MISSILE_MISS, DirToByte( trace->plane.normal ) );
		}
#ifdef IOQ3ZTM // IOQ3BUGFIX: Fix grapple wallmark/death-effect/debris (only tested with TA_WEAPSYS...)
		nent->s.weapon = ent->s.weapon;
#endif
#ifdef TA_WEAPSYS
		if (ent->parent)
			nent->s.playerNum = ent->parent->s.number;
		else
			nent->s.playerNum = ENTITYNUM_NONE;
#endif

		nent->s.weapon = ent->s.weapon;

		ent->enemy = other;
		ent->s.groundEntityNum = other->s.number;

		SnapVectorTowards( v, ent->s.pos.trBase );	// save net bandwidth

		nent->freeAfterEvent = qtrue;
		// change over to a normal entity right at the point of impact
		nent->s.eType = ET_GENERAL;
		ent->s.eType = ET_GRAPPLE;

		G_SetOrigin( ent, v );
		G_SetOrigin( nent, v );

		ent->think = Weapon_HookThink;
		ent->nextthink = level.time + FRAMETIME;

		ent->parent->player->ps.pm_flags |= PMF_GRAPPLE_PULL;
		VectorCopy( ent->r.currentOrigin, ent->parent->player->ps.grapplePoint);

		trap_LinkEntity( ent );
		trap_LinkEntity( nent );

#ifdef TA_WEAPSYS
		// Don't grapple to the entity if you just killed it.
		if (damagedOther && other->health <= 0)
		{
			Weapon_HookFree(ent);
		}
#endif

		return;
	}

#ifdef TA_WEAPSYS
missileExplode:
#endif

	// is it cheaper in bandwidth to just remove this ent and create a new
	// one, rather than changing the missile into the explosion?

	if ( other->takedamage && other->player ) {
		G_AddEvent( ent, EV_MISSILE_HIT, DirToByte( trace->plane.normal ) );
		ent->s.otherEntityNum = other->s.number;
	} else if( trace->surfaceFlags & SURF_METALSTEPS ) {
		G_AddEvent( ent, EV_MISSILE_MISS_METAL, DirToByte( trace->plane.normal ) );
	} else {
		G_AddEvent( ent, EV_MISSILE_MISS, DirToByte( trace->plane.normal ) );
	}
#ifdef TA_WEAPSYS
	if (ent->parent)
		ent->s.playerNum = ent->parent->s.number;
	else
		ent->s.playerNum = ENTITYNUM_NONE;
#endif

	ent->freeAfterEvent = qtrue;

	// change over to a normal entity right at the point of impact
#ifndef TA_WEAPSYS // Must be after G_RadiusDamage
	ent->s.eType = ET_GENERAL;
#endif

	SnapVectorTowards( trace->endpos, ent->s.pos.trBase );	// save net bandwidth

	G_SetOrigin( ent, trace->endpos );

	// splash damage (doesn't apply to person directly hit)
	if ( ent->splashDamage ) {
#ifdef TA_WEAPSYS
		if( G_RadiusDamage( trace->endpos, ent, ent->parent, ent->splashDamage, ent->splashRadius, 
			other, ent->splashMethodOfDeath ) )
#else
		if( G_RadiusDamage( trace->endpos, ent->parent, ent->splashDamage, ent->splashRadius, 
			other, ent->splashMethodOfDeath ) )
#endif
		{
			if( !hitPlayer ) {
				g_entities[ent->r.ownerNum].player->accuracy_hits++;
			}
		}
	}

#ifdef TA_WEAPSYS
	ent->s.eType = ET_GENERAL;
#endif

	trap_LinkEntity( ent );
}
Exemplo n.º 25
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;
	}
}
Exemplo n.º 26
0
// 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;
}
Exemplo n.º 27
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( g_muzzle, LIGHTNING_RANGE, forward, end );

		trap_Trace( &tr, g_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( g_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( g_muzzle, impactpoint, bouncedir, end );
					VectorCopy( impactpoint, g_muzzle );
					VectorSubtract( end, impactpoint, forward );
					VectorNormalize(forward);
					// the player can hit him/herself with the bounced lightning
					passent = ENTITYNUM_NONE;
				}
				else {
					VectorCopy( tr.endpos, g_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;
	}
}
Exemplo n.º 28
0
/*
================
G_ExplodeMissile

Explode a missile without an impact
================
*/
void G_ExplodeMissile( gentity_t *ent ) {
	vec3_t		dir;
	vec3_t		origin;

#ifdef TA_WEAPSYS
	if (bg_projectileinfo[ent->s.weapon].grappling)
	{
		Weapon_HookFree(ent);
		return;
	}

	if (bg_projectileinfo[ent->s.weapon].explosionType == PE_NONE)
	{
		G_FreeEntity(ent);
		return;
	}
#endif

	BG_EvaluateTrajectory( &ent->s.pos, level.time, origin );
	SnapVector( origin );
	G_SetOrigin( ent, origin );

#ifdef TA_WEAPSYS
	// Missile impacted a surface
	if (ent->count & 2)
	{
		VectorCopy(ent->s.angles2, dir);
	}
	else
	{
#endif
	// we don't have a valid direction, so just point straight up
	dir[0] = dir[1] = 0;
	dir[2] = 1;
#ifdef TA_WEAPSYS
	}
#endif

#ifndef TA_WEAPSYS // Must be after G_RadiusDamage
	ent->s.eType = ET_GENERAL;
#endif
	G_AddEvent( ent, EV_MISSILE_MISS, DirToByte( dir ) );
#ifdef TA_WEAPSYS
	if (ent->parent)
		ent->s.playerNum = ent->parent->s.number;
	else
		ent->s.playerNum = ENTITYNUM_NONE;
#endif

	ent->freeAfterEvent = qtrue;

	// splash damage
	if ( ent->splashDamage ) {
#ifdef TA_WEAPSYS
		if( G_RadiusDamage( ent->r.currentOrigin, ent, ent->parent, ent->splashDamage, ent->splashRadius, ent
			, ent->splashMethodOfDeath ) )
#else
		if( G_RadiusDamage( ent->r.currentOrigin, ent->parent, ent->splashDamage, ent->splashRadius, ent
			, ent->splashMethodOfDeath ) )
#endif
		{
			g_entities[ent->r.ownerNum].player->accuracy_hits++;
		}
	}

#ifdef TA_WEAPSYS
	ent->s.eType = ET_GENERAL;
#endif

	trap_LinkEntity( ent );
}
Exemplo n.º 29
0
/*
* W_Fire_Instagun_Strong
*/
void W_Fire_Instagun( edict_t *self, vec3_t start, vec3_t dir, float damage, int knockback,
					  int stun, int radius, int range, int mod, int timeDelta ) {
	vec3_t from, end;
	trace_t	tr;
	edict_t	*ignore, *event, *hit;
	int hit_movetype;
	int mask;
	bool missed = true;
	int dmgflags = 0;

	if( GS_Instagib() ) {
		damage = 9999;
	}

	VectorMA( start, range, dir, end );
	VectorCopy( start, from );
	ignore = self;
	mask = MASK_SHOT;
	if( GS_RaceGametype() ) {
		mask = MASK_SOLID;
	}
	tr.ent = -1;
	while( ignore ) {
		G_Trace4D( &tr, from, NULL, NULL, end, ignore, mask, timeDelta );
		VectorCopy( tr.endpos, from );
		ignore = NULL;
		if( tr.ent == -1 ) {
			break;
		}

		// allow trail to go through SOLID_BBOX entities (players, gibs, etc)
		hit = &game.edicts[tr.ent];
		hit_movetype = hit->movetype; // backup the original movetype as the entity may "die"

		if( !ISBRUSHMODEL( hit->s.modelindex ) ) {
			ignore = hit;
		}

		if( ( hit != self ) && ( hit->takedamage ) ) {
			G_Damage( hit, self, self, dir, dir, tr.endpos, damage, knockback, stun, dmgflags, mod );

			// spawn a impact event on each damaged ent
			event = G_SpawnEvent( EV_INSTA_EXPLOSION, DirToByte( tr.plane.normal ), tr.endpos );
			event->s.ownerNum = ENTNUM( self );
			event->s.firemode = FIRE_MODE_STRONG;
			if( hit->r.client ) {
				missed = false;
			}
		}

		// some entity was touched
		if( hit == world
			|| hit_movetype == MOVETYPE_NONE
			|| hit_movetype == MOVETYPE_PUSH ) {
			if( g_instajump->integer && self && self->r.client ) {
				// create a temporary inflictor entity
				edict_t *inflictor;

				inflictor = G_Spawn();
				inflictor->s.solid = SOLID_NOT;
				inflictor->timeDelta = 0;
				VectorCopy( tr.endpos, inflictor->s.origin );
				inflictor->s.ownerNum = ENTNUM( self );
				inflictor->projectileInfo.maxDamage = 0;
				inflictor->projectileInfo.minDamage = 0;
				inflictor->projectileInfo.maxKnockback = knockback;
				inflictor->projectileInfo.minKnockback = 1;
				inflictor->projectileInfo.stun = 0;
				inflictor->projectileInfo.radius = radius;

				G_RadiusDamage( inflictor, self, &tr.plane, NULL, mod );

				G_FreeEdict( inflictor );
			}
			break;
		}
	}

	if( missed && self->r.client ) {
		G_AwardPlayerMissedElectrobolt( self, mod );
	}

	// send the weapon fire effect
	event = G_SpawnEvent( EV_INSTATRAIL, ENTNUM( self ), start );
	VectorScale( dir, 1024, event->s.origin2 );
}
Exemplo n.º 30
0
void
weapon_railgun_fire(Gentity *ent)
{
	Vec3 end;
#ifdef MISSIONPACK
	Vec3 impactpoint, bouncedir;
#endif
	Trace trace;
	Gentity *tent;
	Gentity *traceEnt;
	int damage;
	int i;
	int hits;
	int unlinked;
	int passent;
	Gentity *unlinkedEntities[MAX_RAIL_HITS];

	damage = 100 * s_quadFactor;

	saddv3 (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){
			if(LogAccuracyHit(traceEnt, ent))
				hits++;
			G_Damage (traceEnt, ent, ent, forward, trace.endpos,
				damage, 0,
				MOD_RAILGUN);
		}
		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 */
	snapv3Towards(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;

	copyv3(muzzle, tent->s.origin2);
	/* move origin a bit to come closer to the drawn gun muzzle */
	saddv3(tent->s.origin2, 4, right, tent->s.origin2);
	saddv3(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++;
	}

}