.:: Bots United ::.

.:: Bots United ::. (http://forums.bots-united.com/index.php)
-   General Bot Coding (http://forums.bots-united.com/forumdisplay.php?f=24)
-   -   Making entities follow the player (http://forums.bots-united.com/showthread.php?t=1578)

Lazy 03-05-2004 12:25

Making entities follow the player
 
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 :)

Pierre-Marie Baty 03-05-2004 15:53

Re: Making entities follow the player
 
I don't see what's so terribly wrong by making the hostage follow waypoints ? ???:(

Else you can do something more realistic, make your hostage fire a TraceHull (human_hull) towards your player and always head up towards the last hit point which reached the player (i.e, the vector location where your player was last visible for the hostage...)

I don't see the place where you put your hostage in movement ?
Setting the angles may not necessarily be enough. IMO a pfnWalkMove() call should be needed (it's the RunPlayerMove() for monsters...)

Lazy 03-05-2004 17:42

Re: Making entities follow the player
 
1 Attachment(s)
Well, pfnWalkMove does not work but it appears random mathematical guessing does.
The hostages now follow their new user except for one bug...
They float.

Here is the new version of PlayerPostThink_Post...
Code:

// 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.origin - ( pHostage->v.origin + pHostage->v.view_ofs ) );
                  pHostage->v.angles.x = 0;
 
                  // Follow our user!
                  pHostage->v.avelocity = pEdict->v.avelocity;
                  pHostage->v.velocity = ( ( pEdict->v.origin - pHostage->v.origin ) - pEdict->v.velocity ) - gpGlobals->v_forward * 64;
          }
    }
 
    RETURN_META( MRES_IGNORED );
 }

Attached is a zipped demo of what the floating looks like.
Just unzip to your ( steam ) cstrike directory, go into CS and type "playdemo hostage.dem".

Huntkillaz 03-05-2004 23:09

Re: Making entities follow the player
 
i haven't read this thread but thought i might mention:

note: pb needs a fix on to check wheather hossies are following or stuck somewhere...so that they dont run to rescue empty


All times are GMT +2. The time now is 04:10.

Powered by vBulletin® Version 3.8.2
Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.