Team Fortress 2 Source Code as on 22/4/2020
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.
 
 
 
 
 
 

437 lines
13 KiB

//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: The robots for use in the Robot Destruction TF2 game mode.
//
//=========================================================================//
#ifndef ROBOT_DESTRUCTION_ROBOT_H
#define ROBOT_DESTRUCTION_ROBOT_H
#pragma once
#include "cbase.h"
#ifdef GAME_DLL
#include "tf_shareddefs.h"
#include "pathtrack.h"
#include "NextBotGroundLocomotion.h"
#include "NextBotIntentionInterface.h"
#include "NextBotBehavior.h"
#include "NextBot.h"
#include "../server/NextBot/Path/NextBotPathFollow.h"
#include "../server/NextBot/Path/NextBotPath.h"
#include "../server/tf/halloween/headless_hatman_body.h"
#include "tf_obj_dispenser.h"
#else
#include "c_obj_dispenser.h"
#endif
#ifdef CLIENT_DLL
#define CTFRobotDestruction_Robot C_TFRobotDestruction_Robot
#define CRobotDispenser C_RobotDispenser
#endif
#include "props_shared.h"
enum eRobotType
{
ROBOT_TYPE_FRUSTUM = 0,
ROBOT_TYPE_SPHERE,
ROBOT_TYPE_KING,
NUM_ROBOT_TYPES
};
enum eRobotUIState
{
ROBOT_STATE_INACIVE = 0,
ROBOT_STATE_ACTIVE,
ROBOT_STATE_DEAD,
ROBOT_STATE_SHIELDED,
NUM_ROBOT_STATES
};
struct RobotData_t
{
public:
enum EStringDataKey_t
{
MODEL_KEY = 0,
DAMAGED_MODEL_KEY,
HURT_SOUND_KEY,
DEATH_SOUND_KEY,
COLLIDE_SOUND_KEY,
IDLE_SOUND_KEY
};
enum EFloatDataKey_t
{
HEALTH_BAR_OFFSET_KEY
};
RobotData_t( const char* pszModelName
, const char* pszDamagedModelName
, const char *pszHurtSound
, const char *pszDeathSound
, const char *pszCollideSound
, const char *pszIdleSound
, float flHealthBarOffset )
{
m_stringMap.SetLessFunc( DefLessFunc(int) );
m_floatMap.SetLessFunc( DefLessFunc(int) );
m_stringMap.Insert( MODEL_KEY, pszModelName );
m_stringMap.Insert( DAMAGED_MODEL_KEY, pszDamagedModelName );
m_stringMap.Insert( HURT_SOUND_KEY, pszHurtSound );
m_stringMap.Insert( DEATH_SOUND_KEY, pszDeathSound );
m_stringMap.Insert( COLLIDE_SOUND_KEY, pszCollideSound );
m_stringMap.Insert( IDLE_SOUND_KEY, pszIdleSound );
m_floatMap.Insert( HEALTH_BAR_OFFSET_KEY, flHealthBarOffset );
}
const char* GetStringData( EStringDataKey_t key ) const
{
return GetData< const char * >( m_stringMap, (int)key );
}
float GetFloatData( EFloatDataKey_t key ) const
{
return GetData< float >( m_floatMap, (int)key );
}
void Precache();
private:
template< typename T >
T GetData( const CUtlMap< int, T >& map, int nKey ) const
{
int nIndex = map.Find( nKey );
if ( nIndex != map.InvalidIndex() )
{
return map.Element( nIndex );
}
AssertMsg1( 0, "No entry for key %d", nKey );
return T(0);
}
CUtlMap< int, const char * > m_stringMap;
CUtlMap< int, float > m_floatMap;
};
class CTFRobotDestruction_Robot;
#ifdef GAME_DLL
struct RobotSpawnData_t
{
RobotSpawnData_t()
: m_eType( ROBOT_TYPE_FRUSTUM )
, m_nRobotHealth( 100 )
, m_nPoints( 0 )
, m_nNumGibs( 0 )
, m_pszPathName( NULL )
, m_pszGroupName( NULL )
{}
RobotSpawnData_t &operator=( const RobotSpawnData_t& rhs )
{
m_eType = rhs.m_eType;
m_nRobotHealth = rhs.m_nRobotHealth;
m_nPoints = rhs.m_nPoints;
m_nNumGibs = rhs.m_nNumGibs;
m_pszPathName = rhs.m_pszPathName;
m_pszGroupName = rhs.m_pszGroupName;
return *this;
}
eRobotType m_eType;
int m_nRobotHealth;
int m_nPoints;
int m_nNumGibs;
const char *m_pszPathName;
const char *m_pszGroupName;
};
//----------------------------------------------------------------------------
class CRobotLocomotion : public NextBotGroundLocomotion
{
public:
CRobotLocomotion( INextBot *bot ) : NextBotGroundLocomotion( bot ) { }
virtual ~CRobotLocomotion() { }
virtual float GetGroundSpeed() const OVERRIDE;
virtual float GetRunSpeed( void ) const OVERRIDE; // get maximum running speed
virtual float GetStepHeight( void ) const OVERRIDE; // if delta Z is greater than this, we have to jump to get up
virtual float GetMaxJumpHeight( void ) const OVERRIDE; // return maximum height of a jump
virtual bool ShouldCollideWith( const CBaseEntity *object ) const OVERRIDE;
private:
virtual float GetMaxYawRate( void ) const OVERRIDE; // return max rate of yaw rotation
};
//----------------------------------------------------------------------------
class CRobotIntention : public IIntention
{
public:
CRobotIntention( class CTFRobotDestruction_Robot *me );
virtual ~CRobotIntention();
virtual void Reset( void ) OVERRIDE;
virtual void Update( void ) OVERRIDE;
virtual QueryResultType IsPositionAllowed( const INextBot *me, const Vector &pos ) const OVERRIDE; // is the a place we can be?
virtual INextBotEventResponder *FirstContainedResponder( void ) const OVERRIDE { return m_behavior; }
virtual INextBotEventResponder *NextContainedResponder( INextBotEventResponder *current ) const OVERRIDE { return NULL; }
private:
Behavior< CTFRobotDestruction_Robot > *m_behavior;
};
//---------------------------------------------------------------------------------------------
class CRobotBehavior : public Action< CTFRobotDestruction_Robot >
{
public:
virtual Action< CTFRobotDestruction_Robot > *InitialContainedAction( CTFRobotDestruction_Robot *me ) OVERRIDE;
virtual ActionResult< CTFRobotDestruction_Robot > OnStart( CTFRobotDestruction_Robot *me, Action< CTFRobotDestruction_Robot > *priorAction ) OVERRIDE;
virtual ActionResult< CTFRobotDestruction_Robot > Update( CTFRobotDestruction_Robot *me, float interval ) OVERRIDE;
virtual EventDesiredResult< CTFRobotDestruction_Robot > OnInjured( CTFRobotDestruction_Robot *me, const CTakeDamageInfo &info );
EventDesiredResult< CTFRobotDestruction_Robot > OnContact( CTFRobotDestruction_Robot *me, CBaseEntity *pOther, CGameTrace *result = NULL );
virtual const char *GetName( void ) const { return "RobotBehavior"; } // return name of this action
private:
CountdownTimer m_SpeakTimer;
CountdownTimer m_IdleSpeakTimer;
};
#endif
class CRobotDispenser :
#ifdef GAME_DLL
public CObjectDispenser
#else
public C_ObjectDispenser
#endif
{
#ifdef GAME_DLL
DECLARE_CLASS( CRobotDispenser, CObjectDispenser )
#else
DECLARE_CLASS( CRobotDispenser, C_ObjectDispenser )
#endif
DECLARE_NETWORKCLASS();
DECLARE_DATADESC();
public:
#ifdef GAME_DLL
CRobotDispenser();
virtual void Spawn( void ) OVERRIDE;
virtual void OnGoActive( void ) OVERRIDE;
virtual void GetControlPanelInfo( int nPanelIndex, const char *&pPanelName ) OVERRIDE;
virtual void SetModel( const char *pModel ) OVERRIDE;
virtual float GetDispenserRadius( void ) OVERRIDE { return 128; }
virtual float GetHealRate() const OVERRIDE { return 5.f; }
virtual int DispenseMetal( CTFPlayer * ) OVERRIDE { return 0; }
virtual bool DispenseAmmo( CTFPlayer * ) OVERRIDE { return false; }
private:
virtual void PlayActiveSound() OVERRIDE { /*DO NOTHING*/ }
#endif
};
class CTFRobotDestruction_RobotAnimController
{
public:
CTFRobotDestruction_RobotAnimController( CTFRobotDestruction_Robot *pOuter );
void Update();
void Impulse( const Vector& vecImpulse );
private:
void Approach( Vector& vecIn, const Vector& vecTarget, float flRate );
void GetPoseParams();
Vector m_vecOldOrigin;
Vector m_vecLean;
Vector m_vecImpulse;
CTFRobotDestruction_Robot *m_pOuter;
struct PoseParams_t
{
int m_nMoveX;
int m_nMoveY;
} m_poseParams;
};
#ifdef GAME_DLL
typedef NextBotCombatCharacter RobotBaseClass;
#else
typedef CBaseCombatCharacter RobotBaseClass;
#endif
class CTFRobotDestruction_Robot : public RobotBaseClass
#ifdef CLIENT_DLL
, public CGameEventListener
#endif
{
DECLARE_DATADESC();
DECLARE_CLASS( CTFRobotDestruction_Robot, RobotBaseClass )
DECLARE_NETWORKCLASS();
public:
CTFRobotDestruction_Robot( void );
virtual ~CTFRobotDestruction_Robot( void );
static void StaticPrecache( void );
virtual void Precache( void ) OVERRIDE;
virtual void Spawn( void ) OVERRIDE;
virtual bool ShouldCollide( int collisionGroup, int contentsMask ) const OVERRIDE;
#ifdef CLIENT_DLL
virtual float GetHealthBarHeightOffset( void ) const OVERRIDE;
virtual void OnDataChanged( DataUpdateType_t type ) OVERRIDE;
virtual int GetHealth( void ) const OVERRIDE { return m_iHealth; }
virtual int GetMaxHealth( void ) const OVERRIDE { return m_iMaxHealth; }
virtual bool IsHealthBarVisible( void ) const OVERRIDE { return true; }
virtual void UpdateClientSideAnimation( void ) OVERRIDE;
virtual void FireGameEvent( IGameEvent *event ) OVERRIDE;
virtual CStudioHdr* OnNewModel() OVERRIDE;
virtual void FireEvent( const Vector& origin, const QAngle& angles, int event, const char *options ) OVERRIDE;
void UpdateDamagedEffects( void );
#else
virtual void HandleAnimEvent( animevent_t *pEvent ) OVERRIDE;
virtual bool IsRemovedOnReset( void ) const { return false; }
virtual void UpdateOnRemove( void ) OVERRIDE;
virtual void Event_Killed( const CTakeDamageInfo &info ) OVERRIDE;
virtual int OnTakeDamage( const CTakeDamageInfo &info ) OVERRIDE;
virtual void TraceAttack( const CTakeDamageInfo &inputInfo, const Vector &vecDir, trace_t *ptr, CDmgAccumulator *pAccumulator ) OVERRIDE;
virtual void UpdateAnimsThink( void );
void RepairSelfThink( void );
bool GetShieldedState( void ) const { return m_bShielded; }
CPathTrack *GetNextPath( void ) const { return m_hNextPath; }
void ArriveAtPath( void );
void SetRobotSpawnData( const RobotSpawnData_t& data ) { m_spawnData = data; m_eType = data.m_eType; }
const RobotSpawnData_t &GetRobotSpawnData() const { return m_spawnData; }
void SetGroup( class CTFRobotDestruction_RobotGroup* pGroup ) { m_hGroup.Set( pGroup ); }
void SetSpawn( class CTFRobotDestruction_RobotSpawn* pSpawn ) { m_hSpawn.Set( pSpawn ); }
void EnableUber( void );
void DisableUber( void );
// INextBot
virtual CRobotIntention *GetIntentionInterface( void ) const { return m_intention; }
virtual CRobotLocomotion *GetLocomotionInterface( void ) const { return m_locomotor; }
virtual CHeadlessHatmanBody *GetBodyInterface( void ) const { return m_body; }
void SetNewActivity( Activity activity );
void SetIsPanicked( bool bPanicked ) { m_bIsPanicked = bPanicked; }
bool GetIsPanicked( void ) const { return m_bIsPanicked; }
//Inputs
void InputStopAndUseComputer( inputdata_t &inputdata );
private:
void PlayDeathEffects( void );
void ModifyDamage( CTakeDamageInfo *info ) const;
void SpewBars( int nNumToSpew );
void SpewBarsThink( void );
void SelfDestructThink( void );
void SpewGibs( void );
#endif
private:
int m_iHealth;
int m_iMaxHealth;
CUtlVector<breakmodel_t> m_aGibs;
CUtlVector<breakmodel_t> m_aSpawnProps;
CTFRobotDestruction_RobotAnimController m_animController;
CNetworkVar( bool, m_bShielded );
CNetworkVar( eRobotType, m_eType );
#ifdef CLIENT_DLL
HPARTICLEFFECT m_hDamagedParticleEffect;
#else
CRobotDispenser *m_pDispenser;
RobotSpawnData_t m_spawnData;
CHandle< CPathTrack > m_hNextPath;
int m_nPointsSpewed;
IMPLEMENT_NETWORK_VAR_FOR_DERIVED( m_iHealth );
CHandle< CTFRobotDestruction_RobotGroup > m_hGroup;
CHandle< CTFRobotDestruction_RobotSpawn > m_hSpawn;
CRobotIntention *m_intention;
CRobotLocomotion *m_locomotor;
CHeadlessHatmanBody *m_body;
bool m_bIsPanicked;
#endif
};
#ifdef GAME_DLL
//--------------------------------------------------------------------------------------------------------------
class CRobotPathCost : public IPathCost
{
public:
CRobotPathCost( CTFRobotDestruction_Robot *me )
{
m_me = me;
}
// return the cost (weighted distance between) of moving from "fromArea" to "area", or -1 if the move is not allowed
virtual float operator()( CNavArea *area, CNavArea *fromArea, const CNavLadder *ladder, const CFuncElevator *elevator, float length ) const
{
if ( fromArea == NULL )
{
// first area in path, no cost
return 0.0f;
}
else
{
if ( !m_me->GetLocomotionInterface()->IsAreaTraversable( area ) )
{
// our locomotor says we can't move here
return -1.0f;
}
// compute distance traveled along path so far
float dist;
if ( ladder )
{
dist = ladder->m_length;
}
else if ( length > 0.0 )
{
// optimization to avoid recomputing length
dist = length;
}
else
{
dist = ( area->GetCenter() - fromArea->GetCenter() ).Length();
}
// check height change
float deltaZ = fromArea->ComputeAdjacentConnectionHeightChange( area );
if ( deltaZ >= m_me->GetLocomotionInterface()->GetStepHeight() )
{
if ( deltaZ >= m_me->GetLocomotionInterface()->GetMaxJumpHeight() )
{
// too high to reach
return -1.0f;
}
// jumping is slower than flat ground
const float jumpPenalty = 5.0f;
dist += jumpPenalty * dist;
}
else if ( deltaZ < -m_me->GetLocomotionInterface()->GetDeathDropHeight() )
{
// too far to drop
return -1.0f;
}
return dist + fromArea->GetCostSoFar();
}
}
CTFRobotDestruction_Robot *m_me;
};
#endif // GAME_DLL
#endif // ROBOT_DESTRUCTION_ROBOT_H