View Single Post
Making entities follow the player
Old
  (#1)
Lazy
Member
 
Lazy's Avatar
 
Status: Offline
Posts: 236
Join Date: Jan 2004
Location: Toronto, Ontario, Canada
Default Making entities follow the player - 03-05-2004

The idea: Allow terrorists to move the hostages in CS.
The problem: I'm not good enough at math to fake the movement.

I have been able to move them around a bit, its very funny to see them slam into walls due to incorrect math.
I first thought of having the using player drop waypoints for the hostage to follow but I think thats overcomplicating the problem.

Any ideas would be helpful here.

Here is the source, just take into consideration that I have not had much time to work on it ( or anything else ) and alot of stuff is not finished or implemented yet ( or could be rewritten ).

Code:
  #include <extdll.h>
  #include <meta_api.h>
  #include "dll.h"
  
  // This prevents the user from "using"
  // every frame.
  bool g_bHasPressedUseAlready[ 32 ];
  
  // The next time the user ( index ) can
  // "press" the use key.
  float g_flNextUseCheckTime[ 32 ];
  
  // Returns true if the given player is on the
  // terrorist team.
  bool
  IsTerrorist( edict_t* pEdict ) {
     return true;
  }
  
  // "Borrowed" From util.cpp
  Vector 
  UTIL_VecToAngles( const Vector& vec ) {
  	float rgflVecOut[ 3 ];
  
  	VEC_TO_ANGLES( vec, rgflVecOut );
  
  	return Vector( rgflVecOut );
  }
  
  // "Borrowed" From util.cpp
  // Overloaded to add IGNORE_GLASS
  void 
 UTIL_TraceLine( const Vector &vecStart, const Vector &vecEnd, IGNORE_MONSTERS igmon, IGNORE_GLASS ignoreGlass, edict_t *pentIgnore, TraceResult *ptr ) {
 	TRACE_LINE( vecStart, vecEnd, (igmon == ignore_monsters ? TRUE : FALSE) | (ignoreGlass?0x100:0), pentIgnore, ptr );
  }
  
  // Traces a line between an entity and a point to
  // determine if that point is visible to the given entity.
  BOOL
  IsVisible( edict_t* pStartEntity, const Vector& vecTarget ) {
     Vector vecStart = pStartEntity->v.origin + pStartEntity->v.view_ofs;
     TraceResult trTrace;
  
     UTIL_TraceLine( vecStart, vecTarget, ignore_monsters, ignore_glass, pStartEntity, &trTrace );
  
     if ( trTrace.flFraction != 1.0f )
  	  return FALSE;
     else
  	  return TRUE;
  
     return FALSE;
  }
  
  // Wrap the angles to make sure we don't overflow.
  void 
  WrapAngles( Vector& vecAngles ) {
     if ( vecAngles.x > 360 )
  	  vecAngles.x = 360;
     else if ( vecAngles.x < -180 )
  	  vecAngles.x = -180;
  
     if ( vecAngles.y > 360 )
  	  vecAngles.y = 360;
     else if ( vecAngles.y < -180 )
  	  vecAngles.y = -180;
  
     if ( vecAngles.z > 360 )
  	  vecAngles.z = 360;
     else if ( vecAngles.z < -180 )
  	  vecAngles.z = -180;
  }
  
  // Called every frame after physics have been applied.
  // Also called after the gamedll's version.
  void 
  PlayerPostThink_Post( edict_t* pEdict ) {
     // The player's entity index.
     int iPlayerIndex = ENTINDEX( pEdict );
  
     // Pointer to our hostage entity.
     edict_t* pHostage = NULL;
     
     // Do we have a valid hostage?
     // Added:
     // The hostage "movement" is done here to save
     // hooking another function.
     // Besides, the hostage is our bitch anyways for
     // the time being.
     if ( ! FNullEnt( pEdict->v.euser4 ) ) {
  	  pHostage = pEdict->v.euser4;
  
  	  // Release the hostage if either they are too far away,
  	  // out of sight,
  	  // the hostage is dead
  	  // or the player is dead.
  	  if ( ( pEdict->v.origin - pHostage->v.origin ).Length( ) > 1024.0f   || 
  		    !IsVisible( pHostage, pEdict->v.origin + pEdict->v.view_ofs )  ||
 			 pHostage->v.health == 0									 || 
  			 pEdict->v.health == 0 ) {
  		 // We are either too far away, out of sight or someone died.
  		 // Release the hostage.
  		 pEdict->v.euser4 = NULL;
  	 }
  	 else {
  		 // The hostage can see us and we aren't too far away.
  		 // Face our user.
 		 // Thanks to PMB for this angles stuff :)
 		 pHostage->v.angles = UTIL_VecToAngles( pEdict->v.oldorigin - ( pHostage->v.origin + pHostage->v.view_ofs ) );
  		 pHostage->v.angles.x = 0;
  	  }
     }
  
     RETURN_META( MRES_IGNORED );
  }
  
  // Called at the start of each video frame.
  void
  StartFrame_Post( void ) {
     // Will hold the origin to start the trace from.
     Vector vecStart = Vector( 0, 0, 0 );
  
     // The origin where the trace should end.
     Vector vecEnd = Vector( 0, 0, 0 );
  
     // Pointer to the current entity.
     edict_t* pCurrent = NULL;
  
     // Pointer to the entity the traceline
     // hit.
     edict_t* pHit = NULL;
  
     // Will hold the result of the trace used
     // to get the entity infront of the player.
     TraceResult trTrace;
  
     // Loop through all of the possible player spots.
     for ( int i = 1; i < 33; i++ ) {
  	  pCurrent = INDEXENT( i );
  
  	  // If this entity is null, we have reached the end
  	  // of the players.
  	  if ( FNullEnt( pCurrent ) )
  		 break;
  
  	  // Continue if the current player is not a terrorist.
  	  if ( ! IsTerrorist( pCurrent ) )
  		 continue;
  
  	  // Are we pressing the use key?
  	  if ( pCurrent->v.button & IN_USE ) {
  		 // Is it time to act upon it?
  		 if ( gpGlobals->time >= g_flNextUseCheckTime[ i - 1 ] ) {
  			// Set the next use check time to time + 0.5 
 			g_flNextUseCheckTime[ i - 1 ] = gpGlobals->time + 0.5;
  
 			// We have just pressed the use key, make sure we do not keep
  			// "using" every few frames.
  			if ( g_bHasPressedUseAlready[ i - 1 ] == false )
  			   g_bHasPressedUseAlready[ i - 1 ] = true;
  			else
  			   RETURN_META( MRES_IGNORED );
  
 			// If we already have a hostage and the use key was pressed
  			// means the player wants to release the hostage.
  			if ( ! FNullEnt( pCurrent->v.euser4 ) ) {
  			   pCurrent->v.euser4 = NULL;
  			   RETURN_META( MRES_IGNORED );
  			}
  
 			vecStart = pCurrent->v.origin + pCurrent->v.view_ofs;
  			vecEnd = vecStart + gpGlobals->v_forward * 72;
  
 			// Trace a line from the player's crosshair to 96 units infront.
 		 TRACE_LINE( vecStart, vecEnd, dont_ignore_monsters, pCurrent, &trTrace );
  			pHit = trTrace.pHit;
  
  			// Did we hit something? Was it a hostage?
 			if ( ! FNullEnt( pHit ) && FClassnameIs( pHit, "hostage_entity" ) ) {
  			   // euser4 Will now contain a pointer to the hostage
  			   // we wish to move.
  			   pCurrent->v.euser4 = pHit;
  			}
  		 }
  	  }
  	  else {
  		 // We are no longer pressing the use key.
  		 g_bHasPressedUseAlready[ i - 1 ] = false;
  	  }
     }
  
     RETURN_META( MRES_IGNORED );
  }
  
  // Called when an entity is spawning.
  int 
  DispatchSpawn_Post( edict_t* pEdict ) {
     // If the world is being spawned...
     if ( ! FNullEnt( pEdict ) ) {
  	  if ( FClassnameIs( pEdict, "worldspawn" ) ) {
  		 // Zero-out some global variables for use on this map
 		 memset( g_bHasPressedUseAlready, 0, sizeof( bool ) * 32 );	 
  		 memset( g_flNextUseCheckTime, 0, sizeof( float ) * 32 );
  	  }
  	  else if ( FClassnameIs( pEdict, "hostage_entity" ) ) {
  		 // Fix hostages hands not matching their skin color.
  		 if ( pEdict->v.body == 2 )
  			pEdict->v.skin = 1;
  	  }
     }
  
     RETURN_META_VALUE( MRES_IGNORED, 0 );
  }
  
  // Called when a player leaves the server.
  void
  ClientDisconnect_Post( edict_t* pEdict ) {
     // If the entity is valid reset their next use check
     // time and "has pressed already" stuff now.
     if ( ! FNullEnt( pEdict ) ) {
  	  g_bHasPressedUseAlready[ ENTINDEX( pEdict ) - 1 ] = false;
  	  g_flNextUseCheckTime[ ENTINDEX( pEdict ) - 1 ] = 0.0f;
     }
  
     RETURN_META( MRES_IGNORED );
  }
Edited to add in a comment I forgot to put in

Last edited by Lazy; 03-05-2004 at 12:28..
  
Reply With Quote