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 ); } }
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 ); } }