Fix line endings. WHAMMY.

This commit is contained in:
Jørgen P. Tjernø
2013-12-02 19:31:46 -08:00
parent c47ad60970
commit f56bb35301
6719 changed files with 2805089 additions and 2805089 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -1,237 +1,237 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#ifndef AI_CRITERIA_H
#define AI_CRITERIA_H
#ifdef _WIN32
#pragma once
#endif
#include "tier1/utlrbtree.h"
#include "tier1/utlsymbol.h"
#include "interval.h"
#include "mathlib/compressed_vector.h"
extern const char *SplitContext( const char *raw, char *key, int keylen, char *value, int valuelen, float *duration );
class AI_CriteriaSet
{
public:
AI_CriteriaSet();
AI_CriteriaSet( const AI_CriteriaSet& src );
~AI_CriteriaSet();
void AppendCriteria( const char *criteria, const char *value = "", float weight = 1.0f );
void RemoveCriteria( const char *criteria );
void Describe();
int GetCount() const;
int FindCriterionIndex( const char *name ) const;
const char *GetName( int index ) const;
const char *GetValue( int index ) const;
float GetWeight( int index ) const;
private:
struct CritEntry_t
{
CritEntry_t() :
criterianame( UTL_INVAL_SYMBOL ),
weight( 0.0f )
{
value[ 0 ] = 0;
}
CritEntry_t( const CritEntry_t& src )
{
criterianame = src.criterianame;
value[ 0 ] = 0;
weight = src.weight;
SetValue( src.value );
}
CritEntry_t& operator=( const CritEntry_t& src )
{
if ( this == &src )
return *this;
criterianame = src.criterianame;
weight = src.weight;
SetValue( src.value );
return *this;
}
static bool LessFunc( const CritEntry_t& lhs, const CritEntry_t& rhs )
{
return Q_stricmp( lhs.criterianame.String(), rhs.criterianame.String() ) < 0 ? true : false;
}
void SetValue( char const *str )
{
if ( !str )
{
value[ 0 ] = 0;
}
else
{
Q_strncpy( value, str, sizeof( value ) );
}
}
CUtlSymbol criterianame;
char value[ 64 ];
float weight;
};
CUtlRBTree< CritEntry_t, short > m_Lookup;
};
#pragma pack(1)
template<typename T>
struct response_interval_t
{
T start;
T range;
interval_t &ToInterval( interval_t &dest ) const { dest.start = start; dest.range = range; return dest; }
void FromInterval( const interval_t &from ) { start = from.start; range = from.range; }
float Random() const { interval_t temp = { start, range }; return RandomInterval( temp ); }
};
typedef response_interval_t<float16_with_assign> responseparams_interval_t;
struct AI_ResponseParams
{
DECLARE_SIMPLE_DATADESC();
enum
{
RG_DELAYAFTERSPEAK = (1<<0),
RG_SPEAKONCE = (1<<1),
RG_ODDS = (1<<2),
RG_RESPEAKDELAY = (1<<3),
RG_SOUNDLEVEL = (1<<4),
RG_DONT_USE_SCENE = (1<<5),
RG_STOP_ON_NONIDLE = (1<<6),
RG_WEAPONDELAY = (1<<7),
RG_DELAYBEFORESPEAK = (1<<8),
};
AI_ResponseParams()
{
flags = 0;
odds = 100;
delay.start = 0;
delay.range = 0;
respeakdelay.start = 0;
respeakdelay.range = 0;
weapondelay.start = 0;
weapondelay.range = 0;
soundlevel = 0;
predelay.start = 0;
predelay.range = 0;
}
responseparams_interval_t delay; //4
responseparams_interval_t respeakdelay; //8
responseparams_interval_t weapondelay; //12
short odds; //14
short flags; //16
byte soundlevel; //17
responseparams_interval_t predelay; //21
};
#pragma pack()
//-----------------------------------------------------------------------------
// Purpose: Generic container for a response to a match to a criteria set
// This is what searching for a response returns
//-----------------------------------------------------------------------------
enum ResponseType_t
{
RESPONSE_NONE = 0,
RESPONSE_SPEAK,
RESPONSE_SENTENCE,
RESPONSE_SCENE,
RESPONSE_RESPONSE, // A reference to another response by name
RESPONSE_PRINT,
NUM_RESPONSES,
};
class AI_Response
{
public:
DECLARE_SIMPLE_DATADESC();
AI_Response();
AI_Response( const AI_Response &from );
~AI_Response();
AI_Response &operator=( const AI_Response &from );
void Release();
void GetName( char *buf, size_t buflen ) const;
void GetResponse( char *buf, size_t buflen ) const;
const AI_ResponseParams *GetParams() const { return &m_Params; }
ResponseType_t GetType() const { return (ResponseType_t)m_Type; }
soundlevel_t GetSoundLevel() const;
float GetRespeakDelay() const;
float GetWeaponDelay() const;
bool GetSpeakOnce() const;
bool ShouldntUseScene( ) const;
bool ShouldBreakOnNonIdle( void ) const;
int GetOdds() const;
float GetDelay() const;
float GetPreDelay() const;
void SetContext( const char *context );
const char * GetContext( void ) const { return m_szContext; }
bool IsApplyContextToWorld( void ) { return m_bApplyContextToWorld; }
void Describe();
const AI_CriteriaSet* GetCriteria();
void Init( ResponseType_t type,
const char *responseName,
const AI_CriteriaSet& criteria,
const AI_ResponseParams& responseparams,
const char *matchingRule,
const char *applyContext,
bool bApplyContextToWorld );
static const char *DescribeResponse( ResponseType_t type );
enum
{
MAX_RESPONSE_NAME = 64,
MAX_RULE_NAME = 64
};
private:
byte m_Type;
char m_szResponseName[ MAX_RESPONSE_NAME ];
char m_szMatchingRule[ MAX_RULE_NAME ];
// The initial criteria to which we are responsive
AI_CriteriaSet *m_pCriteria;
AI_ResponseParams m_Params;
char * m_szContext;
bool m_bApplyContextToWorld;
};
#endif // AI_CRITERIA_H
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#ifndef AI_CRITERIA_H
#define AI_CRITERIA_H
#ifdef _WIN32
#pragma once
#endif
#include "tier1/utlrbtree.h"
#include "tier1/utlsymbol.h"
#include "interval.h"
#include "mathlib/compressed_vector.h"
extern const char *SplitContext( const char *raw, char *key, int keylen, char *value, int valuelen, float *duration );
class AI_CriteriaSet
{
public:
AI_CriteriaSet();
AI_CriteriaSet( const AI_CriteriaSet& src );
~AI_CriteriaSet();
void AppendCriteria( const char *criteria, const char *value = "", float weight = 1.0f );
void RemoveCriteria( const char *criteria );
void Describe();
int GetCount() const;
int FindCriterionIndex( const char *name ) const;
const char *GetName( int index ) const;
const char *GetValue( int index ) const;
float GetWeight( int index ) const;
private:
struct CritEntry_t
{
CritEntry_t() :
criterianame( UTL_INVAL_SYMBOL ),
weight( 0.0f )
{
value[ 0 ] = 0;
}
CritEntry_t( const CritEntry_t& src )
{
criterianame = src.criterianame;
value[ 0 ] = 0;
weight = src.weight;
SetValue( src.value );
}
CritEntry_t& operator=( const CritEntry_t& src )
{
if ( this == &src )
return *this;
criterianame = src.criterianame;
weight = src.weight;
SetValue( src.value );
return *this;
}
static bool LessFunc( const CritEntry_t& lhs, const CritEntry_t& rhs )
{
return Q_stricmp( lhs.criterianame.String(), rhs.criterianame.String() ) < 0 ? true : false;
}
void SetValue( char const *str )
{
if ( !str )
{
value[ 0 ] = 0;
}
else
{
Q_strncpy( value, str, sizeof( value ) );
}
}
CUtlSymbol criterianame;
char value[ 64 ];
float weight;
};
CUtlRBTree< CritEntry_t, short > m_Lookup;
};
#pragma pack(1)
template<typename T>
struct response_interval_t
{
T start;
T range;
interval_t &ToInterval( interval_t &dest ) const { dest.start = start; dest.range = range; return dest; }
void FromInterval( const interval_t &from ) { start = from.start; range = from.range; }
float Random() const { interval_t temp = { start, range }; return RandomInterval( temp ); }
};
typedef response_interval_t<float16_with_assign> responseparams_interval_t;
struct AI_ResponseParams
{
DECLARE_SIMPLE_DATADESC();
enum
{
RG_DELAYAFTERSPEAK = (1<<0),
RG_SPEAKONCE = (1<<1),
RG_ODDS = (1<<2),
RG_RESPEAKDELAY = (1<<3),
RG_SOUNDLEVEL = (1<<4),
RG_DONT_USE_SCENE = (1<<5),
RG_STOP_ON_NONIDLE = (1<<6),
RG_WEAPONDELAY = (1<<7),
RG_DELAYBEFORESPEAK = (1<<8),
};
AI_ResponseParams()
{
flags = 0;
odds = 100;
delay.start = 0;
delay.range = 0;
respeakdelay.start = 0;
respeakdelay.range = 0;
weapondelay.start = 0;
weapondelay.range = 0;
soundlevel = 0;
predelay.start = 0;
predelay.range = 0;
}
responseparams_interval_t delay; //4
responseparams_interval_t respeakdelay; //8
responseparams_interval_t weapondelay; //12
short odds; //14
short flags; //16
byte soundlevel; //17
responseparams_interval_t predelay; //21
};
#pragma pack()
//-----------------------------------------------------------------------------
// Purpose: Generic container for a response to a match to a criteria set
// This is what searching for a response returns
//-----------------------------------------------------------------------------
enum ResponseType_t
{
RESPONSE_NONE = 0,
RESPONSE_SPEAK,
RESPONSE_SENTENCE,
RESPONSE_SCENE,
RESPONSE_RESPONSE, // A reference to another response by name
RESPONSE_PRINT,
NUM_RESPONSES,
};
class AI_Response
{
public:
DECLARE_SIMPLE_DATADESC();
AI_Response();
AI_Response( const AI_Response &from );
~AI_Response();
AI_Response &operator=( const AI_Response &from );
void Release();
void GetName( char *buf, size_t buflen ) const;
void GetResponse( char *buf, size_t buflen ) const;
const AI_ResponseParams *GetParams() const { return &m_Params; }
ResponseType_t GetType() const { return (ResponseType_t)m_Type; }
soundlevel_t GetSoundLevel() const;
float GetRespeakDelay() const;
float GetWeaponDelay() const;
bool GetSpeakOnce() const;
bool ShouldntUseScene( ) const;
bool ShouldBreakOnNonIdle( void ) const;
int GetOdds() const;
float GetDelay() const;
float GetPreDelay() const;
void SetContext( const char *context );
const char * GetContext( void ) const { return m_szContext; }
bool IsApplyContextToWorld( void ) { return m_bApplyContextToWorld; }
void Describe();
const AI_CriteriaSet* GetCriteria();
void Init( ResponseType_t type,
const char *responseName,
const AI_CriteriaSet& criteria,
const AI_ResponseParams& responseparams,
const char *matchingRule,
const char *applyContext,
bool bApplyContextToWorld );
static const char *DescribeResponse( ResponseType_t type );
enum
{
MAX_RESPONSE_NAME = 64,
MAX_RULE_NAME = 64
};
private:
byte m_Type;
char m_szResponseName[ MAX_RESPONSE_NAME ];
char m_szMatchingRule[ MAX_RULE_NAME ];
// The initial criteria to which we are responsive
AI_CriteriaSet *m_pCriteria;
AI_ResponseParams m_Params;
char * m_szContext;
bool m_bApplyContextToWorld;
};
#endif // AI_CRITERIA_H

View File

@@ -1,139 +1,139 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Hooks and classes for the support of humanoid NPCs with
// groovy facial animation capabilities, aka, "Actors"
//
//=============================================================================//
#include "cbase.h"
#include "AI_Interest_Target.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
bool CAI_InterestTarget_t::IsThis( CBaseEntity *pThis )
{
return (pThis == m_hTarget);
};
const Vector &CAI_InterestTarget_t::GetPosition( void )
{
if (m_eType == LOOKAT_ENTITY && m_hTarget != NULL)
{
m_vecPosition = m_hTarget->EyePosition();
}
return m_vecPosition;
};
bool CAI_InterestTarget_t::IsActive( void )
{
if (m_flEndTime < gpGlobals->curtime) return false;
if (m_eType == LOOKAT_ENTITY && m_hTarget == NULL) return false;
return true;
};
float CAI_InterestTarget_t::Interest( void )
{
float t = (gpGlobals->curtime - m_flStartTime) / (m_flEndTime - m_flStartTime);
if (t < 0.0f || t > 1.0f)
return 0.0f;
if (m_flRamp && t < 1 - m_flRamp)
{
//t = t / m_flRamp;
t = 1.0 - ExponentialDecay( 0.2, m_flRamp, t );
//t = 1.0 - ExponentialDecay( 0.01, 1 - m_flRamp, t );
}
else if (t > 1.0f - m_flRamp)
{
t = (1.0 - t) / m_flRamp;
t = 3.0f * t * t - 2.0f * t * t * t;
}
else
{
t = 1.0f;
}
// ramp
t *= m_flInterest;
return t;
}
void CAI_InterestTarget::Add( CBaseEntity *pTarget, float flImportance, float flDuration, float flRamp )
{
int i;
for (i = 0; i < Count(); i++)
{
CAI_InterestTarget_t &target = Element( i );
if (target.m_hTarget == pTarget && target.m_flRamp == 0)
{
if (target.m_flStartTime == gpGlobals->curtime)
{
flImportance = MAX( flImportance, target.m_flInterest );
}
Remove( i );
break;
}
}
Add( CAI_InterestTarget_t::LOOKAT_ENTITY, pTarget, Vector( 0, 0, 0 ), flImportance, flDuration, flRamp );
}
void CAI_InterestTarget::Add( const Vector &vecPosition, float flImportance, float flDuration, float flRamp )
{
int i;
for (i = 0; i < Count(); i++)
{
CAI_InterestTarget_t &target = Element( i );
if (target.m_vecPosition == vecPosition)
{
Remove( i );
break;
}
}
Add( CAI_InterestTarget_t::LOOKAT_POSITION, NULL, vecPosition, flImportance, flDuration, flRamp );
}
void CAI_InterestTarget::Add( CBaseEntity *pTarget, const Vector &vecPosition, float flImportance, float flDuration, float flRamp )
{
int i;
for (i = 0; i < Count(); i++)
{
CAI_InterestTarget_t &target = Element( i );
if (target.m_hTarget == pTarget)
{
if (target.m_flStartTime == gpGlobals->curtime)
{
flImportance = MAX( flImportance, target.m_flInterest );
}
Remove( i );
break;
}
}
Add( CAI_InterestTarget_t::LOOKAT_BOTH, pTarget, vecPosition, flImportance, flDuration, flRamp );
}
void CAI_InterestTarget::Add( CAI_InterestTarget_t::CAI_InterestTarget_e type, CBaseEntity *pTarget, const Vector &vecPosition, float flImportance, float flDuration, float flRamp )
{
int i = AddToTail();
CAI_InterestTarget_t &target = Element( i );
target.m_eType = type;
target.m_hTarget = pTarget;
target.m_vecPosition = vecPosition;
target.m_flInterest = flImportance;
target.m_flStartTime = gpGlobals->curtime;
target.m_flEndTime = gpGlobals->curtime + flDuration;
target.m_flRamp = flRamp / flDuration;
}
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Hooks and classes for the support of humanoid NPCs with
// groovy facial animation capabilities, aka, "Actors"
//
//=============================================================================//
#include "cbase.h"
#include "AI_Interest_Target.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
bool CAI_InterestTarget_t::IsThis( CBaseEntity *pThis )
{
return (pThis == m_hTarget);
};
const Vector &CAI_InterestTarget_t::GetPosition( void )
{
if (m_eType == LOOKAT_ENTITY && m_hTarget != NULL)
{
m_vecPosition = m_hTarget->EyePosition();
}
return m_vecPosition;
};
bool CAI_InterestTarget_t::IsActive( void )
{
if (m_flEndTime < gpGlobals->curtime) return false;
if (m_eType == LOOKAT_ENTITY && m_hTarget == NULL) return false;
return true;
};
float CAI_InterestTarget_t::Interest( void )
{
float t = (gpGlobals->curtime - m_flStartTime) / (m_flEndTime - m_flStartTime);
if (t < 0.0f || t > 1.0f)
return 0.0f;
if (m_flRamp && t < 1 - m_flRamp)
{
//t = t / m_flRamp;
t = 1.0 - ExponentialDecay( 0.2, m_flRamp, t );
//t = 1.0 - ExponentialDecay( 0.01, 1 - m_flRamp, t );
}
else if (t > 1.0f - m_flRamp)
{
t = (1.0 - t) / m_flRamp;
t = 3.0f * t * t - 2.0f * t * t * t;
}
else
{
t = 1.0f;
}
// ramp
t *= m_flInterest;
return t;
}
void CAI_InterestTarget::Add( CBaseEntity *pTarget, float flImportance, float flDuration, float flRamp )
{
int i;
for (i = 0; i < Count(); i++)
{
CAI_InterestTarget_t &target = Element( i );
if (target.m_hTarget == pTarget && target.m_flRamp == 0)
{
if (target.m_flStartTime == gpGlobals->curtime)
{
flImportance = MAX( flImportance, target.m_flInterest );
}
Remove( i );
break;
}
}
Add( CAI_InterestTarget_t::LOOKAT_ENTITY, pTarget, Vector( 0, 0, 0 ), flImportance, flDuration, flRamp );
}
void CAI_InterestTarget::Add( const Vector &vecPosition, float flImportance, float flDuration, float flRamp )
{
int i;
for (i = 0; i < Count(); i++)
{
CAI_InterestTarget_t &target = Element( i );
if (target.m_vecPosition == vecPosition)
{
Remove( i );
break;
}
}
Add( CAI_InterestTarget_t::LOOKAT_POSITION, NULL, vecPosition, flImportance, flDuration, flRamp );
}
void CAI_InterestTarget::Add( CBaseEntity *pTarget, const Vector &vecPosition, float flImportance, float flDuration, float flRamp )
{
int i;
for (i = 0; i < Count(); i++)
{
CAI_InterestTarget_t &target = Element( i );
if (target.m_hTarget == pTarget)
{
if (target.m_flStartTime == gpGlobals->curtime)
{
flImportance = MAX( flImportance, target.m_flInterest );
}
Remove( i );
break;
}
}
Add( CAI_InterestTarget_t::LOOKAT_BOTH, pTarget, vecPosition, flImportance, flDuration, flRamp );
}
void CAI_InterestTarget::Add( CAI_InterestTarget_t::CAI_InterestTarget_e type, CBaseEntity *pTarget, const Vector &vecPosition, float flImportance, float flDuration, float flRamp )
{
int i = AddToTail();
CAI_InterestTarget_t &target = Element( i );
target.m_eType = type;
target.m_hTarget = pTarget;
target.m_vecPosition = vecPosition;
target.m_flInterest = flImportance;
target.m_flStartTime = gpGlobals->curtime;
target.m_flEndTime = gpGlobals->curtime + flDuration;
target.m_flRamp = flRamp / flDuration;
}

View File

@@ -1,88 +1,88 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Hooks and classes for the support of humanoid NPCs with
// groovy facial animation capabilities, aka, "Actors"
//
//=============================================================================//
#ifndef AI_INTEREST_TARGET_H
#define AI_INTEREST_TARGET_H
#if defined( _WIN32 )
#pragma once
#endif
//-----------------------------------------------------------------------------
// CAI_BaseActor
//
// Purpose: The base class for all facially expressive NPCS.
//
//-----------------------------------------------------------------------------
class CAI_InterestTarget_t
{
public:
enum CAI_InterestTarget_e
{
LOOKAT_ENTITY = 0,
LOOKAT_POSITION,
LOOKAT_BOTH
};
public:
bool IsThis( CBaseEntity *pThis );
const Vector &GetPosition( void );
bool IsActive( void );
float Interest( void );
public:
CAI_InterestTarget_e m_eType; // ????
EHANDLE m_hTarget;
Vector m_vecPosition;
float m_flStartTime;
float m_flEndTime;
float m_flRamp;
float m_flInterest;
DECLARE_SIMPLE_DATADESC();
};
class CAI_InterestTarget : public CUtlVector<CAI_InterestTarget_t>
{
public:
void Add( CBaseEntity *pTarget, float flImportance, float flDuration, float flRamp );
void Add( const Vector &vecPosition, float flImportance, float flDuration, float flRamp );
void Add( CBaseEntity *pTarget, const Vector &vecPosition, float flImportance, float flDuration, float flRamp );
int Find( CBaseEntity *pTarget )
{
int i;
for ( i = 0; i < Count(); i++)
{
if (pTarget == (*this)[i].m_hTarget)
return i;
}
return InvalidIndex();
}
void Cleanup( void )
{
int i;
for (i = Count() - 1; i >= 0; i--)
{
if (!Element(i).IsActive())
{
Remove( i );
}
}
};
private:
void Add( CAI_InterestTarget_t::CAI_InterestTarget_e type, CBaseEntity *pTarget, const Vector &vecPosition, float flImportance, float flDuration, float flRamp );
};
//-----------------------------------------------------------------------------
#endif // AI_INTEREST_TARGET_H
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Hooks and classes for the support of humanoid NPCs with
// groovy facial animation capabilities, aka, "Actors"
//
//=============================================================================//
#ifndef AI_INTEREST_TARGET_H
#define AI_INTEREST_TARGET_H
#if defined( _WIN32 )
#pragma once
#endif
//-----------------------------------------------------------------------------
// CAI_BaseActor
//
// Purpose: The base class for all facially expressive NPCS.
//
//-----------------------------------------------------------------------------
class CAI_InterestTarget_t
{
public:
enum CAI_InterestTarget_e
{
LOOKAT_ENTITY = 0,
LOOKAT_POSITION,
LOOKAT_BOTH
};
public:
bool IsThis( CBaseEntity *pThis );
const Vector &GetPosition( void );
bool IsActive( void );
float Interest( void );
public:
CAI_InterestTarget_e m_eType; // ????
EHANDLE m_hTarget;
Vector m_vecPosition;
float m_flStartTime;
float m_flEndTime;
float m_flRamp;
float m_flInterest;
DECLARE_SIMPLE_DATADESC();
};
class CAI_InterestTarget : public CUtlVector<CAI_InterestTarget_t>
{
public:
void Add( CBaseEntity *pTarget, float flImportance, float flDuration, float flRamp );
void Add( const Vector &vecPosition, float flImportance, float flDuration, float flRamp );
void Add( CBaseEntity *pTarget, const Vector &vecPosition, float flImportance, float flDuration, float flRamp );
int Find( CBaseEntity *pTarget )
{
int i;
for ( i = 0; i < Count(); i++)
{
if (pTarget == (*this)[i].m_hTarget)
return i;
}
return InvalidIndex();
}
void Cleanup( void )
{
int i;
for (i = Count() - 1; i >= 0; i--)
{
if (!Element(i).IsActive())
{
Remove( i );
}
}
};
private:
void Add( CAI_InterestTarget_t::CAI_InterestTarget_e type, CBaseEntity *pTarget, const Vector &vecPosition, float flImportance, float flDuration, float flRamp );
};
//-----------------------------------------------------------------------------
#endif // AI_INTEREST_TARGET_H

File diff suppressed because it is too large Load Diff

View File

@@ -1,41 +1,41 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#ifndef AI_RESPONSESYSTEM_H
#define AI_RESPONSESYSTEM_H
#include "utlvector.h"
#ifdef _WIN32
#pragma once
#endif
#include "AI_Criteria.h"
abstract_class IResponseFilter
{
public:
virtual bool IsValidResponse( ResponseType_t type, const char *pszValue ) = 0;
};
abstract_class IResponseSystem
{
public:
virtual ~IResponseSystem() {}
virtual bool FindBestResponse( const AI_CriteriaSet& set, AI_Response& response, IResponseFilter *pFilter = NULL ) = 0;
virtual void GetAllResponses( CUtlVector<AI_Response *> *pResponses ) = 0;
virtual void PrecacheResponses( bool bEnable ) = 0;
};
IResponseSystem *PrecacheCustomResponseSystem( const char *scriptfile );
IResponseSystem *BuildCustomResponseSystemGivenCriteria( const char *pszBaseFile, const char *pszCustomName, AI_CriteriaSet &criteriaSet, float flCriteriaScore );
void DestroyCustomResponseSystems();
class ISaveRestoreBlockHandler *GetDefaultResponseSystemSaveRestoreBlockHandler();
class ISaveRestoreOps *GetResponseSystemSaveRestoreOps();
#endif // AI_RESPONSESYSTEM_H
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#ifndef AI_RESPONSESYSTEM_H
#define AI_RESPONSESYSTEM_H
#include "utlvector.h"
#ifdef _WIN32
#pragma once
#endif
#include "AI_Criteria.h"
abstract_class IResponseFilter
{
public:
virtual bool IsValidResponse( ResponseType_t type, const char *pszValue ) = 0;
};
abstract_class IResponseSystem
{
public:
virtual ~IResponseSystem() {}
virtual bool FindBestResponse( const AI_CriteriaSet& set, AI_Response& response, IResponseFilter *pFilter = NULL ) = 0;
virtual void GetAllResponses( CUtlVector<AI_Response *> *pResponses ) = 0;
virtual void PrecacheResponses( bool bEnable ) = 0;
};
IResponseSystem *PrecacheCustomResponseSystem( const char *scriptfile );
IResponseSystem *BuildCustomResponseSystemGivenCriteria( const char *pszBaseFile, const char *pszCustomName, AI_CriteriaSet &criteriaSet, float flCriteriaScore );
void DestroyCustomResponseSystems();
class ISaveRestoreBlockHandler *GetDefaultResponseSystemSaveRestoreBlockHandler();
class ISaveRestoreOps *GetResponseSystemSaveRestoreOps();
#endif // AI_RESPONSESYSTEM_H

File diff suppressed because it is too large Load Diff

View File

@@ -1,231 +1,231 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//
//=============================================================================//
// #include "BaseAnimating.h"
#ifndef BASE_ANIMATING_OVERLAY_H
#define BASE_ANIMATING_OVERLAY_H
#ifdef _WIN32
#pragma once
#endif
class CBaseAnimatingOverlay;
class CAnimationLayer
{
public:
DECLARE_CLASS_NOBASE( CAnimationLayer );
CAnimationLayer( void );
void Init( CBaseAnimatingOverlay *pOverlay );
// float SetBlending( int iBlender, float flValue, CBaseAnimating *pOwner );
void StudioFrameAdvance( float flInterval, CBaseAnimating *pOwner );
void DispatchAnimEvents( CBaseAnimating *eventHandler, CBaseAnimating *pOwner );
void SetOrder( int nOrder );
float GetFadeout( float flCurTime );
// For CNetworkVars.
void NetworkStateChanged();
void NetworkStateChanged( void *pVar );
public:
#define ANIM_LAYER_ACTIVE 0x0001
#define ANIM_LAYER_AUTOKILL 0x0002
#define ANIM_LAYER_KILLME 0x0004
#define ANIM_LAYER_DONTRESTORE 0x0008
#define ANIM_LAYER_CHECKACCESS 0x0010
#define ANIM_LAYER_DYING 0x0020
int m_fFlags;
bool m_bSequenceFinished;
bool m_bLooping;
CNetworkVar( int, m_nSequence );
CNetworkVar( float, m_flCycle );
CNetworkVar( float, m_flPrevCycle );
CNetworkVar( float, m_flWeight );
float m_flPlaybackRate;
float m_flBlendIn; // start and end blend frac (0.0 for now blend)
float m_flBlendOut;
float m_flKillRate;
float m_flKillDelay;
float m_flLayerAnimtime;
float m_flLayerFadeOuttime;
// For checking for duplicates
Activity m_nActivity;
// order of layering on client
int m_nPriority;
CNetworkVar( int, m_nOrder );
bool IsActive( void ) { return ((m_fFlags & ANIM_LAYER_ACTIVE) != 0); }
bool IsAutokill( void ) { return ((m_fFlags & ANIM_LAYER_AUTOKILL) != 0); }
bool IsKillMe( void ) { return ((m_fFlags & ANIM_LAYER_KILLME) != 0); }
bool IsAutoramp( void ) { return (m_flBlendIn != 0.0 || m_flBlendOut != 0.0); }
void KillMe( void ) { m_fFlags |= ANIM_LAYER_KILLME; }
void Dying( void ) { m_fFlags |= ANIM_LAYER_DYING; }
bool IsDying( void ) { return ((m_fFlags & ANIM_LAYER_DYING) != 0); }
void Dead( void ) { m_fFlags &= ~ANIM_LAYER_DYING; }
bool IsAbandoned( void );
void MarkActive( void );
float m_flLastEventCheck;
float m_flLastAccess;
// Network state changes get forwarded here.
CBaseAnimatingOverlay *m_pOwnerEntity;
DECLARE_SIMPLE_DATADESC();
};
inline float CAnimationLayer::GetFadeout( float flCurTime )
{
float s;
if (m_flLayerFadeOuttime <= 0.0f)
{
s = 0;
}
else
{
// blend in over 0.2 seconds
s = 1.0 - (flCurTime - m_flLayerAnimtime) / m_flLayerFadeOuttime;
if (s > 0 && s <= 1.0)
{
// do a nice spline curve
s = 3 * s * s - 2 * s * s * s;
}
else if ( s > 1.0f )
{
// Shouldn't happen, but maybe curtime is behind animtime?
s = 1.0f;
}
}
return s;
}
class CBaseAnimatingOverlay : public CBaseAnimating
{
DECLARE_CLASS( CBaseAnimatingOverlay, CBaseAnimating );
public:
enum
{
MAX_OVERLAYS = 15,
};
private:
CUtlVector< CAnimationLayer > m_AnimOverlay;
//int m_nActiveLayers;
//int m_nActiveBaseLayers;
public:
virtual void OnRestore();
virtual void StudioFrameAdvance();
virtual void DispatchAnimEvents ( CBaseAnimating *eventHandler );
virtual void GetSkeleton( CStudioHdr *pStudioHdr, Vector pos[], Quaternion q[], int boneMask );
int AddGestureSequence( int sequence, bool autokill = true );
int AddGestureSequence( int sequence, float flDuration, bool autokill = true );
int AddGesture( Activity activity, bool autokill = true );
int AddGesture( Activity activity, float flDuration, bool autokill = true );
bool IsPlayingGesture( Activity activity );
void RestartGesture( Activity activity, bool addifmissing = true, bool autokill = true );
void RemoveGesture( Activity activity );
void RemoveAllGestures( void );
int AddLayeredSequence( int sequence, int iPriority );
void SetLayerPriority( int iLayer, int iPriority );
bool IsValidLayer( int iLayer );
void SetLayerDuration( int iLayer, float flDuration );
float GetLayerDuration( int iLayer );
void SetLayerCycle( int iLayer, float flCycle );
void SetLayerCycle( int iLayer, float flCycle, float flPrevCycle );
float GetLayerCycle( int iLayer );
void SetLayerPlaybackRate( int iLayer, float flPlaybackRate );
void SetLayerWeight( int iLayer, float flWeight );
float GetLayerWeight( int iLayer );
void SetLayerBlendIn( int iLayer, float flBlendIn );
void SetLayerBlendOut( int iLayer, float flBlendOut );
void SetLayerAutokill( int iLayer, bool bAutokill );
void SetLayerLooping( int iLayer, bool bLooping );
void SetLayerNoRestore( int iLayer, bool bNoRestore );
Activity GetLayerActivity( int iLayer );
int GetLayerSequence( int iLayer );
int FindGestureLayer( Activity activity );
void RemoveLayer( int iLayer, float flKillRate = 0.2, float flKillDelay = 0.0 );
void FastRemoveLayer( int iLayer );
CAnimationLayer *GetAnimOverlay( int iIndex );
int GetNumAnimOverlays() const;
void SetNumAnimOverlays( int num );
void VerifyOrder( void );
bool HasActiveLayer( void );
private:
int AllocateLayer( int iPriority = 0 ); // lower priorities are processed first
DECLARE_SERVERCLASS();
DECLARE_DATADESC();
DECLARE_PREDICTABLE();
};
EXTERN_SEND_TABLE(DT_BaseAnimatingOverlay);
inline int CBaseAnimatingOverlay::GetNumAnimOverlays() const
{
return m_AnimOverlay.Count();
}
// ------------------------------------------------------------------------------------------ //
// CAnimationLayer inlines.
// ------------------------------------------------------------------------------------------ //
inline void CAnimationLayer::SetOrder( int nOrder )
{
m_nOrder = nOrder;
}
inline void CAnimationLayer::NetworkStateChanged()
{
if ( m_pOwnerEntity )
m_pOwnerEntity->NetworkStateChanged();
}
inline void CAnimationLayer::NetworkStateChanged( void *pVar )
{
if ( m_pOwnerEntity )
m_pOwnerEntity->NetworkStateChanged();
}
#endif // BASE_ANIMATING_OVERLAY_H
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//
//=============================================================================//
// #include "BaseAnimating.h"
#ifndef BASE_ANIMATING_OVERLAY_H
#define BASE_ANIMATING_OVERLAY_H
#ifdef _WIN32
#pragma once
#endif
class CBaseAnimatingOverlay;
class CAnimationLayer
{
public:
DECLARE_CLASS_NOBASE( CAnimationLayer );
CAnimationLayer( void );
void Init( CBaseAnimatingOverlay *pOverlay );
// float SetBlending( int iBlender, float flValue, CBaseAnimating *pOwner );
void StudioFrameAdvance( float flInterval, CBaseAnimating *pOwner );
void DispatchAnimEvents( CBaseAnimating *eventHandler, CBaseAnimating *pOwner );
void SetOrder( int nOrder );
float GetFadeout( float flCurTime );
// For CNetworkVars.
void NetworkStateChanged();
void NetworkStateChanged( void *pVar );
public:
#define ANIM_LAYER_ACTIVE 0x0001
#define ANIM_LAYER_AUTOKILL 0x0002
#define ANIM_LAYER_KILLME 0x0004
#define ANIM_LAYER_DONTRESTORE 0x0008
#define ANIM_LAYER_CHECKACCESS 0x0010
#define ANIM_LAYER_DYING 0x0020
int m_fFlags;
bool m_bSequenceFinished;
bool m_bLooping;
CNetworkVar( int, m_nSequence );
CNetworkVar( float, m_flCycle );
CNetworkVar( float, m_flPrevCycle );
CNetworkVar( float, m_flWeight );
float m_flPlaybackRate;
float m_flBlendIn; // start and end blend frac (0.0 for now blend)
float m_flBlendOut;
float m_flKillRate;
float m_flKillDelay;
float m_flLayerAnimtime;
float m_flLayerFadeOuttime;
// For checking for duplicates
Activity m_nActivity;
// order of layering on client
int m_nPriority;
CNetworkVar( int, m_nOrder );
bool IsActive( void ) { return ((m_fFlags & ANIM_LAYER_ACTIVE) != 0); }
bool IsAutokill( void ) { return ((m_fFlags & ANIM_LAYER_AUTOKILL) != 0); }
bool IsKillMe( void ) { return ((m_fFlags & ANIM_LAYER_KILLME) != 0); }
bool IsAutoramp( void ) { return (m_flBlendIn != 0.0 || m_flBlendOut != 0.0); }
void KillMe( void ) { m_fFlags |= ANIM_LAYER_KILLME; }
void Dying( void ) { m_fFlags |= ANIM_LAYER_DYING; }
bool IsDying( void ) { return ((m_fFlags & ANIM_LAYER_DYING) != 0); }
void Dead( void ) { m_fFlags &= ~ANIM_LAYER_DYING; }
bool IsAbandoned( void );
void MarkActive( void );
float m_flLastEventCheck;
float m_flLastAccess;
// Network state changes get forwarded here.
CBaseAnimatingOverlay *m_pOwnerEntity;
DECLARE_SIMPLE_DATADESC();
};
inline float CAnimationLayer::GetFadeout( float flCurTime )
{
float s;
if (m_flLayerFadeOuttime <= 0.0f)
{
s = 0;
}
else
{
// blend in over 0.2 seconds
s = 1.0 - (flCurTime - m_flLayerAnimtime) / m_flLayerFadeOuttime;
if (s > 0 && s <= 1.0)
{
// do a nice spline curve
s = 3 * s * s - 2 * s * s * s;
}
else if ( s > 1.0f )
{
// Shouldn't happen, but maybe curtime is behind animtime?
s = 1.0f;
}
}
return s;
}
class CBaseAnimatingOverlay : public CBaseAnimating
{
DECLARE_CLASS( CBaseAnimatingOverlay, CBaseAnimating );
public:
enum
{
MAX_OVERLAYS = 15,
};
private:
CUtlVector< CAnimationLayer > m_AnimOverlay;
//int m_nActiveLayers;
//int m_nActiveBaseLayers;
public:
virtual void OnRestore();
virtual void StudioFrameAdvance();
virtual void DispatchAnimEvents ( CBaseAnimating *eventHandler );
virtual void GetSkeleton( CStudioHdr *pStudioHdr, Vector pos[], Quaternion q[], int boneMask );
int AddGestureSequence( int sequence, bool autokill = true );
int AddGestureSequence( int sequence, float flDuration, bool autokill = true );
int AddGesture( Activity activity, bool autokill = true );
int AddGesture( Activity activity, float flDuration, bool autokill = true );
bool IsPlayingGesture( Activity activity );
void RestartGesture( Activity activity, bool addifmissing = true, bool autokill = true );
void RemoveGesture( Activity activity );
void RemoveAllGestures( void );
int AddLayeredSequence( int sequence, int iPriority );
void SetLayerPriority( int iLayer, int iPriority );
bool IsValidLayer( int iLayer );
void SetLayerDuration( int iLayer, float flDuration );
float GetLayerDuration( int iLayer );
void SetLayerCycle( int iLayer, float flCycle );
void SetLayerCycle( int iLayer, float flCycle, float flPrevCycle );
float GetLayerCycle( int iLayer );
void SetLayerPlaybackRate( int iLayer, float flPlaybackRate );
void SetLayerWeight( int iLayer, float flWeight );
float GetLayerWeight( int iLayer );
void SetLayerBlendIn( int iLayer, float flBlendIn );
void SetLayerBlendOut( int iLayer, float flBlendOut );
void SetLayerAutokill( int iLayer, bool bAutokill );
void SetLayerLooping( int iLayer, bool bLooping );
void SetLayerNoRestore( int iLayer, bool bNoRestore );
Activity GetLayerActivity( int iLayer );
int GetLayerSequence( int iLayer );
int FindGestureLayer( Activity activity );
void RemoveLayer( int iLayer, float flKillRate = 0.2, float flKillDelay = 0.0 );
void FastRemoveLayer( int iLayer );
CAnimationLayer *GetAnimOverlay( int iIndex );
int GetNumAnimOverlays() const;
void SetNumAnimOverlays( int num );
void VerifyOrder( void );
bool HasActiveLayer( void );
private:
int AllocateLayer( int iPriority = 0 ); // lower priorities are processed first
DECLARE_SERVERCLASS();
DECLARE_DATADESC();
DECLARE_PREDICTABLE();
};
EXTERN_SEND_TABLE(DT_BaseAnimatingOverlay);
inline int CBaseAnimatingOverlay::GetNumAnimOverlays() const
{
return m_AnimOverlay.Count();
}
// ------------------------------------------------------------------------------------------ //
// CAnimationLayer inlines.
// ------------------------------------------------------------------------------------------ //
inline void CAnimationLayer::SetOrder( int nOrder )
{
m_nOrder = nOrder;
}
inline void CAnimationLayer::NetworkStateChanged()
{
if ( m_pOwnerEntity )
m_pOwnerEntity->NetworkStateChanged();
}
inline void CAnimationLayer::NetworkStateChanged( void *pVar )
{
if ( m_pOwnerEntity )
m_pOwnerEntity->NetworkStateChanged();
}
#endif // BASE_ANIMATING_OVERLAY_H

View File

@@ -1,275 +1,275 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: A base class for model-based doors. The exact movement required to
// open or close the door is not dictated by this class, only that
// the door has open, closed, opening, and closing states.
//
// Doors must satisfy these requirements:
//
// - Derived classes must support being opened by NPCs.
// - Never autoclose in the face of a player.
// - Never close into an NPC.
//
//=============================================================================//
#ifndef BASEPROPDOOR_H
#define BASEPROPDOOR_H
#ifdef _WIN32
#pragma once
#endif
#include "props.h"
#include "locksounds.h"
#include "entityoutput.h"
extern ConVar g_debug_doors;
struct opendata_t
{
Vector vecStandPos; // Where the NPC should stand.
Vector vecFaceDir; // What direction the NPC should face.
Activity eActivity; // What activity the NPC should play.
};
abstract_class CBasePropDoor : public CDynamicProp
{
public:
DECLARE_CLASS( CBasePropDoor, CDynamicProp );
DECLARE_SERVERCLASS();
CBasePropDoor( void );
void Spawn();
void Precache();
void Activate();
int ObjectCaps();
void HandleAnimEvent( animevent_t *pEvent );
// Base class services.
// Do not make the functions in this block virtual!!
// {
inline bool IsDoorOpen();
inline bool IsDoorAjar();
inline bool IsDoorOpening();
inline bool IsDoorClosed();
inline bool IsDoorClosing();
inline bool IsDoorLocked();
inline bool IsDoorBlocked() const;
inline bool IsNPCOpening(CAI_BaseNPC *pNPC);
inline bool IsPlayerOpening();
inline bool IsOpener(CBaseEntity *pEnt);
bool NPCOpenDoor(CAI_BaseNPC *pNPC);
bool TestCollision( const Ray_t &ray, unsigned int mask, trace_t& trace );
// }
// Implement these in your leaf class.
// {
virtual bool DoorCanClose( bool bAutoClose ) { return true; }
virtual bool DoorCanOpen( void ) { return true; }
virtual void GetNPCOpenData(CAI_BaseNPC *pNPC, opendata_t &opendata) = 0;
virtual float GetOpenInterval(void) = 0;
// }
protected:
enum DoorState_t
{
DOOR_STATE_CLOSED = 0,
DOOR_STATE_OPENING,
DOOR_STATE_OPEN,
DOOR_STATE_CLOSING,
DOOR_STATE_AJAR,
};
// dvs: FIXME: make these private
void DoorClose();
CBasePropDoor *GetMaster( void ) { return m_hMaster; }
bool HasSlaves( void ) { return ( m_hDoorList.Count() > 0 ); }
inline void SetDoorState( DoorState_t eDoorState );
float m_flAutoReturnDelay; // How many seconds to wait before automatically closing, -1 never closes automatically.
CUtlVector< CHandle< CBasePropDoor > > m_hDoorList; // List of doors linked to us
inline CBaseEntity *GetActivator();
private:
// Implement these in your leaf class.
// {
// Called when the door becomes fully open.
virtual void OnDoorOpened() {}
// Called when the door becomes fully closed.
virtual void OnDoorClosed() {}
// Called to tell the door to start opening.
virtual void BeginOpening(CBaseEntity *pOpenAwayFrom) = 0;
// Called to tell the door to start closing.
virtual void BeginClosing( void ) = 0;
// Called when blocked to tell the door to stop moving.
virtual void DoorStop( void ) = 0;
// Called when blocked to tell the door to continue moving.
virtual void DoorResume( void ) = 0;
// Called to send the door instantly to its spawn positions.
virtual void DoorTeleportToSpawnPosition() = 0;
// }
private:
// Main entry points for the door base behaviors.
// Do not make the functions in this block virtual!!
// {
bool DoorActivate();
void DoorOpen( CBaseEntity *pOpenAwayFrom );
void OpenIfUnlocked(CBaseEntity *pActivator, CBaseEntity *pOpenAwayFrom);
void DoorOpenMoveDone();
void DoorCloseMoveDone();
void DoorAutoCloseThink();
void Lock();
void Unlock();
void Use(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value);
void OnUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
inline bool WillAutoReturn() { return m_flAutoReturnDelay != -1; }
void StartBlocked(CBaseEntity *pOther);
void OnStartBlocked( CBaseEntity *pOther );
void MasterStartBlocked( CBaseEntity *pOther );
void Blocked(CBaseEntity *pOther);
void EndBlocked(void);
void OnEndBlocked( void );
void UpdateAreaPortals(bool bOpen);
// Input handlers
void InputClose(inputdata_t &inputdata);
void InputLock(inputdata_t &inputdata);
void InputOpen(inputdata_t &inputdata);
void InputOpenAwayFrom(inputdata_t &inputdata);
void InputToggle(inputdata_t &inputdata);
void InputUnlock(inputdata_t &inputdata);
void SetDoorBlocker( CBaseEntity *pBlocker );
void SetMaster( CBasePropDoor *pMaster ) { m_hMaster = pMaster; }
void CalcDoorSounds();
// }
int m_nHardwareType;
DoorState_t m_eDoorState; // Holds whether the door is open, closed, opening, or closing.
locksound_t m_ls; // The sounds the door plays when being locked, unlocked, etc.
EHANDLE m_hActivator;
bool m_bLocked; // True if the door is locked.
EHANDLE m_hBlocker; // Entity blocking the door currently
bool m_bFirstBlocked; // Marker for being the first door (in a group) to be blocked (needed for motion control)
bool m_bForceClosed; // True if this door must close no matter what.
string_t m_SoundMoving;
string_t m_SoundOpen;
string_t m_SoundClose;
// dvs: FIXME: can we remove m_flSpeed from CBaseEntity?
//float m_flSpeed; // Rotation speed when opening or closing in degrees per second.
DECLARE_DATADESC();
string_t m_SlaveName;
CHandle< CBasePropDoor > m_hMaster;
static void RegisterPrivateActivities();
// Outputs
COutputEvent m_OnBlockedClosing; // Triggered when the door becomes blocked while closing.
COutputEvent m_OnBlockedOpening; // Triggered when the door becomes blocked while opening.
COutputEvent m_OnUnblockedClosing; // Triggered when the door becomes unblocked while closing.
COutputEvent m_OnUnblockedOpening; // Triggered when the door becomes unblocked while opening.
COutputEvent m_OnFullyClosed; // Triggered when the door reaches the fully closed position.
COutputEvent m_OnFullyOpen; // Triggered when the door reaches the fully open position.
COutputEvent m_OnClose; // Triggered when the door is told to close.
COutputEvent m_OnOpen; // Triggered when the door is told to open.
COutputEvent m_OnLockedUse; // Triggered when the user tries to open a locked door.
};
void CBasePropDoor::SetDoorState( DoorState_t eDoorState )
{
m_eDoorState = eDoorState;
}
bool CBasePropDoor::IsDoorOpen()
{
return m_eDoorState == DOOR_STATE_OPEN;
}
bool CBasePropDoor::IsDoorAjar()
{
return ( m_eDoorState == DOOR_STATE_AJAR );
}
bool CBasePropDoor::IsDoorOpening()
{
return m_eDoorState == DOOR_STATE_OPENING;
}
bool CBasePropDoor::IsDoorClosed()
{
return m_eDoorState == DOOR_STATE_CLOSED;
}
bool CBasePropDoor::IsDoorClosing()
{
return m_eDoorState == DOOR_STATE_CLOSING;
}
bool CBasePropDoor::IsDoorLocked()
{
return m_bLocked;
}
CBaseEntity *CBasePropDoor::GetActivator()
{
return m_hActivator;
}
bool CBasePropDoor::IsDoorBlocked() const
{
return ( m_hBlocker != NULL );
}
bool CBasePropDoor::IsNPCOpening( CAI_BaseNPC *pNPC )
{
return ( pNPC == ( CAI_BaseNPC * )GetActivator() );
}
inline bool CBasePropDoor::IsPlayerOpening()
{
return ( GetActivator() && GetActivator()->IsPlayer() );
}
inline bool CBasePropDoor::IsOpener(CBaseEntity *pEnt)
{
return ( GetActivator() == pEnt );
}
#endif // BASEPROPDOOR_H
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: A base class for model-based doors. The exact movement required to
// open or close the door is not dictated by this class, only that
// the door has open, closed, opening, and closing states.
//
// Doors must satisfy these requirements:
//
// - Derived classes must support being opened by NPCs.
// - Never autoclose in the face of a player.
// - Never close into an NPC.
//
//=============================================================================//
#ifndef BASEPROPDOOR_H
#define BASEPROPDOOR_H
#ifdef _WIN32
#pragma once
#endif
#include "props.h"
#include "locksounds.h"
#include "entityoutput.h"
extern ConVar g_debug_doors;
struct opendata_t
{
Vector vecStandPos; // Where the NPC should stand.
Vector vecFaceDir; // What direction the NPC should face.
Activity eActivity; // What activity the NPC should play.
};
abstract_class CBasePropDoor : public CDynamicProp
{
public:
DECLARE_CLASS( CBasePropDoor, CDynamicProp );
DECLARE_SERVERCLASS();
CBasePropDoor( void );
void Spawn();
void Precache();
void Activate();
int ObjectCaps();
void HandleAnimEvent( animevent_t *pEvent );
// Base class services.
// Do not make the functions in this block virtual!!
// {
inline bool IsDoorOpen();
inline bool IsDoorAjar();
inline bool IsDoorOpening();
inline bool IsDoorClosed();
inline bool IsDoorClosing();
inline bool IsDoorLocked();
inline bool IsDoorBlocked() const;
inline bool IsNPCOpening(CAI_BaseNPC *pNPC);
inline bool IsPlayerOpening();
inline bool IsOpener(CBaseEntity *pEnt);
bool NPCOpenDoor(CAI_BaseNPC *pNPC);
bool TestCollision( const Ray_t &ray, unsigned int mask, trace_t& trace );
// }
// Implement these in your leaf class.
// {
virtual bool DoorCanClose( bool bAutoClose ) { return true; }
virtual bool DoorCanOpen( void ) { return true; }
virtual void GetNPCOpenData(CAI_BaseNPC *pNPC, opendata_t &opendata) = 0;
virtual float GetOpenInterval(void) = 0;
// }
protected:
enum DoorState_t
{
DOOR_STATE_CLOSED = 0,
DOOR_STATE_OPENING,
DOOR_STATE_OPEN,
DOOR_STATE_CLOSING,
DOOR_STATE_AJAR,
};
// dvs: FIXME: make these private
void DoorClose();
CBasePropDoor *GetMaster( void ) { return m_hMaster; }
bool HasSlaves( void ) { return ( m_hDoorList.Count() > 0 ); }
inline void SetDoorState( DoorState_t eDoorState );
float m_flAutoReturnDelay; // How many seconds to wait before automatically closing, -1 never closes automatically.
CUtlVector< CHandle< CBasePropDoor > > m_hDoorList; // List of doors linked to us
inline CBaseEntity *GetActivator();
private:
// Implement these in your leaf class.
// {
// Called when the door becomes fully open.
virtual void OnDoorOpened() {}
// Called when the door becomes fully closed.
virtual void OnDoorClosed() {}
// Called to tell the door to start opening.
virtual void BeginOpening(CBaseEntity *pOpenAwayFrom) = 0;
// Called to tell the door to start closing.
virtual void BeginClosing( void ) = 0;
// Called when blocked to tell the door to stop moving.
virtual void DoorStop( void ) = 0;
// Called when blocked to tell the door to continue moving.
virtual void DoorResume( void ) = 0;
// Called to send the door instantly to its spawn positions.
virtual void DoorTeleportToSpawnPosition() = 0;
// }
private:
// Main entry points for the door base behaviors.
// Do not make the functions in this block virtual!!
// {
bool DoorActivate();
void DoorOpen( CBaseEntity *pOpenAwayFrom );
void OpenIfUnlocked(CBaseEntity *pActivator, CBaseEntity *pOpenAwayFrom);
void DoorOpenMoveDone();
void DoorCloseMoveDone();
void DoorAutoCloseThink();
void Lock();
void Unlock();
void Use(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value);
void OnUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
inline bool WillAutoReturn() { return m_flAutoReturnDelay != -1; }
void StartBlocked(CBaseEntity *pOther);
void OnStartBlocked( CBaseEntity *pOther );
void MasterStartBlocked( CBaseEntity *pOther );
void Blocked(CBaseEntity *pOther);
void EndBlocked(void);
void OnEndBlocked( void );
void UpdateAreaPortals(bool bOpen);
// Input handlers
void InputClose(inputdata_t &inputdata);
void InputLock(inputdata_t &inputdata);
void InputOpen(inputdata_t &inputdata);
void InputOpenAwayFrom(inputdata_t &inputdata);
void InputToggle(inputdata_t &inputdata);
void InputUnlock(inputdata_t &inputdata);
void SetDoorBlocker( CBaseEntity *pBlocker );
void SetMaster( CBasePropDoor *pMaster ) { m_hMaster = pMaster; }
void CalcDoorSounds();
// }
int m_nHardwareType;
DoorState_t m_eDoorState; // Holds whether the door is open, closed, opening, or closing.
locksound_t m_ls; // The sounds the door plays when being locked, unlocked, etc.
EHANDLE m_hActivator;
bool m_bLocked; // True if the door is locked.
EHANDLE m_hBlocker; // Entity blocking the door currently
bool m_bFirstBlocked; // Marker for being the first door (in a group) to be blocked (needed for motion control)
bool m_bForceClosed; // True if this door must close no matter what.
string_t m_SoundMoving;
string_t m_SoundOpen;
string_t m_SoundClose;
// dvs: FIXME: can we remove m_flSpeed from CBaseEntity?
//float m_flSpeed; // Rotation speed when opening or closing in degrees per second.
DECLARE_DATADESC();
string_t m_SlaveName;
CHandle< CBasePropDoor > m_hMaster;
static void RegisterPrivateActivities();
// Outputs
COutputEvent m_OnBlockedClosing; // Triggered when the door becomes blocked while closing.
COutputEvent m_OnBlockedOpening; // Triggered when the door becomes blocked while opening.
COutputEvent m_OnUnblockedClosing; // Triggered when the door becomes unblocked while closing.
COutputEvent m_OnUnblockedOpening; // Triggered when the door becomes unblocked while opening.
COutputEvent m_OnFullyClosed; // Triggered when the door reaches the fully closed position.
COutputEvent m_OnFullyOpen; // Triggered when the door reaches the fully open position.
COutputEvent m_OnClose; // Triggered when the door is told to close.
COutputEvent m_OnOpen; // Triggered when the door is told to open.
COutputEvent m_OnLockedUse; // Triggered when the user tries to open a locked door.
};
void CBasePropDoor::SetDoorState( DoorState_t eDoorState )
{
m_eDoorState = eDoorState;
}
bool CBasePropDoor::IsDoorOpen()
{
return m_eDoorState == DOOR_STATE_OPEN;
}
bool CBasePropDoor::IsDoorAjar()
{
return ( m_eDoorState == DOOR_STATE_AJAR );
}
bool CBasePropDoor::IsDoorOpening()
{
return m_eDoorState == DOOR_STATE_OPENING;
}
bool CBasePropDoor::IsDoorClosed()
{
return m_eDoorState == DOOR_STATE_CLOSED;
}
bool CBasePropDoor::IsDoorClosing()
{
return m_eDoorState == DOOR_STATE_CLOSING;
}
bool CBasePropDoor::IsDoorLocked()
{
return m_bLocked;
}
CBaseEntity *CBasePropDoor::GetActivator()
{
return m_hActivator;
}
bool CBasePropDoor::IsDoorBlocked() const
{
return ( m_hBlocker != NULL );
}
bool CBasePropDoor::IsNPCOpening( CAI_BaseNPC *pNPC )
{
return ( pNPC == ( CAI_BaseNPC * )GetActivator() );
}
inline bool CBasePropDoor::IsPlayerOpening()
{
return ( GetActivator() && GetActivator()->IsPlayer() );
}
inline bool CBasePropDoor::IsOpener(CBaseEntity *pEnt)
{
return ( GetActivator() == pEnt );
}
#endif // BASEPROPDOOR_H

View File

@@ -1,222 +1,222 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "game.h"
#include "CRagdollMagnet.h"
#include "cplane.h"
ConVar ai_debug_ragdoll_magnets( "ai_debug_ragdoll_magnets", "0");
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
LINK_ENTITY_TO_CLASS( phys_ragdollmagnet, CRagdollMagnet );
BEGIN_DATADESC( CRagdollMagnet )
DEFINE_KEYFIELD( m_radius, FIELD_FLOAT, "radius" ),
DEFINE_KEYFIELD( m_force, FIELD_FLOAT, "force" ),
DEFINE_KEYFIELD( m_axis, FIELD_VECTOR, "axis" ),
DEFINE_KEYFIELD( m_bDisabled, FIELD_BOOLEAN, "StartDisabled" ),
DEFINE_INPUTFUNC( FIELD_VOID, "Enable", InputEnable ),
DEFINE_INPUTFUNC( FIELD_VOID, "Disable", InputDisable ),
END_DATADESC()
//-----------------------------------------------------------------------------
// Purpose:
// Input : &inputdata -
//-----------------------------------------------------------------------------
void CRagdollMagnet::InputEnable( inputdata_t &inputdata )
{
Enable( true );
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : &inputdata -
//-----------------------------------------------------------------------------
void CRagdollMagnet::InputDisable( inputdata_t &inputdata )
{
Enable( false );
}
//-----------------------------------------------------------------------------
// Purpose: Find the ragdoll magnet entity that should pull this entity's ragdoll
// Input : *pNPC - the npc that's dying
// Output : CRagdollMagnet - the magnet that's best to use.
//
// NOTES:
//
// The nearest ragdoll magnet pulls me in IF:
// - Present
// - I'm within the magnet's RADIUS
// - LATER: There is clear line of sight from my center to the magnet
// - LATER: I'm not flagged to ignore ragdoll magnets
// - LATER: The magnet is not turned OFF
//-----------------------------------------------------------------------------
CRagdollMagnet *CRagdollMagnet::FindBestMagnet( CBaseEntity *pNPC )
{
CRagdollMagnet *pMagnet = NULL;
CRagdollMagnet *pBestMagnet;
float flClosestDist;
// Assume we won't find one.
pBestMagnet = NULL;
flClosestDist = FLT_MAX;
do
{
pMagnet = (CRagdollMagnet *)gEntList.FindEntityByClassname( pMagnet, "phys_ragdollmagnet" );
if( pMagnet && pMagnet->IsEnabled() )
{
if( pMagnet->m_target != NULL_STRING )
{
// if this magnet has a target, only affect that target!
if( pNPC->GetEntityName() == pMagnet->m_target )
{
return pMagnet;
}
else
{
continue;
}
}
float flDist;
flDist = pMagnet->DistToPoint( pNPC->WorldSpaceCenter() );
if( flDist < flClosestDist && flDist <= pMagnet->GetRadius() )
{
// This is the closest magnet that can pull this npc.
flClosestDist = flDist;
pBestMagnet = pMagnet;
}
}
} while( pMagnet );
return pBestMagnet;
}
//-----------------------------------------------------------------------------
// Purpose: Get the force that we should add to this NPC's ragdoll.
// Input : *pNPC -
// Output : Vector
//
// NOTE: This function assumes pNPC is within this magnet's radius.
//-----------------------------------------------------------------------------
Vector CRagdollMagnet::GetForceVector( CBaseEntity *pNPC )
{
Vector vecForceToApply;
if( IsBarMagnet() )
{
CPlane axis;
Vector vecForceDir;
Vector vecClosest;
CalcClosestPointOnLineSegment( pNPC->WorldSpaceCenter(), GetAbsOrigin(), m_axis, vecClosest, NULL );
vecForceDir = (vecClosest - pNPC->WorldSpaceCenter() );
VectorNormalize( vecForceDir );
vecForceToApply = vecForceDir * m_force;
}
else
{
Vector vecForce;
vecForce = GetAbsOrigin() - pNPC->WorldSpaceCenter();
VectorNormalize( vecForce );
vecForceToApply = vecForce * m_force;
}
if( ai_debug_ragdoll_magnets.GetBool() )
{
IPhysicsObject *pPhysObject;
pPhysObject = pNPC->VPhysicsGetObject();
if( pPhysObject )
{
Msg("Ragdoll magnet adding %f inches/sec to %s\n", m_force/pPhysObject->GetMass(), pNPC->GetClassname() );
}
}
return vecForceToApply;
}
//-----------------------------------------------------------------------------
// Purpose: How far away is this point? This is different for point and bar magnets
// Input : &vecPoint - the point
// Output : float - the dist
//-----------------------------------------------------------------------------
float CRagdollMagnet::DistToPoint( const Vector &vecPoint )
{
if( IsBarMagnet() )
{
// I'm a bar magnet, so the point's distance is really the plane constant.
// A bar magnet is a cylinder who's length is AbsOrigin() to m_axis, and whose
// diameter is m_radius.
// first we build two planes. The TOP and BOTTOM planes.
// the idea is that vecPoint must be on the right side of both
// planes to be affected by this particular magnet.
// TOP and BOTTOM planes can be visualized as the 'caps' of the cylinder
// that describes the bar magnet, and they point towards each other.
// We're making sure vecPoint is between the caps.
Vector vecAxis;
vecAxis = GetAxisVector();
VectorNormalize( vecAxis );
CPlane top, bottom;
bottom.InitializePlane( -vecAxis, m_axis );
top.InitializePlane( vecAxis, GetAbsOrigin() );
if( top.PointInFront( vecPoint ) && bottom.PointInFront( vecPoint ) )
{
// This point is between the two caps, so calculate the distance
// of vecPoint from the axis of the bar magnet
CPlane axis;
Vector vecUp;
Vector vecRight;
// Horizontal and Vertical distances.
float hDist, vDist;
// Need to get a vector that's right-hand to m_axis
VectorVectors( vecAxis, vecRight, vecUp );
//CrossProduct( vecAxis, vecUp, vecRight );
//VectorNormalize( vecRight );
//VectorNormalize( vecUp );
// Set up the plane to measure horizontal dist.
axis.InitializePlane( vecRight, GetAbsOrigin() );
hDist = fabs( axis.PointDist( vecPoint ) );
axis.InitializePlane( vecUp, GetAbsOrigin() );
vDist = fabs( axis.PointDist( vecPoint ) );
return MAX( hDist, vDist );
}
else
{
return FLT_MAX;
}
}
else
{
// I'm a point magnet. Just return dist
return ( GetAbsOrigin() - vecPoint ).Length();
}
}
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "game.h"
#include "CRagdollMagnet.h"
#include "cplane.h"
ConVar ai_debug_ragdoll_magnets( "ai_debug_ragdoll_magnets", "0");
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
LINK_ENTITY_TO_CLASS( phys_ragdollmagnet, CRagdollMagnet );
BEGIN_DATADESC( CRagdollMagnet )
DEFINE_KEYFIELD( m_radius, FIELD_FLOAT, "radius" ),
DEFINE_KEYFIELD( m_force, FIELD_FLOAT, "force" ),
DEFINE_KEYFIELD( m_axis, FIELD_VECTOR, "axis" ),
DEFINE_KEYFIELD( m_bDisabled, FIELD_BOOLEAN, "StartDisabled" ),
DEFINE_INPUTFUNC( FIELD_VOID, "Enable", InputEnable ),
DEFINE_INPUTFUNC( FIELD_VOID, "Disable", InputDisable ),
END_DATADESC()
//-----------------------------------------------------------------------------
// Purpose:
// Input : &inputdata -
//-----------------------------------------------------------------------------
void CRagdollMagnet::InputEnable( inputdata_t &inputdata )
{
Enable( true );
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : &inputdata -
//-----------------------------------------------------------------------------
void CRagdollMagnet::InputDisable( inputdata_t &inputdata )
{
Enable( false );
}
//-----------------------------------------------------------------------------
// Purpose: Find the ragdoll magnet entity that should pull this entity's ragdoll
// Input : *pNPC - the npc that's dying
// Output : CRagdollMagnet - the magnet that's best to use.
//
// NOTES:
//
// The nearest ragdoll magnet pulls me in IF:
// - Present
// - I'm within the magnet's RADIUS
// - LATER: There is clear line of sight from my center to the magnet
// - LATER: I'm not flagged to ignore ragdoll magnets
// - LATER: The magnet is not turned OFF
//-----------------------------------------------------------------------------
CRagdollMagnet *CRagdollMagnet::FindBestMagnet( CBaseEntity *pNPC )
{
CRagdollMagnet *pMagnet = NULL;
CRagdollMagnet *pBestMagnet;
float flClosestDist;
// Assume we won't find one.
pBestMagnet = NULL;
flClosestDist = FLT_MAX;
do
{
pMagnet = (CRagdollMagnet *)gEntList.FindEntityByClassname( pMagnet, "phys_ragdollmagnet" );
if( pMagnet && pMagnet->IsEnabled() )
{
if( pMagnet->m_target != NULL_STRING )
{
// if this magnet has a target, only affect that target!
if( pNPC->GetEntityName() == pMagnet->m_target )
{
return pMagnet;
}
else
{
continue;
}
}
float flDist;
flDist = pMagnet->DistToPoint( pNPC->WorldSpaceCenter() );
if( flDist < flClosestDist && flDist <= pMagnet->GetRadius() )
{
// This is the closest magnet that can pull this npc.
flClosestDist = flDist;
pBestMagnet = pMagnet;
}
}
} while( pMagnet );
return pBestMagnet;
}
//-----------------------------------------------------------------------------
// Purpose: Get the force that we should add to this NPC's ragdoll.
// Input : *pNPC -
// Output : Vector
//
// NOTE: This function assumes pNPC is within this magnet's radius.
//-----------------------------------------------------------------------------
Vector CRagdollMagnet::GetForceVector( CBaseEntity *pNPC )
{
Vector vecForceToApply;
if( IsBarMagnet() )
{
CPlane axis;
Vector vecForceDir;
Vector vecClosest;
CalcClosestPointOnLineSegment( pNPC->WorldSpaceCenter(), GetAbsOrigin(), m_axis, vecClosest, NULL );
vecForceDir = (vecClosest - pNPC->WorldSpaceCenter() );
VectorNormalize( vecForceDir );
vecForceToApply = vecForceDir * m_force;
}
else
{
Vector vecForce;
vecForce = GetAbsOrigin() - pNPC->WorldSpaceCenter();
VectorNormalize( vecForce );
vecForceToApply = vecForce * m_force;
}
if( ai_debug_ragdoll_magnets.GetBool() )
{
IPhysicsObject *pPhysObject;
pPhysObject = pNPC->VPhysicsGetObject();
if( pPhysObject )
{
Msg("Ragdoll magnet adding %f inches/sec to %s\n", m_force/pPhysObject->GetMass(), pNPC->GetClassname() );
}
}
return vecForceToApply;
}
//-----------------------------------------------------------------------------
// Purpose: How far away is this point? This is different for point and bar magnets
// Input : &vecPoint - the point
// Output : float - the dist
//-----------------------------------------------------------------------------
float CRagdollMagnet::DistToPoint( const Vector &vecPoint )
{
if( IsBarMagnet() )
{
// I'm a bar magnet, so the point's distance is really the plane constant.
// A bar magnet is a cylinder who's length is AbsOrigin() to m_axis, and whose
// diameter is m_radius.
// first we build two planes. The TOP and BOTTOM planes.
// the idea is that vecPoint must be on the right side of both
// planes to be affected by this particular magnet.
// TOP and BOTTOM planes can be visualized as the 'caps' of the cylinder
// that describes the bar magnet, and they point towards each other.
// We're making sure vecPoint is between the caps.
Vector vecAxis;
vecAxis = GetAxisVector();
VectorNormalize( vecAxis );
CPlane top, bottom;
bottom.InitializePlane( -vecAxis, m_axis );
top.InitializePlane( vecAxis, GetAbsOrigin() );
if( top.PointInFront( vecPoint ) && bottom.PointInFront( vecPoint ) )
{
// This point is between the two caps, so calculate the distance
// of vecPoint from the axis of the bar magnet
CPlane axis;
Vector vecUp;
Vector vecRight;
// Horizontal and Vertical distances.
float hDist, vDist;
// Need to get a vector that's right-hand to m_axis
VectorVectors( vecAxis, vecRight, vecUp );
//CrossProduct( vecAxis, vecUp, vecRight );
//VectorNormalize( vecRight );
//VectorNormalize( vecUp );
// Set up the plane to measure horizontal dist.
axis.InitializePlane( vecRight, GetAbsOrigin() );
hDist = fabs( axis.PointDist( vecPoint ) );
axis.InitializePlane( vecUp, GetAbsOrigin() );
vDist = fabs( axis.PointDist( vecPoint ) );
return MAX( hDist, vDist );
}
else
{
return FLT_MAX;
}
}
else
{
// I'm a point magnet. Just return dist
return ( GetAbsOrigin() - vecPoint ).Length();
}
}

View File

@@ -1,45 +1,45 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Used to influence the initial force for a dying NPC's ragdoll.
// Passive entity. Just represents position in the world, radius, force
//
// $NoKeywords: $
//=============================================================================//
#pragma once
#ifndef CRAGDOLLMAGNET_H
#define CRAGDOLLMAGNET_H
#define SF_RAGDOLLMAGNET_BAR 0x00000002 // this is a bar magnet.
class CRagdollMagnet : public CPointEntity
{
public:
DECLARE_CLASS( CRagdollMagnet, CPointEntity );
DECLARE_DATADESC();
Vector GetForceVector( CBaseEntity *pNPC );
float GetRadius( void ) { return m_radius; }
Vector GetAxisVector( void ) { return m_axis - GetAbsOrigin(); }
float DistToPoint( const Vector &vecPoint );
bool IsEnabled( void ) { return !m_bDisabled; }
int IsBarMagnet( void ) { return (m_spawnflags & SF_RAGDOLLMAGNET_BAR); }
static CRagdollMagnet *FindBestMagnet( CBaseEntity *pNPC );
void Enable( bool bEnable ) { m_bDisabled = !bEnable; }
// Inputs
void InputEnable( inputdata_t &inputdata );
void InputDisable( inputdata_t &inputdata );
private:
bool m_bDisabled;
float m_radius;
float m_force;
Vector m_axis;
};
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Used to influence the initial force for a dying NPC's ragdoll.
// Passive entity. Just represents position in the world, radius, force
//
// $NoKeywords: $
//=============================================================================//
#pragma once
#ifndef CRAGDOLLMAGNET_H
#define CRAGDOLLMAGNET_H
#define SF_RAGDOLLMAGNET_BAR 0x00000002 // this is a bar magnet.
class CRagdollMagnet : public CPointEntity
{
public:
DECLARE_CLASS( CRagdollMagnet, CPointEntity );
DECLARE_DATADESC();
Vector GetForceVector( CBaseEntity *pNPC );
float GetRadius( void ) { return m_radius; }
Vector GetAxisVector( void ) { return m_axis - GetAbsOrigin(); }
float DistToPoint( const Vector &vecPoint );
bool IsEnabled( void ) { return !m_bDisabled; }
int IsBarMagnet( void ) { return (m_spawnflags & SF_RAGDOLLMAGNET_BAR); }
static CRagdollMagnet *FindBestMagnet( CBaseEntity *pNPC );
void Enable( bool bEnable ) { m_bDisabled = !bEnable; }
// Inputs
void InputEnable( inputdata_t &inputdata );
void InputDisable( inputdata_t &inputdata );
private:
bool m_bDisabled;
float m_radius;
float m_force;
Vector m_axis;
};
#endif //CRAGDOLLMAGNET_H

File diff suppressed because it is too large Load Diff

View File

@@ -1,198 +1,198 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Utility code.
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "te.h"
#include "shake.h"
#include "decals.h"
#include "IEffects.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
extern short g_sModelIndexSmoke; // (in combatweapon.cpp) holds the index for the smoke cloud
extern short g_sModelIndexBloodDrop; // (in combatweapon.cpp) holds the sprite index for the initial blood
extern short g_sModelIndexBloodSpray; // (in combatweapon.cpp) holds the sprite index for splattered blood
//-----------------------------------------------------------------------------
// Client-server neutral effects interface
//-----------------------------------------------------------------------------
class CEffectsServer : public IEffects
{
public:
CEffectsServer();
virtual ~CEffectsServer();
// Members of the IEffect interface
virtual void Beam( const Vector &Start, const Vector &End, int nModelIndex,
int nHaloIndex, unsigned char frameStart, unsigned char frameRate,
float flLife, unsigned char width, unsigned char endWidth, unsigned char fadeLength,
unsigned char noise, unsigned char red, unsigned char green,
unsigned char blue, unsigned char brightness, unsigned char speed);
virtual void Smoke( const Vector &origin, int mModel, float flScale, float flFramerate );
virtual void Sparks( const Vector &position, int nMagnitude = 1, int nTrailLength = 1, const Vector *pvecDir = NULL );
virtual void Dust( const Vector &pos, const Vector &dir, float size, float speed );
virtual void MuzzleFlash( const Vector &origin, const QAngle &angles, float scale, int type );
virtual void MetalSparks( const Vector &position, const Vector &direction );
virtual void EnergySplash( const Vector &position, const Vector &direction, bool bExplosive = false );
virtual void Ricochet( const Vector &position, const Vector &direction );
// FIXME: Should these methods remain in this interface? Or go in some
// other client-server neutral interface?
virtual float Time();
virtual bool IsServer();
virtual void SuppressEffectsSounds( bool bSuppress ) { Assert(0); }
private:
//-----------------------------------------------------------------------------
// Purpose: Returning true means don't even call TE func
// Input : filter -
// *suppress_host -
// Output : static bool
//-----------------------------------------------------------------------------
bool SuppressTE( CRecipientFilter& filter )
{
if ( GetSuppressHost() )
{
if ( !filter.IgnorePredictionCull() )
{
filter.RemoveRecipient( (CBasePlayer *)GetSuppressHost() );
}
if ( !filter.GetRecipientCount() )
{
// Suppress it
return true;
}
}
// There's at least one recipient
return false;
}
};
//-----------------------------------------------------------------------------
// Client-server neutral effects interface accessor
//-----------------------------------------------------------------------------
static CEffectsServer s_EffectServer;
EXPOSE_SINGLE_INTERFACE_GLOBALVAR(CEffectsServer, IEffects, IEFFECTS_INTERFACE_VERSION, s_EffectServer);
IEffects *g_pEffects = &s_EffectServer;
//-----------------------------------------------------------------------------
// constructor, destructor
//-----------------------------------------------------------------------------
CEffectsServer::CEffectsServer()
{
}
CEffectsServer::~CEffectsServer()
{
}
//-----------------------------------------------------------------------------
// Generates a beam
//-----------------------------------------------------------------------------
void CEffectsServer::Beam( const Vector &vecStart, const Vector &vecEnd, int nModelIndex,
int nHaloIndex, unsigned char frameStart, unsigned char frameRate,
float flLife, unsigned char width, unsigned char endWidth, unsigned char fadeLength,
unsigned char noise, unsigned char red, unsigned char green,
unsigned char blue, unsigned char brightness, unsigned char speed)
{
CBroadcastRecipientFilter filter;
if ( !SuppressTE( filter ) )
{
te->BeamPoints( filter, 0.0,
&vecStart, &vecEnd, nModelIndex, nHaloIndex, frameStart, frameRate, flLife,
width, endWidth, fadeLength, noise, red, green, blue, brightness, speed );
}
}
//-----------------------------------------------------------------------------
// Generates various tempent effects
//-----------------------------------------------------------------------------
void CEffectsServer::Smoke( const Vector &origin, int mModel, float flScale, float flFramerate )
{
CPVSFilter filter( origin );
if ( !SuppressTE( filter ) )
{
te->Smoke( filter, 0.0, &origin, mModel, flScale * 0.1f, flFramerate );
}
}
void CEffectsServer::Sparks( const Vector &position, int nMagnitude, int nTrailLength, const Vector *pvecDir )
{
CPVSFilter filter( position );
if ( !SuppressTE( filter ) )
{
te->Sparks( filter, 0.0, &position, nMagnitude, nTrailLength, pvecDir );
}
}
void CEffectsServer::Dust( const Vector &pos, const Vector &dir, float size, float speed )
{
CPVSFilter filter( pos );
if ( !SuppressTE( filter ) )
{
te->Dust( filter, 0.0, pos, dir, size, speed );
}
}
void CEffectsServer::MuzzleFlash( const Vector &origin, const QAngle &angles, float scale, int type )
{
CPVSFilter filter( origin );
if ( !SuppressTE( filter ) )
{
te->MuzzleFlash( filter, 0.0f, origin, angles, scale, type );
}
}
void CEffectsServer::MetalSparks( const Vector &position, const Vector &direction )
{
CPVSFilter filter( position );
if ( !SuppressTE( filter ) )
{
te->MetalSparks( filter, 0.0, &position, &direction );
}
}
void CEffectsServer::EnergySplash( const Vector &position, const Vector &direction, bool bExplosive )
{
CPVSFilter filter( position );
if ( !SuppressTE( filter ) )
{
te->EnergySplash( filter, 0.0, &position, &direction, bExplosive );
}
}
void CEffectsServer::Ricochet( const Vector &position, const Vector &direction )
{
CPVSFilter filter( position );
if ( !SuppressTE( filter ) )
{
te->ArmorRicochet( filter, 0.0, &position, &direction );
}
}
//-----------------------------------------------------------------------------
// FIXME: Should these methods remain in this interface? Or go in some
// other client-server neutral interface?
//-----------------------------------------------------------------------------
float CEffectsServer::Time()
{
return gpGlobals->curtime;
}
bool CEffectsServer::IsServer()
{
return true;
}
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Utility code.
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "te.h"
#include "shake.h"
#include "decals.h"
#include "IEffects.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
extern short g_sModelIndexSmoke; // (in combatweapon.cpp) holds the index for the smoke cloud
extern short g_sModelIndexBloodDrop; // (in combatweapon.cpp) holds the sprite index for the initial blood
extern short g_sModelIndexBloodSpray; // (in combatweapon.cpp) holds the sprite index for splattered blood
//-----------------------------------------------------------------------------
// Client-server neutral effects interface
//-----------------------------------------------------------------------------
class CEffectsServer : public IEffects
{
public:
CEffectsServer();
virtual ~CEffectsServer();
// Members of the IEffect interface
virtual void Beam( const Vector &Start, const Vector &End, int nModelIndex,
int nHaloIndex, unsigned char frameStart, unsigned char frameRate,
float flLife, unsigned char width, unsigned char endWidth, unsigned char fadeLength,
unsigned char noise, unsigned char red, unsigned char green,
unsigned char blue, unsigned char brightness, unsigned char speed);
virtual void Smoke( const Vector &origin, int mModel, float flScale, float flFramerate );
virtual void Sparks( const Vector &position, int nMagnitude = 1, int nTrailLength = 1, const Vector *pvecDir = NULL );
virtual void Dust( const Vector &pos, const Vector &dir, float size, float speed );
virtual void MuzzleFlash( const Vector &origin, const QAngle &angles, float scale, int type );
virtual void MetalSparks( const Vector &position, const Vector &direction );
virtual void EnergySplash( const Vector &position, const Vector &direction, bool bExplosive = false );
virtual void Ricochet( const Vector &position, const Vector &direction );
// FIXME: Should these methods remain in this interface? Or go in some
// other client-server neutral interface?
virtual float Time();
virtual bool IsServer();
virtual void SuppressEffectsSounds( bool bSuppress ) { Assert(0); }
private:
//-----------------------------------------------------------------------------
// Purpose: Returning true means don't even call TE func
// Input : filter -
// *suppress_host -
// Output : static bool
//-----------------------------------------------------------------------------
bool SuppressTE( CRecipientFilter& filter )
{
if ( GetSuppressHost() )
{
if ( !filter.IgnorePredictionCull() )
{
filter.RemoveRecipient( (CBasePlayer *)GetSuppressHost() );
}
if ( !filter.GetRecipientCount() )
{
// Suppress it
return true;
}
}
// There's at least one recipient
return false;
}
};
//-----------------------------------------------------------------------------
// Client-server neutral effects interface accessor
//-----------------------------------------------------------------------------
static CEffectsServer s_EffectServer;
EXPOSE_SINGLE_INTERFACE_GLOBALVAR(CEffectsServer, IEffects, IEFFECTS_INTERFACE_VERSION, s_EffectServer);
IEffects *g_pEffects = &s_EffectServer;
//-----------------------------------------------------------------------------
// constructor, destructor
//-----------------------------------------------------------------------------
CEffectsServer::CEffectsServer()
{
}
CEffectsServer::~CEffectsServer()
{
}
//-----------------------------------------------------------------------------
// Generates a beam
//-----------------------------------------------------------------------------
void CEffectsServer::Beam( const Vector &vecStart, const Vector &vecEnd, int nModelIndex,
int nHaloIndex, unsigned char frameStart, unsigned char frameRate,
float flLife, unsigned char width, unsigned char endWidth, unsigned char fadeLength,
unsigned char noise, unsigned char red, unsigned char green,
unsigned char blue, unsigned char brightness, unsigned char speed)
{
CBroadcastRecipientFilter filter;
if ( !SuppressTE( filter ) )
{
te->BeamPoints( filter, 0.0,
&vecStart, &vecEnd, nModelIndex, nHaloIndex, frameStart, frameRate, flLife,
width, endWidth, fadeLength, noise, red, green, blue, brightness, speed );
}
}
//-----------------------------------------------------------------------------
// Generates various tempent effects
//-----------------------------------------------------------------------------
void CEffectsServer::Smoke( const Vector &origin, int mModel, float flScale, float flFramerate )
{
CPVSFilter filter( origin );
if ( !SuppressTE( filter ) )
{
te->Smoke( filter, 0.0, &origin, mModel, flScale * 0.1f, flFramerate );
}
}
void CEffectsServer::Sparks( const Vector &position, int nMagnitude, int nTrailLength, const Vector *pvecDir )
{
CPVSFilter filter( position );
if ( !SuppressTE( filter ) )
{
te->Sparks( filter, 0.0, &position, nMagnitude, nTrailLength, pvecDir );
}
}
void CEffectsServer::Dust( const Vector &pos, const Vector &dir, float size, float speed )
{
CPVSFilter filter( pos );
if ( !SuppressTE( filter ) )
{
te->Dust( filter, 0.0, pos, dir, size, speed );
}
}
void CEffectsServer::MuzzleFlash( const Vector &origin, const QAngle &angles, float scale, int type )
{
CPVSFilter filter( origin );
if ( !SuppressTE( filter ) )
{
te->MuzzleFlash( filter, 0.0f, origin, angles, scale, type );
}
}
void CEffectsServer::MetalSparks( const Vector &position, const Vector &direction )
{
CPVSFilter filter( position );
if ( !SuppressTE( filter ) )
{
te->MetalSparks( filter, 0.0, &position, &direction );
}
}
void CEffectsServer::EnergySplash( const Vector &position, const Vector &direction, bool bExplosive )
{
CPVSFilter filter( position );
if ( !SuppressTE( filter ) )
{
te->EnergySplash( filter, 0.0, &position, &direction, bExplosive );
}
}
void CEffectsServer::Ricochet( const Vector &position, const Vector &direction )
{
CPVSFilter filter( position );
if ( !SuppressTE( filter ) )
{
te->ArmorRicochet( filter, 0.0, &position, &direction );
}
}
//-----------------------------------------------------------------------------
// FIXME: Should these methods remain in this interface? Or go in some
// other client-server neutral interface?
//-----------------------------------------------------------------------------
float CEffectsServer::Time()
{
return gpGlobals->curtime;
}
bool CEffectsServer::IsServer()
{
return true;
}

View File

@@ -1,388 +1,388 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Dissolve entity to be attached to target entity. Serves two purposes:
//
// 1) An entity that can be placed by a level designer and triggered
// to ignite a target entity.
//
// 2) An entity that can be created at runtime to ignite a target entity.
//
//=============================================================================//
#include "cbase.h"
#include "EntityDissolve.h"
#include "baseanimating.h"
#include "physics_prop_ragdoll.h"
#include "ai_basenpc.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
static const char *s_pElectroThinkContext = "ElectroThinkContext";
//-----------------------------------------------------------------------------
// Lifetime
//-----------------------------------------------------------------------------
#define DISSOLVE_FADE_IN_START_TIME 0.0f
#define DISSOLVE_FADE_IN_END_TIME 1.0f
#define DISSOLVE_FADE_OUT_MODEL_START_TIME 1.9f
#define DISSOLVE_FADE_OUT_MODEL_END_TIME 2.0f
#define DISSOLVE_FADE_OUT_START_TIME 2.0f
#define DISSOLVE_FADE_OUT_END_TIME 2.0f
//-----------------------------------------------------------------------------
// Model
//-----------------------------------------------------------------------------
#define DISSOLVE_SPRITE_NAME "sprites/blueglow1.vmt"
//-----------------------------------------------------------------------------
// Save/load
//-----------------------------------------------------------------------------
BEGIN_DATADESC( CEntityDissolve )
DEFINE_FIELD( m_flStartTime, FIELD_TIME ),
DEFINE_FIELD( m_flFadeInStart, FIELD_FLOAT ),
DEFINE_FIELD( m_flFadeInLength, FIELD_FLOAT ),
DEFINE_FIELD( m_flFadeOutModelStart, FIELD_FLOAT ),
DEFINE_FIELD( m_flFadeOutModelLength, FIELD_FLOAT ),
DEFINE_FIELD( m_flFadeOutStart, FIELD_FLOAT ),
DEFINE_FIELD( m_flFadeOutLength, FIELD_FLOAT ),
DEFINE_KEYFIELD( m_nDissolveType, FIELD_INTEGER, "dissolvetype" ),
DEFINE_FIELD( m_vDissolverOrigin, FIELD_VECTOR ),
DEFINE_KEYFIELD( m_nMagnitude, FIELD_INTEGER, "magnitude" ),
DEFINE_FUNCTION( DissolveThink ),
DEFINE_FUNCTION( ElectrocuteThink ),
DEFINE_INPUTFUNC( FIELD_STRING, "Dissolve", InputDissolve ),
END_DATADESC()
//-----------------------------------------------------------------------------
// Networking
//-----------------------------------------------------------------------------
IMPLEMENT_SERVERCLASS_ST( CEntityDissolve, DT_EntityDissolve )
SendPropTime( SENDINFO( m_flStartTime ) ),
SendPropFloat( SENDINFO( m_flFadeInStart ), 0, SPROP_NOSCALE ),
SendPropFloat( SENDINFO( m_flFadeInLength ), 0, SPROP_NOSCALE ),
SendPropFloat( SENDINFO( m_flFadeOutModelStart ), 0, SPROP_NOSCALE ),
SendPropFloat( SENDINFO( m_flFadeOutModelLength ), 0, SPROP_NOSCALE ),
SendPropFloat( SENDINFO( m_flFadeOutStart ), 0, SPROP_NOSCALE ),
SendPropFloat( SENDINFO( m_flFadeOutLength ), 0, SPROP_NOSCALE ),
SendPropInt( SENDINFO( m_nDissolveType ), ENTITY_DISSOLVE_BITS, SPROP_UNSIGNED ),
SendPropVector (SENDINFO(m_vDissolverOrigin), 0, SPROP_NOSCALE ),
SendPropInt( SENDINFO( m_nMagnitude ), 8, SPROP_UNSIGNED ),
END_SEND_TABLE()
LINK_ENTITY_TO_CLASS( env_entity_dissolver, CEntityDissolve );
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
CEntityDissolve::CEntityDissolve( void )
{
m_flStartTime = 0.0f;
m_nMagnitude = 250;
}
CEntityDissolve::~CEntityDissolve( void )
{
}
//-----------------------------------------------------------------------------
// Precache
//-----------------------------------------------------------------------------
void CEntityDissolve::Precache()
{
if ( NULL_STRING == GetModelName() )
{
PrecacheModel( DISSOLVE_SPRITE_NAME );
}
else
{
PrecacheModel( STRING( GetModelName() ) );
}
}
//-----------------------------------------------------------------------------
// Spawn
//-----------------------------------------------------------------------------
void CEntityDissolve::Spawn()
{
BaseClass::Spawn();
Precache();
UTIL_SetModel( this, STRING( GetModelName() ) );
if ( (m_nDissolveType == ENTITY_DISSOLVE_ELECTRICAL) || (m_nDissolveType == ENTITY_DISSOLVE_ELECTRICAL_LIGHT) )
{
if ( dynamic_cast< CRagdollProp* >( GetMoveParent() ) )
{
SetContextThink( &CEntityDissolve::ElectrocuteThink, gpGlobals->curtime + 0.01f, s_pElectroThinkContext );
}
}
// Setup our times
m_flFadeInStart = DISSOLVE_FADE_IN_START_TIME;
m_flFadeInLength = DISSOLVE_FADE_IN_END_TIME - DISSOLVE_FADE_IN_START_TIME;
m_flFadeOutModelStart = DISSOLVE_FADE_OUT_MODEL_START_TIME;
m_flFadeOutModelLength = DISSOLVE_FADE_OUT_MODEL_END_TIME - DISSOLVE_FADE_OUT_MODEL_START_TIME;
m_flFadeOutStart = DISSOLVE_FADE_OUT_START_TIME;
m_flFadeOutLength = DISSOLVE_FADE_OUT_END_TIME - DISSOLVE_FADE_OUT_START_TIME;
if ( m_nDissolveType == ENTITY_DISSOLVE_CORE )
{
m_flFadeInStart = 0.0f;
m_flFadeOutStart = CORE_DISSOLVE_FADE_START;
m_flFadeOutModelStart = CORE_DISSOLVE_MODEL_FADE_START;
m_flFadeOutModelLength = CORE_DISSOLVE_MODEL_FADE_LENGTH;
m_flFadeInLength = CORE_DISSOLVE_FADEIN_LENGTH;
}
m_nRenderMode = kRenderTransColor;
SetRenderColor( 255, 255, 255, 255 );
m_nRenderFX = kRenderFxNone;
SetThink( &CEntityDissolve::DissolveThink );
if ( gpGlobals->curtime > m_flStartTime )
{
// Necessary for server-side ragdolls
DissolveThink();
}
else
{
SetNextThink( gpGlobals->curtime + 0.01f );
}
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : inputdata -
//-----------------------------------------------------------------------------
void CEntityDissolve::InputDissolve( inputdata_t &inputdata )
{
string_t strTarget = inputdata.value.StringID();
if (strTarget == NULL_STRING)
{
strTarget = m_target;
}
CBaseEntity *pTarget = NULL;
while ((pTarget = gEntList.FindEntityGeneric(pTarget, STRING(strTarget), this, inputdata.pActivator)) != NULL)
{
CBaseAnimating *pBaseAnim = pTarget->GetBaseAnimating();
if (pBaseAnim)
{
pBaseAnim->Dissolve( NULL, gpGlobals->curtime, false, m_nDissolveType, GetAbsOrigin(), m_nMagnitude );
}
}
}
//-----------------------------------------------------------------------------
// Purpose: Creates a flame and attaches it to a target entity.
// Input : pTarget -
//-----------------------------------------------------------------------------
CEntityDissolve *CEntityDissolve::Create( CBaseEntity *pTarget, const char *pMaterialName,
float flStartTime, int nDissolveType, bool *pRagdollCreated )
{
if ( pRagdollCreated )
{
*pRagdollCreated = false;
}
if ( !pMaterialName )
{
pMaterialName = DISSOLVE_SPRITE_NAME;
}
if ( pTarget->IsPlayer() )
{
// Simply immediately kill the player.
CBasePlayer *pPlayer = assert_cast< CBasePlayer* >( pTarget );
pPlayer->SetArmorValue( 0 );
CTakeDamageInfo info( pPlayer, pPlayer, pPlayer->GetHealth(), DMG_GENERIC | DMG_REMOVENORAGDOLL | DMG_PREVENT_PHYSICS_FORCE );
pPlayer->TakeDamage( info );
return NULL;
}
CEntityDissolve *pDissolve = (CEntityDissolve *) CreateEntityByName( "env_entity_dissolver" );
if ( pDissolve == NULL )
return NULL;
pDissolve->m_nDissolveType = nDissolveType;
if ( (nDissolveType == ENTITY_DISSOLVE_ELECTRICAL) || (nDissolveType == ENTITY_DISSOLVE_ELECTRICAL_LIGHT) )
{
if ( pTarget->IsNPC() && pTarget->MyNPCPointer()->CanBecomeRagdoll() )
{
CTakeDamageInfo info;
CBaseEntity *pRagdoll = CreateServerRagdoll( pTarget->MyNPCPointer(), 0, info, COLLISION_GROUP_DEBRIS, true );
pRagdoll->SetCollisionBounds( pTarget->CollisionProp()->OBBMins(), pTarget->CollisionProp()->OBBMaxs() );
// Necessary to cause it to do the appropriate death cleanup
if ( pTarget->m_lifeState == LIFE_ALIVE )
{
CBasePlayer *pPlayer = UTIL_PlayerByIndex( 1 );
CTakeDamageInfo ragdollInfo( pPlayer, pPlayer, 10000.0, DMG_SHOCK | DMG_REMOVENORAGDOLL | DMG_PREVENT_PHYSICS_FORCE );
pTarget->TakeDamage( ragdollInfo );
}
if ( pRagdollCreated )
{
*pRagdollCreated = true;
}
UTIL_Remove( pTarget );
pTarget = pRagdoll;
}
}
pDissolve->SetModelName( AllocPooledString(pMaterialName) );
pDissolve->AttachToEntity( pTarget );
pDissolve->SetStartTime( flStartTime );
pDissolve->Spawn();
// Send to the client even though we don't have a model
pDissolve->AddEFlags( EFL_FORCE_CHECK_TRANSMIT );
// Play any appropriate noises when we start to dissolve
if ( (nDissolveType == ENTITY_DISSOLVE_ELECTRICAL) || (nDissolveType == ENTITY_DISSOLVE_ELECTRICAL_LIGHT) )
{
pTarget->DispatchResponse( "TLK_ELECTROCUTESCREAM" );
}
else
{
pTarget->DispatchResponse( "TLK_DISSOLVESCREAM" );
}
return pDissolve;
}
//-----------------------------------------------------------------------------
// What type of dissolve?
//-----------------------------------------------------------------------------
CEntityDissolve *CEntityDissolve::Create( CBaseEntity *pTarget, CBaseEntity *pSource )
{
// Look for other boogies on the ragdoll + kill them
for ( CBaseEntity *pChild = pSource->FirstMoveChild(); pChild; pChild = pChild->NextMovePeer() )
{
CEntityDissolve *pDissolve = dynamic_cast<CEntityDissolve*>(pChild);
if ( !pDissolve )
continue;
return Create( pTarget, STRING( pDissolve->GetModelName() ), pDissolve->m_flStartTime, pDissolve->m_nDissolveType );
}
return NULL;
}
//-----------------------------------------------------------------------------
// Purpose: Attaches the flame to an entity and moves with it
// Input : pTarget - target entity to attach to
//-----------------------------------------------------------------------------
void CEntityDissolve::AttachToEntity( CBaseEntity *pTarget )
{
// So our dissolver follows the entity around on the server.
SetParent( pTarget );
SetLocalOrigin( vec3_origin );
SetLocalAngles( vec3_angle );
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : lifetime -
//-----------------------------------------------------------------------------
void CEntityDissolve::SetStartTime( float flStartTime )
{
m_flStartTime = flStartTime;
}
//-----------------------------------------------------------------------------
// Purpose: Burn targets around us
//-----------------------------------------------------------------------------
void CEntityDissolve::DissolveThink( void )
{
CBaseAnimating *pTarget = ( GetMoveParent() ) ? GetMoveParent()->GetBaseAnimating() : NULL;
if ( GetModelName() == NULL_STRING && pTarget == NULL )
return;
if ( pTarget == NULL )
{
UTIL_Remove( this );
return;
}
// Turn them into debris
pTarget->SetCollisionGroup( COLLISION_GROUP_DISSOLVING );
if ( pTarget && pTarget->GetFlags() & FL_TRANSRAGDOLL )
{
SetRenderColorA( 0 );
}
float dt = gpGlobals->curtime - m_flStartTime;
if ( dt < m_flFadeInStart )
{
SetNextThink( m_flStartTime + m_flFadeInStart );
return;
}
// If we're done fading, then kill our target entity and us
if ( dt >= m_flFadeOutStart + m_flFadeOutLength )
{
// Necessary to cause it to do the appropriate death cleanup
// Yeah, the player may have nothing to do with it, but
// passing NULL to TakeDamage causes bad things to happen
CBasePlayer *pPlayer = UTIL_PlayerByIndex( 1 );
int iNoPhysicsDamage = g_pGameRules->Damage_GetNoPhysicsForce();
CTakeDamageInfo info( pPlayer, pPlayer, 10000.0, DMG_GENERIC | DMG_REMOVENORAGDOLL | iNoPhysicsDamage );
pTarget->TakeDamage( info );
if ( pTarget != pPlayer )
{
UTIL_Remove( pTarget );
}
UTIL_Remove( this );
return;
}
SetNextThink( gpGlobals->curtime + TICK_INTERVAL );
}
//-----------------------------------------------------------------------------
// Purpose: Burn targets around us
//-----------------------------------------------------------------------------
void CEntityDissolve::ElectrocuteThink( void )
{
CRagdollProp *pRagdoll = dynamic_cast< CRagdollProp* >( GetMoveParent() );
if ( !pRagdoll )
return;
ragdoll_t *pRagdollPhys = pRagdoll->GetRagdoll( );
for ( int j = 0; j < pRagdollPhys->listCount; ++j )
{
Vector vecForce;
vecForce = RandomVector( -2400.0f, 2400.0f );
pRagdollPhys->list[j].pObject->ApplyForceCenter( vecForce );
}
SetContextThink( &CEntityDissolve::ElectrocuteThink, gpGlobals->curtime + random->RandomFloat( 0.1, 0.2f ),
s_pElectroThinkContext );
}
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Dissolve entity to be attached to target entity. Serves two purposes:
//
// 1) An entity that can be placed by a level designer and triggered
// to ignite a target entity.
//
// 2) An entity that can be created at runtime to ignite a target entity.
//
//=============================================================================//
#include "cbase.h"
#include "EntityDissolve.h"
#include "baseanimating.h"
#include "physics_prop_ragdoll.h"
#include "ai_basenpc.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
static const char *s_pElectroThinkContext = "ElectroThinkContext";
//-----------------------------------------------------------------------------
// Lifetime
//-----------------------------------------------------------------------------
#define DISSOLVE_FADE_IN_START_TIME 0.0f
#define DISSOLVE_FADE_IN_END_TIME 1.0f
#define DISSOLVE_FADE_OUT_MODEL_START_TIME 1.9f
#define DISSOLVE_FADE_OUT_MODEL_END_TIME 2.0f
#define DISSOLVE_FADE_OUT_START_TIME 2.0f
#define DISSOLVE_FADE_OUT_END_TIME 2.0f
//-----------------------------------------------------------------------------
// Model
//-----------------------------------------------------------------------------
#define DISSOLVE_SPRITE_NAME "sprites/blueglow1.vmt"
//-----------------------------------------------------------------------------
// Save/load
//-----------------------------------------------------------------------------
BEGIN_DATADESC( CEntityDissolve )
DEFINE_FIELD( m_flStartTime, FIELD_TIME ),
DEFINE_FIELD( m_flFadeInStart, FIELD_FLOAT ),
DEFINE_FIELD( m_flFadeInLength, FIELD_FLOAT ),
DEFINE_FIELD( m_flFadeOutModelStart, FIELD_FLOAT ),
DEFINE_FIELD( m_flFadeOutModelLength, FIELD_FLOAT ),
DEFINE_FIELD( m_flFadeOutStart, FIELD_FLOAT ),
DEFINE_FIELD( m_flFadeOutLength, FIELD_FLOAT ),
DEFINE_KEYFIELD( m_nDissolveType, FIELD_INTEGER, "dissolvetype" ),
DEFINE_FIELD( m_vDissolverOrigin, FIELD_VECTOR ),
DEFINE_KEYFIELD( m_nMagnitude, FIELD_INTEGER, "magnitude" ),
DEFINE_FUNCTION( DissolveThink ),
DEFINE_FUNCTION( ElectrocuteThink ),
DEFINE_INPUTFUNC( FIELD_STRING, "Dissolve", InputDissolve ),
END_DATADESC()
//-----------------------------------------------------------------------------
// Networking
//-----------------------------------------------------------------------------
IMPLEMENT_SERVERCLASS_ST( CEntityDissolve, DT_EntityDissolve )
SendPropTime( SENDINFO( m_flStartTime ) ),
SendPropFloat( SENDINFO( m_flFadeInStart ), 0, SPROP_NOSCALE ),
SendPropFloat( SENDINFO( m_flFadeInLength ), 0, SPROP_NOSCALE ),
SendPropFloat( SENDINFO( m_flFadeOutModelStart ), 0, SPROP_NOSCALE ),
SendPropFloat( SENDINFO( m_flFadeOutModelLength ), 0, SPROP_NOSCALE ),
SendPropFloat( SENDINFO( m_flFadeOutStart ), 0, SPROP_NOSCALE ),
SendPropFloat( SENDINFO( m_flFadeOutLength ), 0, SPROP_NOSCALE ),
SendPropInt( SENDINFO( m_nDissolveType ), ENTITY_DISSOLVE_BITS, SPROP_UNSIGNED ),
SendPropVector (SENDINFO(m_vDissolverOrigin), 0, SPROP_NOSCALE ),
SendPropInt( SENDINFO( m_nMagnitude ), 8, SPROP_UNSIGNED ),
END_SEND_TABLE()
LINK_ENTITY_TO_CLASS( env_entity_dissolver, CEntityDissolve );
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
CEntityDissolve::CEntityDissolve( void )
{
m_flStartTime = 0.0f;
m_nMagnitude = 250;
}
CEntityDissolve::~CEntityDissolve( void )
{
}
//-----------------------------------------------------------------------------
// Precache
//-----------------------------------------------------------------------------
void CEntityDissolve::Precache()
{
if ( NULL_STRING == GetModelName() )
{
PrecacheModel( DISSOLVE_SPRITE_NAME );
}
else
{
PrecacheModel( STRING( GetModelName() ) );
}
}
//-----------------------------------------------------------------------------
// Spawn
//-----------------------------------------------------------------------------
void CEntityDissolve::Spawn()
{
BaseClass::Spawn();
Precache();
UTIL_SetModel( this, STRING( GetModelName() ) );
if ( (m_nDissolveType == ENTITY_DISSOLVE_ELECTRICAL) || (m_nDissolveType == ENTITY_DISSOLVE_ELECTRICAL_LIGHT) )
{
if ( dynamic_cast< CRagdollProp* >( GetMoveParent() ) )
{
SetContextThink( &CEntityDissolve::ElectrocuteThink, gpGlobals->curtime + 0.01f, s_pElectroThinkContext );
}
}
// Setup our times
m_flFadeInStart = DISSOLVE_FADE_IN_START_TIME;
m_flFadeInLength = DISSOLVE_FADE_IN_END_TIME - DISSOLVE_FADE_IN_START_TIME;
m_flFadeOutModelStart = DISSOLVE_FADE_OUT_MODEL_START_TIME;
m_flFadeOutModelLength = DISSOLVE_FADE_OUT_MODEL_END_TIME - DISSOLVE_FADE_OUT_MODEL_START_TIME;
m_flFadeOutStart = DISSOLVE_FADE_OUT_START_TIME;
m_flFadeOutLength = DISSOLVE_FADE_OUT_END_TIME - DISSOLVE_FADE_OUT_START_TIME;
if ( m_nDissolveType == ENTITY_DISSOLVE_CORE )
{
m_flFadeInStart = 0.0f;
m_flFadeOutStart = CORE_DISSOLVE_FADE_START;
m_flFadeOutModelStart = CORE_DISSOLVE_MODEL_FADE_START;
m_flFadeOutModelLength = CORE_DISSOLVE_MODEL_FADE_LENGTH;
m_flFadeInLength = CORE_DISSOLVE_FADEIN_LENGTH;
}
m_nRenderMode = kRenderTransColor;
SetRenderColor( 255, 255, 255, 255 );
m_nRenderFX = kRenderFxNone;
SetThink( &CEntityDissolve::DissolveThink );
if ( gpGlobals->curtime > m_flStartTime )
{
// Necessary for server-side ragdolls
DissolveThink();
}
else
{
SetNextThink( gpGlobals->curtime + 0.01f );
}
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : inputdata -
//-----------------------------------------------------------------------------
void CEntityDissolve::InputDissolve( inputdata_t &inputdata )
{
string_t strTarget = inputdata.value.StringID();
if (strTarget == NULL_STRING)
{
strTarget = m_target;
}
CBaseEntity *pTarget = NULL;
while ((pTarget = gEntList.FindEntityGeneric(pTarget, STRING(strTarget), this, inputdata.pActivator)) != NULL)
{
CBaseAnimating *pBaseAnim = pTarget->GetBaseAnimating();
if (pBaseAnim)
{
pBaseAnim->Dissolve( NULL, gpGlobals->curtime, false, m_nDissolveType, GetAbsOrigin(), m_nMagnitude );
}
}
}
//-----------------------------------------------------------------------------
// Purpose: Creates a flame and attaches it to a target entity.
// Input : pTarget -
//-----------------------------------------------------------------------------
CEntityDissolve *CEntityDissolve::Create( CBaseEntity *pTarget, const char *pMaterialName,
float flStartTime, int nDissolveType, bool *pRagdollCreated )
{
if ( pRagdollCreated )
{
*pRagdollCreated = false;
}
if ( !pMaterialName )
{
pMaterialName = DISSOLVE_SPRITE_NAME;
}
if ( pTarget->IsPlayer() )
{
// Simply immediately kill the player.
CBasePlayer *pPlayer = assert_cast< CBasePlayer* >( pTarget );
pPlayer->SetArmorValue( 0 );
CTakeDamageInfo info( pPlayer, pPlayer, pPlayer->GetHealth(), DMG_GENERIC | DMG_REMOVENORAGDOLL | DMG_PREVENT_PHYSICS_FORCE );
pPlayer->TakeDamage( info );
return NULL;
}
CEntityDissolve *pDissolve = (CEntityDissolve *) CreateEntityByName( "env_entity_dissolver" );
if ( pDissolve == NULL )
return NULL;
pDissolve->m_nDissolveType = nDissolveType;
if ( (nDissolveType == ENTITY_DISSOLVE_ELECTRICAL) || (nDissolveType == ENTITY_DISSOLVE_ELECTRICAL_LIGHT) )
{
if ( pTarget->IsNPC() && pTarget->MyNPCPointer()->CanBecomeRagdoll() )
{
CTakeDamageInfo info;
CBaseEntity *pRagdoll = CreateServerRagdoll( pTarget->MyNPCPointer(), 0, info, COLLISION_GROUP_DEBRIS, true );
pRagdoll->SetCollisionBounds( pTarget->CollisionProp()->OBBMins(), pTarget->CollisionProp()->OBBMaxs() );
// Necessary to cause it to do the appropriate death cleanup
if ( pTarget->m_lifeState == LIFE_ALIVE )
{
CBasePlayer *pPlayer = UTIL_PlayerByIndex( 1 );
CTakeDamageInfo ragdollInfo( pPlayer, pPlayer, 10000.0, DMG_SHOCK | DMG_REMOVENORAGDOLL | DMG_PREVENT_PHYSICS_FORCE );
pTarget->TakeDamage( ragdollInfo );
}
if ( pRagdollCreated )
{
*pRagdollCreated = true;
}
UTIL_Remove( pTarget );
pTarget = pRagdoll;
}
}
pDissolve->SetModelName( AllocPooledString(pMaterialName) );
pDissolve->AttachToEntity( pTarget );
pDissolve->SetStartTime( flStartTime );
pDissolve->Spawn();
// Send to the client even though we don't have a model
pDissolve->AddEFlags( EFL_FORCE_CHECK_TRANSMIT );
// Play any appropriate noises when we start to dissolve
if ( (nDissolveType == ENTITY_DISSOLVE_ELECTRICAL) || (nDissolveType == ENTITY_DISSOLVE_ELECTRICAL_LIGHT) )
{
pTarget->DispatchResponse( "TLK_ELECTROCUTESCREAM" );
}
else
{
pTarget->DispatchResponse( "TLK_DISSOLVESCREAM" );
}
return pDissolve;
}
//-----------------------------------------------------------------------------
// What type of dissolve?
//-----------------------------------------------------------------------------
CEntityDissolve *CEntityDissolve::Create( CBaseEntity *pTarget, CBaseEntity *pSource )
{
// Look for other boogies on the ragdoll + kill them
for ( CBaseEntity *pChild = pSource->FirstMoveChild(); pChild; pChild = pChild->NextMovePeer() )
{
CEntityDissolve *pDissolve = dynamic_cast<CEntityDissolve*>(pChild);
if ( !pDissolve )
continue;
return Create( pTarget, STRING( pDissolve->GetModelName() ), pDissolve->m_flStartTime, pDissolve->m_nDissolveType );
}
return NULL;
}
//-----------------------------------------------------------------------------
// Purpose: Attaches the flame to an entity and moves with it
// Input : pTarget - target entity to attach to
//-----------------------------------------------------------------------------
void CEntityDissolve::AttachToEntity( CBaseEntity *pTarget )
{
// So our dissolver follows the entity around on the server.
SetParent( pTarget );
SetLocalOrigin( vec3_origin );
SetLocalAngles( vec3_angle );
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : lifetime -
//-----------------------------------------------------------------------------
void CEntityDissolve::SetStartTime( float flStartTime )
{
m_flStartTime = flStartTime;
}
//-----------------------------------------------------------------------------
// Purpose: Burn targets around us
//-----------------------------------------------------------------------------
void CEntityDissolve::DissolveThink( void )
{
CBaseAnimating *pTarget = ( GetMoveParent() ) ? GetMoveParent()->GetBaseAnimating() : NULL;
if ( GetModelName() == NULL_STRING && pTarget == NULL )
return;
if ( pTarget == NULL )
{
UTIL_Remove( this );
return;
}
// Turn them into debris
pTarget->SetCollisionGroup( COLLISION_GROUP_DISSOLVING );
if ( pTarget && pTarget->GetFlags() & FL_TRANSRAGDOLL )
{
SetRenderColorA( 0 );
}
float dt = gpGlobals->curtime - m_flStartTime;
if ( dt < m_flFadeInStart )
{
SetNextThink( m_flStartTime + m_flFadeInStart );
return;
}
// If we're done fading, then kill our target entity and us
if ( dt >= m_flFadeOutStart + m_flFadeOutLength )
{
// Necessary to cause it to do the appropriate death cleanup
// Yeah, the player may have nothing to do with it, but
// passing NULL to TakeDamage causes bad things to happen
CBasePlayer *pPlayer = UTIL_PlayerByIndex( 1 );
int iNoPhysicsDamage = g_pGameRules->Damage_GetNoPhysicsForce();
CTakeDamageInfo info( pPlayer, pPlayer, 10000.0, DMG_GENERIC | DMG_REMOVENORAGDOLL | iNoPhysicsDamage );
pTarget->TakeDamage( info );
if ( pTarget != pPlayer )
{
UTIL_Remove( pTarget );
}
UTIL_Remove( this );
return;
}
SetNextThink( gpGlobals->curtime + TICK_INTERVAL );
}
//-----------------------------------------------------------------------------
// Purpose: Burn targets around us
//-----------------------------------------------------------------------------
void CEntityDissolve::ElectrocuteThink( void )
{
CRagdollProp *pRagdoll = dynamic_cast< CRagdollProp* >( GetMoveParent() );
if ( !pRagdoll )
return;
ragdoll_t *pRagdollPhys = pRagdoll->GetRagdoll( );
for ( int j = 0; j < pRagdollPhys->listCount; ++j )
{
Vector vecForce;
vecForce = RandomVector( -2400.0f, 2400.0f );
pRagdollPhys->list[j].pObject->ApplyForceCenter( vecForce );
}
SetContextThink( &CEntityDissolve::ElectrocuteThink, gpGlobals->curtime + random->RandomFloat( 0.1, 0.2f ),
s_pElectroThinkContext );
}

View File

@@ -1,63 +1,63 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#ifndef ENTITYDISSOLVE_H
#define ENTITYDISSOLVE_H
#ifdef _WIN32
#pragma once
#endif
class CEntityDissolve : public CBaseEntity
{
public:
DECLARE_SERVERCLASS();
DECLARE_CLASS( CEntityDissolve, CBaseEntity );
CEntityDissolve( void );
~CEntityDissolve( void );
static CEntityDissolve *Create( CBaseEntity *pTarget, const char *pMaterialName,
float flStartTime, int nDissolveType = 0, bool *pRagdollCreated = NULL );
static CEntityDissolve *Create( CBaseEntity *pTarget, CBaseEntity *pSource );
void Precache();
void Spawn();
void AttachToEntity( CBaseEntity *pTarget );
void SetStartTime( float flStartTime );
void SetDissolverOrigin( Vector vOrigin ) { m_vDissolverOrigin = vOrigin; }
void SetMagnitude( int iMagnitude ){ m_nMagnitude = iMagnitude; }
void SetDissolveType( int iType ) { m_nDissolveType = iType; }
Vector GetDissolverOrigin( void )
{
Vector vReturn = m_vDissolverOrigin;
return vReturn;
}
int GetMagnitude( void ) { return m_nMagnitude; }
int GetDissolveType( void ) { return m_nDissolveType; }
DECLARE_DATADESC();
CNetworkVar( float, m_flStartTime );
CNetworkVar( float, m_flFadeInStart );
CNetworkVar( float, m_flFadeInLength );
CNetworkVar( float, m_flFadeOutModelStart );
CNetworkVar( float, m_flFadeOutModelLength );
CNetworkVar( float, m_flFadeOutStart );
CNetworkVar( float, m_flFadeOutLength );
protected:
void InputDissolve( inputdata_t &inputdata );
void DissolveThink( void );
void ElectrocuteThink( void );
CNetworkVar( int, m_nDissolveType );
CNetworkVector( m_vDissolverOrigin );
CNetworkVar( int, m_nMagnitude );
};
#endif // ENTITYDISSOLVE_H
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#ifndef ENTITYDISSOLVE_H
#define ENTITYDISSOLVE_H
#ifdef _WIN32
#pragma once
#endif
class CEntityDissolve : public CBaseEntity
{
public:
DECLARE_SERVERCLASS();
DECLARE_CLASS( CEntityDissolve, CBaseEntity );
CEntityDissolve( void );
~CEntityDissolve( void );
static CEntityDissolve *Create( CBaseEntity *pTarget, const char *pMaterialName,
float flStartTime, int nDissolveType = 0, bool *pRagdollCreated = NULL );
static CEntityDissolve *Create( CBaseEntity *pTarget, CBaseEntity *pSource );
void Precache();
void Spawn();
void AttachToEntity( CBaseEntity *pTarget );
void SetStartTime( float flStartTime );
void SetDissolverOrigin( Vector vOrigin ) { m_vDissolverOrigin = vOrigin; }
void SetMagnitude( int iMagnitude ){ m_nMagnitude = iMagnitude; }
void SetDissolveType( int iType ) { m_nDissolveType = iType; }
Vector GetDissolverOrigin( void )
{
Vector vReturn = m_vDissolverOrigin;
return vReturn;
}
int GetMagnitude( void ) { return m_nMagnitude; }
int GetDissolveType( void ) { return m_nDissolveType; }
DECLARE_DATADESC();
CNetworkVar( float, m_flStartTime );
CNetworkVar( float, m_flFadeInStart );
CNetworkVar( float, m_flFadeInLength );
CNetworkVar( float, m_flFadeOutModelStart );
CNetworkVar( float, m_flFadeOutModelLength );
CNetworkVar( float, m_flFadeOutStart );
CNetworkVar( float, m_flFadeOutLength );
protected:
void InputDissolve( inputdata_t &inputdata );
void DissolveThink( void );
void ElectrocuteThink( void );
CNetworkVar( int, m_nDissolveType );
CNetworkVector( m_vDissolverOrigin );
CNetworkVar( int, m_nMagnitude );
};
#endif // ENTITYDISSOLVE_H

View File

@@ -1,335 +1,335 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Flame entity to be attached to target entity. Serves two purposes:
//
// 1) An entity that can be placed by a level designer and triggered
// to ignite a target entity.
//
// 2) An entity that can be created at runtime to ignite a target entity.
//
//=============================================================================//
#include "cbase.h"
#include "EntityFlame.h"
#include "ai_basenpc.h"
#include "fire.h"
#include "shareddefs.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
BEGIN_DATADESC( CEntityFlame )
DEFINE_KEYFIELD( m_flLifetime, FIELD_FLOAT, "lifetime" ),
DEFINE_FIELD( m_flSize, FIELD_FLOAT ),
DEFINE_FIELD( m_hEntAttached, FIELD_EHANDLE ),
DEFINE_FIELD( m_bUseHitboxes, FIELD_BOOLEAN ),
DEFINE_FIELD( m_iNumHitboxFires, FIELD_INTEGER ),
DEFINE_FIELD( m_flHitboxFireScale, FIELD_FLOAT ),
// DEFINE_FIELD( m_bPlayingSound, FIELD_BOOLEAN ),
DEFINE_FUNCTION( FlameThink ),
DEFINE_INPUTFUNC( FIELD_VOID, "Ignite", InputIgnite ),
END_DATADESC()
IMPLEMENT_SERVERCLASS_ST( CEntityFlame, DT_EntityFlame )
SendPropEHandle( SENDINFO( m_hEntAttached ) ),
END_SEND_TABLE()
LINK_ENTITY_TO_CLASS( entityflame, CEntityFlame );
LINK_ENTITY_TO_CLASS( env_entity_igniter, CEntityFlame );
PRECACHE_REGISTER(entityflame);
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
CEntityFlame::CEntityFlame( void )
{
m_flSize = 0.0f;
m_iNumHitboxFires = 10;
m_flHitboxFireScale = 1.0f;
m_flLifetime = 0.0f;
m_bPlayingSound = false;
}
void CEntityFlame::UpdateOnRemove()
{
// Sometimes the entity I'm burning gets destroyed by other means,
// which kills me. Make sure to stop the burning sound.
if ( m_bPlayingSound )
{
EmitSound( "General.StopBurning" );
m_bPlayingSound = false;
}
BaseClass::UpdateOnRemove();
}
void CEntityFlame::Precache()
{
BaseClass::Precache();
PrecacheScriptSound( "General.StopBurning" );
PrecacheScriptSound( "General.BurningFlesh" );
PrecacheScriptSound( "General.BurningObject" );
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : inputdata -
//-----------------------------------------------------------------------------
void CEntityFlame::InputIgnite( inputdata_t &inputdata )
{
if (m_target != NULL_STRING)
{
CBaseEntity *pTarget = NULL;
while ((pTarget = gEntList.FindEntityGeneric(pTarget, STRING(m_target), this, inputdata.pActivator)) != NULL)
{
// Combat characters know how to catch themselves on fire.
CBaseCombatCharacter *pBCC = pTarget->MyCombatCharacterPointer();
if (pBCC)
{
// DVS TODO: consider promoting Ignite to CBaseEntity and doing everything here
pBCC->Ignite(m_flLifetime);
}
// Everything else, we handle here.
else
{
CEntityFlame *pFlame = CEntityFlame::Create(pTarget);
if (pFlame)
{
pFlame->SetLifetime(m_flLifetime);
}
}
}
}
}
//-----------------------------------------------------------------------------
// Purpose: Creates a flame and attaches it to a target entity.
// Input : pTarget -
//-----------------------------------------------------------------------------
CEntityFlame *CEntityFlame::Create( CBaseEntity *pTarget, bool useHitboxes )
{
CEntityFlame *pFlame = (CEntityFlame *) CreateEntityByName( "entityflame" );
if ( pFlame == NULL )
return NULL;
float xSize = pTarget->CollisionProp()->OBBMaxs().x - pTarget->CollisionProp()->OBBMins().x;
float ySize = pTarget->CollisionProp()->OBBMaxs().y - pTarget->CollisionProp()->OBBMins().y;
float size = ( xSize + ySize ) * 0.5f;
if ( size < 16.0f )
{
size = 16.0f;
}
UTIL_SetOrigin( pFlame, pTarget->GetAbsOrigin() );
pFlame->m_flSize = size;
pFlame->SetThink( &CEntityFlame::FlameThink );
pFlame->SetNextThink( gpGlobals->curtime + 0.1f );
pFlame->AttachToEntity( pTarget );
pFlame->SetLifetime( 2.0f );
//Send to the client even though we don't have a model
pFlame->AddEFlags( EFL_FORCE_CHECK_TRANSMIT );
pFlame->SetUseHitboxes( useHitboxes );
return pFlame;
}
//-----------------------------------------------------------------------------
// Purpose: Attaches the flame to an entity and moves with it
// Input : pTarget - target entity to attach to
//-----------------------------------------------------------------------------
void CEntityFlame::AttachToEntity( CBaseEntity *pTarget )
{
// For networking to the client.
m_hEntAttached = pTarget;
if( pTarget->IsNPC() )
{
EmitSound( "General.BurningFlesh" );
}
else
{
EmitSound( "General.BurningObject" );
}
m_bPlayingSound = true;
// So our heat emitter follows the entity around on the server.
SetParent( pTarget );
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : lifetime -
//-----------------------------------------------------------------------------
void CEntityFlame::SetLifetime( float lifetime )
{
m_flLifetime = gpGlobals->curtime + lifetime;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : use -
//-----------------------------------------------------------------------------
void CEntityFlame::SetUseHitboxes( bool use )
{
m_bUseHitboxes = use;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : iNumHitBoxFires -
//-----------------------------------------------------------------------------
void CEntityFlame::SetNumHitboxFires( int iNumHitboxFires )
{
m_iNumHitboxFires = iNumHitboxFires;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : flHitboxFireScale -
//-----------------------------------------------------------------------------
void CEntityFlame::SetHitboxFireScale( float flHitboxFireScale )
{
m_flHitboxFireScale = flHitboxFireScale;
}
float CEntityFlame::GetRemainingLife( void )
{
return m_flLifetime - gpGlobals->curtime;
}
int CEntityFlame::GetNumHitboxFires( void )
{
return m_iNumHitboxFires;
}
float CEntityFlame::GetHitboxFireScale( void )
{
return m_flHitboxFireScale;
}
//-----------------------------------------------------------------------------
// Purpose: Burn targets around us
//-----------------------------------------------------------------------------
void CEntityFlame::FlameThink( void )
{
// Assure that this function will be ticked again even if we early-out in the if below.
SetNextThink( gpGlobals->curtime + FLAME_DAMAGE_INTERVAL );
if ( m_hEntAttached )
{
if ( m_hEntAttached->GetFlags() & FL_TRANSRAGDOLL )
{
SetRenderColorA( 0 );
return;
}
CAI_BaseNPC *pNPC = m_hEntAttached->MyNPCPointer();
if ( pNPC && !pNPC->IsAlive() )
{
UTIL_Remove( this );
// Notify the NPC that it's no longer burning!
pNPC->Extinguish();
return;
}
if( m_hEntAttached->GetWaterLevel() > 0 )
{
Vector mins, maxs;
mins = m_hEntAttached->WorldSpaceCenter();
maxs = mins;
maxs.z = m_hEntAttached->WorldSpaceCenter().z;
maxs.x += 32;
maxs.y += 32;
mins.z -= 32;
mins.x -= 32;
mins.y -= 32;
UTIL_Bubbles( mins, maxs, 12 );
}
}
else
{
UTIL_Remove( this );
return;
}
// See if we're done burning, or our attached ent has vanished
if ( m_flLifetime < gpGlobals->curtime || m_hEntAttached == NULL )
{
EmitSound( "General.StopBurning" );
m_bPlayingSound = false;
SetThink( &CEntityFlame::SUB_Remove );
SetNextThink( gpGlobals->curtime + 0.5f );
// Notify anything we're attached to
if ( m_hEntAttached )
{
CBaseCombatCharacter *pAttachedCC = m_hEntAttached->MyCombatCharacterPointer();
if( pAttachedCC )
{
// Notify the NPC that it's no longer burning!
pAttachedCC->Extinguish();
}
}
return;
}
if ( m_hEntAttached )
{
// Do radius damage ignoring the entity I'm attached to. This will harm things around me.
RadiusDamage( CTakeDamageInfo( this, this, 4.0f, DMG_BURN ), GetAbsOrigin(), m_flSize/2, CLASS_NONE, m_hEntAttached );
// Directly harm the entity I'm attached to. This is so we can precisely control how much damage the entity
// that is on fire takes without worrying about the flame's position relative to the bodytarget (which is the
// distance that the radius damage code uses to determine how much damage to inflict)
m_hEntAttached->TakeDamage( CTakeDamageInfo( this, this, FLAME_DIRECT_DAMAGE, DMG_BURN | DMG_DIRECT ) );
if( !m_hEntAttached->IsNPC() && hl2_episodic.GetBool() )
{
const float ENTITYFLAME_MOVE_AWAY_DIST = 24.0f;
// Make a sound near my origin, and up a little higher (in case I'm on the ground, so NPC's still hear it)
CSoundEnt::InsertSound( SOUND_MOVE_AWAY, GetAbsOrigin(), ENTITYFLAME_MOVE_AWAY_DIST, 0.1f, this, SOUNDENT_CHANNEL_REPEATED_DANGER );
CSoundEnt::InsertSound( SOUND_MOVE_AWAY, GetAbsOrigin() + Vector( 0, 0, 48.0f ), ENTITYFLAME_MOVE_AWAY_DIST, 0.1f, this, SOUNDENT_CHANNEL_REPEATING );
}
}
else
{
RadiusDamage( CTakeDamageInfo( this, this, FLAME_RADIUS_DAMAGE, DMG_BURN ), GetAbsOrigin(), m_flSize/2, CLASS_NONE, NULL );
}
FireSystem_AddHeatInRadius( GetAbsOrigin(), m_flSize/2, 2.0f );
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : pEnt -
//-----------------------------------------------------------------------------
void CreateEntityFlame(CBaseEntity *pEnt)
{
CEntityFlame::Create( pEnt );
}
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Flame entity to be attached to target entity. Serves two purposes:
//
// 1) An entity that can be placed by a level designer and triggered
// to ignite a target entity.
//
// 2) An entity that can be created at runtime to ignite a target entity.
//
//=============================================================================//
#include "cbase.h"
#include "EntityFlame.h"
#include "ai_basenpc.h"
#include "fire.h"
#include "shareddefs.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
BEGIN_DATADESC( CEntityFlame )
DEFINE_KEYFIELD( m_flLifetime, FIELD_FLOAT, "lifetime" ),
DEFINE_FIELD( m_flSize, FIELD_FLOAT ),
DEFINE_FIELD( m_hEntAttached, FIELD_EHANDLE ),
DEFINE_FIELD( m_bUseHitboxes, FIELD_BOOLEAN ),
DEFINE_FIELD( m_iNumHitboxFires, FIELD_INTEGER ),
DEFINE_FIELD( m_flHitboxFireScale, FIELD_FLOAT ),
// DEFINE_FIELD( m_bPlayingSound, FIELD_BOOLEAN ),
DEFINE_FUNCTION( FlameThink ),
DEFINE_INPUTFUNC( FIELD_VOID, "Ignite", InputIgnite ),
END_DATADESC()
IMPLEMENT_SERVERCLASS_ST( CEntityFlame, DT_EntityFlame )
SendPropEHandle( SENDINFO( m_hEntAttached ) ),
END_SEND_TABLE()
LINK_ENTITY_TO_CLASS( entityflame, CEntityFlame );
LINK_ENTITY_TO_CLASS( env_entity_igniter, CEntityFlame );
PRECACHE_REGISTER(entityflame);
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
CEntityFlame::CEntityFlame( void )
{
m_flSize = 0.0f;
m_iNumHitboxFires = 10;
m_flHitboxFireScale = 1.0f;
m_flLifetime = 0.0f;
m_bPlayingSound = false;
}
void CEntityFlame::UpdateOnRemove()
{
// Sometimes the entity I'm burning gets destroyed by other means,
// which kills me. Make sure to stop the burning sound.
if ( m_bPlayingSound )
{
EmitSound( "General.StopBurning" );
m_bPlayingSound = false;
}
BaseClass::UpdateOnRemove();
}
void CEntityFlame::Precache()
{
BaseClass::Precache();
PrecacheScriptSound( "General.StopBurning" );
PrecacheScriptSound( "General.BurningFlesh" );
PrecacheScriptSound( "General.BurningObject" );
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : inputdata -
//-----------------------------------------------------------------------------
void CEntityFlame::InputIgnite( inputdata_t &inputdata )
{
if (m_target != NULL_STRING)
{
CBaseEntity *pTarget = NULL;
while ((pTarget = gEntList.FindEntityGeneric(pTarget, STRING(m_target), this, inputdata.pActivator)) != NULL)
{
// Combat characters know how to catch themselves on fire.
CBaseCombatCharacter *pBCC = pTarget->MyCombatCharacterPointer();
if (pBCC)
{
// DVS TODO: consider promoting Ignite to CBaseEntity and doing everything here
pBCC->Ignite(m_flLifetime);
}
// Everything else, we handle here.
else
{
CEntityFlame *pFlame = CEntityFlame::Create(pTarget);
if (pFlame)
{
pFlame->SetLifetime(m_flLifetime);
}
}
}
}
}
//-----------------------------------------------------------------------------
// Purpose: Creates a flame and attaches it to a target entity.
// Input : pTarget -
//-----------------------------------------------------------------------------
CEntityFlame *CEntityFlame::Create( CBaseEntity *pTarget, bool useHitboxes )
{
CEntityFlame *pFlame = (CEntityFlame *) CreateEntityByName( "entityflame" );
if ( pFlame == NULL )
return NULL;
float xSize = pTarget->CollisionProp()->OBBMaxs().x - pTarget->CollisionProp()->OBBMins().x;
float ySize = pTarget->CollisionProp()->OBBMaxs().y - pTarget->CollisionProp()->OBBMins().y;
float size = ( xSize + ySize ) * 0.5f;
if ( size < 16.0f )
{
size = 16.0f;
}
UTIL_SetOrigin( pFlame, pTarget->GetAbsOrigin() );
pFlame->m_flSize = size;
pFlame->SetThink( &CEntityFlame::FlameThink );
pFlame->SetNextThink( gpGlobals->curtime + 0.1f );
pFlame->AttachToEntity( pTarget );
pFlame->SetLifetime( 2.0f );
//Send to the client even though we don't have a model
pFlame->AddEFlags( EFL_FORCE_CHECK_TRANSMIT );
pFlame->SetUseHitboxes( useHitboxes );
return pFlame;
}
//-----------------------------------------------------------------------------
// Purpose: Attaches the flame to an entity and moves with it
// Input : pTarget - target entity to attach to
//-----------------------------------------------------------------------------
void CEntityFlame::AttachToEntity( CBaseEntity *pTarget )
{
// For networking to the client.
m_hEntAttached = pTarget;
if( pTarget->IsNPC() )
{
EmitSound( "General.BurningFlesh" );
}
else
{
EmitSound( "General.BurningObject" );
}
m_bPlayingSound = true;
// So our heat emitter follows the entity around on the server.
SetParent( pTarget );
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : lifetime -
//-----------------------------------------------------------------------------
void CEntityFlame::SetLifetime( float lifetime )
{
m_flLifetime = gpGlobals->curtime + lifetime;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : use -
//-----------------------------------------------------------------------------
void CEntityFlame::SetUseHitboxes( bool use )
{
m_bUseHitboxes = use;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : iNumHitBoxFires -
//-----------------------------------------------------------------------------
void CEntityFlame::SetNumHitboxFires( int iNumHitboxFires )
{
m_iNumHitboxFires = iNumHitboxFires;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : flHitboxFireScale -
//-----------------------------------------------------------------------------
void CEntityFlame::SetHitboxFireScale( float flHitboxFireScale )
{
m_flHitboxFireScale = flHitboxFireScale;
}
float CEntityFlame::GetRemainingLife( void )
{
return m_flLifetime - gpGlobals->curtime;
}
int CEntityFlame::GetNumHitboxFires( void )
{
return m_iNumHitboxFires;
}
float CEntityFlame::GetHitboxFireScale( void )
{
return m_flHitboxFireScale;
}
//-----------------------------------------------------------------------------
// Purpose: Burn targets around us
//-----------------------------------------------------------------------------
void CEntityFlame::FlameThink( void )
{
// Assure that this function will be ticked again even if we early-out in the if below.
SetNextThink( gpGlobals->curtime + FLAME_DAMAGE_INTERVAL );
if ( m_hEntAttached )
{
if ( m_hEntAttached->GetFlags() & FL_TRANSRAGDOLL )
{
SetRenderColorA( 0 );
return;
}
CAI_BaseNPC *pNPC = m_hEntAttached->MyNPCPointer();
if ( pNPC && !pNPC->IsAlive() )
{
UTIL_Remove( this );
// Notify the NPC that it's no longer burning!
pNPC->Extinguish();
return;
}
if( m_hEntAttached->GetWaterLevel() > 0 )
{
Vector mins, maxs;
mins = m_hEntAttached->WorldSpaceCenter();
maxs = mins;
maxs.z = m_hEntAttached->WorldSpaceCenter().z;
maxs.x += 32;
maxs.y += 32;
mins.z -= 32;
mins.x -= 32;
mins.y -= 32;
UTIL_Bubbles( mins, maxs, 12 );
}
}
else
{
UTIL_Remove( this );
return;
}
// See if we're done burning, or our attached ent has vanished
if ( m_flLifetime < gpGlobals->curtime || m_hEntAttached == NULL )
{
EmitSound( "General.StopBurning" );
m_bPlayingSound = false;
SetThink( &CEntityFlame::SUB_Remove );
SetNextThink( gpGlobals->curtime + 0.5f );
// Notify anything we're attached to
if ( m_hEntAttached )
{
CBaseCombatCharacter *pAttachedCC = m_hEntAttached->MyCombatCharacterPointer();
if( pAttachedCC )
{
// Notify the NPC that it's no longer burning!
pAttachedCC->Extinguish();
}
}
return;
}
if ( m_hEntAttached )
{
// Do radius damage ignoring the entity I'm attached to. This will harm things around me.
RadiusDamage( CTakeDamageInfo( this, this, 4.0f, DMG_BURN ), GetAbsOrigin(), m_flSize/2, CLASS_NONE, m_hEntAttached );
// Directly harm the entity I'm attached to. This is so we can precisely control how much damage the entity
// that is on fire takes without worrying about the flame's position relative to the bodytarget (which is the
// distance that the radius damage code uses to determine how much damage to inflict)
m_hEntAttached->TakeDamage( CTakeDamageInfo( this, this, FLAME_DIRECT_DAMAGE, DMG_BURN | DMG_DIRECT ) );
if( !m_hEntAttached->IsNPC() && hl2_episodic.GetBool() )
{
const float ENTITYFLAME_MOVE_AWAY_DIST = 24.0f;
// Make a sound near my origin, and up a little higher (in case I'm on the ground, so NPC's still hear it)
CSoundEnt::InsertSound( SOUND_MOVE_AWAY, GetAbsOrigin(), ENTITYFLAME_MOVE_AWAY_DIST, 0.1f, this, SOUNDENT_CHANNEL_REPEATED_DANGER );
CSoundEnt::InsertSound( SOUND_MOVE_AWAY, GetAbsOrigin() + Vector( 0, 0, 48.0f ), ENTITYFLAME_MOVE_AWAY_DIST, 0.1f, this, SOUNDENT_CHANNEL_REPEATING );
}
}
else
{
RadiusDamage( CTakeDamageInfo( this, this, FLAME_RADIUS_DAMAGE, DMG_BURN ), GetAbsOrigin(), m_flSize/2, CLASS_NONE, NULL );
}
FireSystem_AddHeatInRadius( GetAbsOrigin(), m_flSize/2, 2.0f );
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : pEnt -
//-----------------------------------------------------------------------------
void CreateEntityFlame(CBaseEntity *pEnt)
{
CEntityFlame::Create( pEnt );
}

View File

@@ -1,66 +1,66 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#ifndef ENTITYFLAME_H
#define ENTITYFLAME_H
#ifdef _WIN32
#pragma once
#endif
#define FLAME_DAMAGE_INTERVAL 0.2f // How often to deal damage.
#define FLAME_DIRECT_DAMAGE_PER_SEC 5.0f
#define FLAME_RADIUS_DAMAGE_PER_SEC 4.0f
#define FLAME_DIRECT_DAMAGE ( FLAME_DIRECT_DAMAGE_PER_SEC * FLAME_DAMAGE_INTERVAL )
#define FLAME_RADIUS_DAMAGE ( FLAME_RADIUS_DAMAGE_PER_SEC * FLAME_DAMAGE_INTERVAL )
#define FLAME_MAX_LIFETIME_ON_DEAD_NPCS 10.0f
class CEntityFlame : public CBaseEntity
{
public:
DECLARE_SERVERCLASS();
DECLARE_CLASS( CEntityFlame, CBaseEntity );
CEntityFlame( void );
static CEntityFlame *Create( CBaseEntity *pTarget, bool useHitboxes = true );
void AttachToEntity( CBaseEntity *pTarget );
void SetLifetime( float lifetime );
void SetUseHitboxes( bool use );
void SetNumHitboxFires( int iNumHitBoxFires );
void SetHitboxFireScale( float flHitboxFireScale );
float GetRemainingLife( void );
int GetNumHitboxFires( void );
float GetHitboxFireScale( void );
virtual void Precache();
virtual void UpdateOnRemove();
void SetSize( float size ) { m_flSize = size; }
DECLARE_DATADESC();
protected:
void InputIgnite( inputdata_t &inputdata );
void FlameThink( void );
CNetworkHandle( CBaseEntity, m_hEntAttached ); // The entity that we are burning (attached to).
CNetworkVar( float, m_flSize );
CNetworkVar( bool, m_bUseHitboxes );
CNetworkVar( int, m_iNumHitboxFires );
CNetworkVar( float, m_flHitboxFireScale );
CNetworkVar( float, m_flLifetime );
bool m_bPlayingSound;
};
#endif // ENTITYFLAME_H
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#ifndef ENTITYFLAME_H
#define ENTITYFLAME_H
#ifdef _WIN32
#pragma once
#endif
#define FLAME_DAMAGE_INTERVAL 0.2f // How often to deal damage.
#define FLAME_DIRECT_DAMAGE_PER_SEC 5.0f
#define FLAME_RADIUS_DAMAGE_PER_SEC 4.0f
#define FLAME_DIRECT_DAMAGE ( FLAME_DIRECT_DAMAGE_PER_SEC * FLAME_DAMAGE_INTERVAL )
#define FLAME_RADIUS_DAMAGE ( FLAME_RADIUS_DAMAGE_PER_SEC * FLAME_DAMAGE_INTERVAL )
#define FLAME_MAX_LIFETIME_ON_DEAD_NPCS 10.0f
class CEntityFlame : public CBaseEntity
{
public:
DECLARE_SERVERCLASS();
DECLARE_CLASS( CEntityFlame, CBaseEntity );
CEntityFlame( void );
static CEntityFlame *Create( CBaseEntity *pTarget, bool useHitboxes = true );
void AttachToEntity( CBaseEntity *pTarget );
void SetLifetime( float lifetime );
void SetUseHitboxes( bool use );
void SetNumHitboxFires( int iNumHitBoxFires );
void SetHitboxFireScale( float flHitboxFireScale );
float GetRemainingLife( void );
int GetNumHitboxFires( void );
float GetHitboxFireScale( void );
virtual void Precache();
virtual void UpdateOnRemove();
void SetSize( float size ) { m_flSize = size; }
DECLARE_DATADESC();
protected:
void InputIgnite( inputdata_t &inputdata );
void FlameThink( void );
CNetworkHandle( CBaseEntity, m_hEntAttached ); // The entity that we are burning (attached to).
CNetworkVar( float, m_flSize );
CNetworkVar( bool, m_bUseHitboxes );
CNetworkVar( int, m_iNumHitboxFires );
CNetworkVar( float, m_flHitboxFireScale );
CNetworkVar( float, m_flLifetime );
bool m_bPlayingSound;
};
#endif // ENTITYFLAME_H

View File

@@ -1,207 +1,207 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Drops particles where the entity was.
//
//=============================================================================//
#include "cbase.h"
#include "EntityParticleTrail.h"
#include "networkstringtable_gamedll.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
//-----------------------------------------------------------------------------
// Used to retire the entity
//-----------------------------------------------------------------------------
static const char *s_pRetireContext = "RetireContext";
//-----------------------------------------------------------------------------
// Save/load
//-----------------------------------------------------------------------------
BEGIN_DATADESC( CEntityParticleTrail )
DEFINE_FIELD( m_iMaterialName, FIELD_MATERIALINDEX ),
DEFINE_EMBEDDED( m_Info ),
DEFINE_FIELD( m_hConstraintEntity, FIELD_EHANDLE ),
// Think this should be handled by StartTouch/etc.
// DEFINE_FIELD( m_nRefCount, FIELD_INTEGER ),
END_DATADESC()
//-----------------------------------------------------------------------------
// Networking
//-----------------------------------------------------------------------------
IMPLEMENT_SERVERCLASS_ST( CEntityParticleTrail, DT_EntityParticleTrail )
SendPropInt(SENDINFO(m_iMaterialName), MAX_MATERIAL_STRING_BITS, SPROP_UNSIGNED ),
SendPropDataTable( SENDINFO_DT( m_Info ), &REFERENCE_SEND_TABLE( DT_EntityParticleTrailInfo ) ),
SendPropEHandle(SENDINFO(m_hConstraintEntity)),
END_SEND_TABLE()
LINK_ENTITY_TO_CLASS( env_particle_trail, CEntityParticleTrail );
//-----------------------------------------------------------------------------
// Purpose: Creates a flame and attaches it to a target entity.
// Input : pTarget -
//-----------------------------------------------------------------------------
CEntityParticleTrail *CEntityParticleTrail::Create( CBaseEntity *pTarget, const EntityParticleTrailInfo_t &info, CBaseEntity *pConstraintEntity )
{
int iMaterialName = GetMaterialIndex( STRING(info.m_strMaterialName) );
// Look for other particle trails on the entity + copy state to the new entity
CEntityParticleTrail *pTrail;
CBaseEntity *pNext;
for ( CBaseEntity *pChild = pTarget->FirstMoveChild(); pChild; pChild = pNext )
{
pNext = pChild->NextMovePeer();
pTrail = dynamic_cast<CEntityParticleTrail*>(pChild);
if ( pTrail && (pTrail->m_iMaterialName == iMaterialName) )
{
// Prevent destruction if it re-enters the field
pTrail->IncrementRefCount();
return pTrail;
}
}
pTrail = (CEntityParticleTrail *)CreateEntityByName( "env_particle_trail" );
if ( pTrail == NULL )
return NULL;
pTrail->m_hConstraintEntity = pConstraintEntity;
pTrail->m_iMaterialName = iMaterialName;
pTrail->m_Info.CopyFrom(info);
pTrail->m_nRefCount = 1;
pTrail->AttachToEntity( pTarget );
pTrail->Spawn();
return pTrail;
}
//-----------------------------------------------------------------------------
// Spawn
//-----------------------------------------------------------------------------
void CEntityParticleTrail::Spawn()
{
BaseClass::Spawn();
/*
SetThink( &CEntityParticleTrail::BoogieThink );
SetNextThink( gpGlobals->curtime + 0.01f );
if ( HasSpawnFlags( SF_RAGDOLL_BOOGIE_ELECTRICAL ) )
{
SetContextThink( ZapThink, gpGlobals->curtime + random->RandomFloat( 0.1f, 0.3f ), s_pZapContext );
}
*/
}
//-----------------------------------------------------------------------------
// Spawn
//-----------------------------------------------------------------------------
void CEntityParticleTrail::UpdateOnRemove()
{
g_pNotify->ClearEntity( this );
BaseClass::UpdateOnRemove();
}
//-----------------------------------------------------------------------------
// Force our constraint entity to be trasmitted
//-----------------------------------------------------------------------------
void CEntityParticleTrail::SetTransmit( CCheckTransmitInfo *pInfo, bool bAlways )
{
// Are we already marked for transmission?
if ( pInfo->m_pTransmitEdict->Get( entindex() ) )
return;
BaseClass::SetTransmit( pInfo, bAlways );
// Force our constraint entity to be sent too.
if ( m_hConstraintEntity )
{
m_hConstraintEntity->SetTransmit( pInfo, bAlways );
}
}
//-----------------------------------------------------------------------------
// Retire
//-----------------------------------------------------------------------------
void CEntityParticleTrail::IncrementRefCount()
{
if ( m_nRefCount == 0 )
{
SetContextThink( NULL, gpGlobals->curtime, s_pRetireContext );
}
++m_nRefCount;
}
void CEntityParticleTrail::DecrementRefCount()
{
--m_nRefCount;
Assert( m_nRefCount >= 0 );
if ( m_nRefCount == 0 )
{
FollowEntity( NULL );
g_pNotify->ClearEntity( this );
SetContextThink( &CEntityParticleTrail::SUB_Remove, gpGlobals->curtime + m_Info.m_flLifetime, s_pRetireContext );
}
}
//-----------------------------------------------------------------------------
// Clean up when the entity goes away.
//-----------------------------------------------------------------------------
void CEntityParticleTrail::NotifySystemEvent( CBaseEntity *pNotify, notify_system_event_t eventType, const notify_system_event_params_t &params )
{
BaseClass::NotifySystemEvent( pNotify, eventType, params );
Assert( pNotify == GetMoveParent() );
if ( eventType == NOTIFY_EVENT_DESTROY )
{
FollowEntity( NULL );
g_pNotify->ClearEntity( this );
if ( m_nRefCount != 0 )
{
m_nRefCount = 0;
SetContextThink( &CEntityParticleTrail::SUB_Remove, gpGlobals->curtime + m_Info.m_flLifetime, s_pRetireContext );
}
}
}
//-----------------------------------------------------------------------------
// Suppression count
//-----------------------------------------------------------------------------
void CEntityParticleTrail::Destroy( CBaseEntity *pTarget, const EntityParticleTrailInfo_t &info )
{
int iMaterialName = GetMaterialIndex( STRING(info.m_strMaterialName) );
// Look for the particle trail attached to this entity + decrease refcount
CBaseEntity *pNext;
for ( CBaseEntity *pChild = pTarget->FirstMoveChild(); pChild; pChild = pNext )
{
pNext = pChild->NextMovePeer();
CEntityParticleTrail *pTrail = dynamic_cast<CEntityParticleTrail*>(pChild);
if ( !pTrail || (pTrail->m_iMaterialName != iMaterialName) )
continue;
pTrail->DecrementRefCount();
}
}
//-----------------------------------------------------------------------------
// Attach to an entity
//-----------------------------------------------------------------------------
void CEntityParticleTrail::AttachToEntity( CBaseEntity *pTarget )
{
FollowEntity( pTarget );
g_pNotify->AddEntity( this, pTarget );
}
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Drops particles where the entity was.
//
//=============================================================================//
#include "cbase.h"
#include "EntityParticleTrail.h"
#include "networkstringtable_gamedll.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
//-----------------------------------------------------------------------------
// Used to retire the entity
//-----------------------------------------------------------------------------
static const char *s_pRetireContext = "RetireContext";
//-----------------------------------------------------------------------------
// Save/load
//-----------------------------------------------------------------------------
BEGIN_DATADESC( CEntityParticleTrail )
DEFINE_FIELD( m_iMaterialName, FIELD_MATERIALINDEX ),
DEFINE_EMBEDDED( m_Info ),
DEFINE_FIELD( m_hConstraintEntity, FIELD_EHANDLE ),
// Think this should be handled by StartTouch/etc.
// DEFINE_FIELD( m_nRefCount, FIELD_INTEGER ),
END_DATADESC()
//-----------------------------------------------------------------------------
// Networking
//-----------------------------------------------------------------------------
IMPLEMENT_SERVERCLASS_ST( CEntityParticleTrail, DT_EntityParticleTrail )
SendPropInt(SENDINFO(m_iMaterialName), MAX_MATERIAL_STRING_BITS, SPROP_UNSIGNED ),
SendPropDataTable( SENDINFO_DT( m_Info ), &REFERENCE_SEND_TABLE( DT_EntityParticleTrailInfo ) ),
SendPropEHandle(SENDINFO(m_hConstraintEntity)),
END_SEND_TABLE()
LINK_ENTITY_TO_CLASS( env_particle_trail, CEntityParticleTrail );
//-----------------------------------------------------------------------------
// Purpose: Creates a flame and attaches it to a target entity.
// Input : pTarget -
//-----------------------------------------------------------------------------
CEntityParticleTrail *CEntityParticleTrail::Create( CBaseEntity *pTarget, const EntityParticleTrailInfo_t &info, CBaseEntity *pConstraintEntity )
{
int iMaterialName = GetMaterialIndex( STRING(info.m_strMaterialName) );
// Look for other particle trails on the entity + copy state to the new entity
CEntityParticleTrail *pTrail;
CBaseEntity *pNext;
for ( CBaseEntity *pChild = pTarget->FirstMoveChild(); pChild; pChild = pNext )
{
pNext = pChild->NextMovePeer();
pTrail = dynamic_cast<CEntityParticleTrail*>(pChild);
if ( pTrail && (pTrail->m_iMaterialName == iMaterialName) )
{
// Prevent destruction if it re-enters the field
pTrail->IncrementRefCount();
return pTrail;
}
}
pTrail = (CEntityParticleTrail *)CreateEntityByName( "env_particle_trail" );
if ( pTrail == NULL )
return NULL;
pTrail->m_hConstraintEntity = pConstraintEntity;
pTrail->m_iMaterialName = iMaterialName;
pTrail->m_Info.CopyFrom(info);
pTrail->m_nRefCount = 1;
pTrail->AttachToEntity( pTarget );
pTrail->Spawn();
return pTrail;
}
//-----------------------------------------------------------------------------
// Spawn
//-----------------------------------------------------------------------------
void CEntityParticleTrail::Spawn()
{
BaseClass::Spawn();
/*
SetThink( &CEntityParticleTrail::BoogieThink );
SetNextThink( gpGlobals->curtime + 0.01f );
if ( HasSpawnFlags( SF_RAGDOLL_BOOGIE_ELECTRICAL ) )
{
SetContextThink( ZapThink, gpGlobals->curtime + random->RandomFloat( 0.1f, 0.3f ), s_pZapContext );
}
*/
}
//-----------------------------------------------------------------------------
// Spawn
//-----------------------------------------------------------------------------
void CEntityParticleTrail::UpdateOnRemove()
{
g_pNotify->ClearEntity( this );
BaseClass::UpdateOnRemove();
}
//-----------------------------------------------------------------------------
// Force our constraint entity to be trasmitted
//-----------------------------------------------------------------------------
void CEntityParticleTrail::SetTransmit( CCheckTransmitInfo *pInfo, bool bAlways )
{
// Are we already marked for transmission?
if ( pInfo->m_pTransmitEdict->Get( entindex() ) )
return;
BaseClass::SetTransmit( pInfo, bAlways );
// Force our constraint entity to be sent too.
if ( m_hConstraintEntity )
{
m_hConstraintEntity->SetTransmit( pInfo, bAlways );
}
}
//-----------------------------------------------------------------------------
// Retire
//-----------------------------------------------------------------------------
void CEntityParticleTrail::IncrementRefCount()
{
if ( m_nRefCount == 0 )
{
SetContextThink( NULL, gpGlobals->curtime, s_pRetireContext );
}
++m_nRefCount;
}
void CEntityParticleTrail::DecrementRefCount()
{
--m_nRefCount;
Assert( m_nRefCount >= 0 );
if ( m_nRefCount == 0 )
{
FollowEntity( NULL );
g_pNotify->ClearEntity( this );
SetContextThink( &CEntityParticleTrail::SUB_Remove, gpGlobals->curtime + m_Info.m_flLifetime, s_pRetireContext );
}
}
//-----------------------------------------------------------------------------
// Clean up when the entity goes away.
//-----------------------------------------------------------------------------
void CEntityParticleTrail::NotifySystemEvent( CBaseEntity *pNotify, notify_system_event_t eventType, const notify_system_event_params_t &params )
{
BaseClass::NotifySystemEvent( pNotify, eventType, params );
Assert( pNotify == GetMoveParent() );
if ( eventType == NOTIFY_EVENT_DESTROY )
{
FollowEntity( NULL );
g_pNotify->ClearEntity( this );
if ( m_nRefCount != 0 )
{
m_nRefCount = 0;
SetContextThink( &CEntityParticleTrail::SUB_Remove, gpGlobals->curtime + m_Info.m_flLifetime, s_pRetireContext );
}
}
}
//-----------------------------------------------------------------------------
// Suppression count
//-----------------------------------------------------------------------------
void CEntityParticleTrail::Destroy( CBaseEntity *pTarget, const EntityParticleTrailInfo_t &info )
{
int iMaterialName = GetMaterialIndex( STRING(info.m_strMaterialName) );
// Look for the particle trail attached to this entity + decrease refcount
CBaseEntity *pNext;
for ( CBaseEntity *pChild = pTarget->FirstMoveChild(); pChild; pChild = pNext )
{
pNext = pChild->NextMovePeer();
CEntityParticleTrail *pTrail = dynamic_cast<CEntityParticleTrail*>(pChild);
if ( !pTrail || (pTrail->m_iMaterialName != iMaterialName) )
continue;
pTrail->DecrementRefCount();
}
}
//-----------------------------------------------------------------------------
// Attach to an entity
//-----------------------------------------------------------------------------
void CEntityParticleTrail::AttachToEntity( CBaseEntity *pTarget )
{
FollowEntity( pTarget );
g_pNotify->AddEntity( this, pTarget );
}

View File

@@ -1,52 +1,52 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#ifndef ENTITYPARTICLETRAIL_H
#define ENTITYPARTICLETRAIL_H
#ifdef _WIN32
#pragma once
#endif
#include "baseparticleentity.h"
#include "entityparticletrail_shared.h"
//-----------------------------------------------------------------------------
// Spawns particles after the entity
//-----------------------------------------------------------------------------
class CEntityParticleTrail : public CBaseParticleEntity
{
DECLARE_DATADESC();
DECLARE_CLASS( CEntityParticleTrail, CBaseParticleEntity );
DECLARE_SERVERCLASS();
public:
static CEntityParticleTrail *Create( CBaseEntity *pTarget, const EntityParticleTrailInfo_t &info, CBaseEntity *pConstraint );
static void Destroy( CBaseEntity *pTarget, const EntityParticleTrailInfo_t &info );
void Spawn();
virtual void UpdateOnRemove();
// Force our constraint entity to be trasmitted
virtual void SetTransmit( CCheckTransmitInfo *pInfo, bool bAlways );
// Clean up when the entity goes away.
virtual void NotifySystemEvent( CBaseEntity *pNotify, notify_system_event_t eventType, const notify_system_event_params_t &params );
private:
void AttachToEntity( CBaseEntity *pTarget );
void IncrementRefCount();
void DecrementRefCount();
CNetworkVar( int, m_iMaterialName );
CNetworkVarEmbedded( EntityParticleTrailInfo_t, m_Info );
CNetworkHandle( CBaseEntity, m_hConstraintEntity );
int m_nRefCount;
};
#endif // ENTITYPARTICLETRAIL_H
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#ifndef ENTITYPARTICLETRAIL_H
#define ENTITYPARTICLETRAIL_H
#ifdef _WIN32
#pragma once
#endif
#include "baseparticleentity.h"
#include "entityparticletrail_shared.h"
//-----------------------------------------------------------------------------
// Spawns particles after the entity
//-----------------------------------------------------------------------------
class CEntityParticleTrail : public CBaseParticleEntity
{
DECLARE_DATADESC();
DECLARE_CLASS( CEntityParticleTrail, CBaseParticleEntity );
DECLARE_SERVERCLASS();
public:
static CEntityParticleTrail *Create( CBaseEntity *pTarget, const EntityParticleTrailInfo_t &info, CBaseEntity *pConstraint );
static void Destroy( CBaseEntity *pTarget, const EntityParticleTrailInfo_t &info );
void Spawn();
virtual void UpdateOnRemove();
// Force our constraint entity to be trasmitted
virtual void SetTransmit( CCheckTransmitInfo *pInfo, bool bAlways );
// Clean up when the entity goes away.
virtual void NotifySystemEvent( CBaseEntity *pNotify, notify_system_event_t eventType, const notify_system_event_params_t &params );
private:
void AttachToEntity( CBaseEntity *pTarget );
void IncrementRefCount();
void DecrementRefCount();
CNetworkVar( int, m_iMaterialName );
CNetworkVarEmbedded( EntityParticleTrailInfo_t, m_Info );
CNetworkHandle( CBaseEntity, m_hConstraintEntity );
int m_nRefCount;
};
#endif // ENTITYPARTICLETRAIL_H

File diff suppressed because it is too large Load Diff

View File

@@ -1,200 +1,200 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Implements visual effects entities: sprites, beams, bubbles, etc.
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "shake.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
class CEnvFade : public CLogicalEntity
{
private:
float m_Duration;
float m_HoldTime;
COutputEvent m_OnBeginFade;
DECLARE_DATADESC();
public:
DECLARE_CLASS( CEnvFade, CLogicalEntity );
virtual void Spawn( void );
inline float Duration( void ) { return m_Duration; }
inline float HoldTime( void ) { return m_HoldTime; }
inline void SetDuration( float duration ) { m_Duration = duration; }
inline void SetHoldTime( float hold ) { m_HoldTime = hold; }
int DrawDebugTextOverlays(void);
// Inputs
void InputFade( inputdata_t &inputdata );
};
LINK_ENTITY_TO_CLASS( env_fade, CEnvFade );
BEGIN_DATADESC( CEnvFade )
DEFINE_KEYFIELD( m_Duration, FIELD_FLOAT, "duration" ),
DEFINE_KEYFIELD( m_HoldTime, FIELD_FLOAT, "holdtime" ),
DEFINE_INPUTFUNC( FIELD_VOID, "Fade", InputFade ),
DEFINE_OUTPUT( m_OnBeginFade, "OnBeginFade"),
END_DATADESC()
#define SF_FADE_IN 0x0001 // Fade in, not out
#define SF_FADE_MODULATE 0x0002 // Modulate, don't blend
#define SF_FADE_ONLYONE 0x0004
#define SF_FADE_STAYOUT 0x0008
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CEnvFade::Spawn( void )
{
}
//-----------------------------------------------------------------------------
// Purpose: Input handler that does the screen fade.
//-----------------------------------------------------------------------------
void CEnvFade::InputFade( inputdata_t &inputdata )
{
int fadeFlags = 0;
if ( m_spawnflags & SF_FADE_IN )
{
fadeFlags |= FFADE_IN;
}
else
{
fadeFlags |= FFADE_OUT;
}
if ( m_spawnflags & SF_FADE_MODULATE )
{
fadeFlags |= FFADE_MODULATE;
}
if ( m_spawnflags & SF_FADE_STAYOUT )
{
fadeFlags |= FFADE_STAYOUT;
}
if ( m_spawnflags & SF_FADE_ONLYONE )
{
if ( inputdata.pActivator->IsNetClient() )
{
UTIL_ScreenFade( inputdata.pActivator, m_clrRender, Duration(), HoldTime(), fadeFlags );
}
}
else
{
UTIL_ScreenFadeAll( m_clrRender, Duration(), HoldTime(), fadeFlags|FFADE_PURGE );
}
m_OnBeginFade.FireOutput( inputdata.pActivator, this );
}
//-----------------------------------------------------------------------------
// Purpose: Fetches the arguments from the command line for the fadein and fadeout
// console commands.
// Input : flTime - Returns the fade time in seconds (the time to fade in or out)
// clrFade - Returns the color to fade to or from.
//-----------------------------------------------------------------------------
static void GetFadeParms( const CCommand &args, float &flTime, color32 &clrFade)
{
flTime = 2.0f;
if ( args.ArgC() > 1 )
{
flTime = atof( args[1] );
}
clrFade.r = 0;
clrFade.g = 0;
clrFade.b = 0;
clrFade.a = 255;
if ( args.ArgC() > 4 )
{
clrFade.r = atoi( args[2] );
clrFade.g = atoi( args[3] );
clrFade.b = atoi( args[4] );
if ( args.ArgC() == 5 )
{
clrFade.a = atoi( args[5] );
}
}
}
//-----------------------------------------------------------------------------
// Purpose: Console command to fade out to a given color.
//-----------------------------------------------------------------------------
static void CC_FadeOut( const CCommand &args )
{
float flTime;
color32 clrFade;
GetFadeParms( args, flTime, clrFade );
CBasePlayer *pPlayer = UTIL_GetCommandClient();
UTIL_ScreenFade( pPlayer, clrFade, flTime, 0, FFADE_OUT | FFADE_PURGE | FFADE_STAYOUT );
}
static ConCommand fadeout("fadeout", CC_FadeOut, "fadeout {time r g b}: Fades the screen to black or to the specified color over the given number of seconds.", FCVAR_CHEAT );
//-----------------------------------------------------------------------------
// Purpose: Console command to fade in from a given color.
//-----------------------------------------------------------------------------
static void CC_FadeIn( const CCommand &args )
{
float flTime;
color32 clrFade;
GetFadeParms( args, flTime, clrFade );
CBasePlayer *pPlayer = UTIL_GetCommandClient();
UTIL_ScreenFade( pPlayer, clrFade, flTime, 0, FFADE_IN | FFADE_PURGE );
}
static ConCommand fadein("fadein", CC_FadeIn, "fadein {time r g b}: Fades the screen in from black or from the specified color over the given number of seconds.", FCVAR_CHEAT );
//-----------------------------------------------------------------------------
// Purpose: Draw any debug text overlays
// Output : Current text offset from the top
//-----------------------------------------------------------------------------
int CEnvFade::DrawDebugTextOverlays( void )
{
int text_offset = BaseClass::DrawDebugTextOverlays();
if (m_debugOverlays & OVERLAY_TEXT_BIT)
{
char tempstr[512];
// print duration
Q_snprintf(tempstr,sizeof(tempstr)," duration: %f", m_Duration);
EntityText(text_offset,tempstr,0);
text_offset++;
// print hold time
Q_snprintf(tempstr,sizeof(tempstr)," hold time: %f", m_HoldTime);
EntityText(text_offset,tempstr,0);
text_offset++;
}
return text_offset;
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Implements visual effects entities: sprites, beams, bubbles, etc.
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "shake.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
class CEnvFade : public CLogicalEntity
{
private:
float m_Duration;
float m_HoldTime;
COutputEvent m_OnBeginFade;
DECLARE_DATADESC();
public:
DECLARE_CLASS( CEnvFade, CLogicalEntity );
virtual void Spawn( void );
inline float Duration( void ) { return m_Duration; }
inline float HoldTime( void ) { return m_HoldTime; }
inline void SetDuration( float duration ) { m_Duration = duration; }
inline void SetHoldTime( float hold ) { m_HoldTime = hold; }
int DrawDebugTextOverlays(void);
// Inputs
void InputFade( inputdata_t &inputdata );
};
LINK_ENTITY_TO_CLASS( env_fade, CEnvFade );
BEGIN_DATADESC( CEnvFade )
DEFINE_KEYFIELD( m_Duration, FIELD_FLOAT, "duration" ),
DEFINE_KEYFIELD( m_HoldTime, FIELD_FLOAT, "holdtime" ),
DEFINE_INPUTFUNC( FIELD_VOID, "Fade", InputFade ),
DEFINE_OUTPUT( m_OnBeginFade, "OnBeginFade"),
END_DATADESC()
#define SF_FADE_IN 0x0001 // Fade in, not out
#define SF_FADE_MODULATE 0x0002 // Modulate, don't blend
#define SF_FADE_ONLYONE 0x0004
#define SF_FADE_STAYOUT 0x0008
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CEnvFade::Spawn( void )
{
}
//-----------------------------------------------------------------------------
// Purpose: Input handler that does the screen fade.
//-----------------------------------------------------------------------------
void CEnvFade::InputFade( inputdata_t &inputdata )
{
int fadeFlags = 0;
if ( m_spawnflags & SF_FADE_IN )
{
fadeFlags |= FFADE_IN;
}
else
{
fadeFlags |= FFADE_OUT;
}
if ( m_spawnflags & SF_FADE_MODULATE )
{
fadeFlags |= FFADE_MODULATE;
}
if ( m_spawnflags & SF_FADE_STAYOUT )
{
fadeFlags |= FFADE_STAYOUT;
}
if ( m_spawnflags & SF_FADE_ONLYONE )
{
if ( inputdata.pActivator->IsNetClient() )
{
UTIL_ScreenFade( inputdata.pActivator, m_clrRender, Duration(), HoldTime(), fadeFlags );
}
}
else
{
UTIL_ScreenFadeAll( m_clrRender, Duration(), HoldTime(), fadeFlags|FFADE_PURGE );
}
m_OnBeginFade.FireOutput( inputdata.pActivator, this );
}
//-----------------------------------------------------------------------------
// Purpose: Fetches the arguments from the command line for the fadein and fadeout
// console commands.
// Input : flTime - Returns the fade time in seconds (the time to fade in or out)
// clrFade - Returns the color to fade to or from.
//-----------------------------------------------------------------------------
static void GetFadeParms( const CCommand &args, float &flTime, color32 &clrFade)
{
flTime = 2.0f;
if ( args.ArgC() > 1 )
{
flTime = atof( args[1] );
}
clrFade.r = 0;
clrFade.g = 0;
clrFade.b = 0;
clrFade.a = 255;
if ( args.ArgC() > 4 )
{
clrFade.r = atoi( args[2] );
clrFade.g = atoi( args[3] );
clrFade.b = atoi( args[4] );
if ( args.ArgC() == 5 )
{
clrFade.a = atoi( args[5] );
}
}
}
//-----------------------------------------------------------------------------
// Purpose: Console command to fade out to a given color.
//-----------------------------------------------------------------------------
static void CC_FadeOut( const CCommand &args )
{
float flTime;
color32 clrFade;
GetFadeParms( args, flTime, clrFade );
CBasePlayer *pPlayer = UTIL_GetCommandClient();
UTIL_ScreenFade( pPlayer, clrFade, flTime, 0, FFADE_OUT | FFADE_PURGE | FFADE_STAYOUT );
}
static ConCommand fadeout("fadeout", CC_FadeOut, "fadeout {time r g b}: Fades the screen to black or to the specified color over the given number of seconds.", FCVAR_CHEAT );
//-----------------------------------------------------------------------------
// Purpose: Console command to fade in from a given color.
//-----------------------------------------------------------------------------
static void CC_FadeIn( const CCommand &args )
{
float flTime;
color32 clrFade;
GetFadeParms( args, flTime, clrFade );
CBasePlayer *pPlayer = UTIL_GetCommandClient();
UTIL_ScreenFade( pPlayer, clrFade, flTime, 0, FFADE_IN | FFADE_PURGE );
}
static ConCommand fadein("fadein", CC_FadeIn, "fadein {time r g b}: Fades the screen in from black or from the specified color over the given number of seconds.", FCVAR_CHEAT );
//-----------------------------------------------------------------------------
// Purpose: Draw any debug text overlays
// Output : Current text offset from the top
//-----------------------------------------------------------------------------
int CEnvFade::DrawDebugTextOverlays( void )
{
int text_offset = BaseClass::DrawDebugTextOverlays();
if (m_debugOverlays & OVERLAY_TEXT_BIT)
{
char tempstr[512];
// print duration
Q_snprintf(tempstr,sizeof(tempstr)," duration: %f", m_Duration);
EntityText(text_offset,tempstr,0);
text_offset++;
// print hold time
Q_snprintf(tempstr,sizeof(tempstr)," hold time: %f", m_HoldTime);
EntityText(text_offset,tempstr,0);
text_offset++;
}
return text_offset;
}

View File

@@ -1,142 +1,142 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Implements visual effects entities: sprites, beams, bubbles, etc.
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "engine/IEngineSound.h"
#include "baseentity.h"
#include "entityoutput.h"
#include "recipientfilter.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
#define SF_HUDHINT_ALLPLAYERS 0x0001
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
class CEnvHudHint : public CPointEntity
{
public:
DECLARE_CLASS( CEnvHudHint, CPointEntity );
void Spawn( void );
void Precache( void );
private:
inline bool AllPlayers( void ) { return (m_spawnflags & SF_HUDHINT_ALLPLAYERS) != 0; }
void InputShowHudHint( inputdata_t &inputdata );
void InputHideHudHint( inputdata_t &inputdata );
string_t m_iszMessage;
DECLARE_DATADESC();
};
LINK_ENTITY_TO_CLASS( env_hudhint, CEnvHudHint );
BEGIN_DATADESC( CEnvHudHint )
DEFINE_KEYFIELD( m_iszMessage, FIELD_STRING, "message" ),
DEFINE_INPUTFUNC( FIELD_VOID, "ShowHudHint", InputShowHudHint ),
DEFINE_INPUTFUNC( FIELD_VOID, "HideHudHint", InputHideHudHint ),
END_DATADESC()
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CEnvHudHint::Spawn( void )
{
Precache();
SetSolid( SOLID_NONE );
SetMoveType( MOVETYPE_NONE );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CEnvHudHint::Precache( void )
{
}
//-----------------------------------------------------------------------------
// Purpose: Input handler for showing the message and/or playing the sound.
//-----------------------------------------------------------------------------
void CEnvHudHint::InputShowHudHint( inputdata_t &inputdata )
{
if ( AllPlayers() )
{
CReliableBroadcastRecipientFilter user;
UserMessageBegin( user, "KeyHintText" );
WRITE_BYTE( 1 ); // one message
WRITE_STRING( STRING(m_iszMessage) );
MessageEnd();
}
else
{
CBaseEntity *pPlayer = NULL;
if ( inputdata.pActivator && inputdata.pActivator->IsPlayer() )
{
pPlayer = inputdata.pActivator;
}
else
{
pPlayer = UTIL_GetLocalPlayer();
}
if ( !pPlayer || !pPlayer->IsNetClient() )
return;
CSingleUserRecipientFilter user( (CBasePlayer *)pPlayer );
user.MakeReliable();
UserMessageBegin( user, "KeyHintText" );
WRITE_BYTE( 1 ); // one message
WRITE_STRING( STRING(m_iszMessage) );
MessageEnd();
}
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CEnvHudHint::InputHideHudHint( inputdata_t &inputdata )
{
if ( AllPlayers() )
{
CReliableBroadcastRecipientFilter user;
UserMessageBegin( user, "KeyHintText" );
WRITE_BYTE( 1 ); // one message
WRITE_STRING( STRING(NULL_STRING) );
MessageEnd();
}
else
{
CBaseEntity *pPlayer = NULL;
if ( inputdata.pActivator && inputdata.pActivator->IsPlayer() )
{
pPlayer = inputdata.pActivator;
}
else
{
pPlayer = UTIL_GetLocalPlayer();
}
if ( !pPlayer || !pPlayer->IsNetClient() )
return;
CSingleUserRecipientFilter user( (CBasePlayer *)pPlayer );
user.MakeReliable();
UserMessageBegin( user, "KeyHintText" );
WRITE_BYTE( 1 ); // one message
WRITE_STRING( STRING(NULL_STRING) );
MessageEnd();
}
}
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Implements visual effects entities: sprites, beams, bubbles, etc.
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "engine/IEngineSound.h"
#include "baseentity.h"
#include "entityoutput.h"
#include "recipientfilter.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
#define SF_HUDHINT_ALLPLAYERS 0x0001
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
class CEnvHudHint : public CPointEntity
{
public:
DECLARE_CLASS( CEnvHudHint, CPointEntity );
void Spawn( void );
void Precache( void );
private:
inline bool AllPlayers( void ) { return (m_spawnflags & SF_HUDHINT_ALLPLAYERS) != 0; }
void InputShowHudHint( inputdata_t &inputdata );
void InputHideHudHint( inputdata_t &inputdata );
string_t m_iszMessage;
DECLARE_DATADESC();
};
LINK_ENTITY_TO_CLASS( env_hudhint, CEnvHudHint );
BEGIN_DATADESC( CEnvHudHint )
DEFINE_KEYFIELD( m_iszMessage, FIELD_STRING, "message" ),
DEFINE_INPUTFUNC( FIELD_VOID, "ShowHudHint", InputShowHudHint ),
DEFINE_INPUTFUNC( FIELD_VOID, "HideHudHint", InputHideHudHint ),
END_DATADESC()
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CEnvHudHint::Spawn( void )
{
Precache();
SetSolid( SOLID_NONE );
SetMoveType( MOVETYPE_NONE );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CEnvHudHint::Precache( void )
{
}
//-----------------------------------------------------------------------------
// Purpose: Input handler for showing the message and/or playing the sound.
//-----------------------------------------------------------------------------
void CEnvHudHint::InputShowHudHint( inputdata_t &inputdata )
{
if ( AllPlayers() )
{
CReliableBroadcastRecipientFilter user;
UserMessageBegin( user, "KeyHintText" );
WRITE_BYTE( 1 ); // one message
WRITE_STRING( STRING(m_iszMessage) );
MessageEnd();
}
else
{
CBaseEntity *pPlayer = NULL;
if ( inputdata.pActivator && inputdata.pActivator->IsPlayer() )
{
pPlayer = inputdata.pActivator;
}
else
{
pPlayer = UTIL_GetLocalPlayer();
}
if ( !pPlayer || !pPlayer->IsNetClient() )
return;
CSingleUserRecipientFilter user( (CBasePlayer *)pPlayer );
user.MakeReliable();
UserMessageBegin( user, "KeyHintText" );
WRITE_BYTE( 1 ); // one message
WRITE_STRING( STRING(m_iszMessage) );
MessageEnd();
}
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CEnvHudHint::InputHideHudHint( inputdata_t &inputdata )
{
if ( AllPlayers() )
{
CReliableBroadcastRecipientFilter user;
UserMessageBegin( user, "KeyHintText" );
WRITE_BYTE( 1 ); // one message
WRITE_STRING( STRING(NULL_STRING) );
MessageEnd();
}
else
{
CBaseEntity *pPlayer = NULL;
if ( inputdata.pActivator && inputdata.pActivator->IsPlayer() )
{
pPlayer = inputdata.pActivator;
}
else
{
pPlayer = UTIL_GetLocalPlayer();
}
if ( !pPlayer || !pPlayer->IsNetClient() )
return;
CSingleUserRecipientFilter user( (CBasePlayer *)pPlayer );
user.MakeReliable();
UserMessageBegin( user, "KeyHintText" );
WRITE_BYTE( 1 ); // one message
WRITE_STRING( STRING(NULL_STRING) );
MessageEnd();
}
}

View File

@@ -1,250 +1,250 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: A special kind of beam effect that traces from its start position to
// its end position and stops if it hits anything.
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "EnvLaser.h"
#include "Sprite.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
LINK_ENTITY_TO_CLASS( env_laser, CEnvLaser );
BEGIN_DATADESC( CEnvLaser )
DEFINE_KEYFIELD( m_iszLaserTarget, FIELD_STRING, "LaserTarget" ),
DEFINE_FIELD( m_pSprite, FIELD_CLASSPTR ),
DEFINE_KEYFIELD( m_iszSpriteName, FIELD_STRING, "EndSprite" ),
DEFINE_FIELD( m_firePosition, FIELD_VECTOR ),
DEFINE_KEYFIELD( m_flStartFrame, FIELD_FLOAT, "framestart" ),
// Function Pointers
DEFINE_FUNCTION( StrikeThink ),
// Input functions
DEFINE_INPUTFUNC( FIELD_VOID, "TurnOn", InputTurnOn ),
DEFINE_INPUTFUNC( FIELD_VOID, "TurnOff", InputTurnOff ),
DEFINE_INPUTFUNC( FIELD_VOID, "Toggle", InputToggle ),
END_DATADESC()
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CEnvLaser::Spawn( void )
{
if ( !GetModelName() )
{
SetThink( &CEnvLaser::SUB_Remove );
return;
}
SetSolid( SOLID_NONE ); // Remove model & collisions
SetThink( &CEnvLaser::StrikeThink );
SetEndWidth( GetWidth() ); // Note: EndWidth is not scaled
PointsInit( GetLocalOrigin(), GetLocalOrigin() );
Precache( );
if ( !m_pSprite && m_iszSpriteName != NULL_STRING )
{
m_pSprite = CSprite::SpriteCreate( STRING(m_iszSpriteName), GetAbsOrigin(), TRUE );
}
else
{
m_pSprite = NULL;
}
if ( m_pSprite )
{
m_pSprite->SetParent( GetMoveParent() );
m_pSprite->SetTransparency( kRenderGlow, m_clrRender->r, m_clrRender->g, m_clrRender->b, m_clrRender->a, m_nRenderFX );
}
if ( GetEntityName() != NULL_STRING && !(m_spawnflags & SF_BEAM_STARTON) )
{
TurnOff();
}
else
{
TurnOn();
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CEnvLaser::Precache( void )
{
SetModelIndex( PrecacheModel( STRING( GetModelName() ) ) );
if ( m_iszSpriteName != NULL_STRING )
PrecacheModel( STRING(m_iszSpriteName) );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
bool CEnvLaser::KeyValue( const char *szKeyName, const char *szValue )
{
if (FStrEq(szKeyName, "width"))
{
SetWidth( atof(szValue) );
}
else if (FStrEq(szKeyName, "NoiseAmplitude"))
{
SetNoise( atoi(szValue) );
}
else if (FStrEq(szKeyName, "TextureScroll"))
{
SetScrollRate( atoi(szValue) );
}
else if (FStrEq(szKeyName, "texture"))
{
SetModelName( AllocPooledString(szValue) );
}
else
{
BaseClass::KeyValue( szKeyName, szValue );
}
return true;
}
//-----------------------------------------------------------------------------
// Purpose: Returns whether the laser is currently active.
//-----------------------------------------------------------------------------
int CEnvLaser::IsOn( void )
{
if ( IsEffectActive( EF_NODRAW ) )
return 0;
return 1;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CEnvLaser::InputTurnOn( inputdata_t &inputdata )
{
if (!IsOn())
{
TurnOn();
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CEnvLaser::InputTurnOff( inputdata_t &inputdata )
{
if (IsOn())
{
TurnOff();
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CEnvLaser::InputToggle( inputdata_t &inputdata )
{
if ( IsOn() )
{
TurnOff();
}
else
{
TurnOn();
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CEnvLaser::TurnOff( void )
{
AddEffects( EF_NODRAW );
if ( m_pSprite )
m_pSprite->TurnOff();
SetNextThink( TICK_NEVER_THINK );
SetThink( NULL );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CEnvLaser::TurnOn( void )
{
RemoveEffects( EF_NODRAW );
if ( m_pSprite )
m_pSprite->TurnOn();
m_flFireTime = gpGlobals->curtime;
SetThink( &CEnvLaser::StrikeThink );
//
// Call StrikeThink here to update the end position, otherwise we will see
// the beam in the wrong place for one frame since we cleared the nodraw flag.
//
StrikeThink();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CEnvLaser::FireAtPoint( trace_t &tr )
{
SetAbsEndPos( tr.endpos );
if ( m_pSprite )
{
UTIL_SetOrigin( m_pSprite, tr.endpos );
}
// Apply damage and do sparks every 1/10th of a second.
if ( gpGlobals->curtime >= m_flFireTime + 0.1 )
{
BeamDamage( &tr );
DoSparks( GetAbsStartPos(), tr.endpos );
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CEnvLaser::StrikeThink( void )
{
CBaseEntity *pEnd = RandomTargetname( STRING( m_iszLaserTarget ) );
Vector vecFireAt = GetAbsEndPos();
if ( pEnd )
{
vecFireAt = pEnd->GetAbsOrigin();
}
trace_t tr;
UTIL_TraceLine( GetAbsOrigin(), vecFireAt, MASK_SOLID, NULL, COLLISION_GROUP_NONE, &tr );
FireAtPoint( tr );
SetNextThink( gpGlobals->curtime );
}
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: A special kind of beam effect that traces from its start position to
// its end position and stops if it hits anything.
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "EnvLaser.h"
#include "Sprite.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
LINK_ENTITY_TO_CLASS( env_laser, CEnvLaser );
BEGIN_DATADESC( CEnvLaser )
DEFINE_KEYFIELD( m_iszLaserTarget, FIELD_STRING, "LaserTarget" ),
DEFINE_FIELD( m_pSprite, FIELD_CLASSPTR ),
DEFINE_KEYFIELD( m_iszSpriteName, FIELD_STRING, "EndSprite" ),
DEFINE_FIELD( m_firePosition, FIELD_VECTOR ),
DEFINE_KEYFIELD( m_flStartFrame, FIELD_FLOAT, "framestart" ),
// Function Pointers
DEFINE_FUNCTION( StrikeThink ),
// Input functions
DEFINE_INPUTFUNC( FIELD_VOID, "TurnOn", InputTurnOn ),
DEFINE_INPUTFUNC( FIELD_VOID, "TurnOff", InputTurnOff ),
DEFINE_INPUTFUNC( FIELD_VOID, "Toggle", InputToggle ),
END_DATADESC()
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CEnvLaser::Spawn( void )
{
if ( !GetModelName() )
{
SetThink( &CEnvLaser::SUB_Remove );
return;
}
SetSolid( SOLID_NONE ); // Remove model & collisions
SetThink( &CEnvLaser::StrikeThink );
SetEndWidth( GetWidth() ); // Note: EndWidth is not scaled
PointsInit( GetLocalOrigin(), GetLocalOrigin() );
Precache( );
if ( !m_pSprite && m_iszSpriteName != NULL_STRING )
{
m_pSprite = CSprite::SpriteCreate( STRING(m_iszSpriteName), GetAbsOrigin(), TRUE );
}
else
{
m_pSprite = NULL;
}
if ( m_pSprite )
{
m_pSprite->SetParent( GetMoveParent() );
m_pSprite->SetTransparency( kRenderGlow, m_clrRender->r, m_clrRender->g, m_clrRender->b, m_clrRender->a, m_nRenderFX );
}
if ( GetEntityName() != NULL_STRING && !(m_spawnflags & SF_BEAM_STARTON) )
{
TurnOff();
}
else
{
TurnOn();
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CEnvLaser::Precache( void )
{
SetModelIndex( PrecacheModel( STRING( GetModelName() ) ) );
if ( m_iszSpriteName != NULL_STRING )
PrecacheModel( STRING(m_iszSpriteName) );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
bool CEnvLaser::KeyValue( const char *szKeyName, const char *szValue )
{
if (FStrEq(szKeyName, "width"))
{
SetWidth( atof(szValue) );
}
else if (FStrEq(szKeyName, "NoiseAmplitude"))
{
SetNoise( atoi(szValue) );
}
else if (FStrEq(szKeyName, "TextureScroll"))
{
SetScrollRate( atoi(szValue) );
}
else if (FStrEq(szKeyName, "texture"))
{
SetModelName( AllocPooledString(szValue) );
}
else
{
BaseClass::KeyValue( szKeyName, szValue );
}
return true;
}
//-----------------------------------------------------------------------------
// Purpose: Returns whether the laser is currently active.
//-----------------------------------------------------------------------------
int CEnvLaser::IsOn( void )
{
if ( IsEffectActive( EF_NODRAW ) )
return 0;
return 1;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CEnvLaser::InputTurnOn( inputdata_t &inputdata )
{
if (!IsOn())
{
TurnOn();
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CEnvLaser::InputTurnOff( inputdata_t &inputdata )
{
if (IsOn())
{
TurnOff();
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CEnvLaser::InputToggle( inputdata_t &inputdata )
{
if ( IsOn() )
{
TurnOff();
}
else
{
TurnOn();
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CEnvLaser::TurnOff( void )
{
AddEffects( EF_NODRAW );
if ( m_pSprite )
m_pSprite->TurnOff();
SetNextThink( TICK_NEVER_THINK );
SetThink( NULL );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CEnvLaser::TurnOn( void )
{
RemoveEffects( EF_NODRAW );
if ( m_pSprite )
m_pSprite->TurnOn();
m_flFireTime = gpGlobals->curtime;
SetThink( &CEnvLaser::StrikeThink );
//
// Call StrikeThink here to update the end position, otherwise we will see
// the beam in the wrong place for one frame since we cleared the nodraw flag.
//
StrikeThink();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CEnvLaser::FireAtPoint( trace_t &tr )
{
SetAbsEndPos( tr.endpos );
if ( m_pSprite )
{
UTIL_SetOrigin( m_pSprite, tr.endpos );
}
// Apply damage and do sparks every 1/10th of a second.
if ( gpGlobals->curtime >= m_flFireTime + 0.1 )
{
BeamDamage( &tr );
DoSparks( GetAbsStartPos(), tr.endpos );
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CEnvLaser::StrikeThink( void )
{
CBaseEntity *pEnd = RandomTargetname( STRING( m_iszLaserTarget ) );
Vector vecFireAt = GetAbsEndPos();
if ( pEnd )
{
vecFireAt = pEnd->GetAbsOrigin();
}
trace_t tr;
UTIL_TraceLine( GetAbsOrigin(), vecFireAt, MASK_SOLID, NULL, COLLISION_GROUP_NONE, &tr );
FireAtPoint( tr );
SetNextThink( gpGlobals->curtime );
}

View File

@@ -1,51 +1,51 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#ifndef ENVLASER_H
#define ENVLASER_H
#ifdef _WIN32
#pragma once
#endif
#include "baseentity.h"
#include "beam_shared.h"
#include "entityoutput.h"
class CSprite;
class CEnvLaser : public CBeam
{
DECLARE_CLASS( CEnvLaser, CBeam );
public:
void Spawn( void );
void Precache( void );
bool KeyValue( const char *szKeyName, const char *szValue );
void TurnOn( void );
void TurnOff( void );
int IsOn( void );
void FireAtPoint( trace_t &point );
void StrikeThink( void );
void InputTurnOn( inputdata_t &inputdata );
void InputTurnOff( inputdata_t &inputdata );
void InputToggle( inputdata_t &inputdata );
DECLARE_DATADESC();
string_t m_iszLaserTarget; // Name of entity or entities to strike at, randomly picked if more than one match.
CSprite *m_pSprite;
string_t m_iszSpriteName;
Vector m_firePosition;
float m_flStartFrame;
};
#endif // ENVLASER_H
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#ifndef ENVLASER_H
#define ENVLASER_H
#ifdef _WIN32
#pragma once
#endif
#include "baseentity.h"
#include "beam_shared.h"
#include "entityoutput.h"
class CSprite;
class CEnvLaser : public CBeam
{
DECLARE_CLASS( CEnvLaser, CBeam );
public:
void Spawn( void );
void Precache( void );
bool KeyValue( const char *szKeyName, const char *szValue );
void TurnOn( void );
void TurnOff( void );
int IsOn( void );
void FireAtPoint( trace_t &point );
void StrikeThink( void );
void InputTurnOn( inputdata_t &inputdata );
void InputTurnOff( inputdata_t &inputdata );
void InputToggle( inputdata_t &inputdata );
DECLARE_DATADESC();
string_t m_iszLaserTarget; // Name of entity or entities to strike at, randomly picked if more than one match.
CSprite *m_pSprite;
string_t m_iszSpriteName;
Vector m_firePosition;
float m_flStartFrame;
};
#endif // ENVLASER_H

View File

@@ -1,278 +1,278 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Implements visual effects entities: sprites, beams, bubbles, etc.
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "EnvMessage.h"
#include "engine/IEngineSound.h"
#include "KeyValues.h"
#include "filesystem.h"
#include "Color.h"
#include "gamestats.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
LINK_ENTITY_TO_CLASS( env_message, CMessage );
BEGIN_DATADESC( CMessage )
DEFINE_KEYFIELD( m_iszMessage, FIELD_STRING, "message" ),
DEFINE_KEYFIELD( m_sNoise, FIELD_SOUNDNAME, "messagesound" ),
DEFINE_KEYFIELD( m_MessageAttenuation, FIELD_INTEGER, "messageattenuation" ),
DEFINE_KEYFIELD( m_MessageVolume, FIELD_FLOAT, "messagevolume" ),
DEFINE_FIELD( m_Radius, FIELD_FLOAT ),
DEFINE_INPUTFUNC( FIELD_VOID, "ShowMessage", InputShowMessage ),
DEFINE_OUTPUT(m_OnShowMessage, "OnShowMessage"),
END_DATADESC()
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CMessage::Spawn( void )
{
Precache();
SetSolid( SOLID_NONE );
SetMoveType( MOVETYPE_NONE );
switch( m_MessageAttenuation )
{
case 1: // Medium radius
m_Radius = ATTN_STATIC;
break;
case 2: // Large radius
m_Radius = ATTN_NORM;
break;
case 3: //EVERYWHERE
m_Radius = ATTN_NONE;
break;
default:
case 0: // Small radius
m_Radius = SNDLVL_IDLE;
break;
}
m_MessageAttenuation = 0;
// Remap volume from [0,10] to [0,1].
m_MessageVolume *= 0.1;
// No volume, use normal
if ( m_MessageVolume <= 0 )
{
m_MessageVolume = 1.0;
}
}
void CMessage::Precache( void )
{
if ( m_sNoise != NULL_STRING )
{
PrecacheScriptSound( STRING(m_sNoise) );
}
}
//-----------------------------------------------------------------------------
// Purpose: Input handler for showing the message and/or playing the sound.
//-----------------------------------------------------------------------------
void CMessage::InputShowMessage( inputdata_t &inputdata )
{
CBaseEntity *pPlayer = NULL;
if ( m_spawnflags & SF_MESSAGE_ALL )
{
UTIL_ShowMessageAll( STRING( m_iszMessage ) );
}
else
{
if ( inputdata.pActivator && inputdata.pActivator->IsPlayer() )
{
pPlayer = inputdata.pActivator;
}
else
{
pPlayer = (gpGlobals->maxClients > 1) ? NULL : UTIL_GetLocalPlayer();
}
if ( pPlayer && pPlayer->IsPlayer() )
{
UTIL_ShowMessage( STRING( m_iszMessage ), ToBasePlayer( pPlayer ) );
}
}
if ( m_sNoise != NULL_STRING )
{
CPASAttenuationFilter filter( this );
EmitSound_t ep;
ep.m_nChannel = CHAN_BODY;
ep.m_pSoundName = (char*)STRING(m_sNoise);
ep.m_flVolume = m_MessageVolume;
ep.m_SoundLevel = ATTN_TO_SNDLVL( m_Radius );
EmitSound( filter, entindex(), ep );
}
if ( m_spawnflags & SF_MESSAGE_ONCE )
{
UTIL_Remove( this );
}
m_OnShowMessage.FireOutput( inputdata.pActivator, this );
}
void CMessage::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
{
inputdata_t inputdata;
inputdata.pActivator = NULL;
inputdata.pCaller = NULL;
InputShowMessage( inputdata );
}
class CCredits : public CPointEntity
{
public:
DECLARE_CLASS( CMessage, CPointEntity );
DECLARE_DATADESC();
void Spawn( void );
void InputRollCredits( inputdata_t &inputdata );
void InputRollOutroCredits( inputdata_t &inputdata );
void InputShowLogo( inputdata_t &inputdata );
void InputSetLogoLength( inputdata_t &inputdata );
COutputEvent m_OnCreditsDone;
virtual void OnRestore();
private:
void RollOutroCredits();
bool m_bRolledOutroCredits;
float m_flLogoLength;
};
LINK_ENTITY_TO_CLASS( env_credits, CCredits );
BEGIN_DATADESC( CCredits )
DEFINE_INPUTFUNC( FIELD_VOID, "RollCredits", InputRollCredits ),
DEFINE_INPUTFUNC( FIELD_VOID, "RollOutroCredits", InputRollOutroCredits ),
DEFINE_INPUTFUNC( FIELD_VOID, "ShowLogo", InputShowLogo ),
DEFINE_INPUTFUNC( FIELD_FLOAT, "SetLogoLength", InputSetLogoLength ),
DEFINE_OUTPUT( m_OnCreditsDone, "OnCreditsDone"),
DEFINE_FIELD( m_bRolledOutroCredits, FIELD_BOOLEAN ),
DEFINE_FIELD( m_flLogoLength, FIELD_FLOAT )
END_DATADESC()
void CCredits::Spawn( void )
{
SetSolid( SOLID_NONE );
SetMoveType( MOVETYPE_NONE );
}
static void CreditsDone_f( void )
{
CCredits *pCredits = (CCredits*)gEntList.FindEntityByClassname( NULL, "env_credits" );
if ( pCredits )
{
pCredits->m_OnCreditsDone.FireOutput( pCredits, pCredits );
}
}
static ConCommand creditsdone("creditsdone", CreditsDone_f );
extern ConVar sv_unlockedchapters;
void CCredits::OnRestore()
{
BaseClass::OnRestore();
if ( m_bRolledOutroCredits )
{
// Roll them again so that the client .dll will send the "creditsdone" message and we'll
// actually get back to the main menu
RollOutroCredits();
}
}
void CCredits::RollOutroCredits()
{
sv_unlockedchapters.SetValue( "15" );
CBasePlayer *pPlayer = UTIL_GetLocalPlayer();
CSingleUserRecipientFilter user( pPlayer );
user.MakeReliable();
UserMessageBegin( user, "CreditsMsg" );
WRITE_BYTE( 3 );
MessageEnd();
}
void CCredits::InputRollOutroCredits( inputdata_t &inputdata )
{
RollOutroCredits();
// In case we save restore
m_bRolledOutroCredits = true;
gamestats->Event_Credits();
}
void CCredits::InputShowLogo( inputdata_t &inputdata )
{
CBasePlayer *pPlayer = UTIL_GetLocalPlayer();
CSingleUserRecipientFilter user( pPlayer );
user.MakeReliable();
if ( m_flLogoLength )
{
UserMessageBegin( user, "LogoTimeMsg" );
WRITE_FLOAT( m_flLogoLength );
MessageEnd();
}
else
{
UserMessageBegin( user, "CreditsMsg" );
WRITE_BYTE( 1 );
MessageEnd();
}
}
void CCredits::InputSetLogoLength( inputdata_t &inputdata )
{
m_flLogoLength = inputdata.value.Float();
}
void CCredits::InputRollCredits( inputdata_t &inputdata )
{
CBasePlayer *pPlayer = UTIL_GetLocalPlayer();
CSingleUserRecipientFilter user( pPlayer );
user.MakeReliable();
UserMessageBegin( user, "CreditsMsg" );
WRITE_BYTE( 2 );
MessageEnd();
}
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Implements visual effects entities: sprites, beams, bubbles, etc.
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "EnvMessage.h"
#include "engine/IEngineSound.h"
#include "KeyValues.h"
#include "filesystem.h"
#include "Color.h"
#include "gamestats.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
LINK_ENTITY_TO_CLASS( env_message, CMessage );
BEGIN_DATADESC( CMessage )
DEFINE_KEYFIELD( m_iszMessage, FIELD_STRING, "message" ),
DEFINE_KEYFIELD( m_sNoise, FIELD_SOUNDNAME, "messagesound" ),
DEFINE_KEYFIELD( m_MessageAttenuation, FIELD_INTEGER, "messageattenuation" ),
DEFINE_KEYFIELD( m_MessageVolume, FIELD_FLOAT, "messagevolume" ),
DEFINE_FIELD( m_Radius, FIELD_FLOAT ),
DEFINE_INPUTFUNC( FIELD_VOID, "ShowMessage", InputShowMessage ),
DEFINE_OUTPUT(m_OnShowMessage, "OnShowMessage"),
END_DATADESC()
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CMessage::Spawn( void )
{
Precache();
SetSolid( SOLID_NONE );
SetMoveType( MOVETYPE_NONE );
switch( m_MessageAttenuation )
{
case 1: // Medium radius
m_Radius = ATTN_STATIC;
break;
case 2: // Large radius
m_Radius = ATTN_NORM;
break;
case 3: //EVERYWHERE
m_Radius = ATTN_NONE;
break;
default:
case 0: // Small radius
m_Radius = SNDLVL_IDLE;
break;
}
m_MessageAttenuation = 0;
// Remap volume from [0,10] to [0,1].
m_MessageVolume *= 0.1;
// No volume, use normal
if ( m_MessageVolume <= 0 )
{
m_MessageVolume = 1.0;
}
}
void CMessage::Precache( void )
{
if ( m_sNoise != NULL_STRING )
{
PrecacheScriptSound( STRING(m_sNoise) );
}
}
//-----------------------------------------------------------------------------
// Purpose: Input handler for showing the message and/or playing the sound.
//-----------------------------------------------------------------------------
void CMessage::InputShowMessage( inputdata_t &inputdata )
{
CBaseEntity *pPlayer = NULL;
if ( m_spawnflags & SF_MESSAGE_ALL )
{
UTIL_ShowMessageAll( STRING( m_iszMessage ) );
}
else
{
if ( inputdata.pActivator && inputdata.pActivator->IsPlayer() )
{
pPlayer = inputdata.pActivator;
}
else
{
pPlayer = (gpGlobals->maxClients > 1) ? NULL : UTIL_GetLocalPlayer();
}
if ( pPlayer && pPlayer->IsPlayer() )
{
UTIL_ShowMessage( STRING( m_iszMessage ), ToBasePlayer( pPlayer ) );
}
}
if ( m_sNoise != NULL_STRING )
{
CPASAttenuationFilter filter( this );
EmitSound_t ep;
ep.m_nChannel = CHAN_BODY;
ep.m_pSoundName = (char*)STRING(m_sNoise);
ep.m_flVolume = m_MessageVolume;
ep.m_SoundLevel = ATTN_TO_SNDLVL( m_Radius );
EmitSound( filter, entindex(), ep );
}
if ( m_spawnflags & SF_MESSAGE_ONCE )
{
UTIL_Remove( this );
}
m_OnShowMessage.FireOutput( inputdata.pActivator, this );
}
void CMessage::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
{
inputdata_t inputdata;
inputdata.pActivator = NULL;
inputdata.pCaller = NULL;
InputShowMessage( inputdata );
}
class CCredits : public CPointEntity
{
public:
DECLARE_CLASS( CMessage, CPointEntity );
DECLARE_DATADESC();
void Spawn( void );
void InputRollCredits( inputdata_t &inputdata );
void InputRollOutroCredits( inputdata_t &inputdata );
void InputShowLogo( inputdata_t &inputdata );
void InputSetLogoLength( inputdata_t &inputdata );
COutputEvent m_OnCreditsDone;
virtual void OnRestore();
private:
void RollOutroCredits();
bool m_bRolledOutroCredits;
float m_flLogoLength;
};
LINK_ENTITY_TO_CLASS( env_credits, CCredits );
BEGIN_DATADESC( CCredits )
DEFINE_INPUTFUNC( FIELD_VOID, "RollCredits", InputRollCredits ),
DEFINE_INPUTFUNC( FIELD_VOID, "RollOutroCredits", InputRollOutroCredits ),
DEFINE_INPUTFUNC( FIELD_VOID, "ShowLogo", InputShowLogo ),
DEFINE_INPUTFUNC( FIELD_FLOAT, "SetLogoLength", InputSetLogoLength ),
DEFINE_OUTPUT( m_OnCreditsDone, "OnCreditsDone"),
DEFINE_FIELD( m_bRolledOutroCredits, FIELD_BOOLEAN ),
DEFINE_FIELD( m_flLogoLength, FIELD_FLOAT )
END_DATADESC()
void CCredits::Spawn( void )
{
SetSolid( SOLID_NONE );
SetMoveType( MOVETYPE_NONE );
}
static void CreditsDone_f( void )
{
CCredits *pCredits = (CCredits*)gEntList.FindEntityByClassname( NULL, "env_credits" );
if ( pCredits )
{
pCredits->m_OnCreditsDone.FireOutput( pCredits, pCredits );
}
}
static ConCommand creditsdone("creditsdone", CreditsDone_f );
extern ConVar sv_unlockedchapters;
void CCredits::OnRestore()
{
BaseClass::OnRestore();
if ( m_bRolledOutroCredits )
{
// Roll them again so that the client .dll will send the "creditsdone" message and we'll
// actually get back to the main menu
RollOutroCredits();
}
}
void CCredits::RollOutroCredits()
{
sv_unlockedchapters.SetValue( "15" );
CBasePlayer *pPlayer = UTIL_GetLocalPlayer();
CSingleUserRecipientFilter user( pPlayer );
user.MakeReliable();
UserMessageBegin( user, "CreditsMsg" );
WRITE_BYTE( 3 );
MessageEnd();
}
void CCredits::InputRollOutroCredits( inputdata_t &inputdata )
{
RollOutroCredits();
// In case we save restore
m_bRolledOutroCredits = true;
gamestats->Event_Credits();
}
void CCredits::InputShowLogo( inputdata_t &inputdata )
{
CBasePlayer *pPlayer = UTIL_GetLocalPlayer();
CSingleUserRecipientFilter user( pPlayer );
user.MakeReliable();
if ( m_flLogoLength )
{
UserMessageBegin( user, "LogoTimeMsg" );
WRITE_FLOAT( m_flLogoLength );
MessageEnd();
}
else
{
UserMessageBegin( user, "CreditsMsg" );
WRITE_BYTE( 1 );
MessageEnd();
}
}
void CCredits::InputSetLogoLength( inputdata_t &inputdata )
{
m_flLogoLength = inputdata.value.Float();
}
void CCredits::InputRollCredits( inputdata_t &inputdata )
{
CBasePlayer *pPlayer = UTIL_GetLocalPlayer();
CSingleUserRecipientFilter user( pPlayer );
user.MakeReliable();
UserMessageBegin( user, "CreditsMsg" );
WRITE_BYTE( 2 );
MessageEnd();
}

View File

@@ -1,48 +1,48 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#ifndef ENVMESSAGE_H
#define ENVMESSAGE_H
#ifdef _WIN32
#pragma once
#endif
#include "baseentity.h"
#include "entityoutput.h"
#define SF_MESSAGE_ONCE 0x0001 // Fade in, not out
#define SF_MESSAGE_ALL 0x0002 // Send to all clients
class CMessage : public CPointEntity
{
public:
DECLARE_CLASS( CMessage, CPointEntity );
void Spawn( void );
void Precache( void );
inline void SetMessage( string_t iszMessage ) { m_iszMessage = iszMessage; }
void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
private:
void InputShowMessage( inputdata_t &inputdata );
string_t m_iszMessage; // Message to display.
float m_MessageVolume;
int m_MessageAttenuation;
float m_Radius;
DECLARE_DATADESC();
string_t m_sNoise;
COutputEvent m_OnShowMessage;
};
#endif // ENVMESSAGE_H
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#ifndef ENVMESSAGE_H
#define ENVMESSAGE_H
#ifdef _WIN32
#pragma once
#endif
#include "baseentity.h"
#include "entityoutput.h"
#define SF_MESSAGE_ONCE 0x0001 // Fade in, not out
#define SF_MESSAGE_ALL 0x0002 // Send to all clients
class CMessage : public CPointEntity
{
public:
DECLARE_CLASS( CMessage, CPointEntity );
void Spawn( void );
void Precache( void );
inline void SetMessage( string_t iszMessage ) { m_iszMessage = iszMessage; }
void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
private:
void InputShowMessage( inputdata_t &inputdata );
string_t m_iszMessage; // Message to display.
float m_MessageVolume;
int m_MessageAttenuation;
float m_Radius;
DECLARE_DATADESC();
string_t m_sNoise;
COutputEvent m_OnShowMessage;
};
#endif // ENVMESSAGE_H

View File

@@ -1,413 +1,413 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Implements a screen shake effect that can also shake physics objects.
//
// NOTE: UTIL_ScreenShake() will only shake players who are on the ground
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "shake.h"
#include "physics_saverestore.h"
#include "rope.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
class CPhysicsShake : public IMotionEvent
{
DECLARE_SIMPLE_DATADESC();
public:
virtual simresult_e Simulate( IPhysicsMotionController *pController, IPhysicsObject *pObject, float deltaTime, Vector &linear, AngularImpulse &angular )
{
Vector contact;
if ( !pObject->GetContactPoint( &contact, NULL ) )
return SIM_NOTHING;
// fudge the force a bit to make it more dramatic
pObject->CalculateForceOffset( m_force * (1.0f + pObject->GetMass()*0.4f), contact, &linear, &angular );
return SIM_LOCAL_FORCE;
}
Vector m_force;
};
BEGIN_SIMPLE_DATADESC( CPhysicsShake )
DEFINE_FIELD( m_force, FIELD_VECTOR ),
END_DATADESC()
class CEnvShake : public CPointEntity
{
private:
float m_Amplitude;
float m_Frequency;
float m_Duration;
float m_Radius; // radius of 0 means all players
float m_stopTime;
float m_nextShake;
float m_currentAmp;
Vector m_maxForce;
IPhysicsMotionController *m_pShakeController;
CPhysicsShake m_shakeCallback;
DECLARE_DATADESC();
public:
DECLARE_CLASS( CEnvShake, CPointEntity );
~CEnvShake( void );
virtual void Spawn( void );
virtual void OnRestore( void );
inline float Amplitude( void ) { return m_Amplitude; }
inline float Frequency( void ) { return m_Frequency; }
inline float Duration( void ) { return m_Duration; }
float Radius( bool bPlayers = true );
inline void SetAmplitude( float amplitude ) { m_Amplitude = amplitude; }
inline void SetFrequency( float frequency ) { m_Frequency = frequency; }
inline void SetDuration( float duration ) { m_Duration = duration; }
inline void SetRadius( float radius ) { m_Radius = radius; }
int DrawDebugTextOverlays(void);
// Input handlers
void InputStartShake( inputdata_t &inputdata );
void InputStopShake( inputdata_t &inputdata );
void InputAmplitude( inputdata_t &inputdata );
void InputFrequency( inputdata_t &inputdata );
// Causes the camera/physics shakes to happen:
void ApplyShake( ShakeCommand_t command );
void Think( void );
};
LINK_ENTITY_TO_CLASS( env_shake, CEnvShake );
BEGIN_DATADESC( CEnvShake )
DEFINE_KEYFIELD( m_Amplitude, FIELD_FLOAT, "amplitude" ),
DEFINE_KEYFIELD( m_Frequency, FIELD_FLOAT, "frequency" ),
DEFINE_KEYFIELD( m_Duration, FIELD_FLOAT, "duration" ),
DEFINE_KEYFIELD( m_Radius, FIELD_FLOAT, "radius" ),
DEFINE_FIELD( m_stopTime, FIELD_TIME ),
DEFINE_FIELD( m_nextShake, FIELD_TIME ),
DEFINE_FIELD( m_currentAmp, FIELD_FLOAT ),
DEFINE_FIELD( m_maxForce, FIELD_VECTOR ),
DEFINE_PHYSPTR( m_pShakeController ),
DEFINE_EMBEDDED( m_shakeCallback ),
DEFINE_INPUTFUNC( FIELD_VOID, "StartShake", InputStartShake ),
DEFINE_INPUTFUNC( FIELD_VOID, "StopShake", InputStopShake ),
DEFINE_INPUTFUNC( FIELD_FLOAT, "Amplitude", InputAmplitude ),
DEFINE_INPUTFUNC( FIELD_FLOAT, "Frequency", InputFrequency ),
END_DATADESC()
#define SF_SHAKE_EVERYONE 0x0001 // Don't check radius
#define SF_SHAKE_INAIR 0x0004 // Shake players in air
#define SF_SHAKE_PHYSICS 0x0008 // Shake physically (not just camera)
#define SF_SHAKE_ROPES 0x0010 // Shake ropes too.
#define SF_SHAKE_NO_VIEW 0x0020 // DON'T shake the view (only ropes and/or physics objects)
#define SF_SHAKE_NO_RUMBLE 0x0040 // DON'T Rumble the XBox Controller
//-----------------------------------------------------------------------------
// Purpose: Destructor.
//-----------------------------------------------------------------------------
CEnvShake::~CEnvShake( void )
{
if ( m_pShakeController )
{
physenv->DestroyMotionController( m_pShakeController );
}
}
float CEnvShake::Radius(bool bPlayers)
{
// The radius for players is zero if SF_SHAKE_EVERYONE is set
if ( bPlayers && HasSpawnFlags(SF_SHAKE_EVERYONE))
return 0;
return m_Radius;
}
//-----------------------------------------------------------------------------
// Purpose: Sets default member values when spawning.
//-----------------------------------------------------------------------------
void CEnvShake::Spawn( void )
{
SetSolid( SOLID_NONE );
SetMoveType( MOVETYPE_NONE );
if ( GetSpawnFlags() & SF_SHAKE_EVERYONE )
{
m_Radius = 0;
}
if ( HasSpawnFlags( SF_SHAKE_NO_VIEW ) && !HasSpawnFlags( SF_SHAKE_PHYSICS ) && !HasSpawnFlags( SF_SHAKE_ROPES ) )
{
DevWarning( "env_shake %s with \"Don't shake view\" spawnflag set without \"Shake physics\" or \"Shake ropes\" spawnflags set.", GetDebugName() );
}
}
//-----------------------------------------------------------------------------
// Purpose: Restore the motion controller
//-----------------------------------------------------------------------------
void CEnvShake::OnRestore( void )
{
BaseClass::OnRestore();
if ( m_pShakeController )
{
m_pShakeController->SetEventHandler( &m_shakeCallback );
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CEnvShake::ApplyShake( ShakeCommand_t command )
{
if ( !HasSpawnFlags( SF_SHAKE_NO_VIEW ) || !HasSpawnFlags( SF_SHAKE_NO_RUMBLE ) )
{
bool air = (GetSpawnFlags() & SF_SHAKE_INAIR) ? true : false;
UTIL_ScreenShake( GetAbsOrigin(), Amplitude(), Frequency(), Duration(), Radius(), command, air );
}
if ( GetSpawnFlags() & SF_SHAKE_ROPES )
{
CRopeKeyframe::ShakeRopes( GetAbsOrigin(), Radius(false), Frequency() );
}
if ( GetSpawnFlags() & SF_SHAKE_PHYSICS )
{
if ( !m_pShakeController )
{
m_pShakeController = physenv->CreateMotionController( &m_shakeCallback );
}
// do physics shake
switch( command )
{
case SHAKE_START:
case SHAKE_START_NORUMBLE:
case SHAKE_START_RUMBLEONLY:
{
m_stopTime = gpGlobals->curtime + Duration();
m_nextShake = 0;
m_pShakeController->ClearObjects();
SetNextThink( gpGlobals->curtime );
m_currentAmp = Amplitude();
CBaseEntity *list[1024];
float radius = Radius(false);
// probably checked "Shake Everywhere" do a big radius
if ( !radius )
{
radius = 512;
}
Vector extents = Vector(radius, radius, radius);
extents.z = MAX(extents.z, 100);
Vector mins = GetAbsOrigin() - extents;
Vector maxs = GetAbsOrigin() + extents;
int count = UTIL_EntitiesInBox( list, 1024, mins, maxs, 0 );
for ( int i = 0; i < count; i++ )
{
//
// Only shake physics entities that players can see. This is one frame out of date
// so it's possible that we could miss objects if a player changed PVS this frame.
//
if ( ( list[i]->GetMoveType() == MOVETYPE_VPHYSICS ) )
{
IPhysicsObject *pPhys = list[i]->VPhysicsGetObject();
if ( pPhys && pPhys->IsMoveable() )
{
m_pShakeController->AttachObject( pPhys, false );
pPhys->Wake();
}
}
}
}
break;
case SHAKE_STOP:
m_pShakeController->ClearObjects();
break;
case SHAKE_AMPLITUDE:
m_currentAmp = Amplitude();
case SHAKE_FREQUENCY:
m_pShakeController->WakeObjects();
break;
}
}
}
//-----------------------------------------------------------------------------
// Purpose: Input handler that starts the screen shake.
//-----------------------------------------------------------------------------
void CEnvShake::InputStartShake( inputdata_t &inputdata )
{
if ( HasSpawnFlags( SF_SHAKE_NO_RUMBLE ) )
{
ApplyShake( SHAKE_START_NORUMBLE );
}
else if ( HasSpawnFlags( SF_SHAKE_NO_VIEW ) )
{
ApplyShake( SHAKE_START_RUMBLEONLY );
}
else
{
ApplyShake( SHAKE_START );
}
}
//-----------------------------------------------------------------------------
// Purpose: Input handler that stops the screen shake.
//-----------------------------------------------------------------------------
void CEnvShake::InputStopShake( inputdata_t &inputdata )
{
ApplyShake( SHAKE_STOP );
}
//-----------------------------------------------------------------------------
// Purpose: Handles changes to the shake amplitude from an external source.
//-----------------------------------------------------------------------------
void CEnvShake::InputAmplitude( inputdata_t &inputdata )
{
SetAmplitude( inputdata.value.Float() );
ApplyShake( SHAKE_AMPLITUDE );
}
//-----------------------------------------------------------------------------
// Purpose: Handles changes to the shake frequency from an external source.
//-----------------------------------------------------------------------------
void CEnvShake::InputFrequency( inputdata_t &inputdata )
{
SetFrequency( inputdata.value.Float() );
ApplyShake( SHAKE_FREQUENCY );
}
//-----------------------------------------------------------------------------
// Purpose: Calculates the physics shake values
//-----------------------------------------------------------------------------
void CEnvShake::Think( void )
{
int i;
if ( gpGlobals->curtime > m_nextShake )
{
// Higher frequency means we recalc the extents more often and perturb the display again
m_nextShake = gpGlobals->curtime + (1.0f / Frequency());
// Compute random shake extents (the shake will settle down from this)
for (i = 0; i < 2; i++ )
{
m_maxForce[i] = random->RandomFloat( -1, 1 );
}
// make the force it point mostly up
m_maxForce.z = 4;
VectorNormalize( m_maxForce );
m_maxForce *= m_currentAmp * 400; // amplitude is the acceleration of a 100kg object
}
float fraction = ( m_stopTime - gpGlobals->curtime ) / Duration();
if ( fraction < 0 )
{
m_pShakeController->ClearObjects();
return;
}
float freq = 0;
// Ramp up frequency over duration
if ( fraction )
{
freq = (Frequency() / fraction);
}
// square fraction to approach zero more quickly
fraction *= fraction;
// Sine wave that slowly settles to zero
fraction = fraction * sin( gpGlobals->curtime * freq );
// Add to view origin
for ( i = 0; i < 3; i++ )
{
// store the force in the controller callback
m_shakeCallback.m_force[i] = m_maxForce[i] * fraction;
}
// Drop amplitude a bit, less for higher frequency shakes
m_currentAmp -= m_currentAmp * ( gpGlobals->frametime / (Duration() * Frequency()) );
SetNextThink( gpGlobals->curtime );
}
//------------------------------------------------------------------------------
// Purpose: Console command to cause a screen shake.
//------------------------------------------------------------------------------
void CC_Shake( void )
{
CBasePlayer *pPlayer = UTIL_GetCommandClient();
if (pPlayer)
{
UTIL_ScreenShake( pPlayer->WorldSpaceCenter(), 25.0, 150.0, 1.0, 750, SHAKE_START );
}
}
//-----------------------------------------------------------------------------
// Purpose: Draw any debug text overlays
// Returns current text offset from the top
//-----------------------------------------------------------------------------
int CEnvShake::DrawDebugTextOverlays( void )
{
int text_offset = BaseClass::DrawDebugTextOverlays();
if (m_debugOverlays & OVERLAY_TEXT_BIT)
{
char tempstr[512];
// print amplitude
Q_snprintf(tempstr,sizeof(tempstr)," magnitude: %f", m_Amplitude);
EntityText(text_offset,tempstr,0);
text_offset++;
// print frequency
Q_snprintf(tempstr,sizeof(tempstr)," frequency: %f", m_Frequency);
EntityText(text_offset,tempstr,0);
text_offset++;
// print duration
Q_snprintf(tempstr,sizeof(tempstr)," duration: %f", m_Duration);
EntityText(text_offset,tempstr,0);
text_offset++;
// print radius
Q_snprintf(tempstr,sizeof(tempstr)," radius: %f", m_Radius);
EntityText(text_offset,tempstr,0);
text_offset++;
}
return text_offset;
}
static ConCommand shake("shake", CC_Shake, "Shake the screen.", FCVAR_CHEAT );
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Implements a screen shake effect that can also shake physics objects.
//
// NOTE: UTIL_ScreenShake() will only shake players who are on the ground
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "shake.h"
#include "physics_saverestore.h"
#include "rope.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
class CPhysicsShake : public IMotionEvent
{
DECLARE_SIMPLE_DATADESC();
public:
virtual simresult_e Simulate( IPhysicsMotionController *pController, IPhysicsObject *pObject, float deltaTime, Vector &linear, AngularImpulse &angular )
{
Vector contact;
if ( !pObject->GetContactPoint( &contact, NULL ) )
return SIM_NOTHING;
// fudge the force a bit to make it more dramatic
pObject->CalculateForceOffset( m_force * (1.0f + pObject->GetMass()*0.4f), contact, &linear, &angular );
return SIM_LOCAL_FORCE;
}
Vector m_force;
};
BEGIN_SIMPLE_DATADESC( CPhysicsShake )
DEFINE_FIELD( m_force, FIELD_VECTOR ),
END_DATADESC()
class CEnvShake : public CPointEntity
{
private:
float m_Amplitude;
float m_Frequency;
float m_Duration;
float m_Radius; // radius of 0 means all players
float m_stopTime;
float m_nextShake;
float m_currentAmp;
Vector m_maxForce;
IPhysicsMotionController *m_pShakeController;
CPhysicsShake m_shakeCallback;
DECLARE_DATADESC();
public:
DECLARE_CLASS( CEnvShake, CPointEntity );
~CEnvShake( void );
virtual void Spawn( void );
virtual void OnRestore( void );
inline float Amplitude( void ) { return m_Amplitude; }
inline float Frequency( void ) { return m_Frequency; }
inline float Duration( void ) { return m_Duration; }
float Radius( bool bPlayers = true );
inline void SetAmplitude( float amplitude ) { m_Amplitude = amplitude; }
inline void SetFrequency( float frequency ) { m_Frequency = frequency; }
inline void SetDuration( float duration ) { m_Duration = duration; }
inline void SetRadius( float radius ) { m_Radius = radius; }
int DrawDebugTextOverlays(void);
// Input handlers
void InputStartShake( inputdata_t &inputdata );
void InputStopShake( inputdata_t &inputdata );
void InputAmplitude( inputdata_t &inputdata );
void InputFrequency( inputdata_t &inputdata );
// Causes the camera/physics shakes to happen:
void ApplyShake( ShakeCommand_t command );
void Think( void );
};
LINK_ENTITY_TO_CLASS( env_shake, CEnvShake );
BEGIN_DATADESC( CEnvShake )
DEFINE_KEYFIELD( m_Amplitude, FIELD_FLOAT, "amplitude" ),
DEFINE_KEYFIELD( m_Frequency, FIELD_FLOAT, "frequency" ),
DEFINE_KEYFIELD( m_Duration, FIELD_FLOAT, "duration" ),
DEFINE_KEYFIELD( m_Radius, FIELD_FLOAT, "radius" ),
DEFINE_FIELD( m_stopTime, FIELD_TIME ),
DEFINE_FIELD( m_nextShake, FIELD_TIME ),
DEFINE_FIELD( m_currentAmp, FIELD_FLOAT ),
DEFINE_FIELD( m_maxForce, FIELD_VECTOR ),
DEFINE_PHYSPTR( m_pShakeController ),
DEFINE_EMBEDDED( m_shakeCallback ),
DEFINE_INPUTFUNC( FIELD_VOID, "StartShake", InputStartShake ),
DEFINE_INPUTFUNC( FIELD_VOID, "StopShake", InputStopShake ),
DEFINE_INPUTFUNC( FIELD_FLOAT, "Amplitude", InputAmplitude ),
DEFINE_INPUTFUNC( FIELD_FLOAT, "Frequency", InputFrequency ),
END_DATADESC()
#define SF_SHAKE_EVERYONE 0x0001 // Don't check radius
#define SF_SHAKE_INAIR 0x0004 // Shake players in air
#define SF_SHAKE_PHYSICS 0x0008 // Shake physically (not just camera)
#define SF_SHAKE_ROPES 0x0010 // Shake ropes too.
#define SF_SHAKE_NO_VIEW 0x0020 // DON'T shake the view (only ropes and/or physics objects)
#define SF_SHAKE_NO_RUMBLE 0x0040 // DON'T Rumble the XBox Controller
//-----------------------------------------------------------------------------
// Purpose: Destructor.
//-----------------------------------------------------------------------------
CEnvShake::~CEnvShake( void )
{
if ( m_pShakeController )
{
physenv->DestroyMotionController( m_pShakeController );
}
}
float CEnvShake::Radius(bool bPlayers)
{
// The radius for players is zero if SF_SHAKE_EVERYONE is set
if ( bPlayers && HasSpawnFlags(SF_SHAKE_EVERYONE))
return 0;
return m_Radius;
}
//-----------------------------------------------------------------------------
// Purpose: Sets default member values when spawning.
//-----------------------------------------------------------------------------
void CEnvShake::Spawn( void )
{
SetSolid( SOLID_NONE );
SetMoveType( MOVETYPE_NONE );
if ( GetSpawnFlags() & SF_SHAKE_EVERYONE )
{
m_Radius = 0;
}
if ( HasSpawnFlags( SF_SHAKE_NO_VIEW ) && !HasSpawnFlags( SF_SHAKE_PHYSICS ) && !HasSpawnFlags( SF_SHAKE_ROPES ) )
{
DevWarning( "env_shake %s with \"Don't shake view\" spawnflag set without \"Shake physics\" or \"Shake ropes\" spawnflags set.", GetDebugName() );
}
}
//-----------------------------------------------------------------------------
// Purpose: Restore the motion controller
//-----------------------------------------------------------------------------
void CEnvShake::OnRestore( void )
{
BaseClass::OnRestore();
if ( m_pShakeController )
{
m_pShakeController->SetEventHandler( &m_shakeCallback );
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CEnvShake::ApplyShake( ShakeCommand_t command )
{
if ( !HasSpawnFlags( SF_SHAKE_NO_VIEW ) || !HasSpawnFlags( SF_SHAKE_NO_RUMBLE ) )
{
bool air = (GetSpawnFlags() & SF_SHAKE_INAIR) ? true : false;
UTIL_ScreenShake( GetAbsOrigin(), Amplitude(), Frequency(), Duration(), Radius(), command, air );
}
if ( GetSpawnFlags() & SF_SHAKE_ROPES )
{
CRopeKeyframe::ShakeRopes( GetAbsOrigin(), Radius(false), Frequency() );
}
if ( GetSpawnFlags() & SF_SHAKE_PHYSICS )
{
if ( !m_pShakeController )
{
m_pShakeController = physenv->CreateMotionController( &m_shakeCallback );
}
// do physics shake
switch( command )
{
case SHAKE_START:
case SHAKE_START_NORUMBLE:
case SHAKE_START_RUMBLEONLY:
{
m_stopTime = gpGlobals->curtime + Duration();
m_nextShake = 0;
m_pShakeController->ClearObjects();
SetNextThink( gpGlobals->curtime );
m_currentAmp = Amplitude();
CBaseEntity *list[1024];
float radius = Radius(false);
// probably checked "Shake Everywhere" do a big radius
if ( !radius )
{
radius = 512;
}
Vector extents = Vector(radius, radius, radius);
extents.z = MAX(extents.z, 100);
Vector mins = GetAbsOrigin() - extents;
Vector maxs = GetAbsOrigin() + extents;
int count = UTIL_EntitiesInBox( list, 1024, mins, maxs, 0 );
for ( int i = 0; i < count; i++ )
{
//
// Only shake physics entities that players can see. This is one frame out of date
// so it's possible that we could miss objects if a player changed PVS this frame.
//
if ( ( list[i]->GetMoveType() == MOVETYPE_VPHYSICS ) )
{
IPhysicsObject *pPhys = list[i]->VPhysicsGetObject();
if ( pPhys && pPhys->IsMoveable() )
{
m_pShakeController->AttachObject( pPhys, false );
pPhys->Wake();
}
}
}
}
break;
case SHAKE_STOP:
m_pShakeController->ClearObjects();
break;
case SHAKE_AMPLITUDE:
m_currentAmp = Amplitude();
case SHAKE_FREQUENCY:
m_pShakeController->WakeObjects();
break;
}
}
}
//-----------------------------------------------------------------------------
// Purpose: Input handler that starts the screen shake.
//-----------------------------------------------------------------------------
void CEnvShake::InputStartShake( inputdata_t &inputdata )
{
if ( HasSpawnFlags( SF_SHAKE_NO_RUMBLE ) )
{
ApplyShake( SHAKE_START_NORUMBLE );
}
else if ( HasSpawnFlags( SF_SHAKE_NO_VIEW ) )
{
ApplyShake( SHAKE_START_RUMBLEONLY );
}
else
{
ApplyShake( SHAKE_START );
}
}
//-----------------------------------------------------------------------------
// Purpose: Input handler that stops the screen shake.
//-----------------------------------------------------------------------------
void CEnvShake::InputStopShake( inputdata_t &inputdata )
{
ApplyShake( SHAKE_STOP );
}
//-----------------------------------------------------------------------------
// Purpose: Handles changes to the shake amplitude from an external source.
//-----------------------------------------------------------------------------
void CEnvShake::InputAmplitude( inputdata_t &inputdata )
{
SetAmplitude( inputdata.value.Float() );
ApplyShake( SHAKE_AMPLITUDE );
}
//-----------------------------------------------------------------------------
// Purpose: Handles changes to the shake frequency from an external source.
//-----------------------------------------------------------------------------
void CEnvShake::InputFrequency( inputdata_t &inputdata )
{
SetFrequency( inputdata.value.Float() );
ApplyShake( SHAKE_FREQUENCY );
}
//-----------------------------------------------------------------------------
// Purpose: Calculates the physics shake values
//-----------------------------------------------------------------------------
void CEnvShake::Think( void )
{
int i;
if ( gpGlobals->curtime > m_nextShake )
{
// Higher frequency means we recalc the extents more often and perturb the display again
m_nextShake = gpGlobals->curtime + (1.0f / Frequency());
// Compute random shake extents (the shake will settle down from this)
for (i = 0; i < 2; i++ )
{
m_maxForce[i] = random->RandomFloat( -1, 1 );
}
// make the force it point mostly up
m_maxForce.z = 4;
VectorNormalize( m_maxForce );
m_maxForce *= m_currentAmp * 400; // amplitude is the acceleration of a 100kg object
}
float fraction = ( m_stopTime - gpGlobals->curtime ) / Duration();
if ( fraction < 0 )
{
m_pShakeController->ClearObjects();
return;
}
float freq = 0;
// Ramp up frequency over duration
if ( fraction )
{
freq = (Frequency() / fraction);
}
// square fraction to approach zero more quickly
fraction *= fraction;
// Sine wave that slowly settles to zero
fraction = fraction * sin( gpGlobals->curtime * freq );
// Add to view origin
for ( i = 0; i < 3; i++ )
{
// store the force in the controller callback
m_shakeCallback.m_force[i] = m_maxForce[i] * fraction;
}
// Drop amplitude a bit, less for higher frequency shakes
m_currentAmp -= m_currentAmp * ( gpGlobals->frametime / (Duration() * Frequency()) );
SetNextThink( gpGlobals->curtime );
}
//------------------------------------------------------------------------------
// Purpose: Console command to cause a screen shake.
//------------------------------------------------------------------------------
void CC_Shake( void )
{
CBasePlayer *pPlayer = UTIL_GetCommandClient();
if (pPlayer)
{
UTIL_ScreenShake( pPlayer->WorldSpaceCenter(), 25.0, 150.0, 1.0, 750, SHAKE_START );
}
}
//-----------------------------------------------------------------------------
// Purpose: Draw any debug text overlays
// Returns current text offset from the top
//-----------------------------------------------------------------------------
int CEnvShake::DrawDebugTextOverlays( void )
{
int text_offset = BaseClass::DrawDebugTextOverlays();
if (m_debugOverlays & OVERLAY_TEXT_BIT)
{
char tempstr[512];
// print amplitude
Q_snprintf(tempstr,sizeof(tempstr)," magnitude: %f", m_Amplitude);
EntityText(text_offset,tempstr,0);
text_offset++;
// print frequency
Q_snprintf(tempstr,sizeof(tempstr)," frequency: %f", m_Frequency);
EntityText(text_offset,tempstr,0);
text_offset++;
// print duration
Q_snprintf(tempstr,sizeof(tempstr)," duration: %f", m_Duration);
EntityText(text_offset,tempstr,0);
text_offset++;
// print radius
Q_snprintf(tempstr,sizeof(tempstr)," radius: %f", m_Radius);
EntityText(text_offset,tempstr,0);
text_offset++;
}
return text_offset;
}
static ConCommand shake("shake", CC_Shake, "Shake the screen.", FCVAR_CHEAT );

View File

@@ -1,195 +1,195 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: A point entity that periodically emits sparks and "bzzt" sounds.
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "IEffects.h"
#include "engine/IEngineSound.h"
#include "envspark.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
//-----------------------------------------------------------------------------
// Purpose: Emits sparks from the given location and plays a random spark sound.
// Input : pev -
// location -
//-----------------------------------------------------------------------------
void DoSpark( CBaseEntity *ent, const Vector &location, int nMagnitude, int nTrailLength, bool bPlaySound, const Vector &vecDir )
{
g_pEffects->Sparks( location, nMagnitude, nTrailLength, &vecDir );
if ( bPlaySound )
{
ent->EmitSound( "DoSpark" );
}
}
const int SF_SPARK_START_ON = 64;
const int SF_SPARK_GLOW = 128;
const int SF_SPARK_SILENT = 256;
const int SF_SPARK_DIRECTIONAL = 512;
BEGIN_DATADESC( CEnvSpark )
DEFINE_KEYFIELD( m_flDelay, FIELD_FLOAT, "MaxDelay" ),
DEFINE_FIELD( m_nGlowSpriteIndex, FIELD_INTEGER ),
DEFINE_KEYFIELD( m_nMagnitude, FIELD_INTEGER, "Magnitude" ),
DEFINE_KEYFIELD( m_nTrailLength, FIELD_INTEGER, "TrailLength" ),
// Function Pointers
DEFINE_FUNCTION( SparkThink ),
DEFINE_INPUTFUNC( FIELD_VOID, "StartSpark", InputStartSpark ),
DEFINE_INPUTFUNC( FIELD_VOID, "StopSpark", InputStopSpark ),
DEFINE_INPUTFUNC( FIELD_VOID, "ToggleSpark", InputToggleSpark ),
DEFINE_INPUTFUNC( FIELD_VOID, "SparkOnce", InputSparkOnce ),
DEFINE_OUTPUT( m_OnSpark, "OnSpark" ),
END_DATADESC()
LINK_ENTITY_TO_CLASS( env_spark, CEnvSpark );
//-----------------------------------------------------------------------------
// Purpose: Constructor! Exciting, isn't it?
//-----------------------------------------------------------------------------
CEnvSpark::CEnvSpark( void )
{
m_nMagnitude = 1;
m_nTrailLength = 1;
}
//-----------------------------------------------------------------------------
// Purpose: Called when spawning, after keyvalues have been handled.
//-----------------------------------------------------------------------------
void CEnvSpark::Spawn(void)
{
SetThink( NULL );
SetUse( NULL );
if ( FBitSet(m_spawnflags, SF_SPARK_START_ON ) )
{
SetThink( &CEnvSpark::SparkThink ); // start sparking
}
SetNextThink( gpGlobals->curtime + 0.1 + random->RandomFloat( 0, 1.5 ) );
// Negative delays are not allowed
if ( m_flDelay < 0 )
{
m_flDelay = 0;
}
#ifdef HL1_DLL
// Don't allow 0 delays in HL1 Port. Enforce a default
if( m_flDelay == 0 )
{
m_flDelay = 1.0f;
}
#endif//HL1_DLL
Precache( );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CEnvSpark::Precache(void)
{
m_nGlowSpriteIndex = PrecacheModel( "sprites/glow01.vmt" );
PrecacheScriptSound( "DoSpark" );
}
extern ConVar phys_pushscale;
//-----------------------------------------------------------------------------
// Purpose: Emits sparks at random intervals.
//-----------------------------------------------------------------------------
void CEnvSpark::SparkThink(void)
{
SetNextThink( gpGlobals->curtime + 0.1 + random->RandomFloat(0, m_flDelay) );
Vector vecDir = vec3_origin;
if ( FBitSet( m_spawnflags, SF_SPARK_DIRECTIONAL ) )
{
AngleVectors( GetAbsAngles(), &vecDir );
}
DoSpark( this, WorldSpaceCenter(), m_nMagnitude, m_nTrailLength, !( m_spawnflags & SF_SPARK_SILENT ), vecDir );
m_OnSpark.FireOutput( this, this );
if (FBitSet(m_spawnflags, SF_SPARK_GLOW))
{
CPVSFilter filter( GetAbsOrigin() );
te->GlowSprite( filter, 0.0, &GetAbsOrigin(), m_nGlowSpriteIndex, 0.2, 1.5, 25 );
}
}
//-----------------------------------------------------------------------------
// Purpose: Input handler for starting the sparks.
//-----------------------------------------------------------------------------
void CEnvSpark::InputStartSpark( inputdata_t &inputdata )
{
StartSpark();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CEnvSpark::StartSpark( void )
{
SetThink( &CEnvSpark::SparkThink );
SetNextThink( gpGlobals->curtime );
}
//-----------------------------------------------------------------------------
// Purpose: Shoot one spark.
//-----------------------------------------------------------------------------
void CEnvSpark::InputSparkOnce( inputdata_t &inputdata )
{
SparkThink();
SetNextThink( TICK_NEVER_THINK );
}
//-----------------------------------------------------------------------------
// Purpose: Input handler for starting the sparks.
//-----------------------------------------------------------------------------
void CEnvSpark::InputStopSpark( inputdata_t &inputdata )
{
StopSpark();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CEnvSpark::StopSpark( void )
{
SetThink( NULL );
}
//-----------------------------------------------------------------------------
// Purpose: Input handler for toggling the on/off state of the sparks.
//-----------------------------------------------------------------------------
void CEnvSpark::InputToggleSpark( inputdata_t &inputdata )
{
if ( GetNextThink() == TICK_NEVER_THINK )
{
InputStartSpark( inputdata );
}
else
{
InputStopSpark( inputdata );
}
}
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: A point entity that periodically emits sparks and "bzzt" sounds.
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "IEffects.h"
#include "engine/IEngineSound.h"
#include "envspark.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
//-----------------------------------------------------------------------------
// Purpose: Emits sparks from the given location and plays a random spark sound.
// Input : pev -
// location -
//-----------------------------------------------------------------------------
void DoSpark( CBaseEntity *ent, const Vector &location, int nMagnitude, int nTrailLength, bool bPlaySound, const Vector &vecDir )
{
g_pEffects->Sparks( location, nMagnitude, nTrailLength, &vecDir );
if ( bPlaySound )
{
ent->EmitSound( "DoSpark" );
}
}
const int SF_SPARK_START_ON = 64;
const int SF_SPARK_GLOW = 128;
const int SF_SPARK_SILENT = 256;
const int SF_SPARK_DIRECTIONAL = 512;
BEGIN_DATADESC( CEnvSpark )
DEFINE_KEYFIELD( m_flDelay, FIELD_FLOAT, "MaxDelay" ),
DEFINE_FIELD( m_nGlowSpriteIndex, FIELD_INTEGER ),
DEFINE_KEYFIELD( m_nMagnitude, FIELD_INTEGER, "Magnitude" ),
DEFINE_KEYFIELD( m_nTrailLength, FIELD_INTEGER, "TrailLength" ),
// Function Pointers
DEFINE_FUNCTION( SparkThink ),
DEFINE_INPUTFUNC( FIELD_VOID, "StartSpark", InputStartSpark ),
DEFINE_INPUTFUNC( FIELD_VOID, "StopSpark", InputStopSpark ),
DEFINE_INPUTFUNC( FIELD_VOID, "ToggleSpark", InputToggleSpark ),
DEFINE_INPUTFUNC( FIELD_VOID, "SparkOnce", InputSparkOnce ),
DEFINE_OUTPUT( m_OnSpark, "OnSpark" ),
END_DATADESC()
LINK_ENTITY_TO_CLASS( env_spark, CEnvSpark );
//-----------------------------------------------------------------------------
// Purpose: Constructor! Exciting, isn't it?
//-----------------------------------------------------------------------------
CEnvSpark::CEnvSpark( void )
{
m_nMagnitude = 1;
m_nTrailLength = 1;
}
//-----------------------------------------------------------------------------
// Purpose: Called when spawning, after keyvalues have been handled.
//-----------------------------------------------------------------------------
void CEnvSpark::Spawn(void)
{
SetThink( NULL );
SetUse( NULL );
if ( FBitSet(m_spawnflags, SF_SPARK_START_ON ) )
{
SetThink( &CEnvSpark::SparkThink ); // start sparking
}
SetNextThink( gpGlobals->curtime + 0.1 + random->RandomFloat( 0, 1.5 ) );
// Negative delays are not allowed
if ( m_flDelay < 0 )
{
m_flDelay = 0;
}
#ifdef HL1_DLL
// Don't allow 0 delays in HL1 Port. Enforce a default
if( m_flDelay == 0 )
{
m_flDelay = 1.0f;
}
#endif//HL1_DLL
Precache( );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CEnvSpark::Precache(void)
{
m_nGlowSpriteIndex = PrecacheModel( "sprites/glow01.vmt" );
PrecacheScriptSound( "DoSpark" );
}
extern ConVar phys_pushscale;
//-----------------------------------------------------------------------------
// Purpose: Emits sparks at random intervals.
//-----------------------------------------------------------------------------
void CEnvSpark::SparkThink(void)
{
SetNextThink( gpGlobals->curtime + 0.1 + random->RandomFloat(0, m_flDelay) );
Vector vecDir = vec3_origin;
if ( FBitSet( m_spawnflags, SF_SPARK_DIRECTIONAL ) )
{
AngleVectors( GetAbsAngles(), &vecDir );
}
DoSpark( this, WorldSpaceCenter(), m_nMagnitude, m_nTrailLength, !( m_spawnflags & SF_SPARK_SILENT ), vecDir );
m_OnSpark.FireOutput( this, this );
if (FBitSet(m_spawnflags, SF_SPARK_GLOW))
{
CPVSFilter filter( GetAbsOrigin() );
te->GlowSprite( filter, 0.0, &GetAbsOrigin(), m_nGlowSpriteIndex, 0.2, 1.5, 25 );
}
}
//-----------------------------------------------------------------------------
// Purpose: Input handler for starting the sparks.
//-----------------------------------------------------------------------------
void CEnvSpark::InputStartSpark( inputdata_t &inputdata )
{
StartSpark();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CEnvSpark::StartSpark( void )
{
SetThink( &CEnvSpark::SparkThink );
SetNextThink( gpGlobals->curtime );
}
//-----------------------------------------------------------------------------
// Purpose: Shoot one spark.
//-----------------------------------------------------------------------------
void CEnvSpark::InputSparkOnce( inputdata_t &inputdata )
{
SparkThink();
SetNextThink( TICK_NEVER_THINK );
}
//-----------------------------------------------------------------------------
// Purpose: Input handler for starting the sparks.
//-----------------------------------------------------------------------------
void CEnvSpark::InputStopSpark( inputdata_t &inputdata )
{
StopSpark();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CEnvSpark::StopSpark( void )
{
SetThink( NULL );
}
//-----------------------------------------------------------------------------
// Purpose: Input handler for toggling the on/off state of the sparks.
//-----------------------------------------------------------------------------
void CEnvSpark::InputToggleSpark( inputdata_t &inputdata )
{
if ( GetNextThink() == TICK_NEVER_THINK )
{
InputStartSpark( inputdata );
}
else
{
InputStopSpark( inputdata );
}
}

View File

@@ -1,257 +1,257 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//
//=============================================================================//
#include "cbase.h"
#include "EventLog.h"
#include "team.h"
#include "KeyValues.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
CEventLog::CEventLog()
{
}
CEventLog::~CEventLog()
{
}
void CEventLog::FireGameEvent( IGameEvent *event )
{
PrintEvent ( event );
}
bool CEventLog::PrintEvent( IGameEvent *event )
{
const char * name = event->GetName();
if ( Q_strncmp(name, "server_", strlen("server_")) == 0 )
{
return true; // we don't care about server events (engine does)
}
else if ( Q_strncmp(name, "player_", strlen("player_")) == 0 )
{
return PrintPlayerEvent( event );
}
else if ( Q_strncmp(name, "team_", strlen("team_")) == 0 )
{
return PrintTeamEvent( event );
}
else if ( Q_strncmp(name, "game_", strlen("game_")) == 0 )
{
return PrintGameEvent( event );
}
else
{
return PrintOtherEvent( event ); // bomb_, round_, et al
}
}
bool CEventLog::PrintGameEvent( IGameEvent *event )
{
// const char * name = event->GetName() + Q_strlen("game_"); // remove prefix
return false;
}
bool CEventLog::PrintPlayerEvent( IGameEvent *event )
{
const char * eventName = event->GetName();
const int userid = event->GetInt( "userid" );
if ( !Q_strncmp( eventName, "player_connect", Q_strlen("player_connect") ) ) // player connect is before the CBasePlayer pointer is setup
{
const char *name = event->GetString( "name" );
const char *address = event->GetString( "address" );
const char *networkid = event->GetString("networkid" );
UTIL_LogPrintf( "\"%s<%i><%s><>\" connected, address \"%s\"\n", name, userid, networkid, address);
return true;
}
else if ( !Q_strncmp( eventName, "player_disconnect", Q_strlen("player_disconnect") ) )
{
const char *reason = event->GetString("reason" );
const char *name = event->GetString("name" );
const char *networkid = event->GetString("networkid" );
CTeam *team = NULL;
CBasePlayer *pPlayer = UTIL_PlayerByUserId( userid );
if ( pPlayer )
{
team = pPlayer->GetTeam();
}
UTIL_LogPrintf( "\"%s<%i><%s><%s>\" disconnected (reason \"%s\")\n", name, userid, networkid, team ? team->GetName() : "", reason );
return true;
}
CBasePlayer *pPlayer = UTIL_PlayerByUserId( userid );
if ( !pPlayer)
{
DevMsg( "CEventLog::PrintPlayerEvent: Failed to find player (userid: %i, event: %s)\n", userid, eventName );
return false;
}
if ( !Q_strncmp( eventName, "player_team", Q_strlen("player_team") ) )
{
const bool bDisconnecting = event->GetBool( "disconnect" );
if ( !bDisconnecting )
{
const int newTeam = event->GetInt( "team" );
const int oldTeam = event->GetInt( "oldteam" );
CTeam *team = GetGlobalTeam( newTeam );
CTeam *oldteam = GetGlobalTeam( oldTeam );
UTIL_LogPrintf( "\"%s<%i><%s><%s>\" joined team \"%s\"\n",
pPlayer->GetPlayerName(),
pPlayer->GetUserID(),
pPlayer->GetNetworkIDString(),
oldteam->GetName(),
team->GetName() );
}
return true;
}
else if ( !Q_strncmp( eventName, "player_death", Q_strlen("player_death") ) )
{
const int attackerid = event->GetInt("attacker" );
#ifdef HL2MP
const char *weapon = event->GetString( "weapon" );
#endif
CBasePlayer *pAttacker = UTIL_PlayerByUserId( attackerid );
CTeam *team = pPlayer->GetTeam();
CTeam *attackerTeam = NULL;
if ( pAttacker )
{
attackerTeam = pAttacker->GetTeam();
}
if ( pPlayer == pAttacker && pPlayer )
{
#ifdef HL2MP
UTIL_LogPrintf( "\"%s<%i><%s><%s>\" committed suicide with \"%s\"\n",
pPlayer->GetPlayerName(),
userid,
pPlayer->GetNetworkIDString(),
team ? team->GetName() : "",
weapon
);
#else
UTIL_LogPrintf( "\"%s<%i><%s><%s>\" committed suicide with \"%s\"\n",
pPlayer->GetPlayerName(),
userid,
pPlayer->GetNetworkIDString(),
team ? team->GetName() : "",
pAttacker->GetClassname()
);
#endif
}
else if ( pAttacker )
{
CTeam *attackerTeam = pAttacker->GetTeam();
#ifdef HL2MP
UTIL_LogPrintf( "\"%s<%i><%s><%s>\" killed \"%s<%i><%s><%s>\" with \"%s\"\n",
pAttacker->GetPlayerName(),
attackerid,
pAttacker->GetNetworkIDString(),
attackerTeam ? attackerTeam->GetName() : "",
pPlayer->GetPlayerName(),
userid,
pPlayer->GetNetworkIDString(),
team ? team->GetName() : "",
weapon
);
#else
UTIL_LogPrintf( "\"%s<%i><%s><%s>\" killed \"%s<%i><%s><%s>\"\n",
pAttacker->GetPlayerName(),
attackerid,
pAttacker->GetNetworkIDString(),
attackerTeam ? attackerTeam->GetName() : "",
pPlayer->GetPlayerName(),
userid,
pPlayer->GetNetworkIDString(),
team ? team->GetName() : ""
);
#endif
}
else
{
// killed by the world
UTIL_LogPrintf( "\"%s<%i><%s><%s>\" committed suicide with \"world\"\n",
pPlayer->GetPlayerName(),
userid,
pPlayer->GetNetworkIDString(),
team ? team->GetName() : ""
);
}
return true;
}
else if ( !Q_strncmp( eventName, "player_activate", Q_strlen("player_activate") ) )
{
UTIL_LogPrintf( "\"%s<%i><%s><>\" entered the game\n",
pPlayer->GetPlayerName(),
userid,
pPlayer->GetNetworkIDString()
);
return true;
}
else if ( !Q_strncmp( eventName, "player_changename", Q_strlen("player_changename") ) )
{
const char *newName = event->GetString( "newname" );
const char *oldName = event->GetString( "oldname" );
CTeam *team = pPlayer->GetTeam();
UTIL_LogPrintf( "\"%s<%i><%s><%s>\" changed name to \"%s\"\n",
oldName,
userid,
pPlayer->GetNetworkIDString(),
team ? team->GetName() : "",
newName
);
return true;
}
// ignored events
//player_hurt
return false;
}
bool CEventLog::PrintTeamEvent( IGameEvent *event )
{
// const char * name = event->GetName() + Q_strlen("team_"); // remove prefix
return false;
}
bool CEventLog::PrintOtherEvent( IGameEvent *event )
{
return false;
}
bool CEventLog::Init()
{
ListenForGameEvent( "player_changename" );
ListenForGameEvent( "player_activate" );
ListenForGameEvent( "player_death" );
ListenForGameEvent( "player_team" );
ListenForGameEvent( "player_disconnect" );
ListenForGameEvent( "player_connect" );
return true;
}
void CEventLog::Shutdown()
{
StopListeningForAllEvents();
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//
//=============================================================================//
#include "cbase.h"
#include "EventLog.h"
#include "team.h"
#include "KeyValues.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
CEventLog::CEventLog()
{
}
CEventLog::~CEventLog()
{
}
void CEventLog::FireGameEvent( IGameEvent *event )
{
PrintEvent ( event );
}
bool CEventLog::PrintEvent( IGameEvent *event )
{
const char * name = event->GetName();
if ( Q_strncmp(name, "server_", strlen("server_")) == 0 )
{
return true; // we don't care about server events (engine does)
}
else if ( Q_strncmp(name, "player_", strlen("player_")) == 0 )
{
return PrintPlayerEvent( event );
}
else if ( Q_strncmp(name, "team_", strlen("team_")) == 0 )
{
return PrintTeamEvent( event );
}
else if ( Q_strncmp(name, "game_", strlen("game_")) == 0 )
{
return PrintGameEvent( event );
}
else
{
return PrintOtherEvent( event ); // bomb_, round_, et al
}
}
bool CEventLog::PrintGameEvent( IGameEvent *event )
{
// const char * name = event->GetName() + Q_strlen("game_"); // remove prefix
return false;
}
bool CEventLog::PrintPlayerEvent( IGameEvent *event )
{
const char * eventName = event->GetName();
const int userid = event->GetInt( "userid" );
if ( !Q_strncmp( eventName, "player_connect", Q_strlen("player_connect") ) ) // player connect is before the CBasePlayer pointer is setup
{
const char *name = event->GetString( "name" );
const char *address = event->GetString( "address" );
const char *networkid = event->GetString("networkid" );
UTIL_LogPrintf( "\"%s<%i><%s><>\" connected, address \"%s\"\n", name, userid, networkid, address);
return true;
}
else if ( !Q_strncmp( eventName, "player_disconnect", Q_strlen("player_disconnect") ) )
{
const char *reason = event->GetString("reason" );
const char *name = event->GetString("name" );
const char *networkid = event->GetString("networkid" );
CTeam *team = NULL;
CBasePlayer *pPlayer = UTIL_PlayerByUserId( userid );
if ( pPlayer )
{
team = pPlayer->GetTeam();
}
UTIL_LogPrintf( "\"%s<%i><%s><%s>\" disconnected (reason \"%s\")\n", name, userid, networkid, team ? team->GetName() : "", reason );
return true;
}
CBasePlayer *pPlayer = UTIL_PlayerByUserId( userid );
if ( !pPlayer)
{
DevMsg( "CEventLog::PrintPlayerEvent: Failed to find player (userid: %i, event: %s)\n", userid, eventName );
return false;
}
if ( !Q_strncmp( eventName, "player_team", Q_strlen("player_team") ) )
{
const bool bDisconnecting = event->GetBool( "disconnect" );
if ( !bDisconnecting )
{
const int newTeam = event->GetInt( "team" );
const int oldTeam = event->GetInt( "oldteam" );
CTeam *team = GetGlobalTeam( newTeam );
CTeam *oldteam = GetGlobalTeam( oldTeam );
UTIL_LogPrintf( "\"%s<%i><%s><%s>\" joined team \"%s\"\n",
pPlayer->GetPlayerName(),
pPlayer->GetUserID(),
pPlayer->GetNetworkIDString(),
oldteam->GetName(),
team->GetName() );
}
return true;
}
else if ( !Q_strncmp( eventName, "player_death", Q_strlen("player_death") ) )
{
const int attackerid = event->GetInt("attacker" );
#ifdef HL2MP
const char *weapon = event->GetString( "weapon" );
#endif
CBasePlayer *pAttacker = UTIL_PlayerByUserId( attackerid );
CTeam *team = pPlayer->GetTeam();
CTeam *attackerTeam = NULL;
if ( pAttacker )
{
attackerTeam = pAttacker->GetTeam();
}
if ( pPlayer == pAttacker && pPlayer )
{
#ifdef HL2MP
UTIL_LogPrintf( "\"%s<%i><%s><%s>\" committed suicide with \"%s\"\n",
pPlayer->GetPlayerName(),
userid,
pPlayer->GetNetworkIDString(),
team ? team->GetName() : "",
weapon
);
#else
UTIL_LogPrintf( "\"%s<%i><%s><%s>\" committed suicide with \"%s\"\n",
pPlayer->GetPlayerName(),
userid,
pPlayer->GetNetworkIDString(),
team ? team->GetName() : "",
pAttacker->GetClassname()
);
#endif
}
else if ( pAttacker )
{
CTeam *attackerTeam = pAttacker->GetTeam();
#ifdef HL2MP
UTIL_LogPrintf( "\"%s<%i><%s><%s>\" killed \"%s<%i><%s><%s>\" with \"%s\"\n",
pAttacker->GetPlayerName(),
attackerid,
pAttacker->GetNetworkIDString(),
attackerTeam ? attackerTeam->GetName() : "",
pPlayer->GetPlayerName(),
userid,
pPlayer->GetNetworkIDString(),
team ? team->GetName() : "",
weapon
);
#else
UTIL_LogPrintf( "\"%s<%i><%s><%s>\" killed \"%s<%i><%s><%s>\"\n",
pAttacker->GetPlayerName(),
attackerid,
pAttacker->GetNetworkIDString(),
attackerTeam ? attackerTeam->GetName() : "",
pPlayer->GetPlayerName(),
userid,
pPlayer->GetNetworkIDString(),
team ? team->GetName() : ""
);
#endif
}
else
{
// killed by the world
UTIL_LogPrintf( "\"%s<%i><%s><%s>\" committed suicide with \"world\"\n",
pPlayer->GetPlayerName(),
userid,
pPlayer->GetNetworkIDString(),
team ? team->GetName() : ""
);
}
return true;
}
else if ( !Q_strncmp( eventName, "player_activate", Q_strlen("player_activate") ) )
{
UTIL_LogPrintf( "\"%s<%i><%s><>\" entered the game\n",
pPlayer->GetPlayerName(),
userid,
pPlayer->GetNetworkIDString()
);
return true;
}
else if ( !Q_strncmp( eventName, "player_changename", Q_strlen("player_changename") ) )
{
const char *newName = event->GetString( "newname" );
const char *oldName = event->GetString( "oldname" );
CTeam *team = pPlayer->GetTeam();
UTIL_LogPrintf( "\"%s<%i><%s><%s>\" changed name to \"%s\"\n",
oldName,
userid,
pPlayer->GetNetworkIDString(),
team ? team->GetName() : "",
newName
);
return true;
}
// ignored events
//player_hurt
return false;
}
bool CEventLog::PrintTeamEvent( IGameEvent *event )
{
// const char * name = event->GetName() + Q_strlen("team_"); // remove prefix
return false;
}
bool CEventLog::PrintOtherEvent( IGameEvent *event )
{
return false;
}
bool CEventLog::Init()
{
ListenForGameEvent( "player_changename" );
ListenForGameEvent( "player_activate" );
ListenForGameEvent( "player_death" );
ListenForGameEvent( "player_team" );
ListenForGameEvent( "player_disconnect" );
ListenForGameEvent( "player_connect" );
return true;
}
void CEventLog::Shutdown()
{
StopListeningForAllEvents();
}

View File

@@ -1,46 +1,46 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//
//=============================================================================//
#if !defined EVENTLOG_H
#define EVENTLOG_H
#ifdef _WIN32
#pragma once
#endif
#include "GameEventListener.h"
#include <igamesystem.h>
class CEventLog : public CGameEventListener, public CBaseGameSystem
{
public:
CEventLog();
virtual ~CEventLog();
public: // IGameEventListener Interface
virtual void FireGameEvent( IGameEvent * event );
public: // CBaseGameSystem overrides
virtual bool Init();
virtual void Shutdown();
protected:
virtual bool PrintEvent( IGameEvent * event );
virtual bool PrintGameEvent( IGameEvent * event );
virtual bool PrintPlayerEvent( IGameEvent * event );
virtual bool PrintTeamEvent( IGameEvent * event );
virtual bool PrintOtherEvent( IGameEvent * event );
};
extern IGameSystem* GameLogSystem();
#endif // EVENTLOG_H
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//
//=============================================================================//
#if !defined EVENTLOG_H
#define EVENTLOG_H
#ifdef _WIN32
#pragma once
#endif
#include "GameEventListener.h"
#include <igamesystem.h>
class CEventLog : public CGameEventListener, public CBaseGameSystem
{
public:
CEventLog();
virtual ~CEventLog();
public: // IGameEventListener Interface
virtual void FireGameEvent( IGameEvent * event );
public: // CBaseGameSystem overrides
virtual bool Init();
virtual void Shutdown();
protected:
virtual bool PrintEvent( IGameEvent * event );
virtual bool PrintGameEvent( IGameEvent * event );
virtual bool PrintPlayerEvent( IGameEvent * event );
virtual bool PrintTeamEvent( IGameEvent * event );
virtual bool PrintOtherEvent( IGameEvent * event );
};
extern IGameSystem* GameLogSystem();
#endif // EVENTLOG_H

File diff suppressed because it is too large Load Diff

View File

@@ -1,183 +1,183 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================
#include "cbase.h"
#include "gamestats.h"
void BasicGameStatsRecord_t::Clear()
{
m_nCount = 0;
m_nSeconds = 0;
m_nCommentary = 0;
m_nHDR = 0;
m_nCaptions = 0;
m_bSteam = true;
m_bCyberCafe = false;
Q_memset( m_nSkill, 0, sizeof( m_nSkill ) );
m_nDeaths = 0;
}
void BasicGameStatsRecord_t::SaveToBuffer( CUtlBuffer &buf )
{
buf.PutInt( m_nCount );
buf.PutInt( m_nSeconds );
buf.PutInt( m_nCommentary );
buf.PutInt( m_nHDR );
buf.PutInt( m_nCaptions );
for ( int i = 0; i < 3; ++i )
{
buf.PutInt( m_nSkill[ i ] );
}
buf.PutChar( m_bSteam ? 1 : 0 );
buf.PutChar( m_bCyberCafe ? 1 : 0 );
buf.PutInt( m_nDeaths );
}
bool BasicGameStatsRecord_t::ParseFromBuffer( CUtlBuffer &buf, int iBufferStatsVersion )
{
bool bret = true;
m_nCount = buf.GetInt();
if ( m_nCount > 100000 || m_nCount < 0 )
{
bret = false;
}
m_nSeconds = buf.GetInt();
// Note, don't put the buf.GetInt() in the macro since it'll get evaluated twice!!!
m_nSeconds = MAX( m_nSeconds, 0 );
m_nCommentary = buf.GetInt();
if ( m_nCommentary < 0 || m_nCommentary > 100000 )
{
bret = false;
}
m_nHDR = buf.GetInt();
if ( m_nHDR < 0 || m_nHDR > 100000 )
{
bret = false;
}
m_nCaptions = buf.GetInt();
if ( m_nCaptions < 0 || m_nCaptions > 100000 )
{
bret = false;
}
for ( int i = 0; i < 3; ++i )
{
m_nSkill[ i ] = buf.GetInt();
if ( m_nSkill[ i ] < 0 || m_nSkill[ i ] > 100000 )
{
bret = false;
}
}
if ( iBufferStatsVersion > GAMESTATS_FILE_VERSION_OLD )
{
m_bSteam = buf.GetChar() ? true : false;
}
if ( iBufferStatsVersion > GAMESTATS_FILE_VERSION_OLD2 )
{
m_bCyberCafe = buf.GetChar() ? true : false;
}
if ( iBufferStatsVersion > GAMESTATS_FILE_VERSION_OLD5 )
{
m_nDeaths = buf.GetInt();
}
return bret;
}
void BasicGameStats_t::Clear()
{
m_nSecondsToCompleteGame = 0;
m_Summary.Clear();
m_MapTotals.Purge();
}
void BasicGameStats_t::SaveToBuffer( CUtlBuffer& buf )
{
buf.PutInt( m_nSecondsToCompleteGame );
m_Summary.SaveToBuffer( buf );
int c = m_MapTotals.Count();
buf.PutInt( c );
for ( int i = m_MapTotals.First(); i != m_MapTotals.InvalidIndex(); i = m_MapTotals.Next( i ) )
{
char const *name = m_MapTotals.GetElementName( i );
BasicGameStatsRecord_t &rec = m_MapTotals[ i ];
buf.PutString( name );
rec.SaveToBuffer( buf );
}
buf.PutChar( (char)m_nHL2ChaptureUnlocked );
buf.PutChar( m_bSteam ? 1 : 0 );
buf.PutChar( m_bCyberCafe ? 1 : 0 );
buf.PutShort( (short)m_nDXLevel );
}
BasicGameStatsRecord_t *BasicGameStats_t::FindOrAddRecordForMap( char const *mapname )
{
int idx = m_MapTotals.Find( mapname );
if ( idx == m_MapTotals.InvalidIndex() )
{
idx = m_MapTotals.Insert( mapname );
}
return &m_MapTotals[ idx ];
}
bool BasicGameStats_t::ParseFromBuffer( CUtlBuffer& buf, int iBufferStatsVersion )
{
bool bret = true;
m_nSecondsToCompleteGame = buf.GetInt();
if ( m_nSecondsToCompleteGame < 0 || m_nSecondsToCompleteGame > 10000000 )
{
bret = false;
}
m_Summary.ParseFromBuffer( buf, iBufferStatsVersion );
int c = buf.GetInt();
if ( c > 1024 || c < 0 )
{
bret = false;
}
for ( int i = 0; i < c; ++i )
{
char mapname[ 256 ];
buf.GetString( mapname, sizeof( mapname ) );
BasicGameStatsRecord_t *rec = FindOrAddRecordForMap( mapname );
bool valid= rec->ParseFromBuffer( buf, iBufferStatsVersion );
if ( !valid )
{
bret = false;
}
}
if ( iBufferStatsVersion >= GAMESTATS_FILE_VERSION_OLD2 )
{
m_nHL2ChaptureUnlocked = (int)buf.GetChar();
m_bSteam = buf.GetChar() ? true : false;
}
if ( iBufferStatsVersion > GAMESTATS_FILE_VERSION_OLD2 )
{
m_bCyberCafe = buf.GetChar() ? true : false;
}
if ( iBufferStatsVersion > GAMESTATS_FILE_VERSION_OLD3 )
{
m_nDXLevel = (int)buf.GetShort();
}
return bret;
}
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================
#include "cbase.h"
#include "gamestats.h"
void BasicGameStatsRecord_t::Clear()
{
m_nCount = 0;
m_nSeconds = 0;
m_nCommentary = 0;
m_nHDR = 0;
m_nCaptions = 0;
m_bSteam = true;
m_bCyberCafe = false;
Q_memset( m_nSkill, 0, sizeof( m_nSkill ) );
m_nDeaths = 0;
}
void BasicGameStatsRecord_t::SaveToBuffer( CUtlBuffer &buf )
{
buf.PutInt( m_nCount );
buf.PutInt( m_nSeconds );
buf.PutInt( m_nCommentary );
buf.PutInt( m_nHDR );
buf.PutInt( m_nCaptions );
for ( int i = 0; i < 3; ++i )
{
buf.PutInt( m_nSkill[ i ] );
}
buf.PutChar( m_bSteam ? 1 : 0 );
buf.PutChar( m_bCyberCafe ? 1 : 0 );
buf.PutInt( m_nDeaths );
}
bool BasicGameStatsRecord_t::ParseFromBuffer( CUtlBuffer &buf, int iBufferStatsVersion )
{
bool bret = true;
m_nCount = buf.GetInt();
if ( m_nCount > 100000 || m_nCount < 0 )
{
bret = false;
}
m_nSeconds = buf.GetInt();
// Note, don't put the buf.GetInt() in the macro since it'll get evaluated twice!!!
m_nSeconds = MAX( m_nSeconds, 0 );
m_nCommentary = buf.GetInt();
if ( m_nCommentary < 0 || m_nCommentary > 100000 )
{
bret = false;
}
m_nHDR = buf.GetInt();
if ( m_nHDR < 0 || m_nHDR > 100000 )
{
bret = false;
}
m_nCaptions = buf.GetInt();
if ( m_nCaptions < 0 || m_nCaptions > 100000 )
{
bret = false;
}
for ( int i = 0; i < 3; ++i )
{
m_nSkill[ i ] = buf.GetInt();
if ( m_nSkill[ i ] < 0 || m_nSkill[ i ] > 100000 )
{
bret = false;
}
}
if ( iBufferStatsVersion > GAMESTATS_FILE_VERSION_OLD )
{
m_bSteam = buf.GetChar() ? true : false;
}
if ( iBufferStatsVersion > GAMESTATS_FILE_VERSION_OLD2 )
{
m_bCyberCafe = buf.GetChar() ? true : false;
}
if ( iBufferStatsVersion > GAMESTATS_FILE_VERSION_OLD5 )
{
m_nDeaths = buf.GetInt();
}
return bret;
}
void BasicGameStats_t::Clear()
{
m_nSecondsToCompleteGame = 0;
m_Summary.Clear();
m_MapTotals.Purge();
}
void BasicGameStats_t::SaveToBuffer( CUtlBuffer& buf )
{
buf.PutInt( m_nSecondsToCompleteGame );
m_Summary.SaveToBuffer( buf );
int c = m_MapTotals.Count();
buf.PutInt( c );
for ( int i = m_MapTotals.First(); i != m_MapTotals.InvalidIndex(); i = m_MapTotals.Next( i ) )
{
char const *name = m_MapTotals.GetElementName( i );
BasicGameStatsRecord_t &rec = m_MapTotals[ i ];
buf.PutString( name );
rec.SaveToBuffer( buf );
}
buf.PutChar( (char)m_nHL2ChaptureUnlocked );
buf.PutChar( m_bSteam ? 1 : 0 );
buf.PutChar( m_bCyberCafe ? 1 : 0 );
buf.PutShort( (short)m_nDXLevel );
}
BasicGameStatsRecord_t *BasicGameStats_t::FindOrAddRecordForMap( char const *mapname )
{
int idx = m_MapTotals.Find( mapname );
if ( idx == m_MapTotals.InvalidIndex() )
{
idx = m_MapTotals.Insert( mapname );
}
return &m_MapTotals[ idx ];
}
bool BasicGameStats_t::ParseFromBuffer( CUtlBuffer& buf, int iBufferStatsVersion )
{
bool bret = true;
m_nSecondsToCompleteGame = buf.GetInt();
if ( m_nSecondsToCompleteGame < 0 || m_nSecondsToCompleteGame > 10000000 )
{
bret = false;
}
m_Summary.ParseFromBuffer( buf, iBufferStatsVersion );
int c = buf.GetInt();
if ( c > 1024 || c < 0 )
{
bret = false;
}
for ( int i = 0; i < c; ++i )
{
char mapname[ 256 ];
buf.GetString( mapname, sizeof( mapname ) );
BasicGameStatsRecord_t *rec = FindOrAddRecordForMap( mapname );
bool valid= rec->ParseFromBuffer( buf, iBufferStatsVersion );
if ( !valid )
{
bret = false;
}
}
if ( iBufferStatsVersion >= GAMESTATS_FILE_VERSION_OLD2 )
{
m_nHL2ChaptureUnlocked = (int)buf.GetChar();
m_bSteam = buf.GetChar() ? true : false;
}
if ( iBufferStatsVersion > GAMESTATS_FILE_VERSION_OLD2 )
{
m_bCyberCafe = buf.GetChar() ? true : false;
}
if ( iBufferStatsVersion > GAMESTATS_FILE_VERSION_OLD3 )
{
m_nDXLevel = (int)buf.GetShort();
}
return bret;
}

View File

@@ -1,289 +1,289 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Material modify control entity.
//
//=============================================================================//
#include "cbase.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
//------------------------------------------------------------------------------
// FIXME: This really should inherit from something more lightweight.
//------------------------------------------------------------------------------
#define MATERIAL_MODIFY_STRING_SIZE 255
#define MATERIAL_MODIFY_ANIMATION_UNSET -1
// Must match C_MaterialModifyControl.cpp
enum MaterialModifyMode_t
{
MATERIAL_MODIFY_MODE_NONE = 0,
MATERIAL_MODIFY_MODE_SETVAR = 1,
MATERIAL_MODIFY_MODE_ANIM_SEQUENCE = 2,
MATERIAL_MODIFY_MODE_FLOAT_LERP = 3,
};
ConVar debug_materialmodifycontrol( "debug_materialmodifycontrol", "0" );
class CMaterialModifyControl : public CBaseEntity
{
public:
DECLARE_CLASS( CMaterialModifyControl, CBaseEntity );
CMaterialModifyControl();
void Spawn( void );
bool KeyValue( const char *szKeyName, const char *szValue );
int UpdateTransmitState();
int ShouldTransmit( const CCheckTransmitInfo *pInfo );
void SetMaterialVar( inputdata_t &inputdata );
void SetMaterialVarToCurrentTime( inputdata_t &inputdata );
void InputStartAnimSequence( inputdata_t &inputdata );
void InputStartFloatLerp( inputdata_t &inputdata );
virtual int ObjectCaps( void ) { return BaseClass::ObjectCaps() & ~FCAP_ACROSS_TRANSITION; }
DECLARE_SERVERCLASS();
DECLARE_DATADESC();
private:
CNetworkString( m_szMaterialName, MATERIAL_MODIFY_STRING_SIZE );
CNetworkString( m_szMaterialVar, MATERIAL_MODIFY_STRING_SIZE );
CNetworkString( m_szMaterialVarValue, MATERIAL_MODIFY_STRING_SIZE );
CNetworkVar( int, m_iFrameStart );
CNetworkVar( int, m_iFrameEnd );
CNetworkVar( bool, m_bWrap );
CNetworkVar( float, m_flFramerate );
CNetworkVar( bool, m_bNewAnimCommandsSemaphore );
CNetworkVar( float, m_flFloatLerpStartValue );
CNetworkVar( float, m_flFloatLerpEndValue );
CNetworkVar( float, m_flFloatLerpTransitionTime );
CNetworkVar( int, m_nModifyMode );
};
LINK_ENTITY_TO_CLASS(material_modify_control, CMaterialModifyControl);
BEGIN_DATADESC( CMaterialModifyControl )
// Variables.
DEFINE_AUTO_ARRAY( m_szMaterialName, FIELD_CHARACTER ),
DEFINE_AUTO_ARRAY( m_szMaterialVar, FIELD_CHARACTER ),
DEFINE_AUTO_ARRAY( m_szMaterialVarValue, FIELD_CHARACTER ),
DEFINE_FIELD( m_iFrameStart, FIELD_INTEGER ),
DEFINE_FIELD( m_iFrameEnd, FIELD_INTEGER ),
DEFINE_FIELD( m_bWrap, FIELD_BOOLEAN ),
DEFINE_FIELD( m_flFramerate, FIELD_FLOAT ),
DEFINE_FIELD( m_bNewAnimCommandsSemaphore, FIELD_BOOLEAN ),
DEFINE_FIELD( m_flFloatLerpStartValue, FIELD_FLOAT ),
DEFINE_FIELD( m_flFloatLerpEndValue, FIELD_FLOAT ),
DEFINE_FIELD( m_flFloatLerpTransitionTime, FIELD_FLOAT ),
DEFINE_FIELD( m_nModifyMode, FIELD_INTEGER ),
// Inputs.
DEFINE_INPUTFUNC( FIELD_STRING, "SetMaterialVar", SetMaterialVar ),
DEFINE_INPUTFUNC( FIELD_VOID, "SetMaterialVarToCurrentTime", SetMaterialVarToCurrentTime ),
DEFINE_INPUTFUNC( FIELD_STRING, "StartAnimSequence", InputStartAnimSequence ),
DEFINE_INPUTFUNC( FIELD_STRING, "StartFloatLerp", InputStartFloatLerp ),
END_DATADESC()
IMPLEMENT_SERVERCLASS_ST(CMaterialModifyControl, DT_MaterialModifyControl)
SendPropString( SENDINFO( m_szMaterialName ) ),
SendPropString( SENDINFO( m_szMaterialVar ) ),
SendPropString( SENDINFO( m_szMaterialVarValue ) ),
SendPropInt( SENDINFO(m_iFrameStart), 8 ),
SendPropInt( SENDINFO(m_iFrameEnd), 8 ),
SendPropInt( SENDINFO(m_bWrap), 1, SPROP_UNSIGNED ),
SendPropFloat( SENDINFO(m_flFramerate), 0, SPROP_NOSCALE ),
SendPropInt( SENDINFO(m_bNewAnimCommandsSemaphore), 1, SPROP_UNSIGNED ),
SendPropFloat( SENDINFO(m_flFloatLerpStartValue), 0, SPROP_NOSCALE ),
SendPropFloat( SENDINFO(m_flFloatLerpEndValue), 0, SPROP_NOSCALE ),
SendPropFloat( SENDINFO(m_flFloatLerpTransitionTime), 0, SPROP_NOSCALE ),
SendPropInt( SENDINFO(m_nModifyMode), 2, SPROP_UNSIGNED ),
END_SEND_TABLE()
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
CMaterialModifyControl::CMaterialModifyControl()
{
m_iFrameStart = MATERIAL_MODIFY_ANIMATION_UNSET;
m_iFrameEnd = MATERIAL_MODIFY_ANIMATION_UNSET;
m_nModifyMode = MATERIAL_MODIFY_MODE_NONE;
}
//------------------------------------------------------------------------------
// Purpose :
//------------------------------------------------------------------------------
void CMaterialModifyControl::Spawn( void )
{
Precache();
SetSolid( SOLID_NONE );
}
//------------------------------------------------------------------------------
// Purpose :
//------------------------------------------------------------------------------
bool CMaterialModifyControl::KeyValue( const char *szKeyName, const char *szValue )
{
if ( FStrEq( szKeyName, "materialName" ) )
{
Q_strncpy( m_szMaterialName.GetForModify(), szValue, MATERIAL_MODIFY_STRING_SIZE );
return true;
}
if ( FStrEq( szKeyName, "materialVar" ) )
{
Q_strncpy( m_szMaterialVar.GetForModify(), szValue, MATERIAL_MODIFY_STRING_SIZE );
return true;
}
return BaseClass::KeyValue( szKeyName, szValue );
}
//------------------------------------------------------------------------------
// Purpose : Send even though we don't have a model.
//------------------------------------------------------------------------------
int CMaterialModifyControl::UpdateTransmitState()
{
// ALWAYS transmit to all clients.
return SetTransmitState( FL_EDICT_FULLCHECK );
}
//-----------------------------------------------------------------------------
// Send if the parent is being sent:
//-----------------------------------------------------------------------------
int CMaterialModifyControl::ShouldTransmit( const CCheckTransmitInfo *pInfo )
{
CBaseEntity *pEnt = GetMoveParent();
if ( pEnt )
{
return pEnt->ShouldTransmit( pInfo );
}
return FL_EDICT_DONTSEND;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CMaterialModifyControl::SetMaterialVar( inputdata_t &inputdata )
{
//if( debug_materialmodifycontrol.GetBool() && Q_stristr( GetDebugName(), "alyx" ) )
//{
//DevMsg( 1, "CMaterialModifyControl::SetMaterialVar %s %s %s=\"%s\"\n",
//GetDebugName(), m_szMaterialName.Get(), m_szMaterialVar.Get(), inputdata.value.String() );
//}
Q_strncpy( m_szMaterialVarValue.GetForModify(), inputdata.value.String(), MATERIAL_MODIFY_STRING_SIZE );
m_nModifyMode = MATERIAL_MODIFY_MODE_SETVAR;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CMaterialModifyControl::SetMaterialVarToCurrentTime( inputdata_t &inputdata )
{
char temp[32];
Q_snprintf( temp, 32, "%f", gpGlobals->curtime );
Q_strncpy( m_szMaterialVarValue.GetForModify(), temp, MATERIAL_MODIFY_STRING_SIZE );
m_nModifyMode = MATERIAL_MODIFY_MODE_SETVAR;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CMaterialModifyControl::InputStartAnimSequence( inputdata_t &inputdata )
{
char parseString[255];
Q_strncpy(parseString, inputdata.value.String(), sizeof(parseString));
// Get the start & end frames
char *pszParam = strtok(parseString," ");
if ( pszParam && pszParam[0] )
{
int iFrameStart = atoi(pszParam);
pszParam = strtok(NULL," ");
if ( pszParam && pszParam[0] )
{
int iFrameEnd = atoi(pszParam);
pszParam = strtok(NULL," ");
if ( pszParam && pszParam[0] )
{
float flFramerate = atof(pszParam);
pszParam = strtok(NULL," ");
if ( pszParam && pszParam[0] )
{
bool bWrap = atoi(pszParam) != 0;
// Got all the parameters. Save 'em and return;
m_iFrameStart = iFrameStart;
m_iFrameEnd = iFrameEnd;
m_flFramerate = flFramerate;
m_bWrap = bWrap;
m_nModifyMode = MATERIAL_MODIFY_MODE_ANIM_SEQUENCE;
m_bNewAnimCommandsSemaphore = !m_bNewAnimCommandsSemaphore;
return;
}
}
}
}
Warning("%s (%s) received StartAnimSequence input without correct parameters. Syntax: <Frame Start> <Frame End> <Frame Rate> <Loop>\nSetting <Frame End> to -1 uses the last frame of the texture. <Loop> should be 1 or 0.\n", GetClassname(), GetDebugName() );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CMaterialModifyControl::InputStartFloatLerp( inputdata_t &inputdata )
{
char parseString[255];
Q_strncpy(parseString, inputdata.value.String(), sizeof(parseString));
// if( debug_materialmodifycontrol.GetBool() )//&& Q_stristr( GetDebugName(), "alyx" ) )
// {
// DevMsg( 1, "CMaterialModifyControl::InputStartFloatLerp %s %s %s \"%s\"\n",
// GetDebugName(), m_szMaterialName.Get(), m_szMaterialVar.Get(), inputdata.value.String() );
// }
// Get the start & end values
char *pszParam = strtok(parseString," ");
if ( pszParam && pszParam[0] )
{
float flStartValue = atof(pszParam);
pszParam = strtok(NULL," ");
if ( pszParam && pszParam[0] )
{
float flEndValue = atof(pszParam);
pszParam = strtok(NULL," ");
if ( pszParam && pszParam[0] )
{
float flTransitionTime = atof(pszParam);
pszParam = strtok(NULL," ");
if ( pszParam && pszParam[0] )
{
bool bWrap = atoi(pszParam) != 0;
// We don't implement wrap currently.
bWrap = bWrap;
// Got all the parameters. Save 'em and return;
m_flFloatLerpStartValue = flStartValue;
m_flFloatLerpEndValue = flEndValue;
m_flFloatLerpTransitionTime = flTransitionTime;
m_nModifyMode = MATERIAL_MODIFY_MODE_FLOAT_LERP;
m_bNewAnimCommandsSemaphore = !m_bNewAnimCommandsSemaphore;
return;
}
}
}
}
Warning("%s (%s) received StartFloatLerp input without correct parameters. Syntax: <Start Value> <End Value> <Transition Time> <Loop>\n<Loop> should be 1 or 0.\n", GetClassname(), GetDebugName() );
}
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Material modify control entity.
//
//=============================================================================//
#include "cbase.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
//------------------------------------------------------------------------------
// FIXME: This really should inherit from something more lightweight.
//------------------------------------------------------------------------------
#define MATERIAL_MODIFY_STRING_SIZE 255
#define MATERIAL_MODIFY_ANIMATION_UNSET -1
// Must match C_MaterialModifyControl.cpp
enum MaterialModifyMode_t
{
MATERIAL_MODIFY_MODE_NONE = 0,
MATERIAL_MODIFY_MODE_SETVAR = 1,
MATERIAL_MODIFY_MODE_ANIM_SEQUENCE = 2,
MATERIAL_MODIFY_MODE_FLOAT_LERP = 3,
};
ConVar debug_materialmodifycontrol( "debug_materialmodifycontrol", "0" );
class CMaterialModifyControl : public CBaseEntity
{
public:
DECLARE_CLASS( CMaterialModifyControl, CBaseEntity );
CMaterialModifyControl();
void Spawn( void );
bool KeyValue( const char *szKeyName, const char *szValue );
int UpdateTransmitState();
int ShouldTransmit( const CCheckTransmitInfo *pInfo );
void SetMaterialVar( inputdata_t &inputdata );
void SetMaterialVarToCurrentTime( inputdata_t &inputdata );
void InputStartAnimSequence( inputdata_t &inputdata );
void InputStartFloatLerp( inputdata_t &inputdata );
virtual int ObjectCaps( void ) { return BaseClass::ObjectCaps() & ~FCAP_ACROSS_TRANSITION; }
DECLARE_SERVERCLASS();
DECLARE_DATADESC();
private:
CNetworkString( m_szMaterialName, MATERIAL_MODIFY_STRING_SIZE );
CNetworkString( m_szMaterialVar, MATERIAL_MODIFY_STRING_SIZE );
CNetworkString( m_szMaterialVarValue, MATERIAL_MODIFY_STRING_SIZE );
CNetworkVar( int, m_iFrameStart );
CNetworkVar( int, m_iFrameEnd );
CNetworkVar( bool, m_bWrap );
CNetworkVar( float, m_flFramerate );
CNetworkVar( bool, m_bNewAnimCommandsSemaphore );
CNetworkVar( float, m_flFloatLerpStartValue );
CNetworkVar( float, m_flFloatLerpEndValue );
CNetworkVar( float, m_flFloatLerpTransitionTime );
CNetworkVar( int, m_nModifyMode );
};
LINK_ENTITY_TO_CLASS(material_modify_control, CMaterialModifyControl);
BEGIN_DATADESC( CMaterialModifyControl )
// Variables.
DEFINE_AUTO_ARRAY( m_szMaterialName, FIELD_CHARACTER ),
DEFINE_AUTO_ARRAY( m_szMaterialVar, FIELD_CHARACTER ),
DEFINE_AUTO_ARRAY( m_szMaterialVarValue, FIELD_CHARACTER ),
DEFINE_FIELD( m_iFrameStart, FIELD_INTEGER ),
DEFINE_FIELD( m_iFrameEnd, FIELD_INTEGER ),
DEFINE_FIELD( m_bWrap, FIELD_BOOLEAN ),
DEFINE_FIELD( m_flFramerate, FIELD_FLOAT ),
DEFINE_FIELD( m_bNewAnimCommandsSemaphore, FIELD_BOOLEAN ),
DEFINE_FIELD( m_flFloatLerpStartValue, FIELD_FLOAT ),
DEFINE_FIELD( m_flFloatLerpEndValue, FIELD_FLOAT ),
DEFINE_FIELD( m_flFloatLerpTransitionTime, FIELD_FLOAT ),
DEFINE_FIELD( m_nModifyMode, FIELD_INTEGER ),
// Inputs.
DEFINE_INPUTFUNC( FIELD_STRING, "SetMaterialVar", SetMaterialVar ),
DEFINE_INPUTFUNC( FIELD_VOID, "SetMaterialVarToCurrentTime", SetMaterialVarToCurrentTime ),
DEFINE_INPUTFUNC( FIELD_STRING, "StartAnimSequence", InputStartAnimSequence ),
DEFINE_INPUTFUNC( FIELD_STRING, "StartFloatLerp", InputStartFloatLerp ),
END_DATADESC()
IMPLEMENT_SERVERCLASS_ST(CMaterialModifyControl, DT_MaterialModifyControl)
SendPropString( SENDINFO( m_szMaterialName ) ),
SendPropString( SENDINFO( m_szMaterialVar ) ),
SendPropString( SENDINFO( m_szMaterialVarValue ) ),
SendPropInt( SENDINFO(m_iFrameStart), 8 ),
SendPropInt( SENDINFO(m_iFrameEnd), 8 ),
SendPropInt( SENDINFO(m_bWrap), 1, SPROP_UNSIGNED ),
SendPropFloat( SENDINFO(m_flFramerate), 0, SPROP_NOSCALE ),
SendPropInt( SENDINFO(m_bNewAnimCommandsSemaphore), 1, SPROP_UNSIGNED ),
SendPropFloat( SENDINFO(m_flFloatLerpStartValue), 0, SPROP_NOSCALE ),
SendPropFloat( SENDINFO(m_flFloatLerpEndValue), 0, SPROP_NOSCALE ),
SendPropFloat( SENDINFO(m_flFloatLerpTransitionTime), 0, SPROP_NOSCALE ),
SendPropInt( SENDINFO(m_nModifyMode), 2, SPROP_UNSIGNED ),
END_SEND_TABLE()
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
CMaterialModifyControl::CMaterialModifyControl()
{
m_iFrameStart = MATERIAL_MODIFY_ANIMATION_UNSET;
m_iFrameEnd = MATERIAL_MODIFY_ANIMATION_UNSET;
m_nModifyMode = MATERIAL_MODIFY_MODE_NONE;
}
//------------------------------------------------------------------------------
// Purpose :
//------------------------------------------------------------------------------
void CMaterialModifyControl::Spawn( void )
{
Precache();
SetSolid( SOLID_NONE );
}
//------------------------------------------------------------------------------
// Purpose :
//------------------------------------------------------------------------------
bool CMaterialModifyControl::KeyValue( const char *szKeyName, const char *szValue )
{
if ( FStrEq( szKeyName, "materialName" ) )
{
Q_strncpy( m_szMaterialName.GetForModify(), szValue, MATERIAL_MODIFY_STRING_SIZE );
return true;
}
if ( FStrEq( szKeyName, "materialVar" ) )
{
Q_strncpy( m_szMaterialVar.GetForModify(), szValue, MATERIAL_MODIFY_STRING_SIZE );
return true;
}
return BaseClass::KeyValue( szKeyName, szValue );
}
//------------------------------------------------------------------------------
// Purpose : Send even though we don't have a model.
//------------------------------------------------------------------------------
int CMaterialModifyControl::UpdateTransmitState()
{
// ALWAYS transmit to all clients.
return SetTransmitState( FL_EDICT_FULLCHECK );
}
//-----------------------------------------------------------------------------
// Send if the parent is being sent:
//-----------------------------------------------------------------------------
int CMaterialModifyControl::ShouldTransmit( const CCheckTransmitInfo *pInfo )
{
CBaseEntity *pEnt = GetMoveParent();
if ( pEnt )
{
return pEnt->ShouldTransmit( pInfo );
}
return FL_EDICT_DONTSEND;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CMaterialModifyControl::SetMaterialVar( inputdata_t &inputdata )
{
//if( debug_materialmodifycontrol.GetBool() && Q_stristr( GetDebugName(), "alyx" ) )
//{
//DevMsg( 1, "CMaterialModifyControl::SetMaterialVar %s %s %s=\"%s\"\n",
//GetDebugName(), m_szMaterialName.Get(), m_szMaterialVar.Get(), inputdata.value.String() );
//}
Q_strncpy( m_szMaterialVarValue.GetForModify(), inputdata.value.String(), MATERIAL_MODIFY_STRING_SIZE );
m_nModifyMode = MATERIAL_MODIFY_MODE_SETVAR;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CMaterialModifyControl::SetMaterialVarToCurrentTime( inputdata_t &inputdata )
{
char temp[32];
Q_snprintf( temp, 32, "%f", gpGlobals->curtime );
Q_strncpy( m_szMaterialVarValue.GetForModify(), temp, MATERIAL_MODIFY_STRING_SIZE );
m_nModifyMode = MATERIAL_MODIFY_MODE_SETVAR;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CMaterialModifyControl::InputStartAnimSequence( inputdata_t &inputdata )
{
char parseString[255];
Q_strncpy(parseString, inputdata.value.String(), sizeof(parseString));
// Get the start & end frames
char *pszParam = strtok(parseString," ");
if ( pszParam && pszParam[0] )
{
int iFrameStart = atoi(pszParam);
pszParam = strtok(NULL," ");
if ( pszParam && pszParam[0] )
{
int iFrameEnd = atoi(pszParam);
pszParam = strtok(NULL," ");
if ( pszParam && pszParam[0] )
{
float flFramerate = atof(pszParam);
pszParam = strtok(NULL," ");
if ( pszParam && pszParam[0] )
{
bool bWrap = atoi(pszParam) != 0;
// Got all the parameters. Save 'em and return;
m_iFrameStart = iFrameStart;
m_iFrameEnd = iFrameEnd;
m_flFramerate = flFramerate;
m_bWrap = bWrap;
m_nModifyMode = MATERIAL_MODIFY_MODE_ANIM_SEQUENCE;
m_bNewAnimCommandsSemaphore = !m_bNewAnimCommandsSemaphore;
return;
}
}
}
}
Warning("%s (%s) received StartAnimSequence input without correct parameters. Syntax: <Frame Start> <Frame End> <Frame Rate> <Loop>\nSetting <Frame End> to -1 uses the last frame of the texture. <Loop> should be 1 or 0.\n", GetClassname(), GetDebugName() );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CMaterialModifyControl::InputStartFloatLerp( inputdata_t &inputdata )
{
char parseString[255];
Q_strncpy(parseString, inputdata.value.String(), sizeof(parseString));
// if( debug_materialmodifycontrol.GetBool() )//&& Q_stristr( GetDebugName(), "alyx" ) )
// {
// DevMsg( 1, "CMaterialModifyControl::InputStartFloatLerp %s %s %s \"%s\"\n",
// GetDebugName(), m_szMaterialName.Get(), m_szMaterialVar.Get(), inputdata.value.String() );
// }
// Get the start & end values
char *pszParam = strtok(parseString," ");
if ( pszParam && pszParam[0] )
{
float flStartValue = atof(pszParam);
pszParam = strtok(NULL," ");
if ( pszParam && pszParam[0] )
{
float flEndValue = atof(pszParam);
pszParam = strtok(NULL," ");
if ( pszParam && pszParam[0] )
{
float flTransitionTime = atof(pszParam);
pszParam = strtok(NULL," ");
if ( pszParam && pszParam[0] )
{
bool bWrap = atoi(pszParam) != 0;
// We don't implement wrap currently.
bWrap = bWrap;
// Got all the parameters. Save 'em and return;
m_flFloatLerpStartValue = flStartValue;
m_flFloatLerpEndValue = flEndValue;
m_flFloatLerpTransitionTime = flTransitionTime;
m_nModifyMode = MATERIAL_MODIFY_MODE_FLOAT_LERP;
m_bNewAnimCommandsSemaphore = !m_bNewAnimCommandsSemaphore;
return;
}
}
}
}
Warning("%s (%s) received StartFloatLerp input without correct parameters. Syntax: <Start Value> <End Value> <Transition Time> <Loop>\n<Loop> should be 1 or 0.\n", GetClassname(), GetDebugName() );
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,268 +1,268 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Dissolve entity to be attached to target entity. Serves two purposes:
//
// 1) An entity that can be placed by a level designer and triggered
// to ignite a target entity.
//
// 2) An entity that can be created at runtime to ignite a target entity.
//
//=============================================================================//
#include "cbase.h"
#include "RagdollBoogie.h"
#include "physics_prop_ragdoll.h"
#include "effect_dispatch_data.h"
#include "te_effect_dispatch.h"
#include "IEffects.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
//-----------------------------------------------------------------------------
// Make electriciy every so often
//-----------------------------------------------------------------------------
static const char *s_pZapContext = "ZapContext";
//-----------------------------------------------------------------------------
// Save/load
//-----------------------------------------------------------------------------
BEGIN_DATADESC( CRagdollBoogie )
DEFINE_FIELD( m_flStartTime, FIELD_TIME ),
DEFINE_FIELD( m_flBoogieLength, FIELD_FLOAT ),
DEFINE_FIELD( m_flMagnitude, FIELD_FLOAT ),
// Think this should be handled by StartTouch/etc.
// DEFINE_FIELD( m_nSuppressionCount, FIELD_INTEGER ),
DEFINE_FUNCTION( BoogieThink ),
DEFINE_FUNCTION( ZapThink ),
END_DATADESC()
LINK_ENTITY_TO_CLASS( env_ragdoll_boogie, CRagdollBoogie );
//-----------------------------------------------------------------------------
// Purpose: Creates a flame and attaches it to a target entity.
// Input : pTarget -
//-----------------------------------------------------------------------------
CRagdollBoogie *CRagdollBoogie::Create( CBaseEntity *pTarget, float flMagnitude,
float flStartTime, float flLengthTime, int nSpawnFlags )
{
CRagdollProp *pRagdoll = dynamic_cast< CRagdollProp* >( pTarget );
if ( !pRagdoll )
return NULL;
CRagdollBoogie *pBoogie = (CRagdollBoogie *)CreateEntityByName( "env_ragdoll_boogie" );
if ( pBoogie == NULL )
return NULL;
pBoogie->AddSpawnFlags( nSpawnFlags );
pBoogie->AttachToEntity( pTarget );
pBoogie->SetBoogieTime( flStartTime, flLengthTime );
pBoogie->SetMagnitude( flMagnitude );
pBoogie->Spawn();
return pBoogie;
}
//-----------------------------------------------------------------------------
// Spawn
//-----------------------------------------------------------------------------
void CRagdollBoogie::Spawn()
{
BaseClass::Spawn();
SetThink( &CRagdollBoogie::BoogieThink );
SetNextThink( gpGlobals->curtime + 0.01f );
if ( HasSpawnFlags( SF_RAGDOLL_BOOGIE_ELECTRICAL ) )
{
SetContextThink( &CRagdollBoogie::ZapThink, gpGlobals->curtime + random->RandomFloat( 0.1f, 0.3f ), s_pZapContext );
}
}
//-----------------------------------------------------------------------------
// Zap!
//-----------------------------------------------------------------------------
void CRagdollBoogie::ZapThink()
{
if ( !GetMoveParent() )
return;
CBaseAnimating *pRagdoll = GetMoveParent()->GetBaseAnimating();
if ( !pRagdoll )
return;
// Make electricity on the client
CStudioHdr *pStudioHdr = pRagdoll->GetModelPtr( );
if (!pStudioHdr)
return;
mstudiohitboxset_t *set = pStudioHdr->pHitboxSet( pRagdoll->GetHitboxSet() );
if ( set->numhitboxes == 0 )
return;
if ( m_nSuppressionCount == 0 )
{
CEffectData data;
data.m_nEntIndex = GetMoveParent()->entindex();
data.m_flMagnitude = 4;
data.m_flScale = HasSpawnFlags(SF_RAGDOLL_BOOGIE_ELECTRICAL_NARROW_BEAM) ? 1.0f : 2.0f;
DispatchEffect( "TeslaHitboxes", data );
}
#ifdef HL2_EPISODIC
EmitSound( "RagdollBoogie.Zap" );
#endif
SetContextThink( &CRagdollBoogie::ZapThink, gpGlobals->curtime + random->RandomFloat( 0.1f, 0.3f ), s_pZapContext );
}
//-----------------------------------------------------------------------------
// Suppression count
//-----------------------------------------------------------------------------
void CRagdollBoogie::IncrementSuppressionCount( CBaseEntity *pTarget )
{
// Look for other boogies on the ragdoll + kill them
for ( CBaseEntity *pChild = pTarget->FirstMoveChild(); pChild; pChild = pChild->NextMovePeer() )
{
CRagdollBoogie *pBoogie = dynamic_cast<CRagdollBoogie*>(pChild);
if ( !pBoogie )
continue;
++pBoogie->m_nSuppressionCount;
}
}
void CRagdollBoogie::DecrementSuppressionCount( CBaseEntity *pTarget )
{
// Look for other boogies on the ragdoll + kill them
CBaseEntity *pNext;
for ( CBaseEntity *pChild = pTarget->FirstMoveChild(); pChild; pChild = pNext )
{
pNext = pChild->NextMovePeer();
CRagdollBoogie *pBoogie = dynamic_cast<CRagdollBoogie*>(pChild);
if ( !pBoogie )
continue;
if ( --pBoogie->m_nSuppressionCount <= 0 )
{
pBoogie->m_nSuppressionCount = 0;
float dt = gpGlobals->curtime - pBoogie->m_flStartTime;
if ( dt >= pBoogie->m_flBoogieLength )
{
PhysCallbackRemove( pBoogie->NetworkProp() );
}
}
}
}
//-----------------------------------------------------------------------------
// Attach to an entity
//-----------------------------------------------------------------------------
void CRagdollBoogie::AttachToEntity( CBaseEntity *pTarget )
{
m_nSuppressionCount = 0;
// Look for other boogies on the ragdoll + kill them
CBaseEntity *pNext;
for ( CBaseEntity *pChild = pTarget->FirstMoveChild(); pChild; pChild = pNext )
{
pNext = pChild->NextMovePeer();
CRagdollBoogie *pBoogie = dynamic_cast<CRagdollBoogie*>(pChild);
if ( !pBoogie )
continue;
m_nSuppressionCount = pBoogie->m_nSuppressionCount;
UTIL_Remove( pChild );
}
FollowEntity( pTarget );
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : lifetime -
//-----------------------------------------------------------------------------
void CRagdollBoogie::SetBoogieTime( float flStartTime, float flLengthTime )
{
m_flStartTime = flStartTime;
m_flBoogieLength = flLengthTime;
}
//-----------------------------------------------------------------------------
// Purpose: Burn targets around us
//-----------------------------------------------------------------------------
void CRagdollBoogie::SetMagnitude( float flMagnitude )
{
m_flMagnitude = flMagnitude;
}
//-----------------------------------------------------------------------------
// Purpose: Burn targets around us
//-----------------------------------------------------------------------------
void CRagdollBoogie::BoogieThink( void )
{
CRagdollProp *pRagdoll = dynamic_cast< CRagdollProp* >( GetMoveParent() );
if ( !pRagdoll )
{
UTIL_Remove( this );
return;
}
float flMagnitude = m_flMagnitude;
if ( m_flBoogieLength != 0 )
{
float dt = gpGlobals->curtime - m_flStartTime;
if ( dt >= m_flBoogieLength )
{
// Don't remove while suppressed... this helps if we try to start another boogie
if ( m_nSuppressionCount == 0 )
{
UTIL_Remove( this );
}
SetThink( NULL );
return;
}
if ( dt < 0 )
{
SetNextThink( gpGlobals->curtime + random->RandomFloat( 0.1, 0.2f ) );
return;
}
flMagnitude = SimpleSplineRemapVal( dt, 0.0f, m_flBoogieLength, m_flMagnitude, 0.0f );
}
#ifndef _XBOX
if ( m_nSuppressionCount == 0 )
{
ragdoll_t *pRagdollPhys = pRagdoll->GetRagdoll( );
for ( int j = 0; j < pRagdollPhys->listCount; ++j )
{
float flMass = pRagdollPhys->list[j].pObject->GetMass();
float flForce = m_flMagnitude * flMass;
Vector vecForce;
vecForce = RandomVector( -flForce, flForce );
pRagdollPhys->list[j].pObject->ApplyForceCenter( vecForce );
}
}
#endif // !_XBOX
SetNextThink( gpGlobals->curtime + random->RandomFloat( 0.1, 0.2f ) );
}
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Dissolve entity to be attached to target entity. Serves two purposes:
//
// 1) An entity that can be placed by a level designer and triggered
// to ignite a target entity.
//
// 2) An entity that can be created at runtime to ignite a target entity.
//
//=============================================================================//
#include "cbase.h"
#include "RagdollBoogie.h"
#include "physics_prop_ragdoll.h"
#include "effect_dispatch_data.h"
#include "te_effect_dispatch.h"
#include "IEffects.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
//-----------------------------------------------------------------------------
// Make electriciy every so often
//-----------------------------------------------------------------------------
static const char *s_pZapContext = "ZapContext";
//-----------------------------------------------------------------------------
// Save/load
//-----------------------------------------------------------------------------
BEGIN_DATADESC( CRagdollBoogie )
DEFINE_FIELD( m_flStartTime, FIELD_TIME ),
DEFINE_FIELD( m_flBoogieLength, FIELD_FLOAT ),
DEFINE_FIELD( m_flMagnitude, FIELD_FLOAT ),
// Think this should be handled by StartTouch/etc.
// DEFINE_FIELD( m_nSuppressionCount, FIELD_INTEGER ),
DEFINE_FUNCTION( BoogieThink ),
DEFINE_FUNCTION( ZapThink ),
END_DATADESC()
LINK_ENTITY_TO_CLASS( env_ragdoll_boogie, CRagdollBoogie );
//-----------------------------------------------------------------------------
// Purpose: Creates a flame and attaches it to a target entity.
// Input : pTarget -
//-----------------------------------------------------------------------------
CRagdollBoogie *CRagdollBoogie::Create( CBaseEntity *pTarget, float flMagnitude,
float flStartTime, float flLengthTime, int nSpawnFlags )
{
CRagdollProp *pRagdoll = dynamic_cast< CRagdollProp* >( pTarget );
if ( !pRagdoll )
return NULL;
CRagdollBoogie *pBoogie = (CRagdollBoogie *)CreateEntityByName( "env_ragdoll_boogie" );
if ( pBoogie == NULL )
return NULL;
pBoogie->AddSpawnFlags( nSpawnFlags );
pBoogie->AttachToEntity( pTarget );
pBoogie->SetBoogieTime( flStartTime, flLengthTime );
pBoogie->SetMagnitude( flMagnitude );
pBoogie->Spawn();
return pBoogie;
}
//-----------------------------------------------------------------------------
// Spawn
//-----------------------------------------------------------------------------
void CRagdollBoogie::Spawn()
{
BaseClass::Spawn();
SetThink( &CRagdollBoogie::BoogieThink );
SetNextThink( gpGlobals->curtime + 0.01f );
if ( HasSpawnFlags( SF_RAGDOLL_BOOGIE_ELECTRICAL ) )
{
SetContextThink( &CRagdollBoogie::ZapThink, gpGlobals->curtime + random->RandomFloat( 0.1f, 0.3f ), s_pZapContext );
}
}
//-----------------------------------------------------------------------------
// Zap!
//-----------------------------------------------------------------------------
void CRagdollBoogie::ZapThink()
{
if ( !GetMoveParent() )
return;
CBaseAnimating *pRagdoll = GetMoveParent()->GetBaseAnimating();
if ( !pRagdoll )
return;
// Make electricity on the client
CStudioHdr *pStudioHdr = pRagdoll->GetModelPtr( );
if (!pStudioHdr)
return;
mstudiohitboxset_t *set = pStudioHdr->pHitboxSet( pRagdoll->GetHitboxSet() );
if ( set->numhitboxes == 0 )
return;
if ( m_nSuppressionCount == 0 )
{
CEffectData data;
data.m_nEntIndex = GetMoveParent()->entindex();
data.m_flMagnitude = 4;
data.m_flScale = HasSpawnFlags(SF_RAGDOLL_BOOGIE_ELECTRICAL_NARROW_BEAM) ? 1.0f : 2.0f;
DispatchEffect( "TeslaHitboxes", data );
}
#ifdef HL2_EPISODIC
EmitSound( "RagdollBoogie.Zap" );
#endif
SetContextThink( &CRagdollBoogie::ZapThink, gpGlobals->curtime + random->RandomFloat( 0.1f, 0.3f ), s_pZapContext );
}
//-----------------------------------------------------------------------------
// Suppression count
//-----------------------------------------------------------------------------
void CRagdollBoogie::IncrementSuppressionCount( CBaseEntity *pTarget )
{
// Look for other boogies on the ragdoll + kill them
for ( CBaseEntity *pChild = pTarget->FirstMoveChild(); pChild; pChild = pChild->NextMovePeer() )
{
CRagdollBoogie *pBoogie = dynamic_cast<CRagdollBoogie*>(pChild);
if ( !pBoogie )
continue;
++pBoogie->m_nSuppressionCount;
}
}
void CRagdollBoogie::DecrementSuppressionCount( CBaseEntity *pTarget )
{
// Look for other boogies on the ragdoll + kill them
CBaseEntity *pNext;
for ( CBaseEntity *pChild = pTarget->FirstMoveChild(); pChild; pChild = pNext )
{
pNext = pChild->NextMovePeer();
CRagdollBoogie *pBoogie = dynamic_cast<CRagdollBoogie*>(pChild);
if ( !pBoogie )
continue;
if ( --pBoogie->m_nSuppressionCount <= 0 )
{
pBoogie->m_nSuppressionCount = 0;
float dt = gpGlobals->curtime - pBoogie->m_flStartTime;
if ( dt >= pBoogie->m_flBoogieLength )
{
PhysCallbackRemove( pBoogie->NetworkProp() );
}
}
}
}
//-----------------------------------------------------------------------------
// Attach to an entity
//-----------------------------------------------------------------------------
void CRagdollBoogie::AttachToEntity( CBaseEntity *pTarget )
{
m_nSuppressionCount = 0;
// Look for other boogies on the ragdoll + kill them
CBaseEntity *pNext;
for ( CBaseEntity *pChild = pTarget->FirstMoveChild(); pChild; pChild = pNext )
{
pNext = pChild->NextMovePeer();
CRagdollBoogie *pBoogie = dynamic_cast<CRagdollBoogie*>(pChild);
if ( !pBoogie )
continue;
m_nSuppressionCount = pBoogie->m_nSuppressionCount;
UTIL_Remove( pChild );
}
FollowEntity( pTarget );
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : lifetime -
//-----------------------------------------------------------------------------
void CRagdollBoogie::SetBoogieTime( float flStartTime, float flLengthTime )
{
m_flStartTime = flStartTime;
m_flBoogieLength = flLengthTime;
}
//-----------------------------------------------------------------------------
// Purpose: Burn targets around us
//-----------------------------------------------------------------------------
void CRagdollBoogie::SetMagnitude( float flMagnitude )
{
m_flMagnitude = flMagnitude;
}
//-----------------------------------------------------------------------------
// Purpose: Burn targets around us
//-----------------------------------------------------------------------------
void CRagdollBoogie::BoogieThink( void )
{
CRagdollProp *pRagdoll = dynamic_cast< CRagdollProp* >( GetMoveParent() );
if ( !pRagdoll )
{
UTIL_Remove( this );
return;
}
float flMagnitude = m_flMagnitude;
if ( m_flBoogieLength != 0 )
{
float dt = gpGlobals->curtime - m_flStartTime;
if ( dt >= m_flBoogieLength )
{
// Don't remove while suppressed... this helps if we try to start another boogie
if ( m_nSuppressionCount == 0 )
{
UTIL_Remove( this );
}
SetThink( NULL );
return;
}
if ( dt < 0 )
{
SetNextThink( gpGlobals->curtime + random->RandomFloat( 0.1, 0.2f ) );
return;
}
flMagnitude = SimpleSplineRemapVal( dt, 0.0f, m_flBoogieLength, m_flMagnitude, 0.0f );
}
#ifndef _XBOX
if ( m_nSuppressionCount == 0 )
{
ragdoll_t *pRagdollPhys = pRagdoll->GetRagdoll( );
for ( int j = 0; j < pRagdollPhys->listCount; ++j )
{
float flMass = pRagdollPhys->list[j].pObject->GetMass();
float flForce = m_flMagnitude * flMass;
Vector vecForce;
vecForce = RandomVector( -flForce, flForce );
pRagdollPhys->list[j].pObject->ApplyForceCenter( vecForce );
}
}
#endif // !_XBOX
SetNextThink( gpGlobals->curtime + random->RandomFloat( 0.1, 0.2f ) );
}

View File

@@ -1,50 +1,50 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#ifndef RAGDOLLBOOGIE_H
#define RAGDOLLBOOGIE_H
#ifdef _WIN32
#pragma once
#endif
//-----------------------------------------------------------------------------
// Set this spawnflag before calling Spawn to get electrical effects
//-----------------------------------------------------------------------------
#define SF_RAGDOLL_BOOGIE_ELECTRICAL 0x10000
#define SF_RAGDOLL_BOOGIE_ELECTRICAL_NARROW_BEAM 0x20000
//-----------------------------------------------------------------------------
// Makes ragdolls DANCE!
//-----------------------------------------------------------------------------
class CRagdollBoogie : public CBaseEntity
{
DECLARE_DATADESC();
DECLARE_CLASS( CRagdollBoogie, CBaseEntity );
public:
static CRagdollBoogie *Create( CBaseEntity *pTarget, float flMagnitude, float flStartTime, float flLengthTime = 0.0f, int nSpawnFlags = 0 );
static void IncrementSuppressionCount( CBaseEntity *pTarget );
static void DecrementSuppressionCount( CBaseEntity *pTarget );
void Spawn();
private:
void AttachToEntity( CBaseEntity *pTarget );
void SetBoogieTime( float flStartTime, float flLengthTime );
void SetMagnitude( float flMagnitude );
void BoogieThink( void );
void ZapThink();
float m_flStartTime;
float m_flBoogieLength;
float m_flMagnitude;
int m_nSuppressionCount;
};
#endif // RAGDOLLBOOGIE_H
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#ifndef RAGDOLLBOOGIE_H
#define RAGDOLLBOOGIE_H
#ifdef _WIN32
#pragma once
#endif
//-----------------------------------------------------------------------------
// Set this spawnflag before calling Spawn to get electrical effects
//-----------------------------------------------------------------------------
#define SF_RAGDOLL_BOOGIE_ELECTRICAL 0x10000
#define SF_RAGDOLL_BOOGIE_ELECTRICAL_NARROW_BEAM 0x20000
//-----------------------------------------------------------------------------
// Makes ragdolls DANCE!
//-----------------------------------------------------------------------------
class CRagdollBoogie : public CBaseEntity
{
DECLARE_DATADESC();
DECLARE_CLASS( CRagdollBoogie, CBaseEntity );
public:
static CRagdollBoogie *Create( CBaseEntity *pTarget, float flMagnitude, float flStartTime, float flLengthTime = 0.0f, int nSpawnFlags = 0 );
static void IncrementSuppressionCount( CBaseEntity *pTarget );
static void DecrementSuppressionCount( CBaseEntity *pTarget );
void Spawn();
private:
void AttachToEntity( CBaseEntity *pTarget );
void SetBoogieTime( float flStartTime, float flLengthTime );
void SetMagnitude( float flMagnitude );
void BoogieThink( void );
void ZapThink();
float m_flStartTime;
float m_flBoogieLength;
float m_flMagnitude;
int m_nSuppressionCount;
};
#endif // RAGDOLLBOOGIE_H

View File

@@ -1,305 +1,305 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//===========================================================================//
#include "cbase.h"
#include "ServerNetworkProperty.h"
#include "tier0/dbg.h"
#include "gameinterface.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
extern CTimedEventMgr g_NetworkPropertyEventMgr;
//-----------------------------------------------------------------------------
// Save/load
//-----------------------------------------------------------------------------
BEGIN_DATADESC_NO_BASE( CServerNetworkProperty )
// DEFINE_FIELD( m_pOuter, FIELD_CLASSPTR ),
// DEFINE_FIELD( m_pPev, FIELD_CLASSPTR ),
// DEFINE_FIELD( m_PVSInfo, PVSInfo_t ),
// DEFINE_FIELD( m_pServerClass, FIELD_CLASSPTR ),
DEFINE_GLOBAL_FIELD( m_hParent, FIELD_EHANDLE ),
// DEFINE_FIELD( m_TimerEvent, CEventRegister ),
// DEFINE_FIELD( m_bPendingStateChange, FIELD_BOOLEAN ),
END_DATADESC()
//-----------------------------------------------------------------------------
// Constructor, destructor
//-----------------------------------------------------------------------------
CServerNetworkProperty::CServerNetworkProperty()
{
Init( NULL );
}
CServerNetworkProperty::~CServerNetworkProperty()
{
/* Free our transmit proxy.
if ( m_pTransmitProxy )
{
m_pTransmitProxy->Release();
}*/
engine->CleanUpEntityClusterList( &m_PVSInfo );
// remove the attached edict if it exists
DetachEdict();
}
//-----------------------------------------------------------------------------
// Initialization
//-----------------------------------------------------------------------------
void CServerNetworkProperty::Init( CBaseEntity *pEntity )
{
m_pPev = NULL;
m_pOuter = pEntity;
m_pServerClass = NULL;
// m_pTransmitProxy = NULL;
m_bPendingStateChange = false;
m_PVSInfo.m_nClusterCount = 0;
m_TimerEvent.Init( &g_NetworkPropertyEventMgr, this );
}
//-----------------------------------------------------------------------------
// Connects, disconnects edicts
//-----------------------------------------------------------------------------
void CServerNetworkProperty::AttachEdict( edict_t *pRequiredEdict )
{
Assert ( !m_pPev );
// see if there is an edict allocated for it, otherwise get one from the engine
if ( !pRequiredEdict )
{
pRequiredEdict = engine->CreateEdict();
}
m_pPev = pRequiredEdict;
m_pPev->SetEdict( GetBaseEntity(), true );
}
void CServerNetworkProperty::DetachEdict()
{
if ( m_pPev )
{
m_pPev->SetEdict( NULL, false );
engine->RemoveEdict( m_pPev );
m_pPev = NULL;
}
}
//-----------------------------------------------------------------------------
// Entity handles
//-----------------------------------------------------------------------------
IHandleEntity *CServerNetworkProperty::GetEntityHandle( )
{
return m_pOuter;
}
void CServerNetworkProperty::Release()
{
delete m_pOuter;
}
//-----------------------------------------------------------------------------
// Returns the network parent
//-----------------------------------------------------------------------------
CServerNetworkProperty* CServerNetworkProperty::GetNetworkParent()
{
CBaseEntity *pParent = m_hParent.Get();
return pParent ? pParent->NetworkProp() : NULL;
}
//-----------------------------------------------------------------------------
// Marks for deletion
//-----------------------------------------------------------------------------
void CServerNetworkProperty::MarkForDeletion()
{
m_pOuter->AddEFlags( EFL_KILLME );
}
bool CServerNetworkProperty::IsMarkedForDeletion() const
{
return ( m_pOuter->GetEFlags() & EFL_KILLME ) != 0;
}
//-----------------------------------------------------------------------------
// PVS information
//-----------------------------------------------------------------------------
void CServerNetworkProperty::RecomputePVSInformation()
{
if ( m_pPev && ( ( m_pPev->m_fStateFlags & FL_EDICT_DIRTY_PVS_INFORMATION ) != 0 ) )
{
m_pPev->m_fStateFlags &= ~FL_EDICT_DIRTY_PVS_INFORMATION;
engine->BuildEntityClusterList( edict(), &m_PVSInfo );
}
}
//-----------------------------------------------------------------------------
// Serverclass
//-----------------------------------------------------------------------------
ServerClass* CServerNetworkProperty::GetServerClass()
{
if ( !m_pServerClass )
m_pServerClass = m_pOuter->GetServerClass();
return m_pServerClass;
}
const char* CServerNetworkProperty::GetClassName() const
{
return STRING(m_pOuter->m_iClassname);
}
//-----------------------------------------------------------------------------
// Transmit proxies
/*-----------------------------------------------------------------------------
void CServerNetworkProperty::SetTransmitProxy( CBaseTransmitProxy *pProxy )
{
if ( m_pTransmitProxy )
{
m_pTransmitProxy->Release();
}
m_pTransmitProxy = pProxy;
if ( m_pTransmitProxy )
{
m_pTransmitProxy->AddRef();
}
}*/
//-----------------------------------------------------------------------------
// PVS rules
//-----------------------------------------------------------------------------
bool CServerNetworkProperty::IsInPVS( const edict_t *pRecipient, const void *pvs, int pvssize )
{
RecomputePVSInformation();
// ignore if not touching a PV leaf
// negative leaf count is a node number
// If no pvs, add any entity
Assert( pvs && ( edict() != pRecipient ) );
unsigned char *pPVS = ( unsigned char * )pvs;
if ( m_PVSInfo.m_nClusterCount < 0 ) // too many clusters, use headnode
{
return ( engine->CheckHeadnodeVisible( m_PVSInfo.m_nHeadNode, pPVS, pvssize ) != 0);
}
for ( int i = m_PVSInfo.m_nClusterCount; --i >= 0; )
{
if (pPVS[m_PVSInfo.m_pClusters[i] >> 3] & (1 << (m_PVSInfo.m_pClusters[i] & 7) ))
return true;
}
return false; // not visible
}
//-----------------------------------------------------------------------------
// PVS: this function is called a lot, so it avoids function calls
//-----------------------------------------------------------------------------
bool CServerNetworkProperty::IsInPVS( const CCheckTransmitInfo *pInfo )
{
// PVS data must be up to date
Assert( !m_pPev || ( ( m_pPev->m_fStateFlags & FL_EDICT_DIRTY_PVS_INFORMATION ) == 0 ) );
int i;
// Early out if the areas are connected
if ( !m_PVSInfo.m_nAreaNum2 )
{
for ( i=0; i< pInfo->m_AreasNetworked; i++ )
{
int clientArea = pInfo->m_Areas[i];
if ( clientArea == m_PVSInfo.m_nAreaNum || engine->CheckAreasConnected( clientArea, m_PVSInfo.m_nAreaNum ) )
break;
}
}
else
{
// doors can legally straddle two areas, so
// we may need to check another one
for ( i=0; i< pInfo->m_AreasNetworked; i++ )
{
int clientArea = pInfo->m_Areas[i];
if ( clientArea == m_PVSInfo.m_nAreaNum || clientArea == m_PVSInfo.m_nAreaNum2 )
break;
if ( engine->CheckAreasConnected( clientArea, m_PVSInfo.m_nAreaNum ) )
break;
if ( engine->CheckAreasConnected( clientArea, m_PVSInfo.m_nAreaNum2 ) )
break;
}
}
if ( i == pInfo->m_AreasNetworked )
{
// areas not connected
return false;
}
// ignore if not touching a PV leaf
// negative leaf count is a node number
// If no pvs, add any entity
Assert( edict() != pInfo->m_pClientEnt );
unsigned char *pPVS = ( unsigned char * )pInfo->m_PVS;
if ( m_PVSInfo.m_nClusterCount < 0 ) // too many clusters, use headnode
{
return (engine->CheckHeadnodeVisible( m_PVSInfo.m_nHeadNode, pPVS, pInfo->m_nPVSSize ) != 0);
}
for ( i = m_PVSInfo.m_nClusterCount; --i >= 0; )
{
int nCluster = m_PVSInfo.m_pClusters[i];
if ( ((int)(pPVS[nCluster >> 3])) & BitVec_BitInByte( nCluster ) )
return true;
}
return false; // not visible
}
void CServerNetworkProperty::SetUpdateInterval( float val )
{
if ( val == 0 )
m_TimerEvent.StopUpdates();
else
m_TimerEvent.SetUpdateInterval( val );
}
void CServerNetworkProperty::FireEvent()
{
// Our timer went off. If our state has changed in the background, then
// trigger a state change in the edict.
if ( m_bPendingStateChange )
{
m_pPev->StateChanged();
m_bPendingStateChange = false;
}
}
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//===========================================================================//
#include "cbase.h"
#include "ServerNetworkProperty.h"
#include "tier0/dbg.h"
#include "gameinterface.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
extern CTimedEventMgr g_NetworkPropertyEventMgr;
//-----------------------------------------------------------------------------
// Save/load
//-----------------------------------------------------------------------------
BEGIN_DATADESC_NO_BASE( CServerNetworkProperty )
// DEFINE_FIELD( m_pOuter, FIELD_CLASSPTR ),
// DEFINE_FIELD( m_pPev, FIELD_CLASSPTR ),
// DEFINE_FIELD( m_PVSInfo, PVSInfo_t ),
// DEFINE_FIELD( m_pServerClass, FIELD_CLASSPTR ),
DEFINE_GLOBAL_FIELD( m_hParent, FIELD_EHANDLE ),
// DEFINE_FIELD( m_TimerEvent, CEventRegister ),
// DEFINE_FIELD( m_bPendingStateChange, FIELD_BOOLEAN ),
END_DATADESC()
//-----------------------------------------------------------------------------
// Constructor, destructor
//-----------------------------------------------------------------------------
CServerNetworkProperty::CServerNetworkProperty()
{
Init( NULL );
}
CServerNetworkProperty::~CServerNetworkProperty()
{
/* Free our transmit proxy.
if ( m_pTransmitProxy )
{
m_pTransmitProxy->Release();
}*/
engine->CleanUpEntityClusterList( &m_PVSInfo );
// remove the attached edict if it exists
DetachEdict();
}
//-----------------------------------------------------------------------------
// Initialization
//-----------------------------------------------------------------------------
void CServerNetworkProperty::Init( CBaseEntity *pEntity )
{
m_pPev = NULL;
m_pOuter = pEntity;
m_pServerClass = NULL;
// m_pTransmitProxy = NULL;
m_bPendingStateChange = false;
m_PVSInfo.m_nClusterCount = 0;
m_TimerEvent.Init( &g_NetworkPropertyEventMgr, this );
}
//-----------------------------------------------------------------------------
// Connects, disconnects edicts
//-----------------------------------------------------------------------------
void CServerNetworkProperty::AttachEdict( edict_t *pRequiredEdict )
{
Assert ( !m_pPev );
// see if there is an edict allocated for it, otherwise get one from the engine
if ( !pRequiredEdict )
{
pRequiredEdict = engine->CreateEdict();
}
m_pPev = pRequiredEdict;
m_pPev->SetEdict( GetBaseEntity(), true );
}
void CServerNetworkProperty::DetachEdict()
{
if ( m_pPev )
{
m_pPev->SetEdict( NULL, false );
engine->RemoveEdict( m_pPev );
m_pPev = NULL;
}
}
//-----------------------------------------------------------------------------
// Entity handles
//-----------------------------------------------------------------------------
IHandleEntity *CServerNetworkProperty::GetEntityHandle( )
{
return m_pOuter;
}
void CServerNetworkProperty::Release()
{
delete m_pOuter;
}
//-----------------------------------------------------------------------------
// Returns the network parent
//-----------------------------------------------------------------------------
CServerNetworkProperty* CServerNetworkProperty::GetNetworkParent()
{
CBaseEntity *pParent = m_hParent.Get();
return pParent ? pParent->NetworkProp() : NULL;
}
//-----------------------------------------------------------------------------
// Marks for deletion
//-----------------------------------------------------------------------------
void CServerNetworkProperty::MarkForDeletion()
{
m_pOuter->AddEFlags( EFL_KILLME );
}
bool CServerNetworkProperty::IsMarkedForDeletion() const
{
return ( m_pOuter->GetEFlags() & EFL_KILLME ) != 0;
}
//-----------------------------------------------------------------------------
// PVS information
//-----------------------------------------------------------------------------
void CServerNetworkProperty::RecomputePVSInformation()
{
if ( m_pPev && ( ( m_pPev->m_fStateFlags & FL_EDICT_DIRTY_PVS_INFORMATION ) != 0 ) )
{
m_pPev->m_fStateFlags &= ~FL_EDICT_DIRTY_PVS_INFORMATION;
engine->BuildEntityClusterList( edict(), &m_PVSInfo );
}
}
//-----------------------------------------------------------------------------
// Serverclass
//-----------------------------------------------------------------------------
ServerClass* CServerNetworkProperty::GetServerClass()
{
if ( !m_pServerClass )
m_pServerClass = m_pOuter->GetServerClass();
return m_pServerClass;
}
const char* CServerNetworkProperty::GetClassName() const
{
return STRING(m_pOuter->m_iClassname);
}
//-----------------------------------------------------------------------------
// Transmit proxies
/*-----------------------------------------------------------------------------
void CServerNetworkProperty::SetTransmitProxy( CBaseTransmitProxy *pProxy )
{
if ( m_pTransmitProxy )
{
m_pTransmitProxy->Release();
}
m_pTransmitProxy = pProxy;
if ( m_pTransmitProxy )
{
m_pTransmitProxy->AddRef();
}
}*/
//-----------------------------------------------------------------------------
// PVS rules
//-----------------------------------------------------------------------------
bool CServerNetworkProperty::IsInPVS( const edict_t *pRecipient, const void *pvs, int pvssize )
{
RecomputePVSInformation();
// ignore if not touching a PV leaf
// negative leaf count is a node number
// If no pvs, add any entity
Assert( pvs && ( edict() != pRecipient ) );
unsigned char *pPVS = ( unsigned char * )pvs;
if ( m_PVSInfo.m_nClusterCount < 0 ) // too many clusters, use headnode
{
return ( engine->CheckHeadnodeVisible( m_PVSInfo.m_nHeadNode, pPVS, pvssize ) != 0);
}
for ( int i = m_PVSInfo.m_nClusterCount; --i >= 0; )
{
if (pPVS[m_PVSInfo.m_pClusters[i] >> 3] & (1 << (m_PVSInfo.m_pClusters[i] & 7) ))
return true;
}
return false; // not visible
}
//-----------------------------------------------------------------------------
// PVS: this function is called a lot, so it avoids function calls
//-----------------------------------------------------------------------------
bool CServerNetworkProperty::IsInPVS( const CCheckTransmitInfo *pInfo )
{
// PVS data must be up to date
Assert( !m_pPev || ( ( m_pPev->m_fStateFlags & FL_EDICT_DIRTY_PVS_INFORMATION ) == 0 ) );
int i;
// Early out if the areas are connected
if ( !m_PVSInfo.m_nAreaNum2 )
{
for ( i=0; i< pInfo->m_AreasNetworked; i++ )
{
int clientArea = pInfo->m_Areas[i];
if ( clientArea == m_PVSInfo.m_nAreaNum || engine->CheckAreasConnected( clientArea, m_PVSInfo.m_nAreaNum ) )
break;
}
}
else
{
// doors can legally straddle two areas, so
// we may need to check another one
for ( i=0; i< pInfo->m_AreasNetworked; i++ )
{
int clientArea = pInfo->m_Areas[i];
if ( clientArea == m_PVSInfo.m_nAreaNum || clientArea == m_PVSInfo.m_nAreaNum2 )
break;
if ( engine->CheckAreasConnected( clientArea, m_PVSInfo.m_nAreaNum ) )
break;
if ( engine->CheckAreasConnected( clientArea, m_PVSInfo.m_nAreaNum2 ) )
break;
}
}
if ( i == pInfo->m_AreasNetworked )
{
// areas not connected
return false;
}
// ignore if not touching a PV leaf
// negative leaf count is a node number
// If no pvs, add any entity
Assert( edict() != pInfo->m_pClientEnt );
unsigned char *pPVS = ( unsigned char * )pInfo->m_PVS;
if ( m_PVSInfo.m_nClusterCount < 0 ) // too many clusters, use headnode
{
return (engine->CheckHeadnodeVisible( m_PVSInfo.m_nHeadNode, pPVS, pInfo->m_nPVSSize ) != 0);
}
for ( i = m_PVSInfo.m_nClusterCount; --i >= 0; )
{
int nCluster = m_PVSInfo.m_pClusters[i];
if ( ((int)(pPVS[nCluster >> 3])) & BitVec_BitInByte( nCluster ) )
return true;
}
return false; // not visible
}
void CServerNetworkProperty::SetUpdateInterval( float val )
{
if ( val == 0 )
m_TimerEvent.StopUpdates();
else
m_TimerEvent.SetUpdateInterval( val );
}
void CServerNetworkProperty::FireEvent()
{
// Our timer went off. If our state has changed in the background, then
// trigger a state change in the edict.
if ( m_bPendingStateChange )
{
m_pPev->StateChanged();
m_bPendingStateChange = false;
}
}

View File

@@ -1,258 +1,258 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//===========================================================================//
#ifndef SERVERNETWORKPROPERTY_H
#define SERVERNETWORKPROPERTY_H
#ifdef _WIN32
#pragma once
#endif
#include "iservernetworkable.h"
#include "server_class.h"
#include "edict.h"
#include "timedeventmgr.h"
//
// Lightweight base class for networkable data on the server.
//
class CServerNetworkProperty : public IServerNetworkable, public IEventRegisterCallback
{
public:
DECLARE_CLASS_NOBASE( CServerNetworkProperty );
DECLARE_DATADESC();
public:
CServerNetworkProperty();
virtual ~CServerNetworkProperty();
public:
// IServerNetworkable implementation.
virtual IHandleEntity *GetEntityHandle( );
virtual edict_t *GetEdict() const;
virtual CBaseNetworkable* GetBaseNetworkable();
virtual CBaseEntity* GetBaseEntity();
virtual ServerClass* GetServerClass();
virtual const char* GetClassName() const;
virtual void Release();
virtual int AreaNum() const;
virtual PVSInfo_t* GetPVSInfo();
public:
// Other public methods
void Init( CBaseEntity *pEntity );
void AttachEdict( edict_t *pRequiredEdict = NULL );
// Methods to get the entindex + edict
int entindex() const;
edict_t *edict();
const edict_t *edict() const;
// Sets the edict pointer (for swapping edicts)
void SetEdict( edict_t *pEdict );
// All these functions call through to CNetStateMgr.
// See CNetStateMgr for details about these functions.
void NetworkStateForceUpdate();
void NetworkStateChanged();
void NetworkStateChanged( unsigned short offset );
// Marks the PVS information dirty
void MarkPVSInformationDirty();
// Marks for deletion
void MarkForDeletion();
bool IsMarkedForDeletion() const;
// Sets the network parent
void SetNetworkParent( EHANDLE hParent );
CServerNetworkProperty* GetNetworkParent();
// This is useful for entities that don't change frequently or that the client
// doesn't need updates on very often. If you use this mode, the server will only try to
// detect state changes every N seconds, so it will save CPU cycles and bandwidth.
//
// Note: N must be less than AUTOUPDATE_MAX_TIME_LENGTH.
//
// Set back to zero to disable the feature.
//
// This feature works on top of manual mode.
// - If you turn it on and manual mode is off, it will autodetect changes every N seconds.
// - If you turn it on and manual mode is on, then every N seconds it will only say there
// is a change if you've called NetworkStateChanged.
void SetUpdateInterval( float N );
// You can use this to override any entity's ShouldTransmit behavior.
// void SetTransmitProxy( CBaseTransmitProxy *pProxy );
// This version does a PVS check which also checks for connected areas
bool IsInPVS( const CCheckTransmitInfo *pInfo );
// This version doesn't do the area check
bool IsInPVS( const edict_t *pRecipient, const void *pvs, int pvssize );
// Called by the timed event manager when it's time to detect a state change.
virtual void FireEvent();
// Recomputes PVS information
void RecomputePVSInformation();
private:
// Detaches the edict.. should only be called by CBaseNetworkable's destructor.
void DetachEdict();
CBaseEntity *GetOuter();
// Marks the networkable that it will should transmit
void SetTransmit( CCheckTransmitInfo *pInfo );
private:
CBaseEntity *m_pOuter;
// CBaseTransmitProxy *m_pTransmitProxy;
edict_t *m_pPev;
PVSInfo_t m_PVSInfo;
ServerClass *m_pServerClass;
// NOTE: This state is 'owned' by the entity. It's only copied here
// also to help improve cache performance in networking code.
EHANDLE m_hParent;
// Counters for SetUpdateInterval.
CEventRegister m_TimerEvent;
bool m_bPendingStateChange : 1;
// friend class CBaseTransmitProxy;
};
//-----------------------------------------------------------------------------
// inline methods // TODOMO does inline work on virtual functions ?
//-----------------------------------------------------------------------------
inline CBaseNetworkable* CServerNetworkProperty::GetBaseNetworkable()
{
return NULL;
}
inline CBaseEntity* CServerNetworkProperty::GetBaseEntity()
{
return m_pOuter;
}
inline CBaseEntity *CServerNetworkProperty::GetOuter()
{
return m_pOuter;
}
inline PVSInfo_t *CServerNetworkProperty::GetPVSInfo()
{
return &m_PVSInfo;
}
//-----------------------------------------------------------------------------
// Marks the PVS information dirty
//-----------------------------------------------------------------------------
inline void CServerNetworkProperty::MarkPVSInformationDirty()
{
if ( m_pPev )
{
m_pPev->m_fStateFlags |= FL_EDICT_DIRTY_PVS_INFORMATION;
}
}
//-----------------------------------------------------------------------------
// Sets/gets the network parent
//-----------------------------------------------------------------------------
inline void CServerNetworkProperty::SetNetworkParent( EHANDLE hParent )
{
m_hParent = hParent;
}
//-----------------------------------------------------------------------------
// Methods related to the net state mgr
//-----------------------------------------------------------------------------
inline void CServerNetworkProperty::NetworkStateForceUpdate()
{
if ( m_pPev )
m_pPev->StateChanged();
}
inline void CServerNetworkProperty::NetworkStateChanged()
{
// If we're using the timer, then ignore this call.
if ( m_TimerEvent.IsRegistered() )
{
// If we're waiting for a timer event, then queue the change so it happens
// when the timer goes off.
m_bPendingStateChange = true;
}
else
{
if ( m_pPev )
m_pPev->StateChanged();
}
}
inline void CServerNetworkProperty::NetworkStateChanged( unsigned short varOffset )
{
// If we're using the timer, then ignore this call.
if ( m_TimerEvent.IsRegistered() )
{
// If we're waiting for a timer event, then queue the change so it happens
// when the timer goes off.
m_bPendingStateChange = true;
}
else
{
if ( m_pPev )
m_pPev->StateChanged( varOffset );
}
}
//-----------------------------------------------------------------------------
// Methods to get the entindex + edict
//-----------------------------------------------------------------------------
inline int CServerNetworkProperty::entindex() const
{
return ENTINDEX( m_pPev );
}
inline edict_t* CServerNetworkProperty::GetEdict() const
{
// This one's virtual, that's why we have to two other versions
return m_pPev;
}
inline edict_t *CServerNetworkProperty::edict()
{
return m_pPev;
}
inline const edict_t *CServerNetworkProperty::edict() const
{
return m_pPev;
}
//-----------------------------------------------------------------------------
// Sets the edict pointer (for swapping edicts)
//-----------------------------------------------------------------------------
inline void CServerNetworkProperty::SetEdict( edict_t *pEdict )
{
m_pPev = pEdict;
}
inline int CServerNetworkProperty::AreaNum() const
{
const_cast<CServerNetworkProperty*>(this)->RecomputePVSInformation();
return m_PVSInfo.m_nAreaNum;
}
#endif // SERVERNETWORKPROPERTY_H
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//===========================================================================//
#ifndef SERVERNETWORKPROPERTY_H
#define SERVERNETWORKPROPERTY_H
#ifdef _WIN32
#pragma once
#endif
#include "iservernetworkable.h"
#include "server_class.h"
#include "edict.h"
#include "timedeventmgr.h"
//
// Lightweight base class for networkable data on the server.
//
class CServerNetworkProperty : public IServerNetworkable, public IEventRegisterCallback
{
public:
DECLARE_CLASS_NOBASE( CServerNetworkProperty );
DECLARE_DATADESC();
public:
CServerNetworkProperty();
virtual ~CServerNetworkProperty();
public:
// IServerNetworkable implementation.
virtual IHandleEntity *GetEntityHandle( );
virtual edict_t *GetEdict() const;
virtual CBaseNetworkable* GetBaseNetworkable();
virtual CBaseEntity* GetBaseEntity();
virtual ServerClass* GetServerClass();
virtual const char* GetClassName() const;
virtual void Release();
virtual int AreaNum() const;
virtual PVSInfo_t* GetPVSInfo();
public:
// Other public methods
void Init( CBaseEntity *pEntity );
void AttachEdict( edict_t *pRequiredEdict = NULL );
// Methods to get the entindex + edict
int entindex() const;
edict_t *edict();
const edict_t *edict() const;
// Sets the edict pointer (for swapping edicts)
void SetEdict( edict_t *pEdict );
// All these functions call through to CNetStateMgr.
// See CNetStateMgr for details about these functions.
void NetworkStateForceUpdate();
void NetworkStateChanged();
void NetworkStateChanged( unsigned short offset );
// Marks the PVS information dirty
void MarkPVSInformationDirty();
// Marks for deletion
void MarkForDeletion();
bool IsMarkedForDeletion() const;
// Sets the network parent
void SetNetworkParent( EHANDLE hParent );
CServerNetworkProperty* GetNetworkParent();
// This is useful for entities that don't change frequently or that the client
// doesn't need updates on very often. If you use this mode, the server will only try to
// detect state changes every N seconds, so it will save CPU cycles and bandwidth.
//
// Note: N must be less than AUTOUPDATE_MAX_TIME_LENGTH.
//
// Set back to zero to disable the feature.
//
// This feature works on top of manual mode.
// - If you turn it on and manual mode is off, it will autodetect changes every N seconds.
// - If you turn it on and manual mode is on, then every N seconds it will only say there
// is a change if you've called NetworkStateChanged.
void SetUpdateInterval( float N );
// You can use this to override any entity's ShouldTransmit behavior.
// void SetTransmitProxy( CBaseTransmitProxy *pProxy );
// This version does a PVS check which also checks for connected areas
bool IsInPVS( const CCheckTransmitInfo *pInfo );
// This version doesn't do the area check
bool IsInPVS( const edict_t *pRecipient, const void *pvs, int pvssize );
// Called by the timed event manager when it's time to detect a state change.
virtual void FireEvent();
// Recomputes PVS information
void RecomputePVSInformation();
private:
// Detaches the edict.. should only be called by CBaseNetworkable's destructor.
void DetachEdict();
CBaseEntity *GetOuter();
// Marks the networkable that it will should transmit
void SetTransmit( CCheckTransmitInfo *pInfo );
private:
CBaseEntity *m_pOuter;
// CBaseTransmitProxy *m_pTransmitProxy;
edict_t *m_pPev;
PVSInfo_t m_PVSInfo;
ServerClass *m_pServerClass;
// NOTE: This state is 'owned' by the entity. It's only copied here
// also to help improve cache performance in networking code.
EHANDLE m_hParent;
// Counters for SetUpdateInterval.
CEventRegister m_TimerEvent;
bool m_bPendingStateChange : 1;
// friend class CBaseTransmitProxy;
};
//-----------------------------------------------------------------------------
// inline methods // TODOMO does inline work on virtual functions ?
//-----------------------------------------------------------------------------
inline CBaseNetworkable* CServerNetworkProperty::GetBaseNetworkable()
{
return NULL;
}
inline CBaseEntity* CServerNetworkProperty::GetBaseEntity()
{
return m_pOuter;
}
inline CBaseEntity *CServerNetworkProperty::GetOuter()
{
return m_pOuter;
}
inline PVSInfo_t *CServerNetworkProperty::GetPVSInfo()
{
return &m_PVSInfo;
}
//-----------------------------------------------------------------------------
// Marks the PVS information dirty
//-----------------------------------------------------------------------------
inline void CServerNetworkProperty::MarkPVSInformationDirty()
{
if ( m_pPev )
{
m_pPev->m_fStateFlags |= FL_EDICT_DIRTY_PVS_INFORMATION;
}
}
//-----------------------------------------------------------------------------
// Sets/gets the network parent
//-----------------------------------------------------------------------------
inline void CServerNetworkProperty::SetNetworkParent( EHANDLE hParent )
{
m_hParent = hParent;
}
//-----------------------------------------------------------------------------
// Methods related to the net state mgr
//-----------------------------------------------------------------------------
inline void CServerNetworkProperty::NetworkStateForceUpdate()
{
if ( m_pPev )
m_pPev->StateChanged();
}
inline void CServerNetworkProperty::NetworkStateChanged()
{
// If we're using the timer, then ignore this call.
if ( m_TimerEvent.IsRegistered() )
{
// If we're waiting for a timer event, then queue the change so it happens
// when the timer goes off.
m_bPendingStateChange = true;
}
else
{
if ( m_pPev )
m_pPev->StateChanged();
}
}
inline void CServerNetworkProperty::NetworkStateChanged( unsigned short varOffset )
{
// If we're using the timer, then ignore this call.
if ( m_TimerEvent.IsRegistered() )
{
// If we're waiting for a timer event, then queue the change so it happens
// when the timer goes off.
m_bPendingStateChange = true;
}
else
{
if ( m_pPev )
m_pPev->StateChanged( varOffset );
}
}
//-----------------------------------------------------------------------------
// Methods to get the entindex + edict
//-----------------------------------------------------------------------------
inline int CServerNetworkProperty::entindex() const
{
return ENTINDEX( m_pPev );
}
inline edict_t* CServerNetworkProperty::GetEdict() const
{
// This one's virtual, that's why we have to two other versions
return m_pPev;
}
inline edict_t *CServerNetworkProperty::edict()
{
return m_pPev;
}
inline const edict_t *CServerNetworkProperty::edict() const
{
return m_pPev;
}
//-----------------------------------------------------------------------------
// Sets the edict pointer (for swapping edicts)
//-----------------------------------------------------------------------------
inline void CServerNetworkProperty::SetEdict( edict_t *pEdict )
{
m_pPev = pEdict;
}
inline int CServerNetworkProperty::AreaNum() const
{
const_cast<CServerNetworkProperty*>(this)->RecomputePVSInformation();
return m_PVSInfo.m_nAreaNum;
}
#endif // SERVERNETWORKPROPERTY_H

View File

@@ -1,147 +1,147 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#include "cbase.h"
#include "igamesystem.h"
#include "entitylist.h"
#include "SkyCamera.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
// automatically hooks in the system's callbacks
CEntityClassList<CSkyCamera> g_SkyList;
template <> CSkyCamera *CEntityClassList<CSkyCamera>::m_pClassList = NULL;
//-----------------------------------------------------------------------------
// Retrives the current skycamera
//-----------------------------------------------------------------------------
CSkyCamera* GetCurrentSkyCamera()
{
return g_SkyList.m_pClassList;
}
CSkyCamera* GetSkyCameraList()
{
return g_SkyList.m_pClassList;
}
//=============================================================================
LINK_ENTITY_TO_CLASS( sky_camera, CSkyCamera );
BEGIN_DATADESC( CSkyCamera )
DEFINE_KEYFIELD( m_skyboxData.scale, FIELD_INTEGER, "scale" ),
DEFINE_FIELD( m_skyboxData.origin, FIELD_VECTOR ),
DEFINE_FIELD( m_skyboxData.area, FIELD_INTEGER ),
// Quiet down classcheck
// DEFINE_FIELD( m_skyboxData, sky3dparams_t ),
// This is re-set up in the constructor
// DEFINE_FIELD( m_pNext, CSkyCamera ),
// fog data for 3d skybox
DEFINE_KEYFIELD( m_bUseAngles, FIELD_BOOLEAN, "use_angles" ),
DEFINE_KEYFIELD( m_skyboxData.fog.enable, FIELD_BOOLEAN, "fogenable" ),
DEFINE_KEYFIELD( m_skyboxData.fog.blend, FIELD_BOOLEAN, "fogblend" ),
DEFINE_KEYFIELD( m_skyboxData.fog.dirPrimary, FIELD_VECTOR, "fogdir" ),
DEFINE_KEYFIELD( m_skyboxData.fog.colorPrimary, FIELD_COLOR32, "fogcolor" ),
DEFINE_KEYFIELD( m_skyboxData.fog.colorSecondary, FIELD_COLOR32, "fogcolor2" ),
DEFINE_KEYFIELD( m_skyboxData.fog.start, FIELD_FLOAT, "fogstart" ),
DEFINE_KEYFIELD( m_skyboxData.fog.end, FIELD_FLOAT, "fogend" ),
DEFINE_KEYFIELD( m_skyboxData.fog.maxdensity, FIELD_FLOAT, "fogmaxdensity" ),
END_DATADESC()
//-----------------------------------------------------------------------------
// List of maps in HL2 that we must apply our skybox fog fixup hack to
//-----------------------------------------------------------------------------
static const char *s_pBogusFogMaps[] =
{
"d1_canals_01",
"d1_canals_01a",
"d1_canals_02",
"d1_canals_03",
"d1_canals_09",
"d1_canals_10",
"d1_canals_11",
"d1_canals_12",
"d1_canals_13",
"d1_eli_01",
"d1_trainstation_01",
"d1_trainstation_03",
"d1_trainstation_04",
"d1_trainstation_05",
"d1_trainstation_06",
"d3_c17_04",
"d3_c17_11",
"d3_c17_12",
"d3_citadel_01",
NULL
};
//-----------------------------------------------------------------------------
// Constructor, destructor
//-----------------------------------------------------------------------------
CSkyCamera::CSkyCamera()
{
g_SkyList.Insert( this );
m_skyboxData.fog.maxdensity = 1.0f;
}
CSkyCamera::~CSkyCamera()
{
g_SkyList.Remove( this );
}
void CSkyCamera::Spawn( void )
{
m_skyboxData.origin = GetLocalOrigin();
m_skyboxData.area = engine->GetArea( m_skyboxData.origin );
Precache();
}
//-----------------------------------------------------------------------------
// Activate!
//-----------------------------------------------------------------------------
void CSkyCamera::Activate( )
{
BaseClass::Activate();
if ( m_bUseAngles )
{
AngleVectors( GetAbsAngles(), &m_skyboxData.fog.dirPrimary.GetForModify() );
m_skyboxData.fog.dirPrimary.GetForModify() *= -1.0f;
}
#ifdef HL2_DLL
// NOTE! This is a hack. There was a bug in the skybox fog computation
// on the client DLL that caused it to use the average of the primary and
// secondary fog color when blending was enabled. The bug is fixed, but to make
// the maps look the same as before the bug fix without having to download new maps,
// I have to cheat here and slam the primary and secondary colors to be the average of
// the primary and secondary colors.
if ( m_skyboxData.fog.blend )
{
for ( int i = 0; s_pBogusFogMaps[i]; ++i )
{
if ( !Q_stricmp( s_pBogusFogMaps[i], STRING(gpGlobals->mapname) ) )
{
m_skyboxData.fog.colorPrimary.SetR( ( m_skyboxData.fog.colorPrimary.GetR() + m_skyboxData.fog.colorSecondary.GetR() ) * 0.5f );
m_skyboxData.fog.colorPrimary.SetG( ( m_skyboxData.fog.colorPrimary.GetG() + m_skyboxData.fog.colorSecondary.GetG() ) * 0.5f );
m_skyboxData.fog.colorPrimary.SetB( ( m_skyboxData.fog.colorPrimary.GetB() + m_skyboxData.fog.colorSecondary.GetB() ) * 0.5f );
m_skyboxData.fog.colorPrimary.SetA( ( m_skyboxData.fog.colorPrimary.GetA() + m_skyboxData.fog.colorSecondary.GetA() ) * 0.5f );
m_skyboxData.fog.colorSecondary = m_skyboxData.fog.colorPrimary;
}
}
}
#endif
}
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#include "cbase.h"
#include "igamesystem.h"
#include "entitylist.h"
#include "SkyCamera.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
// automatically hooks in the system's callbacks
CEntityClassList<CSkyCamera> g_SkyList;
template <> CSkyCamera *CEntityClassList<CSkyCamera>::m_pClassList = NULL;
//-----------------------------------------------------------------------------
// Retrives the current skycamera
//-----------------------------------------------------------------------------
CSkyCamera* GetCurrentSkyCamera()
{
return g_SkyList.m_pClassList;
}
CSkyCamera* GetSkyCameraList()
{
return g_SkyList.m_pClassList;
}
//=============================================================================
LINK_ENTITY_TO_CLASS( sky_camera, CSkyCamera );
BEGIN_DATADESC( CSkyCamera )
DEFINE_KEYFIELD( m_skyboxData.scale, FIELD_INTEGER, "scale" ),
DEFINE_FIELD( m_skyboxData.origin, FIELD_VECTOR ),
DEFINE_FIELD( m_skyboxData.area, FIELD_INTEGER ),
// Quiet down classcheck
// DEFINE_FIELD( m_skyboxData, sky3dparams_t ),
// This is re-set up in the constructor
// DEFINE_FIELD( m_pNext, CSkyCamera ),
// fog data for 3d skybox
DEFINE_KEYFIELD( m_bUseAngles, FIELD_BOOLEAN, "use_angles" ),
DEFINE_KEYFIELD( m_skyboxData.fog.enable, FIELD_BOOLEAN, "fogenable" ),
DEFINE_KEYFIELD( m_skyboxData.fog.blend, FIELD_BOOLEAN, "fogblend" ),
DEFINE_KEYFIELD( m_skyboxData.fog.dirPrimary, FIELD_VECTOR, "fogdir" ),
DEFINE_KEYFIELD( m_skyboxData.fog.colorPrimary, FIELD_COLOR32, "fogcolor" ),
DEFINE_KEYFIELD( m_skyboxData.fog.colorSecondary, FIELD_COLOR32, "fogcolor2" ),
DEFINE_KEYFIELD( m_skyboxData.fog.start, FIELD_FLOAT, "fogstart" ),
DEFINE_KEYFIELD( m_skyboxData.fog.end, FIELD_FLOAT, "fogend" ),
DEFINE_KEYFIELD( m_skyboxData.fog.maxdensity, FIELD_FLOAT, "fogmaxdensity" ),
END_DATADESC()
//-----------------------------------------------------------------------------
// List of maps in HL2 that we must apply our skybox fog fixup hack to
//-----------------------------------------------------------------------------
static const char *s_pBogusFogMaps[] =
{
"d1_canals_01",
"d1_canals_01a",
"d1_canals_02",
"d1_canals_03",
"d1_canals_09",
"d1_canals_10",
"d1_canals_11",
"d1_canals_12",
"d1_canals_13",
"d1_eli_01",
"d1_trainstation_01",
"d1_trainstation_03",
"d1_trainstation_04",
"d1_trainstation_05",
"d1_trainstation_06",
"d3_c17_04",
"d3_c17_11",
"d3_c17_12",
"d3_citadel_01",
NULL
};
//-----------------------------------------------------------------------------
// Constructor, destructor
//-----------------------------------------------------------------------------
CSkyCamera::CSkyCamera()
{
g_SkyList.Insert( this );
m_skyboxData.fog.maxdensity = 1.0f;
}
CSkyCamera::~CSkyCamera()
{
g_SkyList.Remove( this );
}
void CSkyCamera::Spawn( void )
{
m_skyboxData.origin = GetLocalOrigin();
m_skyboxData.area = engine->GetArea( m_skyboxData.origin );
Precache();
}
//-----------------------------------------------------------------------------
// Activate!
//-----------------------------------------------------------------------------
void CSkyCamera::Activate( )
{
BaseClass::Activate();
if ( m_bUseAngles )
{
AngleVectors( GetAbsAngles(), &m_skyboxData.fog.dirPrimary.GetForModify() );
m_skyboxData.fog.dirPrimary.GetForModify() *= -1.0f;
}
#ifdef HL2_DLL
// NOTE! This is a hack. There was a bug in the skybox fog computation
// on the client DLL that caused it to use the average of the primary and
// secondary fog color when blending was enabled. The bug is fixed, but to make
// the maps look the same as before the bug fix without having to download new maps,
// I have to cheat here and slam the primary and secondary colors to be the average of
// the primary and secondary colors.
if ( m_skyboxData.fog.blend )
{
for ( int i = 0; s_pBogusFogMaps[i]; ++i )
{
if ( !Q_stricmp( s_pBogusFogMaps[i], STRING(gpGlobals->mapname) ) )
{
m_skyboxData.fog.colorPrimary.SetR( ( m_skyboxData.fog.colorPrimary.GetR() + m_skyboxData.fog.colorSecondary.GetR() ) * 0.5f );
m_skyboxData.fog.colorPrimary.SetG( ( m_skyboxData.fog.colorPrimary.GetG() + m_skyboxData.fog.colorSecondary.GetG() ) * 0.5f );
m_skyboxData.fog.colorPrimary.SetB( ( m_skyboxData.fog.colorPrimary.GetB() + m_skyboxData.fog.colorSecondary.GetB() ) * 0.5f );
m_skyboxData.fog.colorPrimary.SetA( ( m_skyboxData.fog.colorPrimary.GetA() + m_skyboxData.fog.colorSecondary.GetA() ) * 0.5f );
m_skyboxData.fog.colorSecondary = m_skyboxData.fog.colorPrimary;
}
}
}
#endif
}

View File

@@ -1,47 +1,47 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Resource collection entity
//
// $NoKeywords: $
//=============================================================================//
#ifndef SKYCAMERA_H
#define SKYCAMERA_H
#ifdef _WIN32
#pragma once
#endif
class CSkyCamera;
//=============================================================================
//
// Sky Camera Class
//
class CSkyCamera : public CLogicalEntity
{
DECLARE_CLASS( CSkyCamera, CLogicalEntity );
public:
DECLARE_DATADESC();
CSkyCamera();
~CSkyCamera();
virtual void Spawn( void );
virtual void Activate();
public:
sky3dparams_t m_skyboxData;
bool m_bUseAngles;
CSkyCamera *m_pNext;
};
//-----------------------------------------------------------------------------
// Retrives the current skycamera
//-----------------------------------------------------------------------------
CSkyCamera* GetCurrentSkyCamera();
CSkyCamera* GetSkyCameraList();
#endif // SKYCAMERA_H
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Resource collection entity
//
// $NoKeywords: $
//=============================================================================//
#ifndef SKYCAMERA_H
#define SKYCAMERA_H
#ifdef _WIN32
#pragma once
#endif
class CSkyCamera;
//=============================================================================
//
// Sky Camera Class
//
class CSkyCamera : public CLogicalEntity
{
DECLARE_CLASS( CSkyCamera, CLogicalEntity );
public:
DECLARE_DATADESC();
CSkyCamera();
~CSkyCamera();
virtual void Spawn( void );
virtual void Activate();
public:
sky3dparams_t m_skyboxData;
bool m_bUseAngles;
CSkyCamera *m_pNext;
};
//-----------------------------------------------------------------------------
// Retrives the current skycamera
//-----------------------------------------------------------------------------
CSkyCamera* GetCurrentSkyCamera();
CSkyCamera* GetSkyCameraList();
#endif // SKYCAMERA_H

File diff suppressed because it is too large Load Diff

View File

@@ -1,36 +1,36 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Template entities are used by spawners to create copies of entities
// that were configured by the level designer. This allows us to spawn
// entities with arbitrary sets of key/value data and entity I/O
// connections.
//
//=============================================================================//
#ifndef TEMPLATEENTITIES_H
#define TEMPLATEENTITIES_H
#ifdef _WIN32
#pragma once
#endif
#include "isaverestore.h"
class CBaseEntity;
class CPointTemplate;
int Templates_Add(CBaseEntity *pEntity, const char *pszMapData, int nLen);
string_t Templates_FindByIndex( int iIndex );
int Templates_GetStringSize( int iIndex );
string_t Templates_FindByTargetName(const char *pszName);
void Templates_ReconnectIOForGroup( CPointTemplate *pGroup );
// Some templates have Entity I/O connecting the entities within the template.
// Unique versions of these templates need to be created whenever they're instanced.
void Templates_StartUniqueInstance( void );
bool Templates_IndexRequiresEntityIOFixup( int iIndex );
char *Templates_GetEntityIOFixedMapData( int iIndex );
// Save / Restore
ISaveRestoreBlockHandler *GetTemplateSaveRestoreBlockHandler( void );
#endif // TEMPLATEENTITIES_H
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Template entities are used by spawners to create copies of entities
// that were configured by the level designer. This allows us to spawn
// entities with arbitrary sets of key/value data and entity I/O
// connections.
//
//=============================================================================//
#ifndef TEMPLATEENTITIES_H
#define TEMPLATEENTITIES_H
#ifdef _WIN32
#pragma once
#endif
#include "isaverestore.h"
class CBaseEntity;
class CPointTemplate;
int Templates_Add(CBaseEntity *pEntity, const char *pszMapData, int nLen);
string_t Templates_FindByIndex( int iIndex );
int Templates_GetStringSize( int iIndex );
string_t Templates_FindByTargetName(const char *pszName);
void Templates_ReconnectIOForGroup( CPointTemplate *pGroup );
// Some templates have Entity I/O connecting the entities within the template.
// Unique versions of these templates need to be created whenever they're instanced.
void Templates_StartUniqueInstance( void );
bool Templates_IndexRequiresEntityIOFixup( int iIndex );
char *Templates_GetEntityIOFixedMapData( int iIndex );
// Save / Restore
ISaveRestoreBlockHandler *GetTemplateSaveRestoreBlockHandler( void );
#endif // TEMPLATEENTITIES_H

View File

@@ -1,118 +1,118 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Shadow control entity.
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
//------------------------------------------------------------------------------
// FIXME: This really should inherit from something more lightweight
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
// Purpose : Water LOD control entity
//------------------------------------------------------------------------------
class CWaterLODControl : public CBaseEntity
{
public:
DECLARE_CLASS( CWaterLODControl, CBaseEntity );
CWaterLODControl();
void Spawn( void );
bool KeyValue( const char *szKeyName, const char *szValue );
int UpdateTransmitState();
void SetCheapWaterStartDistance( inputdata_t &inputdata );
void SetCheapWaterEndDistance( inputdata_t &inputdata );
virtual int ObjectCaps( void ) { return BaseClass::ObjectCaps() & ~FCAP_ACROSS_TRANSITION; }
DECLARE_SERVERCLASS();
DECLARE_DATADESC();
private:
CNetworkVar( float, m_flCheapWaterStartDistance );
CNetworkVar( float, m_flCheapWaterEndDistance );
};
LINK_ENTITY_TO_CLASS(water_lod_control, CWaterLODControl);
BEGIN_DATADESC( CWaterLODControl )
DEFINE_KEYFIELD( m_flCheapWaterStartDistance, FIELD_FLOAT, "cheapwaterstartdistance" ),
DEFINE_KEYFIELD( m_flCheapWaterEndDistance, FIELD_FLOAT, "cheapwaterenddistance" ),
// Inputs
DEFINE_INPUT( m_flCheapWaterStartDistance, FIELD_FLOAT, "SetCheapWaterStartDistance" ),
DEFINE_INPUT( m_flCheapWaterEndDistance, FIELD_FLOAT, "SetCheapWaterEndDistance" ),
END_DATADESC()
IMPLEMENT_SERVERCLASS_ST_NOBASE(CWaterLODControl, DT_WaterLODControl)
SendPropFloat(SENDINFO(m_flCheapWaterStartDistance), 0, SPROP_NOSCALE ),
SendPropFloat(SENDINFO(m_flCheapWaterEndDistance), 0, SPROP_NOSCALE ),
END_SEND_TABLE()
CWaterLODControl::CWaterLODControl()
{
m_flCheapWaterStartDistance = 1000.0f;
m_flCheapWaterEndDistance = 2000.0f;
}
//------------------------------------------------------------------------------
// Purpose : Send even though we don't have a model
//------------------------------------------------------------------------------
int CWaterLODControl::UpdateTransmitState()
{
// ALWAYS transmit to all clients.
return SetTransmitState( FL_EDICT_ALWAYS );
}
bool CWaterLODControl::KeyValue( const char *szKeyName, const char *szValue )
{
if ( FStrEq( szKeyName, "cheapwaterstartdistance" ) )
{
m_flCheapWaterStartDistance = atof( szValue );
return true;
}
if ( FStrEq( szKeyName, "cheapwaterenddistance" ) )
{
m_flCheapWaterEndDistance = atof( szValue );
return true;
}
return BaseClass::KeyValue( szKeyName, szValue );
}
//------------------------------------------------------------------------------
// Purpose :
//------------------------------------------------------------------------------
void CWaterLODControl::Spawn( void )
{
Precache();
SetSolid( SOLID_NONE );
}
//------------------------------------------------------------------------------
// Input values
//------------------------------------------------------------------------------
void CWaterLODControl::SetCheapWaterStartDistance( inputdata_t &inputdata )
{
m_flCheapWaterStartDistance = atof( inputdata.value.String() );
}
void CWaterLODControl::SetCheapWaterEndDistance( inputdata_t &inputdata )
{
m_flCheapWaterEndDistance = atof( inputdata.value.String() );
}
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Shadow control entity.
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
//------------------------------------------------------------------------------
// FIXME: This really should inherit from something more lightweight
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
// Purpose : Water LOD control entity
//------------------------------------------------------------------------------
class CWaterLODControl : public CBaseEntity
{
public:
DECLARE_CLASS( CWaterLODControl, CBaseEntity );
CWaterLODControl();
void Spawn( void );
bool KeyValue( const char *szKeyName, const char *szValue );
int UpdateTransmitState();
void SetCheapWaterStartDistance( inputdata_t &inputdata );
void SetCheapWaterEndDistance( inputdata_t &inputdata );
virtual int ObjectCaps( void ) { return BaseClass::ObjectCaps() & ~FCAP_ACROSS_TRANSITION; }
DECLARE_SERVERCLASS();
DECLARE_DATADESC();
private:
CNetworkVar( float, m_flCheapWaterStartDistance );
CNetworkVar( float, m_flCheapWaterEndDistance );
};
LINK_ENTITY_TO_CLASS(water_lod_control, CWaterLODControl);
BEGIN_DATADESC( CWaterLODControl )
DEFINE_KEYFIELD( m_flCheapWaterStartDistance, FIELD_FLOAT, "cheapwaterstartdistance" ),
DEFINE_KEYFIELD( m_flCheapWaterEndDistance, FIELD_FLOAT, "cheapwaterenddistance" ),
// Inputs
DEFINE_INPUT( m_flCheapWaterStartDistance, FIELD_FLOAT, "SetCheapWaterStartDistance" ),
DEFINE_INPUT( m_flCheapWaterEndDistance, FIELD_FLOAT, "SetCheapWaterEndDistance" ),
END_DATADESC()
IMPLEMENT_SERVERCLASS_ST_NOBASE(CWaterLODControl, DT_WaterLODControl)
SendPropFloat(SENDINFO(m_flCheapWaterStartDistance), 0, SPROP_NOSCALE ),
SendPropFloat(SENDINFO(m_flCheapWaterEndDistance), 0, SPROP_NOSCALE ),
END_SEND_TABLE()
CWaterLODControl::CWaterLODControl()
{
m_flCheapWaterStartDistance = 1000.0f;
m_flCheapWaterEndDistance = 2000.0f;
}
//------------------------------------------------------------------------------
// Purpose : Send even though we don't have a model
//------------------------------------------------------------------------------
int CWaterLODControl::UpdateTransmitState()
{
// ALWAYS transmit to all clients.
return SetTransmitState( FL_EDICT_ALWAYS );
}
bool CWaterLODControl::KeyValue( const char *szKeyName, const char *szValue )
{
if ( FStrEq( szKeyName, "cheapwaterstartdistance" ) )
{
m_flCheapWaterStartDistance = atof( szValue );
return true;
}
if ( FStrEq( szKeyName, "cheapwaterenddistance" ) )
{
m_flCheapWaterEndDistance = atof( szValue );
return true;
}
return BaseClass::KeyValue( szKeyName, szValue );
}
//------------------------------------------------------------------------------
// Purpose :
//------------------------------------------------------------------------------
void CWaterLODControl::Spawn( void )
{
Precache();
SetSolid( SOLID_NONE );
}
//------------------------------------------------------------------------------
// Input values
//------------------------------------------------------------------------------
void CWaterLODControl::SetCheapWaterStartDistance( inputdata_t &inputdata )
{
m_flCheapWaterStartDistance = atof( inputdata.value.String() );
}
void CWaterLODControl::SetCheapWaterEndDistance( inputdata_t &inputdata )
{
m_flCheapWaterEndDistance = atof( inputdata.value.String() );
}

View File

@@ -1,31 +1,31 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//
//=============================================================================//
#include "cbase.h"
#include "actanimating.h"
#include "animation.h"
#include "activitylist.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
BEGIN_DATADESC( CActAnimating )
DEFINE_CUSTOM_FIELD( m_Activity, ActivityDataOps() ),
END_DATADESC()
void CActAnimating::SetActivity( Activity act )
{
int sequence = SelectWeightedSequence( act );
if ( sequence != ACTIVITY_NOT_AVAILABLE )
{
ResetSequence( sequence );
m_Activity = act;
SetCycle( 0 );
}
}
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//
//=============================================================================//
#include "cbase.h"
#include "actanimating.h"
#include "animation.h"
#include "activitylist.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
BEGIN_DATADESC( CActAnimating )
DEFINE_CUSTOM_FIELD( m_Activity, ActivityDataOps() ),
END_DATADESC()
void CActAnimating::SetActivity( Activity act )
{
int sequence = SelectWeightedSequence( act );
if ( sequence != ACTIVITY_NOT_AVAILABLE )
{
ResetSequence( sequence );
m_Activity = act;
SetCycle( 0 );
}
}

View File

@@ -1,35 +1,35 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#ifndef ACTANIMATING_H
#define ACTANIMATING_H
#ifdef _WIN32
#pragma once
#endif
#include "baseanimating.h"
class CActAnimating : public CBaseAnimating
{
public:
DECLARE_CLASS( CActAnimating, CBaseAnimating );
void SetActivity( Activity act );
inline Activity GetActivity( void ) { return m_Activity; }
virtual int ObjectCaps( void ) { return BaseClass::ObjectCaps() & ~FCAP_ACROSS_TRANSITION; }
DECLARE_DATADESC();
private:
Activity m_Activity;
};
#endif // ACTANIMATING_H
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#ifndef ACTANIMATING_H
#define ACTANIMATING_H
#ifdef _WIN32
#pragma once
#endif
#include "baseanimating.h"
class CActAnimating : public CBaseAnimating
{
public:
DECLARE_CLASS( CActAnimating, CBaseAnimating );
void SetActivity( Activity act );
inline Activity GetActivity( void ) { return m_Activity; }
virtual int ObjectCaps( void ) { return BaseClass::ObjectCaps() & ~FCAP_ACROSS_TRANSITION; }
DECLARE_DATADESC();
private:
Activity m_Activity;
};
#endif // ACTANIMATING_H

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,304 +1,304 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Hooks and classes for the support of humanoid NPCs with
// groovy facial animation capabilities, aka, "Actors"
//
//=============================================================================//
#ifndef AI_BASEACTOR_H
#define AI_BASEACTOR_H
#include "ai_basehumanoid.h"
#include "ai_speech.h"
#include "AI_Interest_Target.h"
#include <limits.h>
#if defined( _WIN32 )
#pragma once
#endif
//-----------------------------------------------------------------------------
// CAI_BaseActor
//
// Purpose: The base class for all head/body/eye expressive NPCS.
//
//-----------------------------------------------------------------------------
enum PoseParameter_t { POSE_END=INT_MAX };
enum FlexWeight_t { FLEX_END=INT_MAX };
struct AILookTargetArgs_t
{
EHANDLE hTarget;
Vector vTarget;
float flDuration;
float flInfluence;
float flRamp;
bool bExcludePlayers;
CAI_InterestTarget *pQueue;
};
class CAI_BaseActor : public CAI_ExpresserHost<CAI_BaseHumanoid>
{
DECLARE_CLASS( CAI_BaseActor, CAI_ExpresserHost<CAI_BaseHumanoid> );
//friend CPoseParameter;
//friend CFlexWeight;
public:
// FIXME: this method is lame, isn't there some sort of template thing that would get rid of the Outer pointer?
void Init( PoseParameter_t &index, const char *szName ) { index = (PoseParameter_t)LookupPoseParameter( szName ); };
void Set( PoseParameter_t index, float flValue ) { SetPoseParameter( (int)index, flValue ); }
float Get( PoseParameter_t index ) { return GetPoseParameter( (int)index ); }
float ClampWithBias( PoseParameter_t index, float value, float base );
// Note, you must add all names to this static function in order for Init to work
static bool IsServerSideFlexController( char const *szName );
void Init( FlexWeight_t &index, const char *szName )
{
// Make this fatal!!!
if ( !IsServerSideFlexController( szName ) )
{
Error( "You forgot to add flex controller %s to list in CAI_BaseActor::IsServerSideFlexController().", szName );
}
index = (FlexWeight_t)FindFlexController( szName );
}
void Set( FlexWeight_t index, float flValue ) { SetFlexWeight( (LocalFlexController_t)index, flValue ); }
float Get( FlexWeight_t index ) { return GetFlexWeight( (LocalFlexController_t)index ); }
public:
CAI_BaseActor()
: m_fLatchedPositions( 0 ),
m_latchedEyeOrigin( vec3_origin ),
m_latchedEyeDirection( vec3_origin ),
m_latchedHeadDirection( vec3_origin ),
m_flBlinktime( 0 ),
m_hLookTarget( NULL ),
m_iszExpressionScene( NULL_STRING ),
m_iszIdleExpression( NULL_STRING ),
m_iszAlertExpression( NULL_STRING ),
m_iszCombatExpression( NULL_STRING ),
m_iszDeathExpression( NULL_STRING ),
m_iszExpressionOverride( NULL_STRING )
{
memset( m_flextarget, 0, 64 * sizeof( m_flextarget[0] ) );
}
~CAI_BaseActor()
{
delete m_pExpresser;
}
virtual void StudioFrameAdvance();
virtual void Precache();
virtual void SetModel( const char *szModelName );
virtual bool StartSceneEvent( CSceneEventInfo *info, CChoreoScene *scene, CChoreoEvent *event, CChoreoActor *actor, CBaseEntity *pTarget );
virtual bool ProcessSceneEvent( CSceneEventInfo *info, CChoreoScene *scene, CChoreoEvent *event );
virtual bool ClearSceneEvent( CSceneEventInfo *info, bool fastKill, bool canceled );
virtual bool CheckSceneEventCompletion( CSceneEventInfo *info, float currenttime, CChoreoScene *scene, CChoreoEvent *event );
Vector EyePosition( );
virtual Vector HeadDirection2D( void );
virtual Vector HeadDirection3D( void );
virtual Vector EyeDirection2D( void );
virtual Vector EyeDirection3D( void );
CBaseEntity *GetLooktarget() { return m_hLookTarget.Get(); }
virtual void OnNewLookTarget() {};
// CBaseFlex
virtual void SetViewtarget( const Vector &viewtarget );
// CAI_BaseNPC
virtual float PickLookTarget( bool bExcludePlayers = false, float minTime = 1.5, float maxTime = 2.5 );
virtual float PickLookTarget( CAI_InterestTarget &queue, bool bExcludePlayers = false, float minTime = 1.5, float maxTime = 2.5 );
virtual bool PickTacticalLookTarget( AILookTargetArgs_t *pArgs );
virtual bool PickRandomLookTarget( AILookTargetArgs_t *pArgs );
virtual void MakeRandomLookTarget( AILookTargetArgs_t *pArgs, float minTime, float maxTime );
virtual bool HasActiveLookTargets( void );
virtual void OnSelectedLookTarget( AILookTargetArgs_t *pArgs ) { return; }
virtual void ClearLookTarget( CBaseEntity *pTarget );
virtual void ExpireCurrentRandomLookTarget() { m_flNextRandomLookTime = gpGlobals->curtime - 0.1f; }
virtual void StartTaskRangeAttack1( const Task_t *pTask );
virtual void AddLookTarget( CBaseEntity *pTarget, float flImportance, float flDuration, float flRamp = 0.0 );
virtual void AddLookTarget( const Vector &vecPosition, float flImportance, float flDuration, float flRamp = 0.0 );
virtual void SetHeadDirection( const Vector &vTargetPos, float flInterval );
void UpdateBodyControl( void );
void UpdateHeadControl( const Vector &vHeadTarget, float flHeadInfluence );
virtual float GetHeadDebounce( void ) { return 0.3; } // how much of previous head turn to use
virtual void MaintainLookTargets( float flInterval );
virtual bool ValidEyeTarget(const Vector &lookTargetPos);
virtual bool ValidHeadTarget(const Vector &lookTargetPos);
virtual float HeadTargetValidity(const Vector &lookTargetPos);
virtual bool ShouldBruteForceFailedNav() { return true; }
void AccumulateIdealYaw( float flYaw, float flIntensity );
bool SetAccumulatedYawAndUpdate( void );
float m_flAccumYawDelta;
float m_flAccumYawScale;
//---------------------------------
virtual void OnStateChange( NPC_STATE OldState, NPC_STATE NewState );
//---------------------------------
virtual void PlayExpressionForState( NPC_STATE state );
virtual const char *SelectRandomExpressionForState( NPC_STATE state );
float SetExpression( const char * );
void ClearExpression();
const char * GetExpression();
enum
{
SCENE_AI_BLINK = 1,
SCENE_AI_HOLSTER,
SCENE_AI_UNHOLSTER,
SCENE_AI_AIM,
SCENE_AI_RANDOMLOOK,
SCENE_AI_RANDOMFACEFLEX,
SCENE_AI_RANDOMHEADFLEX,
SCENE_AI_IGNORECOLLISION,
SCENE_AI_DISABLEAI
};
DECLARE_DATADESC();
private:
enum
{
HUMANOID_LATCHED_EYE = 0x0001,
HUMANOID_LATCHED_HEAD = 0x0002,
HUMANOID_LATCHED_ALL = 0x0003,
};
//---------------------------------
void UpdateLatchedValues( void );
// Input handlers.
void InputSetExpressionOverride( inputdata_t &inputdata );
//---------------------------------
int m_fLatchedPositions;
Vector m_latchedEyeOrigin;
Vector m_latchedEyeDirection; // direction eyes are looking
Vector m_latchedHeadDirection; // direction head is aiming
void ClearHeadAdjustment( void );
Vector m_goalHeadDirection;
float m_goalHeadInfluence;
//---------------------------------
float m_goalSpineYaw;
float m_goalBodyYaw;
Vector m_goalHeadCorrection;
//---------------------------------
float m_flBlinktime;
EHANDLE m_hLookTarget;
CAI_InterestTarget m_lookQueue;
CAI_InterestTarget m_syntheticLookQueue;
CAI_InterestTarget m_randomLookQueue;
float m_flNextRandomLookTime; // FIXME: move to scene
//---------------------------------
string_t m_iszExpressionScene;
EHANDLE m_hExpressionSceneEnt;
float m_flNextRandomExpressionTime;
string_t m_iszExpressionOverride;
protected:
string_t m_iszIdleExpression;
string_t m_iszAlertExpression;
string_t m_iszCombatExpression;
string_t m_iszDeathExpression;
private:
//---------------------------------
//PoseParameter_t m_ParameterBodyTransY; // "body_trans_Y"
//PoseParameter_t m_ParameterBodyTransX; // "body_trans_X"
//PoseParameter_t m_ParameterBodyLift; // "body_lift"
PoseParameter_t m_ParameterBodyYaw; // "body_yaw"
//PoseParameter_t m_ParameterBodyPitch; // "body_pitch"
//PoseParameter_t m_ParameterBodyRoll; // "body_roll"
PoseParameter_t m_ParameterSpineYaw; // "spine_yaw"
//PoseParameter_t m_ParameterSpinePitch; // "spine_pitch"
//PoseParameter_t m_ParameterSpineRoll; // "spine_roll"
PoseParameter_t m_ParameterNeckTrans; // "neck_trans"
PoseParameter_t m_ParameterHeadYaw; // "head_yaw"
PoseParameter_t m_ParameterHeadPitch; // "head_pitch"
PoseParameter_t m_ParameterHeadRoll; // "head_roll"
//FlexWeight_t m_FlexweightMoveRightLeft; // "move_rightleft"
//FlexWeight_t m_FlexweightMoveForwardBack;// "move_forwardback"
//FlexWeight_t m_FlexweightMoveUpDown; // "move_updown"
FlexWeight_t m_FlexweightBodyRightLeft; // "body_rightleft"
//FlexWeight_t m_FlexweightBodyUpDown; // "body_updown"
//FlexWeight_t m_FlexweightBodyTilt; // "body_tilt"
FlexWeight_t m_FlexweightChestRightLeft; // "chest_rightleft"
//FlexWeight_t m_FlexweightChestUpDown; // "chest_updown"
//FlexWeight_t m_FlexweightChestTilt; // "chest_tilt"
FlexWeight_t m_FlexweightHeadForwardBack;// "head_forwardback"
FlexWeight_t m_FlexweightHeadRightLeft; // "head_rightleft"
FlexWeight_t m_FlexweightHeadUpDown; // "head_updown"
FlexWeight_t m_FlexweightHeadTilt; // "head_tilt"
PoseParameter_t m_ParameterGestureHeight; // "gesture_height"
PoseParameter_t m_ParameterGestureWidth; // "gesture_width"
FlexWeight_t m_FlexweightGestureUpDown; // "gesture_updown"
FlexWeight_t m_FlexweightGestureRightLeft; // "gesture_rightleft"
private:
//---------------------------------
bool RandomFaceFlex( CSceneEventInfo *info, CChoreoScene *scene, CChoreoEvent *event );
bool RandomHeadFlex( CSceneEventInfo *info, CChoreoScene *scene, CChoreoEvent *event );
float m_flextarget[64];
public:
virtual bool UseSemaphore( void );
protected:
bool m_bDontUseSemaphore;
public:
//---------------------------------
//
// Speech support
//
virtual CAI_Expresser *GetExpresser();
protected:
bool CreateComponents();
virtual CAI_Expresser *CreateExpresser();
private:
//---------------------------------
CAI_Expresser *m_pExpresser;
};
//-----------------------------------------------------------------------------
#endif // AI_BASEACTOR_H
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Hooks and classes for the support of humanoid NPCs with
// groovy facial animation capabilities, aka, "Actors"
//
//=============================================================================//
#ifndef AI_BASEACTOR_H
#define AI_BASEACTOR_H
#include "ai_basehumanoid.h"
#include "ai_speech.h"
#include "AI_Interest_Target.h"
#include <limits.h>
#if defined( _WIN32 )
#pragma once
#endif
//-----------------------------------------------------------------------------
// CAI_BaseActor
//
// Purpose: The base class for all head/body/eye expressive NPCS.
//
//-----------------------------------------------------------------------------
enum PoseParameter_t { POSE_END=INT_MAX };
enum FlexWeight_t { FLEX_END=INT_MAX };
struct AILookTargetArgs_t
{
EHANDLE hTarget;
Vector vTarget;
float flDuration;
float flInfluence;
float flRamp;
bool bExcludePlayers;
CAI_InterestTarget *pQueue;
};
class CAI_BaseActor : public CAI_ExpresserHost<CAI_BaseHumanoid>
{
DECLARE_CLASS( CAI_BaseActor, CAI_ExpresserHost<CAI_BaseHumanoid> );
//friend CPoseParameter;
//friend CFlexWeight;
public:
// FIXME: this method is lame, isn't there some sort of template thing that would get rid of the Outer pointer?
void Init( PoseParameter_t &index, const char *szName ) { index = (PoseParameter_t)LookupPoseParameter( szName ); };
void Set( PoseParameter_t index, float flValue ) { SetPoseParameter( (int)index, flValue ); }
float Get( PoseParameter_t index ) { return GetPoseParameter( (int)index ); }
float ClampWithBias( PoseParameter_t index, float value, float base );
// Note, you must add all names to this static function in order for Init to work
static bool IsServerSideFlexController( char const *szName );
void Init( FlexWeight_t &index, const char *szName )
{
// Make this fatal!!!
if ( !IsServerSideFlexController( szName ) )
{
Error( "You forgot to add flex controller %s to list in CAI_BaseActor::IsServerSideFlexController().", szName );
}
index = (FlexWeight_t)FindFlexController( szName );
}
void Set( FlexWeight_t index, float flValue ) { SetFlexWeight( (LocalFlexController_t)index, flValue ); }
float Get( FlexWeight_t index ) { return GetFlexWeight( (LocalFlexController_t)index ); }
public:
CAI_BaseActor()
: m_fLatchedPositions( 0 ),
m_latchedEyeOrigin( vec3_origin ),
m_latchedEyeDirection( vec3_origin ),
m_latchedHeadDirection( vec3_origin ),
m_flBlinktime( 0 ),
m_hLookTarget( NULL ),
m_iszExpressionScene( NULL_STRING ),
m_iszIdleExpression( NULL_STRING ),
m_iszAlertExpression( NULL_STRING ),
m_iszCombatExpression( NULL_STRING ),
m_iszDeathExpression( NULL_STRING ),
m_iszExpressionOverride( NULL_STRING )
{
memset( m_flextarget, 0, 64 * sizeof( m_flextarget[0] ) );
}
~CAI_BaseActor()
{
delete m_pExpresser;
}
virtual void StudioFrameAdvance();
virtual void Precache();
virtual void SetModel( const char *szModelName );
virtual bool StartSceneEvent( CSceneEventInfo *info, CChoreoScene *scene, CChoreoEvent *event, CChoreoActor *actor, CBaseEntity *pTarget );
virtual bool ProcessSceneEvent( CSceneEventInfo *info, CChoreoScene *scene, CChoreoEvent *event );
virtual bool ClearSceneEvent( CSceneEventInfo *info, bool fastKill, bool canceled );
virtual bool CheckSceneEventCompletion( CSceneEventInfo *info, float currenttime, CChoreoScene *scene, CChoreoEvent *event );
Vector EyePosition( );
virtual Vector HeadDirection2D( void );
virtual Vector HeadDirection3D( void );
virtual Vector EyeDirection2D( void );
virtual Vector EyeDirection3D( void );
CBaseEntity *GetLooktarget() { return m_hLookTarget.Get(); }
virtual void OnNewLookTarget() {};
// CBaseFlex
virtual void SetViewtarget( const Vector &viewtarget );
// CAI_BaseNPC
virtual float PickLookTarget( bool bExcludePlayers = false, float minTime = 1.5, float maxTime = 2.5 );
virtual float PickLookTarget( CAI_InterestTarget &queue, bool bExcludePlayers = false, float minTime = 1.5, float maxTime = 2.5 );
virtual bool PickTacticalLookTarget( AILookTargetArgs_t *pArgs );
virtual bool PickRandomLookTarget( AILookTargetArgs_t *pArgs );
virtual void MakeRandomLookTarget( AILookTargetArgs_t *pArgs, float minTime, float maxTime );
virtual bool HasActiveLookTargets( void );
virtual void OnSelectedLookTarget( AILookTargetArgs_t *pArgs ) { return; }
virtual void ClearLookTarget( CBaseEntity *pTarget );
virtual void ExpireCurrentRandomLookTarget() { m_flNextRandomLookTime = gpGlobals->curtime - 0.1f; }
virtual void StartTaskRangeAttack1( const Task_t *pTask );
virtual void AddLookTarget( CBaseEntity *pTarget, float flImportance, float flDuration, float flRamp = 0.0 );
virtual void AddLookTarget( const Vector &vecPosition, float flImportance, float flDuration, float flRamp = 0.0 );
virtual void SetHeadDirection( const Vector &vTargetPos, float flInterval );
void UpdateBodyControl( void );
void UpdateHeadControl( const Vector &vHeadTarget, float flHeadInfluence );
virtual float GetHeadDebounce( void ) { return 0.3; } // how much of previous head turn to use
virtual void MaintainLookTargets( float flInterval );
virtual bool ValidEyeTarget(const Vector &lookTargetPos);
virtual bool ValidHeadTarget(const Vector &lookTargetPos);
virtual float HeadTargetValidity(const Vector &lookTargetPos);
virtual bool ShouldBruteForceFailedNav() { return true; }
void AccumulateIdealYaw( float flYaw, float flIntensity );
bool SetAccumulatedYawAndUpdate( void );
float m_flAccumYawDelta;
float m_flAccumYawScale;
//---------------------------------
virtual void OnStateChange( NPC_STATE OldState, NPC_STATE NewState );
//---------------------------------
virtual void PlayExpressionForState( NPC_STATE state );
virtual const char *SelectRandomExpressionForState( NPC_STATE state );
float SetExpression( const char * );
void ClearExpression();
const char * GetExpression();
enum
{
SCENE_AI_BLINK = 1,
SCENE_AI_HOLSTER,
SCENE_AI_UNHOLSTER,
SCENE_AI_AIM,
SCENE_AI_RANDOMLOOK,
SCENE_AI_RANDOMFACEFLEX,
SCENE_AI_RANDOMHEADFLEX,
SCENE_AI_IGNORECOLLISION,
SCENE_AI_DISABLEAI
};
DECLARE_DATADESC();
private:
enum
{
HUMANOID_LATCHED_EYE = 0x0001,
HUMANOID_LATCHED_HEAD = 0x0002,
HUMANOID_LATCHED_ALL = 0x0003,
};
//---------------------------------
void UpdateLatchedValues( void );
// Input handlers.
void InputSetExpressionOverride( inputdata_t &inputdata );
//---------------------------------
int m_fLatchedPositions;
Vector m_latchedEyeOrigin;
Vector m_latchedEyeDirection; // direction eyes are looking
Vector m_latchedHeadDirection; // direction head is aiming
void ClearHeadAdjustment( void );
Vector m_goalHeadDirection;
float m_goalHeadInfluence;
//---------------------------------
float m_goalSpineYaw;
float m_goalBodyYaw;
Vector m_goalHeadCorrection;
//---------------------------------
float m_flBlinktime;
EHANDLE m_hLookTarget;
CAI_InterestTarget m_lookQueue;
CAI_InterestTarget m_syntheticLookQueue;
CAI_InterestTarget m_randomLookQueue;
float m_flNextRandomLookTime; // FIXME: move to scene
//---------------------------------
string_t m_iszExpressionScene;
EHANDLE m_hExpressionSceneEnt;
float m_flNextRandomExpressionTime;
string_t m_iszExpressionOverride;
protected:
string_t m_iszIdleExpression;
string_t m_iszAlertExpression;
string_t m_iszCombatExpression;
string_t m_iszDeathExpression;
private:
//---------------------------------
//PoseParameter_t m_ParameterBodyTransY; // "body_trans_Y"
//PoseParameter_t m_ParameterBodyTransX; // "body_trans_X"
//PoseParameter_t m_ParameterBodyLift; // "body_lift"
PoseParameter_t m_ParameterBodyYaw; // "body_yaw"
//PoseParameter_t m_ParameterBodyPitch; // "body_pitch"
//PoseParameter_t m_ParameterBodyRoll; // "body_roll"
PoseParameter_t m_ParameterSpineYaw; // "spine_yaw"
//PoseParameter_t m_ParameterSpinePitch; // "spine_pitch"
//PoseParameter_t m_ParameterSpineRoll; // "spine_roll"
PoseParameter_t m_ParameterNeckTrans; // "neck_trans"
PoseParameter_t m_ParameterHeadYaw; // "head_yaw"
PoseParameter_t m_ParameterHeadPitch; // "head_pitch"
PoseParameter_t m_ParameterHeadRoll; // "head_roll"
//FlexWeight_t m_FlexweightMoveRightLeft; // "move_rightleft"
//FlexWeight_t m_FlexweightMoveForwardBack;// "move_forwardback"
//FlexWeight_t m_FlexweightMoveUpDown; // "move_updown"
FlexWeight_t m_FlexweightBodyRightLeft; // "body_rightleft"
//FlexWeight_t m_FlexweightBodyUpDown; // "body_updown"
//FlexWeight_t m_FlexweightBodyTilt; // "body_tilt"
FlexWeight_t m_FlexweightChestRightLeft; // "chest_rightleft"
//FlexWeight_t m_FlexweightChestUpDown; // "chest_updown"
//FlexWeight_t m_FlexweightChestTilt; // "chest_tilt"
FlexWeight_t m_FlexweightHeadForwardBack;// "head_forwardback"
FlexWeight_t m_FlexweightHeadRightLeft; // "head_rightleft"
FlexWeight_t m_FlexweightHeadUpDown; // "head_updown"
FlexWeight_t m_FlexweightHeadTilt; // "head_tilt"
PoseParameter_t m_ParameterGestureHeight; // "gesture_height"
PoseParameter_t m_ParameterGestureWidth; // "gesture_width"
FlexWeight_t m_FlexweightGestureUpDown; // "gesture_updown"
FlexWeight_t m_FlexweightGestureRightLeft; // "gesture_rightleft"
private:
//---------------------------------
bool RandomFaceFlex( CSceneEventInfo *info, CChoreoScene *scene, CChoreoEvent *event );
bool RandomHeadFlex( CSceneEventInfo *info, CChoreoScene *scene, CChoreoEvent *event );
float m_flextarget[64];
public:
virtual bool UseSemaphore( void );
protected:
bool m_bDontUseSemaphore;
public:
//---------------------------------
//
// Speech support
//
virtual CAI_Expresser *GetExpresser();
protected:
bool CreateComponents();
virtual CAI_Expresser *CreateExpresser();
private:
//---------------------------------
CAI_Expresser *m_pExpresser;
};
//-----------------------------------------------------------------------------
#endif // AI_BASEACTOR_H

View File

@@ -1,335 +1,335 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#include "cbase.h"
#include "BasePropDoor.h"
#include "ai_basehumanoid.h"
#include "ai_blended_movement.h"
#include "ai_navigator.h"
#include "ai_memory.h"
#ifdef HL2_DLL
#include "ai_interactions.h"
#endif
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
//-----------------------------------------------------------------------------
// Purpose: This is a generic function (to be implemented by sub-classes) to
// handle specific interactions between different types of characters
// (For example the barnacle grabbing an NPC)
// Input : Constant for the type of interaction
// Output : true - if sub-class has a response for the interaction
// false - if sub-class has no response
//-----------------------------------------------------------------------------
bool CAI_BaseHumanoid::HandleInteraction(int interactionType, void *data, CBaseCombatCharacter* sourceEnt)
{
#ifdef HL2_DLL
// Annoying to ifdef this out. Copy it into all the HL2 specific humanoid NPC's instead?
if ( interactionType == g_interactionBarnacleVictimDangle )
{
// Force choosing of a new schedule
ClearSchedule( "Grabbed by a barnacle" );
return true;
}
else if ( interactionType == g_interactionBarnacleVictimReleased )
{
// Destroy the entity, the barnacle is going to use the ragdoll that it is releasing
// as the corpse.
UTIL_Remove( this );
return true;
}
#endif
return BaseClass::HandleInteraction( interactionType, data, sourceEnt);
}
//-----------------------------------------------------------------------------
// Purpose: check ammo
//-----------------------------------------------------------------------------
void CAI_BaseHumanoid::CheckAmmo( void )
{
BaseClass::CheckAmmo();
// FIXME: put into GatherConditions()?
// FIXME: why isn't this a baseclass function?
if (!GetActiveWeapon())
return;
// Don't do this while holstering / unholstering
if ( IsWeaponStateChanging() )
return;
if (GetActiveWeapon()->UsesPrimaryAmmo())
{
if (!GetActiveWeapon()->HasPrimaryAmmo() )
{
SetCondition(COND_NO_PRIMARY_AMMO);
}
else if (GetActiveWeapon()->UsesClipsForAmmo1() && GetActiveWeapon()->Clip1() < (GetActiveWeapon()->GetMaxClip1() / 4 + 1))
{
// don't check for low ammo if you're near the max range of the weapon
SetCondition(COND_LOW_PRIMARY_AMMO);
}
}
if (!GetActiveWeapon()->HasSecondaryAmmo() )
{
if ( GetActiveWeapon()->UsesClipsForAmmo2() )
{
SetCondition(COND_NO_SECONDARY_AMMO);
}
}
}
//-----------------------------------------------------------------------------
// TASK_RANGE_ATTACK1
//-----------------------------------------------------------------------------
void CAI_BaseHumanoid::BuildScheduleTestBits( )
{
BaseClass::BuildScheduleTestBits();
if ( CapabilitiesGet() & bits_CAP_USE_SHOT_REGULATOR )
{
if ( GetShotRegulator()->IsInRestInterval() )
{
ClearCustomInterruptCondition( COND_CAN_RANGE_ATTACK1 );
}
}
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
static bool IsSmall( CBaseEntity *pBlocker )
{
CCollisionProperty *pCollisionProp = pBlocker->CollisionProp();
int nSmaller = 0;
Vector vecSize = pCollisionProp->OBBMaxs() - pCollisionProp->OBBMins();
for ( int i = 0; i < 3; i++ )
{
if ( vecSize[i] >= 42 )
return false;
if ( vecSize[i] <= 30 )
{
nSmaller++;
}
}
return ( nSmaller >= 2 );
}
bool CAI_BaseHumanoid::OnMoveBlocked( AIMoveResult_t *pResult )
{
if ( *pResult != AIMR_BLOCKED_NPC && GetNavigator()->GetBlockingEntity() && !GetNavigator()->GetBlockingEntity()->IsNPC() )
{
CBaseEntity *pBlocker = GetNavigator()->GetBlockingEntity();
float massBonus = ( IsNavigationUrgent() ) ? 40.0 : 0;
if ( pBlocker->GetMoveType() == MOVETYPE_VPHYSICS &&
pBlocker != GetGroundEntity() &&
!pBlocker->IsNavIgnored() &&
!dynamic_cast<CBasePropDoor *>(pBlocker) &&
pBlocker->VPhysicsGetObject() &&
pBlocker->VPhysicsGetObject()->IsMoveable() &&
( pBlocker->VPhysicsGetObject()->GetMass() <= 35.0 + massBonus + 0.1 ||
( pBlocker->VPhysicsGetObject()->GetMass() <= 50.0 + massBonus + 0.1 && IsSmall( pBlocker ) ) ) )
{
DbgNavMsg1( this, "Setting ignore on object %s", pBlocker->GetDebugName() );
pBlocker->SetNavIgnore( 2.5 );
}
#if 0
else
{
CPhysicsProp *pProp = dynamic_cast<CPhysicsProp*>( pBlocker );
if ( pProp && pProp->GetHealth() && pProp->GetExplosiveDamage() == 0.0 && GetActiveWeapon() && !GetActiveWeapon()->ClassMatches( "weapon_rpg" ) )
{
Msg( "!\n" );
// Destroy!
}
}
#endif
}
return BaseClass::OnMoveBlocked( pResult );
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
#define SNEAK_ATTACK_DIST 360.0f // 30 feet
void CAI_BaseHumanoid::TraceAttack( const CTakeDamageInfo &info, const Vector &vecDir, trace_t *ptr, CDmgAccumulator *pAccumulator )
{
bool bSneakAttacked = false;
if( ptr->hitgroup == HITGROUP_HEAD )
{
if ( info.GetAttacker() && info.GetAttacker()->IsPlayer() && info.GetAttacker() != GetEnemy() && !IsInAScript() )
{
// Shot in the head by a player I've never seen. In this case the player
// has gotten the drop on this enemy and such an attack is always lethal (at close range)
bSneakAttacked = true;
AIEnemiesIter_t iter;
for( AI_EnemyInfo_t *pMemory = GetEnemies()->GetFirst(&iter); pMemory != NULL; pMemory = GetEnemies()->GetNext(&iter) )
{
if ( pMemory->hEnemy == info.GetAttacker() )
{
bSneakAttacked = false;
break;
}
}
float flDist;
flDist = (info.GetAttacker()->GetAbsOrigin() - GetAbsOrigin()).Length();
if( flDist > SNEAK_ATTACK_DIST )
{
bSneakAttacked = false;
}
}
}
if( bSneakAttacked )
{
CTakeDamageInfo newInfo = info;
newInfo.SetDamage( GetHealth() );
BaseClass::TraceAttack( newInfo, vecDir, ptr, pAccumulator );
return;
}
BaseClass::TraceAttack( info, vecDir, ptr, pAccumulator );
}
//-----------------------------------------------------------------------------
// TASK_RANGE_ATTACK1
//-----------------------------------------------------------------------------
void CAI_BaseHumanoid::StartTaskRangeAttack1( const Task_t *pTask )
{
if ( ( CapabilitiesGet() & bits_CAP_USE_SHOT_REGULATOR ) == 0 )
{
BaseClass::StartTask( pTask );
return;
}
// Can't shoot if we're in the rest interval; fail the schedule
if ( GetShotRegulator()->IsInRestInterval() )
{
TaskFail( "Shot regulator in rest interval" );
return;
}
if ( GetShotRegulator()->ShouldShoot() )
{
OnRangeAttack1();
ResetIdealActivity( ACT_RANGE_ATTACK1 );
}
else
{
// This can happen if we start while in the middle of a burst
// which shouldn't happen, but given the chaotic nature of our AI system,
// does occasionally happen.
ResetIdealActivity( ACT_IDLE_ANGRY );
}
}
//-----------------------------------------------------------------------------
// Starting Tasks
//-----------------------------------------------------------------------------
void CAI_BaseHumanoid::StartTask( const Task_t *pTask )
{
switch( pTask->iTask )
{
case TASK_RANGE_ATTACK1:
StartTaskRangeAttack1( pTask );
break;
default:
BaseClass::StartTask( pTask );
}
}
//-----------------------------------------------------------------------------
// TASK_RANGE_ATTACK1 / TASK_RANGE_ATTACK2 / etc.
//-----------------------------------------------------------------------------
void CAI_BaseHumanoid::RunTaskRangeAttack1( const Task_t *pTask )
{
if ( ( CapabilitiesGet() & bits_CAP_USE_SHOT_REGULATOR ) == 0 )
{
BaseClass::RunTask( pTask );
return;
}
AutoMovement( );
Vector vecEnemyLKP = GetEnemyLKP();
// If our enemy was killed, but I'm not done animating, the last known position comes
// back as the origin and makes the me face the world origin if my attack schedule
// doesn't break when my enemy dies. (sjb)
if( vecEnemyLKP != vec3_origin )
{
if ( ( pTask->iTask == TASK_RANGE_ATTACK1 || pTask->iTask == TASK_RELOAD ) &&
( CapabilitiesGet() & bits_CAP_AIM_GUN ) &&
FInAimCone( vecEnemyLKP ) )
{
// Arms will aim, so leave body yaw as is
GetMotor()->SetIdealYawAndUpdate( GetMotor()->GetIdealYaw(), AI_KEEP_YAW_SPEED );
}
else
{
GetMotor()->SetIdealYawToTargetAndUpdate( vecEnemyLKP, AI_KEEP_YAW_SPEED );
}
}
if ( IsActivityFinished() )
{
if ( !GetEnemy() || !GetEnemy()->IsAlive() )
{
TaskComplete();
return;
}
if ( !GetShotRegulator()->IsInRestInterval() )
{
if ( GetShotRegulator()->ShouldShoot() )
{
OnRangeAttack1();
ResetIdealActivity( ACT_RANGE_ATTACK1 );
}
return;
}
TaskComplete();
}
}
//-----------------------------------------------------------------------------
// Running Tasks
//-----------------------------------------------------------------------------
void CAI_BaseHumanoid::RunTask( const Task_t *pTask )
{
switch( pTask->iTask )
{
case TASK_RANGE_ATTACK1:
RunTaskRangeAttack1( pTask );
break;
default:
BaseClass::RunTask( pTask );
}
}
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#include "cbase.h"
#include "BasePropDoor.h"
#include "ai_basehumanoid.h"
#include "ai_blended_movement.h"
#include "ai_navigator.h"
#include "ai_memory.h"
#ifdef HL2_DLL
#include "ai_interactions.h"
#endif
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
//-----------------------------------------------------------------------------
// Purpose: This is a generic function (to be implemented by sub-classes) to
// handle specific interactions between different types of characters
// (For example the barnacle grabbing an NPC)
// Input : Constant for the type of interaction
// Output : true - if sub-class has a response for the interaction
// false - if sub-class has no response
//-----------------------------------------------------------------------------
bool CAI_BaseHumanoid::HandleInteraction(int interactionType, void *data, CBaseCombatCharacter* sourceEnt)
{
#ifdef HL2_DLL
// Annoying to ifdef this out. Copy it into all the HL2 specific humanoid NPC's instead?
if ( interactionType == g_interactionBarnacleVictimDangle )
{
// Force choosing of a new schedule
ClearSchedule( "Grabbed by a barnacle" );
return true;
}
else if ( interactionType == g_interactionBarnacleVictimReleased )
{
// Destroy the entity, the barnacle is going to use the ragdoll that it is releasing
// as the corpse.
UTIL_Remove( this );
return true;
}
#endif
return BaseClass::HandleInteraction( interactionType, data, sourceEnt);
}
//-----------------------------------------------------------------------------
// Purpose: check ammo
//-----------------------------------------------------------------------------
void CAI_BaseHumanoid::CheckAmmo( void )
{
BaseClass::CheckAmmo();
// FIXME: put into GatherConditions()?
// FIXME: why isn't this a baseclass function?
if (!GetActiveWeapon())
return;
// Don't do this while holstering / unholstering
if ( IsWeaponStateChanging() )
return;
if (GetActiveWeapon()->UsesPrimaryAmmo())
{
if (!GetActiveWeapon()->HasPrimaryAmmo() )
{
SetCondition(COND_NO_PRIMARY_AMMO);
}
else if (GetActiveWeapon()->UsesClipsForAmmo1() && GetActiveWeapon()->Clip1() < (GetActiveWeapon()->GetMaxClip1() / 4 + 1))
{
// don't check for low ammo if you're near the max range of the weapon
SetCondition(COND_LOW_PRIMARY_AMMO);
}
}
if (!GetActiveWeapon()->HasSecondaryAmmo() )
{
if ( GetActiveWeapon()->UsesClipsForAmmo2() )
{
SetCondition(COND_NO_SECONDARY_AMMO);
}
}
}
//-----------------------------------------------------------------------------
// TASK_RANGE_ATTACK1
//-----------------------------------------------------------------------------
void CAI_BaseHumanoid::BuildScheduleTestBits( )
{
BaseClass::BuildScheduleTestBits();
if ( CapabilitiesGet() & bits_CAP_USE_SHOT_REGULATOR )
{
if ( GetShotRegulator()->IsInRestInterval() )
{
ClearCustomInterruptCondition( COND_CAN_RANGE_ATTACK1 );
}
}
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
static bool IsSmall( CBaseEntity *pBlocker )
{
CCollisionProperty *pCollisionProp = pBlocker->CollisionProp();
int nSmaller = 0;
Vector vecSize = pCollisionProp->OBBMaxs() - pCollisionProp->OBBMins();
for ( int i = 0; i < 3; i++ )
{
if ( vecSize[i] >= 42 )
return false;
if ( vecSize[i] <= 30 )
{
nSmaller++;
}
}
return ( nSmaller >= 2 );
}
bool CAI_BaseHumanoid::OnMoveBlocked( AIMoveResult_t *pResult )
{
if ( *pResult != AIMR_BLOCKED_NPC && GetNavigator()->GetBlockingEntity() && !GetNavigator()->GetBlockingEntity()->IsNPC() )
{
CBaseEntity *pBlocker = GetNavigator()->GetBlockingEntity();
float massBonus = ( IsNavigationUrgent() ) ? 40.0 : 0;
if ( pBlocker->GetMoveType() == MOVETYPE_VPHYSICS &&
pBlocker != GetGroundEntity() &&
!pBlocker->IsNavIgnored() &&
!dynamic_cast<CBasePropDoor *>(pBlocker) &&
pBlocker->VPhysicsGetObject() &&
pBlocker->VPhysicsGetObject()->IsMoveable() &&
( pBlocker->VPhysicsGetObject()->GetMass() <= 35.0 + massBonus + 0.1 ||
( pBlocker->VPhysicsGetObject()->GetMass() <= 50.0 + massBonus + 0.1 && IsSmall( pBlocker ) ) ) )
{
DbgNavMsg1( this, "Setting ignore on object %s", pBlocker->GetDebugName() );
pBlocker->SetNavIgnore( 2.5 );
}
#if 0
else
{
CPhysicsProp *pProp = dynamic_cast<CPhysicsProp*>( pBlocker );
if ( pProp && pProp->GetHealth() && pProp->GetExplosiveDamage() == 0.0 && GetActiveWeapon() && !GetActiveWeapon()->ClassMatches( "weapon_rpg" ) )
{
Msg( "!\n" );
// Destroy!
}
}
#endif
}
return BaseClass::OnMoveBlocked( pResult );
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
#define SNEAK_ATTACK_DIST 360.0f // 30 feet
void CAI_BaseHumanoid::TraceAttack( const CTakeDamageInfo &info, const Vector &vecDir, trace_t *ptr, CDmgAccumulator *pAccumulator )
{
bool bSneakAttacked = false;
if( ptr->hitgroup == HITGROUP_HEAD )
{
if ( info.GetAttacker() && info.GetAttacker()->IsPlayer() && info.GetAttacker() != GetEnemy() && !IsInAScript() )
{
// Shot in the head by a player I've never seen. In this case the player
// has gotten the drop on this enemy and such an attack is always lethal (at close range)
bSneakAttacked = true;
AIEnemiesIter_t iter;
for( AI_EnemyInfo_t *pMemory = GetEnemies()->GetFirst(&iter); pMemory != NULL; pMemory = GetEnemies()->GetNext(&iter) )
{
if ( pMemory->hEnemy == info.GetAttacker() )
{
bSneakAttacked = false;
break;
}
}
float flDist;
flDist = (info.GetAttacker()->GetAbsOrigin() - GetAbsOrigin()).Length();
if( flDist > SNEAK_ATTACK_DIST )
{
bSneakAttacked = false;
}
}
}
if( bSneakAttacked )
{
CTakeDamageInfo newInfo = info;
newInfo.SetDamage( GetHealth() );
BaseClass::TraceAttack( newInfo, vecDir, ptr, pAccumulator );
return;
}
BaseClass::TraceAttack( info, vecDir, ptr, pAccumulator );
}
//-----------------------------------------------------------------------------
// TASK_RANGE_ATTACK1
//-----------------------------------------------------------------------------
void CAI_BaseHumanoid::StartTaskRangeAttack1( const Task_t *pTask )
{
if ( ( CapabilitiesGet() & bits_CAP_USE_SHOT_REGULATOR ) == 0 )
{
BaseClass::StartTask( pTask );
return;
}
// Can't shoot if we're in the rest interval; fail the schedule
if ( GetShotRegulator()->IsInRestInterval() )
{
TaskFail( "Shot regulator in rest interval" );
return;
}
if ( GetShotRegulator()->ShouldShoot() )
{
OnRangeAttack1();
ResetIdealActivity( ACT_RANGE_ATTACK1 );
}
else
{
// This can happen if we start while in the middle of a burst
// which shouldn't happen, but given the chaotic nature of our AI system,
// does occasionally happen.
ResetIdealActivity( ACT_IDLE_ANGRY );
}
}
//-----------------------------------------------------------------------------
// Starting Tasks
//-----------------------------------------------------------------------------
void CAI_BaseHumanoid::StartTask( const Task_t *pTask )
{
switch( pTask->iTask )
{
case TASK_RANGE_ATTACK1:
StartTaskRangeAttack1( pTask );
break;
default:
BaseClass::StartTask( pTask );
}
}
//-----------------------------------------------------------------------------
// TASK_RANGE_ATTACK1 / TASK_RANGE_ATTACK2 / etc.
//-----------------------------------------------------------------------------
void CAI_BaseHumanoid::RunTaskRangeAttack1( const Task_t *pTask )
{
if ( ( CapabilitiesGet() & bits_CAP_USE_SHOT_REGULATOR ) == 0 )
{
BaseClass::RunTask( pTask );
return;
}
AutoMovement( );
Vector vecEnemyLKP = GetEnemyLKP();
// If our enemy was killed, but I'm not done animating, the last known position comes
// back as the origin and makes the me face the world origin if my attack schedule
// doesn't break when my enemy dies. (sjb)
if( vecEnemyLKP != vec3_origin )
{
if ( ( pTask->iTask == TASK_RANGE_ATTACK1 || pTask->iTask == TASK_RELOAD ) &&
( CapabilitiesGet() & bits_CAP_AIM_GUN ) &&
FInAimCone( vecEnemyLKP ) )
{
// Arms will aim, so leave body yaw as is
GetMotor()->SetIdealYawAndUpdate( GetMotor()->GetIdealYaw(), AI_KEEP_YAW_SPEED );
}
else
{
GetMotor()->SetIdealYawToTargetAndUpdate( vecEnemyLKP, AI_KEEP_YAW_SPEED );
}
}
if ( IsActivityFinished() )
{
if ( !GetEnemy() || !GetEnemy()->IsAlive() )
{
TaskComplete();
return;
}
if ( !GetShotRegulator()->IsInRestInterval() )
{
if ( GetShotRegulator()->ShouldShoot() )
{
OnRangeAttack1();
ResetIdealActivity( ACT_RANGE_ATTACK1 );
}
return;
}
TaskComplete();
}
}
//-----------------------------------------------------------------------------
// Running Tasks
//-----------------------------------------------------------------------------
void CAI_BaseHumanoid::RunTask( const Task_t *pTask )
{
switch( pTask->iTask )
{
case TASK_RANGE_ATTACK1:
RunTaskRangeAttack1( pTask );
break;
default:
BaseClass::RunTask( pTask );
}
}

View File

@@ -1,50 +1,50 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#ifndef AI_BASEHUMANOID_H
#define AI_BASEHUMANOID_H
#include "ai_behavior.h"
#include "ai_blended_movement.h"
//-----------------------------------------------------------------------------
// CLASS: CAI_BaseHumanoid
//-----------------------------------------------------------------------------
typedef CAI_BlendingHost< CAI_BehaviorHost<CAI_BaseNPC> > CAI_BaseHumanoidBase;
class CAI_BaseHumanoid : public CAI_BaseHumanoidBase
{
DECLARE_CLASS( CAI_BaseHumanoid, CAI_BaseHumanoidBase );
public:
bool HandleInteraction(int interactionType, void *data, CBaseCombatCharacter* sourceEnt);
// Tasks
virtual void StartTask( const Task_t *pTask );
virtual void RunTask( const Task_t *pTask );
virtual void BuildScheduleTestBits( );
// Navigation
bool OnMoveBlocked( AIMoveResult_t *pResult );
// Damage
void TraceAttack( const CTakeDamageInfo &info, const Vector &vecDir, trace_t *ptr, CDmgAccumulator *pAccumulator );
// Various start tasks
virtual void StartTaskRangeAttack1( const Task_t *pTask );
// Various run tasks
virtual void RunTaskRangeAttack1( const Task_t *pTask );
// Purpose: check ammo
virtual void CheckAmmo( void );
};
//-----------------------------------------------------------------------------
#endif
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#ifndef AI_BASEHUMANOID_H
#define AI_BASEHUMANOID_H
#include "ai_behavior.h"
#include "ai_blended_movement.h"
//-----------------------------------------------------------------------------
// CLASS: CAI_BaseHumanoid
//-----------------------------------------------------------------------------
typedef CAI_BlendingHost< CAI_BehaviorHost<CAI_BaseNPC> > CAI_BaseHumanoidBase;
class CAI_BaseHumanoid : public CAI_BaseHumanoidBase
{
DECLARE_CLASS( CAI_BaseHumanoid, CAI_BaseHumanoidBase );
public:
bool HandleInteraction(int interactionType, void *data, CBaseCombatCharacter* sourceEnt);
// Tasks
virtual void StartTask( const Task_t *pTask );
virtual void RunTask( const Task_t *pTask );
virtual void BuildScheduleTestBits( );
// Navigation
bool OnMoveBlocked( AIMoveResult_t *pResult );
// Damage
void TraceAttack( const CTakeDamageInfo &info, const Vector &vecDir, trace_t *ptr, CDmgAccumulator *pAccumulator );
// Various start tasks
virtual void StartTaskRangeAttack1( const Task_t *pTask );
// Various run tasks
virtual void RunTaskRangeAttack1( const Task_t *pTask );
// Purpose: check ammo
virtual void CheckAmmo( void );
};
//-----------------------------------------------------------------------------
#endif

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,263 +1,263 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Base class for many flying NPCs
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "ai_basenpc_flyer.h"
#include "ai_route.h"
#include "ai_navigator.h"
#include "ai_motor.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
BEGIN_DATADESC( CAI_BaseFlyingBot )
DEFINE_FIELD( m_vCurrentVelocity, FIELD_VECTOR),
DEFINE_FIELD( m_vCurrentAngularVelocity, FIELD_VECTOR ),
DEFINE_FIELD( m_vCurrentBanking, FIELD_VECTOR),
DEFINE_FIELD( m_vNoiseMod, FIELD_VECTOR),
DEFINE_FIELD( m_fHeadYaw, FIELD_FLOAT),
DEFINE_FIELD( m_vLastPatrolDir, FIELD_VECTOR),
END_DATADESC()
//------------------------------------------------------------------------------
// Purpose : Override to return correct velocity
// Input :
// Output :
//------------------------------------------------------------------------------
void CAI_BaseFlyingBot::GetVelocity(Vector *vVelocity, AngularImpulse *vAngVelocity)
{
if (vVelocity != NULL)
{
VectorCopy(m_vCurrentVelocity,*vVelocity);
}
if (vAngVelocity != NULL)
{
QAngle tmp = GetLocalAngularVelocity();
QAngleToAngularImpulse( tmp, *vAngVelocity );
}
}
//-----------------------------------------------------------------------------
// Purpose: Turn head yaw into facing direction
// Input :
// Output :
//-----------------------------------------------------------------------------
QAngle CAI_BaseFlyingBot::BodyAngles()
{
return QAngle(0,m_fHeadYaw,0);
}
//-----------------------------------------------------------------------------
// Purpose:
// Input :
// Output :
//-----------------------------------------------------------------------------
void CAI_BaseFlyingBot::TurnHeadToTarget(float flInterval, const Vector &MoveTarget )
{
float flDestYaw = VecToYaw( MoveTarget - GetLocalOrigin() );
float newYaw = AI_ClampYaw( GetHeadTurnRate() * 10.0f, m_fHeadYaw, flDestYaw, gpGlobals->curtime - GetLastThink() );
if ( newYaw != m_fHeadYaw )
{
m_fHeadYaw = newYaw;
}
// Set us to face that way
SetBoneController( 0, m_fHeadYaw );
}
//------------------------------------------------------------------------------
// Purpose :
// Input :
// Output :
//------------------------------------------------------------------------------
float CAI_BaseFlyingBot::MinGroundDist(void)
{
return 0;
}
//------------------------------------------------------------------------------
// Purpose :
// Input :
// Output :
//------------------------------------------------------------------------------
Vector CAI_BaseFlyingBot::VelocityToAvoidObstacles(float flInterval)
{
// --------------------------------
// Avoid banging into stuff
// --------------------------------
trace_t tr;
Vector vTravelDir = m_vCurrentVelocity*flInterval;
Vector endPos = GetAbsOrigin() + vTravelDir;
AI_TraceEntity( this, GetAbsOrigin(), endPos, MASK_NPCSOLID|CONTENTS_WATER, &tr );
if (tr.fraction != 1.0)
{
// Bounce off in normal
Vector vBounce = tr.plane.normal * 0.5 * m_vCurrentVelocity.Length();
return (vBounce);
}
// --------------------------------
// Try to remain above the ground.
// --------------------------------
float flMinGroundDist = MinGroundDist();
AI_TraceLine(GetAbsOrigin(), GetAbsOrigin() + Vector(0, 0, -flMinGroundDist),
MASK_NPCSOLID_BRUSHONLY|CONTENTS_WATER, this, COLLISION_GROUP_NONE, &tr);
if (tr.fraction < 1)
{
// Clamp veloctiy
if (tr.fraction < 0.1)
{
tr.fraction = 0.1;
}
return Vector(0, 0, 50/tr.fraction);
}
return vec3_origin;
}
//------------------------------------------------------------------------------
// Purpose :
// Input :
// Output :
//------------------------------------------------------------------------------
void CAI_BaseFlyingBot::StartTask( const Task_t *pTask )
{
switch (pTask->iTask)
{
// Skip as done via bone controller
case TASK_FACE_ENEMY:
{
TaskComplete();
break;
}
// Activity is just idle (have no run)
case TASK_RUN_PATH:
{
GetNavigator()->SetMovementActivity(ACT_IDLE);
TaskComplete();
break;
}
// Don't check for run/walk activity
case TASK_SCRIPT_RUN_TO_TARGET:
case TASK_SCRIPT_WALK_TO_TARGET:
{
if (GetTarget() == NULL)
{
TaskFail(FAIL_NO_TARGET);
}
else
{
if (!GetNavigator()->SetGoal( GOALTYPE_TARGETENT ) )
{
TaskFail(FAIL_NO_ROUTE);
GetNavigator()->ClearGoal();
}
}
TaskComplete();
break;
}
// Override to get more to get a directional path
case TASK_GET_PATH_TO_RANDOM_NODE:
{
if ( GetNavigator()->SetRandomGoal( pTask->flTaskData, m_vLastPatrolDir ) )
TaskComplete();
else
TaskFail(FAIL_NO_REACHABLE_NODE);
break;
}
default:
{
BaseClass::StartTask(pTask);
}
}
}
//------------------------------------------------------------------------------
void CAI_BaseFlyingBot::MoveToTarget(float flInterval, const Vector &MoveTarget)
{
Assert(0); // This must be overridden in the leaf classes
}
//------------------------------------------------------------------------------
AI_NavPathProgress_t CAI_BaseFlyingBot::ProgressFlyPath(
float flInterval,
const CBaseEntity *pNewTarget,
unsigned collisionMask,
bool bNewTrySimplify,
float strictPointTolerance)
{
AI_ProgressFlyPathParams_t params( collisionMask, strictPointTolerance );
params.SetCurrent( pNewTarget, bNewTrySimplify );
AI_NavPathProgress_t progress = GetNavigator()->ProgressFlyPath( params );
switch ( progress )
{
case AINPP_NO_CHANGE:
case AINPP_ADVANCED:
{
MoveToTarget(flInterval, GetNavigator()->GetCurWaypointPos());
break;
}
case AINPP_COMPLETE:
{
TaskMovementComplete();
break;
}
case AINPP_BLOCKED: // function is not supposed to test blocking, just simple path progression
default:
{
AssertMsg( 0, ( "Unexpected result" ) );
break;
}
}
return progress;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : *pTarget -
// &chasePosition -
//-----------------------------------------------------------------------------
void CAI_BaseFlyingBot::TranslateNavGoal( CBaseEntity *pTarget, Vector &chasePosition )
{
Assert( pTarget != NULL );
if ( pTarget == NULL )
{
chasePosition = vec3_origin;
return;
}
// Chase their eyes
chasePosition = pTarget->GetAbsOrigin() + pTarget->GetViewOffset();
}
//------------------------------------------------------------------------------
// Purpose :
// Input :
// Output :
//------------------------------------------------------------------------------
CAI_BaseFlyingBot::CAI_BaseFlyingBot()
{
#ifdef _DEBUG
m_vCurrentVelocity.Init();
m_vCurrentBanking.Init();
m_vLastPatrolDir.Init();
#endif
}
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Base class for many flying NPCs
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "ai_basenpc_flyer.h"
#include "ai_route.h"
#include "ai_navigator.h"
#include "ai_motor.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
BEGIN_DATADESC( CAI_BaseFlyingBot )
DEFINE_FIELD( m_vCurrentVelocity, FIELD_VECTOR),
DEFINE_FIELD( m_vCurrentAngularVelocity, FIELD_VECTOR ),
DEFINE_FIELD( m_vCurrentBanking, FIELD_VECTOR),
DEFINE_FIELD( m_vNoiseMod, FIELD_VECTOR),
DEFINE_FIELD( m_fHeadYaw, FIELD_FLOAT),
DEFINE_FIELD( m_vLastPatrolDir, FIELD_VECTOR),
END_DATADESC()
//------------------------------------------------------------------------------
// Purpose : Override to return correct velocity
// Input :
// Output :
//------------------------------------------------------------------------------
void CAI_BaseFlyingBot::GetVelocity(Vector *vVelocity, AngularImpulse *vAngVelocity)
{
if (vVelocity != NULL)
{
VectorCopy(m_vCurrentVelocity,*vVelocity);
}
if (vAngVelocity != NULL)
{
QAngle tmp = GetLocalAngularVelocity();
QAngleToAngularImpulse( tmp, *vAngVelocity );
}
}
//-----------------------------------------------------------------------------
// Purpose: Turn head yaw into facing direction
// Input :
// Output :
//-----------------------------------------------------------------------------
QAngle CAI_BaseFlyingBot::BodyAngles()
{
return QAngle(0,m_fHeadYaw,0);
}
//-----------------------------------------------------------------------------
// Purpose:
// Input :
// Output :
//-----------------------------------------------------------------------------
void CAI_BaseFlyingBot::TurnHeadToTarget(float flInterval, const Vector &MoveTarget )
{
float flDestYaw = VecToYaw( MoveTarget - GetLocalOrigin() );
float newYaw = AI_ClampYaw( GetHeadTurnRate() * 10.0f, m_fHeadYaw, flDestYaw, gpGlobals->curtime - GetLastThink() );
if ( newYaw != m_fHeadYaw )
{
m_fHeadYaw = newYaw;
}
// Set us to face that way
SetBoneController( 0, m_fHeadYaw );
}
//------------------------------------------------------------------------------
// Purpose :
// Input :
// Output :
//------------------------------------------------------------------------------
float CAI_BaseFlyingBot::MinGroundDist(void)
{
return 0;
}
//------------------------------------------------------------------------------
// Purpose :
// Input :
// Output :
//------------------------------------------------------------------------------
Vector CAI_BaseFlyingBot::VelocityToAvoidObstacles(float flInterval)
{
// --------------------------------
// Avoid banging into stuff
// --------------------------------
trace_t tr;
Vector vTravelDir = m_vCurrentVelocity*flInterval;
Vector endPos = GetAbsOrigin() + vTravelDir;
AI_TraceEntity( this, GetAbsOrigin(), endPos, MASK_NPCSOLID|CONTENTS_WATER, &tr );
if (tr.fraction != 1.0)
{
// Bounce off in normal
Vector vBounce = tr.plane.normal * 0.5 * m_vCurrentVelocity.Length();
return (vBounce);
}
// --------------------------------
// Try to remain above the ground.
// --------------------------------
float flMinGroundDist = MinGroundDist();
AI_TraceLine(GetAbsOrigin(), GetAbsOrigin() + Vector(0, 0, -flMinGroundDist),
MASK_NPCSOLID_BRUSHONLY|CONTENTS_WATER, this, COLLISION_GROUP_NONE, &tr);
if (tr.fraction < 1)
{
// Clamp veloctiy
if (tr.fraction < 0.1)
{
tr.fraction = 0.1;
}
return Vector(0, 0, 50/tr.fraction);
}
return vec3_origin;
}
//------------------------------------------------------------------------------
// Purpose :
// Input :
// Output :
//------------------------------------------------------------------------------
void CAI_BaseFlyingBot::StartTask( const Task_t *pTask )
{
switch (pTask->iTask)
{
// Skip as done via bone controller
case TASK_FACE_ENEMY:
{
TaskComplete();
break;
}
// Activity is just idle (have no run)
case TASK_RUN_PATH:
{
GetNavigator()->SetMovementActivity(ACT_IDLE);
TaskComplete();
break;
}
// Don't check for run/walk activity
case TASK_SCRIPT_RUN_TO_TARGET:
case TASK_SCRIPT_WALK_TO_TARGET:
{
if (GetTarget() == NULL)
{
TaskFail(FAIL_NO_TARGET);
}
else
{
if (!GetNavigator()->SetGoal( GOALTYPE_TARGETENT ) )
{
TaskFail(FAIL_NO_ROUTE);
GetNavigator()->ClearGoal();
}
}
TaskComplete();
break;
}
// Override to get more to get a directional path
case TASK_GET_PATH_TO_RANDOM_NODE:
{
if ( GetNavigator()->SetRandomGoal( pTask->flTaskData, m_vLastPatrolDir ) )
TaskComplete();
else
TaskFail(FAIL_NO_REACHABLE_NODE);
break;
}
default:
{
BaseClass::StartTask(pTask);
}
}
}
//------------------------------------------------------------------------------
void CAI_BaseFlyingBot::MoveToTarget(float flInterval, const Vector &MoveTarget)
{
Assert(0); // This must be overridden in the leaf classes
}
//------------------------------------------------------------------------------
AI_NavPathProgress_t CAI_BaseFlyingBot::ProgressFlyPath(
float flInterval,
const CBaseEntity *pNewTarget,
unsigned collisionMask,
bool bNewTrySimplify,
float strictPointTolerance)
{
AI_ProgressFlyPathParams_t params( collisionMask, strictPointTolerance );
params.SetCurrent( pNewTarget, bNewTrySimplify );
AI_NavPathProgress_t progress = GetNavigator()->ProgressFlyPath( params );
switch ( progress )
{
case AINPP_NO_CHANGE:
case AINPP_ADVANCED:
{
MoveToTarget(flInterval, GetNavigator()->GetCurWaypointPos());
break;
}
case AINPP_COMPLETE:
{
TaskMovementComplete();
break;
}
case AINPP_BLOCKED: // function is not supposed to test blocking, just simple path progression
default:
{
AssertMsg( 0, ( "Unexpected result" ) );
break;
}
}
return progress;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : *pTarget -
// &chasePosition -
//-----------------------------------------------------------------------------
void CAI_BaseFlyingBot::TranslateNavGoal( CBaseEntity *pTarget, Vector &chasePosition )
{
Assert( pTarget != NULL );
if ( pTarget == NULL )
{
chasePosition = vec3_origin;
return;
}
// Chase their eyes
chasePosition = pTarget->GetAbsOrigin() + pTarget->GetViewOffset();
}
//------------------------------------------------------------------------------
// Purpose :
// Input :
// Output :
//------------------------------------------------------------------------------
CAI_BaseFlyingBot::CAI_BaseFlyingBot()
{
#ifdef _DEBUG
m_vCurrentVelocity.Init();
m_vCurrentBanking.Init();
m_vLastPatrolDir.Init();
#endif
}

View File

@@ -1,132 +1,132 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#ifndef AI_BASENPC_FLYER_H
#define AI_BASENPC_FLYER_H
#ifdef _WIN32
#pragma once
#endif
#include "ai_basenpc.h"
#include "ai_navigator.h"
//-----------------------------------------------------------------------------
// The combot.
//-----------------------------------------------------------------------------
abstract_class CAI_BaseFlyingBot : public CAI_BaseNPC
{
DECLARE_CLASS( CAI_BaseFlyingBot, CAI_BaseNPC );
public:
DECLARE_DATADESC();
void StartTask( const Task_t *pTask );
void GetVelocity(Vector *vVelocity, AngularImpulse *vAngVelocity);
virtual QAngle BodyAngles();
protected:
CAI_BaseFlyingBot();
Vector VelocityToAvoidObstacles(float flInterval);
virtual float MinGroundDist(void);
void TurnHeadToTarget( float flInterval, const Vector &moveTarget );
void MoveInDirection( float flInterval, const Vector &targetDir,
float accelXY, float accelZ, float decay)
{
decay = ExponentialDecay( decay, 1.0, flInterval );
accelXY *= flInterval;
accelZ *= flInterval;
m_vCurrentVelocity.x = ( decay * m_vCurrentVelocity.x + accelXY * targetDir.x );
m_vCurrentVelocity.y = ( decay * m_vCurrentVelocity.y + accelXY * targetDir.y );
m_vCurrentVelocity.z = ( decay * m_vCurrentVelocity.z + accelZ * targetDir.z );
}
void MoveToLocation( float flInterval, const Vector &target,
float accelXY, float accelZ, float decay)
{
Vector targetDir = target - GetLocalOrigin();
VectorNormalize(targetDir);
MoveInDirection(flInterval, targetDir, accelXY, accelZ, decay);
}
void Decelerate( float flInterval, float decay )
{
decay *= flInterval;
m_vCurrentVelocity.x = (decay * m_vCurrentVelocity.x);
m_vCurrentVelocity.y = (decay * m_vCurrentVelocity.y);
m_vCurrentVelocity.z = (decay * m_vCurrentVelocity.z);
}
void AddNoiseToVelocity( float noiseScale = 1.0 )
{
if( m_vNoiseMod.x )
{
m_vCurrentVelocity.x += noiseScale*sin(m_vNoiseMod.x * gpGlobals->curtime + m_vNoiseMod.x);
}
if( m_vNoiseMod.y )
{
m_vCurrentVelocity.y += noiseScale*cos(m_vNoiseMod.y * gpGlobals->curtime + m_vNoiseMod.y);
}
if( m_vNoiseMod.z )
{
m_vCurrentVelocity.z -= noiseScale*cos(m_vNoiseMod.z * gpGlobals->curtime + m_vNoiseMod.z);
}
}
void LimitSpeed( float zLimit, float maxSpeed = -1 )
{
if ( maxSpeed == -1 )
maxSpeed = m_flSpeed;
if (m_vCurrentVelocity.Length() > maxSpeed)
{
VectorNormalize(m_vCurrentVelocity);
m_vCurrentVelocity *= maxSpeed;
}
// Limit fall speed
if (zLimit > 0 && m_vCurrentVelocity.z < -zLimit)
{
m_vCurrentVelocity.z = -zLimit;
}
}
AI_NavPathProgress_t ProgressFlyPath( float flInterval,
const CBaseEntity *pNewTarget,
unsigned collisionMask,
bool bNewTrySimplify = true,
float strictPointTolerance = 32.0 );
virtual float GetHeadTurnRate( void ) { return 15.0f; } // Degrees per second
const Vector &GetCurrentVelocity() const { return m_vCurrentVelocity; }
void SetCurrentVelocity(const Vector &vNewVel) { m_vCurrentVelocity = vNewVel; }
const Vector &GetNoiseMod() const { return m_vNoiseMod; }
void SetNoiseMod( float x, float y, float z ) { m_vNoiseMod.Init( x, y, z ); }
void SetNoiseMod( const Vector &noise ) { m_vNoiseMod = noise; }
virtual void MoveToTarget(float flInterval, const Vector &MoveTarget) = 0;
void TranslateNavGoal( CBaseEntity *pTarget, Vector &chasePosition );
// -------------------------------
// Movement vars
// -------------------------------
Vector m_vCurrentVelocity;
Vector m_vCurrentAngularVelocity;
Vector m_vCurrentBanking;
Vector m_vNoiseMod;
float m_fHeadYaw;
Vector m_vLastPatrolDir;
};
#endif // AI_BASENPC_FLYER_H
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#ifndef AI_BASENPC_FLYER_H
#define AI_BASENPC_FLYER_H
#ifdef _WIN32
#pragma once
#endif
#include "ai_basenpc.h"
#include "ai_navigator.h"
//-----------------------------------------------------------------------------
// The combot.
//-----------------------------------------------------------------------------
abstract_class CAI_BaseFlyingBot : public CAI_BaseNPC
{
DECLARE_CLASS( CAI_BaseFlyingBot, CAI_BaseNPC );
public:
DECLARE_DATADESC();
void StartTask( const Task_t *pTask );
void GetVelocity(Vector *vVelocity, AngularImpulse *vAngVelocity);
virtual QAngle BodyAngles();
protected:
CAI_BaseFlyingBot();
Vector VelocityToAvoidObstacles(float flInterval);
virtual float MinGroundDist(void);
void TurnHeadToTarget( float flInterval, const Vector &moveTarget );
void MoveInDirection( float flInterval, const Vector &targetDir,
float accelXY, float accelZ, float decay)
{
decay = ExponentialDecay( decay, 1.0, flInterval );
accelXY *= flInterval;
accelZ *= flInterval;
m_vCurrentVelocity.x = ( decay * m_vCurrentVelocity.x + accelXY * targetDir.x );
m_vCurrentVelocity.y = ( decay * m_vCurrentVelocity.y + accelXY * targetDir.y );
m_vCurrentVelocity.z = ( decay * m_vCurrentVelocity.z + accelZ * targetDir.z );
}
void MoveToLocation( float flInterval, const Vector &target,
float accelXY, float accelZ, float decay)
{
Vector targetDir = target - GetLocalOrigin();
VectorNormalize(targetDir);
MoveInDirection(flInterval, targetDir, accelXY, accelZ, decay);
}
void Decelerate( float flInterval, float decay )
{
decay *= flInterval;
m_vCurrentVelocity.x = (decay * m_vCurrentVelocity.x);
m_vCurrentVelocity.y = (decay * m_vCurrentVelocity.y);
m_vCurrentVelocity.z = (decay * m_vCurrentVelocity.z);
}
void AddNoiseToVelocity( float noiseScale = 1.0 )
{
if( m_vNoiseMod.x )
{
m_vCurrentVelocity.x += noiseScale*sin(m_vNoiseMod.x * gpGlobals->curtime + m_vNoiseMod.x);
}
if( m_vNoiseMod.y )
{
m_vCurrentVelocity.y += noiseScale*cos(m_vNoiseMod.y * gpGlobals->curtime + m_vNoiseMod.y);
}
if( m_vNoiseMod.z )
{
m_vCurrentVelocity.z -= noiseScale*cos(m_vNoiseMod.z * gpGlobals->curtime + m_vNoiseMod.z);
}
}
void LimitSpeed( float zLimit, float maxSpeed = -1 )
{
if ( maxSpeed == -1 )
maxSpeed = m_flSpeed;
if (m_vCurrentVelocity.Length() > maxSpeed)
{
VectorNormalize(m_vCurrentVelocity);
m_vCurrentVelocity *= maxSpeed;
}
// Limit fall speed
if (zLimit > 0 && m_vCurrentVelocity.z < -zLimit)
{
m_vCurrentVelocity.z = -zLimit;
}
}
AI_NavPathProgress_t ProgressFlyPath( float flInterval,
const CBaseEntity *pNewTarget,
unsigned collisionMask,
bool bNewTrySimplify = true,
float strictPointTolerance = 32.0 );
virtual float GetHeadTurnRate( void ) { return 15.0f; } // Degrees per second
const Vector &GetCurrentVelocity() const { return m_vCurrentVelocity; }
void SetCurrentVelocity(const Vector &vNewVel) { m_vCurrentVelocity = vNewVel; }
const Vector &GetNoiseMod() const { return m_vNoiseMod; }
void SetNoiseMod( float x, float y, float z ) { m_vNoiseMod.Init( x, y, z ); }
void SetNoiseMod( const Vector &noise ) { m_vNoiseMod = noise; }
virtual void MoveToTarget(float flInterval, const Vector &MoveTarget) = 0;
void TranslateNavGoal( CBaseEntity *pTarget, Vector &chasePosition );
// -------------------------------
// Movement vars
// -------------------------------
Vector m_vCurrentVelocity;
Vector m_vCurrentAngularVelocity;
Vector m_vCurrentBanking;
Vector m_vNoiseMod;
float m_fHeadYaw;
Vector m_vLastPatrolDir;
};
#endif // AI_BASENPC_FLYER_H

View File

@@ -1,140 +1,140 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Base class for many flying NPCs
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "ai_basenpc_flyer_new.h"
#include "ai_route.h"
#include "ai_navigator.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
#define FLYER_ROUTE_REBUILD_TIME 3.0 // Time between route rebuilds
// NOTE: Never instantiate ai_base_npc_flyer_new directly!!
//IMPLEMENT_CUSTOM_AI( ai_base_npc_flyer_new, CAI_BaseNPCFlyerNew);
//------------------------------------------------------------------------------
// Purpose :
// Input :
// Output :
//------------------------------------------------------------------------------
CAI_BaseNPCFlyerNew::CAI_BaseNPCFlyerNew()
{
}
//------------------------------------------------------------------------------
// Used to set up a flyer
//------------------------------------------------------------------------------
void CAI_BaseNPCFlyerNew::SpawnFlyer()
{
SetNavType( NAV_FLY );
AddFlag( FL_FLY );
SetMoveType( MOVETYPE_STEP );
CapabilitiesAdd( bits_CAP_MOVE_FLY );
}
/*
void CAI_BaseNPCFlyerNew::InitCustomSchedules(void)
{
INIT_CUSTOM_AI(CAI_BaseNPCFlyerNew);
ADD_CUSTOM_CONDITION(CAI_BaseNPCFlyerNew, COND_FLYER_MOVE_BLOCKED);
ADD_CUSTOM_CONDITION(CAI_BaseNPCFlyerNew, COND_FLYER_MOVE_IMPOSSIBLE);
}
*/
//------------------------------------------------------------------------------
// Should be called during Select Schedule (BLEAH!)
//------------------------------------------------------------------------------
void CAI_BaseNPCFlyerNew::ClearFlyerConditions(void)
{
// ClearCondition( COND_FLYER_MOVE_BLOCKED );
// ClearCondition( COND_FLYER_MOVE_IMPOSSIBLE );
}
//------------------------------------------------------------------------------
// Purpose :
// Input :
// Output :
//------------------------------------------------------------------------------
float CAI_BaseNPCFlyerNew::MinGroundDist(void)
{
return 0;
}
//-----------------------------------------------------------------------------
// Sets the ground speed appropriately:
//-----------------------------------------------------------------------------
float CAI_BaseNPCFlyerNew::GetIdealSpeed( ) const
{
return m_flSpeed;
}
//------------------------------------------------------------------------------
// Purpose :
// Input :
// Output :
//------------------------------------------------------------------------------
void CAI_BaseNPCFlyerNew::StartTask( const Task_t *pTask )
{
switch (pTask->iTask)
{
// Activity is just idle (have no run)
case TASK_RUN_PATH:
{
GetNavigator()->SetMovementActivity(ACT_IDLE);
TaskComplete();
break;
}
// Don't check for run/walk activity
case TASK_SCRIPT_RUN_TO_TARGET:
case TASK_SCRIPT_WALK_TO_TARGET:
{
if (GetTarget() == NULL)
{
TaskFail(FAIL_NO_TARGET);
}
else
{
if (!GetNavigator()->SetGoal( GOALTYPE_TARGETENT ) )
{
TaskFail(FAIL_NO_ROUTE);
GetNavigator()->ClearGoal();
}
}
TaskComplete();
break;
}
default:
{
BaseClass::StartTask(pTask);
}
break;
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CAI_BaseNPCFlyerNew::RunTask( const Task_t *pTask )
{
BaseClass::RunTask(pTask);
}
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Base class for many flying NPCs
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "ai_basenpc_flyer_new.h"
#include "ai_route.h"
#include "ai_navigator.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
#define FLYER_ROUTE_REBUILD_TIME 3.0 // Time between route rebuilds
// NOTE: Never instantiate ai_base_npc_flyer_new directly!!
//IMPLEMENT_CUSTOM_AI( ai_base_npc_flyer_new, CAI_BaseNPCFlyerNew);
//------------------------------------------------------------------------------
// Purpose :
// Input :
// Output :
//------------------------------------------------------------------------------
CAI_BaseNPCFlyerNew::CAI_BaseNPCFlyerNew()
{
}
//------------------------------------------------------------------------------
// Used to set up a flyer
//------------------------------------------------------------------------------
void CAI_BaseNPCFlyerNew::SpawnFlyer()
{
SetNavType( NAV_FLY );
AddFlag( FL_FLY );
SetMoveType( MOVETYPE_STEP );
CapabilitiesAdd( bits_CAP_MOVE_FLY );
}
/*
void CAI_BaseNPCFlyerNew::InitCustomSchedules(void)
{
INIT_CUSTOM_AI(CAI_BaseNPCFlyerNew);
ADD_CUSTOM_CONDITION(CAI_BaseNPCFlyerNew, COND_FLYER_MOVE_BLOCKED);
ADD_CUSTOM_CONDITION(CAI_BaseNPCFlyerNew, COND_FLYER_MOVE_IMPOSSIBLE);
}
*/
//------------------------------------------------------------------------------
// Should be called during Select Schedule (BLEAH!)
//------------------------------------------------------------------------------
void CAI_BaseNPCFlyerNew::ClearFlyerConditions(void)
{
// ClearCondition( COND_FLYER_MOVE_BLOCKED );
// ClearCondition( COND_FLYER_MOVE_IMPOSSIBLE );
}
//------------------------------------------------------------------------------
// Purpose :
// Input :
// Output :
//------------------------------------------------------------------------------
float CAI_BaseNPCFlyerNew::MinGroundDist(void)
{
return 0;
}
//-----------------------------------------------------------------------------
// Sets the ground speed appropriately:
//-----------------------------------------------------------------------------
float CAI_BaseNPCFlyerNew::GetIdealSpeed( ) const
{
return m_flSpeed;
}
//------------------------------------------------------------------------------
// Purpose :
// Input :
// Output :
//------------------------------------------------------------------------------
void CAI_BaseNPCFlyerNew::StartTask( const Task_t *pTask )
{
switch (pTask->iTask)
{
// Activity is just idle (have no run)
case TASK_RUN_PATH:
{
GetNavigator()->SetMovementActivity(ACT_IDLE);
TaskComplete();
break;
}
// Don't check for run/walk activity
case TASK_SCRIPT_RUN_TO_TARGET:
case TASK_SCRIPT_WALK_TO_TARGET:
{
if (GetTarget() == NULL)
{
TaskFail(FAIL_NO_TARGET);
}
else
{
if (!GetNavigator()->SetGoal( GOALTYPE_TARGETENT ) )
{
TaskFail(FAIL_NO_ROUTE);
GetNavigator()->ClearGoal();
}
}
TaskComplete();
break;
}
default:
{
BaseClass::StartTask(pTask);
}
break;
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CAI_BaseNPCFlyerNew::RunTask( const Task_t *pTask )
{
BaseClass::RunTask(pTask);
}

View File

@@ -1,58 +1,58 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#ifndef AI_BASENPC_FLYER_NEW_H
#define AI_BASENPC_FLYER_NEW_H
#ifdef _WIN32
#pragma once
#endif
#include "ai_basenpc.h"
#include "ai_condition.h"
enum BaseNPCFlyerConditions_t
{
COND_FLYER_MOVE_BLOCKED = LAST_SHARED_CONDITION,
COND_FLYER_MOVE_IMPOSSIBLE,
// ======================================
// IMPORTANT: This must be the last enum
// ======================================
LAST_FLYER_SHARED_CONDITION
};
//-----------------------------------------------------------------------------
// The combot.
//-----------------------------------------------------------------------------
class CAI_BaseNPCFlyerNew : public CAI_BaseNPC
{
DECLARE_CLASS( CAI_BaseNPCFlyerNew, CAI_BaseNPC );
public:
// DEFINE_CUSTOM_AI;
virtual void StartTask( const Task_t *pTask );
virtual void RunTask( const Task_t *pTask );
virtual float GetIdealSpeed( ) const;
virtual float MinGroundDist(void);
CAI_BaseNPCFlyerNew();
protected:
// Call this to set up a flyer
void SpawnFlyer();
// Yarg! Must be chained down from leaf classes...
void ClearFlyerConditions(void);
// Override this when we had to abort movement
virtual void AbortedMovement( void ) {}
};
#endif // AI_BASENPC_FLYER_NEW_H
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#ifndef AI_BASENPC_FLYER_NEW_H
#define AI_BASENPC_FLYER_NEW_H
#ifdef _WIN32
#pragma once
#endif
#include "ai_basenpc.h"
#include "ai_condition.h"
enum BaseNPCFlyerConditions_t
{
COND_FLYER_MOVE_BLOCKED = LAST_SHARED_CONDITION,
COND_FLYER_MOVE_IMPOSSIBLE,
// ======================================
// IMPORTANT: This must be the last enum
// ======================================
LAST_FLYER_SHARED_CONDITION
};
//-----------------------------------------------------------------------------
// The combot.
//-----------------------------------------------------------------------------
class CAI_BaseNPCFlyerNew : public CAI_BaseNPC
{
DECLARE_CLASS( CAI_BaseNPCFlyerNew, CAI_BaseNPC );
public:
// DEFINE_CUSTOM_AI;
virtual void StartTask( const Task_t *pTask );
virtual void RunTask( const Task_t *pTask );
virtual float GetIdealSpeed( ) const;
virtual float MinGroundDist(void);
CAI_BaseNPCFlyerNew();
protected:
// Call this to set up a flyer
void SpawnFlyer();
// Yarg! Must be chained down from leaf classes...
void ClearFlyerConditions(void);
// Override this when we had to abort movement
virtual void AbortedMovement( void ) {}
};
#endif // AI_BASENPC_FLYER_NEW_H

View File

@@ -1,499 +1,499 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "game.h"
#include "ndebugoverlay.h"
#include "ai_basenpc.h"
#include "ai_hull.h"
#include "ai_node.h"
#include "ai_motor.h"
#include "ai_navigator.h"
#include "ai_hint.h"
#include "scripted.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
//=============================================================================
// PATHING & HIGHER LEVEL MOVEMENT
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// Purpose: Static debug function to force all selected npcs to go to the
// given node
// Input :
// Output :
//-----------------------------------------------------------------------------
void CAI_BaseNPC::ForceSelectedGo(CBaseEntity *pPlayer, const Vector &targetPos, const Vector &traceDir, bool bRun)
{
CAI_BaseNPC *npc = gEntList.NextEntByClass( (CAI_BaseNPC *)NULL );
while (npc)
{
if (npc->m_debugOverlays & OVERLAY_NPC_SELECTED_BIT)
{
Vector chasePosition = targetPos;
npc->TranslateNavGoal( pPlayer, chasePosition );
// It it legal to drop me here
Vector vUpBit = chasePosition;
vUpBit.z += 1;
trace_t tr;
AI_TraceHull( chasePosition, vUpBit, npc->GetHullMins(),
npc->GetHullMaxs(), MASK_NPCSOLID, npc, COLLISION_GROUP_NONE, &tr );
if (tr.startsolid || tr.fraction != 1.0 )
{
NDebugOverlay::BoxAngles(chasePosition, npc->GetHullMins(),
npc->GetHullMaxs(), npc->GetAbsAngles(), 255,0,0,20,0.5);
}
npc->m_vecLastPosition = chasePosition;
if (npc->m_hCine != NULL)
{
npc->ExitScriptedSequence();
}
if ( bRun )
npc->SetSchedule( SCHED_FORCED_GO_RUN );
else
npc->SetSchedule( SCHED_FORCED_GO );
npc->m_flMoveWaitFinished = gpGlobals->curtime;
}
npc = gEntList.NextEntByClass(npc);
}
}
//-----------------------------------------------------------------------------
// Purpose: Static debug function to make all selected npcs run around
// Input :
// Output :
//-----------------------------------------------------------------------------
void CAI_BaseNPC::ForceSelectedGoRandom(void)
{
CAI_BaseNPC *npc = gEntList.NextEntByClass( (CAI_BaseNPC *)NULL );
while (npc)
{
if (npc->m_debugOverlays & OVERLAY_NPC_SELECTED_BIT)
{
npc->SetSchedule( SCHED_RUN_RANDOM );
npc->GetNavigator()->SetMovementActivity(ACT_RUN);
}
npc = gEntList.NextEntByClass(npc);
}
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
bool CAI_BaseNPC::ScheduledMoveToGoalEntity( int scheduleType, CBaseEntity *pGoalEntity, Activity movementActivity )
{
if ( m_NPCState == NPC_STATE_NONE )
{
// More than likely being grabbed before first think. Set ideal state to prevent schedule stomp
m_NPCState = m_IdealNPCState;
}
SetSchedule( scheduleType );
SetGoalEnt( pGoalEntity );
// HACKHACK: Call through TranslateNavGoal to fixup this goal position
// UNDONE: Remove this and have NPCs that need this functionality fix up paths in the
// movement system instead of when they are specified.
AI_NavGoal_t goal(pGoalEntity->GetAbsOrigin(), movementActivity, AIN_DEF_TOLERANCE, AIN_YAW_TO_DEST);
TranslateNavGoal( pGoalEntity, goal.dest );
return GetNavigator()->SetGoal( goal );
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
bool CAI_BaseNPC::ScheduledFollowPath( int scheduleType, CBaseEntity *pPathStart, Activity movementActivity )
{
if ( m_NPCState == NPC_STATE_NONE )
{
// More than likely being grabbed before first think. Set ideal state to prevent schedule stomp
m_NPCState = m_IdealNPCState;
}
SetSchedule( scheduleType );
SetGoalEnt( pPathStart );
// HACKHACK: Call through TranslateNavGoal to fixup this goal position
AI_NavGoal_t goal(GOALTYPE_PATHCORNER, pPathStart->GetLocalOrigin(), movementActivity, AIN_DEF_TOLERANCE, AIN_YAW_TO_DEST);
TranslateNavGoal( pPathStart, goal.dest );
return GetNavigator()->SetGoal( goal );
}
//-----------------------------------------------------------------------------
// Purpose:
// Input :
// Output :
//-----------------------------------------------------------------------------
bool CAI_BaseNPC::IsMoving( void )
{
return GetNavigator()->IsGoalSet();
}
//-----------------------------------------------------------------------------
bool CAI_BaseNPC::IsCurTaskContinuousMove()
{
const Task_t* pTask = GetTask();
// This bit of logic strikes me funny, but the case does exist. (sjb)
if( !pTask )
return true;
switch( pTask->iTask )
{
case TASK_WAIT_FOR_MOVEMENT:
case TASK_MOVE_TO_TARGET_RANGE:
case TASK_MOVE_TO_GOAL_RANGE:
case TASK_WEAPON_RUN_PATH:
case TASK_PLAY_SCENE:
case TASK_RUN_PATH_TIMED:
case TASK_WALK_PATH_TIMED:
case TASK_RUN_PATH_FOR_UNITS:
case TASK_WALK_PATH_FOR_UNITS:
case TASK_RUN_PATH_FLEE:
case TASK_WALK_PATH_WITHIN_DIST:
case TASK_RUN_PATH_WITHIN_DIST:
return true;
break;
default:
return false;
break;
}
}
//-----------------------------------------------------------------------------
// Purpose: Used to specify that the NPC has a reason not to use the a navigation node
// Input :
// Output :
//-----------------------------------------------------------------------------
bool CAI_BaseNPC::IsUnusableNode(int iNodeID, CAI_Hint *pHint)
{
if ( m_bHintGroupNavLimiting && m_strHintGroup != NULL_STRING && STRING(m_strHintGroup)[0] != 0 )
{
if (!pHint || pHint->GetGroup() != GetHintGroup())
{
return true;
}
}
return false;
}
//-----------------------------------------------------------------------------
// Purpose: Checks the validity of the given route's goaltype
// Input :
// Output :
//-----------------------------------------------------------------------------
bool CAI_BaseNPC::ValidateNavGoal()
{
if (GetNavigator()->GetGoalType() == GOALTYPE_COVER)
{
// Check if this location will block my enemy's line of sight to me
if (GetEnemy())
{
Activity nCoverActivity = GetCoverActivity( GetHintNode() );
Vector vCoverLocation = GetNavigator()->GetGoalPos();
// For now we have to drop the node to the floor so we can
// get an accurate postion of the NPC. Should change once Ken checks in
float floorZ = GetFloorZ(vCoverLocation);
vCoverLocation.z = floorZ;
Vector vEyePos = vCoverLocation + EyeOffset(nCoverActivity);
if (!IsCoverPosition( GetEnemy()->EyePosition(), vEyePos ) )
{
TaskFail(FAIL_BAD_PATH_GOAL);
return false;
}
}
}
return true;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input :
// Output :
//-----------------------------------------------------------------------------
float CAI_BaseNPC::OpenDoorAndWait( CBaseEntity *pDoor )
{
float flTravelTime = 0;
//DevMsg( 2, "A door. ");
if (pDoor && !pDoor->IsLockedByMaster())
{
pDoor->Use(this, this, USE_ON, 0.0);
flTravelTime = pDoor->GetMoveDoneTime();
if ( pDoor->GetEntityName() != NULL_STRING )
{
CBaseEntity *pTarget = NULL;
for (;;)
{
pTarget = gEntList.FindEntityByName( pTarget, pDoor->GetEntityName() );
if ( pTarget != pDoor )
{
if ( !pTarget )
break;
if ( FClassnameIs( pTarget, pDoor->GetClassname() ) )
{
pTarget->Use(this, this, USE_ON, 0.0);
}
}
}
}
}
return gpGlobals->curtime + flTravelTime;
}
//-----------------------------------------------------------------------------
bool CAI_BaseNPC::CanStandOn( CBaseEntity *pSurface ) const
{
if ( !pSurface->IsAIWalkable() )
{
return false;
}
CAI_Navigator *pNavigator = const_cast<CAI_Navigator *>(GetNavigator());
if ( pNavigator->IsGoalActive() &&
pSurface == pNavigator->GetGoalTarget() )
return false;
return BaseClass::CanStandOn( pSurface );
}
//-----------------------------------------------------------------------------
bool CAI_BaseNPC::IsJumpLegal( const Vector &startPos, const Vector &apex, const Vector &endPos,
float maxUp, float maxDown, float maxDist ) const
{
if ((endPos.z - startPos.z) > maxUp + 0.1)
return false;
if ((startPos.z - endPos.z) > maxDown + 0.1)
return false;
if ((apex.z - startPos.z) > maxUp * 1.25 )
return false;
float dist = (startPos - endPos).Length();
if ( dist > maxDist + 0.1)
return false;
return true;
}
//-----------------------------------------------------------------------------
// Purpose: Returns true if a reasonable jumping distance
// Input :
// Output :
//-----------------------------------------------------------------------------
bool CAI_BaseNPC::IsJumpLegal( const Vector &startPos, const Vector &apex, const Vector &endPos ) const
{
const float MAX_JUMP_RISE = 80.0f;
const float MAX_JUMP_DISTANCE = 250.0f;
const float MAX_JUMP_DROP = 192.0f;
return IsJumpLegal( startPos, apex, endPos, MAX_JUMP_RISE, MAX_JUMP_DROP, MAX_JUMP_DISTANCE );
}
//-----------------------------------------------------------------------------
// Purpose: Returns a throw velocity from start to end position
// Input :
// Output :
//-----------------------------------------------------------------------------
Vector CAI_BaseNPC::CalcThrowVelocity(const Vector &startPos, const Vector &endPos, float fGravity, float fArcSize)
{
// Get the height I have to throw to get to the target
float stepHeight = endPos.z - startPos.z;
float throwHeight = 0;
// -----------------------------------------------------------------
// Now calcluate the distance to a point halfway between our current
// and target position. (the apex of our throwing arc)
// -----------------------------------------------------------------
Vector targetDir2D = endPos - startPos;
targetDir2D.z = 0;
float distance = VectorNormalize(targetDir2D);
// If jumping up we want to throw a bit higher than the height diff
if (stepHeight > 0)
{
throwHeight = stepHeight + fArcSize;
}
else
{
throwHeight = fArcSize;
}
// Make sure that I at least catch some air
if (throwHeight < fArcSize)
{
throwHeight = fArcSize;
}
// -------------------------------------------------------------
// calculate the vertical and horizontal launch velocities
// -------------------------------------------------------------
float velVert = (float)sqrt(2.0f*fGravity*throwHeight);
float divisor = velVert;
divisor += (float)sqrt((2.0f*(-fGravity)*(stepHeight-throwHeight)));
float velHorz = (distance * fGravity)/divisor;
// -----------------------------------------------------------
// Make the horizontal throw vector and add vertical component
// -----------------------------------------------------------
Vector throwVel = targetDir2D * velHorz;
throwVel.z = velVert;
return throwVel;
}
bool CAI_BaseNPC::ShouldMoveWait()
{
return (m_flMoveWaitFinished > gpGlobals->curtime);
}
float CAI_BaseNPC::GetStepDownMultiplier() const
{
return m_pNavigator->GetStepDownMultiplier();
}
//-----------------------------------------------------------------------------
// Purpose: execute any movement this sequence may have
// Output :
//-----------------------------------------------------------------------------
bool CAI_BaseNPC::AutoMovement( CBaseEntity *pTarget, AIMoveTrace_t *pTraceResult )
{
return AutoMovement( GetAnimTimeInterval(), pTarget, pTraceResult );
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : flInterval -
// -
// *pTraceResult -
// Output : Returns true on success, false on failure.
//-----------------------------------------------------------------------------
bool CAI_BaseNPC::AutoMovement( float flInterval, CBaseEntity *pTarget, AIMoveTrace_t *pTraceResult )
{
bool ignored;
Vector newPos;
QAngle newAngles;
if (flInterval <= 0.0)
return true;
m_ScheduleState.bTaskRanAutomovement = true;
if (GetIntervalMovement( flInterval, ignored, newPos, newAngles ))
{
// DevMsg( "%.2f : (%.1f) %.1f %.1f %.1f\n", gpGlobals->curtime, (newPos - GetLocalOrigin()).Length(), newPos.x, newPos.y, newAngles.y );
if ( m_hCine )
{
m_hCine->ModifyScriptedAutoMovement( &newPos );
}
if (GetMoveType() == MOVETYPE_STEP)
{
if (!(GetFlags() & FL_FLY))
{
if ( !pTarget )
{
pTarget = GetNavTargetEntity();
}
return ( GetMotor()->MoveGroundStep( newPos, pTarget, newAngles.y, false, true, pTraceResult ) == AIM_SUCCESS );
}
else
{
// FIXME: here's no direct interface to a fly motor, plus this needs to support a state where going through the world is okay.
// FIXME: add callbacks into the script system for validation
// FIXME: add function on scripts to force only legal movements
// FIXME: GetIntervalMovement deals in Local space, nor global. Currently now way to communicate that through these interfaces.
SetLocalOrigin( newPos );
SetLocalAngles( newAngles );
return true;
}
}
else if (GetMoveType() == MOVETYPE_FLY)
{
Vector dist = newPos - GetLocalOrigin();
VectorScale( dist, 1.0 / flInterval, dist );
SetLocalVelocity( dist );
return true;
}
}
return false;
}
//-----------------------------------------------------------------------------
// Purpose: return max 1/10 second rate of turning
// Input :
// Output :
//-----------------------------------------------------------------------------
float CAI_BaseNPC::MaxYawSpeed( void )
{
return 45;
}
//-----------------------------------------------------------------------------
// Returns the estimate in seconds before we reach our nav goal.
// -1 means we don't know / haven't calculated it yet.
//-----------------------------------------------------------------------------
float CAI_BaseNPC::GetTimeToNavGoal()
{
float flDist = GetNavigator()->BuildAndGetPathDistToGoal();
if ( flDist < 0 )
{
return -1.0f;
}
float flSpeed = GetIdealSpeed();
// FIXME: needs to consider stopping time!
if (flSpeed > 0 && flDist > 0)
{
return flDist / flSpeed;
}
return 0.0;
}
//=============================================================================
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "game.h"
#include "ndebugoverlay.h"
#include "ai_basenpc.h"
#include "ai_hull.h"
#include "ai_node.h"
#include "ai_motor.h"
#include "ai_navigator.h"
#include "ai_hint.h"
#include "scripted.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
//=============================================================================
// PATHING & HIGHER LEVEL MOVEMENT
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// Purpose: Static debug function to force all selected npcs to go to the
// given node
// Input :
// Output :
//-----------------------------------------------------------------------------
void CAI_BaseNPC::ForceSelectedGo(CBaseEntity *pPlayer, const Vector &targetPos, const Vector &traceDir, bool bRun)
{
CAI_BaseNPC *npc = gEntList.NextEntByClass( (CAI_BaseNPC *)NULL );
while (npc)
{
if (npc->m_debugOverlays & OVERLAY_NPC_SELECTED_BIT)
{
Vector chasePosition = targetPos;
npc->TranslateNavGoal( pPlayer, chasePosition );
// It it legal to drop me here
Vector vUpBit = chasePosition;
vUpBit.z += 1;
trace_t tr;
AI_TraceHull( chasePosition, vUpBit, npc->GetHullMins(),
npc->GetHullMaxs(), MASK_NPCSOLID, npc, COLLISION_GROUP_NONE, &tr );
if (tr.startsolid || tr.fraction != 1.0 )
{
NDebugOverlay::BoxAngles(chasePosition, npc->GetHullMins(),
npc->GetHullMaxs(), npc->GetAbsAngles(), 255,0,0,20,0.5);
}
npc->m_vecLastPosition = chasePosition;
if (npc->m_hCine != NULL)
{
npc->ExitScriptedSequence();
}
if ( bRun )
npc->SetSchedule( SCHED_FORCED_GO_RUN );
else
npc->SetSchedule( SCHED_FORCED_GO );
npc->m_flMoveWaitFinished = gpGlobals->curtime;
}
npc = gEntList.NextEntByClass(npc);
}
}
//-----------------------------------------------------------------------------
// Purpose: Static debug function to make all selected npcs run around
// Input :
// Output :
//-----------------------------------------------------------------------------
void CAI_BaseNPC::ForceSelectedGoRandom(void)
{
CAI_BaseNPC *npc = gEntList.NextEntByClass( (CAI_BaseNPC *)NULL );
while (npc)
{
if (npc->m_debugOverlays & OVERLAY_NPC_SELECTED_BIT)
{
npc->SetSchedule( SCHED_RUN_RANDOM );
npc->GetNavigator()->SetMovementActivity(ACT_RUN);
}
npc = gEntList.NextEntByClass(npc);
}
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
bool CAI_BaseNPC::ScheduledMoveToGoalEntity( int scheduleType, CBaseEntity *pGoalEntity, Activity movementActivity )
{
if ( m_NPCState == NPC_STATE_NONE )
{
// More than likely being grabbed before first think. Set ideal state to prevent schedule stomp
m_NPCState = m_IdealNPCState;
}
SetSchedule( scheduleType );
SetGoalEnt( pGoalEntity );
// HACKHACK: Call through TranslateNavGoal to fixup this goal position
// UNDONE: Remove this and have NPCs that need this functionality fix up paths in the
// movement system instead of when they are specified.
AI_NavGoal_t goal(pGoalEntity->GetAbsOrigin(), movementActivity, AIN_DEF_TOLERANCE, AIN_YAW_TO_DEST);
TranslateNavGoal( pGoalEntity, goal.dest );
return GetNavigator()->SetGoal( goal );
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
bool CAI_BaseNPC::ScheduledFollowPath( int scheduleType, CBaseEntity *pPathStart, Activity movementActivity )
{
if ( m_NPCState == NPC_STATE_NONE )
{
// More than likely being grabbed before first think. Set ideal state to prevent schedule stomp
m_NPCState = m_IdealNPCState;
}
SetSchedule( scheduleType );
SetGoalEnt( pPathStart );
// HACKHACK: Call through TranslateNavGoal to fixup this goal position
AI_NavGoal_t goal(GOALTYPE_PATHCORNER, pPathStart->GetLocalOrigin(), movementActivity, AIN_DEF_TOLERANCE, AIN_YAW_TO_DEST);
TranslateNavGoal( pPathStart, goal.dest );
return GetNavigator()->SetGoal( goal );
}
//-----------------------------------------------------------------------------
// Purpose:
// Input :
// Output :
//-----------------------------------------------------------------------------
bool CAI_BaseNPC::IsMoving( void )
{
return GetNavigator()->IsGoalSet();
}
//-----------------------------------------------------------------------------
bool CAI_BaseNPC::IsCurTaskContinuousMove()
{
const Task_t* pTask = GetTask();
// This bit of logic strikes me funny, but the case does exist. (sjb)
if( !pTask )
return true;
switch( pTask->iTask )
{
case TASK_WAIT_FOR_MOVEMENT:
case TASK_MOVE_TO_TARGET_RANGE:
case TASK_MOVE_TO_GOAL_RANGE:
case TASK_WEAPON_RUN_PATH:
case TASK_PLAY_SCENE:
case TASK_RUN_PATH_TIMED:
case TASK_WALK_PATH_TIMED:
case TASK_RUN_PATH_FOR_UNITS:
case TASK_WALK_PATH_FOR_UNITS:
case TASK_RUN_PATH_FLEE:
case TASK_WALK_PATH_WITHIN_DIST:
case TASK_RUN_PATH_WITHIN_DIST:
return true;
break;
default:
return false;
break;
}
}
//-----------------------------------------------------------------------------
// Purpose: Used to specify that the NPC has a reason not to use the a navigation node
// Input :
// Output :
//-----------------------------------------------------------------------------
bool CAI_BaseNPC::IsUnusableNode(int iNodeID, CAI_Hint *pHint)
{
if ( m_bHintGroupNavLimiting && m_strHintGroup != NULL_STRING && STRING(m_strHintGroup)[0] != 0 )
{
if (!pHint || pHint->GetGroup() != GetHintGroup())
{
return true;
}
}
return false;
}
//-----------------------------------------------------------------------------
// Purpose: Checks the validity of the given route's goaltype
// Input :
// Output :
//-----------------------------------------------------------------------------
bool CAI_BaseNPC::ValidateNavGoal()
{
if (GetNavigator()->GetGoalType() == GOALTYPE_COVER)
{
// Check if this location will block my enemy's line of sight to me
if (GetEnemy())
{
Activity nCoverActivity = GetCoverActivity( GetHintNode() );
Vector vCoverLocation = GetNavigator()->GetGoalPos();
// For now we have to drop the node to the floor so we can
// get an accurate postion of the NPC. Should change once Ken checks in
float floorZ = GetFloorZ(vCoverLocation);
vCoverLocation.z = floorZ;
Vector vEyePos = vCoverLocation + EyeOffset(nCoverActivity);
if (!IsCoverPosition( GetEnemy()->EyePosition(), vEyePos ) )
{
TaskFail(FAIL_BAD_PATH_GOAL);
return false;
}
}
}
return true;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input :
// Output :
//-----------------------------------------------------------------------------
float CAI_BaseNPC::OpenDoorAndWait( CBaseEntity *pDoor )
{
float flTravelTime = 0;
//DevMsg( 2, "A door. ");
if (pDoor && !pDoor->IsLockedByMaster())
{
pDoor->Use(this, this, USE_ON, 0.0);
flTravelTime = pDoor->GetMoveDoneTime();
if ( pDoor->GetEntityName() != NULL_STRING )
{
CBaseEntity *pTarget = NULL;
for (;;)
{
pTarget = gEntList.FindEntityByName( pTarget, pDoor->GetEntityName() );
if ( pTarget != pDoor )
{
if ( !pTarget )
break;
if ( FClassnameIs( pTarget, pDoor->GetClassname() ) )
{
pTarget->Use(this, this, USE_ON, 0.0);
}
}
}
}
}
return gpGlobals->curtime + flTravelTime;
}
//-----------------------------------------------------------------------------
bool CAI_BaseNPC::CanStandOn( CBaseEntity *pSurface ) const
{
if ( !pSurface->IsAIWalkable() )
{
return false;
}
CAI_Navigator *pNavigator = const_cast<CAI_Navigator *>(GetNavigator());
if ( pNavigator->IsGoalActive() &&
pSurface == pNavigator->GetGoalTarget() )
return false;
return BaseClass::CanStandOn( pSurface );
}
//-----------------------------------------------------------------------------
bool CAI_BaseNPC::IsJumpLegal( const Vector &startPos, const Vector &apex, const Vector &endPos,
float maxUp, float maxDown, float maxDist ) const
{
if ((endPos.z - startPos.z) > maxUp + 0.1)
return false;
if ((startPos.z - endPos.z) > maxDown + 0.1)
return false;
if ((apex.z - startPos.z) > maxUp * 1.25 )
return false;
float dist = (startPos - endPos).Length();
if ( dist > maxDist + 0.1)
return false;
return true;
}
//-----------------------------------------------------------------------------
// Purpose: Returns true if a reasonable jumping distance
// Input :
// Output :
//-----------------------------------------------------------------------------
bool CAI_BaseNPC::IsJumpLegal( const Vector &startPos, const Vector &apex, const Vector &endPos ) const
{
const float MAX_JUMP_RISE = 80.0f;
const float MAX_JUMP_DISTANCE = 250.0f;
const float MAX_JUMP_DROP = 192.0f;
return IsJumpLegal( startPos, apex, endPos, MAX_JUMP_RISE, MAX_JUMP_DROP, MAX_JUMP_DISTANCE );
}
//-----------------------------------------------------------------------------
// Purpose: Returns a throw velocity from start to end position
// Input :
// Output :
//-----------------------------------------------------------------------------
Vector CAI_BaseNPC::CalcThrowVelocity(const Vector &startPos, const Vector &endPos, float fGravity, float fArcSize)
{
// Get the height I have to throw to get to the target
float stepHeight = endPos.z - startPos.z;
float throwHeight = 0;
// -----------------------------------------------------------------
// Now calcluate the distance to a point halfway between our current
// and target position. (the apex of our throwing arc)
// -----------------------------------------------------------------
Vector targetDir2D = endPos - startPos;
targetDir2D.z = 0;
float distance = VectorNormalize(targetDir2D);
// If jumping up we want to throw a bit higher than the height diff
if (stepHeight > 0)
{
throwHeight = stepHeight + fArcSize;
}
else
{
throwHeight = fArcSize;
}
// Make sure that I at least catch some air
if (throwHeight < fArcSize)
{
throwHeight = fArcSize;
}
// -------------------------------------------------------------
// calculate the vertical and horizontal launch velocities
// -------------------------------------------------------------
float velVert = (float)sqrt(2.0f*fGravity*throwHeight);
float divisor = velVert;
divisor += (float)sqrt((2.0f*(-fGravity)*(stepHeight-throwHeight)));
float velHorz = (distance * fGravity)/divisor;
// -----------------------------------------------------------
// Make the horizontal throw vector and add vertical component
// -----------------------------------------------------------
Vector throwVel = targetDir2D * velHorz;
throwVel.z = velVert;
return throwVel;
}
bool CAI_BaseNPC::ShouldMoveWait()
{
return (m_flMoveWaitFinished > gpGlobals->curtime);
}
float CAI_BaseNPC::GetStepDownMultiplier() const
{
return m_pNavigator->GetStepDownMultiplier();
}
//-----------------------------------------------------------------------------
// Purpose: execute any movement this sequence may have
// Output :
//-----------------------------------------------------------------------------
bool CAI_BaseNPC::AutoMovement( CBaseEntity *pTarget, AIMoveTrace_t *pTraceResult )
{
return AutoMovement( GetAnimTimeInterval(), pTarget, pTraceResult );
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : flInterval -
// -
// *pTraceResult -
// Output : Returns true on success, false on failure.
//-----------------------------------------------------------------------------
bool CAI_BaseNPC::AutoMovement( float flInterval, CBaseEntity *pTarget, AIMoveTrace_t *pTraceResult )
{
bool ignored;
Vector newPos;
QAngle newAngles;
if (flInterval <= 0.0)
return true;
m_ScheduleState.bTaskRanAutomovement = true;
if (GetIntervalMovement( flInterval, ignored, newPos, newAngles ))
{
// DevMsg( "%.2f : (%.1f) %.1f %.1f %.1f\n", gpGlobals->curtime, (newPos - GetLocalOrigin()).Length(), newPos.x, newPos.y, newAngles.y );
if ( m_hCine )
{
m_hCine->ModifyScriptedAutoMovement( &newPos );
}
if (GetMoveType() == MOVETYPE_STEP)
{
if (!(GetFlags() & FL_FLY))
{
if ( !pTarget )
{
pTarget = GetNavTargetEntity();
}
return ( GetMotor()->MoveGroundStep( newPos, pTarget, newAngles.y, false, true, pTraceResult ) == AIM_SUCCESS );
}
else
{
// FIXME: here's no direct interface to a fly motor, plus this needs to support a state where going through the world is okay.
// FIXME: add callbacks into the script system for validation
// FIXME: add function on scripts to force only legal movements
// FIXME: GetIntervalMovement deals in Local space, nor global. Currently now way to communicate that through these interfaces.
SetLocalOrigin( newPos );
SetLocalAngles( newAngles );
return true;
}
}
else if (GetMoveType() == MOVETYPE_FLY)
{
Vector dist = newPos - GetLocalOrigin();
VectorScale( dist, 1.0 / flInterval, dist );
SetLocalVelocity( dist );
return true;
}
}
return false;
}
//-----------------------------------------------------------------------------
// Purpose: return max 1/10 second rate of turning
// Input :
// Output :
//-----------------------------------------------------------------------------
float CAI_BaseNPC::MaxYawSpeed( void )
{
return 45;
}
//-----------------------------------------------------------------------------
// Returns the estimate in seconds before we reach our nav goal.
// -1 means we don't know / haven't calculated it yet.
//-----------------------------------------------------------------------------
float CAI_BaseNPC::GetTimeToNavGoal()
{
float flDist = GetNavigator()->BuildAndGetPathDistToGoal();
if ( flDist < 0 )
{
return -1.0f;
}
float flSpeed = GetIdealSpeed();
// FIXME: needs to consider stopping time!
if (flSpeed > 0 && flDist > 0)
{
return flDist / flSpeed;
}
return 0.0;
}
//=============================================================================

View File

@@ -1,382 +1,382 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Base class for many flying NPCs
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "ai_basenpc_physicsflyer.h"
#include "ai_route.h"
#include "ai_navigator.h"
#include "ai_motor.h"
#include "physics_saverestore.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
BEGIN_DATADESC( CAI_BasePhysicsFlyingBot )
DEFINE_FIELD( m_vCurrentVelocity, FIELD_VECTOR),
DEFINE_FIELD( m_vCurrentBanking, FIELD_VECTOR),
DEFINE_FIELD( m_vNoiseMod, FIELD_VECTOR),
DEFINE_FIELD( m_fHeadYaw, FIELD_FLOAT),
DEFINE_FIELD( m_vLastPatrolDir, FIELD_VECTOR),
DEFINE_PHYSPTR( m_pMotionController ),
END_DATADESC()
//------------------------------------------------------------------------------
// Purpose : Override to return correct velocity
// Input :
// Output :
//------------------------------------------------------------------------------
void CAI_BasePhysicsFlyingBot::GetVelocity(Vector *vVelocity, AngularImpulse *vAngVelocity)
{
Assert( GetMoveType() == MOVETYPE_VPHYSICS );
if ( VPhysicsGetObject() )
{
VPhysicsGetObject()->GetVelocity( vVelocity, vAngVelocity );
}
else
{
if ( vVelocity )
{
vVelocity->Init();
}
if ( vAngVelocity )
{
vAngVelocity->Init();
}
}
}
//-----------------------------------------------------------------------------
// Purpose: Turn head yaw into facing direction
// Input :
// Output :
//-----------------------------------------------------------------------------
QAngle CAI_BasePhysicsFlyingBot::BodyAngles()
{
return QAngle(0,m_fHeadYaw,0);
}
//-----------------------------------------------------------------------------
// Purpose:
// Input :
// Output :
//-----------------------------------------------------------------------------
void CAI_BasePhysicsFlyingBot::TurnHeadToTarget(float flInterval, const Vector &MoveTarget )
{
float desYaw = UTIL_AngleDiff(VecToYaw(MoveTarget - GetLocalOrigin()), 0 );
m_fHeadYaw = desYaw;
return;
// If I've flipped completely around, reverse angles
float fYawDiff = m_fHeadYaw - desYaw;
if (fYawDiff > 180)
{
m_fHeadYaw -= 360;
}
else if (fYawDiff < -180)
{
m_fHeadYaw += 360;
}
// RIGHT NOW, this affects every flying bot. This rate should be member data that individuals
// can manipulate. THIS change for MANHACKS E3 2003 (sjb)
float iRate = 0.8;
// Make frame rate independent
float timeToUse = flInterval;
while (timeToUse > 0)
{
m_fHeadYaw = (iRate * m_fHeadYaw) + (1-iRate)*desYaw;
timeToUse -= 0.1;
}
while( m_fHeadYaw > 360 )
{
m_fHeadYaw -= 360.0f;
}
while( m_fHeadYaw < 0 )
{
m_fHeadYaw += 360.f;
}
// SetBoneController( 0, m_fHeadYaw );
}
//------------------------------------------------------------------------------
// Purpose :
// Input :
// Output :
//------------------------------------------------------------------------------
float CAI_BasePhysicsFlyingBot::MinGroundDist(void)
{
return 0;
}
//------------------------------------------------------------------------------
// Purpose :
// Input :
// Output :
//------------------------------------------------------------------------------
Vector CAI_BasePhysicsFlyingBot::VelocityToAvoidObstacles(float flInterval)
{
// --------------------------------
// Avoid banging into stuff
// --------------------------------
trace_t tr;
Vector vTravelDir = m_vCurrentVelocity*flInterval;
Vector endPos = GetAbsOrigin() + vTravelDir;
AI_TraceEntity( this, GetAbsOrigin(), endPos, MASK_NPCSOLID|CONTENTS_WATER, &tr);
if (tr.fraction != 1.0)
{
// Bounce off in normal
Vector vBounce = tr.plane.normal * 0.5 * m_vCurrentVelocity.Length();
return (vBounce);
}
// --------------------------------
// Try to remain above the ground.
// --------------------------------
float flMinGroundDist = MinGroundDist();
AI_TraceLine(GetAbsOrigin(), GetAbsOrigin() + Vector(0, 0, -flMinGroundDist),
MASK_NPCSOLID_BRUSHONLY|CONTENTS_WATER, this, COLLISION_GROUP_NONE, &tr);
if (tr.fraction < 1)
{
// Clamp veloctiy
if (tr.fraction < 0.1)
{
tr.fraction = 0.1;
}
return Vector(0, 0, 50/tr.fraction);
}
return vec3_origin;
}
//------------------------------------------------------------------------------
// Purpose :
// Input :
// Output :
//------------------------------------------------------------------------------
void CAI_BasePhysicsFlyingBot::StartTask( const Task_t *pTask )
{
switch (pTask->iTask)
{
// Skip as done via bone controller
case TASK_FACE_ENEMY:
{
TaskComplete();
break;
}
// Activity is just idle (have no run)
case TASK_RUN_PATH:
{
GetNavigator()->SetMovementActivity(ACT_IDLE);
TaskComplete();
break;
}
// Don't check for run/walk activity
case TASK_SCRIPT_RUN_TO_TARGET:
case TASK_SCRIPT_WALK_TO_TARGET:
{
if (GetTarget() == NULL)
{
TaskFail(FAIL_NO_TARGET);
}
else
{
if (!GetNavigator()->SetGoal( GOALTYPE_TARGETENT ) )
{
TaskFail(FAIL_NO_ROUTE);
GetNavigator()->ClearGoal();
}
}
TaskComplete();
break;
}
// Override to get more to get a directional path
case TASK_GET_PATH_TO_RANDOM_NODE:
{
if ( GetNavigator()->SetRandomGoal( pTask->flTaskData, m_vLastPatrolDir ) )
TaskComplete();
else
TaskFail(FAIL_NO_REACHABLE_NODE);
break;
}
default:
{
BaseClass::StartTask(pTask);
}
}
}
//------------------------------------------------------------------------------
void CAI_BasePhysicsFlyingBot::MoveToTarget(float flInterval, const Vector &MoveTarget)
{
Assert(0); // This must be overridden in the leaf classes
}
//------------------------------------------------------------------------------
AI_NavPathProgress_t CAI_BasePhysicsFlyingBot::ProgressFlyPath(
float flInterval,
const CBaseEntity *pNewTarget,
unsigned collisionMask,
bool bNewTrySimplify,
float strictPointTolerance)
{
AI_ProgressFlyPathParams_t params( collisionMask );
params.strictPointTolerance = strictPointTolerance;
params.SetCurrent( pNewTarget, bNewTrySimplify );
AI_NavPathProgress_t progress = GetNavigator()->ProgressFlyPath( params );
switch ( progress )
{
case AINPP_NO_CHANGE:
case AINPP_ADVANCED:
{
MoveToTarget(flInterval, GetNavigator()->GetCurWaypointPos());
break;
}
case AINPP_COMPLETE:
{
TaskMovementComplete();
break;
}
case AINPP_BLOCKED: // function is not supposed to test blocking, just simple path progression
default:
{
AssertMsg( 0, ( "Unexpected result" ) );
break;
}
}
return progress;
}
//------------------------------------------------------------------------------
// Purpose :
// Input :
// Output :
//------------------------------------------------------------------------------
CAI_BasePhysicsFlyingBot::CAI_BasePhysicsFlyingBot()
{
#ifdef _DEBUG
m_vCurrentVelocity.Init();
m_vCurrentBanking.Init();
m_vLastPatrolDir.Init();
#endif
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
CAI_BasePhysicsFlyingBot::~CAI_BasePhysicsFlyingBot( void )
{
physenv->DestroyMotionController( m_pMotionController );
}
//-----------------------------------------------------------------------------
// Purpose:
//
//
//-----------------------------------------------------------------------------
bool CAI_BasePhysicsFlyingBot::CreateVPhysics( void )
{
// Create the object in the physics system
IPhysicsObject *pPhysicsObject = VPhysicsInitNormal( SOLID_BBOX, FSOLID_NOT_STANDABLE, false );
m_pMotionController = physenv->CreateMotionController( this );
m_pMotionController->AttachObject( pPhysicsObject, true );
return true;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : *pTarget -
// &chasePosition -
//-----------------------------------------------------------------------------
void CAI_BasePhysicsFlyingBot::TranslateNavGoal( CBaseEntity *pTarget, Vector &chasePosition )
{
Assert( pTarget != NULL );
if ( pTarget == NULL )
{
chasePosition = vec3_origin;
return;
}
// Chase their eyes
chasePosition = pTarget->GetAbsOrigin() + pTarget->GetViewOffset();
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : *pController -
// *pObject -
// deltaTime -
// &linear -
// &angular -
// Output : IMotionEvent::simresult_e
//-----------------------------------------------------------------------------
IMotionEvent::simresult_e CAI_BasePhysicsFlyingBot::Simulate( IPhysicsMotionController *pController, IPhysicsObject *pObject, float deltaTime, Vector &linear, AngularImpulse &angular )
{
static int count;
IPhysicsObject *pPhysicsObject = VPhysicsGetObject();
// Assert( pPhysicsObject );
if (!pPhysicsObject)
return SIM_NOTHING;
// move
Vector actualVelocity;
AngularImpulse actualAngularVelocity;
pPhysicsObject->GetVelocity( &actualVelocity, &actualAngularVelocity );
linear = (m_vCurrentVelocity - actualVelocity) * (0.1 / deltaTime) * 10.0;
/*
DevMsg("Sim %d : %5.1f %5.1f %5.1f\n", count++,
m_vCurrentVelocity.x - actualVelocity.x,
m_vCurrentVelocity.y - actualVelocity.y,
m_vCurrentVelocity.z - actualVelocity.z );
*/
// do angles.
Vector actualPosition;
QAngle actualAngles;
pPhysicsObject->GetPosition( &actualPosition, &actualAngles );
// FIXME: banking currently disabled, forces simple upright posture
angular.x = (UTIL_AngleDiff( m_vCurrentBanking.z, actualAngles.z ) - actualAngularVelocity.x) * (1 / deltaTime);
angular.y = (UTIL_AngleDiff( m_vCurrentBanking.x, actualAngles.x ) - actualAngularVelocity.y) * (1 / deltaTime);
// turn toward target
angular.z = UTIL_AngleDiff( m_fHeadYaw, actualAngles.y + actualAngularVelocity.z * 0.1 ) * (1 / deltaTime);
// angular = m_vCurrentAngularVelocity - actualAngularVelocity;
// DevMsg("Sim %d : %.1f %.1f %.1f (%.1f)\n", count++, actualAngles.x, actualAngles.y, actualAngles.z, m_fHeadYaw );
// FIXME: remove the stuff from MoveExecute();
// FIXME: check MOVE?
ClampMotorForces( linear, angular );
return SIM_GLOBAL_ACCELERATION; // on my local axis. SIM_GLOBAL_ACCELERATION
}
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Base class for many flying NPCs
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "ai_basenpc_physicsflyer.h"
#include "ai_route.h"
#include "ai_navigator.h"
#include "ai_motor.h"
#include "physics_saverestore.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
BEGIN_DATADESC( CAI_BasePhysicsFlyingBot )
DEFINE_FIELD( m_vCurrentVelocity, FIELD_VECTOR),
DEFINE_FIELD( m_vCurrentBanking, FIELD_VECTOR),
DEFINE_FIELD( m_vNoiseMod, FIELD_VECTOR),
DEFINE_FIELD( m_fHeadYaw, FIELD_FLOAT),
DEFINE_FIELD( m_vLastPatrolDir, FIELD_VECTOR),
DEFINE_PHYSPTR( m_pMotionController ),
END_DATADESC()
//------------------------------------------------------------------------------
// Purpose : Override to return correct velocity
// Input :
// Output :
//------------------------------------------------------------------------------
void CAI_BasePhysicsFlyingBot::GetVelocity(Vector *vVelocity, AngularImpulse *vAngVelocity)
{
Assert( GetMoveType() == MOVETYPE_VPHYSICS );
if ( VPhysicsGetObject() )
{
VPhysicsGetObject()->GetVelocity( vVelocity, vAngVelocity );
}
else
{
if ( vVelocity )
{
vVelocity->Init();
}
if ( vAngVelocity )
{
vAngVelocity->Init();
}
}
}
//-----------------------------------------------------------------------------
// Purpose: Turn head yaw into facing direction
// Input :
// Output :
//-----------------------------------------------------------------------------
QAngle CAI_BasePhysicsFlyingBot::BodyAngles()
{
return QAngle(0,m_fHeadYaw,0);
}
//-----------------------------------------------------------------------------
// Purpose:
// Input :
// Output :
//-----------------------------------------------------------------------------
void CAI_BasePhysicsFlyingBot::TurnHeadToTarget(float flInterval, const Vector &MoveTarget )
{
float desYaw = UTIL_AngleDiff(VecToYaw(MoveTarget - GetLocalOrigin()), 0 );
m_fHeadYaw = desYaw;
return;
// If I've flipped completely around, reverse angles
float fYawDiff = m_fHeadYaw - desYaw;
if (fYawDiff > 180)
{
m_fHeadYaw -= 360;
}
else if (fYawDiff < -180)
{
m_fHeadYaw += 360;
}
// RIGHT NOW, this affects every flying bot. This rate should be member data that individuals
// can manipulate. THIS change for MANHACKS E3 2003 (sjb)
float iRate = 0.8;
// Make frame rate independent
float timeToUse = flInterval;
while (timeToUse > 0)
{
m_fHeadYaw = (iRate * m_fHeadYaw) + (1-iRate)*desYaw;
timeToUse -= 0.1;
}
while( m_fHeadYaw > 360 )
{
m_fHeadYaw -= 360.0f;
}
while( m_fHeadYaw < 0 )
{
m_fHeadYaw += 360.f;
}
// SetBoneController( 0, m_fHeadYaw );
}
//------------------------------------------------------------------------------
// Purpose :
// Input :
// Output :
//------------------------------------------------------------------------------
float CAI_BasePhysicsFlyingBot::MinGroundDist(void)
{
return 0;
}
//------------------------------------------------------------------------------
// Purpose :
// Input :
// Output :
//------------------------------------------------------------------------------
Vector CAI_BasePhysicsFlyingBot::VelocityToAvoidObstacles(float flInterval)
{
// --------------------------------
// Avoid banging into stuff
// --------------------------------
trace_t tr;
Vector vTravelDir = m_vCurrentVelocity*flInterval;
Vector endPos = GetAbsOrigin() + vTravelDir;
AI_TraceEntity( this, GetAbsOrigin(), endPos, MASK_NPCSOLID|CONTENTS_WATER, &tr);
if (tr.fraction != 1.0)
{
// Bounce off in normal
Vector vBounce = tr.plane.normal * 0.5 * m_vCurrentVelocity.Length();
return (vBounce);
}
// --------------------------------
// Try to remain above the ground.
// --------------------------------
float flMinGroundDist = MinGroundDist();
AI_TraceLine(GetAbsOrigin(), GetAbsOrigin() + Vector(0, 0, -flMinGroundDist),
MASK_NPCSOLID_BRUSHONLY|CONTENTS_WATER, this, COLLISION_GROUP_NONE, &tr);
if (tr.fraction < 1)
{
// Clamp veloctiy
if (tr.fraction < 0.1)
{
tr.fraction = 0.1;
}
return Vector(0, 0, 50/tr.fraction);
}
return vec3_origin;
}
//------------------------------------------------------------------------------
// Purpose :
// Input :
// Output :
//------------------------------------------------------------------------------
void CAI_BasePhysicsFlyingBot::StartTask( const Task_t *pTask )
{
switch (pTask->iTask)
{
// Skip as done via bone controller
case TASK_FACE_ENEMY:
{
TaskComplete();
break;
}
// Activity is just idle (have no run)
case TASK_RUN_PATH:
{
GetNavigator()->SetMovementActivity(ACT_IDLE);
TaskComplete();
break;
}
// Don't check for run/walk activity
case TASK_SCRIPT_RUN_TO_TARGET:
case TASK_SCRIPT_WALK_TO_TARGET:
{
if (GetTarget() == NULL)
{
TaskFail(FAIL_NO_TARGET);
}
else
{
if (!GetNavigator()->SetGoal( GOALTYPE_TARGETENT ) )
{
TaskFail(FAIL_NO_ROUTE);
GetNavigator()->ClearGoal();
}
}
TaskComplete();
break;
}
// Override to get more to get a directional path
case TASK_GET_PATH_TO_RANDOM_NODE:
{
if ( GetNavigator()->SetRandomGoal( pTask->flTaskData, m_vLastPatrolDir ) )
TaskComplete();
else
TaskFail(FAIL_NO_REACHABLE_NODE);
break;
}
default:
{
BaseClass::StartTask(pTask);
}
}
}
//------------------------------------------------------------------------------
void CAI_BasePhysicsFlyingBot::MoveToTarget(float flInterval, const Vector &MoveTarget)
{
Assert(0); // This must be overridden in the leaf classes
}
//------------------------------------------------------------------------------
AI_NavPathProgress_t CAI_BasePhysicsFlyingBot::ProgressFlyPath(
float flInterval,
const CBaseEntity *pNewTarget,
unsigned collisionMask,
bool bNewTrySimplify,
float strictPointTolerance)
{
AI_ProgressFlyPathParams_t params( collisionMask );
params.strictPointTolerance = strictPointTolerance;
params.SetCurrent( pNewTarget, bNewTrySimplify );
AI_NavPathProgress_t progress = GetNavigator()->ProgressFlyPath( params );
switch ( progress )
{
case AINPP_NO_CHANGE:
case AINPP_ADVANCED:
{
MoveToTarget(flInterval, GetNavigator()->GetCurWaypointPos());
break;
}
case AINPP_COMPLETE:
{
TaskMovementComplete();
break;
}
case AINPP_BLOCKED: // function is not supposed to test blocking, just simple path progression
default:
{
AssertMsg( 0, ( "Unexpected result" ) );
break;
}
}
return progress;
}
//------------------------------------------------------------------------------
// Purpose :
// Input :
// Output :
//------------------------------------------------------------------------------
CAI_BasePhysicsFlyingBot::CAI_BasePhysicsFlyingBot()
{
#ifdef _DEBUG
m_vCurrentVelocity.Init();
m_vCurrentBanking.Init();
m_vLastPatrolDir.Init();
#endif
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
CAI_BasePhysicsFlyingBot::~CAI_BasePhysicsFlyingBot( void )
{
physenv->DestroyMotionController( m_pMotionController );
}
//-----------------------------------------------------------------------------
// Purpose:
//
//
//-----------------------------------------------------------------------------
bool CAI_BasePhysicsFlyingBot::CreateVPhysics( void )
{
// Create the object in the physics system
IPhysicsObject *pPhysicsObject = VPhysicsInitNormal( SOLID_BBOX, FSOLID_NOT_STANDABLE, false );
m_pMotionController = physenv->CreateMotionController( this );
m_pMotionController->AttachObject( pPhysicsObject, true );
return true;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : *pTarget -
// &chasePosition -
//-----------------------------------------------------------------------------
void CAI_BasePhysicsFlyingBot::TranslateNavGoal( CBaseEntity *pTarget, Vector &chasePosition )
{
Assert( pTarget != NULL );
if ( pTarget == NULL )
{
chasePosition = vec3_origin;
return;
}
// Chase their eyes
chasePosition = pTarget->GetAbsOrigin() + pTarget->GetViewOffset();
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : *pController -
// *pObject -
// deltaTime -
// &linear -
// &angular -
// Output : IMotionEvent::simresult_e
//-----------------------------------------------------------------------------
IMotionEvent::simresult_e CAI_BasePhysicsFlyingBot::Simulate( IPhysicsMotionController *pController, IPhysicsObject *pObject, float deltaTime, Vector &linear, AngularImpulse &angular )
{
static int count;
IPhysicsObject *pPhysicsObject = VPhysicsGetObject();
// Assert( pPhysicsObject );
if (!pPhysicsObject)
return SIM_NOTHING;
// move
Vector actualVelocity;
AngularImpulse actualAngularVelocity;
pPhysicsObject->GetVelocity( &actualVelocity, &actualAngularVelocity );
linear = (m_vCurrentVelocity - actualVelocity) * (0.1 / deltaTime) * 10.0;
/*
DevMsg("Sim %d : %5.1f %5.1f %5.1f\n", count++,
m_vCurrentVelocity.x - actualVelocity.x,
m_vCurrentVelocity.y - actualVelocity.y,
m_vCurrentVelocity.z - actualVelocity.z );
*/
// do angles.
Vector actualPosition;
QAngle actualAngles;
pPhysicsObject->GetPosition( &actualPosition, &actualAngles );
// FIXME: banking currently disabled, forces simple upright posture
angular.x = (UTIL_AngleDiff( m_vCurrentBanking.z, actualAngles.z ) - actualAngularVelocity.x) * (1 / deltaTime);
angular.y = (UTIL_AngleDiff( m_vCurrentBanking.x, actualAngles.x ) - actualAngularVelocity.y) * (1 / deltaTime);
// turn toward target
angular.z = UTIL_AngleDiff( m_fHeadYaw, actualAngles.y + actualAngularVelocity.z * 0.1 ) * (1 / deltaTime);
// angular = m_vCurrentAngularVelocity - actualAngularVelocity;
// DevMsg("Sim %d : %.1f %.1f %.1f (%.1f)\n", count++, actualAngles.x, actualAngles.y, actualAngles.z, m_fHeadYaw );
// FIXME: remove the stuff from MoveExecute();
// FIXME: check MOVE?
ClampMotorForces( linear, angular );
return SIM_GLOBAL_ACCELERATION; // on my local axis. SIM_GLOBAL_ACCELERATION
}

View File

@@ -1,149 +1,149 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#ifndef AI_BASENPC_PHYSICSFLYER_H
#define AI_BASENPC_PHYSICSFLYER_H
#ifdef _WIN32
#pragma once
#endif
#include "ai_basenpc.h"
#include "ai_navigator.h"
//-----------------------------------------------------------------------------
// The combot.
//-----------------------------------------------------------------------------
abstract_class CAI_BasePhysicsFlyingBot : public CAI_BaseNPC, public IMotionEvent
{
DECLARE_CLASS( CAI_BasePhysicsFlyingBot, CAI_BaseNPC );
public:
DECLARE_DATADESC();
void StartTask( const Task_t *pTask );
void GetVelocity(Vector *vVelocity, AngularImpulse *vAngVelocity);
virtual QAngle BodyAngles();
virtual bool ShouldSavePhysics() { return true; }
protected:
CAI_BasePhysicsFlyingBot();
~CAI_BasePhysicsFlyingBot();
Vector VelocityToAvoidObstacles(float flInterval);
virtual float MinGroundDist(void);
virtual void TurnHeadToTarget( float flInterval, const Vector &moveTarget );
void MoveInDirection( float flInterval, const Vector &targetDir,
float accelXY, float accelZ, float decay)
{
decay = ExponentialDecay( decay, 1.0, flInterval );
accelXY *= flInterval;
accelZ *= flInterval;
m_vCurrentVelocity.x = ( decay * m_vCurrentVelocity.x + accelXY * targetDir.x );
m_vCurrentVelocity.y = ( decay * m_vCurrentVelocity.y + accelXY * targetDir.y );
m_vCurrentVelocity.z = ( decay * m_vCurrentVelocity.z + accelZ * targetDir.z );
}
void MoveToLocation( float flInterval, const Vector &target,
float accelXY, float accelZ, float decay)
{
Vector targetDir = target - GetLocalOrigin();
VectorNormalize(targetDir);
MoveInDirection(flInterval, targetDir, accelXY, accelZ, decay);
}
void Decelerate( float flInterval, float decay )
{
decay *= flInterval;
m_vCurrentVelocity.x = (decay * m_vCurrentVelocity.x);
m_vCurrentVelocity.y = (decay * m_vCurrentVelocity.y);
m_vCurrentVelocity.z = (decay * m_vCurrentVelocity.z);
}
void AddNoiseToVelocity( float noiseScale = 1.0 )
{
if( m_vNoiseMod.x )
{
m_vCurrentVelocity.x += noiseScale*sin(m_vNoiseMod.x * gpGlobals->curtime + m_vNoiseMod.x);
}
if( m_vNoiseMod.y )
{
m_vCurrentVelocity.y += noiseScale*cos(m_vNoiseMod.y * gpGlobals->curtime + m_vNoiseMod.y);
}
if( m_vNoiseMod.z )
{
m_vCurrentVelocity.z -= noiseScale*cos(m_vNoiseMod.z * gpGlobals->curtime + m_vNoiseMod.z);
}
}
void LimitSpeed( float zLimit, float maxSpeed = -1 )
{
if ( maxSpeed == -1 )
maxSpeed = m_flSpeed;
if (m_vCurrentVelocity.Length() > maxSpeed)
{
VectorNormalize(m_vCurrentVelocity);
m_vCurrentVelocity *= maxSpeed;
}
// Limit fall speed
if (zLimit > 0 && m_vCurrentVelocity.z < -zLimit)
{
m_vCurrentVelocity.z = -zLimit;
}
}
AI_NavPathProgress_t ProgressFlyPath( float flInterval,
const CBaseEntity *pNewTarget,
unsigned collisionMask,
bool bNewTrySimplify = true,
float strictPointTolerance = 32.0 );
const Vector &GetCurrentVelocity() const { return m_vCurrentVelocity; }
void SetCurrentVelocity(const Vector &vNewVel) { m_vCurrentVelocity = vNewVel; }
const Vector &GetNoiseMod() const { return m_vNoiseMod; }
void SetNoiseMod( float x, float y, float z ) { m_vNoiseMod.Init( x, y, z ); }
void SetNoiseMod( const Vector &noise ) { m_vNoiseMod = noise; }
void TranslateNavGoal( CBaseEntity *pTarget, Vector &chasePosition );
virtual void MoveToTarget(float flInterval, const Vector &MoveTarget) = 0;
virtual float GetHeadTurnRate( void ) { return 15.0f; } // Degrees per second
bool CreateVPhysics( void );
IMotionEvent::simresult_e Simulate( IPhysicsMotionController *pController, IPhysicsObject *pObject, float deltaTime, Vector &linear, AngularImpulse &angular );
virtual void ClampMotorForces( Vector &linear, AngularImpulse &angular )
{
// limit reaction forces
linear.x = clamp( linear.x, -3000.f, 3000.f );
linear.y = clamp( linear.y, -3000.f, 3000.f );
linear.z = clamp( linear.z, -3000.f, 3000.f );
// add in weightlessness
linear.z += 800.f;
}
// -------------------------------
// Movement vars
// -------------------------------
Vector m_vCurrentVelocity;
Vector m_vCurrentBanking;
Vector m_vNoiseMod;
float m_fHeadYaw;
Vector m_vLastPatrolDir;
IPhysicsMotionController *m_pMotionController;
};
#endif // AI_BASENPC_PHYSICSFLYER_H
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#ifndef AI_BASENPC_PHYSICSFLYER_H
#define AI_BASENPC_PHYSICSFLYER_H
#ifdef _WIN32
#pragma once
#endif
#include "ai_basenpc.h"
#include "ai_navigator.h"
//-----------------------------------------------------------------------------
// The combot.
//-----------------------------------------------------------------------------
abstract_class CAI_BasePhysicsFlyingBot : public CAI_BaseNPC, public IMotionEvent
{
DECLARE_CLASS( CAI_BasePhysicsFlyingBot, CAI_BaseNPC );
public:
DECLARE_DATADESC();
void StartTask( const Task_t *pTask );
void GetVelocity(Vector *vVelocity, AngularImpulse *vAngVelocity);
virtual QAngle BodyAngles();
virtual bool ShouldSavePhysics() { return true; }
protected:
CAI_BasePhysicsFlyingBot();
~CAI_BasePhysicsFlyingBot();
Vector VelocityToAvoidObstacles(float flInterval);
virtual float MinGroundDist(void);
virtual void TurnHeadToTarget( float flInterval, const Vector &moveTarget );
void MoveInDirection( float flInterval, const Vector &targetDir,
float accelXY, float accelZ, float decay)
{
decay = ExponentialDecay( decay, 1.0, flInterval );
accelXY *= flInterval;
accelZ *= flInterval;
m_vCurrentVelocity.x = ( decay * m_vCurrentVelocity.x + accelXY * targetDir.x );
m_vCurrentVelocity.y = ( decay * m_vCurrentVelocity.y + accelXY * targetDir.y );
m_vCurrentVelocity.z = ( decay * m_vCurrentVelocity.z + accelZ * targetDir.z );
}
void MoveToLocation( float flInterval, const Vector &target,
float accelXY, float accelZ, float decay)
{
Vector targetDir = target - GetLocalOrigin();
VectorNormalize(targetDir);
MoveInDirection(flInterval, targetDir, accelXY, accelZ, decay);
}
void Decelerate( float flInterval, float decay )
{
decay *= flInterval;
m_vCurrentVelocity.x = (decay * m_vCurrentVelocity.x);
m_vCurrentVelocity.y = (decay * m_vCurrentVelocity.y);
m_vCurrentVelocity.z = (decay * m_vCurrentVelocity.z);
}
void AddNoiseToVelocity( float noiseScale = 1.0 )
{
if( m_vNoiseMod.x )
{
m_vCurrentVelocity.x += noiseScale*sin(m_vNoiseMod.x * gpGlobals->curtime + m_vNoiseMod.x);
}
if( m_vNoiseMod.y )
{
m_vCurrentVelocity.y += noiseScale*cos(m_vNoiseMod.y * gpGlobals->curtime + m_vNoiseMod.y);
}
if( m_vNoiseMod.z )
{
m_vCurrentVelocity.z -= noiseScale*cos(m_vNoiseMod.z * gpGlobals->curtime + m_vNoiseMod.z);
}
}
void LimitSpeed( float zLimit, float maxSpeed = -1 )
{
if ( maxSpeed == -1 )
maxSpeed = m_flSpeed;
if (m_vCurrentVelocity.Length() > maxSpeed)
{
VectorNormalize(m_vCurrentVelocity);
m_vCurrentVelocity *= maxSpeed;
}
// Limit fall speed
if (zLimit > 0 && m_vCurrentVelocity.z < -zLimit)
{
m_vCurrentVelocity.z = -zLimit;
}
}
AI_NavPathProgress_t ProgressFlyPath( float flInterval,
const CBaseEntity *pNewTarget,
unsigned collisionMask,
bool bNewTrySimplify = true,
float strictPointTolerance = 32.0 );
const Vector &GetCurrentVelocity() const { return m_vCurrentVelocity; }
void SetCurrentVelocity(const Vector &vNewVel) { m_vCurrentVelocity = vNewVel; }
const Vector &GetNoiseMod() const { return m_vNoiseMod; }
void SetNoiseMod( float x, float y, float z ) { m_vNoiseMod.Init( x, y, z ); }
void SetNoiseMod( const Vector &noise ) { m_vNoiseMod = noise; }
void TranslateNavGoal( CBaseEntity *pTarget, Vector &chasePosition );
virtual void MoveToTarget(float flInterval, const Vector &MoveTarget) = 0;
virtual float GetHeadTurnRate( void ) { return 15.0f; } // Degrees per second
bool CreateVPhysics( void );
IMotionEvent::simresult_e Simulate( IPhysicsMotionController *pController, IPhysicsObject *pObject, float deltaTime, Vector &linear, AngularImpulse &angular );
virtual void ClampMotorForces( Vector &linear, AngularImpulse &angular )
{
// limit reaction forces
linear.x = clamp( linear.x, -3000.f, 3000.f );
linear.y = clamp( linear.y, -3000.f, 3000.f );
linear.z = clamp( linear.z, -3000.f, 3000.f );
// add in weightlessness
linear.z += 800.f;
}
// -------------------------------
// Movement vars
// -------------------------------
Vector m_vCurrentVelocity;
Vector m_vCurrentBanking;
Vector m_vNoiseMod;
float m_fHeadYaw;
Vector m_vLastPatrolDir;
IPhysicsMotionController *m_pMotionController;
};
#endif // AI_BASENPC_PHYSICSFLYER_H

File diff suppressed because it is too large Load Diff

View File

@@ -1,292 +1,292 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $Workfile: $
// $Date: $
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "ai_basenpc.h"
#include "ai_default.h"
#include "ai_hull.h"
#include "ai_squadslot.h"
#include "ai_squad.h"
#include "bitstring.h"
#include "entitylist.h"
#include "ai_hint.h"
#include "IEffects.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
//-----------------------------------------------------------------------------
// Purpose: If requested slot is available return true and take the slot
// Otherwise return false
// Input :
// Output :
//-----------------------------------------------------------------------------
bool CAI_BaseNPC::OccupyStrategySlot( int squadSlotID )
{
return OccupyStrategySlotRange( squadSlotID, squadSlotID );
}
//-----------------------------------------------------------------------------
bool CAI_BaseNPC::OccupyStrategySlotRange( int slotIDStart, int slotIDEnd )
{
// If I'm not in a squad a I don't fill slots
return ( !m_pSquad || m_pSquad->OccupyStrategySlotRange( GetEnemy(), slotIDStart, slotIDEnd, &m_iMySquadSlot ) );
}
//-----------------------------------------------------------------------------
// Returns true if all in the range are full
//-----------------------------------------------------------------------------
bool CAI_BaseNPC::IsStrategySlotRangeOccupied( int slotIDStart, int slotIDEnd )
{
return m_pSquad && m_pSquad->IsStrategySlotRangeOccupied( GetEnemy(), slotIDStart, slotIDEnd );
}
//=========================================================
// HasStrategySlot
//=========================================================
bool CAI_BaseNPC::HasStrategySlot( int squadSlotID )
{
// If I wasn't taking up a squad slot I'm done
return (m_iMySquadSlot == squadSlotID);
}
bool CAI_BaseNPC::HasStrategySlotRange( int slotIDStart, int slotIDEnd )
{
// If I wasn't taking up a squad slot I'm done
if (m_iMySquadSlot < slotIDStart || m_iMySquadSlot > slotIDEnd)
{
return false;
}
return true;
}
//=========================================================
// VacateSlot
//=========================================================
void CAI_BaseNPC::VacateStrategySlot(void)
{
if (m_pSquad)
{
m_pSquad->VacateStrategySlot(GetEnemy(), m_iMySquadSlot);
m_iMySquadSlot = SQUAD_SLOT_NONE;
}
}
//------------------------------------------------------------------------------
// Purpose : Is cover node valid
// Input :
// Output :
//------------------------------------------------------------------------------
bool CAI_BaseNPC::IsValidCover( const Vector &vecCoverLocation, CAI_Hint const *pHint )
{
// firstly, limit choices to hint groups
string_t iszHint = GetHintGroup();
char *pszHint = (char *)STRING(iszHint);
if ((iszHint != NULL_STRING) && (pszHint[0] != '\0'))
{
if (!pHint || pHint->GetGroup() != GetHintGroup())
{
return false;
}
}
/*
// If I'm in a squad don't pick cover node it other squad member
// is already nearby
if (m_pSquad)
{
return m_pSquad->IsValidCover( vecCoverLocation, pHint );
}
*/
// UNDONE: Do we really need this test?
// ----------------------------------------------------------------
// Make sure my hull can fit at this node before accepting it.
// Could be another NPC there or it could be blocked
// ----------------------------------------------------------------
// FIXME: shouldn't this see that if I crouch behind it it'll be safe?
Vector startPos = vecCoverLocation;
startPos.z -= GetHullMins().z; // Move hull bottom up to node
Vector endPos = startPos;
endPos.z += 0.01;
trace_t tr;
AI_TraceEntity( this, vecCoverLocation, endPos, MASK_NPCSOLID, &tr );
if (tr.startsolid)
{
return false;
}
return true;
}
//-----------------------------------------------------------------------------
// Purpose: Is squad member in my way from shooting here
// Input :
// Output :
//-----------------------------------------------------------------------------
bool CAI_BaseNPC::IsValidShootPosition( const Vector &vecShootLocation, CAI_Node *pNode, CAI_Hint const *pHint )
{
// limit choices to hint groups
if (GetHintGroup() != NULL_STRING)
{
if (!pHint || pHint->GetGroup() != GetHintGroup())
{
if ( ( vecShootLocation - GetAbsOrigin() ).Length2DSqr() > 1 )
return false;
}
}
return true;
}
//-----------------------------------------------------------------------------
bool CAI_BaseNPC::IsSquadmateInSpread( const Vector &sourcePos, const Vector &targetPos, float flSpread, float maxDistOffCenter )
{
if( !m_pSquad )
return false;
AISquadIter_t iter;
CAI_BaseNPC *pSquadmate = m_pSquad->GetFirstMember( &iter );
while ( pSquadmate )
{
// Ignore squadmates that can't take damage. This is primarily to ignore npc_enemyfinders.
if ( pSquadmate->m_takedamage != DAMAGE_NO )
{
if ( pSquadmate != this )
{
if ( PointInSpread( pSquadmate, sourcePos, targetPos, pSquadmate->GetAbsOrigin(), flSpread, maxDistOffCenter ) )
return true;
}
}
pSquadmate = m_pSquad->GetNextMember( &iter );
}
return false;
}
//-----------------------------------------------------------------------------
void CAI_BaseNPC::AddToSquad( string_t name )
{
g_AI_SquadManager.FindCreateSquad( this, name );
}
//-----------------------------------------------------------------------------
void CAI_BaseNPC::SetSquad( CAI_Squad *pSquad )
{
if ( m_pSquad == pSquad )
{
return;
}
if ( m_pSquad && m_iMySquadSlot != SQUAD_SLOT_NONE)
{
VacateStrategySlot();
}
m_pSquad = pSquad;
}
//-----------------------------------------------------------------------------
void CAI_BaseNPC::RemoveFromSquad()
{
if ( m_pSquad )
{
m_pSquad->RemoveFromSquad( this, false );
m_pSquad = NULL;
}
}
//-----------------------------------------------------------------------------
void CAI_BaseNPC::CheckSquad()
{
if( !IsInSquad() )
return;
if( !GetSquad()->IsLeader(this) )
return;
if( VPhysicsGetObject() != NULL && (VPhysicsGetObject()->GetGameFlags() & FVPHYSICS_PLAYER_HELD) )
{
// I AM the leader, and I'm currently being held. This will screw up all of my relationship checks
// if I'm a manhack or a rollermine, so just bomb out and try next time.
return;
}
AISquadIter_t iter;
CAI_BaseNPC *pSquadmate = m_pSquad->GetFirstMember( &iter );
while ( pSquadmate )
{
if( IRelationType(pSquadmate) < D_LI )
{
bool bWarn = true;
// Rollermines and manhacks set their Class to NONE when held by the player, which makes all of
// their squadmates complain that an enemy is in the squad. Suppress this.
if( pSquadmate->VPhysicsGetObject() != NULL )
{
if (pSquadmate->VPhysicsGetObject()->GetGameFlags() & FVPHYSICS_PLAYER_HELD)
{
bWarn = false;
}
}
if( bWarn )
{
Warning( "ERROR: Squad '%s' has enemies in it!\n", GetSquad()->GetName() );
Warning( "%s doesn't like %s\n\n", GetDebugName(), pSquadmate->GetDebugName() );
}
}
pSquadmate = m_pSquad->GetNextMember( &iter );
}
}
//-----------------------------------------------------------------------------
// Returns the number of weapons of this type currently owned by squad members.
//-----------------------------------------------------------------------------
int CAI_BaseNPC::NumWeaponsInSquad( const char *pszWeaponClassname )
{
string_t iszWeaponClassname = FindPooledString( pszWeaponClassname );
if( !GetSquad() )
{
if( GetActiveWeapon() && GetActiveWeapon()->m_iClassname == iszWeaponClassname )
{
// I'm alone in my squad, but I do have this weapon.
return 1;
}
return 0;
}
int count = 0;
AISquadIter_t iter;
CAI_BaseNPC *pSquadmate = m_pSquad->GetFirstMember( &iter );
while ( pSquadmate )
{
if( pSquadmate->GetActiveWeapon() && pSquadmate->GetActiveWeapon()->m_iClassname == iszWeaponClassname )
{
count++;
}
pSquadmate = m_pSquad->GetNextMember( &iter );
}
return count;
}
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $Workfile: $
// $Date: $
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "ai_basenpc.h"
#include "ai_default.h"
#include "ai_hull.h"
#include "ai_squadslot.h"
#include "ai_squad.h"
#include "bitstring.h"
#include "entitylist.h"
#include "ai_hint.h"
#include "IEffects.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
//-----------------------------------------------------------------------------
// Purpose: If requested slot is available return true and take the slot
// Otherwise return false
// Input :
// Output :
//-----------------------------------------------------------------------------
bool CAI_BaseNPC::OccupyStrategySlot( int squadSlotID )
{
return OccupyStrategySlotRange( squadSlotID, squadSlotID );
}
//-----------------------------------------------------------------------------
bool CAI_BaseNPC::OccupyStrategySlotRange( int slotIDStart, int slotIDEnd )
{
// If I'm not in a squad a I don't fill slots
return ( !m_pSquad || m_pSquad->OccupyStrategySlotRange( GetEnemy(), slotIDStart, slotIDEnd, &m_iMySquadSlot ) );
}
//-----------------------------------------------------------------------------
// Returns true if all in the range are full
//-----------------------------------------------------------------------------
bool CAI_BaseNPC::IsStrategySlotRangeOccupied( int slotIDStart, int slotIDEnd )
{
return m_pSquad && m_pSquad->IsStrategySlotRangeOccupied( GetEnemy(), slotIDStart, slotIDEnd );
}
//=========================================================
// HasStrategySlot
//=========================================================
bool CAI_BaseNPC::HasStrategySlot( int squadSlotID )
{
// If I wasn't taking up a squad slot I'm done
return (m_iMySquadSlot == squadSlotID);
}
bool CAI_BaseNPC::HasStrategySlotRange( int slotIDStart, int slotIDEnd )
{
// If I wasn't taking up a squad slot I'm done
if (m_iMySquadSlot < slotIDStart || m_iMySquadSlot > slotIDEnd)
{
return false;
}
return true;
}
//=========================================================
// VacateSlot
//=========================================================
void CAI_BaseNPC::VacateStrategySlot(void)
{
if (m_pSquad)
{
m_pSquad->VacateStrategySlot(GetEnemy(), m_iMySquadSlot);
m_iMySquadSlot = SQUAD_SLOT_NONE;
}
}
//------------------------------------------------------------------------------
// Purpose : Is cover node valid
// Input :
// Output :
//------------------------------------------------------------------------------
bool CAI_BaseNPC::IsValidCover( const Vector &vecCoverLocation, CAI_Hint const *pHint )
{
// firstly, limit choices to hint groups
string_t iszHint = GetHintGroup();
char *pszHint = (char *)STRING(iszHint);
if ((iszHint != NULL_STRING) && (pszHint[0] != '\0'))
{
if (!pHint || pHint->GetGroup() != GetHintGroup())
{
return false;
}
}
/*
// If I'm in a squad don't pick cover node it other squad member
// is already nearby
if (m_pSquad)
{
return m_pSquad->IsValidCover( vecCoverLocation, pHint );
}
*/
// UNDONE: Do we really need this test?
// ----------------------------------------------------------------
// Make sure my hull can fit at this node before accepting it.
// Could be another NPC there or it could be blocked
// ----------------------------------------------------------------
// FIXME: shouldn't this see that if I crouch behind it it'll be safe?
Vector startPos = vecCoverLocation;
startPos.z -= GetHullMins().z; // Move hull bottom up to node
Vector endPos = startPos;
endPos.z += 0.01;
trace_t tr;
AI_TraceEntity( this, vecCoverLocation, endPos, MASK_NPCSOLID, &tr );
if (tr.startsolid)
{
return false;
}
return true;
}
//-----------------------------------------------------------------------------
// Purpose: Is squad member in my way from shooting here
// Input :
// Output :
//-----------------------------------------------------------------------------
bool CAI_BaseNPC::IsValidShootPosition( const Vector &vecShootLocation, CAI_Node *pNode, CAI_Hint const *pHint )
{
// limit choices to hint groups
if (GetHintGroup() != NULL_STRING)
{
if (!pHint || pHint->GetGroup() != GetHintGroup())
{
if ( ( vecShootLocation - GetAbsOrigin() ).Length2DSqr() > 1 )
return false;
}
}
return true;
}
//-----------------------------------------------------------------------------
bool CAI_BaseNPC::IsSquadmateInSpread( const Vector &sourcePos, const Vector &targetPos, float flSpread, float maxDistOffCenter )
{
if( !m_pSquad )
return false;
AISquadIter_t iter;
CAI_BaseNPC *pSquadmate = m_pSquad->GetFirstMember( &iter );
while ( pSquadmate )
{
// Ignore squadmates that can't take damage. This is primarily to ignore npc_enemyfinders.
if ( pSquadmate->m_takedamage != DAMAGE_NO )
{
if ( pSquadmate != this )
{
if ( PointInSpread( pSquadmate, sourcePos, targetPos, pSquadmate->GetAbsOrigin(), flSpread, maxDistOffCenter ) )
return true;
}
}
pSquadmate = m_pSquad->GetNextMember( &iter );
}
return false;
}
//-----------------------------------------------------------------------------
void CAI_BaseNPC::AddToSquad( string_t name )
{
g_AI_SquadManager.FindCreateSquad( this, name );
}
//-----------------------------------------------------------------------------
void CAI_BaseNPC::SetSquad( CAI_Squad *pSquad )
{
if ( m_pSquad == pSquad )
{
return;
}
if ( m_pSquad && m_iMySquadSlot != SQUAD_SLOT_NONE)
{
VacateStrategySlot();
}
m_pSquad = pSquad;
}
//-----------------------------------------------------------------------------
void CAI_BaseNPC::RemoveFromSquad()
{
if ( m_pSquad )
{
m_pSquad->RemoveFromSquad( this, false );
m_pSquad = NULL;
}
}
//-----------------------------------------------------------------------------
void CAI_BaseNPC::CheckSquad()
{
if( !IsInSquad() )
return;
if( !GetSquad()->IsLeader(this) )
return;
if( VPhysicsGetObject() != NULL && (VPhysicsGetObject()->GetGameFlags() & FVPHYSICS_PLAYER_HELD) )
{
// I AM the leader, and I'm currently being held. This will screw up all of my relationship checks
// if I'm a manhack or a rollermine, so just bomb out and try next time.
return;
}
AISquadIter_t iter;
CAI_BaseNPC *pSquadmate = m_pSquad->GetFirstMember( &iter );
while ( pSquadmate )
{
if( IRelationType(pSquadmate) < D_LI )
{
bool bWarn = true;
// Rollermines and manhacks set their Class to NONE when held by the player, which makes all of
// their squadmates complain that an enemy is in the squad. Suppress this.
if( pSquadmate->VPhysicsGetObject() != NULL )
{
if (pSquadmate->VPhysicsGetObject()->GetGameFlags() & FVPHYSICS_PLAYER_HELD)
{
bWarn = false;
}
}
if( bWarn )
{
Warning( "ERROR: Squad '%s' has enemies in it!\n", GetSquad()->GetName() );
Warning( "%s doesn't like %s\n\n", GetDebugName(), pSquadmate->GetDebugName() );
}
}
pSquadmate = m_pSquad->GetNextMember( &iter );
}
}
//-----------------------------------------------------------------------------
// Returns the number of weapons of this type currently owned by squad members.
//-----------------------------------------------------------------------------
int CAI_BaseNPC::NumWeaponsInSquad( const char *pszWeaponClassname )
{
string_t iszWeaponClassname = FindPooledString( pszWeaponClassname );
if( !GetSquad() )
{
if( GetActiveWeapon() && GetActiveWeapon()->m_iClassname == iszWeaponClassname )
{
// I'm alone in my squad, but I do have this weapon.
return 1;
}
return 0;
}
int count = 0;
AISquadIter_t iter;
CAI_BaseNPC *pSquadmate = m_pSquad->GetFirstMember( &iter );
while ( pSquadmate )
{
if( pSquadmate->GetActiveWeapon() && pSquadmate->GetActiveWeapon()->m_iClassname == iszWeaponClassname )
{
count++;
}
pSquadmate = m_pSquad->GetNextMember( &iter );
}
return count;
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,299 +1,299 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#ifndef AI_BEHAVIOR_ASSAULT_H
#define AI_BEHAVIOR_ASSAULT_H
#ifdef _WIN32
#pragma once
#endif
#include "simtimer.h"
#include "ai_behavior.h"
#include "ai_goalentity.h"
#include "ai_moveshoot.h"
#include "ai_utils.h"
#define CUE_POINT_TOLERANCE (3.0*12.0)
enum RallySelectMethod_t
{
RALLY_POINT_SELECT_DEFAULT = 0,
RALLY_POINT_SELECT_RANDOM,
};
enum AssaultCue_t
{
CUE_NO_ASSAULT = 0, // used to indicate that no assault is being conducted presently
CUE_ENTITY_INPUT = 1,
CUE_PLAYER_GUNFIRE,
CUE_DONT_WAIT,
CUE_COMMANDER,
CUE_NONE,
};
enum
{
ASSAULT_SENTENCE_HIT_RALLY_POINT = SENTENCE_BASE_BEHAVIOR_INDEX,
ASSAULT_SENTENCE_HIT_ASSAULT_POINT,
ASSAULT_SENTENCE_SQUAD_ADVANCE_TO_RALLY,
ASSAULT_SENTENCE_SQUAD_ADVANCE_TO_ASSAULT,
ASSAULT_SENTENCE_COVER_NO_AMMO,
ASSAULT_SENTENCE_UNDER_ATTACK,
};
// Allow diversion from the assault up to this amount of time after last having an enemy
#define ASSAULT_DIVERSION_TIME 4
#define SF_ASSAULTPOINT_CLEARONARRIVAL 0x00000001
//=============================================================================
//=============================================================================
class CRallyPoint : public CPointEntity
{
DECLARE_CLASS( CRallyPoint, CPointEntity );
public:
CRallyPoint()
{
m_hLockedBy.Set(NULL);
m_sExclusivity = RALLY_EXCLUSIVE_NOT_EVALUATED;
}
bool Lock( CBaseEntity *pLocker )
{
if( IsLocked() )
{
// Already locked.
return false;
}
m_hLockedBy.Set( pLocker );
return true;
}
bool Unlock( CBaseEntity *pUnlocker )
{
if( IsLocked() )
{
if( m_hLockedBy.Get() != pUnlocker )
{
// Refuse! Only the locker may unlock.
return false;
}
}
m_hLockedBy.Set( NULL );
return true;
}
bool IsLocked( void ) { return (m_hLockedBy.Get() != NULL); }
int DrawDebugTextOverlays();
bool IsExclusive();
enum
{
RALLY_EXCLUSIVE_NOT_EVALUATED = -1,
RALLY_EXCLUSIVE_NO,
RALLY_EXCLUSIVE_YES,
};
string_t m_AssaultPointName;
string_t m_RallySequenceName;
float m_flAssaultDelay;
int m_iPriority;
int m_iStrictness;
bool m_bForceCrouch;
bool m_bIsUrgent;
short m_sExclusivity;
COutputEvent m_OnArrival;
DECLARE_DATADESC();
private:
EHANDLE m_hLockedBy;
};
//=============================================================================
//=============================================================================
class CAssaultPoint : public CPointEntity
{
DECLARE_CLASS( CAssaultPoint, CPointEntity );
public:
CAssaultPoint()
{
// This used to be a constant in code. Now it's a keyfield in hammer.
// So in the constructor, we set this value to the former constant
// default value, for legacy maps. (sjb)
m_flAssaultPointTolerance = CUE_POINT_TOLERANCE;
}
void InputSetClearOnContact( inputdata_t &inputdata )
{
m_bClearOnContact = inputdata.value.Bool();
}
void InputSetAllowDiversion( inputdata_t &inputdata )
{
m_bAllowDiversion = inputdata.value.Bool();
}
void InputSetForceClear( inputdata_t &inputdata )
{
m_bInputForcedClear = inputdata.value.Bool();
}
public:
string_t m_AssaultHintGroup;
string_t m_NextAssaultPointName;
COutputEvent m_OnAssaultClear;
float m_flAssaultTimeout;
bool m_bClearOnContact;
bool m_bAllowDiversion;
float m_flAllowDiversionRadius;
bool m_bNeverTimeout;
int m_iStrictness;
bool m_bForceCrouch;
bool m_bIsUrgent;
bool m_bInputForcedClear;
float m_flAssaultPointTolerance;
float m_flTimeLastUsed;
COutputEvent m_OnArrival;
DECLARE_DATADESC();
};
//=============================================================================
//=============================================================================
class CAI_AssaultBehavior : public CAI_SimpleBehavior
{
DECLARE_CLASS( CAI_AssaultBehavior, CAI_SimpleBehavior );
public:
CAI_AssaultBehavior();
virtual const char *GetName() { return "Assault"; }
virtual int DrawDebugTextOverlays( int text_offset );
virtual void OnRestore();
bool CanRunAScriptedNPCInteraction( bool bForced );
virtual bool CanSelectSchedule();
virtual void BeginScheduleSelection();
virtual void EndScheduleSelection();
bool HasHitRallyPoint() { return m_bHitRallyPoint; }
bool HasHitAssaultPoint() { return m_bHitAssaultPoint; }
void ClearAssaultPoint( void );
void OnHitAssaultPoint( void );
bool PollAssaultCue( void );
void ReceiveAssaultCue( AssaultCue_t cue );
bool HasAssaultCue( void ) { return m_AssaultCue != CUE_NO_ASSAULT; }
bool AssaultHasBegun();
CAssaultPoint *FindAssaultPoint( string_t iszAssaultPointName );
void SetAssaultPoint( CAssaultPoint *pAssaultPoint );
void GatherConditions( void );
void StartTask( const Task_t *pTask );
void RunTask( const Task_t *pTask );
void BuildScheduleTestBits();
int TranslateSchedule( int scheduleType );
void OnStartSchedule( int scheduleType );
void ClearSchedule( const char *szReason );
void InitializeBehavior();
void SetParameters( string_t rallypointname, AssaultCue_t assaultcue, int rallySelectMethod );
void SetParameters( CBaseEntity *pRallyEnt, AssaultCue_t assaultcue );
bool IsAllowedToDivert( void );
bool IsValidShootPosition( const Vector &vLocation, CAI_Node *pNode, CAI_Hint const *pHint );
float GetMaxTacticalLateralMovement( void );
void UpdateOnRemove();
bool OnStrictAssault( void );
bool UpdateForceCrouch( void );
bool IsForcingCrouch( void );
bool IsUrgent( void );
CRallyPoint *FindBestRallyPointInRadius( const Vector &vecCenter, float flRadius );;
void Disable( void ) { m_AssaultCue = CUE_NO_ASSAULT; m_bHitRallyPoint = false; m_bHitAssaultPoint = false; }
enum
{
SCHED_MOVE_TO_RALLY_POINT = BaseClass::NEXT_SCHEDULE, // Try to get out of the player's way
SCHED_ASSAULT_FAILED_TO_MOVE,
SCHED_FAIL_MOVE_TO_RALLY_POINT,
SCHED_MOVE_TO_ASSAULT_POINT,
SCHED_AT_ASSAULT_POINT,
SCHED_HOLD_RALLY_POINT,
SCHED_HOLD_ASSAULT_POINT,
SCHED_WAIT_AND_CLEAR,
SCHED_ASSAULT_MOVE_AWAY,
SCHED_CLEAR_ASSAULT_POINT,
NEXT_SCHEDULE,
TASK_GET_PATH_TO_RALLY_POINT = BaseClass::NEXT_TASK,
TASK_FACE_RALLY_POINT,
TASK_GET_PATH_TO_ASSAULT_POINT,
TASK_FACE_ASSAULT_POINT,
TASK_HIT_ASSAULT_POINT,
TASK_HIT_RALLY_POINT,
TASK_AWAIT_CUE,
TASK_AWAIT_ASSAULT_TIMEOUT,
TASK_ANNOUNCE_CLEAR,
TASK_WAIT_ASSAULT_DELAY,
TASK_ASSAULT_MOVE_AWAY_PATH,
TASK_ASSAULT_DEFER_SCHEDULE_SELECTION,
NEXT_TASK,
/*
COND_PUT_CONDITIONS_HERE = BaseClass::NEXT_CONDITION,
NEXT_CONDITION,
*/
};
DEFINE_CUSTOM_SCHEDULE_PROVIDER;
public:
CHandle<CAssaultPoint> m_hAssaultPoint;
CHandle<CRallyPoint> m_hRallyPoint;
public:
void UnlockRallyPoint( void );
private:
void OnScheduleChange();
virtual int SelectSchedule();
AssaultCue_t m_AssaultCue; // the cue we're waiting for to begin the assault
AssaultCue_t m_ReceivedAssaultCue; // the last assault cue we received from someone/thing external.
bool m_bHitRallyPoint;
bool m_bHitAssaultPoint;
// Diversion
bool m_bDiverting;
float m_flLastSawAnEnemyAt;
float m_flTimeDeferScheduleSelection;
string_t m_AssaultPointName;
//---------------------------------
DECLARE_DATADESC();
};
#endif // AI_BEHAVIOR_ASSAULT_H
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#ifndef AI_BEHAVIOR_ASSAULT_H
#define AI_BEHAVIOR_ASSAULT_H
#ifdef _WIN32
#pragma once
#endif
#include "simtimer.h"
#include "ai_behavior.h"
#include "ai_goalentity.h"
#include "ai_moveshoot.h"
#include "ai_utils.h"
#define CUE_POINT_TOLERANCE (3.0*12.0)
enum RallySelectMethod_t
{
RALLY_POINT_SELECT_DEFAULT = 0,
RALLY_POINT_SELECT_RANDOM,
};
enum AssaultCue_t
{
CUE_NO_ASSAULT = 0, // used to indicate that no assault is being conducted presently
CUE_ENTITY_INPUT = 1,
CUE_PLAYER_GUNFIRE,
CUE_DONT_WAIT,
CUE_COMMANDER,
CUE_NONE,
};
enum
{
ASSAULT_SENTENCE_HIT_RALLY_POINT = SENTENCE_BASE_BEHAVIOR_INDEX,
ASSAULT_SENTENCE_HIT_ASSAULT_POINT,
ASSAULT_SENTENCE_SQUAD_ADVANCE_TO_RALLY,
ASSAULT_SENTENCE_SQUAD_ADVANCE_TO_ASSAULT,
ASSAULT_SENTENCE_COVER_NO_AMMO,
ASSAULT_SENTENCE_UNDER_ATTACK,
};
// Allow diversion from the assault up to this amount of time after last having an enemy
#define ASSAULT_DIVERSION_TIME 4
#define SF_ASSAULTPOINT_CLEARONARRIVAL 0x00000001
//=============================================================================
//=============================================================================
class CRallyPoint : public CPointEntity
{
DECLARE_CLASS( CRallyPoint, CPointEntity );
public:
CRallyPoint()
{
m_hLockedBy.Set(NULL);
m_sExclusivity = RALLY_EXCLUSIVE_NOT_EVALUATED;
}
bool Lock( CBaseEntity *pLocker )
{
if( IsLocked() )
{
// Already locked.
return false;
}
m_hLockedBy.Set( pLocker );
return true;
}
bool Unlock( CBaseEntity *pUnlocker )
{
if( IsLocked() )
{
if( m_hLockedBy.Get() != pUnlocker )
{
// Refuse! Only the locker may unlock.
return false;
}
}
m_hLockedBy.Set( NULL );
return true;
}
bool IsLocked( void ) { return (m_hLockedBy.Get() != NULL); }
int DrawDebugTextOverlays();
bool IsExclusive();
enum
{
RALLY_EXCLUSIVE_NOT_EVALUATED = -1,
RALLY_EXCLUSIVE_NO,
RALLY_EXCLUSIVE_YES,
};
string_t m_AssaultPointName;
string_t m_RallySequenceName;
float m_flAssaultDelay;
int m_iPriority;
int m_iStrictness;
bool m_bForceCrouch;
bool m_bIsUrgent;
short m_sExclusivity;
COutputEvent m_OnArrival;
DECLARE_DATADESC();
private:
EHANDLE m_hLockedBy;
};
//=============================================================================
//=============================================================================
class CAssaultPoint : public CPointEntity
{
DECLARE_CLASS( CAssaultPoint, CPointEntity );
public:
CAssaultPoint()
{
// This used to be a constant in code. Now it's a keyfield in hammer.
// So in the constructor, we set this value to the former constant
// default value, for legacy maps. (sjb)
m_flAssaultPointTolerance = CUE_POINT_TOLERANCE;
}
void InputSetClearOnContact( inputdata_t &inputdata )
{
m_bClearOnContact = inputdata.value.Bool();
}
void InputSetAllowDiversion( inputdata_t &inputdata )
{
m_bAllowDiversion = inputdata.value.Bool();
}
void InputSetForceClear( inputdata_t &inputdata )
{
m_bInputForcedClear = inputdata.value.Bool();
}
public:
string_t m_AssaultHintGroup;
string_t m_NextAssaultPointName;
COutputEvent m_OnAssaultClear;
float m_flAssaultTimeout;
bool m_bClearOnContact;
bool m_bAllowDiversion;
float m_flAllowDiversionRadius;
bool m_bNeverTimeout;
int m_iStrictness;
bool m_bForceCrouch;
bool m_bIsUrgent;
bool m_bInputForcedClear;
float m_flAssaultPointTolerance;
float m_flTimeLastUsed;
COutputEvent m_OnArrival;
DECLARE_DATADESC();
};
//=============================================================================
//=============================================================================
class CAI_AssaultBehavior : public CAI_SimpleBehavior
{
DECLARE_CLASS( CAI_AssaultBehavior, CAI_SimpleBehavior );
public:
CAI_AssaultBehavior();
virtual const char *GetName() { return "Assault"; }
virtual int DrawDebugTextOverlays( int text_offset );
virtual void OnRestore();
bool CanRunAScriptedNPCInteraction( bool bForced );
virtual bool CanSelectSchedule();
virtual void BeginScheduleSelection();
virtual void EndScheduleSelection();
bool HasHitRallyPoint() { return m_bHitRallyPoint; }
bool HasHitAssaultPoint() { return m_bHitAssaultPoint; }
void ClearAssaultPoint( void );
void OnHitAssaultPoint( void );
bool PollAssaultCue( void );
void ReceiveAssaultCue( AssaultCue_t cue );
bool HasAssaultCue( void ) { return m_AssaultCue != CUE_NO_ASSAULT; }
bool AssaultHasBegun();
CAssaultPoint *FindAssaultPoint( string_t iszAssaultPointName );
void SetAssaultPoint( CAssaultPoint *pAssaultPoint );
void GatherConditions( void );
void StartTask( const Task_t *pTask );
void RunTask( const Task_t *pTask );
void BuildScheduleTestBits();
int TranslateSchedule( int scheduleType );
void OnStartSchedule( int scheduleType );
void ClearSchedule( const char *szReason );
void InitializeBehavior();
void SetParameters( string_t rallypointname, AssaultCue_t assaultcue, int rallySelectMethod );
void SetParameters( CBaseEntity *pRallyEnt, AssaultCue_t assaultcue );
bool IsAllowedToDivert( void );
bool IsValidShootPosition( const Vector &vLocation, CAI_Node *pNode, CAI_Hint const *pHint );
float GetMaxTacticalLateralMovement( void );
void UpdateOnRemove();
bool OnStrictAssault( void );
bool UpdateForceCrouch( void );
bool IsForcingCrouch( void );
bool IsUrgent( void );
CRallyPoint *FindBestRallyPointInRadius( const Vector &vecCenter, float flRadius );;
void Disable( void ) { m_AssaultCue = CUE_NO_ASSAULT; m_bHitRallyPoint = false; m_bHitAssaultPoint = false; }
enum
{
SCHED_MOVE_TO_RALLY_POINT = BaseClass::NEXT_SCHEDULE, // Try to get out of the player's way
SCHED_ASSAULT_FAILED_TO_MOVE,
SCHED_FAIL_MOVE_TO_RALLY_POINT,
SCHED_MOVE_TO_ASSAULT_POINT,
SCHED_AT_ASSAULT_POINT,
SCHED_HOLD_RALLY_POINT,
SCHED_HOLD_ASSAULT_POINT,
SCHED_WAIT_AND_CLEAR,
SCHED_ASSAULT_MOVE_AWAY,
SCHED_CLEAR_ASSAULT_POINT,
NEXT_SCHEDULE,
TASK_GET_PATH_TO_RALLY_POINT = BaseClass::NEXT_TASK,
TASK_FACE_RALLY_POINT,
TASK_GET_PATH_TO_ASSAULT_POINT,
TASK_FACE_ASSAULT_POINT,
TASK_HIT_ASSAULT_POINT,
TASK_HIT_RALLY_POINT,
TASK_AWAIT_CUE,
TASK_AWAIT_ASSAULT_TIMEOUT,
TASK_ANNOUNCE_CLEAR,
TASK_WAIT_ASSAULT_DELAY,
TASK_ASSAULT_MOVE_AWAY_PATH,
TASK_ASSAULT_DEFER_SCHEDULE_SELECTION,
NEXT_TASK,
/*
COND_PUT_CONDITIONS_HERE = BaseClass::NEXT_CONDITION,
NEXT_CONDITION,
*/
};
DEFINE_CUSTOM_SCHEDULE_PROVIDER;
public:
CHandle<CAssaultPoint> m_hAssaultPoint;
CHandle<CRallyPoint> m_hRallyPoint;
public:
void UnlockRallyPoint( void );
private:
void OnScheduleChange();
virtual int SelectSchedule();
AssaultCue_t m_AssaultCue; // the cue we're waiting for to begin the assault
AssaultCue_t m_ReceivedAssaultCue; // the last assault cue we received from someone/thing external.
bool m_bHitRallyPoint;
bool m_bHitAssaultPoint;
// Diversion
bool m_bDiverting;
float m_flLastSawAnEnemyAt;
float m_flTimeDeferScheduleSelection;
string_t m_AssaultPointName;
//---------------------------------
DECLARE_DATADESC();
};
#endif // AI_BEHAVIOR_ASSAULT_H

File diff suppressed because it is too large Load Diff

View File

@@ -1,98 +1,98 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Deal intelligently with an enemy that we're afraid of
//
// $Workfile: $
// $Date: $
//
//-----------------------------------------------------------------------------
// $Log: $
//
// $NoKeywords: $
//=============================================================================//
#ifndef AI_BEHAVIOR_FEAR_H
#define AI_BEHAVIOR_FEAR_H
#ifdef _WIN32
#pragma once
#endif
#include "ai_behavior.h"
class CAI_FearBehavior : public CAI_SimpleBehavior
{
DECLARE_CLASS( CAI_FearBehavior, CAI_SimpleBehavior );
public:
CAI_FearBehavior();
void Precache( void );
virtual const char *GetName() { return "Fear"; }
virtual bool CanSelectSchedule();
void GatherConditions();
virtual void BeginScheduleSelection();
virtual void EndScheduleSelection();
void StartTask( const Task_t *pTask );
void RunTask( const Task_t *pTask );
//void BuildScheduleTestBits();
//int TranslateSchedule( int scheduleType );
//void OnStartSchedule( int scheduleType );
//void InitializeBehavior();
bool EnemyDislikesMe();
void MarkAsUnsafe();
bool IsInASafePlace();
void SpoilSafePlace();
void ReleaseAllHints();
CAI_Hint *FindFearWithdrawalDest();
void BuildScheduleTestBits();
int TranslateSchedule( int scheduleType );
enum
{
SCHED_FEAR_MOVE_TO_SAFE_PLACE = BaseClass::NEXT_SCHEDULE,
SCHED_FEAR_MOVE_TO_SAFE_PLACE_RETRY,
SCHED_FEAR_STAY_IN_SAFE_PLACE,
NEXT_SCHEDULE,
TASK_FEAR_GET_PATH_TO_SAFETY_HINT = BaseClass::NEXT_TASK,
TASK_FEAR_WAIT_FOR_SAFETY,
TASK_FEAR_IN_SAFE_PLACE,
NEXT_TASK,
COND_FEAR_ENEMY_CLOSE = BaseClass::NEXT_CONDITION, // within 30 feet
COND_FEAR_ENEMY_TOO_CLOSE, // within 5 feet
COND_FEAR_SEPARATED_FROM_PLAYER,
NEXT_CONDITION,
};
DEFINE_CUSTOM_SCHEDULE_PROVIDER;
public:
private:
virtual int SelectSchedule();
float m_flTimeToSafety;
float m_flTimePlayerLastVisible;
float m_flDeferUntil;
CAI_MoveMonitor m_SafePlaceMoveMonitor;
CHandle<CAI_Hint> m_hSafePlaceHint;
CHandle<CAI_Hint> m_hMovingToHint;
DECLARE_DATADESC();
};
#endif // AI_BEHAVIOR_FEAR_H
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Deal intelligently with an enemy that we're afraid of
//
// $Workfile: $
// $Date: $
//
//-----------------------------------------------------------------------------
// $Log: $
//
// $NoKeywords: $
//=============================================================================//
#ifndef AI_BEHAVIOR_FEAR_H
#define AI_BEHAVIOR_FEAR_H
#ifdef _WIN32
#pragma once
#endif
#include "ai_behavior.h"
class CAI_FearBehavior : public CAI_SimpleBehavior
{
DECLARE_CLASS( CAI_FearBehavior, CAI_SimpleBehavior );
public:
CAI_FearBehavior();
void Precache( void );
virtual const char *GetName() { return "Fear"; }
virtual bool CanSelectSchedule();
void GatherConditions();
virtual void BeginScheduleSelection();
virtual void EndScheduleSelection();
void StartTask( const Task_t *pTask );
void RunTask( const Task_t *pTask );
//void BuildScheduleTestBits();
//int TranslateSchedule( int scheduleType );
//void OnStartSchedule( int scheduleType );
//void InitializeBehavior();
bool EnemyDislikesMe();
void MarkAsUnsafe();
bool IsInASafePlace();
void SpoilSafePlace();
void ReleaseAllHints();
CAI_Hint *FindFearWithdrawalDest();
void BuildScheduleTestBits();
int TranslateSchedule( int scheduleType );
enum
{
SCHED_FEAR_MOVE_TO_SAFE_PLACE = BaseClass::NEXT_SCHEDULE,
SCHED_FEAR_MOVE_TO_SAFE_PLACE_RETRY,
SCHED_FEAR_STAY_IN_SAFE_PLACE,
NEXT_SCHEDULE,
TASK_FEAR_GET_PATH_TO_SAFETY_HINT = BaseClass::NEXT_TASK,
TASK_FEAR_WAIT_FOR_SAFETY,
TASK_FEAR_IN_SAFE_PLACE,
NEXT_TASK,
COND_FEAR_ENEMY_CLOSE = BaseClass::NEXT_CONDITION, // within 30 feet
COND_FEAR_ENEMY_TOO_CLOSE, // within 5 feet
COND_FEAR_SEPARATED_FROM_PLAYER,
NEXT_CONDITION,
};
DEFINE_CUSTOM_SCHEDULE_PROVIDER;
public:
private:
virtual int SelectSchedule();
float m_flTimeToSafety;
float m_flTimePlayerLastVisible;
float m_flDeferUntil;
CAI_MoveMonitor m_SafePlaceMoveMonitor;
CHandle<CAI_Hint> m_hSafePlaceHint;
CHandle<CAI_Hint> m_hMovingToHint;
DECLARE_DATADESC();
};
#endif // AI_BEHAVIOR_FEAR_H

File diff suppressed because it is too large Load Diff

View File

@@ -1,383 +1,383 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#ifndef AI_BEHAVIOR_FOLLOW_H
#define AI_BEHAVIOR_FOLLOW_H
#include "simtimer.h"
#include "ai_behavior.h"
#include "ai_goalentity.h"
#include "ai_utils.h"
#include "ai_moveshoot.h"
#ifdef HL2_EPISODIC
#include "hl2_gamerules.h"
#endif
#if defined( _WIN32 )
#pragma once
#endif
//-----------------------------------------------------------------------------
// NOTE: these must correspond with the AI_FollowFormation_t array in AI_Behavior_Follow.cpp!!
//-----------------------------------------------------------------------------
enum AI_Formations_t
{
AIF_SIMPLE,
AIF_WIDE,
AIF_ANTLION,
AIF_COMMANDER,
AIF_TIGHT,
AIF_MEDIUM,
AIF_SIDEKICK,
AIF_HUNTER,
AIF_VORTIGAUNT,
};
enum AI_FollowFormationFlags_t
{
AIFF_DEFAULT = 0,
AIFF_USE_FOLLOW_POINTS = 0x01,
AIFF_REQUIRE_LOS_OUTSIDE_COMBAT = 0x02,
};
//-----------------------------------------------------------------------------
//
// CAI_FollowGoal
//
// Purpose: A level tool to control the follow behavior. Use is not required
// in order to use behavior.
//
//-----------------------------------------------------------------------------
class CAI_FollowGoal : public CAI_GoalEntity
{
DECLARE_CLASS( CAI_FollowGoal, CAI_GoalEntity );
public:
virtual void EnableGoal( CAI_BaseNPC *pAI );
virtual void DisableGoal( CAI_BaseNPC *pAI );
#ifdef HL2_EPISODIC
virtual void InputOutsideTransition( inputdata_t &inputdata );
#endif
int m_iFormation;
DECLARE_DATADESC();
};
//-----------------------------------------------------------------------------
int AIGetNumFollowers( CBaseEntity *pEntity, string_t iszClassname = NULL_STRING );
//-----------------------------------------------------------------------------
struct AI_FollowNavInfo_t
{
int flags;
Vector position;
float range;
float Zrange;
float tolerance;
float followPointTolerance;
float targetMoveTolerance;
float repathOnRouteTolerance;
float walkTolerance;
float coverTolerance;
float enemyLOSTolerance;
float chaseEnemyTolerance;
DECLARE_SIMPLE_DATADESC();
};
struct AI_FollowGroup_t;
struct AI_FollowManagerInfoHandle_t
{
AI_FollowGroup_t *m_pGroup;
int m_hFollower;
};
//-------------------------------------
struct AI_FollowParams_t
{
AI_FollowParams_t( AI_Formations_t formation = AIF_SIMPLE, bool bNormalMemoryDiscard = false )
: formation(formation),
bNormalMemoryDiscard( bNormalMemoryDiscard )
{
}
AI_Formations_t formation;
bool bNormalMemoryDiscard;
DECLARE_SIMPLE_DATADESC();
};
//-------------------------------------
class CAI_FollowBehavior : public CAI_SimpleBehavior
{
DECLARE_CLASS( CAI_FollowBehavior, CAI_SimpleBehavior );
public:
CAI_FollowBehavior( const AI_FollowParams_t &params = AIF_SIMPLE );
~CAI_FollowBehavior();
virtual int DrawDebugTextOverlays( int text_offset );
virtual void DrawDebugGeometryOverlays();
// Returns true if the NPC is actively following a target.
bool IsActive( void );
void SetParameters( const AI_FollowParams_t &params );
virtual const char *GetName() { return "Follow"; }
AI_Formations_t GetFormation() const { return m_params.formation; }
virtual bool CanSelectSchedule();
const AI_FollowNavInfo_t &GetFollowGoalInfo();
CBaseEntity * GetFollowTarget();
void SetFollowTarget( CBaseEntity *pLeader, bool fFinishCurSchedule = false );
CAI_FollowGoal *GetFollowGoal() { return m_hFollowGoalEnt; } // if any
bool SetFollowGoal( CAI_FollowGoal *pGoal, bool fFinishCurSchedule = false );
void ClearFollowGoal( CAI_FollowGoal *pGoal );
void SetFollowGoalDirect( CAI_FollowGoal *pGoal );
virtual bool FarFromFollowTarget() { return ( m_hFollowTarget && (GetAbsOrigin() - m_hFollowTarget->GetAbsOrigin()).LengthSqr() > (75*12)*(75*12) ); }
virtual bool TargetIsUnreachable() { return m_bTargetUnreachable; }
int GetNumFailedFollowAttempts() { return m_nFailedFollowAttempts; }
float GetTimeFailFollowStarted() { return m_flTimeFailFollowStarted; }
bool FollowTargetVisible() { return HasCondition( COND_FOLLOW_TARGET_VISIBLE ); };
bool IsMovingToFollowTarget();
float GetGoalRange();
float GetGoalZRange();
virtual Activity NPC_TranslateActivity( Activity activity );
virtual int TranslateSchedule( int scheduleType );
virtual void StartTask( const Task_t *pTask );
virtual int SelectFailSchedule( int failedSchedule, int failedTask, AI_TaskFailureCode_t taskFailCode );
virtual void TaskComplete( bool fIgnoreSetFailedCondition = false );
virtual void GatherConditions();
protected:
const Vector &GetGoalPosition();
virtual bool ShouldFollow();
friend class CAI_FollowManager;
virtual void BeginScheduleSelection();
virtual void EndScheduleSelection();
virtual void CleanupOnDeath( CBaseEntity *pCulprit, bool bFireDeathOutput );
virtual void Precache();
virtual int SelectSchedule();
virtual int FollowCallBaseSelectSchedule() { return BaseClass::SelectSchedule(); }
virtual void OnStartSchedule( int scheduleType );
virtual void RunTask( const Task_t *pTask );
void BuildScheduleTestBits();
bool IsCurScheduleFollowSchedule();
virtual bool IsCurTaskContinuousMove();
virtual void OnMovementFailed();
virtual void OnMovementComplete();
virtual bool FValidateHintType( CAI_Hint *pHint );
bool IsValidCover( const Vector &vLocation, CAI_Hint const *pHint );
bool IsValidShootPosition( const Vector &vLocation, CAI_Node *pNode, CAI_Hint const *pHint );
bool FindCoverFromEnemyAtFollowTarget( float coverRadius, Vector *pResult );
bool ShouldAlwaysThink();
bool ShouldMoveToFollowTarget();
int SelectScheduleManagePosition();
int SelectScheduleFollowPoints();
int SelectScheduleMoveToFormation();
void GetFollowTargetViewLoc( Vector *pResult);
bool ValidateFaceTarget( Vector *pFaceTarget );
//----------------------------
bool ShouldUseFollowPoints();
bool HasFollowPoint();
void SetFollowPoint( CAI_Hint *pHintNode );
void ClearFollowPoint();
const Vector & GetFollowPoint();
CAI_Hint * FindFollowPoint();
bool IsFollowPointInRange();
bool ShouldIgnoreFollowPointFacing();
//----------------------------
bool UpdateFollowPosition();
const int GetGoalFlags();
float GetGoalTolerance();
bool PlayerIsPushing();
bool IsFollowTargetInRange( float rangeMultiplier = 1.0 );
bool IsFollowGoalInRange( float tolerance, float zTolerance, int flags );
virtual bool IsChaseGoalInRange();
void NoteFailedFollow();
void NoteSuccessfulFollow();
//----------------------------
protected:
enum
{
SCHED_FOLLOWER_MOVE_AWAY_FAIL = BaseClass::NEXT_SCHEDULE, // Turn back toward player
SCHED_FOLLOWER_MOVE_AWAY_END,
SCHED_FOLLOW,
SCHED_FOLLOWER_IDLE_STAND,
SCHED_MOVE_TO_FACE_FOLLOW_TARGET,
SCHED_FACE_FOLLOW_TARGET,
SCHED_FOLLOWER_GO_TO_WAIT_POINT,
SCHED_FOLLOWER_GO_TO_WAIT_POINT_FAIL,
SCHED_FOLLOWER_STAND_AT_WAIT_POINT,
SCHED_FOLLOWER_COMBAT_FACE,
NEXT_SCHEDULE,
TASK_CANT_FOLLOW = BaseClass::NEXT_TASK,
TASK_FACE_FOLLOW_TARGET,
TASK_MOVE_TO_FOLLOW_POSITION,
TASK_GET_PATH_TO_FOLLOW_POSITION,
TASK_SET_FOLLOW_TARGET_MARK,
TASK_FOLLOWER_FACE_TACTICAL,
TASK_SET_FOLLOW_DELAY,
TASK_GET_PATH_TO_FOLLOW_POINT,
TASK_ARRIVE_AT_FOLLOW_POINT,
TASK_SET_FOLLOW_POINT_STAND_SCHEDULE,
TASK_BEGIN_STAND_AT_WAIT_POINT,
NEXT_TASK,
COND_TARGET_MOVED_FROM_MARK = BaseClass::NEXT_CONDITION,
COND_FOUND_WAIT_POINT,
COND_FOLLOW_DELAY_EXPIRED,
COND_FOLLOW_TARGET_VISIBLE,
COND_FOLLOW_TARGET_NOT_VISIBLE,
COND_FOLLOW_WAIT_POINT_INVALID,
COND_FOLLOW_PLAYER_IS_LIT,
COND_FOLLOW_PLAYER_IS_NOT_LIT,
NEXT_CONDITION,
};
DEFINE_CUSTOM_SCHEDULE_PROVIDER;
protected:
//----------------------------
EHANDLE m_hFollowTarget;
AI_FollowNavInfo_t m_FollowNavGoal;
float m_flTimeUpdatedFollowPosition;
bool m_bFirstFacing;
float m_flTimeFollowTargetVisible;
CAI_MoveMonitor m_TargetMonitor;
bool m_bTargetUnreachable;
bool m_bFollowNavFailed; // Set when pathfinding fails to limit impact of m_FollowDelay on ShouldFollow
int m_nFailedFollowAttempts;
float m_flTimeFailFollowStarted;
Vector m_vFollowMoveAnchor;
bool m_bMovingToCover;
float m_flOriginalEnemyDiscardTime;
float m_SavedDistTooFar;
CRandStopwatch m_FollowDelay;
CSimpleSimTimer m_RepathOnFollowTimer;
//---------------------------------
Activity m_CurrentFollowActivity;
//---------------------------------
CRandSimTimer m_TimeBlockUseWaitPoint;
CSimTimer m_TimeCheckForWaitPoint;
CAI_Hint * m_pInterruptWaitPoint;
//---------------------------------
CRandSimTimer m_TimeBeforeSpreadFacing;
CRandSimTimer m_TimeNextSpreadFacing;
//---------------------------------
AI_FollowManagerInfoHandle_t m_hFollowManagerInfo;
AI_FollowParams_t m_params;
//---------------------------------
CHandle<CAI_FollowGoal> m_hFollowGoalEnt;
//---------------------------------
DECLARE_DATADESC();
};
//-------------------------------------
inline const AI_FollowNavInfo_t &CAI_FollowBehavior::GetFollowGoalInfo()
{
return m_FollowNavGoal;
}
//-------------------------------------
inline const int CAI_FollowBehavior::GetGoalFlags()
{
return m_FollowNavGoal.flags;
}
//-------------------------------------
inline const Vector &CAI_FollowBehavior::GetGoalPosition()
{
return m_FollowNavGoal.position;
}
//-------------------------------------
inline float CAI_FollowBehavior::GetGoalTolerance()
{
return m_FollowNavGoal.tolerance;
}
//-------------------------------------
inline float CAI_FollowBehavior::GetGoalRange()
{
return m_FollowNavGoal.range;
}
//-------------------------------------
inline float CAI_FollowBehavior::GetGoalZRange()
{
return m_FollowNavGoal.Zrange;
}
//-----------------------------------------------------------------------------
#endif // AI_BEHAVIOR_FOLLOW_H
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#ifndef AI_BEHAVIOR_FOLLOW_H
#define AI_BEHAVIOR_FOLLOW_H
#include "simtimer.h"
#include "ai_behavior.h"
#include "ai_goalentity.h"
#include "ai_utils.h"
#include "ai_moveshoot.h"
#ifdef HL2_EPISODIC
#include "hl2_gamerules.h"
#endif
#if defined( _WIN32 )
#pragma once
#endif
//-----------------------------------------------------------------------------
// NOTE: these must correspond with the AI_FollowFormation_t array in AI_Behavior_Follow.cpp!!
//-----------------------------------------------------------------------------
enum AI_Formations_t
{
AIF_SIMPLE,
AIF_WIDE,
AIF_ANTLION,
AIF_COMMANDER,
AIF_TIGHT,
AIF_MEDIUM,
AIF_SIDEKICK,
AIF_HUNTER,
AIF_VORTIGAUNT,
};
enum AI_FollowFormationFlags_t
{
AIFF_DEFAULT = 0,
AIFF_USE_FOLLOW_POINTS = 0x01,
AIFF_REQUIRE_LOS_OUTSIDE_COMBAT = 0x02,
};
//-----------------------------------------------------------------------------
//
// CAI_FollowGoal
//
// Purpose: A level tool to control the follow behavior. Use is not required
// in order to use behavior.
//
//-----------------------------------------------------------------------------
class CAI_FollowGoal : public CAI_GoalEntity
{
DECLARE_CLASS( CAI_FollowGoal, CAI_GoalEntity );
public:
virtual void EnableGoal( CAI_BaseNPC *pAI );
virtual void DisableGoal( CAI_BaseNPC *pAI );
#ifdef HL2_EPISODIC
virtual void InputOutsideTransition( inputdata_t &inputdata );
#endif
int m_iFormation;
DECLARE_DATADESC();
};
//-----------------------------------------------------------------------------
int AIGetNumFollowers( CBaseEntity *pEntity, string_t iszClassname = NULL_STRING );
//-----------------------------------------------------------------------------
struct AI_FollowNavInfo_t
{
int flags;
Vector position;
float range;
float Zrange;
float tolerance;
float followPointTolerance;
float targetMoveTolerance;
float repathOnRouteTolerance;
float walkTolerance;
float coverTolerance;
float enemyLOSTolerance;
float chaseEnemyTolerance;
DECLARE_SIMPLE_DATADESC();
};
struct AI_FollowGroup_t;
struct AI_FollowManagerInfoHandle_t
{
AI_FollowGroup_t *m_pGroup;
int m_hFollower;
};
//-------------------------------------
struct AI_FollowParams_t
{
AI_FollowParams_t( AI_Formations_t formation = AIF_SIMPLE, bool bNormalMemoryDiscard = false )
: formation(formation),
bNormalMemoryDiscard( bNormalMemoryDiscard )
{
}
AI_Formations_t formation;
bool bNormalMemoryDiscard;
DECLARE_SIMPLE_DATADESC();
};
//-------------------------------------
class CAI_FollowBehavior : public CAI_SimpleBehavior
{
DECLARE_CLASS( CAI_FollowBehavior, CAI_SimpleBehavior );
public:
CAI_FollowBehavior( const AI_FollowParams_t &params = AIF_SIMPLE );
~CAI_FollowBehavior();
virtual int DrawDebugTextOverlays( int text_offset );
virtual void DrawDebugGeometryOverlays();
// Returns true if the NPC is actively following a target.
bool IsActive( void );
void SetParameters( const AI_FollowParams_t &params );
virtual const char *GetName() { return "Follow"; }
AI_Formations_t GetFormation() const { return m_params.formation; }
virtual bool CanSelectSchedule();
const AI_FollowNavInfo_t &GetFollowGoalInfo();
CBaseEntity * GetFollowTarget();
void SetFollowTarget( CBaseEntity *pLeader, bool fFinishCurSchedule = false );
CAI_FollowGoal *GetFollowGoal() { return m_hFollowGoalEnt; } // if any
bool SetFollowGoal( CAI_FollowGoal *pGoal, bool fFinishCurSchedule = false );
void ClearFollowGoal( CAI_FollowGoal *pGoal );
void SetFollowGoalDirect( CAI_FollowGoal *pGoal );
virtual bool FarFromFollowTarget() { return ( m_hFollowTarget && (GetAbsOrigin() - m_hFollowTarget->GetAbsOrigin()).LengthSqr() > (75*12)*(75*12) ); }
virtual bool TargetIsUnreachable() { return m_bTargetUnreachable; }
int GetNumFailedFollowAttempts() { return m_nFailedFollowAttempts; }
float GetTimeFailFollowStarted() { return m_flTimeFailFollowStarted; }
bool FollowTargetVisible() { return HasCondition( COND_FOLLOW_TARGET_VISIBLE ); };
bool IsMovingToFollowTarget();
float GetGoalRange();
float GetGoalZRange();
virtual Activity NPC_TranslateActivity( Activity activity );
virtual int TranslateSchedule( int scheduleType );
virtual void StartTask( const Task_t *pTask );
virtual int SelectFailSchedule( int failedSchedule, int failedTask, AI_TaskFailureCode_t taskFailCode );
virtual void TaskComplete( bool fIgnoreSetFailedCondition = false );
virtual void GatherConditions();
protected:
const Vector &GetGoalPosition();
virtual bool ShouldFollow();
friend class CAI_FollowManager;
virtual void BeginScheduleSelection();
virtual void EndScheduleSelection();
virtual void CleanupOnDeath( CBaseEntity *pCulprit, bool bFireDeathOutput );
virtual void Precache();
virtual int SelectSchedule();
virtual int FollowCallBaseSelectSchedule() { return BaseClass::SelectSchedule(); }
virtual void OnStartSchedule( int scheduleType );
virtual void RunTask( const Task_t *pTask );
void BuildScheduleTestBits();
bool IsCurScheduleFollowSchedule();
virtual bool IsCurTaskContinuousMove();
virtual void OnMovementFailed();
virtual void OnMovementComplete();
virtual bool FValidateHintType( CAI_Hint *pHint );
bool IsValidCover( const Vector &vLocation, CAI_Hint const *pHint );
bool IsValidShootPosition( const Vector &vLocation, CAI_Node *pNode, CAI_Hint const *pHint );
bool FindCoverFromEnemyAtFollowTarget( float coverRadius, Vector *pResult );
bool ShouldAlwaysThink();
bool ShouldMoveToFollowTarget();
int SelectScheduleManagePosition();
int SelectScheduleFollowPoints();
int SelectScheduleMoveToFormation();
void GetFollowTargetViewLoc( Vector *pResult);
bool ValidateFaceTarget( Vector *pFaceTarget );
//----------------------------
bool ShouldUseFollowPoints();
bool HasFollowPoint();
void SetFollowPoint( CAI_Hint *pHintNode );
void ClearFollowPoint();
const Vector & GetFollowPoint();
CAI_Hint * FindFollowPoint();
bool IsFollowPointInRange();
bool ShouldIgnoreFollowPointFacing();
//----------------------------
bool UpdateFollowPosition();
const int GetGoalFlags();
float GetGoalTolerance();
bool PlayerIsPushing();
bool IsFollowTargetInRange( float rangeMultiplier = 1.0 );
bool IsFollowGoalInRange( float tolerance, float zTolerance, int flags );
virtual bool IsChaseGoalInRange();
void NoteFailedFollow();
void NoteSuccessfulFollow();
//----------------------------
protected:
enum
{
SCHED_FOLLOWER_MOVE_AWAY_FAIL = BaseClass::NEXT_SCHEDULE, // Turn back toward player
SCHED_FOLLOWER_MOVE_AWAY_END,
SCHED_FOLLOW,
SCHED_FOLLOWER_IDLE_STAND,
SCHED_MOVE_TO_FACE_FOLLOW_TARGET,
SCHED_FACE_FOLLOW_TARGET,
SCHED_FOLLOWER_GO_TO_WAIT_POINT,
SCHED_FOLLOWER_GO_TO_WAIT_POINT_FAIL,
SCHED_FOLLOWER_STAND_AT_WAIT_POINT,
SCHED_FOLLOWER_COMBAT_FACE,
NEXT_SCHEDULE,
TASK_CANT_FOLLOW = BaseClass::NEXT_TASK,
TASK_FACE_FOLLOW_TARGET,
TASK_MOVE_TO_FOLLOW_POSITION,
TASK_GET_PATH_TO_FOLLOW_POSITION,
TASK_SET_FOLLOW_TARGET_MARK,
TASK_FOLLOWER_FACE_TACTICAL,
TASK_SET_FOLLOW_DELAY,
TASK_GET_PATH_TO_FOLLOW_POINT,
TASK_ARRIVE_AT_FOLLOW_POINT,
TASK_SET_FOLLOW_POINT_STAND_SCHEDULE,
TASK_BEGIN_STAND_AT_WAIT_POINT,
NEXT_TASK,
COND_TARGET_MOVED_FROM_MARK = BaseClass::NEXT_CONDITION,
COND_FOUND_WAIT_POINT,
COND_FOLLOW_DELAY_EXPIRED,
COND_FOLLOW_TARGET_VISIBLE,
COND_FOLLOW_TARGET_NOT_VISIBLE,
COND_FOLLOW_WAIT_POINT_INVALID,
COND_FOLLOW_PLAYER_IS_LIT,
COND_FOLLOW_PLAYER_IS_NOT_LIT,
NEXT_CONDITION,
};
DEFINE_CUSTOM_SCHEDULE_PROVIDER;
protected:
//----------------------------
EHANDLE m_hFollowTarget;
AI_FollowNavInfo_t m_FollowNavGoal;
float m_flTimeUpdatedFollowPosition;
bool m_bFirstFacing;
float m_flTimeFollowTargetVisible;
CAI_MoveMonitor m_TargetMonitor;
bool m_bTargetUnreachable;
bool m_bFollowNavFailed; // Set when pathfinding fails to limit impact of m_FollowDelay on ShouldFollow
int m_nFailedFollowAttempts;
float m_flTimeFailFollowStarted;
Vector m_vFollowMoveAnchor;
bool m_bMovingToCover;
float m_flOriginalEnemyDiscardTime;
float m_SavedDistTooFar;
CRandStopwatch m_FollowDelay;
CSimpleSimTimer m_RepathOnFollowTimer;
//---------------------------------
Activity m_CurrentFollowActivity;
//---------------------------------
CRandSimTimer m_TimeBlockUseWaitPoint;
CSimTimer m_TimeCheckForWaitPoint;
CAI_Hint * m_pInterruptWaitPoint;
//---------------------------------
CRandSimTimer m_TimeBeforeSpreadFacing;
CRandSimTimer m_TimeNextSpreadFacing;
//---------------------------------
AI_FollowManagerInfoHandle_t m_hFollowManagerInfo;
AI_FollowParams_t m_params;
//---------------------------------
CHandle<CAI_FollowGoal> m_hFollowGoalEnt;
//---------------------------------
DECLARE_DATADESC();
};
//-------------------------------------
inline const AI_FollowNavInfo_t &CAI_FollowBehavior::GetFollowGoalInfo()
{
return m_FollowNavGoal;
}
//-------------------------------------
inline const int CAI_FollowBehavior::GetGoalFlags()
{
return m_FollowNavGoal.flags;
}
//-------------------------------------
inline const Vector &CAI_FollowBehavior::GetGoalPosition()
{
return m_FollowNavGoal.position;
}
//-------------------------------------
inline float CAI_FollowBehavior::GetGoalTolerance()
{
return m_FollowNavGoal.tolerance;
}
//-------------------------------------
inline float CAI_FollowBehavior::GetGoalRange()
{
return m_FollowNavGoal.range;
}
//-------------------------------------
inline float CAI_FollowBehavior::GetGoalZRange()
{
return m_FollowNavGoal.Zrange;
}
//-----------------------------------------------------------------------------
#endif // AI_BEHAVIOR_FOLLOW_H

File diff suppressed because it is too large Load Diff

View File

@@ -1,236 +1,236 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#ifndef AI_BEHAVIOR_LEAD_H
#define AI_BEHAVIOR_LEAD_H
#include "simtimer.h"
#include "ai_behavior.h"
#if defined( _WIN32 )
#pragma once
#endif
typedef const char *AIConcept_t;
// Speak concepts
#define TLK_LEAD_START "TLK_LEAD_START"
#define TLK_LEAD_ARRIVAL "TLK_LEAD_ARRIVAL"
#define TLK_LEAD_SUCCESS "TLK_LEAD_SUCCESS"
#define TLK_LEAD_FAILURE "lead_fail"
#define TLK_LEAD_COMINGBACK "TLK_LEAD_COMINGBACK"
#define TLK_LEAD_CATCHUP "TLK_LEAD_CATCHUP"
#define TLK_LEAD_RETRIEVE "TLK_LEAD_RETRIEVE"
#define TLK_LEAD_ATTRACTPLAYER "TLK_LEAD_ATTRACTPLAYER"
#define TLK_LEAD_WAITOVER "TLK_LEAD_WAITOVER"
#define TLK_LEAD_MISSINGWEAPON "TLK_LEAD_MISSING_WEAPON"
#define TLK_LEAD_IDLE "TLK_LEAD_IDLE"
//-----------------------------------------------------------------------------
// class CAI_LeadBehavior
//
// Purpose:
//
//-----------------------------------------------------------------------------
enum LeadBehaviorEvents_t
{
LBE_ARRIVAL,
LBE_ARRIVAL_DONE,
LBE_SUCCESS,
LBE_FAILURE,
LBE_DONE,
};
//-------------------------------------
//
// Handler class interface to listen to and modify actions of the lead behavior.
// Could be an NPC, or another entity (like a goal entity)
//
class CAI_LeadBehaviorHandler
{
public:
virtual void OnEvent( int event ) {}
virtual const char *GetConceptModifiers( const char *pszConcept ) { return NULL; }
};
//-------------------------------------
enum AI_LeadFlags_t
{
AILF_NO_DEF_SUCCESS = 0x01,
AILF_NO_DEF_FAILURE = 0x02,
AILF_USE_GOAL_FACING = 0x04,
};
struct AI_LeadArgs_t
{
const char *pszGoal;
const char *pszWaitPoint;
unsigned flags;
float flWaitDistance;
float flLeadDistance;
float flRetrieveDistance;
float flSuccessDistance;
bool bRun;
int iRetrievePlayer;
int iRetrieveWaitForSpeak;
int iComingBackWaitForSpeak;
bool bStopScenesWhenPlayerLost;
bool bDontSpeakStart;
bool bLeadDuringCombat;
bool bGagLeader;
DECLARE_SIMPLE_DATADESC();
};
class CAI_LeadBehavior : public CAI_SimpleBehavior
{
DECLARE_CLASS( CAI_LeadBehavior, CAI_SimpleBehavior );
public:
CAI_LeadBehavior()
: m_pSink(NULL),
m_LostTimer( 3.0, 4.0 ),
m_LostLOSTimer( 2.0, 3.0 )
{
memset( &m_args, 0, sizeof(m_args) );
ClearGoal();
}
virtual void OnRestore();
virtual const char *GetName() { return "Lead"; }
virtual int DrawDebugTextOverlays( int text_offset );
virtual bool IsNavigationUrgent();
void LeadPlayer( const AI_LeadArgs_t &leadArgs, CAI_LeadBehaviorHandler *pSink = NULL );
void StopLeading( void );
virtual bool CanSelectSchedule();
void BeginScheduleSelection();
virtual bool IsCurTaskContinuousMove();
bool SetGoal( const AI_LeadArgs_t &args );
void ClearGoal() { m_goal = vec3_origin; m_waitpoint = vec3_origin; m_pSink = NULL; m_weaponname = NULL_STRING; }
bool HasGoal() const { return (m_goal != vec3_origin); }
bool HasWaitPoint() const { return (m_waitpoint != vec3_origin); }
bool Connect( CAI_LeadBehaviorHandler *);
bool Disconnect( CAI_LeadBehaviorHandler *);
void SetWaitForWeapon( string_t iszWeaponName ) { m_weaponname = iszWeaponName; m_flWeaponSafetyTimeOut = gpGlobals->curtime + 60; }
enum
{
// Schedules
SCHED_LEAD_PLAYER = BaseClass::NEXT_SCHEDULE,
SCHED_LEAD_PAUSE,
SCHED_LEAD_PAUSE_COMBAT,
SCHED_LEAD_RETRIEVE,
SCHED_LEAD_RETRIEVE_WAIT,
SCHED_LEAD_SUCCEED,
SCHED_LEAD_AWAIT_SUCCESS,
SCHED_LEAD_WAITFORPLAYER,
SCHED_LEAD_WAITFORPLAYERIDLE,
SCHED_LEAD_PLAYERNEEDSWEAPON,
SCHED_LEAD_SPEAK_START,
SCHED_LEAD_SPEAK_THEN_RETRIEVE_PLAYER,
SCHED_LEAD_SPEAK_THEN_LEAD_PLAYER,
NEXT_SCHEDULE,
// Tasks
TASK_GET_PATH_TO_LEAD_GOAL = BaseClass::NEXT_TASK,
TASK_STOP_LEADING,
TASK_LEAD_FACE_GOAL,
TASK_LEAD_ARRIVE,
TASK_LEAD_SUCCEED,
TASK_LEAD_GET_PATH_TO_WAITPOINT,
TASK_LEAD_WAVE_TO_PLAYER,
TASK_LEAD_PLAYER_NEEDS_WEAPON,
TASK_LEAD_SPEAK_START,
TASK_LEAD_MOVE_TO_RANGE,
TASK_LEAD_RETRIEVE_WAIT,
TASK_LEAD_WALK_PATH,
NEXT_TASK,
// Conditions
COND_LEAD_FOLLOWER_LOST = BaseClass::NEXT_CONDITION,
COND_LEAD_FOLLOWER_LAGGING,
COND_LEAD_FOLLOWER_NOT_LAGGING,
COND_LEAD_FOLLOWER_VERY_CLOSE,
COND_LEAD_SUCCESS,
COND_LEAD_HAVE_FOLLOWER_LOS,
COND_LEAD_FOLLOWER_MOVED_FROM_MARK,
COND_LEAD_FOLLOWER_MOVING_TOWARDS_ME,
NEXT_CONDITION
};
private:
void GatherConditions();
virtual int SelectSchedule();
virtual int TranslateSchedule( int scheduleType );
virtual void StartTask( const Task_t *pTask );
virtual void RunTask( const Task_t *pTask );
bool GetClosestPointOnRoute( const Vector &targetPos, Vector *pVecClosestPoint );
bool PlayerIsAheadOfMe( bool bForce = false );
bool Speak( AIConcept_t concept );
bool IsSpeaking();
// --------------------------------
//
// Sink notifiers. Isolated to limit exposure to actual sink storage,
// provide debugging pinch pount, and allow for class-local logic
// in addition to sink logic
//
void NotifyEvent( int event ) { if ( m_pSink ) m_pSink->OnEvent( event ) ; }
const char * GetConceptModifiers( const char *pszConcept ) { return ( m_pSink ) ? m_pSink->GetConceptModifiers( pszConcept ) : NULL; }
// --------------------------------
AI_LeadArgs_t m_args;
CAI_LeadBehaviorHandler *m_pSink;
EHANDLE m_hSinkImplementor;
// --------------------------------
Vector m_goal;
float m_goalyaw;
Vector m_waitpoint;
float m_waitdistance;
float m_leaddistance;
float m_retrievedistance;
float m_successdistance;
string_t m_weaponname;
bool m_run;
bool m_gagleader;
bool m_hasspokenstart;
bool m_hasspokenarrival;
bool m_hasPausedScenes;
float m_flSpeakNextNagTime;
float m_flWeaponSafetyTimeOut;
float m_flNextLeadIdle;
bool m_bInitialAheadTest;
CAI_MoveMonitor m_MoveMonitor;
CRandStopwatch m_LostTimer;
CRandStopwatch m_LostLOSTimer;
DEFINE_CUSTOM_SCHEDULE_PROVIDER;
DECLARE_DATADESC();
};
//-----------------------------------------------------------------------------
#endif // AI_BEHAVIOR_LEAD_H
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#ifndef AI_BEHAVIOR_LEAD_H
#define AI_BEHAVIOR_LEAD_H
#include "simtimer.h"
#include "ai_behavior.h"
#if defined( _WIN32 )
#pragma once
#endif
typedef const char *AIConcept_t;
// Speak concepts
#define TLK_LEAD_START "TLK_LEAD_START"
#define TLK_LEAD_ARRIVAL "TLK_LEAD_ARRIVAL"
#define TLK_LEAD_SUCCESS "TLK_LEAD_SUCCESS"
#define TLK_LEAD_FAILURE "lead_fail"
#define TLK_LEAD_COMINGBACK "TLK_LEAD_COMINGBACK"
#define TLK_LEAD_CATCHUP "TLK_LEAD_CATCHUP"
#define TLK_LEAD_RETRIEVE "TLK_LEAD_RETRIEVE"
#define TLK_LEAD_ATTRACTPLAYER "TLK_LEAD_ATTRACTPLAYER"
#define TLK_LEAD_WAITOVER "TLK_LEAD_WAITOVER"
#define TLK_LEAD_MISSINGWEAPON "TLK_LEAD_MISSING_WEAPON"
#define TLK_LEAD_IDLE "TLK_LEAD_IDLE"
//-----------------------------------------------------------------------------
// class CAI_LeadBehavior
//
// Purpose:
//
//-----------------------------------------------------------------------------
enum LeadBehaviorEvents_t
{
LBE_ARRIVAL,
LBE_ARRIVAL_DONE,
LBE_SUCCESS,
LBE_FAILURE,
LBE_DONE,
};
//-------------------------------------
//
// Handler class interface to listen to and modify actions of the lead behavior.
// Could be an NPC, or another entity (like a goal entity)
//
class CAI_LeadBehaviorHandler
{
public:
virtual void OnEvent( int event ) {}
virtual const char *GetConceptModifiers( const char *pszConcept ) { return NULL; }
};
//-------------------------------------
enum AI_LeadFlags_t
{
AILF_NO_DEF_SUCCESS = 0x01,
AILF_NO_DEF_FAILURE = 0x02,
AILF_USE_GOAL_FACING = 0x04,
};
struct AI_LeadArgs_t
{
const char *pszGoal;
const char *pszWaitPoint;
unsigned flags;
float flWaitDistance;
float flLeadDistance;
float flRetrieveDistance;
float flSuccessDistance;
bool bRun;
int iRetrievePlayer;
int iRetrieveWaitForSpeak;
int iComingBackWaitForSpeak;
bool bStopScenesWhenPlayerLost;
bool bDontSpeakStart;
bool bLeadDuringCombat;
bool bGagLeader;
DECLARE_SIMPLE_DATADESC();
};
class CAI_LeadBehavior : public CAI_SimpleBehavior
{
DECLARE_CLASS( CAI_LeadBehavior, CAI_SimpleBehavior );
public:
CAI_LeadBehavior()
: m_pSink(NULL),
m_LostTimer( 3.0, 4.0 ),
m_LostLOSTimer( 2.0, 3.0 )
{
memset( &m_args, 0, sizeof(m_args) );
ClearGoal();
}
virtual void OnRestore();
virtual const char *GetName() { return "Lead"; }
virtual int DrawDebugTextOverlays( int text_offset );
virtual bool IsNavigationUrgent();
void LeadPlayer( const AI_LeadArgs_t &leadArgs, CAI_LeadBehaviorHandler *pSink = NULL );
void StopLeading( void );
virtual bool CanSelectSchedule();
void BeginScheduleSelection();
virtual bool IsCurTaskContinuousMove();
bool SetGoal( const AI_LeadArgs_t &args );
void ClearGoal() { m_goal = vec3_origin; m_waitpoint = vec3_origin; m_pSink = NULL; m_weaponname = NULL_STRING; }
bool HasGoal() const { return (m_goal != vec3_origin); }
bool HasWaitPoint() const { return (m_waitpoint != vec3_origin); }
bool Connect( CAI_LeadBehaviorHandler *);
bool Disconnect( CAI_LeadBehaviorHandler *);
void SetWaitForWeapon( string_t iszWeaponName ) { m_weaponname = iszWeaponName; m_flWeaponSafetyTimeOut = gpGlobals->curtime + 60; }
enum
{
// Schedules
SCHED_LEAD_PLAYER = BaseClass::NEXT_SCHEDULE,
SCHED_LEAD_PAUSE,
SCHED_LEAD_PAUSE_COMBAT,
SCHED_LEAD_RETRIEVE,
SCHED_LEAD_RETRIEVE_WAIT,
SCHED_LEAD_SUCCEED,
SCHED_LEAD_AWAIT_SUCCESS,
SCHED_LEAD_WAITFORPLAYER,
SCHED_LEAD_WAITFORPLAYERIDLE,
SCHED_LEAD_PLAYERNEEDSWEAPON,
SCHED_LEAD_SPEAK_START,
SCHED_LEAD_SPEAK_THEN_RETRIEVE_PLAYER,
SCHED_LEAD_SPEAK_THEN_LEAD_PLAYER,
NEXT_SCHEDULE,
// Tasks
TASK_GET_PATH_TO_LEAD_GOAL = BaseClass::NEXT_TASK,
TASK_STOP_LEADING,
TASK_LEAD_FACE_GOAL,
TASK_LEAD_ARRIVE,
TASK_LEAD_SUCCEED,
TASK_LEAD_GET_PATH_TO_WAITPOINT,
TASK_LEAD_WAVE_TO_PLAYER,
TASK_LEAD_PLAYER_NEEDS_WEAPON,
TASK_LEAD_SPEAK_START,
TASK_LEAD_MOVE_TO_RANGE,
TASK_LEAD_RETRIEVE_WAIT,
TASK_LEAD_WALK_PATH,
NEXT_TASK,
// Conditions
COND_LEAD_FOLLOWER_LOST = BaseClass::NEXT_CONDITION,
COND_LEAD_FOLLOWER_LAGGING,
COND_LEAD_FOLLOWER_NOT_LAGGING,
COND_LEAD_FOLLOWER_VERY_CLOSE,
COND_LEAD_SUCCESS,
COND_LEAD_HAVE_FOLLOWER_LOS,
COND_LEAD_FOLLOWER_MOVED_FROM_MARK,
COND_LEAD_FOLLOWER_MOVING_TOWARDS_ME,
NEXT_CONDITION
};
private:
void GatherConditions();
virtual int SelectSchedule();
virtual int TranslateSchedule( int scheduleType );
virtual void StartTask( const Task_t *pTask );
virtual void RunTask( const Task_t *pTask );
bool GetClosestPointOnRoute( const Vector &targetPos, Vector *pVecClosestPoint );
bool PlayerIsAheadOfMe( bool bForce = false );
bool Speak( AIConcept_t concept );
bool IsSpeaking();
// --------------------------------
//
// Sink notifiers. Isolated to limit exposure to actual sink storage,
// provide debugging pinch pount, and allow for class-local logic
// in addition to sink logic
//
void NotifyEvent( int event ) { if ( m_pSink ) m_pSink->OnEvent( event ) ; }
const char * GetConceptModifiers( const char *pszConcept ) { return ( m_pSink ) ? m_pSink->GetConceptModifiers( pszConcept ) : NULL; }
// --------------------------------
AI_LeadArgs_t m_args;
CAI_LeadBehaviorHandler *m_pSink;
EHANDLE m_hSinkImplementor;
// --------------------------------
Vector m_goal;
float m_goalyaw;
Vector m_waitpoint;
float m_waitdistance;
float m_leaddistance;
float m_retrievedistance;
float m_successdistance;
string_t m_weaponname;
bool m_run;
bool m_gagleader;
bool m_hasspokenstart;
bool m_hasspokenarrival;
bool m_hasPausedScenes;
float m_flSpeakNextNagTime;
float m_flWeaponSafetyTimeOut;
float m_flNextLeadIdle;
bool m_bInitialAheadTest;
CAI_MoveMonitor m_MoveMonitor;
CRandStopwatch m_LostTimer;
CRandStopwatch m_LostLOSTimer;
DEFINE_CUSTOM_SCHEDULE_PROVIDER;
DECLARE_DATADESC();
};
//-----------------------------------------------------------------------------
#endif // AI_BEHAVIOR_LEAD_H

File diff suppressed because it is too large Load Diff

View File

@@ -1,245 +1,245 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================
#ifndef AI_BEHAVIOR_PASSENGER_H
#define AI_BEHAVIOR_PASSENGER_H
#ifdef _WIN32
#pragma once
#endif
#include "ai_speech.h"
#include "ai_behavior.h"
#include "ai_utils.h"
#include "vehicle_jeep_episodic.h"
#define STOPPED_VELOCITY_THRESHOLD 32.0f
#define STOPPED_VELOCITY_THRESHOLD_SQR (STOPPED_VELOCITY_THRESHOLD*STOPPED_VELOCITY_THRESHOLD)
#define STARTED_VELOCITY_THRESHOLD 64.0f
#define STARTED_VELOCITY_THRESHOLD_SQR (STARTED_VELOCITY_THRESHOLD*STARTED_VELOCITY_THRESHOLD)
// Custom activities
extern int ACT_PASSENGER_IDLE;
extern int ACT_PASSENGER_RANGE_ATTACK1;
// ---------------------------------------------
// Vehicle state
// ---------------------------------------------
struct passengerVehicleState_t
{
Vector m_vecLastLocalVelocity;
Vector m_vecDeltaVelocity;
QAngle m_vecLastAngles;
float m_flNextWarningTime;
float m_flLastSpeedSqr;
bool m_bPlayerInVehicle;
bool m_bWasBoosting;
bool m_bWasOverturned;
DECLARE_SIMPLE_DATADESC();
};
// ---------------------------------------------
// Passenger intent
// ---------------------------------------------
enum passesngerVehicleIntent_e
{
PASSENGER_INTENT_NONE,
PASSENGER_INTENT_ENTER, // We want to be in the vehicle
PASSENGER_INTENT_EXIT, // We want to be outside the vehicle
};
// ---------------------------------------------
// Passenger state functions
// ---------------------------------------------
enum PassengerState_e
{
PASSENGER_STATE_OUTSIDE = 0, // Not in the vehicle
PASSENGER_STATE_ENTERING,
PASSENGER_STATE_INSIDE,
PASSENGER_STATE_EXITING,
};
class CAI_PassengerBehavior : public CAI_SimpleBehavior
{
DECLARE_CLASS( CAI_PassengerBehavior, CAI_SimpleBehavior );
DECLARE_DATADESC()
public:
CAI_PassengerBehavior( void );
enum
{
// Schedules
SCHED_PASSENGER_IDLE = BaseClass::NEXT_SCHEDULE,
SCHED_PASSENGER_ENTER_VEHICLE,
SCHED_PASSENGER_EXIT_VEHICLE,
SCHED_PASSENGER_RUN_TO_ENTER_VEHICLE,
SCHED_PASSENGER_ENTER_VEHICLE_PAUSE,
SCHED_PASSENGER_RUN_TO_ENTER_VEHICLE_FAILED,
SCHED_PASSENGER_PLAY_SCRIPTED_ANIM,
NEXT_SCHEDULE,
// Tasks
TASK_PASSENGER_ENTER_VEHICLE = BaseClass::NEXT_TASK,
TASK_PASSENGER_EXIT_VEHICLE,
TASK_PASSENGER_ATTACH_TO_VEHICLE,
TASK_PASSENGER_DETACH_FROM_VEHICLE,
TASK_PASSENGER_SET_IDEAL_ENTRY_YAW,
NEXT_TASK,
// Conditions
COND_PASSENGER_HARD_IMPACT = BaseClass::NEXT_CONDITION,
COND_PASSENGER_ENTERING,
COND_PASSENGER_EXITING,
COND_PASSENGER_VEHICLE_STARTED,
COND_PASSENGER_VEHICLE_STOPPED,
COND_PASSENGER_OVERTURNED,
COND_PASSENGER_CANCEL_ENTER,
COND_PASSENGER_ERRATIC_DRIVING,
COND_PASSENGER_PLAYER_ENTERED_VEHICLE,
COND_PASSENGER_PLAYER_EXITED_VEHICLE,
COND_PASSENGER_JOSTLE_SMALL,
NEXT_CONDITION
};
bool ForceVehicleInteraction( const char *lpszInteractionName, CBaseCombatCharacter *pOther );
virtual bool CanSelectSchedule( void );
virtual int SelectSchedule( void );
virtual int SelectFailSchedule( int failedSchedule, int failedTask, AI_TaskFailureCode_t taskFailCode );
virtual void RunTask( const Task_t *pTask );
virtual void StartTask( const Task_t *pTask );
virtual void BuildScheduleTestBits( void );
virtual int TranslateSchedule( int scheduleType );
virtual void GetEntryTarget( Vector *vecOrigin, QAngle *vecAngles );
virtual void GatherConditions( void );
virtual void ModifyOrAppendCriteria( AI_CriteriaSet& criteriaSet );
virtual void Teleport( const Vector *newPosition, const QAngle *newAngles, const Vector *newVelocity );
virtual void ClearSchedule( const char *szReason );
virtual bool IsInterruptable( void );
virtual void PrescheduleThink( void );
virtual void CancelEnterVehicle( void );
virtual const char *GetName( void ) { return "Passenger"; }
virtual string_t GetRoleName( void ) { return MAKE_STRING( "passenger" ); }
// Enable/disable code
void Enable( CPropJeepEpisodic *pVehicle, bool bImmediateEntrance = false );
void Disable( void );
bool IsEnabled( void ) const { return m_bEnabled; }
virtual void EnterVehicle( void );
virtual void ExitVehicle( void );
void AddPhysicsPush( float force );
CPropVehicleDriveable *GetTargetVehicle( void ) const { return m_hVehicle; }
PassengerState_e GetPassengerState( void ) const { return m_PassengerState; }
virtual void OnRestore();
protected:
virtual int SelectTransitionSchedule( void );
bool SpeakIfAllowed( AIConcept_t concept, const char *modifiers = NULL, bool bRespondingToPlayer = false, char *pszOutResponseChosen = NULL, size_t bufsize = 0 );
bool CanExitVehicle( void );
void SetTransitionSequence( int nSequence );
void AttachToVehicle( void );
virtual void OnExitVehicleFailed( void ) { } // NPC attempted to leave vehicle, but was unable to
virtual void GatherVehicleStateConditions( void );
// ------------------------------------------
// Entry/exit transition code
// ------------------------------------------
virtual void FinishEnterVehicle( void );
virtual void FinishExitVehicle( void );
void DetachFromVehicle( void );
void DrawDebugTransitionInfo( const Vector &vecIdealPos, const QAngle &vecIdealAngles, const Vector &vecAnimPos, const QAngle &vecAnimAngles );
bool GetEntryPoint( int nSequence, Vector *vecEntryPoint, QAngle *vecEntryAngles = NULL );
bool GetExitPoint( int nSequence, Vector *vecExitPoint, QAngle *vecExitAngles = NULL );
bool PointIsNavigable( const Vector &vecTargetPos );
bool ReserveEntryPoint( VehicleSeatQuery_e eSeatSearchType );
bool ReserveExitPoint( void );
bool FindGroundAtPosition( const Vector &in, float flUpDelta, float flDownDelta, Vector *out );
bool DoTransitionMovement( void );
bool GetSequenceBlendAmount( float flCycle, float *posBlend, float *angBlend );
bool LocalIntervalMovement( float flInterval, bool &bMoveSeqFinished, Vector &newPosition, QAngle &newAngles );
void GetTransitionAnimationIdeal( float flCycle, const Vector &vecTargetPos, const QAngle &vecTargetAngles, Vector *idealOrigin, QAngle *idealAngles );
float GetNextCycleForInterval( int nSequence, float flInterval );
void GetLocalVehicleVelocity( Vector *pOut );
void CacheBlendTargets( void );
void InitVehicleState( void );
int FindEntrySequence( bool bNearest = false );
int FindExitSequence( void );
bool IsValidTransitionPoint( const Vector &vecStartPos, const Vector &vecEndPos );
void SetPassengerState( PassengerState_e state ) { m_PassengerState = state; }
PassengerState_e m_PassengerState; // State we're in, for the vehicle
// ---------------------------------------------
bool IsPassengerHostile( void );
passengerVehicleState_t m_vehicleState; // Internal vehicle state
CHandle <CPropVehicleDriveable> m_hVehicle; // The vehicle we're bound to
CHandle <CEntityBlocker> m_hBlocker; // Blocking entity for space reservation
Vector m_vecTargetPosition; // Target destination for exiting the vehicle
QAngle m_vecTargetAngles; // Target angles for exiting the vehicle
bool m_bEnabled; // If the behavior is running
passesngerVehicleIntent_e m_PassengerIntent; // Gives us information about whether we're meant to get in/out, etc.
int m_nTransitionSequence; // Animation we're using to transition with
float m_flOriginStartFrame;
float m_flOriginEndFrame;
float m_flAnglesStartFrame;
float m_flAnglesEndFrame;
protected:
DEFINE_CUSTOM_SCHEDULE_PROVIDER;
};
class CTraceFilterVehicleTransition : public CTraceFilterSkipTwoEntities
{
public:
DECLARE_CLASS( CTraceFilterVehicleTransition, CTraceFilterSkipTwoEntities );
CTraceFilterVehicleTransition( const IHandleEntity *passentity, const IHandleEntity *passentity2, int collisionGroup ) :
CTraceFilterSkipTwoEntities( passentity, passentity2, collisionGroup ) {}
bool ShouldHitEntity( IHandleEntity *pServerEntity, int contentsMask )
{
bool bRet = BaseClass::ShouldHitEntity( pServerEntity, contentsMask );
CBaseEntity *pEntity = EntityFromEntityHandle( pServerEntity );
if ( pEntity )
{
IPhysicsObject *pPhys = pEntity->VPhysicsGetObject();
if ( pPhys )
{
// Ignore physics objects
// TODO: This will have to be fleshed out more as cases arise
if ( pPhys->IsMoveable() && pPhys->GetMass() < 80.0f )
return false;
}
}
return bRet;
}
};
#endif // AI_BEHAVIOR_PASSENGER_H
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================
#ifndef AI_BEHAVIOR_PASSENGER_H
#define AI_BEHAVIOR_PASSENGER_H
#ifdef _WIN32
#pragma once
#endif
#include "ai_speech.h"
#include "ai_behavior.h"
#include "ai_utils.h"
#include "vehicle_jeep_episodic.h"
#define STOPPED_VELOCITY_THRESHOLD 32.0f
#define STOPPED_VELOCITY_THRESHOLD_SQR (STOPPED_VELOCITY_THRESHOLD*STOPPED_VELOCITY_THRESHOLD)
#define STARTED_VELOCITY_THRESHOLD 64.0f
#define STARTED_VELOCITY_THRESHOLD_SQR (STARTED_VELOCITY_THRESHOLD*STARTED_VELOCITY_THRESHOLD)
// Custom activities
extern int ACT_PASSENGER_IDLE;
extern int ACT_PASSENGER_RANGE_ATTACK1;
// ---------------------------------------------
// Vehicle state
// ---------------------------------------------
struct passengerVehicleState_t
{
Vector m_vecLastLocalVelocity;
Vector m_vecDeltaVelocity;
QAngle m_vecLastAngles;
float m_flNextWarningTime;
float m_flLastSpeedSqr;
bool m_bPlayerInVehicle;
bool m_bWasBoosting;
bool m_bWasOverturned;
DECLARE_SIMPLE_DATADESC();
};
// ---------------------------------------------
// Passenger intent
// ---------------------------------------------
enum passesngerVehicleIntent_e
{
PASSENGER_INTENT_NONE,
PASSENGER_INTENT_ENTER, // We want to be in the vehicle
PASSENGER_INTENT_EXIT, // We want to be outside the vehicle
};
// ---------------------------------------------
// Passenger state functions
// ---------------------------------------------
enum PassengerState_e
{
PASSENGER_STATE_OUTSIDE = 0, // Not in the vehicle
PASSENGER_STATE_ENTERING,
PASSENGER_STATE_INSIDE,
PASSENGER_STATE_EXITING,
};
class CAI_PassengerBehavior : public CAI_SimpleBehavior
{
DECLARE_CLASS( CAI_PassengerBehavior, CAI_SimpleBehavior );
DECLARE_DATADESC()
public:
CAI_PassengerBehavior( void );
enum
{
// Schedules
SCHED_PASSENGER_IDLE = BaseClass::NEXT_SCHEDULE,
SCHED_PASSENGER_ENTER_VEHICLE,
SCHED_PASSENGER_EXIT_VEHICLE,
SCHED_PASSENGER_RUN_TO_ENTER_VEHICLE,
SCHED_PASSENGER_ENTER_VEHICLE_PAUSE,
SCHED_PASSENGER_RUN_TO_ENTER_VEHICLE_FAILED,
SCHED_PASSENGER_PLAY_SCRIPTED_ANIM,
NEXT_SCHEDULE,
// Tasks
TASK_PASSENGER_ENTER_VEHICLE = BaseClass::NEXT_TASK,
TASK_PASSENGER_EXIT_VEHICLE,
TASK_PASSENGER_ATTACH_TO_VEHICLE,
TASK_PASSENGER_DETACH_FROM_VEHICLE,
TASK_PASSENGER_SET_IDEAL_ENTRY_YAW,
NEXT_TASK,
// Conditions
COND_PASSENGER_HARD_IMPACT = BaseClass::NEXT_CONDITION,
COND_PASSENGER_ENTERING,
COND_PASSENGER_EXITING,
COND_PASSENGER_VEHICLE_STARTED,
COND_PASSENGER_VEHICLE_STOPPED,
COND_PASSENGER_OVERTURNED,
COND_PASSENGER_CANCEL_ENTER,
COND_PASSENGER_ERRATIC_DRIVING,
COND_PASSENGER_PLAYER_ENTERED_VEHICLE,
COND_PASSENGER_PLAYER_EXITED_VEHICLE,
COND_PASSENGER_JOSTLE_SMALL,
NEXT_CONDITION
};
bool ForceVehicleInteraction( const char *lpszInteractionName, CBaseCombatCharacter *pOther );
virtual bool CanSelectSchedule( void );
virtual int SelectSchedule( void );
virtual int SelectFailSchedule( int failedSchedule, int failedTask, AI_TaskFailureCode_t taskFailCode );
virtual void RunTask( const Task_t *pTask );
virtual void StartTask( const Task_t *pTask );
virtual void BuildScheduleTestBits( void );
virtual int TranslateSchedule( int scheduleType );
virtual void GetEntryTarget( Vector *vecOrigin, QAngle *vecAngles );
virtual void GatherConditions( void );
virtual void ModifyOrAppendCriteria( AI_CriteriaSet& criteriaSet );
virtual void Teleport( const Vector *newPosition, const QAngle *newAngles, const Vector *newVelocity );
virtual void ClearSchedule( const char *szReason );
virtual bool IsInterruptable( void );
virtual void PrescheduleThink( void );
virtual void CancelEnterVehicle( void );
virtual const char *GetName( void ) { return "Passenger"; }
virtual string_t GetRoleName( void ) { return MAKE_STRING( "passenger" ); }
// Enable/disable code
void Enable( CPropJeepEpisodic *pVehicle, bool bImmediateEntrance = false );
void Disable( void );
bool IsEnabled( void ) const { return m_bEnabled; }
virtual void EnterVehicle( void );
virtual void ExitVehicle( void );
void AddPhysicsPush( float force );
CPropVehicleDriveable *GetTargetVehicle( void ) const { return m_hVehicle; }
PassengerState_e GetPassengerState( void ) const { return m_PassengerState; }
virtual void OnRestore();
protected:
virtual int SelectTransitionSchedule( void );
bool SpeakIfAllowed( AIConcept_t concept, const char *modifiers = NULL, bool bRespondingToPlayer = false, char *pszOutResponseChosen = NULL, size_t bufsize = 0 );
bool CanExitVehicle( void );
void SetTransitionSequence( int nSequence );
void AttachToVehicle( void );
virtual void OnExitVehicleFailed( void ) { } // NPC attempted to leave vehicle, but was unable to
virtual void GatherVehicleStateConditions( void );
// ------------------------------------------
// Entry/exit transition code
// ------------------------------------------
virtual void FinishEnterVehicle( void );
virtual void FinishExitVehicle( void );
void DetachFromVehicle( void );
void DrawDebugTransitionInfo( const Vector &vecIdealPos, const QAngle &vecIdealAngles, const Vector &vecAnimPos, const QAngle &vecAnimAngles );
bool GetEntryPoint( int nSequence, Vector *vecEntryPoint, QAngle *vecEntryAngles = NULL );
bool GetExitPoint( int nSequence, Vector *vecExitPoint, QAngle *vecExitAngles = NULL );
bool PointIsNavigable( const Vector &vecTargetPos );
bool ReserveEntryPoint( VehicleSeatQuery_e eSeatSearchType );
bool ReserveExitPoint( void );
bool FindGroundAtPosition( const Vector &in, float flUpDelta, float flDownDelta, Vector *out );
bool DoTransitionMovement( void );
bool GetSequenceBlendAmount( float flCycle, float *posBlend, float *angBlend );
bool LocalIntervalMovement( float flInterval, bool &bMoveSeqFinished, Vector &newPosition, QAngle &newAngles );
void GetTransitionAnimationIdeal( float flCycle, const Vector &vecTargetPos, const QAngle &vecTargetAngles, Vector *idealOrigin, QAngle *idealAngles );
float GetNextCycleForInterval( int nSequence, float flInterval );
void GetLocalVehicleVelocity( Vector *pOut );
void CacheBlendTargets( void );
void InitVehicleState( void );
int FindEntrySequence( bool bNearest = false );
int FindExitSequence( void );
bool IsValidTransitionPoint( const Vector &vecStartPos, const Vector &vecEndPos );
void SetPassengerState( PassengerState_e state ) { m_PassengerState = state; }
PassengerState_e m_PassengerState; // State we're in, for the vehicle
// ---------------------------------------------
bool IsPassengerHostile( void );
passengerVehicleState_t m_vehicleState; // Internal vehicle state
CHandle <CPropVehicleDriveable> m_hVehicle; // The vehicle we're bound to
CHandle <CEntityBlocker> m_hBlocker; // Blocking entity for space reservation
Vector m_vecTargetPosition; // Target destination for exiting the vehicle
QAngle m_vecTargetAngles; // Target angles for exiting the vehicle
bool m_bEnabled; // If the behavior is running
passesngerVehicleIntent_e m_PassengerIntent; // Gives us information about whether we're meant to get in/out, etc.
int m_nTransitionSequence; // Animation we're using to transition with
float m_flOriginStartFrame;
float m_flOriginEndFrame;
float m_flAnglesStartFrame;
float m_flAnglesEndFrame;
protected:
DEFINE_CUSTOM_SCHEDULE_PROVIDER;
};
class CTraceFilterVehicleTransition : public CTraceFilterSkipTwoEntities
{
public:
DECLARE_CLASS( CTraceFilterVehicleTransition, CTraceFilterSkipTwoEntities );
CTraceFilterVehicleTransition( const IHandleEntity *passentity, const IHandleEntity *passentity2, int collisionGroup ) :
CTraceFilterSkipTwoEntities( passentity, passentity2, collisionGroup ) {}
bool ShouldHitEntity( IHandleEntity *pServerEntity, int contentsMask )
{
bool bRet = BaseClass::ShouldHitEntity( pServerEntity, contentsMask );
CBaseEntity *pEntity = EntityFromEntityHandle( pServerEntity );
if ( pEntity )
{
IPhysicsObject *pPhys = pEntity->VPhysicsGetObject();
if ( pPhys )
{
// Ignore physics objects
// TODO: This will have to be fleshed out more as cases arise
if ( pPhys->IsMoveable() && pPhys->GetMass() < 80.0f )
return false;
}
}
return bRet;
}
};
#endif // AI_BEHAVIOR_PASSENGER_H

View File

@@ -1,459 +1,459 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#include "cbase.h"
#include "ai_motor.h"
#include "ai_behavior_rappel.h"
#include "beam_shared.h"
#include "rope.h"
#include "eventqueue.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
BEGIN_DATADESC( CAI_RappelBehavior )
DEFINE_FIELD( m_bWaitingToRappel, FIELD_BOOLEAN ),
DEFINE_FIELD( m_bOnGround, FIELD_BOOLEAN ),
DEFINE_FIELD( m_hLine, FIELD_EHANDLE ),
DEFINE_FIELD( m_vecRopeAnchor, FIELD_POSITION_VECTOR ),
END_DATADESC();
//=========================================================
//=========================================================
class CRopeAnchor : public CPointEntity
{
DECLARE_CLASS( CRopeAnchor, CPointEntity );
public:
void Spawn( void );
void FallThink( void );
void RemoveThink( void );
EHANDLE m_hRope;
DECLARE_DATADESC();
};
BEGIN_DATADESC( CRopeAnchor )
DEFINE_FIELD( m_hRope, FIELD_EHANDLE ),
DEFINE_THINKFUNC( FallThink ),
DEFINE_THINKFUNC( RemoveThink ),
END_DATADESC();
LINK_ENTITY_TO_CLASS( rope_anchor, CRopeAnchor );
//---------------------------------------------------------
//---------------------------------------------------------
#define RAPPEL_ROPE_WIDTH 1
void CRopeAnchor::Spawn()
{
BaseClass::Spawn();
// Decent enough default in case something happens to our owner!
float flDist = 384;
if( GetOwnerEntity() )
{
flDist = fabs( GetOwnerEntity()->GetAbsOrigin().z - GetAbsOrigin().z );
}
m_hRope = CRopeKeyframe::CreateWithSecondPointDetached( this, -1, flDist, RAPPEL_ROPE_WIDTH, "cable/cable.vmt", 5, true );
ASSERT( m_hRope != NULL );
SetThink( &CRopeAnchor::FallThink );
SetNextThink( gpGlobals->curtime + 0.2 );
}
//---------------------------------------------------------
//---------------------------------------------------------
void CRopeAnchor::FallThink()
{
SetMoveType( MOVETYPE_FLYGRAVITY );
Vector vecVelocity = GetAbsVelocity();
vecVelocity.x = random->RandomFloat( -30.0f, 30.0f );
vecVelocity.y = random->RandomFloat( -30.0f, 30.0f );
SetAbsVelocity( vecVelocity );
SetThink( &CRopeAnchor::RemoveThink );
SetNextThink( gpGlobals->curtime + 3.0 );
}
//---------------------------------------------------------
//---------------------------------------------------------
void CRopeAnchor::RemoveThink()
{
UTIL_Remove( m_hRope );
SetThink( &CRopeAnchor::SUB_Remove );
SetNextThink( gpGlobals->curtime );
}
//=========================================================
//=========================================================
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
CAI_RappelBehavior::CAI_RappelBehavior()
{
m_hLine = NULL;
m_bWaitingToRappel = false;
m_bOnGround = true;
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
bool CAI_RappelBehavior::KeyValue( const char *szKeyName, const char *szValue )
{
if( FStrEq( szKeyName, "waitingtorappel" ) )
{
m_bWaitingToRappel = ( atoi(szValue) != 0);
m_bOnGround = !m_bWaitingToRappel;
return true;
}
return BaseClass::KeyValue( szKeyName, szValue );
}
void CAI_RappelBehavior::Precache()
{
CBaseEntity::PrecacheModel( "cable/cable.vmt" );
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
#define RAPPEL_MAX_SPEED 600 // Go this fast if you're really high.
#define RAPPEL_MIN_SPEED 60 // Go no slower than this.
#define RAPPEL_DECEL_DIST (20.0f * 12.0f) // Start slowing down when you're this close to the ground.
void CAI_RappelBehavior::SetDescentSpeed()
{
// Trace to the floor and see how close we're getting. Slow down if we're close.
// STOP if there's an NPC under us.
trace_t tr;
AI_TraceLine( GetOuter()->GetAbsOrigin(), GetOuter()->GetAbsOrigin() - Vector( 0, 0, 8192 ), MASK_SHOT, GetOuter(), COLLISION_GROUP_NONE, &tr );
float flDist = fabs( GetOuter()->GetAbsOrigin().z - tr.endpos.z );
float speed = RAPPEL_MAX_SPEED;
if( flDist <= RAPPEL_DECEL_DIST )
{
float factor;
factor = flDist / RAPPEL_DECEL_DIST;
speed = MAX( RAPPEL_MIN_SPEED, speed * factor );
}
Vector vecNewVelocity = vec3_origin;
vecNewVelocity.z = -speed;
GetOuter()->SetAbsVelocity( vecNewVelocity );
}
void CAI_RappelBehavior::CleanupOnDeath( CBaseEntity *pCulprit, bool bFireDeathOutput )
{
BaseClass::CleanupOnDeath( pCulprit, bFireDeathOutput );
//This will remove the beam and create a rope if the NPC dies while rappeling down.
if ( m_hLine )
{
CAI_BaseNPC *pNPC = GetOuter();
if ( pNPC )
{
CutZipline();
}
}
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : *pTask -
//-----------------------------------------------------------------------------
void CAI_RappelBehavior::StartTask( const Task_t *pTask )
{
switch( pTask->iTask )
{
case TASK_MOVE_AWAY_PATH:
GetOuter()->GetMotor()->SetIdealYaw( UTIL_AngleMod( GetOuter()->GetLocalAngles().y - 180.0f ) );
BaseClass::StartTask( pTask );
break;
case TASK_RANGE_ATTACK1:
BaseClass::StartTask( pTask );
break;
case TASK_RAPPEL:
{
CreateZipline();
SetDescentSpeed();
}
break;
case TASK_HIT_GROUND:
m_bOnGround = true;
if( GetOuter()->GetGroundEntity() != NULL && GetOuter()->GetGroundEntity()->IsNPC() && GetOuter()->GetGroundEntity()->m_iClassname == GetOuter()->m_iClassname )
{
// Although I tried to get NPC's out from under me, I landed on one. Kill it, so long as it's the same type of character as me.
variant_t val;
val.SetFloat( 0 );
g_EventQueue.AddEvent( GetOuter()->GetGroundEntity(), "sethealth", val, 0, GetOuter(), GetOuter() );
}
TaskComplete();
break;
default:
BaseClass::StartTask( pTask );
break;
}
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : *pTask -
//-----------------------------------------------------------------------------
void CAI_RappelBehavior::RunTask( const Task_t *pTask )
{
switch( pTask->iTask )
{
case TASK_RAPPEL:
{
// If we don't do this, the beam won't show up sometimes. Ideally, all beams would update their
// bboxes correctly, but we're close to shipping and we can't change that now.
if ( m_hLine )
{
m_hLine->RelinkBeam();
}
if( GetEnemy() )
{
// Face the enemy if there's one.
Vector vecEnemyLKP = GetEnemyLKP();
GetOuter()->GetMotor()->SetIdealYawToTargetAndUpdate( vecEnemyLKP );
}
SetDescentSpeed();
if( GetOuter()->GetFlags() & FL_ONGROUND )
{
CBaseEntity *pGroundEnt = GetOuter()->GetGroundEntity();
if( pGroundEnt && pGroundEnt->IsPlayer() )
{
// try to shove the player in the opposite direction as they are facing (so they'll see me)
Vector vecForward;
pGroundEnt->GetVectors( &vecForward, NULL, NULL );
pGroundEnt->SetAbsVelocity( vecForward * -500 );
break;
}
GetOuter()->m_OnRappelTouchdown.FireOutput( GetOuter(), GetOuter(), 0 );
GetOuter()->RemoveFlag( FL_FLY );
CutZipline();
TaskComplete();
}
}
break;
default:
BaseClass::RunTask( pTask );
break;
}
}
//-----------------------------------------------------------------------------
// Purpose:
// Output : Returns true on success, false on failure.
//-----------------------------------------------------------------------------
bool CAI_RappelBehavior::CanSelectSchedule()
{
if ( !GetOuter()->IsInterruptable() )
return false;
if ( m_bWaitingToRappel )
return true;
if ( m_bOnGround )
return false;
return true;
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CAI_RappelBehavior::GatherConditions()
{
BaseClass::GatherConditions();
if( HasCondition( COND_CAN_RANGE_ATTACK1 ) )
{
// Shoot at the enemy so long as I'm six feet or more above them.
if( (GetAbsOrigin().z - GetEnemy()->GetAbsOrigin().z >= 36.0f) && GetOuter()->GetShotRegulator()->ShouldShoot() )
{
Activity activity = GetOuter()->TranslateActivity( ACT_GESTURE_RANGE_ATTACK1 );
Assert( activity != ACT_INVALID );
GetOuter()->AddGesture( activity );
// FIXME: this seems a bit wacked
GetOuter()->Weapon_SetActivity( GetOuter()->Weapon_TranslateActivity( ACT_RANGE_ATTACK1 ), 0 );
GetOuter()->OnRangeAttack1();
}
}
}
//-----------------------------------------------------------------------------
// Purpose:
// Output : int
//-----------------------------------------------------------------------------
int CAI_RappelBehavior::SelectSchedule()
{
if ( HasCondition( COND_BEGIN_RAPPEL ) )
{
m_bWaitingToRappel = false;
return SCHED_RAPPEL;
}
if ( m_bWaitingToRappel )
{
return SCHED_RAPPEL_WAIT;
}
else
{
return SCHED_RAPPEL;
}
return BaseClass::SelectSchedule();
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CAI_RappelBehavior::BeginRappel()
{
// Send the message to begin rappeling!
SetCondition( COND_BEGIN_RAPPEL );
m_vecRopeAnchor = GetOuter()->GetAbsOrigin();
trace_t tr;
UTIL_TraceEntity( GetOuter(), GetAbsOrigin(), GetAbsOrigin()-Vector(0,0,4096), MASK_SHOT, GetOuter(), COLLISION_GROUP_NONE, &tr );
if( tr.m_pEnt != NULL && tr.m_pEnt->IsNPC() )
{
Vector forward;
GetOuter()->GetVectors( &forward, NULL, NULL );
CSoundEnt::InsertSound( SOUND_DANGER, tr.m_pEnt->EarPosition() - forward * 12.0f, 32.0f, 0.2f, GetOuter() );
}
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CAI_RappelBehavior::CutZipline()
{
if( m_hLine )
{
UTIL_Remove( m_hLine );
}
CBaseEntity *pAnchor = CreateEntityByName( "rope_anchor" );
pAnchor->SetOwnerEntity( GetOuter() ); // Boy, this is a hack!!
pAnchor->SetAbsOrigin( m_vecRopeAnchor );
pAnchor->Spawn();
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CAI_RappelBehavior::CreateZipline()
{
#if 1
if( !m_hLine )
{
int attachment = GetOuter()->LookupAttachment( "zipline" );
if( attachment > 0 )
{
CBeam *pBeam;
pBeam = CBeam::BeamCreate( "cable/cable.vmt", 1 );
pBeam->SetColor( 150, 150, 150 );
pBeam->SetWidth( 0.3 );
pBeam->SetEndWidth( 0.3 );
CAI_BaseNPC *pNPC = GetOuter();
pBeam->PointEntInit( pNPC->GetAbsOrigin() + Vector( 0, 0, 80 ), pNPC );
pBeam->SetEndAttachment( attachment );
m_hLine.Set( pBeam );
}
}
#endif
}
AI_BEGIN_CUSTOM_SCHEDULE_PROVIDER( CAI_RappelBehavior )
DECLARE_TASK( TASK_RAPPEL )
DECLARE_TASK( TASK_HIT_GROUND )
DECLARE_CONDITION( COND_BEGIN_RAPPEL )
//===============================================
//===============================================
DEFINE_SCHEDULE
(
SCHED_RAPPEL_WAIT,
" Tasks"
" TASK_SET_ACTIVITY ACTIVITY:ACT_RAPPEL_LOOP"
" TASK_WAIT_INDEFINITE 0"
""
" Interrupts"
" COND_BEGIN_RAPPEL"
);
//===============================================
//===============================================
DEFINE_SCHEDULE
(
SCHED_RAPPEL,
" Tasks"
" TASK_SET_ACTIVITY ACTIVITY:ACT_RAPPEL_LOOP"
" TASK_RAPPEL 0"
" TASK_SET_SCHEDULE SCHEDULE:SCHED_CLEAR_RAPPEL_POINT"
""
" Interrupts"
""
" COND_NEW_ENEMY" // Only so the enemy selection code will pick an enemy!
);
//===============================================
//===============================================
DEFINE_SCHEDULE
(
SCHED_CLEAR_RAPPEL_POINT,
" Tasks"
" TASK_HIT_GROUND 0"
" TASK_MOVE_AWAY_PATH 128" // Clear this spot for other rappellers
" TASK_RUN_PATH 0"
" TASK_WAIT_FOR_MOVEMENT 0"
""
" Interrupts"
""
);
AI_END_CUSTOM_SCHEDULE_PROVIDER()
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#include "cbase.h"
#include "ai_motor.h"
#include "ai_behavior_rappel.h"
#include "beam_shared.h"
#include "rope.h"
#include "eventqueue.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
BEGIN_DATADESC( CAI_RappelBehavior )
DEFINE_FIELD( m_bWaitingToRappel, FIELD_BOOLEAN ),
DEFINE_FIELD( m_bOnGround, FIELD_BOOLEAN ),
DEFINE_FIELD( m_hLine, FIELD_EHANDLE ),
DEFINE_FIELD( m_vecRopeAnchor, FIELD_POSITION_VECTOR ),
END_DATADESC();
//=========================================================
//=========================================================
class CRopeAnchor : public CPointEntity
{
DECLARE_CLASS( CRopeAnchor, CPointEntity );
public:
void Spawn( void );
void FallThink( void );
void RemoveThink( void );
EHANDLE m_hRope;
DECLARE_DATADESC();
};
BEGIN_DATADESC( CRopeAnchor )
DEFINE_FIELD( m_hRope, FIELD_EHANDLE ),
DEFINE_THINKFUNC( FallThink ),
DEFINE_THINKFUNC( RemoveThink ),
END_DATADESC();
LINK_ENTITY_TO_CLASS( rope_anchor, CRopeAnchor );
//---------------------------------------------------------
//---------------------------------------------------------
#define RAPPEL_ROPE_WIDTH 1
void CRopeAnchor::Spawn()
{
BaseClass::Spawn();
// Decent enough default in case something happens to our owner!
float flDist = 384;
if( GetOwnerEntity() )
{
flDist = fabs( GetOwnerEntity()->GetAbsOrigin().z - GetAbsOrigin().z );
}
m_hRope = CRopeKeyframe::CreateWithSecondPointDetached( this, -1, flDist, RAPPEL_ROPE_WIDTH, "cable/cable.vmt", 5, true );
ASSERT( m_hRope != NULL );
SetThink( &CRopeAnchor::FallThink );
SetNextThink( gpGlobals->curtime + 0.2 );
}
//---------------------------------------------------------
//---------------------------------------------------------
void CRopeAnchor::FallThink()
{
SetMoveType( MOVETYPE_FLYGRAVITY );
Vector vecVelocity = GetAbsVelocity();
vecVelocity.x = random->RandomFloat( -30.0f, 30.0f );
vecVelocity.y = random->RandomFloat( -30.0f, 30.0f );
SetAbsVelocity( vecVelocity );
SetThink( &CRopeAnchor::RemoveThink );
SetNextThink( gpGlobals->curtime + 3.0 );
}
//---------------------------------------------------------
//---------------------------------------------------------
void CRopeAnchor::RemoveThink()
{
UTIL_Remove( m_hRope );
SetThink( &CRopeAnchor::SUB_Remove );
SetNextThink( gpGlobals->curtime );
}
//=========================================================
//=========================================================
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
CAI_RappelBehavior::CAI_RappelBehavior()
{
m_hLine = NULL;
m_bWaitingToRappel = false;
m_bOnGround = true;
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
bool CAI_RappelBehavior::KeyValue( const char *szKeyName, const char *szValue )
{
if( FStrEq( szKeyName, "waitingtorappel" ) )
{
m_bWaitingToRappel = ( atoi(szValue) != 0);
m_bOnGround = !m_bWaitingToRappel;
return true;
}
return BaseClass::KeyValue( szKeyName, szValue );
}
void CAI_RappelBehavior::Precache()
{
CBaseEntity::PrecacheModel( "cable/cable.vmt" );
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
#define RAPPEL_MAX_SPEED 600 // Go this fast if you're really high.
#define RAPPEL_MIN_SPEED 60 // Go no slower than this.
#define RAPPEL_DECEL_DIST (20.0f * 12.0f) // Start slowing down when you're this close to the ground.
void CAI_RappelBehavior::SetDescentSpeed()
{
// Trace to the floor and see how close we're getting. Slow down if we're close.
// STOP if there's an NPC under us.
trace_t tr;
AI_TraceLine( GetOuter()->GetAbsOrigin(), GetOuter()->GetAbsOrigin() - Vector( 0, 0, 8192 ), MASK_SHOT, GetOuter(), COLLISION_GROUP_NONE, &tr );
float flDist = fabs( GetOuter()->GetAbsOrigin().z - tr.endpos.z );
float speed = RAPPEL_MAX_SPEED;
if( flDist <= RAPPEL_DECEL_DIST )
{
float factor;
factor = flDist / RAPPEL_DECEL_DIST;
speed = MAX( RAPPEL_MIN_SPEED, speed * factor );
}
Vector vecNewVelocity = vec3_origin;
vecNewVelocity.z = -speed;
GetOuter()->SetAbsVelocity( vecNewVelocity );
}
void CAI_RappelBehavior::CleanupOnDeath( CBaseEntity *pCulprit, bool bFireDeathOutput )
{
BaseClass::CleanupOnDeath( pCulprit, bFireDeathOutput );
//This will remove the beam and create a rope if the NPC dies while rappeling down.
if ( m_hLine )
{
CAI_BaseNPC *pNPC = GetOuter();
if ( pNPC )
{
CutZipline();
}
}
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : *pTask -
//-----------------------------------------------------------------------------
void CAI_RappelBehavior::StartTask( const Task_t *pTask )
{
switch( pTask->iTask )
{
case TASK_MOVE_AWAY_PATH:
GetOuter()->GetMotor()->SetIdealYaw( UTIL_AngleMod( GetOuter()->GetLocalAngles().y - 180.0f ) );
BaseClass::StartTask( pTask );
break;
case TASK_RANGE_ATTACK1:
BaseClass::StartTask( pTask );
break;
case TASK_RAPPEL:
{
CreateZipline();
SetDescentSpeed();
}
break;
case TASK_HIT_GROUND:
m_bOnGround = true;
if( GetOuter()->GetGroundEntity() != NULL && GetOuter()->GetGroundEntity()->IsNPC() && GetOuter()->GetGroundEntity()->m_iClassname == GetOuter()->m_iClassname )
{
// Although I tried to get NPC's out from under me, I landed on one. Kill it, so long as it's the same type of character as me.
variant_t val;
val.SetFloat( 0 );
g_EventQueue.AddEvent( GetOuter()->GetGroundEntity(), "sethealth", val, 0, GetOuter(), GetOuter() );
}
TaskComplete();
break;
default:
BaseClass::StartTask( pTask );
break;
}
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : *pTask -
//-----------------------------------------------------------------------------
void CAI_RappelBehavior::RunTask( const Task_t *pTask )
{
switch( pTask->iTask )
{
case TASK_RAPPEL:
{
// If we don't do this, the beam won't show up sometimes. Ideally, all beams would update their
// bboxes correctly, but we're close to shipping and we can't change that now.
if ( m_hLine )
{
m_hLine->RelinkBeam();
}
if( GetEnemy() )
{
// Face the enemy if there's one.
Vector vecEnemyLKP = GetEnemyLKP();
GetOuter()->GetMotor()->SetIdealYawToTargetAndUpdate( vecEnemyLKP );
}
SetDescentSpeed();
if( GetOuter()->GetFlags() & FL_ONGROUND )
{
CBaseEntity *pGroundEnt = GetOuter()->GetGroundEntity();
if( pGroundEnt && pGroundEnt->IsPlayer() )
{
// try to shove the player in the opposite direction as they are facing (so they'll see me)
Vector vecForward;
pGroundEnt->GetVectors( &vecForward, NULL, NULL );
pGroundEnt->SetAbsVelocity( vecForward * -500 );
break;
}
GetOuter()->m_OnRappelTouchdown.FireOutput( GetOuter(), GetOuter(), 0 );
GetOuter()->RemoveFlag( FL_FLY );
CutZipline();
TaskComplete();
}
}
break;
default:
BaseClass::RunTask( pTask );
break;
}
}
//-----------------------------------------------------------------------------
// Purpose:
// Output : Returns true on success, false on failure.
//-----------------------------------------------------------------------------
bool CAI_RappelBehavior::CanSelectSchedule()
{
if ( !GetOuter()->IsInterruptable() )
return false;
if ( m_bWaitingToRappel )
return true;
if ( m_bOnGround )
return false;
return true;
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CAI_RappelBehavior::GatherConditions()
{
BaseClass::GatherConditions();
if( HasCondition( COND_CAN_RANGE_ATTACK1 ) )
{
// Shoot at the enemy so long as I'm six feet or more above them.
if( (GetAbsOrigin().z - GetEnemy()->GetAbsOrigin().z >= 36.0f) && GetOuter()->GetShotRegulator()->ShouldShoot() )
{
Activity activity = GetOuter()->TranslateActivity( ACT_GESTURE_RANGE_ATTACK1 );
Assert( activity != ACT_INVALID );
GetOuter()->AddGesture( activity );
// FIXME: this seems a bit wacked
GetOuter()->Weapon_SetActivity( GetOuter()->Weapon_TranslateActivity( ACT_RANGE_ATTACK1 ), 0 );
GetOuter()->OnRangeAttack1();
}
}
}
//-----------------------------------------------------------------------------
// Purpose:
// Output : int
//-----------------------------------------------------------------------------
int CAI_RappelBehavior::SelectSchedule()
{
if ( HasCondition( COND_BEGIN_RAPPEL ) )
{
m_bWaitingToRappel = false;
return SCHED_RAPPEL;
}
if ( m_bWaitingToRappel )
{
return SCHED_RAPPEL_WAIT;
}
else
{
return SCHED_RAPPEL;
}
return BaseClass::SelectSchedule();
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CAI_RappelBehavior::BeginRappel()
{
// Send the message to begin rappeling!
SetCondition( COND_BEGIN_RAPPEL );
m_vecRopeAnchor = GetOuter()->GetAbsOrigin();
trace_t tr;
UTIL_TraceEntity( GetOuter(), GetAbsOrigin(), GetAbsOrigin()-Vector(0,0,4096), MASK_SHOT, GetOuter(), COLLISION_GROUP_NONE, &tr );
if( tr.m_pEnt != NULL && tr.m_pEnt->IsNPC() )
{
Vector forward;
GetOuter()->GetVectors( &forward, NULL, NULL );
CSoundEnt::InsertSound( SOUND_DANGER, tr.m_pEnt->EarPosition() - forward * 12.0f, 32.0f, 0.2f, GetOuter() );
}
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CAI_RappelBehavior::CutZipline()
{
if( m_hLine )
{
UTIL_Remove( m_hLine );
}
CBaseEntity *pAnchor = CreateEntityByName( "rope_anchor" );
pAnchor->SetOwnerEntity( GetOuter() ); // Boy, this is a hack!!
pAnchor->SetAbsOrigin( m_vecRopeAnchor );
pAnchor->Spawn();
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CAI_RappelBehavior::CreateZipline()
{
#if 1
if( !m_hLine )
{
int attachment = GetOuter()->LookupAttachment( "zipline" );
if( attachment > 0 )
{
CBeam *pBeam;
pBeam = CBeam::BeamCreate( "cable/cable.vmt", 1 );
pBeam->SetColor( 150, 150, 150 );
pBeam->SetWidth( 0.3 );
pBeam->SetEndWidth( 0.3 );
CAI_BaseNPC *pNPC = GetOuter();
pBeam->PointEntInit( pNPC->GetAbsOrigin() + Vector( 0, 0, 80 ), pNPC );
pBeam->SetEndAttachment( attachment );
m_hLine.Set( pBeam );
}
}
#endif
}
AI_BEGIN_CUSTOM_SCHEDULE_PROVIDER( CAI_RappelBehavior )
DECLARE_TASK( TASK_RAPPEL )
DECLARE_TASK( TASK_HIT_GROUND )
DECLARE_CONDITION( COND_BEGIN_RAPPEL )
//===============================================
//===============================================
DEFINE_SCHEDULE
(
SCHED_RAPPEL_WAIT,
" Tasks"
" TASK_SET_ACTIVITY ACTIVITY:ACT_RAPPEL_LOOP"
" TASK_WAIT_INDEFINITE 0"
""
" Interrupts"
" COND_BEGIN_RAPPEL"
);
//===============================================
//===============================================
DEFINE_SCHEDULE
(
SCHED_RAPPEL,
" Tasks"
" TASK_SET_ACTIVITY ACTIVITY:ACT_RAPPEL_LOOP"
" TASK_RAPPEL 0"
" TASK_SET_SCHEDULE SCHEDULE:SCHED_CLEAR_RAPPEL_POINT"
""
" Interrupts"
""
" COND_NEW_ENEMY" // Only so the enemy selection code will pick an enemy!
);
//===============================================
//===============================================
DEFINE_SCHEDULE
(
SCHED_CLEAR_RAPPEL_POINT,
" Tasks"
" TASK_HIT_GROUND 0"
" TASK_MOVE_AWAY_PATH 128" // Clear this spot for other rappellers
" TASK_RUN_PATH 0"
" TASK_WAIT_FOR_MOVEMENT 0"
""
" Interrupts"
""
);
AI_END_CUSTOM_SCHEDULE_PROVIDER()

View File

@@ -1,93 +1,93 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Deal with weapon being out
//
// $Workfile: $
// $Date: $
//
//-----------------------------------------------------------------------------
// $Log: $
//
// $NoKeywords: $
//=============================================================================//
#ifndef AI_BEHAVIOR_RAPPEL_H
#define AI_BEHAVIOR_RAPPEL_H
#ifdef _WIN32
#pragma once
#endif
#include "ai_behavior.h"
class CBeam;
class CAI_RappelBehavior : public CAI_SimpleBehavior
{
DECLARE_CLASS( CAI_RappelBehavior, CAI_SimpleBehavior );
public:
CAI_RappelBehavior();
void Precache( void );
virtual const char *GetName() { return "Rappel"; }
virtual bool KeyValue( const char *szKeyName, const char *szValue );
virtual bool CanSelectSchedule();
void GatherConditions();
void CleanupOnDeath( CBaseEntity *pCulprit = NULL, bool bFireDeathOutput = true );
//virtual void BeginScheduleSelection();
//virtual void EndScheduleSelection();
void StartTask( const Task_t *pTask );
void RunTask( const Task_t *pTask );
bool IsWaitingToRappel() { return m_bWaitingToRappel; }
void BeginRappel();
void SetDescentSpeed();
void CreateZipline();
void CutZipline();
//void BuildScheduleTestBits();
//int TranslateSchedule( int scheduleType );
//void OnStartSchedule( int scheduleType );
//void InitializeBehavior();
enum
{
SCHED_RAPPEL_WAIT = BaseClass::NEXT_SCHEDULE,
SCHED_RAPPEL,
SCHED_CLEAR_RAPPEL_POINT, // Get out of the way for the next guy
NEXT_SCHEDULE,
TASK_RAPPEL = BaseClass::NEXT_TASK,
TASK_HIT_GROUND,
NEXT_TASK,
COND_BEGIN_RAPPEL = BaseClass::NEXT_CONDITION,
NEXT_CONDITION,
};
DEFINE_CUSTOM_SCHEDULE_PROVIDER;
public:
private:
virtual int SelectSchedule();
//---------------------------------
bool m_bWaitingToRappel;
bool m_bOnGround;
CHandle<CBeam> m_hLine;
Vector m_vecRopeAnchor;
DECLARE_DATADESC();
};
#endif // AI_BEHAVIOR_RAPPEL_H
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Deal with weapon being out
//
// $Workfile: $
// $Date: $
//
//-----------------------------------------------------------------------------
// $Log: $
//
// $NoKeywords: $
//=============================================================================//
#ifndef AI_BEHAVIOR_RAPPEL_H
#define AI_BEHAVIOR_RAPPEL_H
#ifdef _WIN32
#pragma once
#endif
#include "ai_behavior.h"
class CBeam;
class CAI_RappelBehavior : public CAI_SimpleBehavior
{
DECLARE_CLASS( CAI_RappelBehavior, CAI_SimpleBehavior );
public:
CAI_RappelBehavior();
void Precache( void );
virtual const char *GetName() { return "Rappel"; }
virtual bool KeyValue( const char *szKeyName, const char *szValue );
virtual bool CanSelectSchedule();
void GatherConditions();
void CleanupOnDeath( CBaseEntity *pCulprit = NULL, bool bFireDeathOutput = true );
//virtual void BeginScheduleSelection();
//virtual void EndScheduleSelection();
void StartTask( const Task_t *pTask );
void RunTask( const Task_t *pTask );
bool IsWaitingToRappel() { return m_bWaitingToRappel; }
void BeginRappel();
void SetDescentSpeed();
void CreateZipline();
void CutZipline();
//void BuildScheduleTestBits();
//int TranslateSchedule( int scheduleType );
//void OnStartSchedule( int scheduleType );
//void InitializeBehavior();
enum
{
SCHED_RAPPEL_WAIT = BaseClass::NEXT_SCHEDULE,
SCHED_RAPPEL,
SCHED_CLEAR_RAPPEL_POINT, // Get out of the way for the next guy
NEXT_SCHEDULE,
TASK_RAPPEL = BaseClass::NEXT_TASK,
TASK_HIT_GROUND,
NEXT_TASK,
COND_BEGIN_RAPPEL = BaseClass::NEXT_CONDITION,
NEXT_CONDITION,
};
DEFINE_CUSTOM_SCHEDULE_PROVIDER;
public:
private:
virtual int SelectSchedule();
//---------------------------------
bool m_bWaitingToRappel;
bool m_bOnGround;
CHandle<CBeam> m_hLine;
Vector m_vecRopeAnchor;
DECLARE_DATADESC();
};
#endif // AI_BEHAVIOR_RAPPEL_H

File diff suppressed because it is too large Load Diff

View File

@@ -1,232 +1,232 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Combat behaviors for AIs in a relatively self-preservationist mode.
// Lots of cover taking and attempted shots out of cover.
//
//=============================================================================//
#ifndef AI_BEHAVIOR_STANDOFF_H
#define AI_BEHAVIOR_STANDOFF_H
#include "utlvector.h"
#include "utlmap.h"
#include "ai_behavior.h"
#include "ai_utils.h"
#include "ai_hint.h"
#if defined( _WIN32 )
#pragma once
#endif
//-----------------------------------------------------------------------------
enum AI_HintChangeReaction_t
{
AIHCR_DEFAULT_AI,
AIHCR_MOVE_ON_COVER,
AIHCR_MOVE_IMMEDIATE,
};
struct AI_StandoffParams_t
{
AI_HintChangeReaction_t hintChangeReaction;
bool fCoverOnReload;
bool fPlayerIsBattleline;
float minTimeShots;
float maxTimeShots;
int minShots;
int maxShots;
int oddsCover;
bool fStayAtCover;
float flAbandonTimeLimit;
DECLARE_SIMPLE_DATADESC();
};
//-------------------------------------
enum AI_Posture_t
{
AIP_INDIFFERENT,
AIP_STANDING,
AIP_CROUCHING,
AIP_PEEKING,
};
enum
{
STANDOFF_SENTENCE_BEGIN_STANDOFF = SENTENCE_BASE_BEHAVIOR_INDEX,
STANDOFF_SENTENCE_END_STANDOFF,
STANDOFF_SENTENCE_OUT_OF_AMMO,
STANDOFF_SENTENCE_FORCED_TAKE_COVER,
STANDOFF_SENTENCE_STAND_CHECK_TARGET,
};
class CAI_MappedActivityBehavior_Temporary : public CAI_SimpleBehavior
{
DECLARE_CLASS( CAI_MappedActivityBehavior_Temporary, CAI_SimpleBehavior );
public:
CAI_MappedActivityBehavior_Temporary( CAI_BaseNPC *pOuter = NULL )
: CAI_SimpleBehavior(pOuter)
{
SetDefLessFunc( m_ActivityMap );
}
protected:
Activity GetMappedActivity( AI_Posture_t posture, Activity activity );
void OnChangeActiveWeapon( CBaseCombatWeapon *pOldWeapon, CBaseCombatWeapon *pNewWeapon );
virtual void UpdateTranslateActivityMap();
private:
CUtlMap<unsigned, Activity> m_ActivityMap;
};
class CAI_StandoffBehavior : public CAI_MappedActivityBehavior_Temporary
{
DECLARE_CLASS( CAI_StandoffBehavior, CAI_MappedActivityBehavior_Temporary );
public:
CAI_StandoffBehavior( CAI_BaseNPC *pOuter = NULL );
virtual const char *GetName() { return "Standoff"; }
void SetActive( bool fActive );
void SetParameters( const AI_StandoffParams_t &params, CAI_GoalEntity *pGoalEntity = NULL );
Vector GetStandoffGoalPosition();
void SetStandoffGoalPosition( const Vector &vecPos );
void ClearStandoffGoalPosition();
AI_Posture_t GetPosture();
bool IsActive( void ) { return m_fActive; }
void OnChangeTacticalConstraints();
bool CanSelectSchedule();
bool IsBehindBattleLines( const Vector &point );
protected:
void Spawn();
void BeginScheduleSelection();
void EndScheduleSelection();
void PrescheduleThink();
void GatherConditions();
int SelectSchedule();
int TranslateSchedule( int scheduleType );
void StartTask( const Task_t *pTask );
void BuildScheduleTestBits();
virtual void OnUpdateShotRegulator();
Activity NPC_TranslateActivity( Activity eNewActivity );
bool IsValidCover( const Vector &vecCoverLocation, CAI_Hint const *pHint );
bool IsValidShootPosition( const Vector &vecCoverLocation, CAI_Node *pNode, CAI_Hint const *pHint );
void SetPosture( AI_Posture_t posture );
void OnChangeHintGroup( string_t oldGroup, string_t newGroup );
virtual int SelectScheduleUpdateWeapon();
virtual int SelectScheduleCheckCover();
virtual int SelectScheduleEstablishAim();
virtual int SelectScheduleAttack();
bool PlayerIsLeading();
CBaseEntity *GetPlayerLeader();
bool GetDirectionOfStandoff( Vector *pDir );
void UpdateBattleLines();
Hint_e GetHintType();
void SetReuseCurrentCover();
void UnlockHintNode();
Activity GetCoverActivity();
void OnRestore();
void UpdateTranslateActivityMap();
// Standoff overrides base AI crouch handling
bool IsCrouching( void ) { return false; }
private:
//----------------------------
enum
{
NEXT_SCHEDULE = BaseClass::NEXT_SCHEDULE,
NEXT_TASK = BaseClass::NEXT_TASK,
COND_ABANDON_TIME_EXPIRED = BaseClass::NEXT_CONDITION,
NEXT_CONDITION
};
DEFINE_CUSTOM_SCHEDULE_PROVIDER;
//---------------------------------
// @TODO (toml 07-30-03): replace all these booleans with a singe 32 bit unsigned & bit flags
bool m_fActive;
bool m_fTestNoDamage;
Vector m_vecStandoffGoalPosition;
AI_Posture_t m_posture;
AI_StandoffParams_t m_params;
EHANDLE m_hStandoffGoal;
bool m_fTakeCover;
float m_SavedDistTooFar;
bool m_fForceNewEnemy;
CAI_MoveMonitor m_PlayerMoveMonitor;
CSimTimer m_TimeForceCoverHint;
CSimTimer m_TimePreventForceNewEnemy;
CRandSimTimer m_RandomCoverChangeTimer;
// FIXME: TEMPORARY! REMOVE
int m_nSavedMinShots, m_nSavedMaxShots;
float m_flSavedMinRest, m_flSavedMaxRest;
//---------------------------------
struct BattleLine_t
{
Vector point;
Vector normal;
};
CThinkOnceSemaphore m_UpdateBattleLinesSemaphore;
CUtlVector<BattleLine_t> m_BattleLines;
bool m_fIgnoreFronts;
//---------------------------------
bool m_bHasLowCoverActivity;
//---------------------------------
DECLARE_DATADESC();
};
//-------------------------------------
inline void CAI_StandoffBehavior::SetPosture( AI_Posture_t posture )
{
m_posture = posture;
}
//-------------------------------------
inline AI_Posture_t CAI_StandoffBehavior::GetPosture()
{
return m_posture;
}
//-----------------------------------------------------------------------------
#endif // AI_BEHAVIOR_STANDOFF_H
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Combat behaviors for AIs in a relatively self-preservationist mode.
// Lots of cover taking and attempted shots out of cover.
//
//=============================================================================//
#ifndef AI_BEHAVIOR_STANDOFF_H
#define AI_BEHAVIOR_STANDOFF_H
#include "utlvector.h"
#include "utlmap.h"
#include "ai_behavior.h"
#include "ai_utils.h"
#include "ai_hint.h"
#if defined( _WIN32 )
#pragma once
#endif
//-----------------------------------------------------------------------------
enum AI_HintChangeReaction_t
{
AIHCR_DEFAULT_AI,
AIHCR_MOVE_ON_COVER,
AIHCR_MOVE_IMMEDIATE,
};
struct AI_StandoffParams_t
{
AI_HintChangeReaction_t hintChangeReaction;
bool fCoverOnReload;
bool fPlayerIsBattleline;
float minTimeShots;
float maxTimeShots;
int minShots;
int maxShots;
int oddsCover;
bool fStayAtCover;
float flAbandonTimeLimit;
DECLARE_SIMPLE_DATADESC();
};
//-------------------------------------
enum AI_Posture_t
{
AIP_INDIFFERENT,
AIP_STANDING,
AIP_CROUCHING,
AIP_PEEKING,
};
enum
{
STANDOFF_SENTENCE_BEGIN_STANDOFF = SENTENCE_BASE_BEHAVIOR_INDEX,
STANDOFF_SENTENCE_END_STANDOFF,
STANDOFF_SENTENCE_OUT_OF_AMMO,
STANDOFF_SENTENCE_FORCED_TAKE_COVER,
STANDOFF_SENTENCE_STAND_CHECK_TARGET,
};
class CAI_MappedActivityBehavior_Temporary : public CAI_SimpleBehavior
{
DECLARE_CLASS( CAI_MappedActivityBehavior_Temporary, CAI_SimpleBehavior );
public:
CAI_MappedActivityBehavior_Temporary( CAI_BaseNPC *pOuter = NULL )
: CAI_SimpleBehavior(pOuter)
{
SetDefLessFunc( m_ActivityMap );
}
protected:
Activity GetMappedActivity( AI_Posture_t posture, Activity activity );
void OnChangeActiveWeapon( CBaseCombatWeapon *pOldWeapon, CBaseCombatWeapon *pNewWeapon );
virtual void UpdateTranslateActivityMap();
private:
CUtlMap<unsigned, Activity> m_ActivityMap;
};
class CAI_StandoffBehavior : public CAI_MappedActivityBehavior_Temporary
{
DECLARE_CLASS( CAI_StandoffBehavior, CAI_MappedActivityBehavior_Temporary );
public:
CAI_StandoffBehavior( CAI_BaseNPC *pOuter = NULL );
virtual const char *GetName() { return "Standoff"; }
void SetActive( bool fActive );
void SetParameters( const AI_StandoffParams_t &params, CAI_GoalEntity *pGoalEntity = NULL );
Vector GetStandoffGoalPosition();
void SetStandoffGoalPosition( const Vector &vecPos );
void ClearStandoffGoalPosition();
AI_Posture_t GetPosture();
bool IsActive( void ) { return m_fActive; }
void OnChangeTacticalConstraints();
bool CanSelectSchedule();
bool IsBehindBattleLines( const Vector &point );
protected:
void Spawn();
void BeginScheduleSelection();
void EndScheduleSelection();
void PrescheduleThink();
void GatherConditions();
int SelectSchedule();
int TranslateSchedule( int scheduleType );
void StartTask( const Task_t *pTask );
void BuildScheduleTestBits();
virtual void OnUpdateShotRegulator();
Activity NPC_TranslateActivity( Activity eNewActivity );
bool IsValidCover( const Vector &vecCoverLocation, CAI_Hint const *pHint );
bool IsValidShootPosition( const Vector &vecCoverLocation, CAI_Node *pNode, CAI_Hint const *pHint );
void SetPosture( AI_Posture_t posture );
void OnChangeHintGroup( string_t oldGroup, string_t newGroup );
virtual int SelectScheduleUpdateWeapon();
virtual int SelectScheduleCheckCover();
virtual int SelectScheduleEstablishAim();
virtual int SelectScheduleAttack();
bool PlayerIsLeading();
CBaseEntity *GetPlayerLeader();
bool GetDirectionOfStandoff( Vector *pDir );
void UpdateBattleLines();
Hint_e GetHintType();
void SetReuseCurrentCover();
void UnlockHintNode();
Activity GetCoverActivity();
void OnRestore();
void UpdateTranslateActivityMap();
// Standoff overrides base AI crouch handling
bool IsCrouching( void ) { return false; }
private:
//----------------------------
enum
{
NEXT_SCHEDULE = BaseClass::NEXT_SCHEDULE,
NEXT_TASK = BaseClass::NEXT_TASK,
COND_ABANDON_TIME_EXPIRED = BaseClass::NEXT_CONDITION,
NEXT_CONDITION
};
DEFINE_CUSTOM_SCHEDULE_PROVIDER;
//---------------------------------
// @TODO (toml 07-30-03): replace all these booleans with a singe 32 bit unsigned & bit flags
bool m_fActive;
bool m_fTestNoDamage;
Vector m_vecStandoffGoalPosition;
AI_Posture_t m_posture;
AI_StandoffParams_t m_params;
EHANDLE m_hStandoffGoal;
bool m_fTakeCover;
float m_SavedDistTooFar;
bool m_fForceNewEnemy;
CAI_MoveMonitor m_PlayerMoveMonitor;
CSimTimer m_TimeForceCoverHint;
CSimTimer m_TimePreventForceNewEnemy;
CRandSimTimer m_RandomCoverChangeTimer;
// FIXME: TEMPORARY! REMOVE
int m_nSavedMinShots, m_nSavedMaxShots;
float m_flSavedMinRest, m_flSavedMaxRest;
//---------------------------------
struct BattleLine_t
{
Vector point;
Vector normal;
};
CThinkOnceSemaphore m_UpdateBattleLinesSemaphore;
CUtlVector<BattleLine_t> m_BattleLines;
bool m_fIgnoreFronts;
//---------------------------------
bool m_bHasLowCoverActivity;
//---------------------------------
DECLARE_DATADESC();
};
//-------------------------------------
inline void CAI_StandoffBehavior::SetPosture( AI_Posture_t posture )
{
m_posture = posture;
}
//-------------------------------------
inline AI_Posture_t CAI_StandoffBehavior::GetPosture()
{
return m_posture;
}
//-----------------------------------------------------------------------------
#endif // AI_BEHAVIOR_STANDOFF_H

File diff suppressed because it is too large Load Diff

View File

@@ -1,260 +1,260 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#ifndef AI_BLENDED_MOVEMENT_H
#define AI_BLENDED_MOVEMENT_H
#include "ai_basenpc.h"
#include "ai_motor.h"
#include "ai_navigator.h"
struct AI_Waypoint_t;
//-----------------------------------------------------------------------------
// CLASS: CAI_BlendedMotor
//
// Purpose: Home of fancy human animation transition code
//
//-----------------------------------------------------------------------------
class CAI_BlendedMotor : public CAI_Motor
{
typedef CAI_Motor BaseClass;
public:
CAI_BlendedMotor( CAI_BaseNPC *pOuter )
: BaseClass( pOuter )
{
m_iPrimaryLayer = -1;
m_nPrimarySequence = ACT_INVALID;
m_iSecondaryLayer = -1;
m_nSecondarySequence = ACT_INVALID;
m_flSecondaryWeight = 0.0f;
m_nSavedGoalActivity = ACT_INVALID;
m_nSavedTranslatedGoalActivity = ACT_INVALID;
m_nGoalSequence = ACT_INVALID;
m_nPrevMovementSequence = ACT_INVALID;
m_nInteriorSequence = ACT_INVALID;
m_bDeceleratingToGoal = false;
m_flStartCycle = 0.0f;
m_flPredictiveSpeedAdjust = 1.0f;
m_flReactiveSpeedAdjust = 1.0f;
m_vecPrevOrigin1.Init();
m_vecPrevOrigin2.Init();
m_prevYaw = 0.0f;
m_doTurn = 0.0f;
m_doLeft = 0.0f;
m_doRight = 0.0f;
m_flNextTurnAct = 0.0f;
}
void MoveClimbStart( const Vector &climbDest, const Vector &climbDir, float climbDist, float yaw );
void MoveJumpStart( const Vector &velocity );
void ResetMoveCalculations();
void MoveStart();
void ResetGoalSequence();
void MoveStop();
void MovePaused();
void MoveContinue();
float OverrideMaxYawSpeed( Activity activity );
void UpdateYaw( int speed );
void RecalculateYawSpeed();
bool IsDeceleratingToGoal() const { return m_bDeceleratingToGoal; }
float GetMoveScriptTotalTime();
void MaintainTurnActivity( void );
bool AddTurnGesture( float flYD );
private:
AIMotorMoveResult_t MoveGroundExecute( const AILocalMoveGoal_t &move, AIMoveTrace_t *pTraceResult );
AIMotorMoveResult_t MoveFlyExecute( const AILocalMoveGoal_t &move, AIMoveTrace_t *pTraceResult );
// --------------------------------
void BuildMoveScript( const AILocalMoveGoal_t &move, AIMoveTrace_t *pTraceResult );
void BuildVelocityScript( const AILocalMoveGoal_t &move );
void InsertSlowdown( float distToObstruction, float idealAccel, bool bAlwaysSlowdown );
int BuildTurnScript( int i, int j );
void BuildTurnScript( const AILocalMoveGoal_t &move );
int BuildInsertNode( int i, float flTime );
Activity GetTransitionActivity( void );
// --------------------------------
// helpers to simplify code
float GetCycle() { return GetOuter()->GetCycle(); }
int AddLayeredSequence( int sequence, int iPriority ) { return GetOuter()->AddLayeredSequence( sequence, iPriority ); }
void SetLayerWeight( int iLayer, float flWeight ) { GetOuter()->SetLayerWeight( iLayer, flWeight ); }
void SetLayerPlaybackRate( int iLayer, float flPlaybackRate ) { GetOuter()->SetLayerPlaybackRate( iLayer, flPlaybackRate ); }
void SetLayerNoRestore( int iLayer, bool bNoRestore ) { GetOuter()->SetLayerNoRestore( iLayer, bNoRestore ); }
void SetLayerCycle( int iLayer, float flCycle ) { GetOuter()->SetLayerCycle( iLayer, flCycle ); }
void SetLayerCycle( int iLayer, float flCycle, float flPrevCycle ) { GetOuter()->SetLayerCycle( iLayer, flCycle, flPrevCycle ); }
void RemoveLayer( int iLayer, float flKillRate, float flKillDelay ) { GetOuter()->RemoveLayer( iLayer, flKillRate, flKillDelay ); }
// --------------------------------
struct AI_Movementscript_t
{
public:
AI_Movementscript_t( )
{
Init( );
};
void Init( void )
{
memset( this, 0, sizeof(*this) );
};
float flTime; // time till next entry
float flElapsedTime; // time since first entry
float flDist; // distance to next entry
float flMaxVelocity;
// float flVelocity;
float flYaw;
float flAngularVelocity;
bool bLooping;
int nFlags;
AI_Waypoint_t *pWaypoint;
public:
AI_Movementscript_t *pNext;
AI_Movementscript_t *pPrev;
Vector vecLocation;
};
//---------------------------------
CUtlVector<AI_Movementscript_t> m_scriptMove;
CUtlVector<AI_Movementscript_t> m_scriptTurn;
//---------------------------------
bool m_bDeceleratingToGoal;
int m_iPrimaryLayer;
int m_iSecondaryLayer;
int m_nPrimarySequence;
int m_nSecondarySequence;
float m_flSecondaryWeight;
Activity m_nSavedGoalActivity;
Activity m_nSavedTranslatedGoalActivity;
int m_nGoalSequence;
int m_nPrevMovementSequence;
int m_nInteriorSequence;
float m_flStartCycle;
float m_flCurrRate;
float m_flPredictiveSpeedAdjust; // predictive speed adjust from probing slope
float m_flReactiveSpeedAdjust; // reactive speed adjust when slope movement detected
Vector m_vecPrevOrigin1;
Vector m_vecPrevOrigin2;
//---------------------------------
float m_flNextTurnGesture; // next time for large turn gesture
//---------------------------------
float m_prevYaw;
float m_doTurn;
float m_doLeft;
float m_doRight;
float m_flNextTurnAct; // next time for small turn gesture
float GetMoveScriptDist( float &flNewSpeed );
float GetMoveScriptYaw( void );
void SetMoveScriptAnim( float flNewSpeed );
int GetInteriorSequence( int fromSequence );
DECLARE_SIMPLE_DATADESC();
};
//-----------------------------------------------------------------------------
// CLASS: CAI_BlendingHost
//
// Purpose: Bridge to the home of fancy human animation transition code
//
//-----------------------------------------------------------------------------
template <class BASE_NPC>
class CAI_BlendingHost : public BASE_NPC
{
DECLARE_CLASS_NOFRIEND( CAI_BlendingHost, BASE_NPC );
public:
const CAI_BlendedMotor *GetBlendedMotor() const { return assert_cast<const CAI_BlendedMotor *>(this->GetMotor()); }
CAI_BlendedMotor * GetBlendedMotor() { return assert_cast<CAI_BlendedMotor *>(this->GetMotor()); }
CAI_Motor *CreateMotor()
{
MEM_ALLOC_CREDIT();
return new CAI_BlendedMotor( this );
}
CAI_Navigator *CreateNavigator()
{
CAI_Navigator *pNavigator = BaseClass::CreateNavigator();
pNavigator->SetValidateActivitySpeed( false );
return pNavigator;
}
float MaxYawSpeed( void )
{
float override = GetBlendedMotor()->OverrideMaxYawSpeed( this->GetActivity() );
if ( override != -1 )
return override;
return BaseClass::MaxYawSpeed();
}
float GetTimeToNavGoal()
{
float result = GetBlendedMotor()->GetMoveScriptTotalTime();
if ( result != -1 )
return result;
return BaseClass::GetTimeToNavGoal();
}
};
//-------------------------------------
// to simplify basic usage:
class CAI_BlendedNPC : public CAI_BlendingHost<CAI_BaseNPC>
{
DECLARE_CLASS( CAI_BlendedNPC, CAI_BlendingHost<CAI_BaseNPC> );
};
//-----------------------------------------------------------------------------
#endif
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#ifndef AI_BLENDED_MOVEMENT_H
#define AI_BLENDED_MOVEMENT_H
#include "ai_basenpc.h"
#include "ai_motor.h"
#include "ai_navigator.h"
struct AI_Waypoint_t;
//-----------------------------------------------------------------------------
// CLASS: CAI_BlendedMotor
//
// Purpose: Home of fancy human animation transition code
//
//-----------------------------------------------------------------------------
class CAI_BlendedMotor : public CAI_Motor
{
typedef CAI_Motor BaseClass;
public:
CAI_BlendedMotor( CAI_BaseNPC *pOuter )
: BaseClass( pOuter )
{
m_iPrimaryLayer = -1;
m_nPrimarySequence = ACT_INVALID;
m_iSecondaryLayer = -1;
m_nSecondarySequence = ACT_INVALID;
m_flSecondaryWeight = 0.0f;
m_nSavedGoalActivity = ACT_INVALID;
m_nSavedTranslatedGoalActivity = ACT_INVALID;
m_nGoalSequence = ACT_INVALID;
m_nPrevMovementSequence = ACT_INVALID;
m_nInteriorSequence = ACT_INVALID;
m_bDeceleratingToGoal = false;
m_flStartCycle = 0.0f;
m_flPredictiveSpeedAdjust = 1.0f;
m_flReactiveSpeedAdjust = 1.0f;
m_vecPrevOrigin1.Init();
m_vecPrevOrigin2.Init();
m_prevYaw = 0.0f;
m_doTurn = 0.0f;
m_doLeft = 0.0f;
m_doRight = 0.0f;
m_flNextTurnAct = 0.0f;
}
void MoveClimbStart( const Vector &climbDest, const Vector &climbDir, float climbDist, float yaw );
void MoveJumpStart( const Vector &velocity );
void ResetMoveCalculations();
void MoveStart();
void ResetGoalSequence();
void MoveStop();
void MovePaused();
void MoveContinue();
float OverrideMaxYawSpeed( Activity activity );
void UpdateYaw( int speed );
void RecalculateYawSpeed();
bool IsDeceleratingToGoal() const { return m_bDeceleratingToGoal; }
float GetMoveScriptTotalTime();
void MaintainTurnActivity( void );
bool AddTurnGesture( float flYD );
private:
AIMotorMoveResult_t MoveGroundExecute( const AILocalMoveGoal_t &move, AIMoveTrace_t *pTraceResult );
AIMotorMoveResult_t MoveFlyExecute( const AILocalMoveGoal_t &move, AIMoveTrace_t *pTraceResult );
// --------------------------------
void BuildMoveScript( const AILocalMoveGoal_t &move, AIMoveTrace_t *pTraceResult );
void BuildVelocityScript( const AILocalMoveGoal_t &move );
void InsertSlowdown( float distToObstruction, float idealAccel, bool bAlwaysSlowdown );
int BuildTurnScript( int i, int j );
void BuildTurnScript( const AILocalMoveGoal_t &move );
int BuildInsertNode( int i, float flTime );
Activity GetTransitionActivity( void );
// --------------------------------
// helpers to simplify code
float GetCycle() { return GetOuter()->GetCycle(); }
int AddLayeredSequence( int sequence, int iPriority ) { return GetOuter()->AddLayeredSequence( sequence, iPriority ); }
void SetLayerWeight( int iLayer, float flWeight ) { GetOuter()->SetLayerWeight( iLayer, flWeight ); }
void SetLayerPlaybackRate( int iLayer, float flPlaybackRate ) { GetOuter()->SetLayerPlaybackRate( iLayer, flPlaybackRate ); }
void SetLayerNoRestore( int iLayer, bool bNoRestore ) { GetOuter()->SetLayerNoRestore( iLayer, bNoRestore ); }
void SetLayerCycle( int iLayer, float flCycle ) { GetOuter()->SetLayerCycle( iLayer, flCycle ); }
void SetLayerCycle( int iLayer, float flCycle, float flPrevCycle ) { GetOuter()->SetLayerCycle( iLayer, flCycle, flPrevCycle ); }
void RemoveLayer( int iLayer, float flKillRate, float flKillDelay ) { GetOuter()->RemoveLayer( iLayer, flKillRate, flKillDelay ); }
// --------------------------------
struct AI_Movementscript_t
{
public:
AI_Movementscript_t( )
{
Init( );
};
void Init( void )
{
memset( this, 0, sizeof(*this) );
};
float flTime; // time till next entry
float flElapsedTime; // time since first entry
float flDist; // distance to next entry
float flMaxVelocity;
// float flVelocity;
float flYaw;
float flAngularVelocity;
bool bLooping;
int nFlags;
AI_Waypoint_t *pWaypoint;
public:
AI_Movementscript_t *pNext;
AI_Movementscript_t *pPrev;
Vector vecLocation;
};
//---------------------------------
CUtlVector<AI_Movementscript_t> m_scriptMove;
CUtlVector<AI_Movementscript_t> m_scriptTurn;
//---------------------------------
bool m_bDeceleratingToGoal;
int m_iPrimaryLayer;
int m_iSecondaryLayer;
int m_nPrimarySequence;
int m_nSecondarySequence;
float m_flSecondaryWeight;
Activity m_nSavedGoalActivity;
Activity m_nSavedTranslatedGoalActivity;
int m_nGoalSequence;
int m_nPrevMovementSequence;
int m_nInteriorSequence;
float m_flStartCycle;
float m_flCurrRate;
float m_flPredictiveSpeedAdjust; // predictive speed adjust from probing slope
float m_flReactiveSpeedAdjust; // reactive speed adjust when slope movement detected
Vector m_vecPrevOrigin1;
Vector m_vecPrevOrigin2;
//---------------------------------
float m_flNextTurnGesture; // next time for large turn gesture
//---------------------------------
float m_prevYaw;
float m_doTurn;
float m_doLeft;
float m_doRight;
float m_flNextTurnAct; // next time for small turn gesture
float GetMoveScriptDist( float &flNewSpeed );
float GetMoveScriptYaw( void );
void SetMoveScriptAnim( float flNewSpeed );
int GetInteriorSequence( int fromSequence );
DECLARE_SIMPLE_DATADESC();
};
//-----------------------------------------------------------------------------
// CLASS: CAI_BlendingHost
//
// Purpose: Bridge to the home of fancy human animation transition code
//
//-----------------------------------------------------------------------------
template <class BASE_NPC>
class CAI_BlendingHost : public BASE_NPC
{
DECLARE_CLASS_NOFRIEND( CAI_BlendingHost, BASE_NPC );
public:
const CAI_BlendedMotor *GetBlendedMotor() const { return assert_cast<const CAI_BlendedMotor *>(this->GetMotor()); }
CAI_BlendedMotor * GetBlendedMotor() { return assert_cast<CAI_BlendedMotor *>(this->GetMotor()); }
CAI_Motor *CreateMotor()
{
MEM_ALLOC_CREDIT();
return new CAI_BlendedMotor( this );
}
CAI_Navigator *CreateNavigator()
{
CAI_Navigator *pNavigator = BaseClass::CreateNavigator();
pNavigator->SetValidateActivitySpeed( false );
return pNavigator;
}
float MaxYawSpeed( void )
{
float override = GetBlendedMotor()->OverrideMaxYawSpeed( this->GetActivity() );
if ( override != -1 )
return override;
return BaseClass::MaxYawSpeed();
}
float GetTimeToNavGoal()
{
float result = GetBlendedMotor()->GetMoveScriptTotalTime();
if ( result != -1 )
return result;
return BaseClass::GetTimeToNavGoal();
}
};
//-------------------------------------
// to simplify basic usage:
class CAI_BlendedNPC : public CAI_BlendingHost<CAI_BaseNPC>
{
DECLARE_CLASS( CAI_BlendedNPC, CAI_BlendingHost<CAI_BaseNPC> );
};
//-----------------------------------------------------------------------------
#endif

View File

@@ -1,171 +1,171 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#ifndef AI_COMPONENT_H
#define AI_COMPONENT_H
#if defined( _WIN32 )
#pragma once
#endif
class CAI_BaseNPC;
class CAI_Enemies;
typedef int AI_TaskFailureCode_t;
struct Task_t;
//-----------------------------------------------------------------------------
// CAI_Component
//
// Purpose: Shared functionality of all classes that assume some of the
// responsibilities of an owner AI.
//-----------------------------------------------------------------------------
class CAI_Component
{
DECLARE_CLASS_NOBASE( CAI_Component );
protected:
CAI_Component( CAI_BaseNPC *pOuter = NULL )
: m_pOuter(pOuter)
{
}
virtual ~CAI_Component() {}
public:
virtual void SetOuter( CAI_BaseNPC *pOuter ) { m_pOuter = pOuter; }
CAI_BaseNPC * GetOuter() { return m_pOuter; }
const CAI_BaseNPC * GetOuter() const { return m_pOuter; }
Hull_t GetHullType() const;
float GetHullWidth() const;
float GetHullHeight() const;
const Vector & GetHullMins() const;
const Vector & GetHullMaxs() const;
protected:
//
// Common services provided by CAI_BaseNPC, Convenience methods to simplify derived code
//
edict_t * GetEdict();
const Vector & GetLocalOrigin() const;
void SetLocalOrigin( const Vector &origin );
const Vector & GetAbsOrigin() const;
const QAngle& GetAbsAngles() const;
void SetLocalAngles( const QAngle& angles );
const QAngle & GetLocalAngles( void ) const;
const Vector& WorldAlignMins() const;
const Vector& WorldAlignMaxs() const;
Vector WorldSpaceCenter() const;
int GetCollisionGroup() const;
void SetSolid( SolidType_t val );
SolidType_t GetSolid() const;
float GetGravity() const;
void SetGravity( float );
CBaseEntity* GetEnemy();
const Vector & GetEnemyLKP() const;
void TranslateNavGoal( CBaseEntity *pEnemy, Vector &chasePosition);
CBaseEntity* GetTarget();
void SetTarget( CBaseEntity *pTarget );
const Task_t* GetCurTask( void );
virtual void TaskFail( AI_TaskFailureCode_t );
void TaskFail( const char *pszGeneralFailText );
virtual void TaskComplete( bool fIgnoreSetFailedCondition = false );
int TaskIsRunning();
inline int TaskIsComplete();
Activity GetActivity();
void SetActivity( Activity NewActivity );
float GetIdealSpeed() const;
float GetIdealAccel() const;
int GetSequence();
int GetEntFlags() const;
void AddEntFlag( int flags );
void RemoveEntFlag( int flagsToRemove );
void ToggleEntFlag( int flagToToggle );
void SetGroundEntity( CBaseEntity *ground );
CBaseEntity* GetGoalEnt();
void SetGoalEnt( CBaseEntity *pGoalEnt );
void Remember( int iMemory );
void Forget( int iMemory );
bool HasMemory( int iMemory );
CAI_Enemies * GetEnemies();
const char * GetEntClassname();
int CapabilitiesGet();
float GetLastThink( const char *szContext = NULL );
public:
#if defined(new)
#error
#endif
void *operator new( size_t nBytes )
{
MEM_ALLOC_CREDIT();
void *pResult = MemAlloc_Alloc( nBytes );
memset( pResult, 0, nBytes );
return pResult;
};
void *operator new( size_t nBytes, int nBlockUse, const char *pFileName, int nLine )
{
MEM_ALLOC_CREDIT();
void *pResult = MemAlloc_Alloc( nBytes, pFileName, nLine );
memset( pResult, 0, nBytes );
return pResult;
}
private:
CAI_BaseNPC *m_pOuter;
};
//-----------------------------------------------------------------------------
template <class NPC_CLASS, class BASE_COMPONENT = CAI_Component>
class CAI_ComponentWithOuter : public BASE_COMPONENT
{
protected:
CAI_ComponentWithOuter(NPC_CLASS *pOuter = NULL)
: BASE_COMPONENT(pOuter)
{
}
public:
// Hides base version
void SetOuter( NPC_CLASS *pOuter ) { BASE_COMPONENT::SetOuter((CAI_BaseNPC *)pOuter); }
NPC_CLASS * GetOuter() { return (NPC_CLASS *)(BASE_COMPONENT::GetOuter()); }
const NPC_CLASS * GetOuter() const { return (NPC_CLASS *)(BASE_COMPONENT::GetOuter()); }
};
//-----------------------------------------------------------------------------
#define DEFINE_AI_COMPONENT_OUTER( NPC_CLASS ) \
void SetOuter( NPC_CLASS *pOuter ) { CAI_Component::SetOuter((CAI_BaseNPC *)pOuter); } \
NPC_CLASS * GetOuter() { return (NPC_CLASS *)(CAI_Component::GetOuter()); } \
const NPC_CLASS * GetOuter() const { return (NPC_CLASS *)(CAI_Component::GetOuter()); }
//-----------------------------------------------------------------------------
#endif // AI_COMPONENT_H
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#ifndef AI_COMPONENT_H
#define AI_COMPONENT_H
#if defined( _WIN32 )
#pragma once
#endif
class CAI_BaseNPC;
class CAI_Enemies;
typedef int AI_TaskFailureCode_t;
struct Task_t;
//-----------------------------------------------------------------------------
// CAI_Component
//
// Purpose: Shared functionality of all classes that assume some of the
// responsibilities of an owner AI.
//-----------------------------------------------------------------------------
class CAI_Component
{
DECLARE_CLASS_NOBASE( CAI_Component );
protected:
CAI_Component( CAI_BaseNPC *pOuter = NULL )
: m_pOuter(pOuter)
{
}
virtual ~CAI_Component() {}
public:
virtual void SetOuter( CAI_BaseNPC *pOuter ) { m_pOuter = pOuter; }
CAI_BaseNPC * GetOuter() { return m_pOuter; }
const CAI_BaseNPC * GetOuter() const { return m_pOuter; }
Hull_t GetHullType() const;
float GetHullWidth() const;
float GetHullHeight() const;
const Vector & GetHullMins() const;
const Vector & GetHullMaxs() const;
protected:
//
// Common services provided by CAI_BaseNPC, Convenience methods to simplify derived code
//
edict_t * GetEdict();
const Vector & GetLocalOrigin() const;
void SetLocalOrigin( const Vector &origin );
const Vector & GetAbsOrigin() const;
const QAngle& GetAbsAngles() const;
void SetLocalAngles( const QAngle& angles );
const QAngle & GetLocalAngles( void ) const;
const Vector& WorldAlignMins() const;
const Vector& WorldAlignMaxs() const;
Vector WorldSpaceCenter() const;
int GetCollisionGroup() const;
void SetSolid( SolidType_t val );
SolidType_t GetSolid() const;
float GetGravity() const;
void SetGravity( float );
CBaseEntity* GetEnemy();
const Vector & GetEnemyLKP() const;
void TranslateNavGoal( CBaseEntity *pEnemy, Vector &chasePosition);
CBaseEntity* GetTarget();
void SetTarget( CBaseEntity *pTarget );
const Task_t* GetCurTask( void );
virtual void TaskFail( AI_TaskFailureCode_t );
void TaskFail( const char *pszGeneralFailText );
virtual void TaskComplete( bool fIgnoreSetFailedCondition = false );
int TaskIsRunning();
inline int TaskIsComplete();
Activity GetActivity();
void SetActivity( Activity NewActivity );
float GetIdealSpeed() const;
float GetIdealAccel() const;
int GetSequence();
int GetEntFlags() const;
void AddEntFlag( int flags );
void RemoveEntFlag( int flagsToRemove );
void ToggleEntFlag( int flagToToggle );
void SetGroundEntity( CBaseEntity *ground );
CBaseEntity* GetGoalEnt();
void SetGoalEnt( CBaseEntity *pGoalEnt );
void Remember( int iMemory );
void Forget( int iMemory );
bool HasMemory( int iMemory );
CAI_Enemies * GetEnemies();
const char * GetEntClassname();
int CapabilitiesGet();
float GetLastThink( const char *szContext = NULL );
public:
#if defined(new)
#error
#endif
void *operator new( size_t nBytes )
{
MEM_ALLOC_CREDIT();
void *pResult = MemAlloc_Alloc( nBytes );
memset( pResult, 0, nBytes );
return pResult;
};
void *operator new( size_t nBytes, int nBlockUse, const char *pFileName, int nLine )
{
MEM_ALLOC_CREDIT();
void *pResult = MemAlloc_Alloc( nBytes, pFileName, nLine );
memset( pResult, 0, nBytes );
return pResult;
}
private:
CAI_BaseNPC *m_pOuter;
};
//-----------------------------------------------------------------------------
template <class NPC_CLASS, class BASE_COMPONENT = CAI_Component>
class CAI_ComponentWithOuter : public BASE_COMPONENT
{
protected:
CAI_ComponentWithOuter(NPC_CLASS *pOuter = NULL)
: BASE_COMPONENT(pOuter)
{
}
public:
// Hides base version
void SetOuter( NPC_CLASS *pOuter ) { BASE_COMPONENT::SetOuter((CAI_BaseNPC *)pOuter); }
NPC_CLASS * GetOuter() { return (NPC_CLASS *)(BASE_COMPONENT::GetOuter()); }
const NPC_CLASS * GetOuter() const { return (NPC_CLASS *)(BASE_COMPONENT::GetOuter()); }
};
//-----------------------------------------------------------------------------
#define DEFINE_AI_COMPONENT_OUTER( NPC_CLASS ) \
void SetOuter( NPC_CLASS *pOuter ) { CAI_Component::SetOuter((CAI_BaseNPC *)pOuter); } \
NPC_CLASS * GetOuter() { return (NPC_CLASS *)(CAI_Component::GetOuter()); } \
const NPC_CLASS * GetOuter() const { return (NPC_CLASS *)(CAI_Component::GetOuter()); }
//-----------------------------------------------------------------------------
#endif // AI_COMPONENT_H

File diff suppressed because it is too large Load Diff

View File

@@ -1,105 +1,105 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#include "cbase.h"
#include "stringregistry.h"
#include "ai_basenpc.h"
#include "ai_condition.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
//-----------------------------------------------------------------------------
// Purpose: Given and condition name, return the condition ID
//-----------------------------------------------------------------------------
int CAI_BaseNPC::GetConditionID(const char* condName)
{
return GetSchedulingSymbols()->ConditionSymbolToId(condName);
}
//-----------------------------------------------------------------------------
// Purpose: Register the default conditions
// Input :
// Output :
//-----------------------------------------------------------------------------
#define ADD_CONDITION_TO_SR( _n ) idSpace.AddCondition( #_n, _n, "CAI_BaseNPC" )
void CAI_BaseNPC::InitDefaultConditionSR(void)
{
CAI_ClassScheduleIdSpace &idSpace = CAI_BaseNPC::AccessClassScheduleIdSpaceDirect();
ADD_CONDITION_TO_SR( COND_NONE );
ADD_CONDITION_TO_SR( COND_IN_PVS );
ADD_CONDITION_TO_SR( COND_IDLE_INTERRUPT );
ADD_CONDITION_TO_SR( COND_LOW_PRIMARY_AMMO );
ADD_CONDITION_TO_SR( COND_NO_PRIMARY_AMMO );
ADD_CONDITION_TO_SR( COND_NO_SECONDARY_AMMO );
ADD_CONDITION_TO_SR( COND_NO_WEAPON );
ADD_CONDITION_TO_SR( COND_SEE_HATE );
ADD_CONDITION_TO_SR( COND_SEE_FEAR );
ADD_CONDITION_TO_SR( COND_SEE_DISLIKE );
ADD_CONDITION_TO_SR( COND_SEE_ENEMY );
ADD_CONDITION_TO_SR( COND_LOST_ENEMY );
ADD_CONDITION_TO_SR( COND_ENEMY_WENT_NULL );
ADD_CONDITION_TO_SR( COND_HAVE_ENEMY_LOS );
ADD_CONDITION_TO_SR( COND_HAVE_TARGET_LOS );
ADD_CONDITION_TO_SR( COND_ENEMY_OCCLUDED );
ADD_CONDITION_TO_SR( COND_TARGET_OCCLUDED );
ADD_CONDITION_TO_SR( COND_ENEMY_TOO_FAR );
ADD_CONDITION_TO_SR( COND_LIGHT_DAMAGE );
ADD_CONDITION_TO_SR( COND_HEAVY_DAMAGE );
ADD_CONDITION_TO_SR( COND_PHYSICS_DAMAGE );
ADD_CONDITION_TO_SR( COND_REPEATED_DAMAGE );
ADD_CONDITION_TO_SR( COND_CAN_RANGE_ATTACK1 );
ADD_CONDITION_TO_SR( COND_CAN_RANGE_ATTACK2 );
ADD_CONDITION_TO_SR( COND_CAN_MELEE_ATTACK1 );
ADD_CONDITION_TO_SR( COND_CAN_MELEE_ATTACK2 );
ADD_CONDITION_TO_SR( COND_PROVOKED );
ADD_CONDITION_TO_SR( COND_NEW_ENEMY );
ADD_CONDITION_TO_SR( COND_ENEMY_FACING_ME );
ADD_CONDITION_TO_SR( COND_BEHIND_ENEMY );
ADD_CONDITION_TO_SR( COND_ENEMY_DEAD );
ADD_CONDITION_TO_SR( COND_ENEMY_UNREACHABLE );
ADD_CONDITION_TO_SR( COND_SEE_PLAYER );
ADD_CONDITION_TO_SR( COND_LOST_PLAYER );
ADD_CONDITION_TO_SR( COND_SEE_NEMESIS );
ADD_CONDITION_TO_SR( COND_TASK_FAILED );
ADD_CONDITION_TO_SR( COND_SCHEDULE_DONE );
ADD_CONDITION_TO_SR( COND_SMELL );
ADD_CONDITION_TO_SR( COND_TOO_CLOSE_TO_ATTACK );
ADD_CONDITION_TO_SR( COND_TOO_FAR_TO_ATTACK );
ADD_CONDITION_TO_SR( COND_NOT_FACING_ATTACK );
ADD_CONDITION_TO_SR( COND_WEAPON_HAS_LOS );
ADD_CONDITION_TO_SR( COND_WEAPON_BLOCKED_BY_FRIEND ); // Friend between gun and target
ADD_CONDITION_TO_SR( COND_WEAPON_PLAYER_IN_SPREAD ); // Player in shooting direction
ADD_CONDITION_TO_SR( COND_WEAPON_PLAYER_NEAR_TARGET ); // Player near shooting position
ADD_CONDITION_TO_SR( COND_WEAPON_SIGHT_OCCLUDED );
ADD_CONDITION_TO_SR( COND_BETTER_WEAPON_AVAILABLE );
ADD_CONDITION_TO_SR( COND_HEALTH_ITEM_AVAILABLE );
ADD_CONDITION_TO_SR( COND_FLOATING_OFF_GROUND );
ADD_CONDITION_TO_SR( COND_MOBBED_BY_ENEMIES );
ADD_CONDITION_TO_SR( COND_GIVE_WAY );
ADD_CONDITION_TO_SR( COND_WAY_CLEAR );
ADD_CONDITION_TO_SR( COND_HEAR_DANGER );
ADD_CONDITION_TO_SR( COND_HEAR_THUMPER );
ADD_CONDITION_TO_SR( COND_HEAR_COMBAT );
ADD_CONDITION_TO_SR( COND_HEAR_WORLD );
ADD_CONDITION_TO_SR( COND_HEAR_PLAYER );
ADD_CONDITION_TO_SR( COND_HEAR_BULLET_IMPACT );
ADD_CONDITION_TO_SR( COND_HEAR_BUGBAIT );
ADD_CONDITION_TO_SR( COND_HEAR_PHYSICS_DANGER );
ADD_CONDITION_TO_SR( COND_HEAR_MOVE_AWAY );
ADD_CONDITION_TO_SR( COND_NO_HEAR_DANGER );
ADD_CONDITION_TO_SR( COND_PLAYER_PUSHING );
ADD_CONDITION_TO_SR( COND_RECEIVED_ORDERS );
ADD_CONDITION_TO_SR( COND_PLAYER_ADDED_TO_SQUAD );
ADD_CONDITION_TO_SR( COND_PLAYER_REMOVED_FROM_SQUAD );
ADD_CONDITION_TO_SR( COND_NPC_FREEZE );
ADD_CONDITION_TO_SR( COND_NPC_UNFREEZE );
ADD_CONDITION_TO_SR( COND_TALKER_RESPOND_TO_QUESTION );
ADD_CONDITION_TO_SR( COND_NO_CUSTOM_INTERRUPTS );
}
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#include "cbase.h"
#include "stringregistry.h"
#include "ai_basenpc.h"
#include "ai_condition.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
//-----------------------------------------------------------------------------
// Purpose: Given and condition name, return the condition ID
//-----------------------------------------------------------------------------
int CAI_BaseNPC::GetConditionID(const char* condName)
{
return GetSchedulingSymbols()->ConditionSymbolToId(condName);
}
//-----------------------------------------------------------------------------
// Purpose: Register the default conditions
// Input :
// Output :
//-----------------------------------------------------------------------------
#define ADD_CONDITION_TO_SR( _n ) idSpace.AddCondition( #_n, _n, "CAI_BaseNPC" )
void CAI_BaseNPC::InitDefaultConditionSR(void)
{
CAI_ClassScheduleIdSpace &idSpace = CAI_BaseNPC::AccessClassScheduleIdSpaceDirect();
ADD_CONDITION_TO_SR( COND_NONE );
ADD_CONDITION_TO_SR( COND_IN_PVS );
ADD_CONDITION_TO_SR( COND_IDLE_INTERRUPT );
ADD_CONDITION_TO_SR( COND_LOW_PRIMARY_AMMO );
ADD_CONDITION_TO_SR( COND_NO_PRIMARY_AMMO );
ADD_CONDITION_TO_SR( COND_NO_SECONDARY_AMMO );
ADD_CONDITION_TO_SR( COND_NO_WEAPON );
ADD_CONDITION_TO_SR( COND_SEE_HATE );
ADD_CONDITION_TO_SR( COND_SEE_FEAR );
ADD_CONDITION_TO_SR( COND_SEE_DISLIKE );
ADD_CONDITION_TO_SR( COND_SEE_ENEMY );
ADD_CONDITION_TO_SR( COND_LOST_ENEMY );
ADD_CONDITION_TO_SR( COND_ENEMY_WENT_NULL );
ADD_CONDITION_TO_SR( COND_HAVE_ENEMY_LOS );
ADD_CONDITION_TO_SR( COND_HAVE_TARGET_LOS );
ADD_CONDITION_TO_SR( COND_ENEMY_OCCLUDED );
ADD_CONDITION_TO_SR( COND_TARGET_OCCLUDED );
ADD_CONDITION_TO_SR( COND_ENEMY_TOO_FAR );
ADD_CONDITION_TO_SR( COND_LIGHT_DAMAGE );
ADD_CONDITION_TO_SR( COND_HEAVY_DAMAGE );
ADD_CONDITION_TO_SR( COND_PHYSICS_DAMAGE );
ADD_CONDITION_TO_SR( COND_REPEATED_DAMAGE );
ADD_CONDITION_TO_SR( COND_CAN_RANGE_ATTACK1 );
ADD_CONDITION_TO_SR( COND_CAN_RANGE_ATTACK2 );
ADD_CONDITION_TO_SR( COND_CAN_MELEE_ATTACK1 );
ADD_CONDITION_TO_SR( COND_CAN_MELEE_ATTACK2 );
ADD_CONDITION_TO_SR( COND_PROVOKED );
ADD_CONDITION_TO_SR( COND_NEW_ENEMY );
ADD_CONDITION_TO_SR( COND_ENEMY_FACING_ME );
ADD_CONDITION_TO_SR( COND_BEHIND_ENEMY );
ADD_CONDITION_TO_SR( COND_ENEMY_DEAD );
ADD_CONDITION_TO_SR( COND_ENEMY_UNREACHABLE );
ADD_CONDITION_TO_SR( COND_SEE_PLAYER );
ADD_CONDITION_TO_SR( COND_LOST_PLAYER );
ADD_CONDITION_TO_SR( COND_SEE_NEMESIS );
ADD_CONDITION_TO_SR( COND_TASK_FAILED );
ADD_CONDITION_TO_SR( COND_SCHEDULE_DONE );
ADD_CONDITION_TO_SR( COND_SMELL );
ADD_CONDITION_TO_SR( COND_TOO_CLOSE_TO_ATTACK );
ADD_CONDITION_TO_SR( COND_TOO_FAR_TO_ATTACK );
ADD_CONDITION_TO_SR( COND_NOT_FACING_ATTACK );
ADD_CONDITION_TO_SR( COND_WEAPON_HAS_LOS );
ADD_CONDITION_TO_SR( COND_WEAPON_BLOCKED_BY_FRIEND ); // Friend between gun and target
ADD_CONDITION_TO_SR( COND_WEAPON_PLAYER_IN_SPREAD ); // Player in shooting direction
ADD_CONDITION_TO_SR( COND_WEAPON_PLAYER_NEAR_TARGET ); // Player near shooting position
ADD_CONDITION_TO_SR( COND_WEAPON_SIGHT_OCCLUDED );
ADD_CONDITION_TO_SR( COND_BETTER_WEAPON_AVAILABLE );
ADD_CONDITION_TO_SR( COND_HEALTH_ITEM_AVAILABLE );
ADD_CONDITION_TO_SR( COND_FLOATING_OFF_GROUND );
ADD_CONDITION_TO_SR( COND_MOBBED_BY_ENEMIES );
ADD_CONDITION_TO_SR( COND_GIVE_WAY );
ADD_CONDITION_TO_SR( COND_WAY_CLEAR );
ADD_CONDITION_TO_SR( COND_HEAR_DANGER );
ADD_CONDITION_TO_SR( COND_HEAR_THUMPER );
ADD_CONDITION_TO_SR( COND_HEAR_COMBAT );
ADD_CONDITION_TO_SR( COND_HEAR_WORLD );
ADD_CONDITION_TO_SR( COND_HEAR_PLAYER );
ADD_CONDITION_TO_SR( COND_HEAR_BULLET_IMPACT );
ADD_CONDITION_TO_SR( COND_HEAR_BUGBAIT );
ADD_CONDITION_TO_SR( COND_HEAR_PHYSICS_DANGER );
ADD_CONDITION_TO_SR( COND_HEAR_MOVE_AWAY );
ADD_CONDITION_TO_SR( COND_NO_HEAR_DANGER );
ADD_CONDITION_TO_SR( COND_PLAYER_PUSHING );
ADD_CONDITION_TO_SR( COND_RECEIVED_ORDERS );
ADD_CONDITION_TO_SR( COND_PLAYER_ADDED_TO_SQUAD );
ADD_CONDITION_TO_SR( COND_PLAYER_REMOVED_FROM_SQUAD );
ADD_CONDITION_TO_SR( COND_NPC_FREEZE );
ADD_CONDITION_TO_SR( COND_NPC_UNFREEZE );
ADD_CONDITION_TO_SR( COND_TALKER_RESPOND_TO_QUESTION );
ADD_CONDITION_TO_SR( COND_NO_CUSTOM_INTERRUPTS );
}

View File

@@ -1,121 +1,121 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: The default shared conditions
//
// $Workfile: $
// $Date: $
//
//-----------------------------------------------------------------------------
// $Log: $
//
// $NoKeywords: $
//=============================================================================//
#ifndef CONDITION_H
#define CONDITION_H
// NOTE: Changing this constant will break save files!!! (changes type of CAI_ScheduleBits)
#ifndef MAX_CONDITIONS
#define MAX_CONDITIONS 32*8
#endif
//=========================================================
// These are the default shared conditions
//=========================================================
enum SCOND_t
{
COND_NONE, // A way for a function to return no condition to get
COND_IN_PVS,
COND_IDLE_INTERRUPT, // The schedule in question is a low priority idle, and therefore a candidate for translation into something else
COND_LOW_PRIMARY_AMMO,
COND_NO_PRIMARY_AMMO,
COND_NO_SECONDARY_AMMO,
COND_NO_WEAPON,
COND_SEE_HATE,
COND_SEE_FEAR,
COND_SEE_DISLIKE,
COND_SEE_ENEMY,
COND_LOST_ENEMY,
COND_ENEMY_WENT_NULL, // What most people think COND_LOST_ENEMY is: This condition is set in the edge case where you had an enemy last think, but don't have one this think.
COND_ENEMY_OCCLUDED, // Can't see m_hEnemy
COND_TARGET_OCCLUDED, // Can't see m_hTargetEnt
COND_HAVE_ENEMY_LOS,
COND_HAVE_TARGET_LOS,
COND_LIGHT_DAMAGE,
COND_HEAVY_DAMAGE,
COND_PHYSICS_DAMAGE,
COND_REPEATED_DAMAGE, // Damaged several times in a row
COND_CAN_RANGE_ATTACK1, // Hitscan weapon only
COND_CAN_RANGE_ATTACK2, // Grenade weapon only
COND_CAN_MELEE_ATTACK1,
COND_CAN_MELEE_ATTACK2,
COND_PROVOKED,
COND_NEW_ENEMY,
COND_ENEMY_TOO_FAR, // Can we get rid of this one!?!?
COND_ENEMY_FACING_ME,
COND_BEHIND_ENEMY,
COND_ENEMY_DEAD,
COND_ENEMY_UNREACHABLE, // Not connected to me via node graph
COND_SEE_PLAYER,
COND_LOST_PLAYER,
COND_SEE_NEMESIS,
COND_TASK_FAILED,
COND_SCHEDULE_DONE,
COND_SMELL,
COND_TOO_CLOSE_TO_ATTACK, // FIXME: most of this next group are meaningless since they're shared between all attack checks!
COND_TOO_FAR_TO_ATTACK,
COND_NOT_FACING_ATTACK,
COND_WEAPON_HAS_LOS,
COND_WEAPON_BLOCKED_BY_FRIEND, // Friend between weapon and target
COND_WEAPON_PLAYER_IN_SPREAD, // Player in shooting direction
COND_WEAPON_PLAYER_NEAR_TARGET, // Player near shooting position
COND_WEAPON_SIGHT_OCCLUDED,
COND_BETTER_WEAPON_AVAILABLE,
COND_HEALTH_ITEM_AVAILABLE, // There's a healthkit available.
COND_GIVE_WAY, // Another npc requested that I give way
COND_WAY_CLEAR, // I no longer have to give way
COND_HEAR_DANGER,
COND_HEAR_THUMPER,
COND_HEAR_BUGBAIT,
COND_HEAR_COMBAT,
COND_HEAR_WORLD,
COND_HEAR_PLAYER,
COND_HEAR_BULLET_IMPACT,
COND_HEAR_PHYSICS_DANGER,
COND_HEAR_MOVE_AWAY,
COND_HEAR_SPOOKY, // Zombies make this when Alyx is in darkness mode
COND_NO_HEAR_DANGER, // Since we can't use ~CONDITION. Mutually exclusive with COND_HEAR_DANGER
COND_FLOATING_OFF_GROUND,
COND_MOBBED_BY_ENEMIES, // Surrounded by a large number of enemies melee attacking me. (Zombies or Antlions, usually).
// Commander stuff
COND_RECEIVED_ORDERS,
COND_PLAYER_ADDED_TO_SQUAD,
COND_PLAYER_REMOVED_FROM_SQUAD,
COND_PLAYER_PUSHING,
COND_NPC_FREEZE, // We received an npc_freeze command while we were unfrozen
COND_NPC_UNFREEZE, // We received an npc_freeze command while we were frozen
// This is a talker condition, but done here because we need to handle it in base AI
// due to it's interaction with behaviors.
COND_TALKER_RESPOND_TO_QUESTION,
COND_NO_CUSTOM_INTERRUPTS, // Don't call BuildScheduleTestBits for this schedule. Used for schedules that must strictly control their interruptibility.
// ======================================
// IMPORTANT: This must be the last enum
// ======================================
LAST_SHARED_CONDITION
};
#endif //CONDITION_H
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: The default shared conditions
//
// $Workfile: $
// $Date: $
//
//-----------------------------------------------------------------------------
// $Log: $
//
// $NoKeywords: $
//=============================================================================//
#ifndef CONDITION_H
#define CONDITION_H
// NOTE: Changing this constant will break save files!!! (changes type of CAI_ScheduleBits)
#ifndef MAX_CONDITIONS
#define MAX_CONDITIONS 32*8
#endif
//=========================================================
// These are the default shared conditions
//=========================================================
enum SCOND_t
{
COND_NONE, // A way for a function to return no condition to get
COND_IN_PVS,
COND_IDLE_INTERRUPT, // The schedule in question is a low priority idle, and therefore a candidate for translation into something else
COND_LOW_PRIMARY_AMMO,
COND_NO_PRIMARY_AMMO,
COND_NO_SECONDARY_AMMO,
COND_NO_WEAPON,
COND_SEE_HATE,
COND_SEE_FEAR,
COND_SEE_DISLIKE,
COND_SEE_ENEMY,
COND_LOST_ENEMY,
COND_ENEMY_WENT_NULL, // What most people think COND_LOST_ENEMY is: This condition is set in the edge case where you had an enemy last think, but don't have one this think.
COND_ENEMY_OCCLUDED, // Can't see m_hEnemy
COND_TARGET_OCCLUDED, // Can't see m_hTargetEnt
COND_HAVE_ENEMY_LOS,
COND_HAVE_TARGET_LOS,
COND_LIGHT_DAMAGE,
COND_HEAVY_DAMAGE,
COND_PHYSICS_DAMAGE,
COND_REPEATED_DAMAGE, // Damaged several times in a row
COND_CAN_RANGE_ATTACK1, // Hitscan weapon only
COND_CAN_RANGE_ATTACK2, // Grenade weapon only
COND_CAN_MELEE_ATTACK1,
COND_CAN_MELEE_ATTACK2,
COND_PROVOKED,
COND_NEW_ENEMY,
COND_ENEMY_TOO_FAR, // Can we get rid of this one!?!?
COND_ENEMY_FACING_ME,
COND_BEHIND_ENEMY,
COND_ENEMY_DEAD,
COND_ENEMY_UNREACHABLE, // Not connected to me via node graph
COND_SEE_PLAYER,
COND_LOST_PLAYER,
COND_SEE_NEMESIS,
COND_TASK_FAILED,
COND_SCHEDULE_DONE,
COND_SMELL,
COND_TOO_CLOSE_TO_ATTACK, // FIXME: most of this next group are meaningless since they're shared between all attack checks!
COND_TOO_FAR_TO_ATTACK,
COND_NOT_FACING_ATTACK,
COND_WEAPON_HAS_LOS,
COND_WEAPON_BLOCKED_BY_FRIEND, // Friend between weapon and target
COND_WEAPON_PLAYER_IN_SPREAD, // Player in shooting direction
COND_WEAPON_PLAYER_NEAR_TARGET, // Player near shooting position
COND_WEAPON_SIGHT_OCCLUDED,
COND_BETTER_WEAPON_AVAILABLE,
COND_HEALTH_ITEM_AVAILABLE, // There's a healthkit available.
COND_GIVE_WAY, // Another npc requested that I give way
COND_WAY_CLEAR, // I no longer have to give way
COND_HEAR_DANGER,
COND_HEAR_THUMPER,
COND_HEAR_BUGBAIT,
COND_HEAR_COMBAT,
COND_HEAR_WORLD,
COND_HEAR_PLAYER,
COND_HEAR_BULLET_IMPACT,
COND_HEAR_PHYSICS_DANGER,
COND_HEAR_MOVE_AWAY,
COND_HEAR_SPOOKY, // Zombies make this when Alyx is in darkness mode
COND_NO_HEAR_DANGER, // Since we can't use ~CONDITION. Mutually exclusive with COND_HEAR_DANGER
COND_FLOATING_OFF_GROUND,
COND_MOBBED_BY_ENEMIES, // Surrounded by a large number of enemies melee attacking me. (Zombies or Antlions, usually).
// Commander stuff
COND_RECEIVED_ORDERS,
COND_PLAYER_ADDED_TO_SQUAD,
COND_PLAYER_REMOVED_FROM_SQUAD,
COND_PLAYER_PUSHING,
COND_NPC_FREEZE, // We received an npc_freeze command while we were unfrozen
COND_NPC_UNFREEZE, // We received an npc_freeze command while we were frozen
// This is a talker condition, but done here because we need to handle it in base AI
// due to it's interaction with behaviors.
COND_TALKER_RESPOND_TO_QUESTION,
COND_NO_CUSTOM_INTERRUPTS, // Don't call BuildScheduleTestBits for this schedule. Used for schedules that must strictly control their interruptibility.
// ======================================
// IMPORTANT: This must be the last enum
// ======================================
LAST_SHARED_CONDITION
};
#endif //CONDITION_H

View File

@@ -1,88 +1,88 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#ifndef AI_DEBUG_H
#define AI_DEBUG_H
#include "fmtstr.h"
#include "ai_debug_shared.h"
#if defined( _WIN32 )
#pragma once
#endif
// This dumps a summary result on exit
//#define PROFILE_AI 1
#define AI_PROFILE_SCOPE_BEGIN( tag ) if (0) ; else { AI_PROFILE_SCOPE( tag )
#define AI_PROFILE_SCOPE_BEGIN_( pszName ) if (0) ; else { AI_PROFILE_SCOPE_( pszName )
#define AI_PROFILE_SCOPE_END() } do {} while (0)
#if defined(VPROF_AI)
#define VProfAI() true
#else
#define VProfAI() false
#endif
#if defined(VPROF_AI)
#include "tier0/vprof.h"
#define AI_PROFILE_SCOPE( tag ) VPROF( #tag )
#define AI_PROFILE_SCOPE_( pszName ) VPROF( pszName )
#define AI_PROFILE_MEASURE_SCOPE( tag ) VPROF( #tag )
#elif defined(PROFILE_AI)
#include "tier0/fasttimer.h"
#define AI_PROFILE_SCOPE( tag ) PROFILE_SCOPE( tag )
#define AI_PROFILE_MEASURE_SCOPE( tag ) PROFILE_SCOPE( tag )
#else
#define AI_PROFILE_MEASURE_SCOPE( tag ) ((void)0)
#define AI_PROFILE_SCOPE( tag ) ((void)0)
#endif
#ifndef AI_PROFILE_SCOPE_
#define AI_PROFILE_SCOPE_( pszName ) ((void)0)
#endif
enum AIMsgFlags
{
AIMF_IGNORE_SELECTED = 0x01
};
void DevMsg( CAI_BaseNPC *pAI, unsigned flags, PRINTF_FORMAT_STRING const char *pszFormat, ... );
void DevMsg( CAI_BaseNPC *pAI, PRINTF_FORMAT_STRING const char *pszFormat, ... );
//-----------------------------------------------------------------------------
// Purpose: Use this to perform AI tracelines that are trying to determine LOS between points.
// LOS checks between entities should use FVisible.
//-----------------------------------------------------------------------------
void AI_TraceLOS( const Vector& vecAbsStart, const Vector& vecAbsEnd, CBaseEntity *pLooker, trace_t *ptr, ITraceFilter *pFilter = NULL );
//-----------------------------------------------------------------------------
#ifdef DEBUG
extern bool g_fTestSteering;
#define TestingSteering() g_fTestSteering
#else
#define TestingSteering() false
#endif
//-----------------------------------------------------------------------------
#ifdef _DEBUG
extern ConVar ai_debug_doors;
#define AIIsDebuggingDoors( pNPC ) ( ai_debug_doors.GetBool() && pNPC->m_bSelected )
#define AIDoorDebugMsg( pNPC, msg ) if ( !AIIsDebuggingDoors( pNPC ) ) ; else Msg( msg )
#else
#define AIIsDebuggingDoors( pNPC ) (false)
#define AIDoorDebugMsg( pNPC, msg ) ((void)(0))
#endif
//-----------------------------------------------------------------------------
#endif // AI_DEBUG_H
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#ifndef AI_DEBUG_H
#define AI_DEBUG_H
#include "fmtstr.h"
#include "ai_debug_shared.h"
#if defined( _WIN32 )
#pragma once
#endif
// This dumps a summary result on exit
//#define PROFILE_AI 1
#define AI_PROFILE_SCOPE_BEGIN( tag ) if (0) ; else { AI_PROFILE_SCOPE( tag )
#define AI_PROFILE_SCOPE_BEGIN_( pszName ) if (0) ; else { AI_PROFILE_SCOPE_( pszName )
#define AI_PROFILE_SCOPE_END() } do {} while (0)
#if defined(VPROF_AI)
#define VProfAI() true
#else
#define VProfAI() false
#endif
#if defined(VPROF_AI)
#include "tier0/vprof.h"
#define AI_PROFILE_SCOPE( tag ) VPROF( #tag )
#define AI_PROFILE_SCOPE_( pszName ) VPROF( pszName )
#define AI_PROFILE_MEASURE_SCOPE( tag ) VPROF( #tag )
#elif defined(PROFILE_AI)
#include "tier0/fasttimer.h"
#define AI_PROFILE_SCOPE( tag ) PROFILE_SCOPE( tag )
#define AI_PROFILE_MEASURE_SCOPE( tag ) PROFILE_SCOPE( tag )
#else
#define AI_PROFILE_MEASURE_SCOPE( tag ) ((void)0)
#define AI_PROFILE_SCOPE( tag ) ((void)0)
#endif
#ifndef AI_PROFILE_SCOPE_
#define AI_PROFILE_SCOPE_( pszName ) ((void)0)
#endif
enum AIMsgFlags
{
AIMF_IGNORE_SELECTED = 0x01
};
void DevMsg( CAI_BaseNPC *pAI, unsigned flags, PRINTF_FORMAT_STRING const char *pszFormat, ... );
void DevMsg( CAI_BaseNPC *pAI, PRINTF_FORMAT_STRING const char *pszFormat, ... );
//-----------------------------------------------------------------------------
// Purpose: Use this to perform AI tracelines that are trying to determine LOS between points.
// LOS checks between entities should use FVisible.
//-----------------------------------------------------------------------------
void AI_TraceLOS( const Vector& vecAbsStart, const Vector& vecAbsEnd, CBaseEntity *pLooker, trace_t *ptr, ITraceFilter *pFilter = NULL );
//-----------------------------------------------------------------------------
#ifdef DEBUG
extern bool g_fTestSteering;
#define TestingSteering() g_fTestSteering
#else
#define TestingSteering() false
#endif
//-----------------------------------------------------------------------------
#ifdef _DEBUG
extern ConVar ai_debug_doors;
#define AIIsDebuggingDoors( pNPC ) ( ai_debug_doors.GetBool() && pNPC->m_bSelected )
#define AIDoorDebugMsg( pNPC, msg ) if ( !AIIsDebuggingDoors( pNPC ) ) ; else Msg( msg )
#else
#define AIIsDebuggingDoors( pNPC ) (false)
#define AIDoorDebugMsg( pNPC, msg ) ((void)(0))
#endif
//-----------------------------------------------------------------------------
#endif // AI_DEBUG_H

File diff suppressed because it is too large Load Diff

View File

@@ -1,121 +1,121 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Default schedules.
//
//=============================================================================//
#ifndef AI_DEFAULT_H
#define AI_DEFAULT_H
#ifdef _WIN32
#pragma once
#endif
//=========================================================
// These are the schedule types
//=========================================================
enum
{
SCHED_NONE = 0,
SCHED_IDLE_STAND,
SCHED_IDLE_WALK,
SCHED_IDLE_WANDER,
SCHED_WAKE_ANGRY,
SCHED_ALERT_FACE,
SCHED_ALERT_FACE_BESTSOUND,
SCHED_ALERT_REACT_TO_COMBAT_SOUND,
SCHED_ALERT_SCAN,
SCHED_ALERT_STAND,
SCHED_ALERT_WALK,
SCHED_INVESTIGATE_SOUND,
SCHED_COMBAT_FACE,
SCHED_COMBAT_SWEEP,
SCHED_FEAR_FACE,
SCHED_COMBAT_STAND,
SCHED_COMBAT_WALK,
SCHED_CHASE_ENEMY,
SCHED_CHASE_ENEMY_FAILED,
SCHED_VICTORY_DANCE,
SCHED_TARGET_FACE,
SCHED_TARGET_CHASE,
SCHED_SMALL_FLINCH,
SCHED_BIG_FLINCH,
SCHED_BACK_AWAY_FROM_ENEMY,
SCHED_MOVE_AWAY_FROM_ENEMY,
SCHED_BACK_AWAY_FROM_SAVE_POSITION,
SCHED_TAKE_COVER_FROM_ENEMY,
SCHED_TAKE_COVER_FROM_BEST_SOUND,
SCHED_FLEE_FROM_BEST_SOUND,
SCHED_TAKE_COVER_FROM_ORIGIN,
SCHED_FAIL_TAKE_COVER,
SCHED_RUN_FROM_ENEMY,
SCHED_RUN_FROM_ENEMY_FALLBACK,
SCHED_MOVE_TO_WEAPON_RANGE,
SCHED_ESTABLISH_LINE_OF_FIRE,
SCHED_ESTABLISH_LINE_OF_FIRE_FALLBACK,
SCHED_PRE_FAIL_ESTABLISH_LINE_OF_FIRE,
SCHED_FAIL_ESTABLISH_LINE_OF_FIRE,
SCHED_SHOOT_ENEMY_COVER,
SCHED_COWER, // usually a last resort!
SCHED_MELEE_ATTACK1,
SCHED_MELEE_ATTACK2,
SCHED_RANGE_ATTACK1,
SCHED_RANGE_ATTACK2,
SCHED_SPECIAL_ATTACK1,
SCHED_SPECIAL_ATTACK2,
SCHED_STANDOFF,
SCHED_ARM_WEAPON,
SCHED_DISARM_WEAPON,
SCHED_HIDE_AND_RELOAD,
SCHED_RELOAD,
SCHED_AMBUSH,
SCHED_DIE,
SCHED_DIE_RAGDOLL,
SCHED_WAIT_FOR_SCRIPT,
SCHED_AISCRIPT,
SCHED_SCRIPTED_WALK,
SCHED_SCRIPTED_RUN,
SCHED_SCRIPTED_CUSTOM_MOVE,
SCHED_SCRIPTED_WAIT,
SCHED_SCRIPTED_FACE,
SCHED_SCENE_GENERIC,
SCHED_NEW_WEAPON,
SCHED_NEW_WEAPON_CHEAT,
SCHED_SWITCH_TO_PENDING_WEAPON,
SCHED_GET_HEALTHKIT,
SCHED_WAIT_FOR_SPEAK_FINISH,
SCHED_MOVE_AWAY,
SCHED_MOVE_AWAY_FAIL,
SCHED_MOVE_AWAY_END,
SCHED_FORCED_GO,
SCHED_FORCED_GO_RUN,
SCHED_NPC_FREEZE,
SCHED_PATROL_WALK,
SCHED_COMBAT_PATROL,
SCHED_PATROL_RUN,
SCHED_RUN_RANDOM,
SCHED_FALL_TO_GROUND,
SCHED_DROPSHIP_DUSTOFF,
SCHED_FLINCH_PHYSICS,
SCHED_FAIL,
SCHED_FAIL_NOSTOP,
SCHED_RUN_FROM_ENEMY_MOB,
SCHED_DUCK_DODGE,
SCHED_INTERACTION_MOVE_TO_PARTNER,
SCHED_INTERACTION_WAIT_FOR_PARTNER,
SCHED_SLEEP,
// ======================================
// IMPORTANT: This must be the last enum
// ======================================
LAST_SHARED_SCHEDULE
};
#endif // AI_DEFAULT_H
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Default schedules.
//
//=============================================================================//
#ifndef AI_DEFAULT_H
#define AI_DEFAULT_H
#ifdef _WIN32
#pragma once
#endif
//=========================================================
// These are the schedule types
//=========================================================
enum
{
SCHED_NONE = 0,
SCHED_IDLE_STAND,
SCHED_IDLE_WALK,
SCHED_IDLE_WANDER,
SCHED_WAKE_ANGRY,
SCHED_ALERT_FACE,
SCHED_ALERT_FACE_BESTSOUND,
SCHED_ALERT_REACT_TO_COMBAT_SOUND,
SCHED_ALERT_SCAN,
SCHED_ALERT_STAND,
SCHED_ALERT_WALK,
SCHED_INVESTIGATE_SOUND,
SCHED_COMBAT_FACE,
SCHED_COMBAT_SWEEP,
SCHED_FEAR_FACE,
SCHED_COMBAT_STAND,
SCHED_COMBAT_WALK,
SCHED_CHASE_ENEMY,
SCHED_CHASE_ENEMY_FAILED,
SCHED_VICTORY_DANCE,
SCHED_TARGET_FACE,
SCHED_TARGET_CHASE,
SCHED_SMALL_FLINCH,
SCHED_BIG_FLINCH,
SCHED_BACK_AWAY_FROM_ENEMY,
SCHED_MOVE_AWAY_FROM_ENEMY,
SCHED_BACK_AWAY_FROM_SAVE_POSITION,
SCHED_TAKE_COVER_FROM_ENEMY,
SCHED_TAKE_COVER_FROM_BEST_SOUND,
SCHED_FLEE_FROM_BEST_SOUND,
SCHED_TAKE_COVER_FROM_ORIGIN,
SCHED_FAIL_TAKE_COVER,
SCHED_RUN_FROM_ENEMY,
SCHED_RUN_FROM_ENEMY_FALLBACK,
SCHED_MOVE_TO_WEAPON_RANGE,
SCHED_ESTABLISH_LINE_OF_FIRE,
SCHED_ESTABLISH_LINE_OF_FIRE_FALLBACK,
SCHED_PRE_FAIL_ESTABLISH_LINE_OF_FIRE,
SCHED_FAIL_ESTABLISH_LINE_OF_FIRE,
SCHED_SHOOT_ENEMY_COVER,
SCHED_COWER, // usually a last resort!
SCHED_MELEE_ATTACK1,
SCHED_MELEE_ATTACK2,
SCHED_RANGE_ATTACK1,
SCHED_RANGE_ATTACK2,
SCHED_SPECIAL_ATTACK1,
SCHED_SPECIAL_ATTACK2,
SCHED_STANDOFF,
SCHED_ARM_WEAPON,
SCHED_DISARM_WEAPON,
SCHED_HIDE_AND_RELOAD,
SCHED_RELOAD,
SCHED_AMBUSH,
SCHED_DIE,
SCHED_DIE_RAGDOLL,
SCHED_WAIT_FOR_SCRIPT,
SCHED_AISCRIPT,
SCHED_SCRIPTED_WALK,
SCHED_SCRIPTED_RUN,
SCHED_SCRIPTED_CUSTOM_MOVE,
SCHED_SCRIPTED_WAIT,
SCHED_SCRIPTED_FACE,
SCHED_SCENE_GENERIC,
SCHED_NEW_WEAPON,
SCHED_NEW_WEAPON_CHEAT,
SCHED_SWITCH_TO_PENDING_WEAPON,
SCHED_GET_HEALTHKIT,
SCHED_WAIT_FOR_SPEAK_FINISH,
SCHED_MOVE_AWAY,
SCHED_MOVE_AWAY_FAIL,
SCHED_MOVE_AWAY_END,
SCHED_FORCED_GO,
SCHED_FORCED_GO_RUN,
SCHED_NPC_FREEZE,
SCHED_PATROL_WALK,
SCHED_COMBAT_PATROL,
SCHED_PATROL_RUN,
SCHED_RUN_RANDOM,
SCHED_FALL_TO_GROUND,
SCHED_DROPSHIP_DUSTOFF,
SCHED_FLINCH_PHYSICS,
SCHED_FAIL,
SCHED_FAIL_NOSTOP,
SCHED_RUN_FROM_ENEMY_MOB,
SCHED_DUCK_DODGE,
SCHED_INTERACTION_MOVE_TO_PARTNER,
SCHED_INTERACTION_WAIT_FOR_PARTNER,
SCHED_SLEEP,
// ======================================
// IMPORTANT: This must be the last enum
// ======================================
LAST_SHARED_SCHEDULE
};
#endif // AI_DEFAULT_H

File diff suppressed because it is too large Load Diff

View File

@@ -1,125 +1,125 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: A link that can be turned on and off. Unlike normal links
// dyanimc links must be entities so they and receive messages.
// They update the state of the actual links. Allows us to save
// a lot of memory by not making all links into entities
//
// $Workfile: $
// $Date: $
//
//-----------------------------------------------------------------------------
// $Log: $
//
// $NoKeywords: $
//=============================================================================//
#ifndef AI_DYNAMICLINK_H
#define AI_DYNAMICLINK_H
#pragma once
enum DynamicLinkState_t
{
LINK_OFF = 0,
LINK_ON = 1,
};
class CAI_Link;
//=============================================================================
// >> CAI_DynanicLink
//=============================================================================
class CAI_DynamicLink : public CServerOnlyEntity
{
DECLARE_CLASS( CAI_DynamicLink, CServerOnlyEntity );
public:
static void InitDynamicLinks(void);
static void ResetDynamicLinks(void);
static void PurgeDynamicLinks(void);
static void GenerateControllerLinks();
static bool gm_bInitialized;
static CAI_DynamicLink* GetDynamicLink(int nSrcID, int nDstID);
static CAI_DynamicLink* m_pAllDynamicLinks; // A linked list of all dynamic link
CAI_DynamicLink* m_pNextDynamicLink; // The next dynamic link in the list of dynamic links
int m_nSrcEditID; // the node that 'owns' this link
int m_nDestEditID; // the node on the other end of the link.
int m_nSrcID; // the node that 'owns' this link
int m_nDestID; // the node on the other end of the link.
DynamicLinkState_t m_nLinkState; //
string_t m_strAllowUse; // Only this entity name or classname may use the link
bool m_bInvertAllow; // Instead of only allowing the m_strAllowUse entity, exclude only it
bool m_bFixedUpIds;
bool m_bNotSaved;
int m_nLinkType;
void SetLinkState( void );
bool IsLinkValid( void );
CAI_Link * FindLink();
int ObjectCaps();
// ----------------
// Inputs
// ----------------
void InputTurnOn( inputdata_t &inputdata );
void InputTurnOff( inputdata_t &inputdata );
DECLARE_DATADESC();
CAI_DynamicLink();
~CAI_DynamicLink();
};
//=============================================================================
// >> CAI_DynanicLinkVolume
//=============================================================================
class CAI_DynamicLinkController : public CServerOnlyEntity
{
DECLARE_CLASS( CAI_DynamicLinkController, CServerOnlyEntity );
public:
void GenerateLinksFromVolume();
// ----------------
// Inputs
// ----------------
void InputTurnOn( inputdata_t &inputdata );
void InputTurnOff( inputdata_t &inputdata );
void InputSetAllowed( inputdata_t &inputdata );
void InputSetInvert( inputdata_t &inputdata );
CUtlVector< CHandle<CAI_DynamicLink> > m_ControlledLinks;
DynamicLinkState_t m_nLinkState;
string_t m_strAllowUse; // Only this entity name or classname may use the link
bool m_bInvertAllow; // Instead of only allowing the m_strAllowUse entity, exclude only it
bool m_bUseAirLinkRadius;
DECLARE_DATADESC();
};
//=============================================================================
//=============================================================================
class CAI_RadialLinkController : public CBaseEntity
{
DECLARE_CLASS( CAI_RadialLinkController, CBaseEntity );
public:
void Spawn();
void Activate();
void PollMotionThink();
void ModifyNodeLinks( bool bMakeStale );
public:
float m_flRadius;
Vector m_vecAtRestOrigin;
bool m_bAtRest;
DECLARE_DATADESC();
};
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: A link that can be turned on and off. Unlike normal links
// dyanimc links must be entities so they and receive messages.
// They update the state of the actual links. Allows us to save
// a lot of memory by not making all links into entities
//
// $Workfile: $
// $Date: $
//
//-----------------------------------------------------------------------------
// $Log: $
//
// $NoKeywords: $
//=============================================================================//
#ifndef AI_DYNAMICLINK_H
#define AI_DYNAMICLINK_H
#pragma once
enum DynamicLinkState_t
{
LINK_OFF = 0,
LINK_ON = 1,
};
class CAI_Link;
//=============================================================================
// >> CAI_DynanicLink
//=============================================================================
class CAI_DynamicLink : public CServerOnlyEntity
{
DECLARE_CLASS( CAI_DynamicLink, CServerOnlyEntity );
public:
static void InitDynamicLinks(void);
static void ResetDynamicLinks(void);
static void PurgeDynamicLinks(void);
static void GenerateControllerLinks();
static bool gm_bInitialized;
static CAI_DynamicLink* GetDynamicLink(int nSrcID, int nDstID);
static CAI_DynamicLink* m_pAllDynamicLinks; // A linked list of all dynamic link
CAI_DynamicLink* m_pNextDynamicLink; // The next dynamic link in the list of dynamic links
int m_nSrcEditID; // the node that 'owns' this link
int m_nDestEditID; // the node on the other end of the link.
int m_nSrcID; // the node that 'owns' this link
int m_nDestID; // the node on the other end of the link.
DynamicLinkState_t m_nLinkState; //
string_t m_strAllowUse; // Only this entity name or classname may use the link
bool m_bInvertAllow; // Instead of only allowing the m_strAllowUse entity, exclude only it
bool m_bFixedUpIds;
bool m_bNotSaved;
int m_nLinkType;
void SetLinkState( void );
bool IsLinkValid( void );
CAI_Link * FindLink();
int ObjectCaps();
// ----------------
// Inputs
// ----------------
void InputTurnOn( inputdata_t &inputdata );
void InputTurnOff( inputdata_t &inputdata );
DECLARE_DATADESC();
CAI_DynamicLink();
~CAI_DynamicLink();
};
//=============================================================================
// >> CAI_DynanicLinkVolume
//=============================================================================
class CAI_DynamicLinkController : public CServerOnlyEntity
{
DECLARE_CLASS( CAI_DynamicLinkController, CServerOnlyEntity );
public:
void GenerateLinksFromVolume();
// ----------------
// Inputs
// ----------------
void InputTurnOn( inputdata_t &inputdata );
void InputTurnOff( inputdata_t &inputdata );
void InputSetAllowed( inputdata_t &inputdata );
void InputSetInvert( inputdata_t &inputdata );
CUtlVector< CHandle<CAI_DynamicLink> > m_ControlledLinks;
DynamicLinkState_t m_nLinkState;
string_t m_strAllowUse; // Only this entity name or classname may use the link
bool m_bInvertAllow; // Instead of only allowing the m_strAllowUse entity, exclude only it
bool m_bUseAirLinkRadius;
DECLARE_DATADESC();
};
//=============================================================================
//=============================================================================
class CAI_RadialLinkController : public CBaseEntity
{
DECLARE_CLASS( CAI_RadialLinkController, CBaseEntity );
public:
void Spawn();
void Activate();
void PollMotionThink();
void ModifyNodeLinks( bool bMakeStale );
public:
float m_flRadius;
Vector m_vecAtRestOrigin;
bool m_bAtRest;
DECLARE_DATADESC();
};
#endif // AI_DYNAMICLINK_H

View File

@@ -1,50 +1,50 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Events that are available to all NPCs.
//
//=============================================================================//
#include "cbase.h"
#include "ai_basenpc.h"
#include "eventlist.h"
#include "stringregistry.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
//=============================================================================
// Init static variables
//=============================================================================
CStringRegistry* CAI_BaseNPC::m_pEventSR = NULL;
int CAI_BaseNPC::m_iNumEvents = 0;
//-----------------------------------------------------------------------------
// Purpose: Add an activity to the activity string registry and increment
// the acitivty counter
//-----------------------------------------------------------------------------
void CAI_BaseNPC::AddEventToSR(const char *eventName, int eventID)
{
MEM_ALLOC_CREDIT();
Assert( m_pEventSR );
m_pEventSR->AddString( eventName, eventID );
m_iNumEvents++;
}
//-----------------------------------------------------------------------------
// Purpose: Given and activity ID, return the activity name
//-----------------------------------------------------------------------------
const char *CAI_BaseNPC::GetEventName(int eventID)
{
const char *name = m_pEventSR->GetStringText( eventID );
return name;
}
//-----------------------------------------------------------------------------
// Purpose: Given and activity name, return the activity ID
//-----------------------------------------------------------------------------
int CAI_BaseNPC::GetEventID(const char* eventName)
{
return m_pEventSR->GetStringID( eventName );
}
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Events that are available to all NPCs.
//
//=============================================================================//
#include "cbase.h"
#include "ai_basenpc.h"
#include "eventlist.h"
#include "stringregistry.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
//=============================================================================
// Init static variables
//=============================================================================
CStringRegistry* CAI_BaseNPC::m_pEventSR = NULL;
int CAI_BaseNPC::m_iNumEvents = 0;
//-----------------------------------------------------------------------------
// Purpose: Add an activity to the activity string registry and increment
// the acitivty counter
//-----------------------------------------------------------------------------
void CAI_BaseNPC::AddEventToSR(const char *eventName, int eventID)
{
MEM_ALLOC_CREDIT();
Assert( m_pEventSR );
m_pEventSR->AddString( eventName, eventID );
m_iNumEvents++;
}
//-----------------------------------------------------------------------------
// Purpose: Given and activity ID, return the activity name
//-----------------------------------------------------------------------------
const char *CAI_BaseNPC::GetEventName(int eventID)
{
const char *name = m_pEventSR->GetStringText( eventID );
return name;
}
//-----------------------------------------------------------------------------
// Purpose: Given and activity name, return the activity ID
//-----------------------------------------------------------------------------
int CAI_BaseNPC::GetEventID(const char* eventName)
{
return m_pEventSR->GetStringID( eventName );
}

View File

@@ -1,215 +1,215 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: AI system that makes NPCs verbally respond to game events
//
//=============================================================================
#include "cbase.h"
#include "ai_eventresponse.h"
#include "ai_basenpc.h"
ConVar ai_debug_eventresponses( "ai_debug_eventresponses", "0", FCVAR_NONE, "Set to 1 to see all NPC response events trigger, and which NPCs choose to respond to them." );
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
CNPCEventResponseSystem g_NPCEventResponseSystem( "CNPCEventResponseSystem" );
CNPCEventResponseSystem *NPCEventResponse()
{
return &g_NPCEventResponseSystem;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CNPCEventResponseSystem::LevelInitPreEntity( void )
{
m_ActiveEvents.Purge();
m_flNextEventPoll = 0;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CNPCEventResponseSystem::TriggerEvent( const char *pResponse, bool bForce, bool bCancelScript )
{
m_flNextEventPoll = gpGlobals->curtime;
// Find the event by name
int iIndex = m_ActiveEvents.Find( pResponse );
if ( iIndex == m_ActiveEvents.InvalidIndex() )
{
storedevent_t newEvent;
newEvent.flEventTime = gpGlobals->curtime;
newEvent.flNextResponseTime = 0;
newEvent.bForce = bForce;
newEvent.bCancelScript = bCancelScript;
newEvent.bPreventExpiration = false;
m_ActiveEvents.Insert( pResponse, newEvent );
if ( ai_debug_eventresponses.GetBool() )
{
Msg( "NPCEVENTRESPONSE: (%.2f) Trigger fired for event named: %s\n", gpGlobals->curtime, pResponse );
}
}
else
{
// Update the trigger time
m_ActiveEvents[iIndex].flEventTime = gpGlobals->curtime;
m_ActiveEvents[iIndex].bForce = bForce;
m_ActiveEvents[iIndex].bCancelScript = bCancelScript;
if ( ai_debug_eventresponses.GetBool() )
{
Msg( "NPCEVENTRESPONSE: (%.2f) Trigger resetting already-active event firing named: %s\n", gpGlobals->curtime, pResponse );
}
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CNPCEventResponseSystem::FrameUpdatePreEntityThink()
{
if ( !m_ActiveEvents.Count() || !AI_IsSinglePlayer() || !UTIL_GetLocalPlayer() )
return;
if ( m_flNextEventPoll > gpGlobals->curtime )
return;
m_flNextEventPoll = gpGlobals->curtime + 0.2;
// Move through all events, removing expired ones and finding NPCs for active ones.
for ( int i = m_ActiveEvents.First(); i != m_ActiveEvents.InvalidIndex(); )
{
float flTime = m_ActiveEvents[i].flEventTime;
const char *pResponse = m_ActiveEvents.GetElementName(i);
// Save off the next index so we can safely remove this one
int iNext = m_ActiveEvents.Next(i);
// Should it have expired by now?
if ( !m_ActiveEvents[i].bPreventExpiration && (flTime + NPCEVENTRESPONSE_GIVEUP_TIME) < gpGlobals->curtime )
{
if ( ai_debug_eventresponses.GetBool() )
{
Msg( "NPCEVENTRESPONSE: (%.2f) Removing expired event named: %s\n", gpGlobals->curtime, pResponse );
}
m_ActiveEvents.RemoveAt(i);
}
else if ( m_ActiveEvents[i].flNextResponseTime < gpGlobals->curtime )
{
// If we've fired once, and our current event should expire now, then expire.
if ( m_ActiveEvents[i].bPreventExpiration && (flTime + NPCEVENTRESPONSE_GIVEUP_TIME) < gpGlobals->curtime )
{
if ( ai_debug_eventresponses.GetBool() )
{
Msg( "NPCEVENTRESPONSE: (%.2f) Removing expired fired event named: %s\n", gpGlobals->curtime, pResponse );
}
m_ActiveEvents.RemoveAt(i);
}
else
{
float flNearestDist = NPCEVENTRESPONSE_DISTANCE_SQR;
CAI_BaseNPC *pNearestNPC = NULL;
Vector vecPlayerCenter = UTIL_GetLocalPlayer()->WorldSpaceCenter();
// Try and find the nearest NPC to the player
CAI_BaseNPC **ppAIs = g_AI_Manager.AccessAIs();
for ( int j = 0; j < g_AI_Manager.NumAIs(); j++ )
{
if ( ppAIs[j]->CanRespondToEvent( pResponse ))
{
float flDistToPlayer = ( vecPlayerCenter - ppAIs[j]->WorldSpaceCenter()).LengthSqr();
if ( flDistToPlayer < flNearestDist )
{
flNearestDist = flDistToPlayer;
pNearestNPC = ppAIs[j];
}
}
}
// Found one?
if ( pNearestNPC )
{
if ( pNearestNPC->RespondedTo( pResponse, m_ActiveEvents[i].bForce, m_ActiveEvents[i].bCancelScript ) )
{
// Don't remove the response yet. Leave it around until the refire time has expired.
// This stops repeated firings of the same concept from spamming the NPCs.
m_ActiveEvents[i].bPreventExpiration = true;
m_ActiveEvents[i].flNextResponseTime = gpGlobals->curtime + NPCEVENTRESPONSE_REFIRE_TIME;
if ( ai_debug_eventresponses.GetBool() )
{
Msg( "NPCEVENTRESPONSE: (%.2f) Event '%s' responded to by NPC '%s'. Refire available at: %.2f\n", gpGlobals->curtime, pResponse, pNearestNPC->GetDebugName(), m_ActiveEvents[i].flNextResponseTime );
}
// Don't issue multiple responses at once
return;
}
}
}
}
i = iNext;
}
}
//---------------------------------------------------------------------------------------------
// Entity version for mapmaker to hook into the system
//---------------------------------------------------------------------------------------------
class CNPCEventResponseSystemEntity : public CBaseEntity
{
DECLARE_CLASS( CNPCEventResponseSystemEntity, CBaseEntity );
public:
DECLARE_DATADESC();
void Spawn();
void InputTriggerResponseEvent( inputdata_t &inputdata );
void InputForceTriggerResponseEvent( inputdata_t &inputdata );
void InputForceTriggerResponseEventNoCancel( inputdata_t &inputdata );
};
LINK_ENTITY_TO_CLASS( ai_npc_eventresponsesystem, CNPCEventResponseSystemEntity );
BEGIN_DATADESC( CNPCEventResponseSystemEntity )
DEFINE_INPUTFUNC( FIELD_STRING, "TriggerResponseEvent", InputTriggerResponseEvent ),
DEFINE_INPUTFUNC( FIELD_STRING, "ForceTriggerResponseEvent", InputForceTriggerResponseEvent ),
DEFINE_INPUTFUNC( FIELD_STRING, "ForceTriggerResponseEventNoCancel", InputForceTriggerResponseEventNoCancel ),
END_DATADESC()
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CNPCEventResponseSystemEntity::Spawn( void )
{
// Invisible, non solid.
AddSolidFlags( FSOLID_NOT_SOLID );
AddEffects( EF_NODRAW );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CNPCEventResponseSystemEntity::InputTriggerResponseEvent( inputdata_t &inputdata )
{
NPCEventResponse()->TriggerEvent( inputdata.value.String(), false, false );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CNPCEventResponseSystemEntity::InputForceTriggerResponseEvent( inputdata_t &inputdata )
{
NPCEventResponse()->TriggerEvent( inputdata.value.String(), true, true );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CNPCEventResponseSystemEntity::InputForceTriggerResponseEventNoCancel( inputdata_t &inputdata )
{
NPCEventResponse()->TriggerEvent( inputdata.value.String(), true, false );
}
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: AI system that makes NPCs verbally respond to game events
//
//=============================================================================
#include "cbase.h"
#include "ai_eventresponse.h"
#include "ai_basenpc.h"
ConVar ai_debug_eventresponses( "ai_debug_eventresponses", "0", FCVAR_NONE, "Set to 1 to see all NPC response events trigger, and which NPCs choose to respond to them." );
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
CNPCEventResponseSystem g_NPCEventResponseSystem( "CNPCEventResponseSystem" );
CNPCEventResponseSystem *NPCEventResponse()
{
return &g_NPCEventResponseSystem;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CNPCEventResponseSystem::LevelInitPreEntity( void )
{
m_ActiveEvents.Purge();
m_flNextEventPoll = 0;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CNPCEventResponseSystem::TriggerEvent( const char *pResponse, bool bForce, bool bCancelScript )
{
m_flNextEventPoll = gpGlobals->curtime;
// Find the event by name
int iIndex = m_ActiveEvents.Find( pResponse );
if ( iIndex == m_ActiveEvents.InvalidIndex() )
{
storedevent_t newEvent;
newEvent.flEventTime = gpGlobals->curtime;
newEvent.flNextResponseTime = 0;
newEvent.bForce = bForce;
newEvent.bCancelScript = bCancelScript;
newEvent.bPreventExpiration = false;
m_ActiveEvents.Insert( pResponse, newEvent );
if ( ai_debug_eventresponses.GetBool() )
{
Msg( "NPCEVENTRESPONSE: (%.2f) Trigger fired for event named: %s\n", gpGlobals->curtime, pResponse );
}
}
else
{
// Update the trigger time
m_ActiveEvents[iIndex].flEventTime = gpGlobals->curtime;
m_ActiveEvents[iIndex].bForce = bForce;
m_ActiveEvents[iIndex].bCancelScript = bCancelScript;
if ( ai_debug_eventresponses.GetBool() )
{
Msg( "NPCEVENTRESPONSE: (%.2f) Trigger resetting already-active event firing named: %s\n", gpGlobals->curtime, pResponse );
}
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CNPCEventResponseSystem::FrameUpdatePreEntityThink()
{
if ( !m_ActiveEvents.Count() || !AI_IsSinglePlayer() || !UTIL_GetLocalPlayer() )
return;
if ( m_flNextEventPoll > gpGlobals->curtime )
return;
m_flNextEventPoll = gpGlobals->curtime + 0.2;
// Move through all events, removing expired ones and finding NPCs for active ones.
for ( int i = m_ActiveEvents.First(); i != m_ActiveEvents.InvalidIndex(); )
{
float flTime = m_ActiveEvents[i].flEventTime;
const char *pResponse = m_ActiveEvents.GetElementName(i);
// Save off the next index so we can safely remove this one
int iNext = m_ActiveEvents.Next(i);
// Should it have expired by now?
if ( !m_ActiveEvents[i].bPreventExpiration && (flTime + NPCEVENTRESPONSE_GIVEUP_TIME) < gpGlobals->curtime )
{
if ( ai_debug_eventresponses.GetBool() )
{
Msg( "NPCEVENTRESPONSE: (%.2f) Removing expired event named: %s\n", gpGlobals->curtime, pResponse );
}
m_ActiveEvents.RemoveAt(i);
}
else if ( m_ActiveEvents[i].flNextResponseTime < gpGlobals->curtime )
{
// If we've fired once, and our current event should expire now, then expire.
if ( m_ActiveEvents[i].bPreventExpiration && (flTime + NPCEVENTRESPONSE_GIVEUP_TIME) < gpGlobals->curtime )
{
if ( ai_debug_eventresponses.GetBool() )
{
Msg( "NPCEVENTRESPONSE: (%.2f) Removing expired fired event named: %s\n", gpGlobals->curtime, pResponse );
}
m_ActiveEvents.RemoveAt(i);
}
else
{
float flNearestDist = NPCEVENTRESPONSE_DISTANCE_SQR;
CAI_BaseNPC *pNearestNPC = NULL;
Vector vecPlayerCenter = UTIL_GetLocalPlayer()->WorldSpaceCenter();
// Try and find the nearest NPC to the player
CAI_BaseNPC **ppAIs = g_AI_Manager.AccessAIs();
for ( int j = 0; j < g_AI_Manager.NumAIs(); j++ )
{
if ( ppAIs[j]->CanRespondToEvent( pResponse ))
{
float flDistToPlayer = ( vecPlayerCenter - ppAIs[j]->WorldSpaceCenter()).LengthSqr();
if ( flDistToPlayer < flNearestDist )
{
flNearestDist = flDistToPlayer;
pNearestNPC = ppAIs[j];
}
}
}
// Found one?
if ( pNearestNPC )
{
if ( pNearestNPC->RespondedTo( pResponse, m_ActiveEvents[i].bForce, m_ActiveEvents[i].bCancelScript ) )
{
// Don't remove the response yet. Leave it around until the refire time has expired.
// This stops repeated firings of the same concept from spamming the NPCs.
m_ActiveEvents[i].bPreventExpiration = true;
m_ActiveEvents[i].flNextResponseTime = gpGlobals->curtime + NPCEVENTRESPONSE_REFIRE_TIME;
if ( ai_debug_eventresponses.GetBool() )
{
Msg( "NPCEVENTRESPONSE: (%.2f) Event '%s' responded to by NPC '%s'. Refire available at: %.2f\n", gpGlobals->curtime, pResponse, pNearestNPC->GetDebugName(), m_ActiveEvents[i].flNextResponseTime );
}
// Don't issue multiple responses at once
return;
}
}
}
}
i = iNext;
}
}
//---------------------------------------------------------------------------------------------
// Entity version for mapmaker to hook into the system
//---------------------------------------------------------------------------------------------
class CNPCEventResponseSystemEntity : public CBaseEntity
{
DECLARE_CLASS( CNPCEventResponseSystemEntity, CBaseEntity );
public:
DECLARE_DATADESC();
void Spawn();
void InputTriggerResponseEvent( inputdata_t &inputdata );
void InputForceTriggerResponseEvent( inputdata_t &inputdata );
void InputForceTriggerResponseEventNoCancel( inputdata_t &inputdata );
};
LINK_ENTITY_TO_CLASS( ai_npc_eventresponsesystem, CNPCEventResponseSystemEntity );
BEGIN_DATADESC( CNPCEventResponseSystemEntity )
DEFINE_INPUTFUNC( FIELD_STRING, "TriggerResponseEvent", InputTriggerResponseEvent ),
DEFINE_INPUTFUNC( FIELD_STRING, "ForceTriggerResponseEvent", InputForceTriggerResponseEvent ),
DEFINE_INPUTFUNC( FIELD_STRING, "ForceTriggerResponseEventNoCancel", InputForceTriggerResponseEventNoCancel ),
END_DATADESC()
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CNPCEventResponseSystemEntity::Spawn( void )
{
// Invisible, non solid.
AddSolidFlags( FSOLID_NOT_SOLID );
AddEffects( EF_NODRAW );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CNPCEventResponseSystemEntity::InputTriggerResponseEvent( inputdata_t &inputdata )
{
NPCEventResponse()->TriggerEvent( inputdata.value.String(), false, false );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CNPCEventResponseSystemEntity::InputForceTriggerResponseEvent( inputdata_t &inputdata )
{
NPCEventResponse()->TriggerEvent( inputdata.value.String(), true, true );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CNPCEventResponseSystemEntity::InputForceTriggerResponseEventNoCancel( inputdata_t &inputdata )
{
NPCEventResponse()->TriggerEvent( inputdata.value.String(), true, false );
}

View File

@@ -1,48 +1,48 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: AI system that makes NPCs verbally respond to game events
//
//=============================================================================//
#ifndef AI_EVENTRESPONSE_H
#define AI_EVENTRESPONSE_H
#include "utldict.h"
#define NPCEVENTRESPONSE_DISTANCE_SQR (768 * 768) // Maximum distance for responding to NPCs
#define NPCEVENTRESPONSE_REFIRE_TIME 15.0 // Time after giving a response before giving any more
#define NPCEVENTRESPONSE_GIVEUP_TIME 4.0 // Time after a response trigger was fired before discarding it without responding
//-----------------------------------------------------------------------------
// Purpose: AI system that makes NPCs verbally respond to game events
//-----------------------------------------------------------------------------
class CNPCEventResponseSystem : public CAutoGameSystemPerFrame
{
public:
CNPCEventResponseSystem( char const *name ) : CAutoGameSystemPerFrame( name )
{
}
void LevelInitPreEntity();
void FrameUpdatePreEntityThink();
void TriggerEvent( const char *pResponse, bool bForce, bool bCancelScript );
private:
float m_flNextEventPoll;
struct storedevent_t
{
float flEventTime;
float flNextResponseTime;
bool bForce;
bool bCancelScript;
bool bPreventExpiration;
};
typedef CUtlDict< storedevent_t, int > EventMap;
EventMap m_ActiveEvents;
};
CNPCEventResponseSystem *NPCEventResponse();
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: AI system that makes NPCs verbally respond to game events
//
//=============================================================================//
#ifndef AI_EVENTRESPONSE_H
#define AI_EVENTRESPONSE_H
#include "utldict.h"
#define NPCEVENTRESPONSE_DISTANCE_SQR (768 * 768) // Maximum distance for responding to NPCs
#define NPCEVENTRESPONSE_REFIRE_TIME 15.0 // Time after giving a response before giving any more
#define NPCEVENTRESPONSE_GIVEUP_TIME 4.0 // Time after a response trigger was fired before discarding it without responding
//-----------------------------------------------------------------------------
// Purpose: AI system that makes NPCs verbally respond to game events
//-----------------------------------------------------------------------------
class CNPCEventResponseSystem : public CAutoGameSystemPerFrame
{
public:
CNPCEventResponseSystem( char const *name ) : CAutoGameSystemPerFrame( name )
{
}
void LevelInitPreEntity();
void FrameUpdatePreEntityThink();
void TriggerEvent( const char *pResponse, bool bForce, bool bCancelScript );
private:
float m_flNextEventPoll;
struct storedevent_t
{
float flEventTime;
float flNextResponseTime;
bool bForce;
bool bCancelScript;
bool bPreventExpiration;
};
typedef CUtlDict< storedevent_t, int > EventMap;
EventMap m_ActiveEvents;
};
CNPCEventResponseSystem *NPCEventResponse();
#endif // AI_EVENTRESPONSE_H

View File

@@ -1,278 +1,278 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#include "cbase.h"
#include "utlrbtree.h"
#include "saverestore_utlvector.h"
#include "ai_goalentity.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
//-----------------------------------------------------------------------------
//
// CAI_GoalEntity implementation
//
BEGIN_DATADESC( CAI_GoalEntity )
DEFINE_KEYFIELD( m_iszActor, FIELD_STRING, "Actor" ),
DEFINE_KEYFIELD( m_iszGoal, FIELD_STRING, "Goal" ),
DEFINE_KEYFIELD( m_fStartActive, FIELD_BOOLEAN, "StartActive" ),
DEFINE_KEYFIELD( m_iszConceptModifiers, FIELD_STRING, "BaseConceptModifiers" ),
DEFINE_KEYFIELD( m_SearchType, FIELD_INTEGER, "SearchType" ),
DEFINE_UTLVECTOR( m_actors, FIELD_EHANDLE ),
DEFINE_FIELD( m_hGoalEntity, FIELD_EHANDLE ),
DEFINE_FIELD( m_flags, FIELD_INTEGER ),
DEFINE_THINKFUNC( DelayedRefresh ),
// Inputs
DEFINE_INPUTFUNC( FIELD_VOID, "Activate", InputActivate ),
DEFINE_INPUTFUNC( FIELD_VOID, "UpdateActors", InputUpdateActors ),
DEFINE_INPUTFUNC( FIELD_VOID, "Deactivate", InputDeactivate ),
END_DATADESC()
//-------------------------------------
void CAI_GoalEntity::Spawn()
{
SetThink( &CAI_GoalEntity::DelayedRefresh );
SetNextThink( gpGlobals->curtime + 0.1f );
}
//-------------------------------------
void CAI_GoalEntity::OnRestore()
{
BaseClass::OnRestore();
ExitDormant();
if ( ( m_flags & ACTIVE ) )
gEntList.AddListenerEntity( this );
}
//-------------------------------------
void CAI_GoalEntity::DelayedRefresh()
{
inputdata_t ignored;
if ( m_fStartActive )
{
Assert( !(m_flags & ACTIVE) );
InputActivate( ignored );
m_fStartActive = false;
}
else
InputUpdateActors( ignored );
SetThink( NULL );
}
//-------------------------------------
void CAI_GoalEntity::PruneActors()
{
for ( int i = m_actors.Count() - 1; i >= 0; i-- )
{
if ( m_actors[i] == NULL || m_actors[i]->IsMarkedForDeletion() || m_actors[i]->GetState() == NPC_STATE_DEAD )
m_actors.FastRemove( i );
}
}
//-------------------------------------
void CAI_GoalEntity::ResolveNames()
{
m_actors.SetCount( 0 );
CBaseEntity *pEntity = NULL;
for (;;)
{
switch ( m_SearchType )
{
case ST_ENTNAME:
{
pEntity = gEntList.FindEntityByName( pEntity, m_iszActor );
break;
}
case ST_CLASSNAME:
{
pEntity = gEntList.FindEntityByClassname( pEntity, STRING( m_iszActor ) );
break;
}
}
if ( !pEntity )
break;
CAI_BaseNPC *pActor = pEntity->MyNPCPointer();
if ( pActor && pActor->GetState() != NPC_STATE_DEAD )
{
AIHANDLE temp;
temp = pActor;
m_actors.AddToTail( temp );
}
}
m_hGoalEntity = gEntList.FindEntityByName( NULL, m_iszGoal );
}
//-------------------------------------
void CAI_GoalEntity::InputActivate( inputdata_t &inputdata )
{
if ( !( m_flags & ACTIVE ) )
{
gEntList.AddListenerEntity( this );
UpdateActors();
m_flags |= ACTIVE;
for ( int i = 0; i < m_actors.Count(); i++ )
{
EnableGoal( m_actors[i] );
}
}
}
//-------------------------------------
void CAI_GoalEntity::InputUpdateActors( inputdata_t &inputdata )
{
int i;
CUtlRBTree<CAI_BaseNPC *> prevActors;
CUtlRBTree<CAI_BaseNPC *>::IndexType_t index;
SetDefLessFunc( prevActors );
PruneActors();
for ( i = 0; i < m_actors.Count(); i++ )
{
prevActors.Insert( m_actors[i] );
}
ResolveNames();
for ( i = 0; i < m_actors.Count(); i++ )
{
index = prevActors.Find( m_actors[i] );
if ( index == prevActors.InvalidIndex() )
{
if ( m_flags & ACTIVE )
EnableGoal( m_actors[i] );
}
else
prevActors.Remove( m_actors[i] );
}
for ( index = prevActors.FirstInorder(); index != prevActors.InvalidIndex(); index = prevActors.NextInorder( index ) )
{
if ( m_flags & ACTIVE )
DisableGoal( prevActors[ index ] );
}
}
//-------------------------------------
void CAI_GoalEntity::InputDeactivate( inputdata_t &inputdata )
{
if ( m_flags & ACTIVE )
{
gEntList.RemoveListenerEntity( this );
UpdateActors();
m_flags &= ~ACTIVE;
for ( int i = 0; i < m_actors.Count(); i++ )
{
DisableGoal( m_actors[i] );
}
}
}
//-------------------------------------
void CAI_GoalEntity::EnterDormant( void )
{
if ( m_flags & ACTIVE )
{
m_flags |= DORMANT;
for ( int i = 0; i < m_actors.Count(); i++ )
{
DisableGoal( m_actors[i] );
}
}
}
//-------------------------------------
void CAI_GoalEntity::ExitDormant( void )
{
if ( m_flags & DORMANT )
{
m_flags &= ~DORMANT;
inputdata_t ignored;
InputUpdateActors( ignored );
}
}
//-------------------------------------
void CAI_GoalEntity::UpdateOnRemove()
{
if ( m_flags & ACTIVE )
{
inputdata_t inputdata;
InputDeactivate( inputdata );
}
BaseClass::UpdateOnRemove();
}
//-------------------------------------
void CAI_GoalEntity::OnEntityCreated( CBaseEntity *pEntity )
{
Assert( m_flags & ACTIVE );
if ( pEntity->MyNPCPointer() )
{
SetThink( &CAI_GoalEntity::DelayedRefresh );
SetNextThink( gpGlobals->curtime + 0.1f );
}
}
//-------------------------------------
void CAI_GoalEntity::OnEntityDeleted( CBaseEntity *pEntity )
{
Assert( pEntity != this );
}
//-----------------------------------------------------------------------------
int CAI_GoalEntity::DrawDebugTextOverlays()
{
char tempstr[512];
int offset = BaseClass::DrawDebugTextOverlays();
Q_snprintf( tempstr, sizeof(tempstr), "Active: %s", IsActive() ? "yes" : "no" );
EntityText( offset, tempstr, 0 );
offset++;
return offset;
}
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#include "cbase.h"
#include "utlrbtree.h"
#include "saverestore_utlvector.h"
#include "ai_goalentity.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
//-----------------------------------------------------------------------------
//
// CAI_GoalEntity implementation
//
BEGIN_DATADESC( CAI_GoalEntity )
DEFINE_KEYFIELD( m_iszActor, FIELD_STRING, "Actor" ),
DEFINE_KEYFIELD( m_iszGoal, FIELD_STRING, "Goal" ),
DEFINE_KEYFIELD( m_fStartActive, FIELD_BOOLEAN, "StartActive" ),
DEFINE_KEYFIELD( m_iszConceptModifiers, FIELD_STRING, "BaseConceptModifiers" ),
DEFINE_KEYFIELD( m_SearchType, FIELD_INTEGER, "SearchType" ),
DEFINE_UTLVECTOR( m_actors, FIELD_EHANDLE ),
DEFINE_FIELD( m_hGoalEntity, FIELD_EHANDLE ),
DEFINE_FIELD( m_flags, FIELD_INTEGER ),
DEFINE_THINKFUNC( DelayedRefresh ),
// Inputs
DEFINE_INPUTFUNC( FIELD_VOID, "Activate", InputActivate ),
DEFINE_INPUTFUNC( FIELD_VOID, "UpdateActors", InputUpdateActors ),
DEFINE_INPUTFUNC( FIELD_VOID, "Deactivate", InputDeactivate ),
END_DATADESC()
//-------------------------------------
void CAI_GoalEntity::Spawn()
{
SetThink( &CAI_GoalEntity::DelayedRefresh );
SetNextThink( gpGlobals->curtime + 0.1f );
}
//-------------------------------------
void CAI_GoalEntity::OnRestore()
{
BaseClass::OnRestore();
ExitDormant();
if ( ( m_flags & ACTIVE ) )
gEntList.AddListenerEntity( this );
}
//-------------------------------------
void CAI_GoalEntity::DelayedRefresh()
{
inputdata_t ignored;
if ( m_fStartActive )
{
Assert( !(m_flags & ACTIVE) );
InputActivate( ignored );
m_fStartActive = false;
}
else
InputUpdateActors( ignored );
SetThink( NULL );
}
//-------------------------------------
void CAI_GoalEntity::PruneActors()
{
for ( int i = m_actors.Count() - 1; i >= 0; i-- )
{
if ( m_actors[i] == NULL || m_actors[i]->IsMarkedForDeletion() || m_actors[i]->GetState() == NPC_STATE_DEAD )
m_actors.FastRemove( i );
}
}
//-------------------------------------
void CAI_GoalEntity::ResolveNames()
{
m_actors.SetCount( 0 );
CBaseEntity *pEntity = NULL;
for (;;)
{
switch ( m_SearchType )
{
case ST_ENTNAME:
{
pEntity = gEntList.FindEntityByName( pEntity, m_iszActor );
break;
}
case ST_CLASSNAME:
{
pEntity = gEntList.FindEntityByClassname( pEntity, STRING( m_iszActor ) );
break;
}
}
if ( !pEntity )
break;
CAI_BaseNPC *pActor = pEntity->MyNPCPointer();
if ( pActor && pActor->GetState() != NPC_STATE_DEAD )
{
AIHANDLE temp;
temp = pActor;
m_actors.AddToTail( temp );
}
}
m_hGoalEntity = gEntList.FindEntityByName( NULL, m_iszGoal );
}
//-------------------------------------
void CAI_GoalEntity::InputActivate( inputdata_t &inputdata )
{
if ( !( m_flags & ACTIVE ) )
{
gEntList.AddListenerEntity( this );
UpdateActors();
m_flags |= ACTIVE;
for ( int i = 0; i < m_actors.Count(); i++ )
{
EnableGoal( m_actors[i] );
}
}
}
//-------------------------------------
void CAI_GoalEntity::InputUpdateActors( inputdata_t &inputdata )
{
int i;
CUtlRBTree<CAI_BaseNPC *> prevActors;
CUtlRBTree<CAI_BaseNPC *>::IndexType_t index;
SetDefLessFunc( prevActors );
PruneActors();
for ( i = 0; i < m_actors.Count(); i++ )
{
prevActors.Insert( m_actors[i] );
}
ResolveNames();
for ( i = 0; i < m_actors.Count(); i++ )
{
index = prevActors.Find( m_actors[i] );
if ( index == prevActors.InvalidIndex() )
{
if ( m_flags & ACTIVE )
EnableGoal( m_actors[i] );
}
else
prevActors.Remove( m_actors[i] );
}
for ( index = prevActors.FirstInorder(); index != prevActors.InvalidIndex(); index = prevActors.NextInorder( index ) )
{
if ( m_flags & ACTIVE )
DisableGoal( prevActors[ index ] );
}
}
//-------------------------------------
void CAI_GoalEntity::InputDeactivate( inputdata_t &inputdata )
{
if ( m_flags & ACTIVE )
{
gEntList.RemoveListenerEntity( this );
UpdateActors();
m_flags &= ~ACTIVE;
for ( int i = 0; i < m_actors.Count(); i++ )
{
DisableGoal( m_actors[i] );
}
}
}
//-------------------------------------
void CAI_GoalEntity::EnterDormant( void )
{
if ( m_flags & ACTIVE )
{
m_flags |= DORMANT;
for ( int i = 0; i < m_actors.Count(); i++ )
{
DisableGoal( m_actors[i] );
}
}
}
//-------------------------------------
void CAI_GoalEntity::ExitDormant( void )
{
if ( m_flags & DORMANT )
{
m_flags &= ~DORMANT;
inputdata_t ignored;
InputUpdateActors( ignored );
}
}
//-------------------------------------
void CAI_GoalEntity::UpdateOnRemove()
{
if ( m_flags & ACTIVE )
{
inputdata_t inputdata;
InputDeactivate( inputdata );
}
BaseClass::UpdateOnRemove();
}
//-------------------------------------
void CAI_GoalEntity::OnEntityCreated( CBaseEntity *pEntity )
{
Assert( m_flags & ACTIVE );
if ( pEntity->MyNPCPointer() )
{
SetThink( &CAI_GoalEntity::DelayedRefresh );
SetNextThink( gpGlobals->curtime + 0.1f );
}
}
//-------------------------------------
void CAI_GoalEntity::OnEntityDeleted( CBaseEntity *pEntity )
{
Assert( pEntity != this );
}
//-----------------------------------------------------------------------------
int CAI_GoalEntity::DrawDebugTextOverlays()
{
char tempstr[512];
int offset = BaseClass::DrawDebugTextOverlays();
Q_snprintf( tempstr, sizeof(tempstr), "Active: %s", IsActive() ? "yes" : "no" );
EntityText( offset, tempstr, 0 );
offset++;
return offset;
}

View File

@@ -1,194 +1,194 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#ifndef AI_GOALENTITY_H
#define AI_GOALENTITY_H
#include "ai_basenpc.h"
#include "utlvector.h"
#if defined( _WIN32 )
#pragma once
#endif
//-----------------------------------------------------------------------------
//
// CAI_GoalEntity
//
// Purpose: Serves as the base class for all entities the designer may place
// that establish an NPC goal. Provides standard input, output &
// fields common to all goals.
//
class CAI_GoalEntity : public CBaseEntity,
public IEntityListener
{
DECLARE_CLASS( CAI_GoalEntity, CBaseEntity );
public:
CAI_GoalEntity()
: m_iszActor(NULL_STRING),
m_iszGoal(NULL_STRING),
m_fStartActive(false),
m_SearchType(ST_ENTNAME),
m_iszConceptModifiers(NULL_STRING),
m_hGoalEntity(NULL),
m_flags( 0 )
{
}
virtual int ObjectCaps() { return ((BaseClass::ObjectCaps() & ~FCAP_ACROSS_TRANSITION) | FCAP_NOTIFY_ON_TRANSITION); }
virtual void Spawn();
virtual void OnRestore();
virtual int DrawDebugTextOverlays();
virtual void InputActivate( inputdata_t &inputdata );
virtual void InputUpdateActors( inputdata_t &inputdata );
virtual void InputDeactivate( inputdata_t &inputdata );
// Goal entities can become Dormant if they're left behind on previous maps.
// Transitioning back to the map with cause a dormant goal entity to reactivate itself.
void EnterDormant( void );
void ExitDormant( void );
bool IsActive();
int NumActors();
CAI_BaseNPC * GetActor( int iActor = 0 );
void SetGoalEntity( CBaseEntity *pGoalEntity );
CBaseEntity * GetGoalEntity();
const char * GetGoalEntityName();
const char * GetConceptModifiers();
protected:
virtual void UpdateOnRemove();
virtual void OnEntityCreated( CBaseEntity *pEntity );
virtual void OnEntityDeleted( CBaseEntity *pEntity );
virtual void EnableGoal( CAI_BaseNPC *pAI ) {}
virtual void DisableGoal( CAI_BaseNPC *pAI ) {}
void UpdateActors();
const CUtlVector<AIHANDLE> &AccessActors()
{
return m_actors;
}
private:
enum Flags_t
{
ACTIVE = 0x01,
RESOLVED_NAME = 0x02,
DORMANT = 0x04,
};
enum SearchType_t
{
ST_ENTNAME,
ST_CLASSNAME,
};
void DelayedRefresh();
void PruneActors();
void ResolveNames();
// From Worldcraft
string_t m_iszActor;
string_t m_iszGoal;
bool m_fStartActive;
SearchType_t m_SearchType;
string_t m_iszConceptModifiers;
CUtlVector<AIHANDLE> m_actors;
EHANDLE m_hGoalEntity;
unsigned m_flags;
protected:
DECLARE_DATADESC();
};
//-------------------------------------
// @TODO (toml 03-18-03): Efficiency wart -- make this an explicit duty of the client?
inline void CAI_GoalEntity::UpdateActors()
{
if ( !( m_flags & ACTIVE ) || !( m_flags & RESOLVED_NAME ) )
{
ResolveNames();
m_flags |= RESOLVED_NAME;
}
else
PruneActors();
}
//-------------------------------------
inline bool CAI_GoalEntity::IsActive()
{
if ( m_flags & ACTIVE )
{
UpdateActors();
return ( m_actors.Count() != 0 );
}
return false;
}
//-------------------------------------
inline int CAI_GoalEntity::NumActors()
{
UpdateActors();
return m_actors.Count();
}
//-------------------------------------
inline CAI_BaseNPC *CAI_GoalEntity::GetActor( int iActor )
{
UpdateActors();
if ( m_actors.Count() > iActor )
return m_actors[iActor];
return NULL;
}
//-------------------------------------
inline void CAI_GoalEntity::SetGoalEntity( CBaseEntity *pGoalEntity )
{
m_iszGoal = pGoalEntity->GetEntityName();
m_hGoalEntity = pGoalEntity;
}
//-------------------------------------
inline CBaseEntity *CAI_GoalEntity::GetGoalEntity()
{
UpdateActors();
return m_hGoalEntity;
}
//-------------------------------------
inline const char *CAI_GoalEntity::GetGoalEntityName()
{
return STRING( m_iszGoal );
}
//-------------------------------------
inline const char *CAI_GoalEntity::GetConceptModifiers()
{
return STRING( m_iszConceptModifiers );
}
//-----------------------------------------------------------------------------
#endif // AI_GOALENTITY_H
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#ifndef AI_GOALENTITY_H
#define AI_GOALENTITY_H
#include "ai_basenpc.h"
#include "utlvector.h"
#if defined( _WIN32 )
#pragma once
#endif
//-----------------------------------------------------------------------------
//
// CAI_GoalEntity
//
// Purpose: Serves as the base class for all entities the designer may place
// that establish an NPC goal. Provides standard input, output &
// fields common to all goals.
//
class CAI_GoalEntity : public CBaseEntity,
public IEntityListener
{
DECLARE_CLASS( CAI_GoalEntity, CBaseEntity );
public:
CAI_GoalEntity()
: m_iszActor(NULL_STRING),
m_iszGoal(NULL_STRING),
m_fStartActive(false),
m_SearchType(ST_ENTNAME),
m_iszConceptModifiers(NULL_STRING),
m_hGoalEntity(NULL),
m_flags( 0 )
{
}
virtual int ObjectCaps() { return ((BaseClass::ObjectCaps() & ~FCAP_ACROSS_TRANSITION) | FCAP_NOTIFY_ON_TRANSITION); }
virtual void Spawn();
virtual void OnRestore();
virtual int DrawDebugTextOverlays();
virtual void InputActivate( inputdata_t &inputdata );
virtual void InputUpdateActors( inputdata_t &inputdata );
virtual void InputDeactivate( inputdata_t &inputdata );
// Goal entities can become Dormant if they're left behind on previous maps.
// Transitioning back to the map with cause a dormant goal entity to reactivate itself.
void EnterDormant( void );
void ExitDormant( void );
bool IsActive();
int NumActors();
CAI_BaseNPC * GetActor( int iActor = 0 );
void SetGoalEntity( CBaseEntity *pGoalEntity );
CBaseEntity * GetGoalEntity();
const char * GetGoalEntityName();
const char * GetConceptModifiers();
protected:
virtual void UpdateOnRemove();
virtual void OnEntityCreated( CBaseEntity *pEntity );
virtual void OnEntityDeleted( CBaseEntity *pEntity );
virtual void EnableGoal( CAI_BaseNPC *pAI ) {}
virtual void DisableGoal( CAI_BaseNPC *pAI ) {}
void UpdateActors();
const CUtlVector<AIHANDLE> &AccessActors()
{
return m_actors;
}
private:
enum Flags_t
{
ACTIVE = 0x01,
RESOLVED_NAME = 0x02,
DORMANT = 0x04,
};
enum SearchType_t
{
ST_ENTNAME,
ST_CLASSNAME,
};
void DelayedRefresh();
void PruneActors();
void ResolveNames();
// From Worldcraft
string_t m_iszActor;
string_t m_iszGoal;
bool m_fStartActive;
SearchType_t m_SearchType;
string_t m_iszConceptModifiers;
CUtlVector<AIHANDLE> m_actors;
EHANDLE m_hGoalEntity;
unsigned m_flags;
protected:
DECLARE_DATADESC();
};
//-------------------------------------
// @TODO (toml 03-18-03): Efficiency wart -- make this an explicit duty of the client?
inline void CAI_GoalEntity::UpdateActors()
{
if ( !( m_flags & ACTIVE ) || !( m_flags & RESOLVED_NAME ) )
{
ResolveNames();
m_flags |= RESOLVED_NAME;
}
else
PruneActors();
}
//-------------------------------------
inline bool CAI_GoalEntity::IsActive()
{
if ( m_flags & ACTIVE )
{
UpdateActors();
return ( m_actors.Count() != 0 );
}
return false;
}
//-------------------------------------
inline int CAI_GoalEntity::NumActors()
{
UpdateActors();
return m_actors.Count();
}
//-------------------------------------
inline CAI_BaseNPC *CAI_GoalEntity::GetActor( int iActor )
{
UpdateActors();
if ( m_actors.Count() > iActor )
return m_actors[iActor];
return NULL;
}
//-------------------------------------
inline void CAI_GoalEntity::SetGoalEntity( CBaseEntity *pGoalEntity )
{
m_iszGoal = pGoalEntity->GetEntityName();
m_hGoalEntity = pGoalEntity;
}
//-------------------------------------
inline CBaseEntity *CAI_GoalEntity::GetGoalEntity()
{
UpdateActors();
return m_hGoalEntity;
}
//-------------------------------------
inline const char *CAI_GoalEntity::GetGoalEntityName()
{
return STRING( m_iszGoal );
}
//-------------------------------------
inline const char *CAI_GoalEntity::GetConceptModifiers()
{
return STRING( m_iszConceptModifiers );
}
//-----------------------------------------------------------------------------
#endif // AI_GOALENTITY_H

File diff suppressed because it is too large Load Diff

View File

@@ -1,341 +1,341 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Hint node utilities and functions.
//
// $NoKeywords: $
//=============================================================================//
#ifndef AI_HINT_H
#define AI_HINT_H
#pragma once
#include "ai_initutils.h"
#include "tier1/utlmap.h"
//Flags for FindHintNode
#define bits_HINT_NODE_NONE 0x00000000
#define bits_HINT_NODE_VISIBLE 0x00000001
#define bits_HINT_NODE_NEAREST 0x00000002 // Choose the node nearest me
#define bits_HINT_NODE_RANDOM 0x00000004 // Find a random hintnode meeting other criteria
#define bits_HINT_NODE_CLEAR 0x00000008 // Only choose nodes that have clear room for my bounding box (requires NPC)
#define bits_HINT_NODE_USE_GROUP 0x00000010 // Use the NPC's hintgroup when searching for a node (requires NPC)
#define bits_HINT_NODE_VISIBLE_TO_PLAYER 0x00000020
#define bits_HINT_NODE_NOT_VISIBLE_TO_PLAYER 0x00000040
#define bits_HINT_NODE_REPORT_FAILURES 0x00000080
#define bits_HINT_NODE_IN_VIEWCONE 0x00000100
#define bits_HINT_NODE_IN_AIMCONE 0x00000200
#define bits_HINT_NPC_IN_NODE_FOV 0x00000400 // Is the searcher inside the hint node's FOV?
#define bits_HINT_NOT_CLOSE_TO_ENEMY 0x00000800 // Hint must not be within 30 feet of my enemy
#define bits_HINT_HAS_LOS_TO_PLAYER 0x00001000 // Like VISIBLE_TO_PLAYER but doesn't care about player's facing
#define bits_HAS_EYEPOSITION_LOS_TO_PLAYER 0x00002000 // Like HAS LOS TO PLAYER, but checks NPC's eye position at the node, not node origin.
//-----------------------------------------------------------------------------
//
// hints - these MUST coincide with the HINTS listed under
// info_node in the FGD file!
//
// For debugging, they must also coincide with g_pszHintDescriptions.
//
//-----------------------------------------------------------------------------
enum Hint_e
{
HINT_ANY = -1,
HINT_NONE = 0,
HINT_NOT_USED_WORLD_DOOR,
HINT_WORLD_WINDOW,
HINT_NOT_USED_WORLD_BUTTON,
HINT_NOT_USED_WORLD_MACHINERY,
HINT_NOT_USED_WORLD_LEDGE,
HINT_NOT_USED_WORLD_LIGHT_SOURCE,
HINT_NOT_USED_WORLD_HEAT_SOURCE,
HINT_NOT_USED_WORLD_BLINKING_LIGHT,
HINT_NOT_USED_WORLD_BRIGHT_COLORS,
HINT_NOT_USED_WORLD_HUMAN_BLOOD,
HINT_NOT_USED_WORLD_ALIEN_BLOOD,
HINT_WORLD_WORK_POSITION,
HINT_WORLD_VISUALLY_INTERESTING,
HINT_WORLD_VISUALLY_INTERESTING_DONT_AIM,
HINT_WORLD_INHIBIT_COMBINE_MINES,
HINT_WORLD_VISUALLY_INTERESTING_STEALTH,
HINT_TACTICAL_COVER_MED = 100,
HINT_TACTICAL_COVER_LOW,
HINT_TACTICAL_SPAWN,
HINT_TACTICAL_PINCH, // Exit / entrance to an arena
HINT_NOT_USED_TACTICAL_GUARD,
HINT_TACTICAL_ENEMY_DISADVANTAGED, //Disadvantageous position for the enemy
HINT_NOT_USED_HEALTH_KIT,
HINT_NOT_USED_URBAN_STREETCORNER = 200,
HINT_NOT_USED_URBAN_STREETLAMP,
HINT_NOT_USED_URBAN_DARK_SPOT,
HINT_NOT_USED_URBAN_POSTER,
HINT_NOT_USED_URBAN_SHELTER,
HINT_NOT_USED_ASSASSIN_SECLUDED = 300,
HINT_NOT_USED_ASSASSIN_RAFTERS,
HINT_NOT_USED_ASSASSIN_GROUND,
HINT_NOT_USED_ASSASSIN_MONKEYBARS,
HINT_ANTLION_BURROW_POINT = 400,
HINT_ANTLION_THUMPER_FLEE_POINT,
HINT_HEADCRAB_BURROW_POINT = 450,
HINT_HEADCRAB_EXIT_POD_POINT,
HINT_NOT_USED_ROLLER_PATROL_POINT = 500,
HINT_NOT_USED_ROLLER_CLEANUP_POINT,
HINT_NOT_USED_PSTORM_ROCK_SPAWN = 600,
HINT_CROW_FLYTO_POINT = 700,
// TF2 Hints
HINT_BUG_PATROL_POINT = 800,
// HL2 Hints
HINT_FOLLOW_WAIT_POINT = 900,
HINT_JUMP_OVERRIDE = 901,
HINT_PLAYER_SQUAD_TRANSITON_POINT = 902,
HINT_NPC_EXIT_POINT = 903,
HINT_STRIDER_NODE = 904,
HINT_PLAYER_ALLY_MOVE_AWAY_DEST = 950,
HINT_PLAYER_ALLY_FEAR_DEST,
// HL1 port hints
HINT_HL1_WORLD_MACHINERY = 1000,
HINT_HL1_WORLD_BLINKING_LIGHT,
HINT_HL1_WORLD_HUMAN_BLOOD,
HINT_HL1_WORLD_ALIEN_BLOOD,
// CS port hints
HINT_CSTRIKE_HOSTAGE_ESCAPE = 1100,
};
const char *GetHintTypeDescription( Hint_e iHintType );
const char *GetHintTypeDescription( CAI_Hint *pHint );
//-----------------------------------------------------------------------------
// CHintCriteria
//-----------------------------------------------------------------------------
class CHintCriteria
{
public:
CHintCriteria();
~CHintCriteria();
bool HasFlag( int bitmask ) const { return ( m_iFlags & bitmask ) != 0; }
void SetFlag( int bitmask );
void ClearFlag( int bitmask );
void SetGroup( string_t group );
string_t GetGroup( void ) const { return m_strGroup; }
int GetFirstHintType( void ) const { return m_iFirstHintType; }
int GetLastHintType( void ) const { return m_iLastHintType; }
bool MatchesHintType( int hintType ) const;
bool MatchesSingleHintType() const;
bool HasIncludeZones( void ) const { return ( m_zoneInclude.Count() != 0 ); }
bool HasExcludeZones( void ) const { return ( m_zoneExclude.Count() != 0 ); }
void AddIncludePosition( const Vector &position, float radius );
void AddExcludePosition( const Vector &position, float radius );
void SetHintType( int hintType );
void SetHintTypeRange( int firstType, int lastType );
void AddHintType( int hintType );
bool InIncludedZone( const Vector &testPosition ) const;
bool InExcludedZone( const Vector &testPosition ) const;
int NumHintTypes() const;
int GetHintType( int idx ) const;
private:
struct hintZone_t
{
Vector position;
float radiussqr;
};
typedef CUtlVector < hintZone_t > zoneList_t;
void AddZone( zoneList_t &list, const Vector &position, float radius );
bool InZone( const zoneList_t &zone, const Vector &testPosition ) const;
CUtlVector<int> m_HintTypes;
int m_iFlags;
int m_iFirstHintType;
int m_iLastHintType;
string_t m_strGroup;
zoneList_t m_zoneInclude;
zoneList_t m_zoneExclude;
};
class CAI_Node;
//-----------------------------------------------------------------------------
// CAI_HintManager
//-----------------------------------------------------------------------------
DECLARE_POINTER_HANDLE(AIHintIter_t);
class CAIHintVector : public CUtlVector< CAI_Hint * >
{
public:
CAIHintVector() : CUtlVector< CAI_Hint * >( 1, 0 )
{
}
CAIHintVector( const CAIHintVector& src )
{
CopyArray( src.Base(), src.Count() );
}
CAIHintVector &operator=( const CAIHintVector &src )
{
CopyArray( src.Base(), src.Count() );
return *this;
}
};
class CAI_HintManager
{
friend class CAI_Hint;
public:
// Hint node creation
static CAI_Hint *CreateHint( HintNodeData *pNodeData, const char *pMapData = NULL );
static void DrawHintOverlays(float flDrawDuration);
static void AddHint( CAI_Hint *pTestHint );
static void RemoveHint( CAI_Hint *pTestHint );
static void AddHintByType( CAI_Hint *pHint );
static void RemoveHintByType( CAI_Hint *pHintToRemove );
// Interface for searching the hint node list
static CAI_Hint *FindHint( CAI_BaseNPC *pNPC, const Vector &position, const CHintCriteria &hintCriteria );
static CAI_Hint *FindHint( CAI_BaseNPC *pNPC, const CHintCriteria &hintCriteria );
static CAI_Hint *FindHint( const Vector &position, const CHintCriteria &hintCriteria );
static CAI_Hint *FindHint( CAI_BaseNPC *pNPC, Hint_e nHintType, int nFlags, float flMaxDist, const Vector *pMaxDistFrom = NULL );
// Purpose: Finds a random suitable hint within the requested radious of the npc
static CAI_Hint *FindHintRandom( CAI_BaseNPC *pNPC, const Vector &position, const CHintCriteria &hintCriteria );
static int FindAllHints( CAI_BaseNPC *pNPC, const Vector &position, const CHintCriteria &hintCriteria, CUtlVector<CAI_Hint *> *pResult );
static int FindAllHints( const Vector &position, const CHintCriteria &hintCriteria, CUtlVector<CAI_Hint *> *pResult ) { return FindAllHints( NULL, position, hintCriteria, pResult ); }
static int FindAllHints( CAI_BaseNPC *pNPC, const CHintCriteria &hintCriteria, CUtlVector<CAI_Hint *> *pResult ) { return FindAllHints( pNPC, pNPC->GetAbsOrigin(), hintCriteria, pResult ); }
static int GetFlags( const char *token );
static CAI_Hint *GetFirstHint( AIHintIter_t *pIter );
static CAI_Hint *GetNextHint( AIHintIter_t *pIter );
static void DumpHints();
static void ValidateHints();
private:
enum
{
// MUST BE POWER OF 2
HINT_HISTORY = (1<<3),
HINT_HISTORY_MASK = (HINT_HISTORY-1)
};
static CAI_Hint *AddFoundHint( CAI_Hint *hint );
static int GetFoundHintCount();
static CAI_Hint *GetFoundHint( int index );
static CAI_Hint *GetLastFoundHint();
static void ResetFoundHints();
static bool IsInFoundHintList( CAI_Hint *hint );
static int gm_nFoundHintIndex;
static CAI_Hint *gm_pLastFoundHints[ HINT_HISTORY ]; // Last used hint
static CAIHintVector gm_AllHints; // A linked list of all hints
static CUtlMap< int, CAIHintVector > gm_TypedHints;
};
//-----------------------------------------------------------------------------
// CAI_Hint
//-----------------------------------------------------------------------------
class CAI_Hint : public CServerOnlyEntity
{
DECLARE_CLASS( CAI_Hint, CServerOnlyEntity );
public:
CAI_Hint( void );
~CAI_Hint( void );
// Interface for specific nodes
bool Lock( CBaseEntity *pNPC ); // Makes unavailable for hints
void Unlock( float delay = 0.0 ); // Makes available for hints after delay
bool IsLocked(void); // Whether this node is available for use.
bool IsLockedBy( CBaseEntity *pNPC ); // Whether this node is available for use.
void GetPosition(CBaseCombatCharacter *pBCC, Vector *vPosition);
void GetPosition( Hull_t hull, Vector *vPosition );
Vector GetDirection( void );
float Yaw( void );
CAI_Node *GetNode( void );
string_t GetGroup( void ) const { return m_NodeData.strGroup; }
CBaseEntity *User( void ) const { return m_hHintOwner; };
Hint_e HintType( void ) const { return (Hint_e)m_NodeData.nHintType; };
void SetHintType( int hintType, bool force = false );
string_t HintActivityName( void ) const { return m_NodeData.iszActivityName; }
int GetTargetNode( void ) const { return m_nTargetNodeID; }
bool IsDisabled( void ) const { return (m_NodeData.iDisabled != 0); }
void SetDisabled( bool bDisabled ) { m_NodeData.iDisabled = bDisabled; }
void DisableForSeconds( float flSeconds );
void EnableThink();
void FixupTargetNode();
void NPCStartedUsing( CAI_BaseNPC *pNPC );
void NPCStoppedUsing( CAI_BaseNPC *pNPC );
HintIgnoreFacing_t GetIgnoreFacing() const { return m_NodeData.fIgnoreFacing; }
NPC_STATE GetMinState() const { return m_NodeData.minState; }
NPC_STATE GetMaxState() const { return m_NodeData.maxState; }
int GetNodeId() { return m_NodeData.nNodeID; }
int GetWCId() { return m_NodeData.nWCNodeID; }
bool HintMatchesCriteria( CAI_BaseNPC *pNPC, const CHintCriteria &hintCriteria, const Vector &position, float *flNearestDistance, bool bIgnoreLock = false, bool bIgnoreHintType = false );
bool IsInNodeFOV( CBaseEntity *pOther );
private:
void Spawn( void );
virtual void Activate();
virtual void UpdateOnRemove( void );
int DrawDebugTextOverlays(void);
virtual int ObjectCaps( void ) { return (BaseClass::ObjectCaps() & ~FCAP_ACROSS_TRANSITION); }
virtual void OnRestore();
bool IsViewable( void );
// Input handlers
void InputEnableHint( inputdata_t &inputdata );
void InputDisableHint( inputdata_t &inputdata );
private:
HintNodeData m_NodeData;
int m_nTargetNodeID;
EHANDLE m_hHintOwner; // Is hint locked (being used by NPC / NPC en-route to use it)
float m_flNextUseTime; // When can I be used again?
COutputEHANDLE m_OnNPCStartedUsing; // Triggered when an NPC has actively begun to use the node.
COutputEHANDLE m_OnNPCStoppedUsing; // Triggered when an NPC has finished using this node.
float m_nodeFOV;
Vector m_vecForward;
// The next hint in list of all hints
friend class CAI_HintManager;
DECLARE_DATADESC();
};
#define SF_ALLOW_JUMP_UP 65536
#endif //AI_HINT_H
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Hint node utilities and functions.
//
// $NoKeywords: $
//=============================================================================//
#ifndef AI_HINT_H
#define AI_HINT_H
#pragma once
#include "ai_initutils.h"
#include "tier1/utlmap.h"
//Flags for FindHintNode
#define bits_HINT_NODE_NONE 0x00000000
#define bits_HINT_NODE_VISIBLE 0x00000001
#define bits_HINT_NODE_NEAREST 0x00000002 // Choose the node nearest me
#define bits_HINT_NODE_RANDOM 0x00000004 // Find a random hintnode meeting other criteria
#define bits_HINT_NODE_CLEAR 0x00000008 // Only choose nodes that have clear room for my bounding box (requires NPC)
#define bits_HINT_NODE_USE_GROUP 0x00000010 // Use the NPC's hintgroup when searching for a node (requires NPC)
#define bits_HINT_NODE_VISIBLE_TO_PLAYER 0x00000020
#define bits_HINT_NODE_NOT_VISIBLE_TO_PLAYER 0x00000040
#define bits_HINT_NODE_REPORT_FAILURES 0x00000080
#define bits_HINT_NODE_IN_VIEWCONE 0x00000100
#define bits_HINT_NODE_IN_AIMCONE 0x00000200
#define bits_HINT_NPC_IN_NODE_FOV 0x00000400 // Is the searcher inside the hint node's FOV?
#define bits_HINT_NOT_CLOSE_TO_ENEMY 0x00000800 // Hint must not be within 30 feet of my enemy
#define bits_HINT_HAS_LOS_TO_PLAYER 0x00001000 // Like VISIBLE_TO_PLAYER but doesn't care about player's facing
#define bits_HAS_EYEPOSITION_LOS_TO_PLAYER 0x00002000 // Like HAS LOS TO PLAYER, but checks NPC's eye position at the node, not node origin.
//-----------------------------------------------------------------------------
//
// hints - these MUST coincide with the HINTS listed under
// info_node in the FGD file!
//
// For debugging, they must also coincide with g_pszHintDescriptions.
//
//-----------------------------------------------------------------------------
enum Hint_e
{
HINT_ANY = -1,
HINT_NONE = 0,
HINT_NOT_USED_WORLD_DOOR,
HINT_WORLD_WINDOW,
HINT_NOT_USED_WORLD_BUTTON,
HINT_NOT_USED_WORLD_MACHINERY,
HINT_NOT_USED_WORLD_LEDGE,
HINT_NOT_USED_WORLD_LIGHT_SOURCE,
HINT_NOT_USED_WORLD_HEAT_SOURCE,
HINT_NOT_USED_WORLD_BLINKING_LIGHT,
HINT_NOT_USED_WORLD_BRIGHT_COLORS,
HINT_NOT_USED_WORLD_HUMAN_BLOOD,
HINT_NOT_USED_WORLD_ALIEN_BLOOD,
HINT_WORLD_WORK_POSITION,
HINT_WORLD_VISUALLY_INTERESTING,
HINT_WORLD_VISUALLY_INTERESTING_DONT_AIM,
HINT_WORLD_INHIBIT_COMBINE_MINES,
HINT_WORLD_VISUALLY_INTERESTING_STEALTH,
HINT_TACTICAL_COVER_MED = 100,
HINT_TACTICAL_COVER_LOW,
HINT_TACTICAL_SPAWN,
HINT_TACTICAL_PINCH, // Exit / entrance to an arena
HINT_NOT_USED_TACTICAL_GUARD,
HINT_TACTICAL_ENEMY_DISADVANTAGED, //Disadvantageous position for the enemy
HINT_NOT_USED_HEALTH_KIT,
HINT_NOT_USED_URBAN_STREETCORNER = 200,
HINT_NOT_USED_URBAN_STREETLAMP,
HINT_NOT_USED_URBAN_DARK_SPOT,
HINT_NOT_USED_URBAN_POSTER,
HINT_NOT_USED_URBAN_SHELTER,
HINT_NOT_USED_ASSASSIN_SECLUDED = 300,
HINT_NOT_USED_ASSASSIN_RAFTERS,
HINT_NOT_USED_ASSASSIN_GROUND,
HINT_NOT_USED_ASSASSIN_MONKEYBARS,
HINT_ANTLION_BURROW_POINT = 400,
HINT_ANTLION_THUMPER_FLEE_POINT,
HINT_HEADCRAB_BURROW_POINT = 450,
HINT_HEADCRAB_EXIT_POD_POINT,
HINT_NOT_USED_ROLLER_PATROL_POINT = 500,
HINT_NOT_USED_ROLLER_CLEANUP_POINT,
HINT_NOT_USED_PSTORM_ROCK_SPAWN = 600,
HINT_CROW_FLYTO_POINT = 700,
// TF2 Hints
HINT_BUG_PATROL_POINT = 800,
// HL2 Hints
HINT_FOLLOW_WAIT_POINT = 900,
HINT_JUMP_OVERRIDE = 901,
HINT_PLAYER_SQUAD_TRANSITON_POINT = 902,
HINT_NPC_EXIT_POINT = 903,
HINT_STRIDER_NODE = 904,
HINT_PLAYER_ALLY_MOVE_AWAY_DEST = 950,
HINT_PLAYER_ALLY_FEAR_DEST,
// HL1 port hints
HINT_HL1_WORLD_MACHINERY = 1000,
HINT_HL1_WORLD_BLINKING_LIGHT,
HINT_HL1_WORLD_HUMAN_BLOOD,
HINT_HL1_WORLD_ALIEN_BLOOD,
// CS port hints
HINT_CSTRIKE_HOSTAGE_ESCAPE = 1100,
};
const char *GetHintTypeDescription( Hint_e iHintType );
const char *GetHintTypeDescription( CAI_Hint *pHint );
//-----------------------------------------------------------------------------
// CHintCriteria
//-----------------------------------------------------------------------------
class CHintCriteria
{
public:
CHintCriteria();
~CHintCriteria();
bool HasFlag( int bitmask ) const { return ( m_iFlags & bitmask ) != 0; }
void SetFlag( int bitmask );
void ClearFlag( int bitmask );
void SetGroup( string_t group );
string_t GetGroup( void ) const { return m_strGroup; }
int GetFirstHintType( void ) const { return m_iFirstHintType; }
int GetLastHintType( void ) const { return m_iLastHintType; }
bool MatchesHintType( int hintType ) const;
bool MatchesSingleHintType() const;
bool HasIncludeZones( void ) const { return ( m_zoneInclude.Count() != 0 ); }
bool HasExcludeZones( void ) const { return ( m_zoneExclude.Count() != 0 ); }
void AddIncludePosition( const Vector &position, float radius );
void AddExcludePosition( const Vector &position, float radius );
void SetHintType( int hintType );
void SetHintTypeRange( int firstType, int lastType );
void AddHintType( int hintType );
bool InIncludedZone( const Vector &testPosition ) const;
bool InExcludedZone( const Vector &testPosition ) const;
int NumHintTypes() const;
int GetHintType( int idx ) const;
private:
struct hintZone_t
{
Vector position;
float radiussqr;
};
typedef CUtlVector < hintZone_t > zoneList_t;
void AddZone( zoneList_t &list, const Vector &position, float radius );
bool InZone( const zoneList_t &zone, const Vector &testPosition ) const;
CUtlVector<int> m_HintTypes;
int m_iFlags;
int m_iFirstHintType;
int m_iLastHintType;
string_t m_strGroup;
zoneList_t m_zoneInclude;
zoneList_t m_zoneExclude;
};
class CAI_Node;
//-----------------------------------------------------------------------------
// CAI_HintManager
//-----------------------------------------------------------------------------
DECLARE_POINTER_HANDLE(AIHintIter_t);
class CAIHintVector : public CUtlVector< CAI_Hint * >
{
public:
CAIHintVector() : CUtlVector< CAI_Hint * >( 1, 0 )
{
}
CAIHintVector( const CAIHintVector& src )
{
CopyArray( src.Base(), src.Count() );
}
CAIHintVector &operator=( const CAIHintVector &src )
{
CopyArray( src.Base(), src.Count() );
return *this;
}
};
class CAI_HintManager
{
friend class CAI_Hint;
public:
// Hint node creation
static CAI_Hint *CreateHint( HintNodeData *pNodeData, const char *pMapData = NULL );
static void DrawHintOverlays(float flDrawDuration);
static void AddHint( CAI_Hint *pTestHint );
static void RemoveHint( CAI_Hint *pTestHint );
static void AddHintByType( CAI_Hint *pHint );
static void RemoveHintByType( CAI_Hint *pHintToRemove );
// Interface for searching the hint node list
static CAI_Hint *FindHint( CAI_BaseNPC *pNPC, const Vector &position, const CHintCriteria &hintCriteria );
static CAI_Hint *FindHint( CAI_BaseNPC *pNPC, const CHintCriteria &hintCriteria );
static CAI_Hint *FindHint( const Vector &position, const CHintCriteria &hintCriteria );
static CAI_Hint *FindHint( CAI_BaseNPC *pNPC, Hint_e nHintType, int nFlags, float flMaxDist, const Vector *pMaxDistFrom = NULL );
// Purpose: Finds a random suitable hint within the requested radious of the npc
static CAI_Hint *FindHintRandom( CAI_BaseNPC *pNPC, const Vector &position, const CHintCriteria &hintCriteria );
static int FindAllHints( CAI_BaseNPC *pNPC, const Vector &position, const CHintCriteria &hintCriteria, CUtlVector<CAI_Hint *> *pResult );
static int FindAllHints( const Vector &position, const CHintCriteria &hintCriteria, CUtlVector<CAI_Hint *> *pResult ) { return FindAllHints( NULL, position, hintCriteria, pResult ); }
static int FindAllHints( CAI_BaseNPC *pNPC, const CHintCriteria &hintCriteria, CUtlVector<CAI_Hint *> *pResult ) { return FindAllHints( pNPC, pNPC->GetAbsOrigin(), hintCriteria, pResult ); }
static int GetFlags( const char *token );
static CAI_Hint *GetFirstHint( AIHintIter_t *pIter );
static CAI_Hint *GetNextHint( AIHintIter_t *pIter );
static void DumpHints();
static void ValidateHints();
private:
enum
{
// MUST BE POWER OF 2
HINT_HISTORY = (1<<3),
HINT_HISTORY_MASK = (HINT_HISTORY-1)
};
static CAI_Hint *AddFoundHint( CAI_Hint *hint );
static int GetFoundHintCount();
static CAI_Hint *GetFoundHint( int index );
static CAI_Hint *GetLastFoundHint();
static void ResetFoundHints();
static bool IsInFoundHintList( CAI_Hint *hint );
static int gm_nFoundHintIndex;
static CAI_Hint *gm_pLastFoundHints[ HINT_HISTORY ]; // Last used hint
static CAIHintVector gm_AllHints; // A linked list of all hints
static CUtlMap< int, CAIHintVector > gm_TypedHints;
};
//-----------------------------------------------------------------------------
// CAI_Hint
//-----------------------------------------------------------------------------
class CAI_Hint : public CServerOnlyEntity
{
DECLARE_CLASS( CAI_Hint, CServerOnlyEntity );
public:
CAI_Hint( void );
~CAI_Hint( void );
// Interface for specific nodes
bool Lock( CBaseEntity *pNPC ); // Makes unavailable for hints
void Unlock( float delay = 0.0 ); // Makes available for hints after delay
bool IsLocked(void); // Whether this node is available for use.
bool IsLockedBy( CBaseEntity *pNPC ); // Whether this node is available for use.
void GetPosition(CBaseCombatCharacter *pBCC, Vector *vPosition);
void GetPosition( Hull_t hull, Vector *vPosition );
Vector GetDirection( void );
float Yaw( void );
CAI_Node *GetNode( void );
string_t GetGroup( void ) const { return m_NodeData.strGroup; }
CBaseEntity *User( void ) const { return m_hHintOwner; };
Hint_e HintType( void ) const { return (Hint_e)m_NodeData.nHintType; };
void SetHintType( int hintType, bool force = false );
string_t HintActivityName( void ) const { return m_NodeData.iszActivityName; }
int GetTargetNode( void ) const { return m_nTargetNodeID; }
bool IsDisabled( void ) const { return (m_NodeData.iDisabled != 0); }
void SetDisabled( bool bDisabled ) { m_NodeData.iDisabled = bDisabled; }
void DisableForSeconds( float flSeconds );
void EnableThink();
void FixupTargetNode();
void NPCStartedUsing( CAI_BaseNPC *pNPC );
void NPCStoppedUsing( CAI_BaseNPC *pNPC );
HintIgnoreFacing_t GetIgnoreFacing() const { return m_NodeData.fIgnoreFacing; }
NPC_STATE GetMinState() const { return m_NodeData.minState; }
NPC_STATE GetMaxState() const { return m_NodeData.maxState; }
int GetNodeId() { return m_NodeData.nNodeID; }
int GetWCId() { return m_NodeData.nWCNodeID; }
bool HintMatchesCriteria( CAI_BaseNPC *pNPC, const CHintCriteria &hintCriteria, const Vector &position, float *flNearestDistance, bool bIgnoreLock = false, bool bIgnoreHintType = false );
bool IsInNodeFOV( CBaseEntity *pOther );
private:
void Spawn( void );
virtual void Activate();
virtual void UpdateOnRemove( void );
int DrawDebugTextOverlays(void);
virtual int ObjectCaps( void ) { return (BaseClass::ObjectCaps() & ~FCAP_ACROSS_TRANSITION); }
virtual void OnRestore();
bool IsViewable( void );
// Input handlers
void InputEnableHint( inputdata_t &inputdata );
void InputDisableHint( inputdata_t &inputdata );
private:
HintNodeData m_NodeData;
int m_nTargetNodeID;
EHANDLE m_hHintOwner; // Is hint locked (being used by NPC / NPC en-route to use it)
float m_flNextUseTime; // When can I be used again?
COutputEHANDLE m_OnNPCStartedUsing; // Triggered when an NPC has actively begun to use the node.
COutputEHANDLE m_OnNPCStoppedUsing; // Triggered when an NPC has finished using this node.
float m_nodeFOV;
Vector m_vecForward;
// The next hint in list of all hints
friend class CAI_HintManager;
DECLARE_DATADESC();
};
#define SF_ALLOW_JUMP_UP 65536
#endif //AI_HINT_H

View File

@@ -1,185 +1,185 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
//=============================================================================//
#include "cbase.h"
#include "ai_hull.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
struct ai_hull_t
{
ai_hull_t( int bit, const char *pName, const Vector &_mins, const Vector &_maxs, const Vector &_smallMins, const Vector &_smallMaxs )
: hullBit( bit ), mins( _mins ), maxs( _maxs ), smallMins( _smallMins ), smallMaxs( _smallMaxs ), name( pName ) {}
int hullBit;
const char* name;
Vector mins;
Vector maxs;
Vector smallMins;
Vector smallMaxs;
};
//=================================================================================
// Create the hull types here.
//=================================================================================
#ifdef HL1_DLL
ai_hull_t Human_Hull (bits_HUMAN_HULL, "HUMAN_HULL", Vector(-13,-13, 0), Vector(13, 13, 72), Vector(-8,-8, 0), Vector( 8, 8, 72) );
ai_hull_t Small_Centered_Hull (bits_SMALL_CENTERED_HULL, "SMALL_CENTERED_HULL", Vector(-20,-20, -20), Vector(20, 20, 20), Vector(-12,-12,-12), Vector(12, 12, 12) );
ai_hull_t Wide_Human_Hull (bits_WIDE_HUMAN_HULL, "WIDE_HUMAN_HULL", Vector(-32,-32, 0), Vector(32, 32, 72), Vector(-10,-10, 0), Vector(10, 10, 72) );
ai_hull_t Tiny_Hull (bits_TINY_HULL, "TINY_HULL", Vector(-12,-12, 0), Vector(12, 12, 24), Vector(-12,-12, 0), Vector(12, 12, 24) );
ai_hull_t Wide_Short_Hull (bits_WIDE_SHORT_HULL, "WIDE_SHORT_HULL", Vector(-35,-35, 0), Vector(35, 35, 32), Vector(-20,-20, 0), Vector(20, 20, 32) );
ai_hull_t Medium_Hull (bits_MEDIUM_HULL, "MEDIUM_HULL", Vector(-16,-16, 0), Vector(16, 16, 64), Vector(-8,-8, 0), Vector(8, 8, 64) );
ai_hull_t Tiny_Centered_Hull (bits_TINY_CENTERED_HULL, "TINY_CENTERED_HULL", Vector(-8, -8, -4), Vector(8, 8, 4), Vector(-8,-8, -4), Vector( 8, 8, 4) );
ai_hull_t Large_Hull (bits_LARGE_HULL, "LARGE_HULL", Vector(-40,-40, 0), Vector(40, 40, 100), Vector(-40,-40, 0), Vector(40, 40, 100) );
ai_hull_t Large_Centered_Hull (bits_LARGE_CENTERED_HULL, "LARGE_CENTERED_HULL", Vector(-38,-38, -38), Vector(38, 38, 38), Vector(-30,-30,-30), Vector(30, 30, 30) );
ai_hull_t Medium_Tall_Hull (bits_MEDIUM_TALL_HULL, "MEDIUM_TALL_HULL", Vector(-18,-18, 0), Vector(18, 18, 100), Vector(-12,-12, 0), Vector(12, 12, 100) );
#else
ai_hull_t Human_Hull (bits_HUMAN_HULL, "HUMAN_HULL", Vector(-13,-13, 0), Vector(13, 13, 72), Vector(-8,-8, 0), Vector( 8, 8, 72) );
ai_hull_t Small_Centered_Hull (bits_SMALL_CENTERED_HULL, "SMALL_CENTERED_HULL", Vector(-20,-20, -20), Vector(20, 20, 20), Vector(-12,-12,-12), Vector(12, 12, 12) );
ai_hull_t Wide_Human_Hull (bits_WIDE_HUMAN_HULL, "WIDE_HUMAN_HULL", Vector(-15,-15, 0), Vector(15, 15, 72), Vector(-10,-10, 0), Vector(10, 10, 72) );
ai_hull_t Tiny_Hull (bits_TINY_HULL, "TINY_HULL", Vector(-12,-12, 0), Vector(12, 12, 24), Vector(-12,-12, 0), Vector(12, 12, 24) );
ai_hull_t Wide_Short_Hull (bits_WIDE_SHORT_HULL, "WIDE_SHORT_HULL", Vector(-35,-35, 0), Vector(35, 35, 32), Vector(-20,-20, 0), Vector(20, 20, 32) );
ai_hull_t Medium_Hull (bits_MEDIUM_HULL, "MEDIUM_HULL", Vector(-16,-16, 0), Vector(16, 16, 64), Vector(-8,-8, 0), Vector(8, 8, 64) );
ai_hull_t Tiny_Centered_Hull (bits_TINY_CENTERED_HULL, "TINY_CENTERED_HULL", Vector(-8, -8, -4), Vector(8, 8, 4), Vector(-8,-8, -4), Vector( 8, 8, 4) );
ai_hull_t Large_Hull (bits_LARGE_HULL, "LARGE_HULL", Vector(-40,-40, 0), Vector(40, 40, 100), Vector(-40,-40, 0), Vector(40, 40, 100) );
ai_hull_t Large_Centered_Hull (bits_LARGE_CENTERED_HULL, "LARGE_CENTERED_HULL", Vector(-38,-38, -38), Vector(38, 38, 38), Vector(-30,-30,-30), Vector(30, 30, 30) );
ai_hull_t Medium_Tall_Hull (bits_MEDIUM_TALL_HULL, "MEDIUM_TALL_HULL", Vector(-18,-18, 0), Vector(18, 18, 100), Vector(-12,-12, 0), Vector(12, 12, 100) );
#endif//HL1_DLL
//
// Array of hulls. These hulls must correspond with the enumerations in AI_Hull.h!
//
ai_hull_t* hull[NUM_HULLS] =
{
&Human_Hull,
&Small_Centered_Hull,
&Wide_Human_Hull,
&Tiny_Hull,
&Wide_Short_Hull,
&Medium_Hull,
&Tiny_Centered_Hull,
&Large_Hull,
&Large_Centered_Hull,
&Medium_Tall_Hull,
};
//-----------------------------------------------------------------------------
// Purpose:
// Input :
// Output :
//-----------------------------------------------------------------------------
const Vector &NAI_Hull::Mins(int id)
{
return hull[id]->mins;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input :
// Output :
//-----------------------------------------------------------------------------
const Vector &NAI_Hull::Maxs(int id)
{
return hull[id]->maxs;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input :
// Output :
//-----------------------------------------------------------------------------
const Vector &NAI_Hull::SmallMins(int id)
{
return hull[id]->smallMins;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input :
// Output :
//-----------------------------------------------------------------------------
const Vector &NAI_Hull::SmallMaxs(int id)
{
return hull[id]->smallMaxs;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input :
// Output :
//-----------------------------------------------------------------------------
float NAI_Hull::Length(int id)
{
return (hull[id]->maxs.x - hull[id]->mins.x);
}
//-----------------------------------------------------------------------------
// Purpose:
// Input :
// Output :
//-----------------------------------------------------------------------------
float NAI_Hull::Width(int id)
{
return (hull[id]->maxs.y - hull[id]->mins.y);
}
//-----------------------------------------------------------------------------
// Purpose:
// Input :
// Output :
//-----------------------------------------------------------------------------
float NAI_Hull::Height(int id)
{
return (hull[id]->maxs.z - hull[id]->mins.z);
}
//-----------------------------------------------------------------------------
// Purpose:
// Input :
// Output :
//-----------------------------------------------------------------------------
int NAI_Hull::Bits(int id)
{
return hull[id]->hullBit;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input :
// Output :
//-----------------------------------------------------------------------------
const char *NAI_Hull::Name(int id)
{
return hull[id]->name;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input :
// Output :
//-----------------------------------------------------------------------------
Hull_t NAI_Hull::LookupId(const char *szName)
{
int i;
if (!szName)
{
return HULL_HUMAN;
}
for (i = 0; i < NUM_HULLS; i++)
{
if (stricmp( szName, NAI_Hull::Name( i )) == 0)
{
return (Hull_t)i;
}
}
return HULL_HUMAN;
}
//========= Copyright Valve Corporation, All rights reserved. ============//
//
//=============================================================================//
#include "cbase.h"
#include "ai_hull.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
struct ai_hull_t
{
ai_hull_t( int bit, const char *pName, const Vector &_mins, const Vector &_maxs, const Vector &_smallMins, const Vector &_smallMaxs )
: hullBit( bit ), mins( _mins ), maxs( _maxs ), smallMins( _smallMins ), smallMaxs( _smallMaxs ), name( pName ) {}
int hullBit;
const char* name;
Vector mins;
Vector maxs;
Vector smallMins;
Vector smallMaxs;
};
//=================================================================================
// Create the hull types here.
//=================================================================================
#ifdef HL1_DLL
ai_hull_t Human_Hull (bits_HUMAN_HULL, "HUMAN_HULL", Vector(-13,-13, 0), Vector(13, 13, 72), Vector(-8,-8, 0), Vector( 8, 8, 72) );
ai_hull_t Small_Centered_Hull (bits_SMALL_CENTERED_HULL, "SMALL_CENTERED_HULL", Vector(-20,-20, -20), Vector(20, 20, 20), Vector(-12,-12,-12), Vector(12, 12, 12) );
ai_hull_t Wide_Human_Hull (bits_WIDE_HUMAN_HULL, "WIDE_HUMAN_HULL", Vector(-32,-32, 0), Vector(32, 32, 72), Vector(-10,-10, 0), Vector(10, 10, 72) );
ai_hull_t Tiny_Hull (bits_TINY_HULL, "TINY_HULL", Vector(-12,-12, 0), Vector(12, 12, 24), Vector(-12,-12, 0), Vector(12, 12, 24) );
ai_hull_t Wide_Short_Hull (bits_WIDE_SHORT_HULL, "WIDE_SHORT_HULL", Vector(-35,-35, 0), Vector(35, 35, 32), Vector(-20,-20, 0), Vector(20, 20, 32) );
ai_hull_t Medium_Hull (bits_MEDIUM_HULL, "MEDIUM_HULL", Vector(-16,-16, 0), Vector(16, 16, 64), Vector(-8,-8, 0), Vector(8, 8, 64) );
ai_hull_t Tiny_Centered_Hull (bits_TINY_CENTERED_HULL, "TINY_CENTERED_HULL", Vector(-8, -8, -4), Vector(8, 8, 4), Vector(-8,-8, -4), Vector( 8, 8, 4) );
ai_hull_t Large_Hull (bits_LARGE_HULL, "LARGE_HULL", Vector(-40,-40, 0), Vector(40, 40, 100), Vector(-40,-40, 0), Vector(40, 40, 100) );
ai_hull_t Large_Centered_Hull (bits_LARGE_CENTERED_HULL, "LARGE_CENTERED_HULL", Vector(-38,-38, -38), Vector(38, 38, 38), Vector(-30,-30,-30), Vector(30, 30, 30) );
ai_hull_t Medium_Tall_Hull (bits_MEDIUM_TALL_HULL, "MEDIUM_TALL_HULL", Vector(-18,-18, 0), Vector(18, 18, 100), Vector(-12,-12, 0), Vector(12, 12, 100) );
#else
ai_hull_t Human_Hull (bits_HUMAN_HULL, "HUMAN_HULL", Vector(-13,-13, 0), Vector(13, 13, 72), Vector(-8,-8, 0), Vector( 8, 8, 72) );
ai_hull_t Small_Centered_Hull (bits_SMALL_CENTERED_HULL, "SMALL_CENTERED_HULL", Vector(-20,-20, -20), Vector(20, 20, 20), Vector(-12,-12,-12), Vector(12, 12, 12) );
ai_hull_t Wide_Human_Hull (bits_WIDE_HUMAN_HULL, "WIDE_HUMAN_HULL", Vector(-15,-15, 0), Vector(15, 15, 72), Vector(-10,-10, 0), Vector(10, 10, 72) );
ai_hull_t Tiny_Hull (bits_TINY_HULL, "TINY_HULL", Vector(-12,-12, 0), Vector(12, 12, 24), Vector(-12,-12, 0), Vector(12, 12, 24) );
ai_hull_t Wide_Short_Hull (bits_WIDE_SHORT_HULL, "WIDE_SHORT_HULL", Vector(-35,-35, 0), Vector(35, 35, 32), Vector(-20,-20, 0), Vector(20, 20, 32) );
ai_hull_t Medium_Hull (bits_MEDIUM_HULL, "MEDIUM_HULL", Vector(-16,-16, 0), Vector(16, 16, 64), Vector(-8,-8, 0), Vector(8, 8, 64) );
ai_hull_t Tiny_Centered_Hull (bits_TINY_CENTERED_HULL, "TINY_CENTERED_HULL", Vector(-8, -8, -4), Vector(8, 8, 4), Vector(-8,-8, -4), Vector( 8, 8, 4) );
ai_hull_t Large_Hull (bits_LARGE_HULL, "LARGE_HULL", Vector(-40,-40, 0), Vector(40, 40, 100), Vector(-40,-40, 0), Vector(40, 40, 100) );
ai_hull_t Large_Centered_Hull (bits_LARGE_CENTERED_HULL, "LARGE_CENTERED_HULL", Vector(-38,-38, -38), Vector(38, 38, 38), Vector(-30,-30,-30), Vector(30, 30, 30) );
ai_hull_t Medium_Tall_Hull (bits_MEDIUM_TALL_HULL, "MEDIUM_TALL_HULL", Vector(-18,-18, 0), Vector(18, 18, 100), Vector(-12,-12, 0), Vector(12, 12, 100) );
#endif//HL1_DLL
//
// Array of hulls. These hulls must correspond with the enumerations in AI_Hull.h!
//
ai_hull_t* hull[NUM_HULLS] =
{
&Human_Hull,
&Small_Centered_Hull,
&Wide_Human_Hull,
&Tiny_Hull,
&Wide_Short_Hull,
&Medium_Hull,
&Tiny_Centered_Hull,
&Large_Hull,
&Large_Centered_Hull,
&Medium_Tall_Hull,
};
//-----------------------------------------------------------------------------
// Purpose:
// Input :
// Output :
//-----------------------------------------------------------------------------
const Vector &NAI_Hull::Mins(int id)
{
return hull[id]->mins;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input :
// Output :
//-----------------------------------------------------------------------------
const Vector &NAI_Hull::Maxs(int id)
{
return hull[id]->maxs;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input :
// Output :
//-----------------------------------------------------------------------------
const Vector &NAI_Hull::SmallMins(int id)
{
return hull[id]->smallMins;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input :
// Output :
//-----------------------------------------------------------------------------
const Vector &NAI_Hull::SmallMaxs(int id)
{
return hull[id]->smallMaxs;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input :
// Output :
//-----------------------------------------------------------------------------
float NAI_Hull::Length(int id)
{
return (hull[id]->maxs.x - hull[id]->mins.x);
}
//-----------------------------------------------------------------------------
// Purpose:
// Input :
// Output :
//-----------------------------------------------------------------------------
float NAI_Hull::Width(int id)
{
return (hull[id]->maxs.y - hull[id]->mins.y);
}
//-----------------------------------------------------------------------------
// Purpose:
// Input :
// Output :
//-----------------------------------------------------------------------------
float NAI_Hull::Height(int id)
{
return (hull[id]->maxs.z - hull[id]->mins.z);
}
//-----------------------------------------------------------------------------
// Purpose:
// Input :
// Output :
//-----------------------------------------------------------------------------
int NAI_Hull::Bits(int id)
{
return hull[id]->hullBit;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input :
// Output :
//-----------------------------------------------------------------------------
const char *NAI_Hull::Name(int id)
{
return hull[id]->name;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input :
// Output :
//-----------------------------------------------------------------------------
Hull_t NAI_Hull::LookupId(const char *szName)
{
int i;
if (!szName)
{
return HULL_HUMAN;
}
for (i = 0; i < NUM_HULLS; i++)
{
if (stricmp( szName, NAI_Hull::Name( i )) == 0)
{
return (Hull_t)i;
}
}
return HULL_HUMAN;
}

View File

@@ -1,75 +1,75 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
//=============================================================================//
#ifndef AI_HULL_H
#define AI_HULL_H
#pragma once
class Vector;
//=========================================================
// Link Properties. These hulls must correspond to the hulls
// in AI_Hull.cpp!
//=========================================================
enum Hull_t
{
HULL_HUMAN, // Combine, Stalker, Zombie...
HULL_SMALL_CENTERED, // Scanner
HULL_WIDE_HUMAN, // Vortigaunt
HULL_TINY, // Headcrab
HULL_WIDE_SHORT, // Bullsquid
HULL_MEDIUM, // Cremator
HULL_TINY_CENTERED, // Manhack
HULL_LARGE, // Antlion Guard
HULL_LARGE_CENTERED, // Mortar Synth
HULL_MEDIUM_TALL, // Hunter
//--------------------------------------------
NUM_HULLS,
HULL_NONE // No Hull (appears after num hulls as we don't want to count it)
};
enum Hull_Bits_t
{
bits_HUMAN_HULL = 0x00000001,
bits_SMALL_CENTERED_HULL = 0x00000002,
bits_WIDE_HUMAN_HULL = 0x00000004,
bits_TINY_HULL = 0x00000008,
bits_WIDE_SHORT_HULL = 0x00000010,
bits_MEDIUM_HULL = 0x00000020,
bits_TINY_CENTERED_HULL = 0x00000040,
bits_LARGE_HULL = 0x00000080,
bits_LARGE_CENTERED_HULL = 0x00000100,
bits_MEDIUM_TALL_HULL = 0x00000200,
bits_HULL_BITS_MASK = 0x000002ff,
};
inline int HullToBit( Hull_t hull )
{
return ( 1 << hull );
}
//=============================================================================
// >> CAI_Hull
//=============================================================================
namespace NAI_Hull
{
const Vector &Mins(int id);
const Vector &Maxs(int id);
const Vector &SmallMins(int id);
const Vector &SmallMaxs(int id);
float Length(int id);
float Width(int id);
float Height(int id);
int Bits(int id);
const char* Name(int id);
Hull_t LookupId(const char *szName);
};
#endif // AI_HULL_H
//========= Copyright Valve Corporation, All rights reserved. ============//
//
//=============================================================================//
#ifndef AI_HULL_H
#define AI_HULL_H
#pragma once
class Vector;
//=========================================================
// Link Properties. These hulls must correspond to the hulls
// in AI_Hull.cpp!
//=========================================================
enum Hull_t
{
HULL_HUMAN, // Combine, Stalker, Zombie...
HULL_SMALL_CENTERED, // Scanner
HULL_WIDE_HUMAN, // Vortigaunt
HULL_TINY, // Headcrab
HULL_WIDE_SHORT, // Bullsquid
HULL_MEDIUM, // Cremator
HULL_TINY_CENTERED, // Manhack
HULL_LARGE, // Antlion Guard
HULL_LARGE_CENTERED, // Mortar Synth
HULL_MEDIUM_TALL, // Hunter
//--------------------------------------------
NUM_HULLS,
HULL_NONE // No Hull (appears after num hulls as we don't want to count it)
};
enum Hull_Bits_t
{
bits_HUMAN_HULL = 0x00000001,
bits_SMALL_CENTERED_HULL = 0x00000002,
bits_WIDE_HUMAN_HULL = 0x00000004,
bits_TINY_HULL = 0x00000008,
bits_WIDE_SHORT_HULL = 0x00000010,
bits_MEDIUM_HULL = 0x00000020,
bits_TINY_CENTERED_HULL = 0x00000040,
bits_LARGE_HULL = 0x00000080,
bits_LARGE_CENTERED_HULL = 0x00000100,
bits_MEDIUM_TALL_HULL = 0x00000200,
bits_HULL_BITS_MASK = 0x000002ff,
};
inline int HullToBit( Hull_t hull )
{
return ( 1 << hull );
}
//=============================================================================
// >> CAI_Hull
//=============================================================================
namespace NAI_Hull
{
const Vector &Mins(int id);
const Vector &Maxs(int id);
const Vector &SmallMins(int id);
const Vector &SmallMaxs(int id);
float Length(int id);
float Width(int id);
float Height(int id);
int Bits(int id);
const char* Name(int id);
Hull_t LookupId(const char *szName);
};
#endif // AI_HULL_H

View File

@@ -1,342 +1,342 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: AI Utility classes for building the initial AI Networks
//
// $Workfile: $
// $Date: $
//
//-----------------------------------------------------------------------------
// $Log: $
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "ai_node.h"
#include "ai_hull.h"
#include "ai_hint.h"
#include "ai_initutils.h"
#include "ai_networkmanager.h"
// to help eliminate node clutter by level designers, this is used to cap how many other nodes
// any given node is allowed to 'see' in the first stage of graph creation "LinkVisibleNodes()".
#include "ai_network.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
LINK_ENTITY_TO_CLASS( info_hint, CNodeEnt );
LINK_ENTITY_TO_CLASS( info_node, CNodeEnt );
LINK_ENTITY_TO_CLASS( info_node_hint, CNodeEnt );
LINK_ENTITY_TO_CLASS( info_node_air, CNodeEnt );
LINK_ENTITY_TO_CLASS( info_node_air_hint, CNodeEnt );
LINK_ENTITY_TO_CLASS( info_node_climb, CNodeEnt );
LINK_ENTITY_TO_CLASS( aitesthull, CAI_TestHull );
//-----------------------------------------------------------------------------
// Init static variables
//-----------------------------------------------------------------------------
CAI_TestHull* CAI_TestHull::pTestHull = NULL;
#ifdef CSTRIKE_DLL
#define PLAYER_MODEL "models/player/ct_urban.mdl"
#else
#define PLAYER_MODEL "models/player.mdl"
#endif
//-----------------------------------------------------------------------------
// Purpose: Make sure we have a "player.mdl" hull to test with
//-----------------------------------------------------------------------------
void CAI_TestHull::Precache()
{
BaseClass::Precache();
PrecacheModel( PLAYER_MODEL );
}
//=========================================================
// CAI_TestHull::Spawn
//=========================================================
void CAI_TestHull::Spawn(void)
{
Precache();
SetModel( PLAYER_MODEL );
// Set an initial hull size (this will change later)
SetHullType(HULL_HUMAN);
SetHullSizeNormal();
SetSolid( SOLID_BBOX );
AddSolidFlags( FSOLID_NOT_SOLID );
SetMoveType( MOVETYPE_STEP );
m_iHealth = 50;
bInUse = false;
// Make this invisible
AddEffects( EF_NODRAW );
}
//-----------------------------------------------------------------------------
// Purpose: Get the test hull (create if none)
// Input :
// Output :
//-----------------------------------------------------------------------------
CAI_TestHull* CAI_TestHull::GetTestHull(void)
{
if (!CAI_TestHull::pTestHull)
{
CAI_TestHull::pTestHull = CREATE_ENTITY( CAI_TestHull, "aitesthull" );
CAI_TestHull::pTestHull->Spawn();
CAI_TestHull::pTestHull->AddFlag( FL_NPC );
}
if (CAI_TestHull::pTestHull->bInUse == true)
{
DevMsg("WARNING: TestHull used and never returned!\n");
Assert( 0 );
}
CAI_TestHull::pTestHull->RemoveSolidFlags( FSOLID_NOT_SOLID );
CAI_TestHull::pTestHull->bInUse = true;
return CAI_TestHull::pTestHull;
}
//-----------------------------------------------------------------------------
// Purpose: Get the test hull (create if none)
// Input :
// Output :
//-----------------------------------------------------------------------------
void CAI_TestHull::ReturnTestHull(void)
{
CAI_TestHull::pTestHull->bInUse = false;
CAI_TestHull::pTestHull->AddSolidFlags( FSOLID_NOT_SOLID );
UTIL_SetSize(CAI_TestHull::pTestHull, vec3_origin, vec3_origin);
UTIL_RemoveImmediate( pTestHull );
pTestHull = NULL;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : &startPos -
// &endPos -
// Output : Returns true on success, false on failure.
//-----------------------------------------------------------------------------
bool CAI_TestHull::IsJumpLegal(const Vector &startPos, const Vector &apex, const Vector &endPos) const
{
const float MAX_JUMP_RISE = 1024.0f;
const float MAX_JUMP_DISTANCE = 1024.0f;
const float MAX_JUMP_DROP = 1024.0f;
return BaseClass::IsJumpLegal( startPos, apex, endPos, MAX_JUMP_RISE, MAX_JUMP_DISTANCE, MAX_JUMP_DROP );
}
//-----------------------------------------------------------------------------
// Purpose:
// Input :
// Output :
//-----------------------------------------------------------------------------
CAI_TestHull::~CAI_TestHull(void)
{
CAI_TestHull::pTestHull = NULL;
}
//###########################################################
// > CNodeEnt
//
// nodes start out as ents in the world. As they are spawned,
// the node info is recorded then the ents are discarded.
//###########################################################
//----------------------------------------------------
// Static vars
//----------------------------------------------------
int CNodeEnt::m_nNodeCount = 0;
// -------------
// Data table
// -------------
BEGIN_SIMPLE_DATADESC( HintNodeData )
DEFINE_FIELD( strEntityName, FIELD_STRING ),
// DEFINE_FIELD( vecPosition, FIELD_VECTOR ), // Don't save
DEFINE_KEYFIELD( nHintType, FIELD_SHORT, "hinttype" ),
DEFINE_KEYFIELD( strGroup, FIELD_STRING, "Group" ),
DEFINE_KEYFIELD( iDisabled, FIELD_INTEGER, "StartHintDisabled" ),
DEFINE_FIELD( nNodeID, FIELD_INTEGER ),
DEFINE_KEYFIELD( iszActivityName, FIELD_STRING, "hintactivity" ),
DEFINE_KEYFIELD( nTargetWCNodeID, FIELD_INTEGER, "TargetNode" ),
DEFINE_KEYFIELD( nWCNodeID, FIELD_INTEGER, "nodeid" ),
DEFINE_KEYFIELD( fIgnoreFacing, FIELD_INTEGER, "IgnoreFacing" ),
DEFINE_KEYFIELD( minState, FIELD_INTEGER, "MinimumState" ),
DEFINE_KEYFIELD( maxState, FIELD_INTEGER, "MaximumState" ),
END_DATADESC()
// -------------
// Data table
// -------------
BEGIN_DATADESC( CNodeEnt )
DEFINE_EMBEDDED( m_NodeData ),
END_DATADESC()
//=========================================================
//=========================================================
void CNodeEnt::Spawn( void )
{
Spawn( NULL );
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : *pMapData -
//-----------------------------------------------------------------------------
int CNodeEnt::Spawn( const char *pMapData )
{
m_NodeData.strEntityName = GetEntityName();
m_NodeData.vecPosition = GetAbsOrigin();
m_NodeData.nNodeID = NO_NODE;
if ( m_NodeData.minState == NPC_STATE_NONE )
m_NodeData.minState = NPC_STATE_IDLE;
if ( m_NodeData.maxState == NPC_STATE_NONE )
m_NodeData.maxState = NPC_STATE_COMBAT;
// ---------------------------------------------------------------------------------
// If just a hint node (not used for navigation) just create a hint and bail
// ---------------------------------------------------------------------------------
if (FClassnameIs( this, "info_hint" ))
{
if (m_NodeData.nHintType)
{
CAI_HintManager::CreateHint( &m_NodeData, pMapData );
}
else
{
Warning("info_hint (HammerID: %d, position (%.2f, %.2f, %.2f)) with no hint type.\n", m_NodeData.nWCNodeID, m_NodeData.vecPosition.x, m_NodeData.vecPosition.y, m_NodeData.vecPosition.z );
}
UTIL_RemoveImmediate( this );
return -1;
}
// ---------------------------------------------------------------------------------
// First check if this node has a hint. If so create a hint entity
// ---------------------------------------------------------------------------------
CAI_Hint *pHint = NULL;
if ( ClassMatches( "info_node_hint" ) || ClassMatches( "info_node_air_hint" ) )
{
if ( m_NodeData.nHintType || m_NodeData.strGroup != NULL_STRING || m_NodeData.strEntityName != NULL_STRING )
{
m_NodeData.nNodeID = m_nNodeCount;
pHint = CAI_HintManager::CreateHint( &m_NodeData, pMapData );
pHint->AddSpawnFlags( GetSpawnFlags() );
}
}
// ---------------------------------------------------------------------------------
// If we loaded from disk, we can discard all these node ents as soon as they spawn
// unless we are in WC edited mode
// ---------------------------------------------------------------------------------
if ( g_pAINetworkManager->NetworksLoaded() && !engine->IsInEditMode())
{
// If hint exists for this node, set it
if (pHint)
{
CAI_Node *pNode = g_pBigAINet->GetNode(m_nNodeCount);
if (pNode)
pNode->SetHint( pHint );
else
{
DevMsg("AI node graph corrupt\n");
}
}
m_nNodeCount++;
UTIL_RemoveImmediate( this );
return -1;
}
else
{
m_nNodeCount++;
}
// ---------------------------------------------------------------------------------
// Add a new node to the network
// ---------------------------------------------------------------------------------
// For now just using one big AI network
CAI_Node *new_node = g_pBigAINet->AddNode( GetAbsOrigin(), GetAbsAngles().y );
new_node->SetHint( pHint );
// -------------------------------------------------------------------------
// Update table of how each WC id relates to each engine ID
// -------------------------------------------------------------------------
if (g_pAINetworkManager->GetEditOps()->m_pNodeIndexTable)
{
g_pAINetworkManager->GetEditOps()->m_pNodeIndexTable[new_node->GetId()] = m_NodeData.nWCNodeID;
}
// Keep track of largest index used by WC
if (g_pAINetworkManager->GetEditOps()->m_nNextWCIndex <= m_NodeData.nWCNodeID)
{
g_pAINetworkManager->GetEditOps()->m_nNextWCIndex = m_NodeData.nWCNodeID+1;
}
// -------------------------------------------------------------------------
// If in WC edit mode:
// Remember the original positions of the nodes before
// they drop so we can send the undropped positions to wc.
// -------------------------------------------------------------------------
if (engine->IsInEditMode())
{
if (g_pAINetworkManager->GetEditOps()->m_pWCPosition)
{
g_pAINetworkManager->GetEditOps()->m_pWCPosition[new_node->GetId()] = new_node->GetOrigin();
}
}
if (FClassnameIs( this, "info_node_air" ) || FClassnameIs( this, "info_node_air_hint" ))
{
new_node->SetType( NODE_AIR );
}
else if (FClassnameIs( this, "info_node_climb" ))
{
new_node->SetType( NODE_CLIMB );
}
else
{
new_node->SetType( NODE_GROUND );
}
new_node->m_eNodeInfo = ( m_spawnflags << NODE_ENT_FLAGS_SHIFT );
// If changed as part of WC editing process note that network must be rebuilt
if (m_debugOverlays & OVERLAY_WC_CHANGE_ENTITY)
{
g_pAINetworkManager->GetEditOps()->SetRebuildFlags();
new_node->m_eNodeInfo |= bits_NODE_WC_CHANGED;
// Initialize the new nodes position. The graph may not be rebuild
// right away but the node should at least be positioned correctly
g_AINetworkBuilder.InitNodePosition( g_pBigAINet, new_node );
}
UTIL_RemoveImmediate( this );
return -1;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input :
// Output :
//-----------------------------------------------------------------------------
CNodeEnt::CNodeEnt( void )
{
m_debugOverlays = 0;
}
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: AI Utility classes for building the initial AI Networks
//
// $Workfile: $
// $Date: $
//
//-----------------------------------------------------------------------------
// $Log: $
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "ai_node.h"
#include "ai_hull.h"
#include "ai_hint.h"
#include "ai_initutils.h"
#include "ai_networkmanager.h"
// to help eliminate node clutter by level designers, this is used to cap how many other nodes
// any given node is allowed to 'see' in the first stage of graph creation "LinkVisibleNodes()".
#include "ai_network.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
LINK_ENTITY_TO_CLASS( info_hint, CNodeEnt );
LINK_ENTITY_TO_CLASS( info_node, CNodeEnt );
LINK_ENTITY_TO_CLASS( info_node_hint, CNodeEnt );
LINK_ENTITY_TO_CLASS( info_node_air, CNodeEnt );
LINK_ENTITY_TO_CLASS( info_node_air_hint, CNodeEnt );
LINK_ENTITY_TO_CLASS( info_node_climb, CNodeEnt );
LINK_ENTITY_TO_CLASS( aitesthull, CAI_TestHull );
//-----------------------------------------------------------------------------
// Init static variables
//-----------------------------------------------------------------------------
CAI_TestHull* CAI_TestHull::pTestHull = NULL;
#ifdef CSTRIKE_DLL
#define PLAYER_MODEL "models/player/ct_urban.mdl"
#else
#define PLAYER_MODEL "models/player.mdl"
#endif
//-----------------------------------------------------------------------------
// Purpose: Make sure we have a "player.mdl" hull to test with
//-----------------------------------------------------------------------------
void CAI_TestHull::Precache()
{
BaseClass::Precache();
PrecacheModel( PLAYER_MODEL );
}
//=========================================================
// CAI_TestHull::Spawn
//=========================================================
void CAI_TestHull::Spawn(void)
{
Precache();
SetModel( PLAYER_MODEL );
// Set an initial hull size (this will change later)
SetHullType(HULL_HUMAN);
SetHullSizeNormal();
SetSolid( SOLID_BBOX );
AddSolidFlags( FSOLID_NOT_SOLID );
SetMoveType( MOVETYPE_STEP );
m_iHealth = 50;
bInUse = false;
// Make this invisible
AddEffects( EF_NODRAW );
}
//-----------------------------------------------------------------------------
// Purpose: Get the test hull (create if none)
// Input :
// Output :
//-----------------------------------------------------------------------------
CAI_TestHull* CAI_TestHull::GetTestHull(void)
{
if (!CAI_TestHull::pTestHull)
{
CAI_TestHull::pTestHull = CREATE_ENTITY( CAI_TestHull, "aitesthull" );
CAI_TestHull::pTestHull->Spawn();
CAI_TestHull::pTestHull->AddFlag( FL_NPC );
}
if (CAI_TestHull::pTestHull->bInUse == true)
{
DevMsg("WARNING: TestHull used and never returned!\n");
Assert( 0 );
}
CAI_TestHull::pTestHull->RemoveSolidFlags( FSOLID_NOT_SOLID );
CAI_TestHull::pTestHull->bInUse = true;
return CAI_TestHull::pTestHull;
}
//-----------------------------------------------------------------------------
// Purpose: Get the test hull (create if none)
// Input :
// Output :
//-----------------------------------------------------------------------------
void CAI_TestHull::ReturnTestHull(void)
{
CAI_TestHull::pTestHull->bInUse = false;
CAI_TestHull::pTestHull->AddSolidFlags( FSOLID_NOT_SOLID );
UTIL_SetSize(CAI_TestHull::pTestHull, vec3_origin, vec3_origin);
UTIL_RemoveImmediate( pTestHull );
pTestHull = NULL;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : &startPos -
// &endPos -
// Output : Returns true on success, false on failure.
//-----------------------------------------------------------------------------
bool CAI_TestHull::IsJumpLegal(const Vector &startPos, const Vector &apex, const Vector &endPos) const
{
const float MAX_JUMP_RISE = 1024.0f;
const float MAX_JUMP_DISTANCE = 1024.0f;
const float MAX_JUMP_DROP = 1024.0f;
return BaseClass::IsJumpLegal( startPos, apex, endPos, MAX_JUMP_RISE, MAX_JUMP_DISTANCE, MAX_JUMP_DROP );
}
//-----------------------------------------------------------------------------
// Purpose:
// Input :
// Output :
//-----------------------------------------------------------------------------
CAI_TestHull::~CAI_TestHull(void)
{
CAI_TestHull::pTestHull = NULL;
}
//###########################################################
// > CNodeEnt
//
// nodes start out as ents in the world. As they are spawned,
// the node info is recorded then the ents are discarded.
//###########################################################
//----------------------------------------------------
// Static vars
//----------------------------------------------------
int CNodeEnt::m_nNodeCount = 0;
// -------------
// Data table
// -------------
BEGIN_SIMPLE_DATADESC( HintNodeData )
DEFINE_FIELD( strEntityName, FIELD_STRING ),
// DEFINE_FIELD( vecPosition, FIELD_VECTOR ), // Don't save
DEFINE_KEYFIELD( nHintType, FIELD_SHORT, "hinttype" ),
DEFINE_KEYFIELD( strGroup, FIELD_STRING, "Group" ),
DEFINE_KEYFIELD( iDisabled, FIELD_INTEGER, "StartHintDisabled" ),
DEFINE_FIELD( nNodeID, FIELD_INTEGER ),
DEFINE_KEYFIELD( iszActivityName, FIELD_STRING, "hintactivity" ),
DEFINE_KEYFIELD( nTargetWCNodeID, FIELD_INTEGER, "TargetNode" ),
DEFINE_KEYFIELD( nWCNodeID, FIELD_INTEGER, "nodeid" ),
DEFINE_KEYFIELD( fIgnoreFacing, FIELD_INTEGER, "IgnoreFacing" ),
DEFINE_KEYFIELD( minState, FIELD_INTEGER, "MinimumState" ),
DEFINE_KEYFIELD( maxState, FIELD_INTEGER, "MaximumState" ),
END_DATADESC()
// -------------
// Data table
// -------------
BEGIN_DATADESC( CNodeEnt )
DEFINE_EMBEDDED( m_NodeData ),
END_DATADESC()
//=========================================================
//=========================================================
void CNodeEnt::Spawn( void )
{
Spawn( NULL );
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : *pMapData -
//-----------------------------------------------------------------------------
int CNodeEnt::Spawn( const char *pMapData )
{
m_NodeData.strEntityName = GetEntityName();
m_NodeData.vecPosition = GetAbsOrigin();
m_NodeData.nNodeID = NO_NODE;
if ( m_NodeData.minState == NPC_STATE_NONE )
m_NodeData.minState = NPC_STATE_IDLE;
if ( m_NodeData.maxState == NPC_STATE_NONE )
m_NodeData.maxState = NPC_STATE_COMBAT;
// ---------------------------------------------------------------------------------
// If just a hint node (not used for navigation) just create a hint and bail
// ---------------------------------------------------------------------------------
if (FClassnameIs( this, "info_hint" ))
{
if (m_NodeData.nHintType)
{
CAI_HintManager::CreateHint( &m_NodeData, pMapData );
}
else
{
Warning("info_hint (HammerID: %d, position (%.2f, %.2f, %.2f)) with no hint type.\n", m_NodeData.nWCNodeID, m_NodeData.vecPosition.x, m_NodeData.vecPosition.y, m_NodeData.vecPosition.z );
}
UTIL_RemoveImmediate( this );
return -1;
}
// ---------------------------------------------------------------------------------
// First check if this node has a hint. If so create a hint entity
// ---------------------------------------------------------------------------------
CAI_Hint *pHint = NULL;
if ( ClassMatches( "info_node_hint" ) || ClassMatches( "info_node_air_hint" ) )
{
if ( m_NodeData.nHintType || m_NodeData.strGroup != NULL_STRING || m_NodeData.strEntityName != NULL_STRING )
{
m_NodeData.nNodeID = m_nNodeCount;
pHint = CAI_HintManager::CreateHint( &m_NodeData, pMapData );
pHint->AddSpawnFlags( GetSpawnFlags() );
}
}
// ---------------------------------------------------------------------------------
// If we loaded from disk, we can discard all these node ents as soon as they spawn
// unless we are in WC edited mode
// ---------------------------------------------------------------------------------
if ( g_pAINetworkManager->NetworksLoaded() && !engine->IsInEditMode())
{
// If hint exists for this node, set it
if (pHint)
{
CAI_Node *pNode = g_pBigAINet->GetNode(m_nNodeCount);
if (pNode)
pNode->SetHint( pHint );
else
{
DevMsg("AI node graph corrupt\n");
}
}
m_nNodeCount++;
UTIL_RemoveImmediate( this );
return -1;
}
else
{
m_nNodeCount++;
}
// ---------------------------------------------------------------------------------
// Add a new node to the network
// ---------------------------------------------------------------------------------
// For now just using one big AI network
CAI_Node *new_node = g_pBigAINet->AddNode( GetAbsOrigin(), GetAbsAngles().y );
new_node->SetHint( pHint );
// -------------------------------------------------------------------------
// Update table of how each WC id relates to each engine ID
// -------------------------------------------------------------------------
if (g_pAINetworkManager->GetEditOps()->m_pNodeIndexTable)
{
g_pAINetworkManager->GetEditOps()->m_pNodeIndexTable[new_node->GetId()] = m_NodeData.nWCNodeID;
}
// Keep track of largest index used by WC
if (g_pAINetworkManager->GetEditOps()->m_nNextWCIndex <= m_NodeData.nWCNodeID)
{
g_pAINetworkManager->GetEditOps()->m_nNextWCIndex = m_NodeData.nWCNodeID+1;
}
// -------------------------------------------------------------------------
// If in WC edit mode:
// Remember the original positions of the nodes before
// they drop so we can send the undropped positions to wc.
// -------------------------------------------------------------------------
if (engine->IsInEditMode())
{
if (g_pAINetworkManager->GetEditOps()->m_pWCPosition)
{
g_pAINetworkManager->GetEditOps()->m_pWCPosition[new_node->GetId()] = new_node->GetOrigin();
}
}
if (FClassnameIs( this, "info_node_air" ) || FClassnameIs( this, "info_node_air_hint" ))
{
new_node->SetType( NODE_AIR );
}
else if (FClassnameIs( this, "info_node_climb" ))
{
new_node->SetType( NODE_CLIMB );
}
else
{
new_node->SetType( NODE_GROUND );
}
new_node->m_eNodeInfo = ( m_spawnflags << NODE_ENT_FLAGS_SHIFT );
// If changed as part of WC editing process note that network must be rebuilt
if (m_debugOverlays & OVERLAY_WC_CHANGE_ENTITY)
{
g_pAINetworkManager->GetEditOps()->SetRebuildFlags();
new_node->m_eNodeInfo |= bits_NODE_WC_CHANGED;
// Initialize the new nodes position. The graph may not be rebuild
// right away but the node should at least be positioned correctly
g_AINetworkBuilder.InitNodePosition( g_pBigAINet, new_node );
}
UTIL_RemoveImmediate( this );
return -1;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input :
// Output :
//-----------------------------------------------------------------------------
CNodeEnt::CNodeEnt( void )
{
m_debugOverlays = 0;
}

View File

@@ -1,105 +1,105 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: AI Utility classes for building the initial AI Networks
//
// $NoKeywords: $
//=============================================================================//
#ifndef AI_INITUTILS_H
#define AI_INITUTILS_H
#ifdef _WIN32
#pragma once
#endif
#include "ai_basenpc.h"
#include "ai_node.h"
//###########################################################
// >> HintNodeData
//
// This is a chunk of data that's passed to a hint node entity
// when it's created from a CNodeEnt.
//###########################################################
enum HintIgnoreFacing_t
{
HIF_NO,
HIF_YES,
HIF_DEFAULT,
};
struct HintNodeData
{
string_t strEntityName;
Vector vecPosition;
short nHintType;
int nNodeID;
string_t strGroup;
int iDisabled;
string_t iszActivityName;
int nTargetWCNodeID;
HintIgnoreFacing_t fIgnoreFacing;
NPC_STATE minState;
NPC_STATE maxState;
int nWCNodeID; // Node ID assigned by worldcraft (not same as engine!)
DECLARE_SIMPLE_DATADESC();
};
//###########################################################
// >> CNodeEnt
//
// This is the entity that is loaded in from worldcraft.
// It is only used to build the network and is deleted
// immediately
//###########################################################
class CNodeEnt : public CServerOnlyPointEntity
{
DECLARE_CLASS( CNodeEnt, CServerOnlyPointEntity );
public:
virtual void SetOwnerEntity( CBaseEntity* pOwner ) { BaseClass::SetOwnerEntity( NULL ); }
static int m_nNodeCount;
void Spawn( void );
int Spawn( const char *pMapData );
DECLARE_DATADESC();
CNodeEnt(void);
public:
HintNodeData m_NodeData;
};
//###########################################################
// >> CAI_TestHull
//
// a modelless clip hull that verifies reachable nodes by
// walking from every node to each of it's connections//
//###########################################################
class CAI_TestHull : public CAI_BaseNPC
{
DECLARE_CLASS( CAI_TestHull, CAI_BaseNPC );
private:
static CAI_TestHull* pTestHull; // Hull for testing connectivity
public:
static CAI_TestHull* GetTestHull(void); // Get the test hull
static void ReturnTestHull(void); // Return the test hull
bool bInUse;
virtual void Precache();
void Spawn(void);
virtual int ObjectCaps( void ) { return BaseClass::ObjectCaps() & ~(FCAP_ACROSS_TRANSITION|FCAP_DONT_SAVE); }
virtual bool IsJumpLegal(const Vector &startPos, const Vector &apex, const Vector &endPos) const;
~CAI_TestHull(void);
};
#endif // AI_INITUTILS_H
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: AI Utility classes for building the initial AI Networks
//
// $NoKeywords: $
//=============================================================================//
#ifndef AI_INITUTILS_H
#define AI_INITUTILS_H
#ifdef _WIN32
#pragma once
#endif
#include "ai_basenpc.h"
#include "ai_node.h"
//###########################################################
// >> HintNodeData
//
// This is a chunk of data that's passed to a hint node entity
// when it's created from a CNodeEnt.
//###########################################################
enum HintIgnoreFacing_t
{
HIF_NO,
HIF_YES,
HIF_DEFAULT,
};
struct HintNodeData
{
string_t strEntityName;
Vector vecPosition;
short nHintType;
int nNodeID;
string_t strGroup;
int iDisabled;
string_t iszActivityName;
int nTargetWCNodeID;
HintIgnoreFacing_t fIgnoreFacing;
NPC_STATE minState;
NPC_STATE maxState;
int nWCNodeID; // Node ID assigned by worldcraft (not same as engine!)
DECLARE_SIMPLE_DATADESC();
};
//###########################################################
// >> CNodeEnt
//
// This is the entity that is loaded in from worldcraft.
// It is only used to build the network and is deleted
// immediately
//###########################################################
class CNodeEnt : public CServerOnlyPointEntity
{
DECLARE_CLASS( CNodeEnt, CServerOnlyPointEntity );
public:
virtual void SetOwnerEntity( CBaseEntity* pOwner ) { BaseClass::SetOwnerEntity( NULL ); }
static int m_nNodeCount;
void Spawn( void );
int Spawn( const char *pMapData );
DECLARE_DATADESC();
CNodeEnt(void);
public:
HintNodeData m_NodeData;
};
//###########################################################
// >> CAI_TestHull
//
// a modelless clip hull that verifies reachable nodes by
// walking from every node to each of it's connections//
//###########################################################
class CAI_TestHull : public CAI_BaseNPC
{
DECLARE_CLASS( CAI_TestHull, CAI_BaseNPC );
private:
static CAI_TestHull* pTestHull; // Hull for testing connectivity
public:
static CAI_TestHull* GetTestHull(void); // Get the test hull
static void ReturnTestHull(void); // Return the test hull
bool bInUse;
virtual void Precache();
void Spawn(void);
virtual int ObjectCaps( void ) { return BaseClass::ObjectCaps() & ~(FCAP_ACROSS_TRANSITION|FCAP_DONT_SAVE); }
virtual bool IsJumpLegal(const Vector &startPos, const Vector &apex, const Vector &endPos) const;
~CAI_TestHull(void);
};
#endif // AI_INITUTILS_H

View File

@@ -1,57 +1,57 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $Workfile: $
// $Date: $
//
//-----------------------------------------------------------------------------
// $Log: $
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "ai_link.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
ASSERT_INVARIANT( ( bits_LINK_STALE_SUGGESTED | bits_LINK_OFF ) <= 255 && ( AI_MOVE_TYPE_BITS <= 255 ) );
//-----------------------------------------------------------------------------
// Purpose: Given the source node ID, returns the destination ID
// Input :
// Output :
//-----------------------------------------------------------------------------
int CAI_Link::DestNodeID(int srcID)
{
if (srcID == m_iSrcID)
{
return m_iDestID;
}
else
{
return m_iSrcID;
}
}
//-----------------------------------------------------------------------------
// Purpose: Constructor
// Input :
// Output :
//-----------------------------------------------------------------------------
CAI_Link::CAI_Link(void)
{
m_iSrcID = -1;
m_iDestID = -1;
m_LinkInfo = 0;
m_timeStaleExpires = 0;
m_pDynamicLink = NULL;
for (int hull=0;hull<NUM_HULLS;hull++)
{
m_iAcceptedMoveTypes[hull] = 0;
}
};
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $Workfile: $
// $Date: $
//
//-----------------------------------------------------------------------------
// $Log: $
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "ai_link.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
ASSERT_INVARIANT( ( bits_LINK_STALE_SUGGESTED | bits_LINK_OFF ) <= 255 && ( AI_MOVE_TYPE_BITS <= 255 ) );
//-----------------------------------------------------------------------------
// Purpose: Given the source node ID, returns the destination ID
// Input :
// Output :
//-----------------------------------------------------------------------------
int CAI_Link::DestNodeID(int srcID)
{
if (srcID == m_iSrcID)
{
return m_iDestID;
}
else
{
return m_iSrcID;
}
}
//-----------------------------------------------------------------------------
// Purpose: Constructor
// Input :
// Output :
//-----------------------------------------------------------------------------
CAI_Link::CAI_Link(void)
{
m_iSrcID = -1;
m_iDestID = -1;
m_LinkInfo = 0;
m_timeStaleExpires = 0;
m_pDynamicLink = NULL;
for (int hull=0;hull<NUM_HULLS;hull++)
{
m_iAcceptedMoveTypes[hull] = 0;
}
};

Some files were not shown because too many files have changed in this diff Show More