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
