Exemple #1
0
/*
================
FireBullets

Go to the trouble of combining multiple pellets into a single damage call.

This version is used by Monsters.
================
*/
void CBaseEntity::FireBullets(ULONG cShots, Vector vecSrc, Vector vecDirShooting, Vector vecSpread, float flDistance, int iBulletType, int iTracerFreq, int iDamage, entvars_t *pevAttacker )
{
	static int tracerCount;
	int tracer;
	TraceResult tr;
	Vector vecRight = gpGlobals->v_right;
	Vector vecUp = gpGlobals->v_up;

	if ( pevAttacker == NULL )
		pevAttacker = pev;  // the default attacker is ourselves

	ClearMultiDamage();
	gMultiDamage.type = DMG_BULLET | DMG_NEVERGIB;

	for (ULONG iShot = 1; iShot <= cShots; iShot++)
	{
		// get circular gaussian spread
		float x, y, z;
		do {
			x = RANDOM_FLOAT(-0.5,0.5) + RANDOM_FLOAT(-0.5,0.5);
			y = RANDOM_FLOAT(-0.5,0.5) + RANDOM_FLOAT(-0.5,0.5);
			z = x*x+y*y;
		} while (z > 1);

		Vector vecDir = vecDirShooting +
						x * vecSpread.x * vecRight +
						y * vecSpread.y * vecUp;
		Vector vecEnd;

		vecEnd = vecSrc + vecDir * flDistance;
		UTIL_TraceLine(vecSrc, vecEnd, dont_ignore_monsters, ENT(pev)/*pentIgnore*/, &tr);

		tracer = 0;
		if (iTracerFreq != 0 && (tracerCount++ % iTracerFreq) == 0)
		{
			Vector vecTracerSrc;

			if ( IsPlayer() )
			{// adjust tracer position for player
				vecTracerSrc = vecSrc + Vector ( 0 , 0 , -4 ) + gpGlobals->v_right * 2 + gpGlobals->v_forward * 16;
			}
			else
			{
				vecTracerSrc = vecSrc;
			}
			
			if ( iTracerFreq != 1 )		// guns that always trace also always decal
				tracer = 1;
			switch( iBulletType )
			{
			case BULLET_MONSTER_MP5:
			case BULLET_MONSTER_9MM:
			case BULLET_MONSTER_12MM:
			default:
				MESSAGE_BEGIN( MSG_PAS, SVC_TEMPENTITY, vecTracerSrc );
					WRITE_BYTE( TE_TRACER );
					WRITE_COORD( vecTracerSrc.x );
					WRITE_COORD( vecTracerSrc.y );
					WRITE_COORD( vecTracerSrc.z );
					WRITE_COORD( tr.vecEndPos.x );
					WRITE_COORD( tr.vecEndPos.y );
					WRITE_COORD( tr.vecEndPos.z );
				MESSAGE_END();
				break;
			}
		}
		// do damage, paint decals
		if (tr.flFraction != 1.0)
		{
			CBaseEntity *pEntity = CBaseEntity::Instance(tr.pHit);

			if ( iDamage )
			{
				pEntity->TraceAttack(pevAttacker, iDamage, vecDir, &tr, DMG_BULLET | ((iDamage > 16) ? DMG_ALWAYSGIB : DMG_NEVERGIB) );
				
				TEXTURETYPE_PlaySound(&tr, vecSrc, vecEnd, iBulletType);
				DecalGunshot( &tr, iBulletType );
			} 
			else switch(iBulletType)
			{
			default:
			case BULLET_MONSTER_9MM:
				pEntity->TraceAttack(pevAttacker, gSkillData.monDmg9MM, vecDir, &tr, DMG_BULLET);
				
				TEXTURETYPE_PlaySound(&tr, vecSrc, vecEnd, iBulletType);
				DecalGunshot( &tr, iBulletType );

				break;

			case BULLET_MONSTER_MP5:
				pEntity->TraceAttack(pevAttacker, gSkillData.monDmgMP5, vecDir, &tr, DMG_BULLET);
				
				TEXTURETYPE_PlaySound(&tr, vecSrc, vecEnd, iBulletType);
				DecalGunshot( &tr, iBulletType );

				break;

			case BULLET_MONSTER_12MM:		
				pEntity->TraceAttack(pevAttacker, gSkillData.monDmg12MM, vecDir, &tr, DMG_BULLET); 
				if ( !tracer )
				{
					TEXTURETYPE_PlaySound(&tr, vecSrc, vecEnd, iBulletType);
					DecalGunshot( &tr, iBulletType );
				}
				break;
			
			case BULLET_NONE: // FIX 
				pEntity->TraceAttack(pevAttacker, 50, vecDir, &tr, DMG_CLUB);
				TEXTURETYPE_PlaySound(&tr, vecSrc, vecEnd, iBulletType);
				// only decal glass
				if ( !FNullEnt(tr.pHit) && VARS(tr.pHit)->rendermode != 0)
				{
					UTIL_DecalTrace( &tr, DECAL_GLASSBREAK1 + RANDOM_LONG(0,2) );
				}

				break;
			}
		}
		// make bullet trails
		UTIL_BubbleTrail( vecSrc, tr.vecEndPos, (flDistance * tr.flFraction) / 64.0 );
	}
	ApplyMultiDamage(pev, pevAttacker);
}
Exemple #2
0
/*
================
FireBullets

Go to the trouble of combining multiple pellets into a single damage call.

This version is used by Players, uses the random seed generator to sync client and server side shots.
================
*/
Vector CBaseEntity::FireBulletsPlayer ( ULONG cShots, Vector vecSrc, Vector vecDirShooting, Vector vecSpread, float flDistance, int iBulletType, int iTracerFreq, int iDamage, entvars_t *pevAttacker, int shared_rand )
{
	static int tracerCount;
	TraceResult tr;
	Vector vecRight = gpGlobals->v_right;
	Vector vecUp = gpGlobals->v_up;
	float x, y, z;

	if ( pevAttacker == NULL )
		pevAttacker = pev;  // the default attacker is ourselves

	ClearMultiDamage();
	gMultiDamage.type = DMG_BULLET | DMG_NEVERGIB;

	for ( ULONG iShot = 1; iShot <= cShots; iShot++ )
	{
		//Use player's random seed.
		// get circular gaussian spread
		x = UTIL_SharedRandomFloat( shared_rand + iShot, -0.5, 0.5 ) + UTIL_SharedRandomFloat( shared_rand + ( 1 + iShot ) , -0.5, 0.5 );
		y = UTIL_SharedRandomFloat( shared_rand + ( 2 + iShot ), -0.5, 0.5 ) + UTIL_SharedRandomFloat( shared_rand + ( 3 + iShot ), -0.5, 0.5 );
		z = x * x + y * y;

		Vector vecDir = vecDirShooting +
						x * vecSpread.x * vecRight +
						y * vecSpread.y * vecUp;
		Vector vecEnd;

		vecEnd = vecSrc + vecDir * flDistance;
		UTIL_TraceLine(vecSrc, vecEnd, dont_ignore_monsters, ENT(pev)/*pentIgnore*/, &tr);
		
		// do damage, paint decals
		if (tr.flFraction != 1.0)
		{
			CBaseEntity *pEntity = CBaseEntity::Instance(tr.pHit);

			if ( iDamage )
			{
				pEntity->TraceAttack(pevAttacker, iDamage, vecDir, &tr, DMG_BULLET | ((iDamage > 16) ? DMG_ALWAYSGIB : DMG_NEVERGIB) );
				
				TEXTURETYPE_PlaySound(&tr, vecSrc, vecEnd, iBulletType);
				DecalGunshot( &tr, iBulletType );
			} 
			else switch(iBulletType)
			{
			default:
			case BULLET_PLAYER_9MM:		
				pEntity->TraceAttack(pevAttacker, gSkillData.plrDmg9MM, vecDir, &tr, DMG_BULLET); 
				break;

			case BULLET_PLAYER_MP5:		
				pEntity->TraceAttack(pevAttacker, gSkillData.plrDmgMP5, vecDir, &tr, DMG_BULLET); 
				break;

			case BULLET_PLAYER_BUCKSHOT:	
				 // make distance based!
				pEntity->TraceAttack(pevAttacker, gSkillData.plrDmgBuckshot, vecDir, &tr, DMG_BULLET); 
				break;
			
			case BULLET_PLAYER_357:		
				pEntity->TraceAttack(pevAttacker, gSkillData.plrDmg357, vecDir, &tr, DMG_BULLET); 
				break;
				
			case BULLET_NONE: // FIX 
				pEntity->TraceAttack(pevAttacker, 50, vecDir, &tr, DMG_CLUB);
				TEXTURETYPE_PlaySound(&tr, vecSrc, vecEnd, iBulletType);
				// only decal glass
				if ( !FNullEnt(tr.pHit) && VARS(tr.pHit)->rendermode != 0)
				{
					UTIL_DecalTrace( &tr, DECAL_GLASSBREAK1 + RANDOM_LONG(0,2) );
				}

				break;
			}
		}
		// make bullet trails
		UTIL_BubbleTrail( vecSrc, tr.vecEndPos, (flDistance * tr.flFraction) / 64.0 );
	}
	ApplyMultiDamage(pev, pevAttacker);

	return Vector( x * vecSpread.x, y * vecSpread.y, 0.0 );
}
//=========================================================
//=========================================================
void CHornet::Spawn(void)
{
	Precache();

	pev->movetype = MOVETYPE_FLY;
	pev->solid = SOLID_BBOX;
	pev->takedamage = DAMAGE_YES;
	pev->flags |= FL_MONSTER;
	pev->health = 1;// weak!

	if (g_pGameRules->IsMultiplayer())
	{
		// hornets don't live as long in multiplayer
		m_flStopAttack = gpGlobals->time + 3.5;
	}
	else
	{
		m_flStopAttack = gpGlobals->time + 5.0;
	}

	m_flFieldOfView = 0.9; // +- 25 degrees

	if (RANDOM_LONG(1, 5) <= 2)
	{
		m_iHornetType = HORNET_TYPE_RED;
		m_flFlySpeed = HORNET_RED_SPEED;
	}
	else
	{
		m_iHornetType = HORNET_TYPE_ORANGE;
		m_flFlySpeed = HORNET_ORANGE_SPEED;
	}

	SET_MODEL(ENT(pev), "models/hornet.mdl");
	UTIL_SetSize(pev, Vector(-4, -4, -4), Vector(4, 4, 4));

	SetTouch(&CHornet::DieTouch);
	SetThink(&CHornet::StartTrack);

	edict_t *pSoundEnt = pev->owner;
	if (!pSoundEnt)
		pSoundEnt = edict();

	switch (RANDOM_LONG(0, 2))
	{
	case 0:	EMIT_SOUND(pSoundEnt, CHAN_WEAPON, "agrunt/ag_fire1.wav", 1, ATTN_NORM);	break;
	case 1:	EMIT_SOUND(pSoundEnt, CHAN_WEAPON, "agrunt/ag_fire2.wav", 1, ATTN_NORM);	break;
	case 2:	EMIT_SOUND(pSoundEnt, CHAN_WEAPON, "agrunt/ag_fire3.wav", 1, ATTN_NORM);	break;
	}

	if (!FNullEnt(pev->owner) && (pev->owner->v.flags & FL_CLIENT))
	{
		pev->dmg = gSkillData.plrDmgHornet;
	}
	else
	{
		// no real owner, or owner isn't a client. 
		pev->dmg = gSkillData.monDmgHornet;
	}

	SetNextThink(0.1);
	ResetSequenceInfo();
}
//=========================================================
// MakeMonster-  this is the code that drops the monster
//=========================================================
CBaseMonster* CMonsterMaker::MakeMonster( void )
{
	edict_t	*pent;
	entvars_t		*pevCreate;

//	ALERT(at_console,"Making Monster NOW\n");

	pent = CREATE_NAMED_ENTITY( m_iszMonsterClassname );

	if ( FNullEnt( pent ) )
	{
		ALERT ( at_debug, "NULL Ent in MonsterMaker!\n" );
		return NULL;
	}

	pevCreate = VARS( pent );
	pevCreate->origin = pev->origin;
	pevCreate->angles = pev->angles;
	SetBits( pevCreate->spawnflags, SF_MONSTER_FALL_TO_GROUND );

	if (pev->spawnflags & SF_MONSTERMAKER_NO_WPN_DROP)
		SetBits( pevCreate->spawnflags, SF_MONSTER_NO_WPN_DROP);

	// Children hit monsterclip brushes
	if ( pev->spawnflags & SF_MONSTERMAKER_MONSTERCLIP )
		SetBits( pevCreate->spawnflags, SF_MONSTER_HITMONSTERCLIP );

	DispatchSpawn( ENT( pevCreate ) );
	pevCreate->owner = edict();

	//LRC - custom monster behaviour
	CBaseEntity *pEntity = CBaseEntity::Instance( pevCreate );
	CBaseMonster *pMonst = NULL;
	if (pEntity && (pMonst = pEntity->MyMonsterPointer()) != NULL)
	{
		pMonst->m_iClass = this->m_iClass;
		pMonst->m_iPlayerReact = this->m_iPlayerReact;
	}

	if ( !FStringNull( pev->netname ) )
	{
		// if I have a netname (overloaded), give the child monster that name as a targetname
		pevCreate->targetname = pev->netname;
	}

	m_cLiveChildren++;// count this monster
	m_cNumMonsters--;

	if ( m_cNumMonsters == 0 )
	{
		// Disable this forever.  Don't kill it because it still gets death notices
		SetThink( NULL );
		SetUse( NULL );
	}
	else if (m_fActive)
	{
		SetNextThink( m_flDelay );
		SetThink(&CMonsterMaker:: MakerThink );
	}

	return pMonst;
}
Exemple #5
0
//// HOST_SAY
// String comes in as
// say blah blah blah
// or as
// blah blah blah
//
void Host_Say( edict_t *pEntity, int teamonly )
{
	CBasePlayer *client;
	int		j;
	char	*p;
	char	text[128];
	char    szTemp[256];
	const char *cpSay = "say";
	const char *cpSayTeam = "say_team";
	const char *pcmd = CMD_ARGV(0);

	// We can get a raw string now, without the "say " prepended
	if ( CMD_ARGC() == 0 )
		return;

	entvars_t *pev = &pEntity->v;
	CBasePlayer* player = GetClassPtr((CBasePlayer *)pev);

	//Not yet.
	if ( player->m_flNextChatTime > gpGlobals->time )
		 return;

	if ( !stricmp( pcmd, cpSay) || !stricmp( pcmd, cpSayTeam ) )
	{
		if ( CMD_ARGC() >= 2 )
		{
			p = (char *)CMD_ARGS();
		}
		else
		{
			// say with a blank message, nothing to do
			return;
		}
	}
	else  // Raw text, need to prepend argv[0]
	{
		if ( CMD_ARGC() >= 2 )
		{
			sprintf( szTemp, "%s %s", ( char * )pcmd, (char *)CMD_ARGS() );
		}
		else
		{
			// Just a one word command, use the first word...sigh
			sprintf( szTemp, "%s", ( char * )pcmd );
		}
		p = szTemp;
	}

// remove quotes if present
	if (*p == '"')
	{
		p++;
		p[strlen(p)-1] = 0;
	}

	char *pc = NULL;

// make sure the text has content
	for ( pc = p; pc != NULL && *pc != 0; pc++ )
	{
		if ( !isspace( *pc ) )
		{
			pc = NULL;	// we've found an alphanumeric character,  so text is valid
			break;
		}
	}
	if ( pc != NULL )
		return;  // no character found, so say nothing

// turn on color set 2  (color on,  no sound)
	if ( teamonly )
		sprintf( text, "%c(TEAM) %s: ", 2, STRING( pEntity->v.netname ) );
	else
		sprintf( text, "%c%s: ", 2, STRING( pEntity->v.netname ) );

	j = sizeof(text) - 2 - strlen(text);  // -2 for /n and null terminator
	if ( (int)strlen(p) > j )
		p[j] = 0;

	strcat( text, p );
	strcat( text, "\n" );


	player->m_flNextChatTime = gpGlobals->time + CHAT_INTERVAL;

	// loop through all players
	// Start with the first player.
	// This may return the world in single player if the client types something between levels or during spawn
	// so check it, or it will infinite loop

	client = NULL;
	while ( ((client = (CBasePlayer*)UTIL_FindEntityByClassname( client, "player" )) != NULL) && (!FNullEnt(client->edict())) )
	{
		if ( !client->pev )
			continue;

		if ( client->edict() == pEntity )
			continue;

		if ( !(client->IsNetClient()) )	// Not a client ? (should never be true)
			continue;

		// can the receiver hear the sender? or has he muted him?
		if ( g_VoiceGameMgr.PlayerHasBlockedPlayer( client, player ) )
			continue;

		if ( teamonly && g_pGameRules->PlayerRelationship(client, CBaseEntity::Instance(pEntity)) != GR_TEAMMATE )
			continue;

		MESSAGE_BEGIN( MSG_ONE, gmsgSayText, NULL, client->pev );
			WRITE_BYTE( ENTINDEX(pEntity) );
			WRITE_STRING( text );
		MESSAGE_END();

	}

	// print to the sending client
	MESSAGE_BEGIN( MSG_ONE, gmsgSayText, NULL, &pEntity->v );
		WRITE_BYTE( ENTINDEX(pEntity) );
		WRITE_STRING( text );
	MESSAGE_END();

	// echo to server console
	g_engfuncs.pfnServerPrint( text );

	char * temp;
	if ( teamonly )
		temp = "say_team";
	else
		temp = "say";

	// team match?
	if ( g_teamplay )
	{
		UTIL_LogPrintf( "\"%s<%i><%s><%s>\" %s \"%s\"\n",
			STRING( pEntity->v.netname ),
			GETPLAYERUSERID( pEntity ),
			GETPLAYERAUTHID( pEntity ),
			g_engfuncs.pfnInfoKeyValue( g_engfuncs.pfnGetInfoKeyBuffer( pEntity ), "model" ),
			temp,
			p );
	}
	else
	{
		UTIL_LogPrintf( "\"%s<%i><%s><%i>\" %s \"%s\"\n",
			STRING( pEntity->v.netname ),
			GETPLAYERUSERID( pEntity ),
			GETPLAYERAUTHID( pEntity ),
			GETPLAYERUSERID( pEntity ),
			temp,
			p );
	}
}
Exemple #6
0
void NetworkMsg::Execute (void *p)
{
	if (m_message == NETMSG_UNDEFINED)
		return; // no message or not for bot, return

   // some needed variables
   static uint8_t r, g, b;
   static uint8_t enabled;

   static int damageArmor, damageTaken, damageBits;
   static int killerIndex, victimIndex, playerIndex;
   static int index, numPlayers;
   static int state, id, clip;

   static Vector damageOrigin;
   static WeaponProperty weaponProp;

   // now starts of netmessage execution
   switch (m_message)
   {
   case NETMSG_VGUI:
      // this message is sent when a VGUI menu is displayed.
      if (m_state == 0)
      {
         switch (PTR_TO_INT (p))
         {
         case GMENU_TEAM:
            m_bot->m_startAction = CMENU_TEAM;
            break;

         case GMENU_TERRORIST:
         case GMENU_COUNTER:
            m_bot->m_startAction = CMENU_CLASS;
            break;
         }
      }
      break; 

   case NETMSG_SHOWMENU:
      // this message is sent when a text menu is displayed.

      if (m_state < 3) // ignore first 3 fields of message
         break;

	  if (strcmp(PTR_TO_STR(p), "#Team_Select") == 0) // team select menu?
		  m_bot->m_startAction = CMENU_TEAM;
      else if (strcmp (PTR_TO_STR (p), "#Team_Select_Spect") == 0) // team select menu?
         m_bot->m_startAction = CMENU_TEAM;
      else if (strcmp (PTR_TO_STR (p), "#IG_Team_Select_Spect") == 0) // team select menu?
         m_bot->m_startAction = CMENU_TEAM;
      else if (strcmp (PTR_TO_STR (p), "#IG_Team_Select") == 0) // team select menu?
         m_bot->m_startAction = CMENU_TEAM;
      else if (strcmp (PTR_TO_STR (p), "#IG_VIP_Team_Select") == 0) // team select menu?
         m_bot->m_startAction = CMENU_TEAM;
      else if (strcmp (PTR_TO_STR (p), "#IG_VIP_Team_Select_Spect") == 0) // team select menu?
         m_bot->m_startAction = CMENU_TEAM;
	  else if (strcmp(PTR_TO_STR(p), "#Terrorist_Select") == 0) // T model select?
		  m_bot->m_startAction = CMENU_CLASS;
      else if (strcmp (PTR_TO_STR (p), "#CT_Select") == 0) // CT model select menu?
         m_bot->m_startAction = CMENU_CLASS;

      break;

   case NETMSG_WLIST:
      // this message is sent when a client joins the game. All of the weapons are sent with the weapon ID and information about what ammo is used.

      switch (m_state)
      {
      case 0:
         strcpy (weaponProp.className, PTR_TO_STR (p));
         break;

      case 1:
         weaponProp.ammo1 = PTR_TO_INT (p); // ammo index 1
         break;

      case 2:
		  weaponProp.ammo1Max = PTR_TO_INT(p); // max ammo 1
		  break;

      case 5:
         weaponProp.slotID = PTR_TO_INT (p); // slot for this weapon
         break;

      case 6:
         weaponProp.position = PTR_TO_INT (p); // position in slot
         break;

      case 7:
         weaponProp.id = PTR_TO_INT (p); // weapon ID
         break;

      case 8:
         weaponProp.flags = PTR_TO_INT (p); // flags for weapon (WTF???)
         g_weaponDefs[weaponProp.id] = weaponProp; // store away this weapon with it's ammo information...
         break;
      }
      break;

   case NETMSG_CURWEAPON:
      // this message is sent when a weapon is selected (either by the bot chosing a weapon or by the server auto assigning the bot a weapon). In CS it's also called when Ammo is increased/decreased

      switch (m_state)
      {
      case 0:
         state = PTR_TO_INT (p); // state of the current weapon (WTF???)
         break;

      case 1:
         id = PTR_TO_INT (p); // weapon ID of current weapon
         break;

      case 2:
         clip = PTR_TO_INT (p); // ammo currently in the clip for this weapon

         if (id <= 31)
         {
            if (state != 0)
               m_bot->m_currentWeapon = id;

            // ammo amount decreased ? must have fired a bullet...
            if (id == m_bot->m_currentWeapon && m_bot->m_ammoInClip[id] > clip)
            {
               // time fired with in burst firing time ?
               if (m_bot->m_timeLastFired + 1.0f > engine->GetTime ())
                  m_bot->m_burstShotsFired++;

               m_bot->m_timeLastFired = engine->GetTime (); // remember the last bullet time
            }
            m_bot->m_ammoInClip[id] = clip;
         }
         break;
      }
      break;

   case NETMSG_AMMOX:
      // this message is sent whenever ammo amounts are adjusted (up or down). NOTE: Logging reveals that CS uses it very unreliable!

      switch (m_state)
      {
      case 0:
         index = PTR_TO_INT (p); // ammo index (for type of ammo)
         break;

      case 1:
         m_bot->m_ammo[index] = PTR_TO_INT (p); // store it away
         break;
      }
      break;

   case NETMSG_AMMOPICK:
      // this message is sent when the bot picks up some ammo (AmmoX messages are also sent so this message is probably
      // not really necessary except it allows the HUD to draw pictures of ammo that have been picked up.  The bots
      // don't really need pictures since they don't have any eyes anyway.

      switch (m_state)
      {
      case 0:
         index = PTR_TO_INT (p);
         break;

      case 1:
         m_bot->m_ammo[index] = PTR_TO_INT (p);
         break;
      }
      break;

   case NETMSG_DAMAGE:
      // this message gets sent when the bots are getting damaged.
      switch (m_state)
      {
      case 0:
         damageArmor = PTR_TO_INT (p);
         break;

      case 1:
         damageTaken = PTR_TO_INT (p);
         break;

      case 2:
         damageBits = PTR_TO_INT (p);

         if (damageArmor > 0 || damageTaken > 0)
            m_bot->TakeDamage (m_bot->pev->dmg_inflictor, damageTaken, damageArmor, damageBits);
         break;
      }

      break;

   case NETMSG_MONEY:
      // this message gets sent when the bots money amount changes

      if (m_state == 0)
         m_bot->m_moneyAmount = PTR_TO_INT (p); // amount of money
      break;

   case NETMSG_STATUSICON:
	   switch (m_state)
	   {
	   case 0:
		   enabled = PTR_TO_BYTE(p);
		   break;

	   case 1:
		   if (strcmp(PTR_TO_STR(p), "defuser") == 0)
			   m_bot->m_hasDefuser = (enabled != 0);
		   else if (strcmp(PTR_TO_STR(p), "buyzone") == 0)
		   {
			   m_bot->m_inBuyZone = (enabled != 0);
			   m_bot->EquipInBuyzone(0);
		   }
		   else if (strcmp(PTR_TO_STR(p), "vipsafety") == 0)
			   m_bot->m_inVIPZone = (enabled != 0);
		   else if (strcmp(PTR_TO_STR(p), "c4") == 0)
			   m_bot->m_inBombZone = (enabled == 2);

		   break;
	   }
	   break;

   case NETMSG_DEATH: // this message sends on death
      switch (m_state)
      {
      case 0:
         killerIndex = PTR_TO_INT (p);
         break;

      case 1:
         victimIndex = PTR_TO_INT (p);
         break;

      case 2:
		  // SyPB Pro P.45 - Death Msg improve 
		  edict_t *victim = INDEXENT(victimIndex);
		  if (FNullEnt(victim) || !IsValidPlayer(victim))
			  break;

		  Bot *victimer = g_botManager->GetBot(victim);
		  if (victimer != null)
		  {
			  victimer->GetCurrentTask()->data = -1;
			  victimer->DeleteSearchNodes();
		  }

		  /*
		  // SyPB Pro P.40 - Death Msg improve
		  if (killerIndex != victimIndex)
		  {
			  edict_t *killer = INDEXENT(killerIndex);
			  edict_t *victim = INDEXENT(victimIndex);

			  if (FNullEnt(killer) || FNullEnt(victim) || !IsValidPlayer(victim))
				  break;

			  Bot *victimer = g_botManager->GetBot(victim);
			  if (victimer != null)
			  {
				  victimer->GetCurrentTask()->data = -1;
				  victimer->DeleteSearchNodes();
			  }

			  if (!IsZombieEntity(victim) && IsAlive(victim))
				  break;

			  for (int i = 0; i < engine->GetMaxClients(); i++)
			  {
				  Bot *bot = g_botManager->GetBot(i);
				  if (bot == null || !IsAlive(bot->GetEntity()))
					  continue;

				  if (IsZombieEntity(bot->GetEntity()))
					  continue;

				  if (GetGameMod() == 0 && killer != bot->GetEntity() && bot->EntityIsVisible(GetEntityOrigin(victim)) &&
					  GetTeam(killer) == GetTeam(bot->GetEntity()) && GetTeam(killer) != GetTeam(victim))
				  {
					  if (killer == g_hostEntity)
						  bot->HandleChatterMessage("#Bot_NiceShotCommander");
					  else
						  bot->HandleChatterMessage("#Bot_NiceShotPall");

					  break;
				  }

				  if (GetTeam(bot->GetEntity()) == GetTeam(victim) && IsVisible(GetEntityOrigin(killer), bot->GetEntity()) && FNullEnt(bot->m_enemy) && GetTeam(killer) != GetTeam(victim))
				  {
					  // SyPB Pro P.30 - AMXX API
					  if (bot->m_blockCheckEnemyTime > engine->GetTime())
						  continue;

					  bot->m_actualReactionTime = 0.0f;
					  bot->m_seeEnemyTime = engine->GetTime();
					  bot->m_enemy = killer;
					  bot->SetLastEnemy(killer);
				  }
			  }

			  Bot *bot = g_botManager->GetBot(killer);

			  if (bot != null)
				  bot->m_lastVictim = victim;
			  else if (GetGameMod () == 0)
			  {
				  if (victimer != null)
				  {
					  if (GetTeam(killer) == GetTeam(victim))
						  victimer->m_voteKickIndex = killerIndex;

					  victimer->m_notKilled = false;
				  }
			  }
		  } */
		  break;
      }
      break;

   case NETMSG_SCREENFADE: // this message gets sent when the Screen fades (Flashbang)
      switch (m_state)
      {
      case 3:
         r = PTR_TO_BYTE (p);
         break;

      case 4:
         g = PTR_TO_BYTE (p);
         break;

      case 5:
         b = PTR_TO_BYTE (p);
         break;

      case 6:
         m_bot->TakeBlinded (Vector (r, g, b), PTR_TO_BYTE (p));
         break;
      }
      break;

   case NETMSG_HLTV: // round restart in steam cs
	   switch (m_state)
	   {
	   case 0:
		   numPlayers = PTR_TO_INT(p);
		   break;

	   case 1:
		   if (numPlayers == 0 && PTR_TO_INT(p) == 0)
			   RoundInit();
         break;
      }
      break;


   case NETMSG_RESETHUD:
#if 0
      if (m_bot != null)
         m_bot->NewRound ();
#endif
      break;

   case NETMSG_TEXTMSG:
      if (m_state == 1)
      {
         if (FStrEq (PTR_TO_STR (p), "#CTs_Win") ||
            FStrEq (PTR_TO_STR (p), "#Bomb_Defused") ||
            FStrEq (PTR_TO_STR (p), "#Terrorists_Win") ||
            FStrEq (PTR_TO_STR (p), "#Round_Draw") ||
            FStrEq (PTR_TO_STR (p), "#All_Hostages_Rescued") ||
            FStrEq (PTR_TO_STR (p), "#Target_Saved") ||
            FStrEq (PTR_TO_STR (p), "#Hostages_Not_Rescued") ||
            FStrEq (PTR_TO_STR (p), "#Terrorists_Not_Escaped") ||
            FStrEq (PTR_TO_STR (p), "#VIP_Not_Escaped") ||
            FStrEq (PTR_TO_STR (p), "#Escaping_Terrorists_Neutralized") ||
            FStrEq (PTR_TO_STR (p), "#VIP_Assassinated") ||
            FStrEq (PTR_TO_STR (p), "#VIP_Escaped") ||
            FStrEq (PTR_TO_STR (p), "#Terrorists_Escaped") ||
            FStrEq (PTR_TO_STR (p), "#CTs_PreventEscape") ||
            FStrEq (PTR_TO_STR (p), "#Target_Bombed") ||
            FStrEq (PTR_TO_STR (p), "#Game_Commencing") ||
            FStrEq (PTR_TO_STR (p), "#Game_will_restart_in"))
         {
            g_roundEnded = true;

            if (FStrEq (PTR_TO_STR (p), "#Game_Commencing"))
               g_isCommencing = true;

			// SyPB Pro P.29 - msg setting
			if (GetGameMod() == 0)
			{
				if (FStrEq(PTR_TO_STR(p), "#CTs_Win"))
					g_botManager->SetLastWinner(TEAM_COUNTER); // update last winner for economics

				if (FStrEq(PTR_TO_STR(p), "#Terrorists_Win"))
					g_botManager->SetLastWinner(TEAM_TERRORIST); // update last winner for economics
			}

            g_waypoint->SetBombPosition (true);
         }
         else if (!g_bombPlanted && FStrEq (PTR_TO_STR (p), "#Bomb_Planted"))
         {
            g_bombPlanted = true;
            g_bombSayString = true;
            g_timeBombPlanted = engine->GetTime ();

            for (int i = 0; i < engine->GetMaxClients (); i++)
            {
               Bot *bot = g_botManager->GetBot (i);

               if (bot != null && IsAlive (bot->GetEntity ()))
               {
                  bot->DeleteSearchNodes ();
                  bot->ResetTasks ();

                  if (engine->RandomInt (0, 100) < 85 && GetTeam (bot->GetEntity ()) == TEAM_COUNTER)
                     bot->ChatterMessage (Chatter_WhereIsTheBomb);
               }
            }
            g_waypoint->SetBombPosition ();
         }
         else if (m_bot != null && FStrEq (PTR_TO_STR (p), "#Switch_To_BurstFire"))
            m_bot->m_weaponBurstMode = BURST_ENABLED;
         else if (m_bot != null && FStrEq (PTR_TO_STR (p), "#Switch_To_SemiAuto"))
            m_bot->m_weaponBurstMode = BURST_DISABLED;
      }
      break;

   //case NETMSG_SCOREINFO:
	   // SyPB Pro P.45 - TESTTEST
	   /*
	   switch (m_state)
	   {
	   case 0:
		   playerIndex = PTR_TO_INT(p);
		   break;

	   case 4:
		   // SyPB Pro P.29 - msg set team
		   if (playerIndex >= 0 && playerIndex <= engine->GetMaxClients())
			   GetTeam(ENT(playerIndex));
      } */
    //  break;

   case NETMSG_BARTIME:
	   if (m_state == 0)
	   {
		   // SyPB Pro P.34 - Base Change
		   if (GetGameMod() == 0)
		   {
			   if (PTR_TO_INT(p) > 0)
				   m_bot->m_hasProgressBar = true; // the progress bar on a hud
			   else if (PTR_TO_INT(p) == 0)
				   m_bot->m_hasProgressBar = false; // no progress bar or disappeared
		   }
		   else
			   m_bot->m_hasProgressBar = false;
	   }
	   break;

   default:
      AddLogEntry (true, LOG_FATAL, "Network message handler error. Call to unrecognized message id (%d).\n", m_message);
   }
   m_state++; // and finally update network message state
}
Exemple #7
0
void CLeech::SwimThink(void)
{
	TraceResult  tr;
	float        flLeftSide;
	float        flRightSide;
	float        targetSpeed;
	float        targetYaw = 0;
	CBaseEntity *pTarget;

	if(FNullEnt(FIND_CLIENT_IN_PVS(edict())))
	{
		pev->nextthink = gpGlobals->time + RANDOM_FLOAT(1, 1.5);
		pev->velocity  = g_vecZero;
		return;
	}
	else
		pev->nextthink = gpGlobals->time + 0.1;

	targetSpeed = LEECH_SWIM_SPEED;

	if(m_waterTime < gpGlobals->time)
		RecalculateWaterlevel();

	if(m_stateTime < gpGlobals->time)
		SwitchLeechState();

	ClearConditions(bits_COND_CAN_MELEE_ATTACK1);
	switch(m_MonsterState)
	{
	case MONSTERSTATE_COMBAT:
		pTarget = m_hEnemy;
		if(!pTarget)
			SwitchLeechState();
		else
		{
			// Chase the enemy's eyes
			m_height = pTarget->pev->origin.z + pTarget->pev->view_ofs.z - 5;
			// Clip to viable water area
			if(m_height < m_bottom)
				m_height = m_bottom;
			else if(m_height > m_top)
				m_height    = m_top;
			Vector location = pTarget->pev->origin - pev->origin;
			location.z += (pTarget->pev->view_ofs.z);
			if(location.Length() < 40)
				SetConditions(bits_COND_CAN_MELEE_ATTACK1);
			// Turn towards target ent
			targetYaw = UTIL_VecToYaw(location);

			targetYaw = UTIL_AngleDiff(targetYaw, UTIL_AngleMod(pev->angles.y));

			if(targetYaw < (-LEECH_TURN_RATE * 0.75))
				targetYaw = (-LEECH_TURN_RATE * 0.75);
			else if(targetYaw > (LEECH_TURN_RATE * 0.75))
				targetYaw = (LEECH_TURN_RATE * 0.75);
			else
				targetSpeed *= 2;
		}

		break;

	default:
		if(m_zTime < gpGlobals->time)
		{
			float newHeight = RANDOM_FLOAT(m_bottom, m_top);
			m_height        = 0.5 * m_height + 0.5 * newHeight;
			m_zTime         = gpGlobals->time + RANDOM_FLOAT(1, 4);
		}
		if(RANDOM_LONG(0, 100) < 10)
			targetYaw = RANDOM_LONG(-30, 30);
		pTarget       = NULL;
		// oldorigin test
		if((pev->origin - pev->oldorigin).Length() < 1)
		{
			// If leech didn't move, there must be something blocking it, so try to turn
			m_sideTime = 0;
		}

		break;
	}

	m_obstacle     = ObstacleDistance(pTarget);
	pev->oldorigin = pev->origin;
	if(m_obstacle < 0.1)
		m_obstacle = 0.1;

	// is the way ahead clear?
	if(m_obstacle == 1.0)
	{
		// if the leech is turning, stop the trend.
		if(m_flTurning != 0)
		{
			m_flTurning = 0;
		}

		m_fPathBlocked = FALSE;
		pev->speed     = UTIL_Approach(targetSpeed, pev->speed, LEECH_SWIM_ACCEL * LEECH_FRAMETIME);
		pev->velocity  = gpGlobals->v_forward * pev->speed;
	}
	else
	{
		m_obstacle = 1.0 / m_obstacle;
		// IF we get this far in the function, the leader's path is blocked!
		m_fPathBlocked = TRUE;

		if(m_flTurning == 0) // something in the way and leech is not already turning to avoid
		{
			Vector vecTest;
			// measure clearance on left and right to pick the best dir to turn
			vecTest = pev->origin + (gpGlobals->v_right * LEECH_SIZEX) + (gpGlobals->v_forward * LEECH_CHECK_DIST);
			UTIL_TraceLine(pev->origin, vecTest, missile, edict(), &tr);
			flRightSide = tr.flFraction;

			vecTest = pev->origin + (gpGlobals->v_right * -LEECH_SIZEX) + (gpGlobals->v_forward * LEECH_CHECK_DIST);
			UTIL_TraceLine(pev->origin, vecTest, missile, edict(), &tr);
			flLeftSide = tr.flFraction;

			// turn left, right or random depending on clearance ratio
			float delta = (flRightSide - flLeftSide);
			if(delta > 0.1 || (delta > -0.1 && RANDOM_LONG(0, 100) < 50))
				m_flTurning = -LEECH_TURN_RATE;
			else
				m_flTurning = LEECH_TURN_RATE;
		}
		pev->speed    = UTIL_Approach(-(LEECH_SWIM_SPEED * 0.5), pev->speed, LEECH_SWIM_DECEL * LEECH_FRAMETIME * m_obstacle);
		pev->velocity = gpGlobals->v_forward * pev->speed;
	}
	pev->ideal_yaw = m_flTurning + targetYaw;
	UpdateMotion();
}
Exemple #8
0
// Add bot -> ARG1(team), ARG2(skill), ARG3(model), ARG4(name)
int cGame::CreateBot(edict_t * pPlayer, const char *arg1, const char *arg2,
                     const char *arg3, const char *arg4) {
   edict_t *BotEnt;
   cBot *pBot;
   char c_skin[BOT_SKIN_LEN + 1];
   char c_name[BOT_NAME_LEN + 1];

   // clear
   memset(c_skin, 0, sizeof(c_skin));
   memset(c_name, 0, sizeof(c_name));

   int skill;
   int i, j, length;
   if ((arg4 != NULL) && (*arg4 != 0)) {
      strncpy(c_name, arg4, BOT_NAME_LEN - 1);
      c_name[BOT_NAME_LEN] = 0; // make sure c_name is null terminated
   } else {
      if (NamesAvailable())
         SelectName(c_name);
      else
         strcpy(c_name, "RealBot");
   }

   skill = -2;                  // -2, not valid

   if ((arg2 != NULL) && (*arg2 != 0))
      skill = atoi(arg2);       // set to given skill

   // when not valid (-2), it has default skill
   if ((skill < -1) || (skill > 10))
      skill = iDefaultBotSkill;

   // When skill is -1, random, we set it by boundries given
   if (skill == -1)
      skill = RANDOM_LONG(iRandomMinSkill, iRandomMaxSkill);

   // length of name
   length = strlen(c_name);

   // remove any illegal characters from name...
   for (i = 0; i < length; i++) {
      if ((c_name[i] <= ' ') || (c_name[i] > '~') || (c_name[i] == '"')) {
         for (j = i; j < length; j++)   // shuffle chars left (and null)
            c_name[j] = c_name[j + 1];
         length--;
      }
   }

   BotEnt = (*g_engfuncs.pfnCreateFakeClient) (c_name);
   if (FNullEnt(BotEnt)) {
      REALBOT_PRINT(NULL, "cGame::CreateBot",
                    "Cannot create bot, server is full");
      return GAME_MSG_FAIL_SERVERFULL;  // failed
   } else {
      char ptr[128];            // allocate space for message from ClientConnect
      char *infobuffer;
      int clientIndex;
      int index;
      index = 0;
      while ((bots[index].bIsUsed) && (index < 32))
         index++;
      if (index == 32) {
         return GAME_MSG_FAILURE;
      }
      // create the player entity by calling MOD's player function
      // (from LINK_ENTITY_TO_CLASS for player object)

      // FIX: Free data for bot, so we can fill in new
      if (BotEnt->pvPrivateData != NULL)
         FREE_PRIVATE(BotEnt);

      BotEnt->pvPrivateData = NULL;
      BotEnt->v.frags = 0;

      // END OF FIX: --- score resetted
      CALL_GAME_ENTITY(PLID, "player", VARS(BotEnt));
      infobuffer = (*g_engfuncs.pfnGetInfoKeyBuffer) (BotEnt);
      clientIndex = ENTINDEX(BotEnt);

      (*g_engfuncs.pfnSetClientKeyValue) (clientIndex, infobuffer, "model", "");
      (*g_engfuncs.pfnSetClientKeyValue) (clientIndex, infobuffer, "rate", "3500.000000");
      (*g_engfuncs.pfnSetClientKeyValue) (clientIndex, infobuffer, "cl_updaterate", "20");
      (*g_engfuncs.pfnSetClientKeyValue) (clientIndex, infobuffer, "cl_lw", "1");
      (*g_engfuncs.pfnSetClientKeyValue) (clientIndex, infobuffer, "cl_lc", "1");
      (*g_engfuncs.pfnSetClientKeyValue) (clientIndex, infobuffer, "tracker", "0");
      (*g_engfuncs.pfnSetClientKeyValue) (clientIndex, infobuffer, "cl_dlmax", "128");

	  if (RANDOM_LONG(0, 100) < 50) {
         (*g_engfuncs.pfnSetClientKeyValue) (clientIndex, infobuffer, "lefthand", "1");
	  } else {
         (*g_engfuncs.pfnSetClientKeyValue) (clientIndex, infobuffer, "lefthand", "0");
	  }

      (*g_engfuncs.pfnSetClientKeyValue) (clientIndex, infobuffer, "friends", "0");
      (*g_engfuncs.pfnSetClientKeyValue) (clientIndex, infobuffer, "dm", "0");
      (*g_engfuncs.pfnSetClientKeyValue) (clientIndex, infobuffer, "ah", "1");
      (*g_engfuncs.pfnSetClientKeyValue) (clientIndex, infobuffer, "_vgui_menus", "0");

      MDLL_ClientConnect(BotEnt, c_name, "127.0.0.1", ptr);

      // Pieter van Dijk - use instead of DispatchSpawn() - Hip Hip Hurray!
      MDLL_ClientPutInServer(BotEnt);
      BotEnt->v.flags |= FL_THIRDPARTYBOT;

      // initialize all the variables for this bot...

      // Retrieve Pointer
      pBot = &bots[index];

      // Set variables
      pBot->iIndex = index;
      pBot->bIsUsed = true;
      pBot->respawn_state = RESPAWN_IDLE;
      pBot->fCreateTime = gpGlobals->time;
      pBot->fKickTime = 0.0;
      pBot->name[0] = 0;        // name not set by server yet
      pBot->bot_money = 0;
      strcpy(pBot->skin, c_skin);
      pBot->pEdict = BotEnt;
      pBot->bStarted = false;   // hasn't joined game yet

      // CS Message IDLE..
      pBot->start_action = MSG_CS_IDLE;
      pBot->SpawnInit();
      pBot->bInitialize = false;        // don't need to initialize yet
      BotEnt->v.idealpitch = BotEnt->v.v_angle.x;
      BotEnt->v.ideal_yaw = BotEnt->v.v_angle.y;
      BotEnt->v.pitch_speed = BOT_PITCH_SPEED;
      BotEnt->v.yaw_speed = BOT_YAW_SPEED;
      pBot->bot_skill = skill;

      // Personality related
      pBot->ipHostage = 0;
      pBot->ipBombspot = 0;
      pBot->ipRandom = 0;
      pBot->ipTurnSpeed = 20;
      pBot->ipReplyToRadio = 0;
      pBot->ipCreateRadio = 0;
      pBot->ipHelpTeammate = 0;
      pBot->ipWalkWithKnife = 0;
      pBot->ipDroppedBomb = 0;
      pBot->ipCampRate = 0;
      pBot->ipChatRate = 0;
      pBot->ipFearRate = 0;
      pBot->ipHearRate = 0;

      pBot->played_rounds = 0;

      // Buy-personality related
      pBot->ipFavoPriWeapon = -1;
      pBot->ipFavoSecWeapon = -1;
      pBot->ipBuyFlashBang = 0;
      pBot->ipBuyGrenade = 0;
      pBot->ipBuySmokeGren = 0;
      pBot->ipBuyDefuseKit = 0;
      pBot->ipSaveForWeapon = 0;
      pBot->ipBuyArmour = 0;

      // here we set team
      if ((arg1 != NULL) && (arg1[0] != 0)) {
         pBot->iTeam = atoi(arg1);

         // and class
         if ((arg3 != NULL) && (arg3[0] != 0)) {
            pBot->bot_class = atoi(arg3);
         }
      }
      // Parsing name into bot identity
      INI_PARSE_BOTS(c_name, pBot);

      // return success
      return GAME_MSG_SUCCESS;
   }
}                               // CreateBot()
Exemple #9
0
/*
============
TakeDamage

The damage is coming from inflictor, but get mad at attacker
This should be the only function that ever reduces health.
bitsDamageType indicates the type of damage sustained, ie: DMG_SHOCK

Time-based damage: only occurs while the monster is within the trigger_hurt.
When a monster is poisoned via an arrow etc it takes all the poison damage at once.



GLOBALS ASSUMED SET:  g_iSkillLevel
============
*/
int CBaseMonster :: TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType )
{
	float	flTake;
	Vector	vecDir;

	if (!pev->takedamage)
		return 0;

	if ( !IsAlive() )
	{
		return DeadTakeDamage( pevInflictor, pevAttacker, flDamage, bitsDamageType );
	}

	if ( pev->deadflag == DEAD_NO )
	{
		// no pain sound during death animation.
		PainSound();// "Ouch!"
	}

	//!!!LATER - make armor consideration here!
	flTake = flDamage;

	// set damage type sustained
	m_bitsDamageType |= bitsDamageType;

	// grab the vector of the incoming attack. ( pretend that the inflictor is a little lower than it really is, so the body will tend to fly upward a bit).
	vecDir = Vector( 0, 0, 0 );
	if (!FNullEnt( pevInflictor ))
	{
		CBaseEntity *pInflictor = CBaseEntity :: Instance( pevInflictor );
		if (pInflictor)
		{
			vecDir = ( pInflictor->Center() - Vector ( 0, 0, 10 ) - Center() ).Normalize();
			vecDir = g_vecAttackDir = vecDir.Normalize();
		}
	}

	// add to the damage total for clients, which will be sent as a single
	// message at the end of the frame
	// todo: remove after combining shotgun blasts?
	if ( IsPlayer() )
	{
		if ( pevInflictor )
			pev->dmg_inflictor = ENT(pevInflictor);

		pev->dmg_take += flTake;

		// check for godmode or invincibility
		if ( pev->flags & FL_GODMODE )
		{
			return 0;
		}
	}

	// HL: if this is a player, move him around!
	// NS: Don't move players
	if ( ( !FNullEnt( pevInflictor ) ) && (pev->movetype == MOVETYPE_WALK) && (!pevAttacker || pevAttacker->solid != SOLID_TRIGGER) && !IsPlayer())
	{
		pev->velocity = pev->velocity + vecDir * -DamageForce( flDamage );
	}

	// do the damage
	pev->health -= flTake;

	
	// HACKHACK Don't kill monsters in a script.  Let them break their scripts first
	if ( m_MonsterState == MONSTERSTATE_SCRIPT )
	{
		SetConditions( bits_COND_LIGHT_DAMAGE );
		return 0;
	}

	if ( (int)(pev->health) <= 0 )
	{
		g_pevLastInflictor = pevInflictor;

// Removed gibbing, as death animations weren't playing with gibs off
//		if ( bitsDamageType & DMG_ALWAYSGIB )
//		{
//			Killed( pevAttacker, GIB_ALWAYS );
//		}
//		else if ( bitsDamageType & DMG_NEVERGIB )
//		{
			Killed( pevAttacker, GIB_NEVER );
//		}
//		else
//		{
//			Killed( pevAttacker, GIB_NORMAL );
//		}

		// Trigger log message if needed
//		AvHPlayer* theDeadPlayer = dynamic_cast<AvHPlayer*>(this);
//		AvHPlayer* theAttackingPlayer = dynamic_cast<AvHPlayer*>(CBaseEntity::Instance(ENT(pevAttacker)));
//		const char* inWeaponName = STRING(pevInflictor->classname);
//		if(theDeadPlayer && theAttackingPlayer && inWeaponName)
//		{
//			theDeadPlayer->LogPlayerKilledPlayer(theAttackingPlayer, inWeaponName);
//		}

		g_pevLastInflictor = NULL;

		return 0;
	}

	// react to the damage (get mad)
	if ( (pev->flags & FL_MONSTER) && !FNullEnt(pevAttacker) )
	{
		if ( pevAttacker->flags & (FL_MONSTER | FL_CLIENT) )
		{// only if the attack was a monster or client!
			
			// enemy's last known position is somewhere down the vector that the attack came from.
			if (pevInflictor)
			{
				if (m_hEnemy == NULL || pevInflictor == m_hEnemy->pev || !HasConditions(bits_COND_SEE_ENEMY))
				{
					m_vecEnemyLKP = pevInflictor->origin;
				}
			}
			else
			{
				m_vecEnemyLKP = pev->origin + ( g_vecAttackDir * 64 ); 
			}

			MakeIdealYaw( m_vecEnemyLKP );

			// add pain to the conditions 
			// !!!HACKHACK - fudged for now. Do we want to have a virtual function to determine what is light and 
			// heavy damage per monster class?
			if ( flDamage > 0 )
			{
				SetConditions(bits_COND_LIGHT_DAMAGE);
			}

			if ( flDamage >= 20 )
			{
				SetConditions(bits_COND_HEAVY_DAMAGE);
			}
		}
	}

	return 1;
}