/* * W_Touch_Plasma */ static void W_Touch_Plasma( edict_t *ent, edict_t *other, cplane_t *plane, int surfFlags ) { int hitType; vec3_t dir; if( surfFlags & SURF_NOIMPACT ) { G_FreeEdict( ent ); return; } hitType = G_Projectile_HitStyle( ent, other ); if( hitType == PROJECTILE_TOUCH_NOT ) return; if( other->takedamage ) { VectorNormalize2( ent->velocity, dir ); if( hitType == PROJECTILE_TOUCH_DIRECTSPLASH ) // use hybrid direction from splash and projectile { G_SplashFrac4D( ENTNUM( other ), ent->s.origin, ent->projectileInfo.radius, dir, NULL, NULL, ent->timeDelta ); } else { VectorNormalize2( ent->velocity, dir ); } G_Damage( other, ent, ent->r.owner, dir, ent->velocity, ent->s.origin, ent->projectileInfo.maxDamage, ent->projectileInfo.maxKnockback, ent->projectileInfo.stun, DAMAGE_KNOCKBACK_SOFT, ent->style ); } W_Plasma_Explosion( ent, other, plane, surfFlags ); }
/* * W_Touch_Rocket */ static void W_Touch_Rocket( edict_t *ent, edict_t *other, cplane_t *plane, int surfFlags ) { int mod_splash; vec3_t dir; int hitType; if( surfFlags & SURF_NOIMPACT ) { G_FreeEdict( ent ); return; } hitType = G_Projectile_HitStyle( ent, other ); if( hitType == PROJECTILE_TOUCH_NOT ) { return; } if( other->takedamage ) { int directHitDamage = ent->projectileInfo.maxDamage; VectorNormalize2( ent->velocity, dir ); if( hitType == PROJECTILE_TOUCH_DIRECTSPLASH ) { // use hybrid direction from splash and projectile G_SplashFrac4D( ENTNUM( other ), ent->s.origin, ent->projectileInfo.radius, dir, NULL, NULL, ent->timeDelta ); } else { VectorNormalize2( ent->velocity, dir ); if( hitType == PROJECTILE_TOUCH_DIRECTAIRHIT ) { directHitDamage += DIRECTAIRTHIT_DAMAGE_BONUS; } else if( hitType == PROJECTILE_TOUCH_DIRECTHIT ) { directHitDamage += DIRECTHIT_DAMAGE_BONUS; } } G_Damage( other, ent, ent->r.owner, dir, ent->velocity, ent->s.origin, directHitDamage, ent->projectileInfo.maxKnockback, ent->projectileInfo.stun, 0, ent->style ); } if( ent->s.effects & EF_STRONG_WEAPON ) { mod_splash = MOD_ROCKET_SPLASH_S; } else { mod_splash = MOD_ROCKET_SPLASH_W; } G_RadiusDamage( ent, ent->r.owner, plane, other, mod_splash ); // spawn the explosion if( !( surfFlags & SURF_NOIMPACT ) ) { edict_t *event; vec3_t explosion_origin; VectorMA( ent->s.origin, -0.02, ent->velocity, explosion_origin ); event = G_SpawnEvent( EV_ROCKET_EXPLOSION, DirToByte( plane ? plane->normal : NULL ), explosion_origin ); event->s.firemode = ( ent->s.effects & EF_STRONG_WEAPON ) ? FIRE_MODE_STRONG : FIRE_MODE_WEAK; event->s.weapon = ( ( ent->projectileInfo.radius * 1 / 8 ) > 255 ) ? 255 : ( ent->projectileInfo.radius * 1 / 8 ); } // free the rocket at next frame G_FreeEdict( ent ); }
/* * W_Touch_Grenade */ static void W_Touch_Grenade( edict_t *ent, edict_t *other, cplane_t *plane, int surfFlags ) { int hitType; vec3_t dir; if( surfFlags & SURF_NOIMPACT ) { G_FreeEdict( ent ); return; } hitType = G_Projectile_HitStyle( ent, other ); if( hitType == PROJECTILE_TOUCH_NOT ) return; // don't explode on doors and plats that take damage if( !other->takedamage || ISBRUSHMODEL( other->s.modelindex ) ) { G_AddEvent( ent, EV_GRENADE_BOUNCE, ( ent->s.effects & EF_STRONG_WEAPON ) ? FIRE_MODE_STRONG : FIRE_MODE_WEAK, true ); return; } if( other->takedamage ) { int directHitDamage = ent->projectileInfo.maxDamage; VectorNormalize2( ent->velocity, dir ); if( hitType == PROJECTILE_TOUCH_DIRECTSPLASH ) // use hybrid direction from splash and projectile { G_SplashFrac4D( ENTNUM( other ), ent->s.origin, ent->projectileInfo.radius, dir, NULL, NULL, ent->timeDelta ); } else { VectorNormalize2( ent->velocity, dir ); // no direct hit bonuses for grenades /* if( hitType == PROJECTILE_TOUCH_DIRECTAIRHIT ) directHitDamage += DIRECTAIRTHIT_DAMAGE_BONUS; else if( hitType == PROJECTILE_TOUCH_DIRECTHIT ) directHitDamage += DIRECTHIT_DAMAGE_BONUS; */ } G_Damage( other, ent, ent->r.owner, dir, ent->velocity, ent->s.origin, directHitDamage, ent->projectileInfo.maxKnockback, ent->projectileInfo.stun, 0, ent->style ); } ent->enemy = other; W_Grenade_ExplodeDir( ent, plane ? plane->normal : NULL ); }
/* * W_Touch_GunbladeBlast */ static void W_Touch_GunbladeBlast( edict_t *ent, edict_t *other, cplane_t *plane, int surfFlags ) { vec3_t dir; int hitType; if( surfFlags & SURF_NOIMPACT ) { G_FreeEdict( ent ); return; } hitType = G_Projectile_HitStyle( ent, other ); if( hitType == PROJECTILE_TOUCH_NOT ) return; if( other->takedamage ) { VectorNormalize2( ent->velocity, dir ); if( hitType == PROJECTILE_TOUCH_DIRECTSPLASH ) // use hybrid direction from splash and projectile { G_SplashFrac4D( ENTNUM( other ), ent->s.origin, ent->projectileInfo.radius, dir, NULL, NULL, ent->timeDelta ); } else { VectorNormalize2( ent->velocity, dir ); } G_Damage( other, ent, ent->r.owner, dir, ent->velocity, ent->s.origin, ent->projectileInfo.maxDamage, ent->projectileInfo.maxKnockback, ent->projectileInfo.stun, 0, ent->style ); } G_RadiusDamage( ent, ent->r.owner, plane, other, MOD_GUNBLADE_S ); // add explosion event if( ( !other->takedamage || ISBRUSHMODEL( other->s.modelindex ) ) ) { edict_t *event; event = G_SpawnEvent( EV_GUNBLADEBLAST_IMPACT, DirToByte( plane ? plane->normal : NULL ), ent->s.origin ); event->s.weapon = ( ( ent->projectileInfo.radius * 1/8 ) > 127 ) ? 127 : ( ent->projectileInfo.radius * 1/8 ); event->s.skinnum = ( ( ent->projectileInfo.maxKnockback * 1/8 ) > 255 ) ? 255 : ( ent->projectileInfo.maxKnockback * 1/8 ); } // free at next frame G_FreeEdict( ent ); }
/* * W_Touch_Projectile - Generic projectile touch func. Only for replacement in tests */ static void W_Touch_Projectile( edict_t *ent, edict_t *other, cplane_t *plane, int surfFlags ) { vec3_t dir, normal; int hitType; if( surfFlags & SURF_NOIMPACT ) { G_FreeEdict( ent ); return; } hitType = G_Projectile_HitStyle( ent, other ); if( hitType == PROJECTILE_TOUCH_NOT ) return; if( other->takedamage ) { VectorNormalize2( ent->velocity, dir ); if( hitType == PROJECTILE_TOUCH_DIRECTSPLASH ) // use hybrid direction from splash and projectile { G_SplashFrac4D( ENTNUM( other ), ent->s.origin, ent->projectileInfo.radius, dir, NULL, NULL, ent->timeDelta ); } else { VectorNormalize2( ent->velocity, dir ); } G_Damage( other, ent, ent->r.owner, dir, ent->velocity, ent->s.origin, ent->projectileInfo.maxDamage, ent->projectileInfo.maxKnockback, ent->projectileInfo.stun, 0, ent->style ); } G_RadiusDamage( ent, ent->r.owner, plane, other, MOD_EXPLOSIVE ); if( !plane->normal ) VectorSet( normal, 0, 0, 1 ); else VectorCopy( plane->normal, normal ); G_Gametype_ScoreEvent( NULL, "projectilehit", va( "%i %i %f %f %f", ent->s.number, surfFlags, normal[0], normal[1], normal[2] ) ); }
/* * G_RadiusDamage */ void G_RadiusDamage( edict_t *inflictor, edict_t *attacker, cplane_t *plane, edict_t *ignore, int mod ) { edict_t *ent = NULL; float dmgFrac, kickFrac, damage, knockback, stun; vec3_t pushDir; int timeDelta; float maxdamage, mindamage, maxknockback, minknockback, maxstun, minstun, radius; assert( inflictor ); maxdamage = inflictor->projectileInfo.maxDamage; mindamage = inflictor->projectileInfo.minDamage; maxknockback = inflictor->projectileInfo.maxKnockback; minknockback = inflictor->projectileInfo.minKnockback; maxstun = inflictor->projectileInfo.stun; minstun = 1; radius = inflictor->projectileInfo.radius; if( radius <= 1.0f || ( maxdamage <= 0.0f && maxknockback <= 0.0f ) ) return; clamp_high( mindamage, maxdamage ); clamp_high( minknockback, maxknockback ); clamp_high( minstun, maxstun ); while( ( ent = GClip_FindBoxInRadius4D( ent, inflictor->s.origin, radius, inflictor->timeDelta ) ) != NULL ) { if( ent == ignore || !ent->takedamage ) continue; if( ent == attacker && ent->r.client ) timeDelta = 0; else timeDelta = inflictor->timeDelta; G_SplashFrac4D( ENTNUM( ent ), inflictor->s.origin, radius, pushDir, &kickFrac, &dmgFrac, timeDelta ); damage = max( 0, mindamage + ( ( maxdamage - mindamage ) * dmgFrac ) ); stun = max( 0, minstun + ( ( maxstun - minstun ) * dmgFrac ) ); knockback = max( 0, minknockback + ( ( maxknockback - minknockback ) * kickFrac ) ); // weapon jumps hack : when knockback on self, use strong weapon definition if( ent == attacker && ent->r.client ) { gs_weapon_definition_t *weapondef = NULL; if( inflictor->s.type == ET_ROCKET ) weapondef = GS_GetWeaponDef( WEAP_ROCKETLAUNCHER ); else if( inflictor->s.type == ET_GRENADE ) weapondef = GS_GetWeaponDef( WEAP_GRENADELAUNCHER ); else if( inflictor->s.type == ET_PLASMA ) weapondef = GS_GetWeaponDef( WEAP_PLASMAGUN ); else if( inflictor->s.type == ET_BLASTER ) weapondef = GS_GetWeaponDef( WEAP_GUNBLADE ); if( weapondef ) { G_SplashFrac4D( ENTNUM( ent ), inflictor->s.origin, radius, pushDir, &kickFrac, NULL, 0 ); minknockback = weapondef->firedef.minknockback; maxknockback = weapondef->firedef.knockback; clamp_high( minknockback, maxknockback ); knockback = ( minknockback + ( (float)( maxknockback - minknockback ) * kickFrac ) ) * g_self_knockback->value; damage *= weapondef->firedef.selfdamage; } } if( knockback < 1.0f ) knockback = 0.0f; if( stun < 1.0f ) stun = 0.0f; if( damage <= 0.0f && knockback <= 0.0f && stun <= 0.0f ) continue; if( G_CanSplashDamage( ent, inflictor, plane ) ) G_Damage( ent, inflictor, attacker, pushDir, inflictor->velocity, inflictor->s.origin, damage, knockback, stun, DAMAGE_RADIUS, mod ); } }