initial
This commit is contained in:
862
game/server/NextBot/Player/NextBotPlayer.h
Normal file
862
game/server/NextBot/Player/NextBotPlayer.h
Normal file
@@ -0,0 +1,862 @@
|
||||
// NextBotPlayer.h
|
||||
// A CBasePlayer bot based on the NextBot technology
|
||||
// Author: Michael Booth, November 2005
|
||||
// Copyright (c) 2007 Turtle Rock Studios, Inc. - All Rights Reserved
|
||||
|
||||
#ifndef _NEXT_BOT_PLAYER_H_
|
||||
#define _NEXT_BOT_PLAYER_H_
|
||||
|
||||
#include "cbase.h"
|
||||
#include "gameinterface.h"
|
||||
|
||||
#include "NextBot.h"
|
||||
#include "Path/NextBotPathFollow.h"
|
||||
//#include "NextBotPlayerBody.h"
|
||||
#include "NextBotBehavior.h"
|
||||
|
||||
#include "in_buttons.h"
|
||||
|
||||
extern ConVar NextBotPlayerStop;
|
||||
extern ConVar NextBotPlayerWalk;
|
||||
extern ConVar NextBotPlayerCrouch;
|
||||
extern ConVar NextBotPlayerMove;
|
||||
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
/**
|
||||
* Instantiate a NextBot derived from CBasePlayer and spawn it into the environment.
|
||||
* Assumes class T is derived from CBasePlayer, and has the following method that
|
||||
* creates a new entity of type T and returns it:
|
||||
*
|
||||
* static CBasePlayer *T::AllocatePlayerEntity( edict_t *pEdict, const char *playerName )
|
||||
*
|
||||
*/
|
||||
template < typename T >
|
||||
T * NextBotCreatePlayerBot( const char *name )
|
||||
{
|
||||
/*
|
||||
if ( UTIL_ClientsInGame() >= gpGlobals->maxClients )
|
||||
{
|
||||
Msg( "CreatePlayerBot: Failed - server is full (%d/%d clients).\n", UTIL_ClientsInGame(), gpGlobals->maxClients );
|
||||
return NULL;
|
||||
}
|
||||
*/
|
||||
|
||||
// This is a "back door" for allocating a custom player bot entity when
|
||||
// the engine calls ClientPutInServer (from CreateFakeClient)
|
||||
ClientPutInServerOverride( T::AllocatePlayerEntity );
|
||||
|
||||
// create the bot and spawn it into the environment
|
||||
edict_t *botEdict = engine->CreateFakeClient( name );
|
||||
|
||||
// close the "back door"
|
||||
ClientPutInServerOverride( NULL );
|
||||
|
||||
if ( botEdict == NULL )
|
||||
{
|
||||
Msg( "CreatePlayerBot: Unable to create bot %s - CreateFakeClient() returned NULL.\n", name );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// create an instance of the bot's class and bind it to the edict
|
||||
T *bot = dynamic_cast< T * >( CBaseEntity::Instance( botEdict ) );
|
||||
|
||||
if ( bot == NULL )
|
||||
{
|
||||
Assert( false );
|
||||
Error( "CreatePlayerBot: Could not Instance() from the bot edict.\n" );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// set the fakeclient's name
|
||||
// char trimmedName[ MAX_PLAYER_NAME_LENGTH ];
|
||||
// Q_strncpy( trimmedName, name, sizeof( trimmedName ) );
|
||||
// bot->PlayerData()->netname = AllocPooledString( trimmedName );
|
||||
bot->SetPlayerName( name );
|
||||
|
||||
// flag this as a fakeclient (bot)
|
||||
bot->ClearFlags();
|
||||
bot->AddFlag( FL_CLIENT | FL_FAKECLIENT );
|
||||
|
||||
return bot;
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
/**
|
||||
* Interface to access player input buttons.
|
||||
* Unless a duration is given, each button is released at the start of the next frame.
|
||||
* The release methods allow releasing a button before its duration has elapsed.
|
||||
*/
|
||||
class INextBotPlayerInput
|
||||
{
|
||||
public:
|
||||
virtual void PressFireButton( float duration = -1.0f ) = 0;
|
||||
virtual void ReleaseFireButton( void ) = 0;
|
||||
|
||||
virtual void PressAltFireButton( float duration = -1.0f ) = 0;
|
||||
virtual void ReleaseAltFireButton( void ) = 0;
|
||||
|
||||
virtual void PressMeleeButton( float duration = -1.0f ) = 0;
|
||||
virtual void ReleaseMeleeButton( void ) = 0;
|
||||
|
||||
virtual void PressUseButton( float duration = -1.0f ) = 0;
|
||||
virtual void ReleaseUseButton( void ) = 0;
|
||||
|
||||
virtual void PressReloadButton( float duration = -1.0f ) = 0;
|
||||
virtual void ReleaseReloadButton( void ) = 0;
|
||||
|
||||
virtual void PressForwardButton( float duration = -1.0f ) = 0;
|
||||
virtual void ReleaseForwardButton( void ) = 0;
|
||||
|
||||
virtual void PressBackwardButton( float duration = -1.0f ) = 0;
|
||||
virtual void ReleaseBackwardButton( void ) = 0;
|
||||
|
||||
virtual void PressLeftButton( float duration = -1.0f ) = 0;
|
||||
virtual void ReleaseLeftButton( void ) = 0;
|
||||
|
||||
virtual void PressRightButton( float duration = -1.0f ) = 0;
|
||||
virtual void ReleaseRightButton( void ) = 0;
|
||||
|
||||
virtual void PressJumpButton( float duration = -1.0f ) = 0;
|
||||
virtual void ReleaseJumpButton( void ) = 0;
|
||||
|
||||
virtual void PressCrouchButton( float duration = -1.0f ) = 0;
|
||||
virtual void ReleaseCrouchButton( void ) = 0;
|
||||
|
||||
virtual void PressWalkButton( float duration = -1.0f ) = 0;
|
||||
virtual void ReleaseWalkButton( void ) = 0;
|
||||
|
||||
virtual void SetButtonScale( float forward, float right ) = 0;
|
||||
};
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
/**
|
||||
* Drive a CBasePlayer-derived entity via NextBot logic
|
||||
*/
|
||||
template < typename PlayerType >
|
||||
class NextBotPlayer : public PlayerType, public INextBot, public INextBotPlayerInput
|
||||
{
|
||||
public:
|
||||
DECLARE_CLASS( NextBotPlayer, PlayerType );
|
||||
|
||||
NextBotPlayer( void );
|
||||
virtual ~NextBotPlayer();
|
||||
|
||||
virtual void Spawn( void );
|
||||
virtual void PhysicsSimulate( void );
|
||||
|
||||
virtual bool IsNetClient( void ) const { return false; } // Bots should return FALSE for this, they can't receive NET messages
|
||||
virtual bool IsFakeClient( void ) const { return true; }
|
||||
virtual bool IsBot( void ) const { return true; }
|
||||
virtual INextBot *MyNextBotPointer( void ) { return this; }
|
||||
|
||||
// this is valid because the templatized PlayerType must be derived from CBasePlayer, which is derived from CBaseCombatCharacter
|
||||
virtual CBaseCombatCharacter *GetEntity( void ) const { return ( PlayerType * )this; }
|
||||
|
||||
virtual bool IsRemovedOnReset( void ) const { return false; } // remove this bot when the NextBot manager calls Reset
|
||||
|
||||
virtual bool IsDormantWhenDead( void ) const { return true; } // should this player-bot continue to update itself when dead (respawn logic, etc)
|
||||
|
||||
// allocate a bot and bind it to the edict
|
||||
static CBasePlayer *AllocatePlayerEntity( edict_t *edict, const char *playerName );
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// utility methods
|
||||
float GetDistanceBetween( CBaseEntity *other ) const; // return distance between us and the given entity
|
||||
bool IsDistanceBetweenLessThan( CBaseEntity *other, float range ) const; // return true if distance between is less than the given value
|
||||
bool IsDistanceBetweenGreaterThan( CBaseEntity *other, float range ) const; // return true if distance between is greater than the given value
|
||||
|
||||
float GetDistanceBetween( const Vector &target ) const; // return distance between us and the given entity
|
||||
bool IsDistanceBetweenLessThan( const Vector &target, float range ) const; // return true if distance between is less than the given value
|
||||
bool IsDistanceBetweenGreaterThan( const Vector &target, float range ) const; // return true if distance between is greater than the given value
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// INextBotPlayerInput
|
||||
virtual void PressFireButton( float duration = -1.0f );
|
||||
virtual void ReleaseFireButton( void );
|
||||
|
||||
virtual void PressAltFireButton( float duration = -1.0f );
|
||||
virtual void ReleaseAltFireButton( void );
|
||||
|
||||
virtual void PressMeleeButton( float duration = -1.0f );
|
||||
virtual void ReleaseMeleeButton( void );
|
||||
|
||||
virtual void PressUseButton( float duration = -1.0f );
|
||||
virtual void ReleaseUseButton( void );
|
||||
|
||||
virtual void PressReloadButton( float duration = -1.0f );
|
||||
virtual void ReleaseReloadButton( void );
|
||||
|
||||
virtual void PressForwardButton( float duration = -1.0f );
|
||||
virtual void ReleaseForwardButton( void );
|
||||
|
||||
virtual void PressBackwardButton( float duration = -1.0f );
|
||||
virtual void ReleaseBackwardButton( void );
|
||||
|
||||
virtual void PressLeftButton( float duration = -1.0f );
|
||||
virtual void ReleaseLeftButton( void );
|
||||
|
||||
virtual void PressRightButton( float duration = -1.0f );
|
||||
virtual void ReleaseRightButton( void );
|
||||
|
||||
virtual void PressJumpButton( float duration = -1.0f );
|
||||
virtual void ReleaseJumpButton( void );
|
||||
|
||||
virtual void PressCrouchButton( float duration = -1.0f );
|
||||
virtual void ReleaseCrouchButton( void );
|
||||
|
||||
virtual void PressWalkButton( float duration = -1.0f );
|
||||
virtual void ReleaseWalkButton( void );
|
||||
|
||||
virtual void SetButtonScale( float forward, float right );
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// Event hooks into NextBot system
|
||||
virtual int OnTakeDamage_Alive( const CTakeDamageInfo &info );
|
||||
virtual int OnTakeDamage_Dying( const CTakeDamageInfo &info );
|
||||
virtual void Event_Killed( const CTakeDamageInfo &info );
|
||||
virtual void HandleAnimEvent( animevent_t *event );
|
||||
virtual void OnNavAreaChanged( CNavArea *enteredArea, CNavArea *leftArea ); // invoked (by UpdateLastKnownArea) when we enter a new nav area (or it is reset to NULL)
|
||||
virtual void Touch( CBaseEntity *other );
|
||||
virtual void Weapon_Equip( CBaseCombatWeapon *weapon ); // for OnPickUp
|
||||
virtual void Weapon_Drop( CBaseCombatWeapon *weapon, const Vector *target, const Vector *velocity ); // for OnDrop
|
||||
virtual void OnMainActivityComplete( Activity newActivity, Activity oldActivity );
|
||||
virtual void OnMainActivityInterrupted( Activity newActivity, Activity oldActivity );
|
||||
//------------------------------------------------------------------------
|
||||
|
||||
bool IsAbleToAutoCenterOnLadders( void ) const;
|
||||
|
||||
public:
|
||||
// begin INextBot ------------------------------------------------------------------------------------------------------------------
|
||||
virtual void Update( void ); // (EXTEND) update internal state
|
||||
|
||||
protected:
|
||||
int m_inputButtons; // this is still needed to guarantee each button press is captured at least once
|
||||
int m_prevInputButtons;
|
||||
CountdownTimer m_fireButtonTimer;
|
||||
CountdownTimer m_meleeButtonTimer;
|
||||
CountdownTimer m_useButtonTimer;
|
||||
CountdownTimer m_reloadButtonTimer;
|
||||
CountdownTimer m_forwardButtonTimer;
|
||||
CountdownTimer m_backwardButtonTimer;
|
||||
CountdownTimer m_leftButtonTimer;
|
||||
CountdownTimer m_rightButtonTimer;
|
||||
CountdownTimer m_jumpButtonTimer;
|
||||
CountdownTimer m_crouchButtonTimer;
|
||||
CountdownTimer m_walkButtonTimer;
|
||||
CountdownTimer m_buttonScaleTimer;
|
||||
IntervalTimer m_burningTimer; // how long since we were last burning
|
||||
float m_forwardScale;
|
||||
float m_rightScale;
|
||||
};
|
||||
|
||||
|
||||
template < typename PlayerType >
|
||||
inline float NextBotPlayer< PlayerType >::GetDistanceBetween( CBaseEntity *other ) const
|
||||
{
|
||||
return (this->GetAbsOrigin() - other->GetAbsOrigin()).Length();
|
||||
}
|
||||
|
||||
template < typename PlayerType >
|
||||
inline bool NextBotPlayer< PlayerType >::IsDistanceBetweenLessThan( CBaseEntity *other, float range ) const
|
||||
{
|
||||
return (this->GetAbsOrigin() - other->GetAbsOrigin()).IsLengthLessThan( range );
|
||||
}
|
||||
|
||||
template < typename PlayerType >
|
||||
inline bool NextBotPlayer< PlayerType >::IsDistanceBetweenGreaterThan( CBaseEntity *other, float range ) const
|
||||
{
|
||||
return (this->GetAbsOrigin() - other->GetAbsOrigin()).IsLengthGreaterThan( range );
|
||||
}
|
||||
|
||||
template < typename PlayerType >
|
||||
inline float NextBotPlayer< PlayerType >::GetDistanceBetween( const Vector &target ) const
|
||||
{
|
||||
return (this->GetAbsOrigin() - target).Length();
|
||||
}
|
||||
|
||||
template < typename PlayerType >
|
||||
inline bool NextBotPlayer< PlayerType >::IsDistanceBetweenLessThan( const Vector &target, float range ) const
|
||||
{
|
||||
return (this->GetAbsOrigin() - target).IsLengthLessThan( range );
|
||||
}
|
||||
|
||||
template < typename PlayerType >
|
||||
inline bool NextBotPlayer< PlayerType >::IsDistanceBetweenGreaterThan( const Vector &target, float range ) const
|
||||
{
|
||||
return (this->GetAbsOrigin() - target).IsLengthGreaterThan( range );
|
||||
}
|
||||
|
||||
template < typename PlayerType >
|
||||
inline void NextBotPlayer< PlayerType >::PressFireButton( float duration )
|
||||
{
|
||||
m_inputButtons |= IN_ATTACK;
|
||||
m_fireButtonTimer.Start( duration );
|
||||
}
|
||||
|
||||
template < typename PlayerType >
|
||||
inline void NextBotPlayer< PlayerType >::ReleaseFireButton( void )
|
||||
{
|
||||
m_inputButtons &= ~IN_ATTACK;
|
||||
m_fireButtonTimer.Invalidate();
|
||||
}
|
||||
|
||||
template < typename PlayerType >
|
||||
inline void NextBotPlayer< PlayerType >::PressAltFireButton( float duration )
|
||||
{
|
||||
PressMeleeButton( duration );
|
||||
}
|
||||
|
||||
template < typename PlayerType >
|
||||
inline void NextBotPlayer< PlayerType >::ReleaseAltFireButton( void )
|
||||
{
|
||||
ReleaseMeleeButton();
|
||||
}
|
||||
|
||||
template < typename PlayerType >
|
||||
inline void NextBotPlayer< PlayerType >::PressMeleeButton( float duration )
|
||||
{
|
||||
m_inputButtons |= IN_ATTACK2;
|
||||
m_meleeButtonTimer.Start( duration );
|
||||
}
|
||||
|
||||
template < typename PlayerType >
|
||||
inline void NextBotPlayer< PlayerType >::ReleaseMeleeButton( void )
|
||||
{
|
||||
m_inputButtons &= ~IN_ATTACK2;
|
||||
m_meleeButtonTimer.Invalidate();
|
||||
}
|
||||
|
||||
template < typename PlayerType >
|
||||
inline void NextBotPlayer< PlayerType >::PressUseButton( float duration )
|
||||
{
|
||||
m_inputButtons |= IN_USE;
|
||||
m_useButtonTimer.Start( duration );
|
||||
}
|
||||
|
||||
template < typename PlayerType >
|
||||
inline void NextBotPlayer< PlayerType >::ReleaseUseButton( void )
|
||||
{
|
||||
m_inputButtons &= ~IN_USE;
|
||||
m_useButtonTimer.Invalidate();
|
||||
}
|
||||
|
||||
template < typename PlayerType >
|
||||
inline void NextBotPlayer< PlayerType >::PressReloadButton( float duration )
|
||||
{
|
||||
m_inputButtons |= IN_RELOAD;
|
||||
m_reloadButtonTimer.Start( duration );
|
||||
}
|
||||
|
||||
template < typename PlayerType >
|
||||
inline void NextBotPlayer< PlayerType >::ReleaseReloadButton( void )
|
||||
{
|
||||
m_inputButtons &= ~IN_RELOAD;
|
||||
m_reloadButtonTimer.Invalidate();
|
||||
}
|
||||
|
||||
template < typename PlayerType >
|
||||
inline void NextBotPlayer< PlayerType >::PressJumpButton( float duration )
|
||||
{
|
||||
m_inputButtons |= IN_JUMP;
|
||||
m_jumpButtonTimer.Start( duration );
|
||||
}
|
||||
|
||||
template < typename PlayerType >
|
||||
inline void NextBotPlayer< PlayerType >::ReleaseJumpButton( void )
|
||||
{
|
||||
m_inputButtons &= ~IN_JUMP;
|
||||
m_jumpButtonTimer.Invalidate();
|
||||
}
|
||||
|
||||
template < typename PlayerType >
|
||||
inline void NextBotPlayer< PlayerType >::PressCrouchButton( float duration )
|
||||
{
|
||||
m_inputButtons |= IN_DUCK;
|
||||
m_crouchButtonTimer.Start( duration );
|
||||
}
|
||||
|
||||
template < typename PlayerType >
|
||||
inline void NextBotPlayer< PlayerType >::ReleaseCrouchButton( void )
|
||||
{
|
||||
m_inputButtons &= ~IN_DUCK;
|
||||
m_crouchButtonTimer.Invalidate();
|
||||
}
|
||||
|
||||
template < typename PlayerType >
|
||||
inline void NextBotPlayer< PlayerType >::PressWalkButton( float duration )
|
||||
{
|
||||
m_inputButtons |= IN_SPEED;
|
||||
m_walkButtonTimer.Start( duration );
|
||||
}
|
||||
|
||||
template < typename PlayerType >
|
||||
inline void NextBotPlayer< PlayerType >::ReleaseWalkButton( void )
|
||||
{
|
||||
m_inputButtons &= ~IN_SPEED;
|
||||
m_walkButtonTimer.Invalidate();
|
||||
}
|
||||
|
||||
template < typename PlayerType >
|
||||
inline void NextBotPlayer< PlayerType >::PressForwardButton( float duration )
|
||||
{
|
||||
m_inputButtons |= IN_FORWARD;
|
||||
m_forwardButtonTimer.Start( duration );
|
||||
}
|
||||
|
||||
template < typename PlayerType >
|
||||
inline void NextBotPlayer< PlayerType >::ReleaseForwardButton( void )
|
||||
{
|
||||
m_inputButtons &= ~IN_FORWARD;
|
||||
m_forwardButtonTimer.Invalidate();
|
||||
}
|
||||
|
||||
template < typename PlayerType >
|
||||
inline void NextBotPlayer< PlayerType >::PressBackwardButton( float duration )
|
||||
{
|
||||
m_inputButtons |= IN_BACK;
|
||||
m_backwardButtonTimer.Start( duration );
|
||||
}
|
||||
|
||||
template < typename PlayerType >
|
||||
inline void NextBotPlayer< PlayerType >::ReleaseBackwardButton( void )
|
||||
{
|
||||
m_inputButtons &= ~IN_BACK;
|
||||
m_backwardButtonTimer.Invalidate();
|
||||
}
|
||||
|
||||
template < typename PlayerType >
|
||||
inline void NextBotPlayer< PlayerType >::PressLeftButton( float duration )
|
||||
{
|
||||
m_inputButtons |= IN_MOVELEFT;
|
||||
m_leftButtonTimer.Start( duration );
|
||||
}
|
||||
|
||||
template < typename PlayerType >
|
||||
inline void NextBotPlayer< PlayerType >::ReleaseLeftButton( void )
|
||||
{
|
||||
m_inputButtons &= ~IN_MOVELEFT;
|
||||
m_leftButtonTimer.Invalidate();
|
||||
}
|
||||
|
||||
template < typename PlayerType >
|
||||
inline void NextBotPlayer< PlayerType >::PressRightButton( float duration )
|
||||
{
|
||||
m_inputButtons |= IN_MOVERIGHT;
|
||||
m_rightButtonTimer.Start( duration );
|
||||
}
|
||||
|
||||
template < typename PlayerType >
|
||||
inline void NextBotPlayer< PlayerType >::ReleaseRightButton( void )
|
||||
{
|
||||
m_inputButtons &= ~IN_MOVERIGHT;
|
||||
m_rightButtonTimer.Invalidate();
|
||||
}
|
||||
|
||||
template < typename PlayerType >
|
||||
inline void NextBotPlayer< PlayerType >::SetButtonScale( float forward, float right )
|
||||
{
|
||||
m_forwardScale = forward;
|
||||
m_rightScale = right;
|
||||
m_buttonScaleTimer.Start( 0.01 );
|
||||
}
|
||||
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------------------------------
|
||||
template < typename PlayerType >
|
||||
inline NextBotPlayer< PlayerType >::NextBotPlayer( void )
|
||||
{
|
||||
m_prevInputButtons = 0;
|
||||
m_inputButtons = 0;
|
||||
m_burningTimer.Invalidate();
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------------------------------
|
||||
template < typename PlayerType >
|
||||
inline NextBotPlayer< PlayerType >::~NextBotPlayer()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------------------------------
|
||||
template < typename PlayerType >
|
||||
inline void NextBotPlayer< PlayerType >::Spawn( void )
|
||||
{
|
||||
engine->SetFakeClientConVarValue( this->edict(), "cl_autohelp", "0" );
|
||||
|
||||
m_prevInputButtons = m_inputButtons = 0;
|
||||
m_fireButtonTimer.Invalidate();
|
||||
m_meleeButtonTimer.Invalidate();
|
||||
m_useButtonTimer.Invalidate();
|
||||
m_reloadButtonTimer.Invalidate();
|
||||
m_forwardButtonTimer.Invalidate();
|
||||
m_backwardButtonTimer.Invalidate();
|
||||
m_leftButtonTimer.Invalidate();
|
||||
m_rightButtonTimer.Invalidate();
|
||||
m_jumpButtonTimer.Invalidate();
|
||||
m_crouchButtonTimer.Invalidate();
|
||||
m_walkButtonTimer.Invalidate();
|
||||
m_buttonScaleTimer.Invalidate();
|
||||
m_forwardScale = m_rightScale = 0.04;
|
||||
m_burningTimer.Invalidate();
|
||||
|
||||
// reset first, because Spawn() may access various interfaces
|
||||
INextBot::Reset();
|
||||
|
||||
BaseClass::Spawn();
|
||||
}
|
||||
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------------------------------
|
||||
inline void _NextBot_BuildUserCommand( CUserCmd *cmd, const QAngle &viewangles, float forwardmove, float sidemove, float upmove, int buttons, byte impulse )
|
||||
{
|
||||
Q_memset( cmd, 0, sizeof( CUserCmd ) );
|
||||
|
||||
cmd->command_number = gpGlobals->tickcount;
|
||||
cmd->forwardmove = forwardmove;
|
||||
cmd->sidemove = sidemove;
|
||||
cmd->upmove = upmove;
|
||||
cmd->buttons = buttons;
|
||||
cmd->impulse = impulse;
|
||||
|
||||
VectorCopy( viewangles, cmd->viewangles );
|
||||
|
||||
cmd->random_seed = random->RandomInt( 0, 0x7fffffff );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------------------------------
|
||||
template < typename PlayerType >
|
||||
inline void NextBotPlayer< PlayerType >::PhysicsSimulate( void )
|
||||
{
|
||||
VPROF( "NextBotPlayer::PhysicsSimulate" );
|
||||
|
||||
if ( engine->IsPaused() )
|
||||
{
|
||||
// We're paused - don't add new commands
|
||||
PlayerType::PhysicsSimulate();
|
||||
return;
|
||||
}
|
||||
|
||||
if ( ( IsDormantWhenDead() && PlayerType::m_lifeState == LIFE_DEAD ) || NextBotStop.GetBool() )
|
||||
{
|
||||
// death animation complete - nothing left to do except let PhysicsSimulate run PreThink etc
|
||||
PlayerType::PhysicsSimulate();
|
||||
return;
|
||||
}
|
||||
|
||||
int inputButtons;
|
||||
//
|
||||
// Update bot behavior
|
||||
//
|
||||
if ( BeginUpdate() )
|
||||
{
|
||||
Update();
|
||||
|
||||
// build button bits
|
||||
if ( !m_fireButtonTimer.IsElapsed() )
|
||||
m_inputButtons |= IN_ATTACK;
|
||||
|
||||
if ( !m_meleeButtonTimer.IsElapsed() )
|
||||
m_inputButtons |= IN_ATTACK2;
|
||||
|
||||
if ( !m_useButtonTimer.IsElapsed() )
|
||||
m_inputButtons |= IN_USE;
|
||||
|
||||
if ( !m_reloadButtonTimer.IsElapsed() )
|
||||
m_inputButtons |= IN_RELOAD;
|
||||
|
||||
if ( !m_forwardButtonTimer.IsElapsed() )
|
||||
m_inputButtons |= IN_FORWARD;
|
||||
|
||||
if ( !m_backwardButtonTimer.IsElapsed() )
|
||||
m_inputButtons |= IN_BACK;
|
||||
|
||||
if ( !m_leftButtonTimer.IsElapsed() )
|
||||
m_inputButtons |= IN_MOVELEFT;
|
||||
|
||||
if ( !m_rightButtonTimer.IsElapsed() )
|
||||
m_inputButtons |= IN_MOVERIGHT;
|
||||
|
||||
if ( !m_jumpButtonTimer.IsElapsed() )
|
||||
m_inputButtons |= IN_JUMP;
|
||||
|
||||
if ( !m_crouchButtonTimer.IsElapsed() )
|
||||
m_inputButtons |= IN_DUCK;
|
||||
|
||||
if ( !m_walkButtonTimer.IsElapsed() )
|
||||
m_inputButtons |= IN_SPEED;
|
||||
|
||||
m_prevInputButtons = m_inputButtons;
|
||||
inputButtons = m_inputButtons;
|
||||
|
||||
EndUpdate();
|
||||
}
|
||||
else
|
||||
{
|
||||
// HACK: Smooth out body animations
|
||||
GetBodyInterface()->Update();
|
||||
|
||||
// keep buttons pressed between Update() calls (m_prevInputButtons),
|
||||
// and include any button presses that occurred this tick (m_inputButtons).
|
||||
inputButtons = m_prevInputButtons | m_inputButtons;
|
||||
}
|
||||
|
||||
//
|
||||
// Convert NextBot locomotion and posture into
|
||||
// player commands
|
||||
//
|
||||
IBody *body = GetBodyInterface();
|
||||
ILocomotion *mover = GetLocomotionInterface();
|
||||
|
||||
if ( body->IsActualPosture( IBody::CROUCH ) )
|
||||
{
|
||||
inputButtons |= IN_DUCK;
|
||||
}
|
||||
|
||||
float forwardSpeed = 0.0f;
|
||||
float strafeSpeed = 0.0f;
|
||||
float verticalSpeed = ( m_inputButtons & IN_JUMP ) ? mover->GetRunSpeed() : 0.0f;
|
||||
|
||||
if ( inputButtons & IN_FORWARD )
|
||||
{
|
||||
forwardSpeed = mover->GetRunSpeed();
|
||||
}
|
||||
else if ( inputButtons & IN_BACK )
|
||||
{
|
||||
forwardSpeed = -mover->GetRunSpeed();
|
||||
}
|
||||
|
||||
if ( inputButtons & IN_MOVELEFT )
|
||||
{
|
||||
strafeSpeed = -mover->GetRunSpeed();
|
||||
}
|
||||
else if ( inputButtons & IN_MOVERIGHT )
|
||||
{
|
||||
strafeSpeed = mover->GetRunSpeed();
|
||||
}
|
||||
|
||||
if ( NextBotPlayerWalk.GetBool() )
|
||||
{
|
||||
inputButtons |= IN_SPEED;
|
||||
}
|
||||
|
||||
if ( NextBotPlayerCrouch.GetBool() )
|
||||
{
|
||||
inputButtons |= IN_DUCK;
|
||||
}
|
||||
|
||||
if ( !m_buttonScaleTimer.IsElapsed() )
|
||||
{
|
||||
forwardSpeed = mover->GetRunSpeed() * m_forwardScale;
|
||||
strafeSpeed = mover->GetRunSpeed() * m_rightScale;
|
||||
}
|
||||
|
||||
if ( !NextBotPlayerMove.GetBool() )
|
||||
{
|
||||
inputButtons &= ~(IN_FORWARD | IN_BACK | IN_MOVELEFT | IN_MOVERIGHT | IN_JUMP );
|
||||
forwardSpeed = 0.0f;
|
||||
strafeSpeed = 0.0f;
|
||||
verticalSpeed = 0.0f;
|
||||
}
|
||||
|
||||
QAngle angles = this->EyeAngles();
|
||||
|
||||
#ifdef TERROR
|
||||
if ( IsStunned() )
|
||||
{
|
||||
inputButtons &= ~(IN_FORWARD | IN_BACK | IN_MOVELEFT | IN_MOVERIGHT | IN_JUMP | IN_DUCK );
|
||||
}
|
||||
|
||||
// "Look" in the direction we're climbing/stumbling etc. We can't do anything anyway, and it
|
||||
// keeps motion extraction working.
|
||||
if ( IsRenderYawOverridden() && IsMotionControlledXY( GetMainActivity() ) )
|
||||
{
|
||||
angles[YAW] = GetOverriddenRenderYaw();
|
||||
}
|
||||
#endif
|
||||
|
||||
// construct a "command" to move the player
|
||||
CUserCmd userCmd;
|
||||
_NextBot_BuildUserCommand( &userCmd, angles, forwardSpeed, strafeSpeed, verticalSpeed, inputButtons, 0 );
|
||||
|
||||
#ifdef TERROR
|
||||
AvoidPlayers( &userCmd );
|
||||
#endif
|
||||
|
||||
// allocate a new command and add it to the player's list of command to process
|
||||
this->ProcessUsercmds( &userCmd, 1, 1, 0, false );
|
||||
|
||||
m_inputButtons = 0;
|
||||
|
||||
// actually execute player commands and do player physics
|
||||
PlayerType::PhysicsSimulate();
|
||||
}
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------------------------------------
|
||||
template < typename PlayerType >
|
||||
inline void NextBotPlayer< PlayerType >::OnNavAreaChanged( CNavArea *enteredArea, CNavArea *leftArea )
|
||||
{
|
||||
// propagate into NextBot responders
|
||||
INextBotEventResponder::OnNavAreaChanged( enteredArea, leftArea );
|
||||
|
||||
BaseClass::OnNavAreaChanged( enteredArea, leftArea );
|
||||
}
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------------------------------------
|
||||
template < typename PlayerType >
|
||||
inline void NextBotPlayer< PlayerType >::Touch( CBaseEntity *other )
|
||||
{
|
||||
if ( ShouldTouch( other ) )
|
||||
{
|
||||
// propagate touch into NextBot event responders
|
||||
trace_t result;
|
||||
result = this->GetTouchTrace();
|
||||
OnContact( other, &result );
|
||||
}
|
||||
|
||||
BaseClass::Touch( other );
|
||||
}
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------------------------------------
|
||||
template < typename PlayerType >
|
||||
inline void NextBotPlayer< PlayerType >::Weapon_Equip( CBaseCombatWeapon *weapon )
|
||||
{
|
||||
#ifdef TERROR
|
||||
// TODO: Reimplement GetDroppingPlayer() into GetLastOwner()
|
||||
OnPickUp( weapon, weapon->GetDroppingPlayer() );
|
||||
#else
|
||||
OnPickUp( weapon, NULL );
|
||||
#endif
|
||||
|
||||
BaseClass::Weapon_Equip( weapon );
|
||||
}
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------------------------------------
|
||||
template < typename PlayerType >
|
||||
inline void NextBotPlayer< PlayerType >::Weapon_Drop( CBaseCombatWeapon *weapon, const Vector *target, const Vector *velocity )
|
||||
{
|
||||
OnDrop( weapon );
|
||||
|
||||
BaseClass::Weapon_Drop( weapon, target, velocity );
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
template < typename PlayerType >
|
||||
inline void NextBotPlayer< PlayerType >::OnMainActivityComplete( Activity newActivity, Activity oldActivity )
|
||||
{
|
||||
#ifdef TERROR
|
||||
BaseClass::OnMainActivityComplete( newActivity, oldActivity );
|
||||
#endif
|
||||
OnAnimationActivityComplete( oldActivity );
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
template < typename PlayerType >
|
||||
inline void NextBotPlayer< PlayerType >::OnMainActivityInterrupted( Activity newActivity, Activity oldActivity )
|
||||
{
|
||||
#ifdef TERROR
|
||||
BaseClass::OnMainActivityInterrupted( newActivity, oldActivity );
|
||||
#endif
|
||||
OnAnimationActivityInterrupted( oldActivity );
|
||||
}
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------------------------------------
|
||||
template < typename PlayerType >
|
||||
inline void NextBotPlayer< PlayerType >::Update( void )
|
||||
{
|
||||
// don't spend CPU updating if this Survivor is dead
|
||||
if ( ( this->IsAlive() || !IsDormantWhenDead() ) && !NextBotPlayerStop.GetBool() )
|
||||
{
|
||||
INextBot::Update();
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------------
|
||||
template < typename PlayerType >
|
||||
inline bool NextBotPlayer< PlayerType >::IsAbleToAutoCenterOnLadders( void ) const
|
||||
{
|
||||
const ILocomotion *locomotion = GetLocomotionInterface();
|
||||
return locomotion && locomotion->IsAbleToAutoCenterOnLadder();
|
||||
}
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------------------------------------
|
||||
template < typename PlayerType >
|
||||
inline int NextBotPlayer< PlayerType >::OnTakeDamage_Alive( const CTakeDamageInfo &info )
|
||||
{
|
||||
if ( info.GetDamageType() & DMG_BURN )
|
||||
{
|
||||
if ( !m_burningTimer.HasStarted() || m_burningTimer.IsGreaterThen( 1.0f ) )
|
||||
{
|
||||
// emit ignite event periodically as long as we are burning
|
||||
OnIgnite();
|
||||
m_burningTimer.Start();
|
||||
}
|
||||
}
|
||||
|
||||
// propagate event to components
|
||||
OnInjured( info );
|
||||
|
||||
return BaseClass::OnTakeDamage_Alive( info );
|
||||
}
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------------------------------------
|
||||
template < typename PlayerType >
|
||||
inline int NextBotPlayer< PlayerType >::OnTakeDamage_Dying( const CTakeDamageInfo &info )
|
||||
{
|
||||
if ( info.GetDamageType() & DMG_BURN )
|
||||
{
|
||||
if ( !m_burningTimer.HasStarted() || m_burningTimer.IsGreaterThen( 1.0f ) )
|
||||
{
|
||||
// emit ignite event periodically as long as we are burning
|
||||
OnIgnite();
|
||||
m_burningTimer.Start();
|
||||
}
|
||||
}
|
||||
|
||||
// propagate event to components
|
||||
OnInjured( info );
|
||||
|
||||
return BaseClass::OnTakeDamage_Dying( info );
|
||||
}
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------------------------------------
|
||||
template < typename PlayerType >
|
||||
inline void NextBotPlayer< PlayerType >::Event_Killed( const CTakeDamageInfo &info )
|
||||
{
|
||||
// propagate event to my components
|
||||
OnKilled( info );
|
||||
|
||||
BaseClass::Event_Killed( info );
|
||||
}
|
||||
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------------------------------------
|
||||
template < typename PlayerType >
|
||||
inline void NextBotPlayer< PlayerType >::HandleAnimEvent( animevent_t *event )
|
||||
{
|
||||
// propagate event to components
|
||||
OnAnimationEvent( event );
|
||||
|
||||
BaseClass::HandleAnimEvent( event );
|
||||
}
|
||||
|
||||
|
||||
#endif // _NEXT_BOT_PLAYER_H_
|
||||
Reference in New Issue
Block a user