You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
246 lines
6.0 KiB
246 lines
6.0 KiB
![]()
4 years ago
|
// 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;
|
||
|
}
|
||
|
|
||
|
//--------------------------------------------------------------------------------------------------------
|