initial
This commit is contained in:
245
game/client/NextBot/C_NextBot.cpp
Normal file
245
game/client/NextBot/C_NextBot.cpp
Normal file
@@ -0,0 +1,245 @@
|
||||
// C_NextBot.cpp
|
||||
// Client-side implementation of Next generation bot system
|
||||
// Author: Michael Booth, April 2005
|
||||
// Copyright (c) 2005 Turtle Rock Studios, Inc. - 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;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
134
game/client/NextBot/C_NextBot.h
Normal file
134
game/client/NextBot/C_NextBot.h
Normal file
@@ -0,0 +1,134 @@
|
||||
// C_NextBot.h
|
||||
// Next generation bot system
|
||||
// Author: Michael Booth, April 2005
|
||||
// Copyright (c) 2005 Turtle Rock Studios, Inc. - 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_
|
||||
Reference in New Issue
Block a user