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
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
|