Ejemplo n.º 1
0
//=========================================================
// CheckRangeAttack2 - toss grenade is enemy gets in the way and is too close. 
//=========================================================
BOOL CHAssassin :: CheckRangeAttack2 ( float flDot, float flDist )
{
	m_fThrowGrenade = FALSE;
	if ( !FBitSet ( m_hEnemy->pev->flags, FL_ONGROUND ) )
	{
		// don't throw grenades at anything that isn't on the ground!
		return FALSE;
	}

	// don't get grenade happy unless the player starts to piss you off
	if ( m_iFrustration <= 2)
		return FALSE;

	if ( m_flNextGrenadeCheck < gpGlobals->time && !HasConditions( bits_COND_ENEMY_OCCLUDED ) && flDist <= 512 /* && flDot >= 0.5 */ /* && NoFriendlyFire() */ )
	{
		Vector vecToss = VecCheckThrow( pev, GetGunPosition( ), m_hEnemy->Center(), flDist, 0.5 ); // use dist as speed to get there in 1 second

		if ( vecToss != g_vecZero )
		{
			m_vecTossVelocity = vecToss;

			// throw a hand grenade
			m_fThrowGrenade = TRUE;

			return TRUE;
		}
	}

	return FALSE;
}
Ejemplo n.º 2
0
bool CEntity::FBoxVisible(CEntity *pEntity, Vector *pvHit, unsigned char *ucBodyPart)
{
    if (ucBodyPart)
        *ucBodyPart = 0;

    // don't look through water
    if (IsInWater() != pEntity->IsInWater())
        return false;

    bool            fVisible = false;
    traceresult_t   tr;

    // Check direct Line to waist
    Vector vecLookerOrigin = GetGunPosition();
    Vector vecTarget = pEntity->GetOrigin();
    tr = TestLine(vecLookerOrigin, vecTarget, true, NULL);
    if (tr.fraction >= 1.0) {
        if (pvHit)
            *pvHit = tr.endpos;
        if (ucBodyPart)
            *ucBodyPart |= WAIST_VISIBLE;
        fVisible = true;
    }

    // Check direct Line to head
    vecTarget = pEntity->GetGunPosition();
    tr = TestLine(vecLookerOrigin, vecTarget, true, NULL);
    if (tr.fraction >= 1.0) {
        if (pvHit)
            *pvHit = tr.endpos;
        if (ucBodyPart)
            *ucBodyPart |= HEAD_VISIBLE;
        fVisible = true;
    }

    if (fVisible)
        return true;

    // Nothing visible - check randomly other parts of body
    for (int i = 0; i < 5; i++) {
        vecTarget.x = RandomFloat(pEntity->GetAbsMin().x, pEntity->GetAbsMax().x);
        vecTarget.y = RandomFloat(pEntity->GetAbsMin().y, pEntity->GetAbsMax().y);
        vecTarget.z = RandomFloat(pEntity->GetAbsMin().z, pEntity->GetAbsMax().z);

        tr = TestLine(vecLookerOrigin, vecTarget, true, NULL);

        if (tr.fraction == 1.0) {
            // Return seen position
            if (pvHit)
                *pvHit = tr.endpos;
            if (ucBodyPart)
                *ucBodyPart |= CUSTOM_VISIBLE;
            return true;
        }
    }

    return false; // it's invisible
}
Ejemplo n.º 3
0
//=========================================================
// FVisible - returns true if a line can be traced from
// the caller's eyes to the target
//=========================================================
bool CEntity::FVisible(const Vector &vecDest)
{
    // don't look through water
    if (IsLiquid(GetGunPosition()) != IsLiquid(vecDest))
        return false;

    // check if line of sight to object is not blocked (i.e. visible)
    return (TestLine(EyePosition(), vecDest).fraction >= 1.0);
}
Ejemplo n.º 4
0
//=========================================================
// FInViewCone - returns true is the passed vector is in
// the caller's forward view cone.
//=========================================================
bool CEntity::FInViewCone(Vector *pOrigin, float fov)
{
    if (fov <= 0)
        fov = GetFov();

    Vector forward;
    GetViewAngles().AngleVectors(&forward);

    Vector vecLOS = (*pOrigin - GetGunPosition()).Normalize();
    float flDot = DotProduct(vecLOS, forward);

    return (flDot >= cos((fov / 2) * (M_PI / 180)));
}
Ejemplo n.º 5
0
void Bot::FocusEnemy (void)
{
   // aim for the head and/or body
   Vector enemyOrigin = GetAimPosition ();
   m_lookAt = enemyOrigin;

   if (m_enemySurpriseTime > engine->GetTime ())
      return;

   enemyOrigin = (enemyOrigin - GetGunPosition ()).SkipZ ();

   float distance = enemyOrigin.GetLength ();  // how far away is the enemy scum?

   if (distance < 128)
   {
      if (m_currentWeapon == WEAPON_KNIFE)
      {
         if (distance < 80.0f)
            m_wantsToFire = true;
      }
      else
         m_wantsToFire = true;
   }
   else
   {
      if (m_currentWeapon == WEAPON_KNIFE)
         m_wantsToFire = true;
      else
      {
         float dot = GetShootingConeDeviation (GetEntity (), &m_enemyOrigin);

         if (dot < 0.90)
            m_wantsToFire = false;
         else
         {
            float enemyDot = GetShootingConeDeviation (m_enemy, &pev->origin);

            // enemy faces bot?
            if (enemyDot >= 0.90)
               m_wantsToFire = true;
            else
            {
               if (dot > 0.99)
                  m_wantsToFire = true;
               else
                  m_wantsToFire = false;
            }
         }
      }
   }
}
Ejemplo n.º 6
0
//=========================================================
// Shoot
//=========================================================
void CHAssassin :: Shoot ( void )
{
	if (m_hEnemy == NULL)
	{
		return;
	}

	Vector vecShootOrigin = GetGunPosition();
	Vector vecShootDir = ShootAtEnemy( vecShootOrigin );

	if (m_flLastShot + 2 < gpGlobals->time)
	{
		m_flDiviation = 0.10;
	}
	else
	{
		m_flDiviation -= 0.01;
		if (m_flDiviation < 0.02)
			m_flDiviation = 0.02;
	}
	m_flLastShot = gpGlobals->time;

	UTIL_MakeVectors ( pev->angles );

	Vector	vecShellVelocity = gpGlobals->v_right * RANDOM_FLOAT(40,90) + gpGlobals->v_up * RANDOM_FLOAT(75,200) + gpGlobals->v_forward * RANDOM_FLOAT(-40, 40);
	EjectBrass ( pev->origin + gpGlobals->v_up * 32 + gpGlobals->v_forward * 12, vecShellVelocity, pev->angles.y, m_iShell, TE_BOUNCE_SHELL); 
	FireBullets(1, vecShootOrigin, vecShootDir, Vector( m_flDiviation, m_flDiviation, m_flDiviation ), 2048, BULLET_MONSTER_9MM ); // shoot +-8 degrees

	switch(RANDOM_LONG(0,1))
	{
	case 0:
		EMIT_SOUND(ENT(pev), CHAN_WEAPON, "weapons/pl_gun1.wav", RANDOM_FLOAT(0.6, 0.8), ATTN_NORM);
		break;
	case 1:
		EMIT_SOUND(ENT(pev), CHAN_WEAPON, "weapons/pl_gun2.wav", RANDOM_FLOAT(0.6, 0.8), ATTN_NORM);
		break;
	}

	pev->effects |= EF_MUZZLEFLASH;

	Vector angDir = UTIL_VecToAngles( vecShootDir );
	SetBlending( 0, angDir.x );

	m_cAmmoLoaded--;
}
Ejemplo n.º 7
0
//=========================================================
// CheckRangeAttack1  - drop a cap in their ass
//
//=========================================================
BOOL CHAssassin :: CheckRangeAttack1 ( float flDot, float flDist )
{
	if ( !HasConditions( bits_COND_ENEMY_OCCLUDED ) && flDist > 64 && flDist <= 2048 /* && flDot >= 0.5 */ /* && NoFriendlyFire() */ )
	{
		TraceResult	tr;

		Vector vecSrc = GetGunPosition();

		// verify that a bullet fired from the gun will hit the enemy before the world.
		UTIL_TraceLine( vecSrc, m_hEnemy->BodyTarget(vecSrc), dont_ignore_monsters, ENT(pev), &tr);

		if ( tr.flFraction == 1 || tr.pHit == m_hEnemy->edict() )
		{
			return TRUE;
		}
	}
	return FALSE;
}
Ejemplo n.º 8
0
bool RadioCreate( edict_t *pEntity )
{
	// Create the radio and stick to the wall

	entvars_t *pPev = VARS( pEntity );

	if (pPev->iuser1 > 0) return 0;


	// make sure we dont already have a radio

	int radiocount = 0;
	int i = 1;
	char *pClassname;
	edict_t *frontEnt;

	for (i; i < 1025; i++) {

		frontEnt = INDEXENT ( i );
		if (frontEnt) {
			pClassname =  (char *)STRING(frontEnt->v.classname); 
			if (FStrEq("building_radio", pClassname)) {

				if (frontEnt->v.euser4 == pEntity) 
				{
					radiocount++;
				}
			}
		}
	}

	
	if (AdminLoggedIn[ENTINDEX(pEntity)] == 0)
	{
		if (radiocount >= 2) {
			ClientPrint( pPev, HUD_PRINTTALK, "* Cant have more than 2 radios!\n");
			return 0;
		}
	}

	UTIL_MakeVectors( pPev->v_angle + pPev->punchangle );
	Vector vecSrc	 = GetGunPosition( pEntity );
	Vector vecAiming = gpGlobals->v_forward;

	TraceResult tr;

	UTIL_TraceLine( vecSrc, vecSrc + vecAiming * 128, dont_ignore_monsters, pEntity , &tr );

	if (tr.flFraction < 1.0 || AdminLoggedIn[ENTINDEX(pEntity)])
	{

		
		if (tr.pHit && !(tr.pHit->v.flags & FL_CONVEYOR) && (FStrEq((char *)STRING(tr.pHit->v.classname), "worldspawn") || FStrEq((char *)STRING(tr.pHit->v.classname), "func_wall") || AdminLoggedIn[ENTINDEX(pEntity)] || FStrEq((char *)STRING(tr.pHit->v.classname), "building_dancemachine")))	// Make sure it isnt a conveyor!
		{
			Vector angles = UTIL_VecToAngles( tr.vecPlaneNormal );

			if ((angles.x > 30 || angles.x < -30) && AdminLoggedIn[ENTINDEX(pEntity)] == 0)
			{
				ClientPrint( pPev, HUD_PRINTTALK, "* Can't place radios on floors or cielings!\n");
				return 0;
			}
			// Create the camera here!
			Vector vecOri = tr.vecEndPos + tr.vecPlaneNormal * 14;
			//Vector vecOri = tr.vecEndPos + tr.vecPlaneNormal * 15;

			int maxdist = (int)CVAR_GET_FLOAT("sa_radiospread");

			// make sure we arent placing it within 400 units of another radio
			for (i=1; i < 1025; i++) {

				frontEnt = INDEXENT ( i );
				if (frontEnt) {
					pClassname =  (char *)STRING(frontEnt->v.classname); 
					if (FStrEq("building_radio", pClassname)) {
						
						if ((frontEnt->v.origin - vecOri).Length() < maxdist && AdminLoggedIn[ENTINDEX(pEntity)] == 0)
						{
							ClientPrint( pPev, HUD_PRINTTALK, "* Can't place a radio so close to another radio!\n");
							return 0;
						}
					}
				}
			}

			KeyValueData	kvd;
			
			//edict_t *pent = CREATE_ENTITY();
			//edict_t *pent = CREATE_NAMED_ENTITY(MAKE_STRING("info_target"));

			edict_t *tEntity;
			tEntity = CREATE_NAMED_ENTITY(MAKE_STRING("info_target"));
		
			entvars_t *pRunOnPev;
			pRunOnPev =  VARS(tEntity);
			
			char buf[80];
			sprintf( buf, "%s", "building_radio");

			// Set the KEYVALUES here!
			kvd.fHandled = FALSE;
			kvd.szClassName = NULL;
			kvd.szKeyName = "classname";
			kvd.szValue = buf;

			DispatchKeyValue( tEntity, &kvd );

			// place this in front

			pRunOnPev->origin = vecOri;
			SET_ORIGIN( tEntity , vecOri );
			pRunOnPev->angles = angles;

			//DispatchSpawn( ENT( pRunOnPev ) );

			pRunOnPev->solid = SOLID_BBOX;

			SET_MODEL( ENT( pRunOnPev ) , "avatar-x/avadd16.avfil");
			UTIL_SetSize( pRunOnPev, Vector( -2, -2 ,-2) - (tr.vecPlaneNormal * 15), Vector(2, 2, 16) - (tr.vecPlaneNormal * 15));
			
			pRunOnPev->takedamage = DAMAGE_YES;
			pRunOnPev->max_health = 40 + 10000;
			pRunOnPev->health = 40 + 10000;
			pRunOnPev->euser4 = pEntity;
			
			/*
			edict_t *pent;
			pent = CREATE_NAMED_ENTITY(MAKE_STRING("xen_tree"));
			entvars_t *pv = VARS( pent );
			
			pv->origin = vecOri;
			SET_ORIGIN(pent, vecOri);

			kvd.fHandled = FALSE;
			kvd.szClassName = NULL;
			kvd.szKeyName = "classname";
			kvd.szValue = "xen_tree";
			DispatchKeyValue( pent, &kvd );

			DispatchSpawn(pent);
			//pev->angles = angles;
			
			
			*/

			//pev->iuser1 = angles.y;
			//pv->vuser3 = angles;

			// for now don't take damage
			//pev->takedamage = DAMAGE_YES;
			//pev->max_health = 40 + 10000;
			//pev->health = 40 + 10000;

			/*
			// Call the SPAWN routine to set more stuff
			kvd.fHandled = FALSE;
			kvd.szClassName = NULL;
			kvd.szKeyName = "classname";
			kvd.szValue = "building_radio";
			//DispatchKeyValue( pent, &kvd );
			kvd.fHandled = FALSE;

			

			
			*/

			RadioSpawn( tEntity );
	
			return 1;
		}
		else
		{
			ClientPrint( pPev, HUD_PRINTTALK, "* Couldn't place radio here!\n");
			return 0;
		}
		
	}
	else
	{
		ClientPrint( pPev, HUD_PRINTTALK, "* Couldn't place radio here!\n");
		
	}
	return 0;
}
Ejemplo n.º 9
0
//=========================================================
// HandleAnimEvent - catches the monster-specific messages
// that occur when tagged animation frames are played.
//=========================================================
void CZombie :: HandleAnimEvent( MonsterEvent_t *pEvent )
{
	switch( pEvent->event )
	{
		case ZOMBIE_AE_ATTACK_RANGE:
		{
			Vector vecToss;
			UTIL_MakeAimVectors ( pev->angles );
			vecToss = VecCheckThrow( pev, GetGunPosition(), m_vecEnemyLKP, 750, 1 );

			AttackMissSound();
			CGuts::ShootGuts(pev, GetGunPosition(), vecToss);
		}
		break;

		case ZOMBIE_AE_ATTACK_RIGHT:
		{
			// do stuff for this event.
			CBaseEntity *pHurt = CheckTraceHullAttack( 70, zombie_dmg_melee.value, DMG_SLASH );
			if ( pHurt )
			{
				if ( pHurt->pev->flags & (FL_MONSTER|FL_CLIENT) )
				{
					pHurt->pev->punchangle.z = -18;
					pHurt->pev->punchangle.x = 5;
					pHurt->pev->velocity = pHurt->pev->velocity - gpGlobals->v_right * 100;
				}
				AttackHitSound();
			}
			else
				AttackMissSound();

			if (RANDOM_LONG(0,1))
				AttackSound();
		}
		break;

		case ZOMBIE_AE_ATTACK_LEFT:
		{
			// do stuff for this event.
			CBaseEntity *pHurt = CheckTraceHullAttack( 70, zombie_dmg_melee.value, DMG_SLASH );
			if ( pHurt )
			{
				if ( pHurt->pev->flags & (FL_MONSTER|FL_CLIENT) )
				{
					pHurt->pev->punchangle.z = 18;
					pHurt->pev->punchangle.x = 5;
					pHurt->pev->velocity = pHurt->pev->velocity + gpGlobals->v_right * 100;
				}
				AttackHitSound();
			}
			else
				AttackMissSound();

			if (RANDOM_LONG(0,1))
				AttackSound();
		}
		break;

		case ZOMBIE_AE_ATTACK_BOTH:
		{
			// do stuff for this event.
			CBaseEntity *pHurt = CheckTraceHullAttack( 70, zombie_dmg_melee.value*2, DMG_SLASH );
			if ( pHurt )
			{
				if ( pHurt->pev->flags & (FL_MONSTER|FL_CLIENT) )
				{
					pHurt->pev->punchangle.x = 5;
					pHurt->pev->velocity = pHurt->pev->velocity + gpGlobals->v_forward * -100;
				}
				AttackHitSound();
			}
			else
				AttackMissSound();

			if (RANDOM_LONG(0,1))
				AttackSound();
		}
		break;

		default:
			CBaseMonster::HandleAnimEvent( pEvent );
			break;
	}
}
Ejemplo n.º 10
0
bool DanceCreate( edict_t *pEntity )
{
	// Create the dance machine

	entvars_t *pPev = VARS( pEntity );


	if (AdminLoggedIn[ENTINDEX(pEntity)] == 0)
	{
		ClientPrint( pPev, HUD_PRINTTALK, "* Admin only feature\n");
		return 0;
	}

	UTIL_MakeVectors( pPev->v_angle + pPev->punchangle );
	Vector vecSrc	 = GetGunPosition( pEntity );
	Vector vecAiming = gpGlobals->v_forward;

	TraceResult tr;

	UTIL_TraceLine( vecSrc, vecSrc + vecAiming * 128, dont_ignore_monsters, pEntity , &tr );

	//if (tr.flFraction < 1.0)
	//{
	
			Vector angles = UTIL_VecToAngles( tr.vecPlaneNormal );

			// Create the paper here!
			KeyValueData	kvd;
			
			edict_t *tEntity;
			tEntity = CREATE_NAMED_ENTITY(MAKE_STRING("info_target"));
		
			entvars_t *pRunOnPev;
			pRunOnPev =  VARS(tEntity);
			
			// Set the KEYVALUES here!
			kvd.fHandled = FALSE;
			kvd.szClassName = NULL;
			kvd.szKeyName = "classname";
			kvd.szValue = "building_dancemachine";

			DispatchKeyValue( tEntity, &kvd );

			// place this in front
			Vector vecOri = tr.vecEndPos;
			pRunOnPev->origin = vecOri;
			pRunOnPev->solid = SOLID_BBOX;

			SET_ORIGIN( tEntity , vecOri );
			pRunOnPev->angles = angles;
			pRunOnPev->solid = SOLID_BBOX;

			SET_MODEL( ENT( pRunOnPev ) , "models/sphere.mdl");

			UTIL_SetSize( pRunOnPev, Vector( -16, -16 , -16), Vector(16, 16, 16) );

			pRunOnPev->takedamage = DAMAGE_NO;
			pRunOnPev->max_health = 40 + 10000;
			pRunOnPev->health = 40 + 10000;
			pRunOnPev->euser4 = pEntity;
			pRunOnPev->movetype = MOVETYPE_FLY;

			//DROP_TO_FLOOR( tEntity );


			// play deploy sound
			EMIT_SOUND_DYN2( tEntity, CHAN_VOICE, "weapons/mine_deploy.wav", 1.0, ATTN_NORM , 0, 100);
			//unOnPev->iuser2 = pRunOnPev->euser4->v.team; // Set the team this radio belongs to
			pRunOnPev->nextthink = gpGlobals->time + 1;
			
			pRunOnPev->avelocity.y = 50;
	
			sprintf( EntData[ENTINDEX(tEntity)].digitgroup, "%s", Cmd_Argv(1));

			if (FStrEq(Cmd_Argv(2), "rot"))
			{
				// rotates. get the distance, angular speed, and initial angle

				pRunOnPev->iuser1 = atoi(Cmd_Argv(3));
				pRunOnPev->fuser1 = atof(Cmd_Argv(4));
				pRunOnPev->iuser3 = atoi(Cmd_Argv(5));
	
				// mark original origin
				pRunOnPev->vuser1 = pEntity->v.origin;
				pRunOnPev->avelocity.y = 0;
	
			}


			
	return 0;
}
Ejemplo n.º 11
0
//=========================================================
// HandleAnimEvent - catches the monster-specific messages
// that occur when tagged animation frames are played.
//
// Returns number of events handled, 0 if none.
//=========================================================
void CFriend :: HandleAnimEvent( MonsterEvent_t *pEvent )
{
	Vector	vecGunPos;
	Vector	vecGunAngles;

	GetAttachment( 0, vecGunPos, vecGunAngles );

	switch( pEvent->event )
	{
	case HGRUNT_AE_BURST1:
		BarneyFirePistol();
		break;
//sys	
	case HGRUNT_AE_BURST2:
	case HGRUNT_AE_BURST3:
		BarneyFirePistol();
		break;
/*
	case HGRUNT_AE_KICK:
	{
		CBaseEntity *pHurt = Kick();

		if ( pHurt )
		{
			// SOUND HERE!
			UTIL_MakeVectors( pev->angles );
			pHurt->pev->punchangle.x = 15;
			pHurt->pev->velocity = pHurt->pev->velocity + gpGlobals->v_forward * 100 + gpGlobals->v_up * 50;
			pHurt->TakeDamage( pev, pev, gSkillData.hgruntDmgKick, DMG_CLUB );
		}
	}
	break;
*/
		case HGRUNT_AE_DROP_GUN:
			{
				//SP: si tiene el flag de "no tirar arma" cerrar con break y no ejecutar
				//mas codigo
				if (pev->spawnflags & SF_MONSTER_NO_WPN_DROP) break; //LRC

				Vector	vecGunPos;
				Vector	vecGunAngles;

				GetAttachment( 0, vecGunPos, vecGunAngles );

				SetBodygroup( GUN_GROUP, GUN_NONE );

				CBaseEntity *pItem;

				// now spawn a gun.
				//if (FBitSet( pev->weapons, HGRUNT_SHOTGUN ))
				if (pev->frags)
				{
					pItem = DropItem( "weapon_shotgun", vecGunPos, vecGunAngles );
					pItem->pev->spawnflags |= SF_NORESPAWN; // No respawn
				}
				else
				{
					pItem = DropItem( "weapon_m16", vecGunPos, vecGunAngles );
					pItem->pev->spawnflags |= SF_NORESPAWN; // No respawn
				}
				
			//if -> crash, remove the following	
			//	pItem->pev->avelocity = Vector ( RANDOM_FLOAT( -222, 222 ), RANDOM_FLOAT( -222, 222 ),RANDOM_FLOAT( -222, 222 ) );
			}
		break;

	case HGRUNT_AE_RELOAD:
		EMIT_SOUND( ENT(pev), CHAN_WEAPON, "hgrunt/gr_reload1.wav", 1, ATTN_NORM );
		m_cAmmoLoaded = m_cClipSize;
		ClearConditions(bits_COND_NO_AMMO_LOADED);
				
//		DropItem( "item_clip_rifle", vecGunPos, vecGunAngles );//test
		break;

	case FBARNEY_AE_DRAW:
		if (pev->frags)//shotgun
		SetBodygroup( GUN_GROUP, GUN_SHOTGUN );
		else
		SetBodygroup( GUN_GROUP, GUN_MP5 );

		m_fGunDrawn = TRUE;
		break;
	
	case HGRUNT_AE_GREN_DROP:
		{
			UTIL_MakeVectors( pev->angles );		
		
			CGrenade::ShootTimed( pev, pev->origin + gpGlobals->v_forward * 17 - gpGlobals->v_right * 27 + gpGlobals->v_up * 6, g_vecZero, 3 );
		}
		break;
	
	case HGRUNT_AE_GREN_TOSS:
		{
			UTIL_MakeVectors( pev->angles );
			// CGrenade::ShootTimed( pev, pev->origin + gpGlobals->v_forward * 34 + Vector (0, 0, 32), m_vecTossVelocity, 3.5 );
			
			CGrenade::ShootTimed( pev, GetGunPosition(), m_vecTossVelocity, 3.5 );

			m_fThrowGrenade = FALSE;
			m_flNextGrenadeCheck = gpGlobals->time + 6;// wait six seconds before even looking again to see if a grenade can be thrown.
		}
		break;

	default:
		CTalkMonster::HandleAnimEvent( pEvent );
	}
}
Ejemplo n.º 12
0
//=========================================================
// CheckRangeAttack2 - this checks the Grunt's grenade
// attack. 
//=========================================================
BOOL CFriend :: CheckRangeAttack2 ( float flDot, float flDist )
{	
	// if the grunt isn't moving, it's ok to check.
	if ( m_flGroundSpeed != 0 )
	{
		m_fThrowGrenade = FALSE;
		return m_fThrowGrenade;
	}

	// assume things haven't changed too much since last time
	if (gpGlobals->time < m_flNextGrenadeCheck )
	{
		return m_fThrowGrenade;
	}

	if ( !FBitSet ( m_hEnemy->pev->flags, FL_ONGROUND ) && m_hEnemy->pev->waterlevel == 0 && m_vecEnemyLKP.z > pev->absmax.z  )
	{
		//!!!BUGBUG - we should make this check movetype and make sure it isn't FLY? Players who jump a lot are unlikely to 
		// be grenaded.
		// don't throw grenades at anything that isn't on the ground!
		m_fThrowGrenade = FALSE;
		return m_fThrowGrenade;
	}
	
	Vector vecTarget;

	// find feet
	if (RANDOM_LONG(0,1))
	{
		// magically know where they are
		vecTarget = Vector( m_hEnemy->pev->origin.x, m_hEnemy->pev->origin.y, m_hEnemy->pev->absmin.z );
	}
	else
	{
		// toss it to where you last saw them
		vecTarget = m_vecEnemyLKP;
	}
	// vecTarget = m_vecEnemyLKP + (m_hEnemy->BodyTarget( pev->origin ) - m_hEnemy->pev->origin);
	// estimate position
	// vecTarget = vecTarget + m_hEnemy->pev->velocity * 2;
	
	if ( ( vecTarget - pev->origin ).Length2D() <= 256 )
	{
		// crap, I don't want to blow myself up
		m_flNextGrenadeCheck = gpGlobals->time + 1; // one full second.
		m_fThrowGrenade = FALSE;
		return m_fThrowGrenade;
	}

	Vector vecToss = VecCheckToss( pev, GetGunPosition(), vecTarget, 0.5 );

	if ( vecToss != g_vecZero )
	{
		m_vecTossVelocity = vecToss;

		// throw a hand grenade
		m_fThrowGrenade = TRUE;
		// don't check again for a while.
		m_flNextGrenadeCheck = gpGlobals->time; // 1/3 second.
	}
	else
	{
		// don't throw
		m_fThrowGrenade = FALSE;
		// don't check again for a while.
		m_flNextGrenadeCheck = gpGlobals->time + 1; // one full second.
	}
	

	return m_fThrowGrenade;
}