Fix line endings. WHAMMY.
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
@@ -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
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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 );
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 );
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 ¶ms )
|
||||
{
|
||||
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 ¶ms )
|
||||
{
|
||||
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 );
|
||||
}
|
||||
|
||||
@@ -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 ¶ms );
|
||||
|
||||
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 ¶ms );
|
||||
|
||||
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
@@ -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;
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 );
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 );
|
||||
|
||||
|
||||
|
||||
@@ -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 );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
@@ -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 ) );
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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() );
|
||||
}
|
||||
|
||||
@@ -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 );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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 );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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 ¶ms = 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 ¶ms );
|
||||
|
||||
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 ¶ms = 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 ¶ms );
|
||||
|
||||
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
@@ -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
@@ -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
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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
@@ -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 ¶ms, 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 ¶ms, 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
@@ -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
|
||||
|
||||
@@ -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
@@ -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 );
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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
@@ -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
|
||||
@@ -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 );
|
||||
}
|
||||
|
||||
|
||||
@@ -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 );
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user