예제 #1
0
void FireSentryBulletsNEW( int shotcount, gedict_t * targ, float spread_x, float spread_y, float spread_z )
{
    vec3_t  src;
    vec3_t  dst;
    vec3_t  norm_dir;

    sgAimNew( self, targ, src, dst, norm_dir );

    ClearMultiDamage(  );
    traceline( PASSVEC3( src ), PASSVEC3( dst ), 0, self );

    VectorScale( norm_dir, 4, puff_org );
    VectorSubtract( g_globalvars.trace_endpos, puff_org, puff_org );

    for (  ; shotcount > 0  ; shotcount-- )
    {
        // для каждого выстрела определяем trace_ent trace_endpos
        // т.к.выстрелы могут убрать препятствия
        traceline( PASSVEC3( src ), PASSVEC3( dst ), 0, self );

        // TraceAttack требует нормализованый вектор для корректного определения blood_org
        if(g_globalvars.trace_fraction != 1)
            TraceAttack( 4, norm_dir ); 
    }
    ApplyMultiDamage(  );
    Multi_Finish(  );
}
예제 #2
0
파일: view.c 프로젝트: toneddu2000/DPTECH
void View_ThirdPerson ()
{
	local float dist, dist2;
	local vector view, add_h;

	dist = 50;

	view = input_angles;
	view_x = view_x * (-1);

	makevectors (view);

	view = '0 0 0';
	view_z = input_angles_x * 0.1;

	traceline(player.origin + '0 0 40' + v_right*(dist/6), player.origin + '0 0 40' + view - v_forward*dist - v_up*(input_angles_x/6) + v_right*(dist/3), TRUE, self);

	dist2 = vlen(trace_endpos - (player.origin + '0 0 40' + v_right*(dist/6))) ;
	add_h_z = 35 + (dist2 * 2 * (input_angles_x * 0.01));

	traceline(player.origin + '0 0 40' + v_right*(dist/6), player.origin + add_h + view - v_forward*dist2 - v_up*(input_angles_x/6) + v_right*(dist/3), TRUE, self);

	CSQC_VIEW = trace_endpos;
	CSQC_VIEW = CSQC_VIEW + v_forward*4;
}
예제 #3
0
파일: engineer.c 프로젝트: MrPnut/QHome
int CheckArea( gedict_t * obj, gedict_t * builder )
{
    vec3_t src;
    vec3_t end;
    int pos;
    gedict_t *te;

    pos = CheckAreaNew( obj, builder );
    if ( pos == 0 )
	return 0;

    pos = trap_pointcontents( PASSVEC3( obj->s.v.origin ) );
    if ( pos == CONTENT_SOLID || pos == CONTENT_SKY )
	return 0;
    src[0] = obj->s.v.origin[0]  + 24;
    src[1] = obj->s.v.origin[1]  + 24;
    src[2] = obj->s.v.origin[2]  + 16;
    pos = trap_pointcontents( PASSVEC3( src ) );
    if ( pos == CONTENT_SOLID || pos == CONTENT_SKY )
	return 0;
    end[0] = obj->s.v.origin[0]  - 16;
    end[1] = obj->s.v.origin[1]  - 16;
    end[2] = obj->s.v.origin[2]  - 16;
    traceline( PASSVEC3( src ), PASSVEC3( end ), 1, obj );
    if ( g_globalvars.trace_fraction != 1 )
	return 0;
    pos = trap_pointcontents( PASSVEC3( end ) );
    if ( pos == CONTENT_SOLID || pos == CONTENT_SKY )
	return 0;
    src[0] = obj->s.v.origin[0] - 16;
    src[1] = obj->s.v.origin[1] + 16;
    src[2] = obj->s.v.origin[2] + 16;
    pos = trap_pointcontents( PASSVEC3( src ) );
    if ( pos == CONTENT_SOLID || pos == CONTENT_SKY )
	return 0;
    end[0] = obj->s.v.origin[0] + 16;
    end[1] = obj->s.v.origin[1] - 16;
    end[2] = obj->s.v.origin[2] - 16;
    traceline( PASSVEC3( src ), PASSVEC3( end ), 1, obj );

    if ( g_globalvars.trace_fraction != 1 )
	return 0;
    pos = trap_pointcontents( PASSVEC3( end ) );
    if ( pos == CONTENT_SOLID || pos == CONTENT_SKY )
	return 0;
    traceline( PASSVEC3( builder->s.v.origin ), PASSVEC3( obj->s.v.origin ), 1, builder );
    if ( g_globalvars.trace_fraction != 1 )
	return 0;
    te = findradius( world, obj->s.v.origin, 64 );
    if ( te )
		return 0;
    return 1;
}
예제 #4
0
/*
=================
LightningDamage
=================
*/
void LightningDamage( vec3_t p1, vec3_t p2, gedict_t * from, float damage )
{
	gedict_t       *e1, *e2;
	vec3_t          f;


	VectorSubtract( p2, p1, f );	// f = p2 - p1;
	VectorNormalize( f );	// normalize (f);

	f[0] = 0 - f[1];
	f[1] = f[0];
	f[2] = 0;
	VectorScale( f, 16, f );	//f = f*16;

	e1 = e2 = world;

	traceline( PASSVEC3( p1 ), PASSVEC3( p2 ), false, self );

	if ( PROG_TO_EDICT( g_globalvars.trace_ent )->s.v.takedamage )
	{
		LightningHit( from, damage );
		if ( streq( self->s.v.classname, "player" ) )
		{
			if ( streq( other->s.v.classname, "player" ) )
				PROG_TO_EDICT( g_globalvars.trace_ent )->s.v.
				    velocity[2] += 400;
		}
	}
	e1 = PROG_TO_EDICT( g_globalvars.trace_ent );

	//traceline (p1 + f, p2 + f, FALSE, self);
	traceline( p1[0] + f[0], p1[1] + f[1], p1[2] + f[2], p2[0] + f[0],
			p2[1] + f[1], p2[2] + f[2], false, self );
	if ( PROG_TO_EDICT( g_globalvars.trace_ent ) != e1
	     && PROG_TO_EDICT( g_globalvars.trace_ent )->s.v.takedamage )
	{
		LightningHit( from, damage );
	}
	e2 = PROG_TO_EDICT( g_globalvars.trace_ent );

	traceline( p1[0] - f[0], p1[1] - f[1], p1[2] - f[2], p2[0] - f[0],
			p2[1] - f[1], p2[2] - f[2], false, self );
	if ( PROG_TO_EDICT( g_globalvars.trace_ent ) != e1
	     && PROG_TO_EDICT( g_globalvars.trace_ent ) != e2
	     && PROG_TO_EDICT( g_globalvars.trace_ent )->s.v.takedamage )
	{
		LightningHit( from, damage );
	}
}
예제 #5
0
/*
================
FireBullets

Used by shotgun, super shotgun, and enemy soldier firing
Go to the trouble of combining multiple pellets into a single damage call.
================
*/
void FireBullets( float shotcount, vec3_t dir, float spread_x, float spread_y,
		  float spread_z )
{
	vec3_t          direction;
	vec3_t          src, tmp;

	makevectors( self->s.v.v_angle );
	VectorScale( g_globalvars.v_forward, 10, tmp );
	VectorAdd( self->s.v.origin, tmp, src );
	//src = self->s.v.origin + v_forward*10;
	src[2] = self->s.v.absmin[2] + self->s.v.size[2] * 0.7;

	ClearMultiDamage();

	traceline( PASSVEC3( src ), src[0] + dir[0] * 2048, src[1] + dir[1] * 2048,
			src[2] + dir[2] * 2048, false, self );
	VectorScale( dir, 4, tmp );
	VectorSubtract( g_globalvars.trace_endpos, tmp, puff_org );	// puff_org = trace_endpos - dir*4;

	while ( shotcount > 0 )
	{
		VectorScale( g_globalvars.v_right, crandom() * spread_x, tmp );
		VectorAdd( dir, tmp, direction );
		VectorScale( g_globalvars.v_up, crandom() * spread_y, tmp );
		VectorAdd( direction, tmp, direction );

//  direction = dir + crandom()*spread[0]*v_right + crandom()*spread[1]*v_up;
		VectorScale( direction, 2048, tmp );
		VectorAdd( src, tmp, tmp );
		traceline( PASSVEC3( src ), PASSVEC3( tmp ), false, self );
		if ( g_globalvars.trace_fraction != 1.0 )
			TraceAttack( 4, direction );

		shotcount = shotcount - 1;
	}
	ApplyMultiDamage();
	Multi_Finish();
}
예제 #6
0
void FireSentryBulletsMTFL2( int shotcount, gedict_t * targ, float spread_x, float spread_y, float spread_z )
{
    vec3_t  direction;
    vec3_t  src;
    vec3_t  dir, end, tmp;

    sgAimMTFL2( self, targ, src, dir );

    ClearMultiDamage(  );
    VectorScale( dir, 2048, end );
    VectorAdd( end, src, end );
    traceline( PASSVEC3( src ), PASSVEC3( end ), 0, self );

    VectorScale( dir, 4, puff_org );
    VectorSubtract( g_globalvars.trace_endpos, puff_org, puff_org );
    while ( shotcount > 0 )
    {
        VectorScale( g_globalvars.v_right, crandom(  ) * spread_x, tmp );
        VectorScale( g_globalvars.v_up, crandom(  ) * spread_y, direction );
        VectorAdd( direction, tmp, direction );
        VectorAdd( direction, dir, direction );
        VectorNormalize( direction );

        VectorScale( direction, 2048, end );
        VectorAdd( end, src, end );
        traceline( PASSVEC3( src ), PASSVEC3( end ), 0, self );


        if ( g_globalvars.trace_fraction != 1 )
        {
            TraceAttack( 4, direction );
        }
        shotcount = shotcount - 1;
    }
    ApplyMultiDamage(  );
    Multi_Finish(  );
}
예제 #7
0
void traceerror( tsd_t *TSD, const treenode *thisptr, int RC )
{
   streng *message;

   if ( ( TSD->trace_stat == 'N' ) || ( TSD->trace_stat == 'F' ) )
      traceline( TSD, thisptr, 'C', 0 );

   if ( TSD->trace_stat != 'O' )
   {
      message = Str_makeTSD( 20 + sizeof( int ) * 3 ) ;
      message->len = sprintf( message->value, "       +++ RC=%d +++", RC );

      printout( TSD, message );
      Free_stringTSD( message );
   }
}
예제 #8
0
파일: sp_ai.c 프로젝트: JosephPecoraro/ktx
/*
=============
visible

returns 1 if the entity is visible to self, even if not infront ()
=============
*/
float visible( gedict_t *targ )
{
	vec3_t	spot1, spot2;

	VectorAdd( self->s.v.origin, self->s.v.view_ofs, spot1 );
	VectorAdd( targ->s.v.origin, targ->s.v.view_ofs, spot2 );

	traceline( PASSVEC3( spot1 ), PASSVEC3( spot2 ), true, self ); // see through other monsters

	if ( g_globalvars.trace_inopen && g_globalvars.trace_inwater )
		return false;			// sight line crossed contents

	if ( g_globalvars.trace_fraction == 1 )
		return true;

	return false;
}
예제 #9
0
파일: engineer.c 프로젝트: MrPnut/QHome
void CheckBelowBuilding( gedict_t * bld )
{
    vec3_t below;

    VectorCopy( bld->s.v.origin, below );
    if ( streq( bld->s.v.classname, "detpack" ) )
	below[2] = below[2] - 8;
    else
	below[2] = below[2] - 24;
    traceline( PASSVEC3( bld->s.v.origin ), PASSVEC3( below ), 1, bld );
    if ( g_globalvars.trace_fraction == 1 )
    {
	bld->s.v.movetype = MOVETYPE_TOSS;
	bld->s.v.flags = ( int ) bld->s.v.flags - ( ( int ) bld->s.v.flags & FL_ONGROUND );
    }

}
예제 #10
0
/*
================
W_FireAxe
================
*/
void W_FireAxe()
{
	vec3_t          source, dest;
	vec3_t          org;

	makevectors( self->s.v.v_angle );

	VectorCopy( self->s.v.origin, source );
	source[2] += 16;
	VectorScale( g_globalvars.v_forward, 64, dest );
	VectorAdd( dest, source, dest )
	//source = self->s.v.origin + '0 0 16';
	
	traceline( PASSVEC3( source ), PASSVEC3( dest ), false, self );
	if ( g_globalvars.trace_fraction == 1.0 )
		return;

	VectorScale( g_globalvars.v_forward, 4, org );
	VectorSubtract( g_globalvars.trace_endpos, org, org );
// org = trace_endpos - v_forward*4;

	if ( PROG_TO_EDICT( g_globalvars.trace_ent )->s.v.takedamage )
	{
		PROG_TO_EDICT( g_globalvars.trace_ent )->axhitme = 1;
		SpawnBlood( org, 20 );
		if ( deathmatch > 3 )
			T_Damage( PROG_TO_EDICT( g_globalvars.trace_ent ), self, self,
				  75 );
		else
			T_Damage( PROG_TO_EDICT( g_globalvars.trace_ent ), self, self,
				  20 );
	} else
	{			// hit wall
		sound( self, CHAN_WEAPON, "player/axhit2.wav", 1, ATTN_NORM );

		trap_WriteByte( MSG_MULTICAST, SVC_TEMPENTITY );
		trap_WriteByte( MSG_MULTICAST, TE_GUNSHOT );
		trap_WriteByte( MSG_MULTICAST, 3 );
		trap_WriteCoord( MSG_MULTICAST, org[0] );
		trap_WriteCoord( MSG_MULTICAST, org[1] );
		trap_WriteCoord( MSG_MULTICAST, org[2] );
		trap_multicast( PASSVEC3( org ), MULTICAST_PVS );
	}
}
예제 #11
0
void sgAimNew( gedict_t* self, gedict_t* targ, vec3_t src, vec3_t dst, vec3_t norm_dir)
{
    vec3_t  dir,  tmp;
    trap_makevectors( self->s.v.v_angle );

    VectorAdd( self->s.v.origin, self->s.v.view_ofs, src );
    VectorAdd( targ->s.v.origin, targ->s.v.view_ofs, dst );
    VectorSubtract( dst, src, dir );

    normalize(dir, norm_dir);

    //чтобы не попадать в подставку
    traceline( PASSVEC3( src ), PASSVEC3( dst ), 0, self );

    if( (PROG_TO_EDICT(g_globalvars.trace_ent) == self->trigger_field) && vlen(dir) > 100 )
    {
        VectorScale( norm_dir, 60, tmp);
        VectorAdd(src,tmp,src);
    }
}
예제 #12
0
파일: mtf_hwguy.c 프로젝트: MrPnut/QHome
// 20mm cannon
// self->nojumptime < - fixes the bh w/ 20mm bug
void BigAssBullet ( vec3_t direction, float damage )
{
	vec3_t org, src, vtemp;

	makevectors( self->s.v.v_angle );
	src[0] = self->s.v.origin[0] + ( g_globalvars.v_forward[0] * 10 );
	src[1] = self->s.v.origin[1] + ( g_globalvars.v_forward[0] * 10 );
	src[2] = self->s.v.absmin[2] + ( self->s.v.size[2] * 0.7 );
	ClearMultiDamage ( );
	VectorScale( direction, 1500, vtemp );
	VectorAdd( vtemp, src, vtemp );
	traceline( PASSVEC3( src ), PASSVEC3( vtemp ), 0, self );
	//traceline( src, (src + (direction * 1500)), 0, self );
	if ( g_globalvars.trace_fraction != 1 )
		TraceAttack ( damage, direction );

	if ( PROG_TO_EDICT( g_globalvars.trace_ent )->s.v.takedamage ) {
		org[0] = g_globalvars.trace_endpos[0] - ( g_globalvars.v_forward[0] * 4 );
		org[1] = g_globalvars.trace_endpos[1] - ( g_globalvars.v_forward[1] * 4 );
		org[2] = g_globalvars.trace_endpos[2] - ( g_globalvars.v_forward[2] * 4 );
		//org = (trace_endpos - (v_forward * 4));
		SpawnBlood ( org, 9 );
	}
	else {
		//org = (trace_endpos - (v_forward * 4));
		org[0] = g_globalvars.trace_endpos[0] - ( g_globalvars.v_forward[0] * 4 );
		org[1] = g_globalvars.trace_endpos[1] - ( g_globalvars.v_forward[1] * 4 );
		org[2] = g_globalvars.trace_endpos[2] - ( g_globalvars.v_forward[0] * 4 );
		trap_WriteByte( MSG_BROADCAST, SVC_TEMPENTITY );
		trap_WriteByte( MSG_BROADCAST, TE_SPIKE );
		trap_WriteCoord( MSG_BROADCAST, org[0] );
		trap_WriteCoord( MSG_BROADCAST, org[1] );
		trap_WriteCoord( MSG_BROADCAST, org[2] );
		trap_multicast( PASSVEC3( g_globalvars.trace_endpos ), MULTICAST_PHS );
	}

	ApplyMultiDamage ( );
}
예제 #13
0
파일: combat.c 프로젝트: meag/ktx
/*
============
CanDamage

Returns true if the inflictor can directly damage the target.  Used for
explosions and melee attacks.
============
*/
qbool CanDamage( gedict_t * targ, gedict_t * inflictor )
{
	vec3_t	dif;

// bmodels need special checking because their origin is 0,0,0
	if ( targ->s.v.movetype == MOVETYPE_PUSH )
	{
		traceline( PASSVEC3( inflictor->s.v.origin ),
				0.5 * ( targ->s.v.absmin[0] + targ->s.v.absmax[0] ),
				0.5 * ( targ->s.v.absmin[1] + targ->s.v.absmax[1] ),
				0.5 * ( targ->s.v.absmin[2] + targ->s.v.absmax[2] ),
				true, self );

		if ( g_globalvars.trace_fraction == 1 )
			return true;

		if ( PROG_TO_EDICT( g_globalvars.trace_ent ) == targ )
			return true;

		return false;
	}

	traceline( PASSVEC3( inflictor->s.v.origin ), PASSVEC3( targ->s.v.origin ),	true, self );
	if ( g_globalvars.trace_fraction == 1 )
		return true;

// 1998-09-16 CanDamage fix by Maddes/Kryten start

	// testing middle of half-size bounding box
	dif[2] = 0;

	// ...front right
	dif[1] = targ->s.v.maxs[1] * 0.5;
	dif[0] = targ->s.v.maxs[0] * 0.5;
	traceline(PASSVEC3( inflictor->s.v.origin ), 
		targ->s.v.origin[0] + dif[0], targ->s.v.origin[1] + dif[1], targ->s.v.origin[2] + dif[2], true, self);
	if ( g_globalvars.trace_fraction == 1 )
		return true;

	// ...front left
	dif[0] = targ->s.v.mins[0] * 0.5;
	traceline(PASSVEC3( inflictor->s.v.origin ),
		targ->s.v.origin[0] + dif[0], targ->s.v.origin[1] + dif[1], targ->s.v.origin[2] + dif[2], true, self);
	if ( g_globalvars.trace_fraction == 1 )
		return true;

	// ...back left
	dif[1] = targ->s.v.mins[1] * 0.5;
	traceline(PASSVEC3( inflictor->s.v.origin ),
		targ->s.v.origin[0] + dif[0], targ->s.v.origin[1] + dif[1], targ->s.v.origin[2] + dif[2], true, self);
	if ( g_globalvars.trace_fraction == 1 )
		return true;

	// ...back right
	dif[0] = targ->s.v.maxs[0] * 0.5;
	traceline(PASSVEC3( inflictor->s.v.origin ),
		targ->s.v.origin[0] + dif[0], targ->s.v.origin[1] + dif[1], targ->s.v.origin[2] + dif[2], true, self);
	if ( g_globalvars.trace_fraction == 1 )
		return true;

	// testing top of half-sized bounding box
	dif[2] = targ->s.v.maxs[2] * 0.5;

	// ...front right
	dif[1] = targ->s.v.maxs[1] * 0.5;
	dif[0] = targ->s.v.maxs[0] * 0.5;
	traceline(PASSVEC3( inflictor->s.v.origin ),
		targ->s.v.origin[0] + dif[0], targ->s.v.origin[1] + dif[1], targ->s.v.origin[2] + dif[2], true, self);
	if ( g_globalvars.trace_fraction == 1 )
		return true;

	// ...front left
	dif[0] = targ->s.v.mins[0] * 0.5;
	traceline(PASSVEC3( inflictor->s.v.origin ),
		targ->s.v.origin[0] + dif[0], targ->s.v.origin[1] + dif[1], targ->s.v.origin[2] + dif[2], true, self);
	if ( g_globalvars.trace_fraction == 1 )
		return true;

	// ...back left
	dif[1] = targ->s.v.mins[1] * 0.5;
	traceline(PASSVEC3( inflictor->s.v.origin ),
		targ->s.v.origin[0] + dif[0], targ->s.v.origin[1] + dif[1], targ->s.v.origin[2] + dif[2], true, self);
	if ( g_globalvars.trace_fraction == 1 )
		return true;

	// ...back right
	dif[0] = targ->s.v.maxs[0] * 0.5;
	traceline(PASSVEC3( inflictor->s.v.origin ),
		targ->s.v.origin[0] + dif[0], targ->s.v.origin[1] + dif[1], targ->s.v.origin[2] + dif[2], true, self);
	if ( g_globalvars.trace_fraction == 1 )
		return true;

	// testing bottom of half-sized bounding box
	dif[2] = targ->s.v.mins[2] * 0.5;

	// ...front right
	dif[1] = targ->s.v.maxs[1] * 0.5;
	dif[0] = targ->s.v.maxs[0] * 0.5;
	traceline(PASSVEC3( inflictor->s.v.origin ),
		targ->s.v.origin[0] + dif[0], targ->s.v.origin[1] + dif[1], targ->s.v.origin[2] + dif[2], true, self);
	if ( g_globalvars.trace_fraction == 1 )
		return true;

	// ...front left
	dif[0] = targ->s.v.mins[0] * 0.5;
	traceline(PASSVEC3( inflictor->s.v.origin ),
		targ->s.v.origin[0] + dif[0], targ->s.v.origin[1] + dif[1], targ->s.v.origin[2] + dif[2], true, self);
	if ( g_globalvars.trace_fraction == 1 )
		return true;

	// ...back left
	dif[1] = targ->s.v.mins[1] * 0.5;
	traceline(PASSVEC3( inflictor->s.v.origin ),
		targ->s.v.origin[0] + dif[0], targ->s.v.origin[1] + dif[1], targ->s.v.origin[2] + dif[2], true, self);
	if ( g_globalvars.trace_fraction == 1 )
		return true;

	// ...back right
	dif[0] = targ->s.v.maxs[0] * 0.5;
	traceline(PASSVEC3( inflictor->s.v.origin ),
		targ->s.v.origin[0] + dif[0], targ->s.v.origin[1] + dif[1], targ->s.v.origin[2] + dif[2], true, self);
	if ( g_globalvars.trace_fraction == 1 )
		return true;

// 1998-09-16 CanDamage fix by Maddes/Kryten end

	return false;
}
예제 #14
0
파일: combat.c 프로젝트: meag/ktx
void T_Damage( gedict_t * targ, gedict_t * inflictor, gedict_t * attacker, float damage )
{
	vec3_t          dir;
	gedict_t       *oldself;
	float           save;
	float           take;
	int				i, c1 = 8, c2 = 4, hdp;
	float			dmg_dealt = 0, virtual_take = 0;
	float			non_hdp_damage; // save damage before handicap apply for kickback calculation
	float			native_damage = damage; // save damage before apply any modificator
	char            *attackerteam, *targteam, *attackername, *victimname;
	qbool			tp4teamdmg = false;

	//midair and instagib
	float playerheight = 0, midheight = 0;
	qbool midair = false, inwater = false, do_dmg = false, rl_dmg = false, stomp_dmg = false;

	// can't apply damage to dead
	if ( !targ->s.v.takedamage || ISDEAD( targ ) )
		return;

	// can't damage other players in race
	if ( isRACE() && ( attacker != targ ) )
	{
			if ( targ->ct == ctPlayer || attacker->ct == ctPlayer )
				return;
	}

	// ignore almost all damage in CA while coutdown
	if ( isCA() && match_in_progress && ra_match_fight != 2 )
	{
		if ( !( 	dtTELE1 == targ->deathtype	// always do tele damage
				 || dtTELE2 == targ->deathtype	// always do tele damage
				 || dtTELE3 == targ->deathtype	// always do tele damage
				 || dtSUICIDE == targ->deathtype // do suicide damage anyway
			  )
		)
			return;
	}	

	// used by buttons and triggers to set activator for target firing
	damage_attacker = attacker;
	damage_inflictor = inflictor;

	attackerteam = getteam( attacker );
	targteam = getteam( targ );

	if ( (int)cvar("k_midair") )
		midair = true;

	// in bloodfest boss damage factor.
	if ( k_bloodfest && attacker->bloodfest_boss )
	{
		damage *= 4;
	}

	// check for quad damage powerup on the attacker
	// midair quad makes rockets fast, but no change to damage
	if ( attacker->super_damage_finished > g_globalvars.time
	     && strneq( inflictor->s.v.classname, "door" ) && dtSTOMP != targ->deathtype
		 && !midair 
	   )
		damage *= ( deathmatch == 4 ? 8 : 4 ); // in dmm4 quad is octa actually

	// ctf strength rune
	if ( attacker->ctf_flag & CTF_RUNE_STR )
		damage *= 2;

	// ctf resistance rune
	if ( targ->ctf_flag & CTF_RUNE_RES )
	{
		damage /= 2;
		ResistanceSound( targ );
	}

	// did we hurt enemy flag carrier?
	if ( (targ->ctf_flag & CTF_FLAG) && (!streq(targteam, attackerteam)) )
	{
		attacker->carrier_hurt_time = g_globalvars.time;
	}

	// in teamplay 4 we do no armor or health damage to teammates (unless telefrag), but do apply velocity changes
	if ( tp_num() == 4 && streq(targteam, attackerteam) && ( isCA() || targ != attacker ) && !TELEDEATH(targ) )
	{
		tp4teamdmg = true;
	}

	if ( midair || cvar("k_instagib") )
	{
		traceline( PASSVEC3(targ->s.v.origin),
				targ->s.v.origin[0], 
				targ->s.v.origin[1], 
				targ->s.v.origin[2] - 2048,
				true, targ );

		playerheight = targ->s.v.absmin[2] - g_globalvars.trace_endpos[2] + ( cvar("k_instagib") ? 1 : 0 );
	}

	// get some data before apply damage in mid air mode
	if ( midair )
	{
		inwater = ( ((int)targ->s.v.flags & FL_INWATER) && targ->s.v.waterlevel > 1 );

		if ( streq( inflictor->s.v.classname, "rocket" ))
			midheight = targ->s.v.origin[2] - inflictor->s.v.oldorigin[2];

		rl_dmg = ( targ->ct == ctPlayer && dtRL == targ->deathtype );
		stomp_dmg = ( targ->ct == ctPlayer && dtSTOMP == targ->deathtype );

		if ( !rl_dmg ) {
			// damage types which ignore "lowheight"
			do_dmg =   targ->ct != ctPlayer				// always do damage to non player, secret doors etc...
				 	|| dtWATER_DMG == targ->deathtype	// always do water damage
				 	|| dtLAVA_DMG  == targ->deathtype	// always do lava damage
				 	|| dtSLIME_DMG == targ->deathtype	// always do slime damage
				 	|| dtSTOMP == targ->deathtype	// always do stomp damage
				 	|| dtTELE1 == targ->deathtype	// always do tele damage
				 	|| dtTELE2 == targ->deathtype	// always do tele damage
				 	|| dtTELE3 == targ->deathtype	// always do tele damage
					|| dtSUICIDE == targ->deathtype; // do suicide damage anyway
		}
	}

	non_hdp_damage = damage; // save damage before handicap apply for kickback calculation

	// #handicap#
	if ( attacker != targ ) // attack no self
	if ( attacker->ct == ctPlayer && targ->ct == ctPlayer ) // player vs player
	if ( ( hdp = GetHandicap(attacker) ) != 100 ) // skip checks if hdp == 100
	if (    dtAXE  == targ->deathtype
 		 || dtSG   == targ->deathtype
		 || dtSSG  == targ->deathtype
		 || dtNG   == targ->deathtype
		 || dtSNG  == targ->deathtype
		 || dtGL   == targ->deathtype
		 || dtRL   == targ->deathtype
		 || dtLG_BEAM     == targ->deathtype
		 || dtLG_DIS      == targ->deathtype
		 || dtLG_DIS_SELF == targ->deathtype // even that impossible
	   ) {
		damage *= 0.01f * hdp;
	}

	// save damage based on the target's armor level

	save = newceil( targ->s.v.armortype * damage );

	if ( tp4teamdmg )
		save = 0; // we do not touch armor

	if ( save >= targ->s.v.armorvalue )
	{
		save = targ->s.v.armorvalue;
		targ->s.v.armortype = 0;	// lost all armor
		targ->s.v.items -= ( ( int ) targ->s.v.items & ( IT_ARMOR1 | IT_ARMOR2 | IT_ARMOR3 ) );
	}

	dmg_dealt += save;

	if ( match_in_progress == 2 )
		targ->s.v.armorvalue = targ->s.v.armorvalue - save;

	take = newceil( damage - save );

	// mid air damage modificators
	if ( midair )
	{
		int k_midair_minheight, midair_minheight;

		k_midair_minheight = (int)cvar("k_midair_minheight");	

		if ( k_midair_minheight == 1 )
			midair_minheight = 128;
		else if ( k_midair_minheight == 2 )
			midair_minheight = 256;
		else if ( k_midair_minheight == 3 )
			midair_minheight = 512;
		else if ( k_midair_minheight == 4 )
			midair_minheight = 1024;
		else
			midair_minheight = 64;

		if ( rl_dmg || stomp_dmg )
			take = 9999;

		if ( playerheight < midair_minheight && rl_dmg )
			take = 0; // no dmg done if target is not high enough

		if ( playerheight < 45 && !inwater && rl_dmg )
			take = 0; // no rl dmg in such case

		if ( !rl_dmg && !do_dmg )
			take = 0; // unknown damage for midair, so do not damage

		if ( rl_dmg && targ == attacker )
			take = 0; // no self rl damage
	}

	// instagib damage modificators
	if ( cvar("k_instagib") )
	{
		if ( inflictor->ct == ctPlayer )
			take = 5000;

		if ( attacker == targ )
			take = 0;
	}

	// helps kill player in prewar at "wrong" places
	if ( match_in_progress != 2 && native_damage > 450 )
		take = 99999;

	// team play damage avoidance and godmode or invincibility check

	virtual_take = max(0, take); // virtual_take used for calculating dmg_dealt only in case of k_dmgfrags

	// ignore this checks for suicide damage
	if ( dtSUICIDE != targ->deathtype )
	{
		if ( ( int ) targ->s.v.flags & FL_GODMODE )
		{
			take = 0; // what if god was one of us
		}
		else if ( targ->invincible_finished >= g_globalvars.time )
		{
			if ( targ->invincible_sound < g_globalvars.time )
			{
				sound( targ, CHAN_AUTO, "items/protect3.wav", 1, ATTN_NORM );
				targ->invincible_sound = g_globalvars.time + 2;
			}

			take = 0;
		}
		else if ( ( tp_num() == 1 || ( tp_num() == 3 && targ != attacker ) )
		 	&& !strnull( attackerteam )
		 	&& streq( targteam, attackerteam )
		 	&& attacker->ct == ctPlayer
		 	&& strneq( inflictor->s.v.classname, "door" )
		 	&& !TELEDEATH( targ ) // do telefrag damage in tp
	   	)
	   	{
			// teamplay == 1 don't damage self and mates (armor affected anyway)
			// teamplay == 3 don't damage mates, do damage to self (armor affected anyway)

			take = 0;	   	
	   	}
	   	else if ( tp4teamdmg )
	   	{
			take = 0; // we do not touch health	   	
	   	}
	}

	take = max(0, take); // avoid negative take, if any

	if ( cvar("k_dmgfrags") )
	{
		if ( TELEDEATH( targ ) )
		{
			// tele doesn't count for any dmgfrags damage
			dmg_dealt = 0; 
		}
		else if ( targ->invincible_finished >= g_globalvars.time )
		{
			// damage dealt _not_ capped by victim's health if victim has pent
			dmg_dealt += virtual_take;
		}
		else
		{
			// damage dealt capped by victim's health
			dmg_dealt += bound( 0, virtual_take, targ->s.v.health );
		}
	}
	else
	{
		// damage dealt capped by victim's health
		dmg_dealt += bound( 0, take, targ->s.v.health );
	}

	// add to the damage total for clients, which will be sent as a single
	// message at the end of the frame
	// FIXME: remove after combining shotgun blasts?
	if ( targ->ct == ctPlayer )
	{
		targ->s.v.dmg_take += take;
		targ->s.v.dmg_save += save;
		targ->s.v.dmg_inflictor = EDICT_TO_PROG( inflictor );
	}

	if ( save )
	{
		if (( streq( inflictor->s.v.classname, "worldspawn" ) || strnull( attacker->s.v.classname ))
	        	|| ( targ->deathtype == dtWATER_DMG )
	                || ( targ->deathtype == dtEXPLO_BOX )
	                || ( targ->deathtype == dtFALL )
	                || ( targ->deathtype == dtSQUISH )
	                || ( targ->deathtype == dtCHANGELEVEL )
	                || ( targ->deathtype == dtFIREBALL )
	                || ( targ->deathtype == dtSLIME_DMG )
	                || ( targ->deathtype == dtLAVA_DMG )
	                || ( targ->deathtype == dtTRIGGER_HURT )
		)
				attackername = "world";
		else
			attackername = attacker->s.v.netname;
			victimname = targ->s.v.netname;

		log_printf(
			"\t\t<event>\n"
			"\t\t\t<damage>\n"
			"\t\t\t\t<time>%f</time>\n"
			"\t\t\t\t<attacker>%s</attacker>\n"
			"\t\t\t\t<target>%s</target>\n"
			"\t\t\t\t<type>%s</type>\n"
			"\t\t\t\t<quad>%d</quad>\n"
			"\t\t\t\t<splash>%d</splash>\n"
			"\t\t\t\t<value>%d</value>\n"
			"\t\t\t\t<armor>1</armor>\n"
			"\t\t\t</damage>\n"
			"\t\t</event>\n",
			g_globalvars.time - match_start_time,
			cleantext(attackername),
			cleantext(victimname),
			death_type( targ->deathtype ),
			(int)(attacker->super_damage_finished > g_globalvars.time ? 1 : 0 ),
			dmg_is_splash,
			(int)save
		);
	}

	// figure momentum add
	if ( inflictor != world
		 && (	targ->s.v.movetype == MOVETYPE_WALK
			  || ( k_bloodfest && ( (int)targ->s.v.flags & FL_MONSTER ) )
			 )
	)
	{
		float nailkick;

		for ( i = 0; i < 3; i++ )
			dir[i] = targ->s.v.origin[i] - ( inflictor->s.v.absmin[i] + inflictor->s.v.absmax[i] ) * 0.5;

		VectorNormalize( dir );

		dir[2] = ((dtLG_DIS_SELF == targ->deathtype || dtLG_DIS == targ->deathtype) && dir[2] < 0) ? -dir[2] : dir[2];

		if ( midair && non_hdp_damage < 60 && attacker != targ ) {
			c1 = 11;
			c2 = 6;
		}

		// Yawnmode: nails increases kickback
		// - Molgrum
		if ( k_yawnmode && streq( inflictor->s.v.classname, "spike" ) )
			nailkick = 1.2;
		else
			nailkick = 1.0;

		for ( i = 0; i < 3; i++ ) 
			targ->s.v.velocity[i] += dir[i] * non_hdp_damage * c1 * nailkick * ( midair && playerheight >= 45 ? ( 1 + ( playerheight - 45 ) / 64 ) : 1 );

		if ( midair && playerheight < 45 )
			targ->s.v.velocity[2] += dir[2] * non_hdp_damage * c2 * nailkick; // only for z component

		if ( k_bloodfest && ( (int)targ->s.v.flags & FL_MONSTER ) )
		{
			targ->s.v.flags = (int)targ->s.v.flags & ~FL_ONGROUND;		
		}
	}

	if ( match_in_progress == 2 && (int)cvar("k_dmgfrags") )
	{
		if ( attacker->ct == ctPlayer && targ->ct == ctPlayer && attacker != targ )
		{
			if ( isDuel() || isFFA() || strneq(attackerteam, targteam) )
			{
				int dmg_frags;
				attacker->ps.dmg_frags += dmg_dealt; // add dealt
				dmg_frags = attacker->ps.dmg_frags / 100; // 1 frag = 100 damage
				attacker->s.v.frags = (int)(attacker->s.v.frags + dmg_frags);
				attacker->ps.dmg_frags -= dmg_frags * 100;
			}
		}
	}

	// do the damage

	if (    match_in_progress == 2
		 || dtSUICIDE == targ->deathtype // do suicide damage anyway
		 || TELEDEATH( targ )
		 || ( k_practice && targ->ct != ctPlayer ) // #practice mode#
		 || take >= 99999 // do such huge damage even in prewar, prewar because indirectly here match_in_progress != 2
	   ) 
	{
		targ->s.v.health -= take;

//		G_bprint( 2, "%s %f\n", targ->s.v.classname, targ->s.v.health );

		if ( take )
		{
			if (( streq( inflictor->s.v.classname, "worldspawn" ) || strnull( attacker->s.v.classname ))
		        	|| ( targ->deathtype == dtWATER_DMG )
		                || ( targ->deathtype == dtEXPLO_BOX )
		                || ( targ->deathtype == dtFALL )
		                || ( targ->deathtype == dtSQUISH )
		                || ( targ->deathtype == dtCHANGELEVEL )
		                || ( targ->deathtype == dtFIREBALL )
		                || ( targ->deathtype == dtSLIME_DMG )
		                || ( targ->deathtype == dtLAVA_DMG )
		                || ( targ->deathtype == dtTRIGGER_HURT )
			)
				attackername = "world";
			else
				attackername = attacker->s.v.netname;
				victimname = targ->s.v.netname;

			log_printf(
				"\t\t<event>\n"
				"\t\t\t<damage>\n"
				"\t\t\t\t<time>%f</time>\n"
				"\t\t\t\t<attacker>%s</attacker>\n"
				"\t\t\t\t<target>%s</target>\n"
				"\t\t\t\t<type>%s</type>\n"
				"\t\t\t\t<quad>%d</quad>\n"
				"\t\t\t\t<splash>%d</splash>\n"
				"\t\t\t\t<value>%d</value>\n"
				"\t\t\t\t<armor>0</armor>\n"
				"\t\t\t</damage>\n"
				"\t\t</event>\n",
				g_globalvars.time - match_start_time,
				cleantext(attackername),
				cleantext(victimname),
				death_type( targ->deathtype ),
				(int)(attacker->super_damage_finished > g_globalvars.time ? 1 : 0 ),
				dmg_is_splash,
				(int)take
			);
		}

		if ( !targ->s.v.health || dtSUICIDE == targ->deathtype )
			targ->s.v.health = -1; // qqshka, no zero health, heh, imo less bugs after this
	}

	// show damage in sbar
	if ( match_in_progress != 2 && ISLIVE( targ ) && !k_matchLess )
	{
		if ( !midair || ( (int)targ->s.v.flags & FL_ONGROUND ) )
		{
			if ( targ->ct == ctPlayer )			
				targ->s.v.currentammo = 1000 + Q_rint(damage);

			if ( attacker != targ && attacker->ct == ctPlayer)
				attacker->s.v.health = 1000 + Q_rint(damage);
		}
	}

	// update damage stats like: give/taked/team damage
	if ( attacker->ct == ctPlayer && targ->ct == ctPlayer )
	{
		if ( attacker == targ )
		{
			// self damage

			attacker->ps.dmg_self += dmg_dealt;
		}
		else
		{
			int items = targ->s.v.items;

			// damage to enemy weapon
			if ( items & (IT_ROCKET_LAUNCHER | IT_LIGHTNING) )
			{
				attacker->ps.dmg_eweapon += dmg_dealt;
			}

			if ( tp_num() && streq(attackerteam, targteam) )
			{
				attacker->ps.dmg_team += dmg_dealt;
			}
			else 
			{
				attacker->ps.dmg_g += dmg_dealt;
				targ->ps.dmg_t     += dmg_dealt;
			}

			// real hits

			if ( take || save )
			{
				if ( dtRL == targ->deathtype )
					attacker->ps.wpn[wpRL].rhits++;

				if ( dtGL == targ->deathtype )
					attacker->ps.wpn[wpGL].rhits++;
			}

			// virtual hits

			if ( virtual_take || save )
			{
				if ( dtRL == targ->deathtype )
				{
					attacker->ps.wpn[wpRL].vhits++;
					// virtual given rl damage
					attacker->ps.dmg_g_rl += ( virtual_take + save );
				}

				if ( dtGL == targ->deathtype )
					attacker->ps.wpn[wpGL].vhits++;
			}
		}
	}

	// mid air bonuses
	if ( midair && match_in_progress == 2 && attacker != targ && take && rl_dmg)
			MidairDamageBonus(attacker, midheight);

	if ( midair && match_in_progress == 2 && stomp_dmg ) {
		attacker->ps.mid_stomps++;
		targ->s.v.frags -= 3;
	}

 	// if targed killed, do appropriate action and return
	if ( ISDEAD( targ ) )
	{
		Killed( targ, attacker, inflictor );
		return;
	}

	// react to the damage - call pain function
	oldself = self;
	self = targ;

  	if ( (int)self->s.v.flags & FL_MONSTER )
  	{
		GetMadAtAttacker( attacker );
  	}

	if ( self->th_pain )
	{
		self->th_pain( attacker, take );
	}

	self = oldself;
}
예제 #15
0
파일: bot_movement.c 프로젝트: deurk/ktx
float AverageTraceAngle (gedict_t* self, qbool debug, qbool report)
{
	vec3_t back_left, projection, incr;
	int angles[] = { 45, 30, 15, 0, -15, -30, -45 };
	int i;
	float best_angle = 0;
	float best_angle_frac = 0;
	float total_angle = 0;
	float avg_angle;

	float distance = 320;

	if (self->fb.path_state & JUMP_LEDGE)
		return 0;

	if (debug) {
		trap_makevectors (self->s.v.angles);
	}
	else {
		trap_makevectors (self->fb.dir_move_);
	}
	VectorMA (self->s.v.origin, -VEC_HULL_MIN[0], g_globalvars.v_forward, back_left);
	VectorMA (back_left, VEC_HULL_MIN[1], g_globalvars.v_right, back_left);

	VectorScale (g_globalvars.v_right, (VEC_HULL_MAX[0] - VEC_HULL_MIN[0]) / (sizeof(angles) / sizeof(angles[0]) - 1), incr);

	if (debug) {
		G_bprint (2, "Current origin: %d %d %d\n", PASSINTVEC3 (self->s.v.origin));
		G_bprint (2, "Current angles: %d %d\n", PASSINTVEC3 (self->s.v.angles));
	}

	for (i = 0; i < sizeof (angles) / sizeof (angles[0]); ++i) {
		int angle = angles[i];

		RotatePointAroundVector (projection, g_globalvars.v_up, g_globalvars.v_forward, angle);
		VectorMA (back_left, distance, projection, projection);
		traceline (PASSVEC3 (back_left), PASSVEC3 (projection), false, self);

		if (g_globalvars.trace_fraction == 1) {
			total_angle += angle * 1.5; // bonus for success
		}
		else if (g_globalvars.trace_fraction > 0.4) {
			total_angle += angle * g_globalvars.trace_fraction;
		}

		if (debug) {
			G_bprint (2, "Angle: %d => [%d %d %d] [%d %d %d] = %f\n", angle, PASSINTVEC3 (back_left), PASSINTVEC3 (projection), g_globalvars.trace_fraction);
		}

		if (i == 0 || g_globalvars.trace_fraction > best_angle_frac) {
			best_angle = angle;
			best_angle_frac = g_globalvars.trace_fraction;
		}

		VectorAdd (back_left, incr, back_left);
	}

	avg_angle = total_angle / (sizeof (angles) / sizeof (angles[0]));

	if (debug) {
		G_bprint (2, "Best angle: %d\n", best_angle);
		G_bprint (2, "Total angle: %f\n", avg_angle);
	}
	return avg_angle;
}
예제 #16
0
void    FireSentryLighting( gedict_t * targ )  
{
    vec3_t  src;
    vec3_t  dst;
    vec3_t  dir, end, norm_dir;
    gedict_t*trace_ent;

    switch( tfset_sg_sfire )
    {
        case SG_SFIRE_NEW:
            VectorCopy( self->s.v.angles, self->s.v.v_angle );
            sgAimNew( self, targ, src, dst, norm_dir );

            VectorCopy(dst,end);
            break;
        case SG_SFIRE_MTFL2:
            VectorCopy( self->s.v.angles, self->s.v.v_angle );
            sgAimMTFL2( self, targ, src, dir );

            VectorNormalize( dir );
            VectorScale( dir, 2048, end );
            VectorAdd( end, src, end );
            break;

        case SG_SFIRE_MTFL1:
            VectorCopy( self->s.v.angles, self->s.v.v_angle );
        case SG_SFIRE_281:
            trap_makevectors( self->s.v.v_angle );
            VectorScale( g_globalvars.v_forward, 10, src );
            VectorAdd( self->s.v.origin, src, src );
            src[2] = self->s.v.absmin[2] + self->s.v.size[2] * 0.7;
            VectorSubtract( targ->s.v.origin, self->s.v.origin, dir );
            VectorScale( dir, 2048, end );
            VectorAdd( end, src, end );
            break;
        default:
            return;
    }
    g_globalvars.trace_ent = 0;

    traceline( PASSVEC3( src ), PASSVEC3( end ), 0, self );


    trap_WriteByte( MSG_MULTICAST, SVC_TEMPENTITY );
    trap_WriteByte( MSG_MULTICAST, TE_LIGHTNING2 );
    WriteEntity( MSG_MULTICAST, self );
    trap_WriteCoord( MSG_MULTICAST, src[0] );
    trap_WriteCoord( MSG_MULTICAST, src[1] );
    trap_WriteCoord( MSG_MULTICAST, src[2] );
    trap_WriteCoord( MSG_MULTICAST, g_globalvars.trace_endpos[0] );
    trap_WriteCoord( MSG_MULTICAST, g_globalvars.trace_endpos[1] );
    trap_WriteCoord( MSG_MULTICAST, g_globalvars.trace_endpos[2] );
    trap_multicast( PASSVEC3( src ), 1 );
    if ( g_globalvars.trace_ent )
    {
        trace_ent = PROG_TO_EDICT(g_globalvars.trace_ent);
        if ( streq( trace_ent->s.v.classname, "player" ) )
        {
            switch((int)( g_random(  ) * 30) )  
            {
                case 0:
                    sound( trace_ent, 2, "player/pain1.wav" , 1, 1 );
                    break;
                case 1:
                    sound( trace_ent, 2, "player/pain1.wav" , 1, 1 );
                    break;
                case 2:
                    sound( trace_ent, 2, "player/pain2.wav" , 1, 1 );
                    break;
                case 3:
                    sound( trace_ent, 2, "player/pain3.wav" , 1, 1 );
                    break;
                case 4:
                    sound( trace_ent, 2, "player/pain4.wav" , 1, 1 );
                    break;
                case 5:
                    sound( trace_ent, 2, "player/pain5.wav" , 1, 1 );
                    break;
                case 6:
                    sound( trace_ent, 2, "player/pain6.wav" , 1, 1 );
                    break;
                default:break;
            }
        }
    }
}
예제 #17
0
파일: sp_ai.c 프로젝트: JosephPecoraro/ktx
/*
===========
CheckAttack

The player is in view, so decide to move or launch an attack
Returns false if movement should continue
============
*/
float CheckAttack ()
{
	vec3_t		spot1, spot2;
	gedict_t	*targ;
	float		chance;

	targ = PROG_TO_EDICT( self->s.v.enemy );

	// see if any entities are in the way of the shot
	VectorAdd( self->s.v.origin, self->s.v.view_ofs, spot1 );
	VectorAdd( targ->s.v.origin, targ->s.v.view_ofs, spot2 );

	traceline( PASSVEC3( spot1 ), PASSVEC3( spot2 ), false, self );

	if ( PROG_TO_EDICT( g_globalvars.trace_ent ) != targ )
		return false; // don't have a clear shot

	if ( g_globalvars.trace_inopen && g_globalvars.trace_inwater )
		return false; // sight line crossed contents

	if ( enemy_range == RANGE_MELEE )
	{	// melee attack
		if ( self->th_melee )
		{
			self->th_melee();

			return true;
		}
	}

	// missile attack
	if ( !self->th_missile )
		return false;

	if ( g_globalvars.time < self->attack_finished )
		return false;

	if ( enemy_range == RANGE_FAR )
		return false;

	if ( enemy_range == RANGE_MELEE )
	{
		chance = 0.9;
		self->attack_finished = 0;
	}
	else if ( enemy_range == RANGE_NEAR )
	{
		if (self->th_melee)
			chance = 0.2;
		else
			chance = 0.4;
	}
	else if ( enemy_range == RANGE_MID )
	{
		if ( self->th_melee )
			chance = 0.05;
		else
			chance = 0.1;
	}
	else
		chance = 0;

	if ( g_random() < chance )
	{
		if ( self->th_missile )
			self->th_missile();

		SUB_AttackFinished( 2 * g_random() );

		return true;
	}

	return false;
}
예제 #18
0
void W_FireLightning()
{
	vec3_t          org;
	float           cells;
	vec3_t          tmp;

	if ( self->s.v.ammo_cells < 1 )
	{
		self->s.v.weapon = W_BestWeapon();
		W_SetCurrentAmmo();
		return;
	}
// explode if under water
	if ( self->s.v.waterlevel > 1 )
	{
		if ( deathmatch > 3 )
		{
			if ( g_random() <= 0.5 )
			{
				self->deathtype = "selfwater";
				T_Damage( self, self, PROG_TO_EDICT( self->s.v.owner ),
					  4000 );
			} else
			{
				cells = self->s.v.ammo_cells;
				self->s.v.ammo_cells = 0;
				W_SetCurrentAmmo();
				T_RadiusDamage( self, self, 35 * cells, world, "" );
				return;
			}
		} else
		{
			cells = self->s.v.ammo_cells;
			self->s.v.ammo_cells = 0;
			W_SetCurrentAmmo();
			T_RadiusDamage( self, self, 35 * cells, world, "" );
			return;
		}
	}

	if ( self->t_width < g_globalvars.time )
	{
		sound( self, CHAN_WEAPON, "weapons/lhit.wav", 1, ATTN_NORM );
		self->t_width = g_globalvars.time + 0.6;
	}
	g_globalvars.msg_entity = EDICT_TO_PROG( self );
	trap_WriteByte( MSG_ONE, SVC_SMALLKICK );

	if ( deathmatch != 4 )
		self->s.v.currentammo = self->s.v.ammo_cells = self->s.v.ammo_cells - 1;

	VectorCopy( self->s.v.origin, org );	//org = self->s.v.origin + '0 0 16';
	org[2] += 16;


	traceline( PASSVEC3( org ), org[0] + g_globalvars.v_forward[0] * 600,
			org[1] + g_globalvars.v_forward[1] * 600,
			org[2] + g_globalvars.v_forward[2] * 600, true, self );

	trap_WriteByte( MSG_MULTICAST, SVC_TEMPENTITY );
	trap_WriteByte( MSG_MULTICAST, TE_LIGHTNING2 );
	WriteEntity( MSG_MULTICAST, self );
	trap_WriteCoord( MSG_MULTICAST, org[0] );
	trap_WriteCoord( MSG_MULTICAST, org[1] );
	trap_WriteCoord( MSG_MULTICAST, org[2] );
	trap_WriteCoord( MSG_MULTICAST, g_globalvars.trace_endpos[0] );
	trap_WriteCoord( MSG_MULTICAST, g_globalvars.trace_endpos[1] );
	trap_WriteCoord( MSG_MULTICAST, g_globalvars.trace_endpos[2] );

	trap_multicast( PASSVEC3( org ), MULTICAST_PHS );

	VectorScale( g_globalvars.v_forward, 4, tmp );
	VectorAdd( g_globalvars.trace_endpos, tmp, tmp );
	LightningDamage( self->s.v.origin, tmp, self, 30 );
}