summaryrefslogtreecommitdiff
path: root/game/client/NextBot
diff options
context:
space:
mode:
Diffstat (limited to 'game/client/NextBot')
-rw-r--r--game/client/NextBot/C_NextBot.cpp245
-rw-r--r--game/client/NextBot/C_NextBot.h134
2 files changed, 379 insertions, 0 deletions
diff --git a/game/client/NextBot/C_NextBot.cpp b/game/client/NextBot/C_NextBot.cpp
new file mode 100644
index 0000000..13d5501
--- /dev/null
+++ b/game/client/NextBot/C_NextBot.cpp
@@ -0,0 +1,245 @@
+// C_NextBot.cpp
+// Client-side implementation of Next generation bot system
+// Author: Michael Booth, April 2005
+//========= Copyright Valve Corporation, All rights reserved. ============//
+
+#include "cbase.h"
+#include "C_NextBot.h"
+#include "debugoverlay_shared.h"
+#include <bitbuf.h>
+#include "viewrender.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+#undef NextBot
+
+ConVar NextBotShadowDist( "nb_shadow_dist", "400" );
+
+//-----------------------------------------------------------------------------
+IMPLEMENT_CLIENTCLASS_DT( C_NextBotCombatCharacter, DT_NextBot, NextBotCombatCharacter )
+END_RECV_TABLE()
+
+
+//-----------------------------------------------------------------------------
+C_NextBotCombatCharacter::C_NextBotCombatCharacter()
+{
+ // Left4Dead have surfaces too steep for IK to work properly
+ m_EntClientFlags |= ENTCLIENTFLAG_DONTUSEIK;
+
+ m_shadowType = SHADOWS_SIMPLE;
+ m_forcedShadowType = SHADOWS_NONE;
+ m_bForceShadowType = false;
+
+ TheClientNextBots().Register( this );
+}
+
+
+//-----------------------------------------------------------------------------
+C_NextBotCombatCharacter::~C_NextBotCombatCharacter()
+{
+ TheClientNextBots().UnRegister( this );
+}
+
+
+//-----------------------------------------------------------------------------
+void C_NextBotCombatCharacter::Spawn( void )
+{
+ BaseClass::Spawn();
+}
+
+
+//-----------------------------------------------------------------------------
+void C_NextBotCombatCharacter::UpdateClientSideAnimation()
+{
+ if (IsDormant())
+ {
+ return;
+ }
+
+ BaseClass::UpdateClientSideAnimation();
+}
+
+
+//--------------------------------------------------------------------------------------------------------
+void C_NextBotCombatCharacter::UpdateShadowLOD( void )
+{
+ ShadowType_t oldShadowType = m_shadowType;
+
+ if ( m_bForceShadowType )
+ {
+ m_shadowType = m_forcedShadowType;
+ }
+ else
+ {
+#ifdef NEED_SPLITSCREEN_INTEGRATION
+ FOR_EACH_VALID_SPLITSCREEN_PLAYER( hh )
+ {
+ C_BasePlayer *pl = C_BasePlayer::GetLocalPlayer(hh);
+ if ( pl )
+ {
+ Vector delta = GetAbsOrigin() - C_BasePlayer::GetLocalPlayer(hh)->GetAbsOrigin();
+#else
+ {
+ if ( C_BasePlayer::GetLocalPlayer() )
+ {
+ Vector delta = GetAbsOrigin() - C_BasePlayer::GetLocalPlayer()->GetAbsOrigin();
+#endif
+ if ( delta.IsLengthLessThan( NextBotShadowDist.GetFloat() ) )
+ {
+ m_shadowType = SHADOWS_RENDER_TO_TEXTURE_DYNAMIC;
+ }
+ else
+ {
+ m_shadowType = SHADOWS_SIMPLE;
+ }
+ }
+ else
+ {
+ m_shadowType = SHADOWS_SIMPLE;
+ }
+ }
+ }
+
+ if ( oldShadowType != m_shadowType )
+ {
+ DestroyShadow();
+ }
+}
+
+
+//--------------------------------------------------------------------------------------------------------
+ShadowType_t C_NextBotCombatCharacter::ShadowCastType( void )
+{
+ if ( !IsVisible() )
+ return SHADOWS_NONE;
+
+ if ( m_shadowTimer.IsElapsed() )
+ {
+ m_shadowTimer.Start( 0.15f );
+ UpdateShadowLOD();
+ }
+
+ return m_shadowType;
+}
+
+
+//--------------------------------------------------------------------------------------------------------
+bool C_NextBotCombatCharacter::GetForcedShadowCastType( ShadowType_t* pForcedShadowType ) const
+{
+ if ( pForcedShadowType )
+ {
+ *pForcedShadowType = m_forcedShadowType;
+ }
+ return m_bForceShadowType;
+}
+
+//--------------------------------------------------------------------------------------------------------
+/**
+ * Singleton accessor.
+ * By returning a reference, we guarantee construction of the
+ * instance before its first use.
+ */
+C_NextBotManager &TheClientNextBots( void )
+{
+ static C_NextBotManager manager;
+ return manager;
+}
+
+
+//--------------------------------------------------------------------------------------------------------
+C_NextBotManager::C_NextBotManager( void )
+{
+}
+
+
+//--------------------------------------------------------------------------------------------------------
+C_NextBotManager::~C_NextBotManager()
+{
+}
+
+
+//--------------------------------------------------------------------------------------------------------
+void C_NextBotManager::Register( C_NextBotCombatCharacter *bot )
+{
+ m_botList.AddToTail( bot );
+}
+
+
+//--------------------------------------------------------------------------------------------------------
+void C_NextBotManager::UnRegister( C_NextBotCombatCharacter *bot )
+{
+ m_botList.FindAndRemove( bot );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+bool C_NextBotManager::SetupInFrustumData( void )
+{
+#ifdef ENABLE_AFTER_INTEGRATION
+ // Done already this frame.
+ if ( IsInFrustumDataValid() )
+ return true;
+
+ // Can we use the view data yet?
+ if ( !FrustumCache()->IsValid() )
+ return false;
+
+ // Get the number of active bots.
+ int nBotCount = m_botList.Count();
+
+ // Reset.
+ for ( int iBot = 0; iBot < nBotCount; ++iBot )
+ {
+ // Get the current bot.
+ C_NextBotCombatCharacter *pBot = m_botList[iBot];
+ if ( !pBot )
+ continue;
+
+ pBot->InitFrustumData();
+ }
+
+ FOR_EACH_VALID_SPLITSCREEN_PLAYER( iSlot )
+ {
+ ACTIVE_SPLITSCREEN_PLAYER_GUARD( iSlot );
+ // Get the active local player.
+ C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
+ if ( !pPlayer )
+ continue;
+
+ for ( int iBot = 0; iBot < nBotCount; ++iBot )
+ {
+ // Get the current bot.
+ C_NextBotCombatCharacter *pBot = m_botList[iBot];
+ if ( !pBot )
+ continue;
+
+ // Are we in the view frustum?
+ Vector vecMin, vecMax;
+ pBot->CollisionProp()->WorldSpaceAABB( &vecMin, &vecMax );
+ bool bInFrustum = !FrustumCache()->m_Frustums[iSlot].CullBox( vecMin, vecMax );
+
+ if ( bInFrustum )
+ {
+ Vector vecSegment;
+ VectorSubtract( pBot->GetAbsOrigin(), pPlayer->GetAbsOrigin(), vecSegment );
+ float flDistance = vecSegment.LengthSqr();
+ if ( flDistance < pBot->GetInFrustumDistanceSqr() )
+ {
+ pBot->SetInFrustumDistanceSqr( flDistance );
+ }
+
+ pBot->SetInFrustum( true );
+ }
+ }
+ }
+
+ // Mark as setup this frame.
+ m_nInFrustumFrame = gpGlobals->framecount;
+#endif
+
+ return true;
+}
+
+//--------------------------------------------------------------------------------------------------------
diff --git a/game/client/NextBot/C_NextBot.h b/game/client/NextBot/C_NextBot.h
new file mode 100644
index 0000000..c26d7b9
--- /dev/null
+++ b/game/client/NextBot/C_NextBot.h
@@ -0,0 +1,134 @@
+// C_NextBot.h
+// Next generation bot system
+// Author: Michael Booth, April 2005
+//========= Copyright Valve Corporation, All rights reserved. ============//
+
+#ifndef _C_NEXT_BOT_H_
+#define _C_NEXT_BOT_H_
+
+#include "c_ai_basenpc.h"
+
+//----------------------------------------------------------------------------------------------------------------
+/**
+* The interface holding IBody information
+*/
+class IBodyClient
+{
+public:
+ enum ActivityType
+ {
+ MOTION_CONTROLLED_XY = 0x0001, // XY position and orientation of the bot is driven by the animation.
+ MOTION_CONTROLLED_Z = 0x0002, // Z position of the bot is driven by the animation.
+ ACTIVITY_UNINTERRUPTIBLE= 0x0004, // activity can't be changed until animation finishes
+ ACTIVITY_TRANSITORY = 0x0008, // a short animation that takes over from the underlying animation momentarily, resuming it upon completion
+ ENTINDEX_PLAYBACK_RATE = 0x0010, // played back at different rates based on entindex
+ };
+};
+
+
+//--------------------------------------------------------------------------------------------------------
+/**
+ * The client-side implementation of the NextBot
+ */
+class C_NextBotCombatCharacter : public C_BaseCombatCharacter
+{
+public:
+ DECLARE_CLASS( C_NextBotCombatCharacter, C_BaseCombatCharacter );
+ DECLARE_CLIENTCLASS();
+
+ C_NextBotCombatCharacter();
+ virtual ~C_NextBotCombatCharacter();
+
+public:
+ virtual void Spawn( void );
+ virtual void UpdateClientSideAnimation( void );
+ virtual ShadowType_t ShadowCastType( void );
+ virtual bool IsNextBot() { return true; }
+ void ForceShadowCastType( bool bForce, ShadowType_t forcedShadowType = SHADOWS_NONE ) { m_bForceShadowType = bForce; m_forcedShadowType = forcedShadowType; }
+ bool GetForcedShadowCastType( ShadowType_t* pForcedShadowType ) const;
+
+ // Local In View Data.
+ void InitFrustumData( void ) { m_bInFrustum = false; m_flFrustumDistanceSqr = FLT_MAX; m_nInFrustumFrame = gpGlobals->framecount; }
+ bool IsInFrustumValid( void ) { return ( m_nInFrustumFrame == gpGlobals->framecount ); }
+ void SetInFrustum( bool bInFrustum ) { m_bInFrustum = bInFrustum; }
+ bool IsInFrustum( void ) { return m_bInFrustum; }
+ void SetInFrustumDistanceSqr( float flDistance ) { m_flFrustumDistanceSqr = flDistance; }
+ float GetInFrustumDistanceSqr( void ) { return m_flFrustumDistanceSqr; }
+
+private:
+ ShadowType_t m_shadowType; // Are we LOD'd to simple shadows?
+ CountdownTimer m_shadowTimer; // Timer to throttle checks for shadow LOD
+ ShadowType_t m_forcedShadowType;
+ bool m_bForceShadowType;
+ void UpdateShadowLOD( void );
+
+ // Local In View Data.
+ int m_nInFrustumFrame;
+ bool m_bInFrustum;
+ float m_flFrustumDistanceSqr;
+
+private:
+ C_NextBotCombatCharacter( const C_NextBotCombatCharacter & ); // not defined, not accessible
+};
+
+//--------------------------------------------------------------------------------------------------------
+/**
+ * The C_NextBotManager manager
+ */
+class C_NextBotManager
+{
+public:
+ C_NextBotManager( void );
+ ~C_NextBotManager();
+
+ /**
+ * Execute functor for each NextBot in the system.
+ * If a functor returns false, stop iteration early
+ * and return false.
+ */
+ template < typename Functor >
+ bool ForEachCombatCharacter( Functor &func )
+ {
+ for( int i=0; i < m_botList.Count(); ++i )
+ {
+ C_NextBotCombatCharacter *character = m_botList[i];
+ if ( character->IsPlayer() )
+ {
+ continue;
+ }
+
+ if ( character->IsDormant() )
+ {
+ continue;
+ }
+
+ if ( !func( character ) )
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ int GetActiveCount() { return m_botList.Count(); }
+
+ bool SetupInFrustumData( void );
+ bool IsInFrustumDataValid( void ) { return ( m_nInFrustumFrame == gpGlobals->framecount ); }
+
+private:
+ friend class C_NextBotCombatCharacter;
+
+ void Register( C_NextBotCombatCharacter *bot );
+ void UnRegister( C_NextBotCombatCharacter *bot );
+
+ CUtlVector< C_NextBotCombatCharacter * > m_botList; ///< list of all active NextBots
+
+ int m_nInFrustumFrame;
+};
+
+// singleton accessor
+extern C_NextBotManager &TheClientNextBots( void );
+
+
+#endif // _C_NEXT_BOT_H_