diff options
| author | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
|---|---|---|
| committer | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
| commit | 3bf9df6b2785fa6d951086978a3e66f49427166a (patch) | |
| tree | 2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /game/server/NextBot/Player/NextBotPlayer.h | |
| download | archived-source-engine-2018-hl2-src-master.tar.xz archived-source-engine-2018-hl2-src-master.zip | |
Diffstat (limited to 'game/server/NextBot/Player/NextBotPlayer.h')
| -rw-r--r-- | game/server/NextBot/Player/NextBotPlayer.h | 910 |
1 files changed, 910 insertions, 0 deletions
diff --git a/game/server/NextBot/Player/NextBotPlayer.h b/game/server/NextBot/Player/NextBotPlayer.h new file mode 100644 index 0000000..2032c72 --- /dev/null +++ b/game/server/NextBot/Player/NextBotPlayer.h @@ -0,0 +1,910 @@ +// NextBotPlayer.h +// A CBasePlayer bot based on the NextBot technology +// Author: Michael Booth, November 2005 +//========= Copyright Valve Corporation, 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, bool bReportFakeClient = true ) +{ + /* + 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->CreateFakeClientEx( name, bReportFakeClient ); + + // 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; + } + + 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 PressSpecialFireButton( float duration = -1.0f ) = 0; + virtual void ReleaseSpecialFireButton( 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 SetSpawnPoint( CBaseEntity *spawnPoint ); // define place in environment where bot will (re)spawn + virtual CBaseEntity *EntSelectSpawnPoint( 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 PressSpecialFireButton( float duration = -1.0f ); + virtual void ReleaseSpecialFireButton( 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; + + virtual void AvoidPlayers( CUserCmd *pCmd ) { } // some game types allow players to pass through each other, this method pushes them apart + +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_specialFireButtonTimer; + 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; + CHandle< CBaseEntity > m_spawnPointEntity; +}; + + +template < typename PlayerType > +inline void NextBotPlayer< PlayerType >::SetSpawnPoint( CBaseEntity *spawnPoint ) +{ + m_spawnPointEntity = spawnPoint; +} + +template < typename PlayerType > +inline CBaseEntity *NextBotPlayer< PlayerType >::EntSelectSpawnPoint( void ) +{ + if ( m_spawnPointEntity != NULL ) + return m_spawnPointEntity; + + return BaseClass::EntSelectSpawnPoint(); +} + +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 >::PressSpecialFireButton( float duration ) +{ + m_inputButtons |= IN_ATTACK3; + m_specialFireButtonTimer.Start( duration ); +} + +template < typename PlayerType > +inline void NextBotPlayer< PlayerType >::ReleaseSpecialFireButton( void ) +{ + m_inputButtons &= ~IN_ATTACK3; + m_specialFireButtonTimer.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(); + m_spawnPointEntity = NULL; +} + + +//----------------------------------------------------------------------------------------------------- +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_specialFireButtonTimer.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" ); + + // Make sure not to simulate this guy twice per frame + if ( PlayerType::m_nSimulationTick == gpGlobals->tickcount ) + { + return; + } + + 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_specialFireButtonTimer.IsElapsed() ) + m_inputButtons |= IN_ATTACK3; + + 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 ); + + AvoidPlayers( &userCmd ); + + // 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_ |