Exemple #1
0
static void FireLasgun( gentity_t *self )
{
	// TODO: Merge this with other *Fire functions

	trace_t   tr;
	vec3_t    end;
	gentity_t *target;

	VectorMA( muzzle, 8192 * 16, forward, end );

	G_UnlaggedOn( self, muzzle, 8192 * 16 );
	trap_Trace( &tr, muzzle, NULL, NULL, end, self->s.number, MASK_SHOT );
	G_UnlaggedOff();

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

	target = &g_entities[ tr.entityNum ];

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

	SendRangedHitEvent( self, target, &tr );

	if ( target->takedamage )
	{
		G_Damage( target, self, self, forward, tr.endpos, LASGUN_DAMAGE, 0, MOD_LASGUN );
	}
}
Exemple #2
0
static void SendRangedHitEvent( gentity_t *attacker, gentity_t *target, trace_t *tr )
{
	gentity_t *event;

	// snap the endpos to integers, but nudged towards the line
	G_SnapVectorTowards( tr->endpos, muzzle );

	if ( target->takedamage && ( target->s.eType == ET_BUILDABLE || target->s.eType == ET_PLAYER ) )
	{
		event = G_NewTempEntity( tr->endpos, EV_WEAPON_HIT_ENTITY );
	}
	else
	{
		event = G_NewTempEntity( tr->endpos, EV_WEAPON_HIT_ENVIRONMENT );
	}

	// normal
	event->s.eventParm = DirToByte( tr->plane.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;
}
static void FireMassdriver( gentity_t *self )
{
	// TODO: Merge this with other *Fire functions

	trace_t   tr;
	vec3_t    end;
	gentity_t *target;

	VectorMA( muzzle, 8192.0f * 16.0f, forward, end );

	G_UnlaggedOn( self, muzzle, 8192.0f * 16.0f );
	trap_Trace( &tr, muzzle, nullptr, nullptr, end, self->s.number, MASK_SHOT, 0 );
	G_UnlaggedOff();

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

	target = &g_entities[ tr.entityNum ];

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

	SendRangedHitEvent( self, target, &tr );

	if ( target->takedamage )
	{
		G_Damage( target, self, self, forward, tr.endpos, MDRIVER_DMG, DAMAGE_KNOCKBACK,
		          MOD_MDRIVER );
	}
}
static void FireLasgun( gentity_t *self )
{
	// TODO: Merge this with other *Fire functions

	trace_t   tr;
	vec3_t    end;
	gentity_t *target;

	VectorMA( muzzle, 8192 * 16, forward, end );

	G_UnlaggedOn( self, muzzle, 8192 * 16 );
	trap_Trace( &tr, muzzle, nullptr, nullptr, end, self->s.number, MASK_SHOT, 0 );
	G_UnlaggedOff();

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

	target = &g_entities[ tr.entityNum ];

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

	SendRangedHitEvent( self, target, &tr );

	target->entity->Damage((float)LASGUN_DAMAGE, self, Vec3::Load(tr.endpos),
	                       Vec3::Load(forward), 0, (meansOfDeath_t)MOD_LASGUN);
}
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 );
	}
}