This commit is contained in:
2022-09-04 13:11:00 +03:00
parent 1e58bd6836
commit 079734ddae
468 changed files with 231173 additions and 0 deletions

View File

@@ -0,0 +1,283 @@
//========= 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;
// }
#ifdef MAPBASE
virtual bool PassesDoorFilter(CBaseEntity *pEntity) { return true; }
#endif
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);
#ifdef MAPBASE
void InputAllowPlayerUse(inputdata_t &inputdata);
void InputDisallowPlayerUse(inputdata_t &inputdata);
#endif
void SetDoorBlocker( CBaseEntity *pBlocker );
void SetMaster( CBasePropDoor *pMaster ) { m_hMaster = pMaster; }
void CalcDoorSounds();
// }
int m_nHardwareType;
DoorState_t m_eDoorState; // Holds whether the door is open, closed, opening, or closing.
locksound_t m_ls; // The sounds the door plays when being locked, unlocked, etc.
EHANDLE m_hActivator;
bool m_bLocked; // True if the door is locked.
EHANDLE m_hBlocker; // Entity blocking the door currently
bool m_bFirstBlocked; // Marker for being the first door (in a group) to be blocked (needed for motion control)
bool m_bForceClosed; // True if this door must close no matter what.
string_t m_SoundMoving;
string_t m_SoundOpen;
string_t m_SoundClose;
// dvs: FIXME: can we remove m_flSpeed from CBaseEntity?
//float m_flSpeed; // Rotation speed when opening or closing in degrees per second.
DECLARE_DATADESC();
string_t m_SlaveName;
CHandle< CBasePropDoor > m_hMaster;
static void RegisterPrivateActivities();
// Outputs
COutputEvent m_OnBlockedClosing; // Triggered when the door becomes blocked while closing.
COutputEvent m_OnBlockedOpening; // Triggered when the door becomes blocked while opening.
COutputEvent m_OnUnblockedClosing; // Triggered when the door becomes unblocked while closing.
COutputEvent m_OnUnblockedOpening; // Triggered when the door becomes unblocked while opening.
COutputEvent m_OnFullyClosed; // Triggered when the door reaches the fully closed position.
COutputEvent m_OnFullyOpen; // Triggered when the door reaches the fully open position.
COutputEvent m_OnClose; // Triggered when the door is told to close.
COutputEvent m_OnOpen; // Triggered when the door is told to open.
COutputEvent m_OnLockedUse; // Triggered when the user tries to open a locked door.
};
void CBasePropDoor::SetDoorState( DoorState_t eDoorState )
{
m_eDoorState = eDoorState;
}
bool CBasePropDoor::IsDoorOpen()
{
return m_eDoorState == DOOR_STATE_OPEN;
}
bool CBasePropDoor::IsDoorAjar()
{
return ( m_eDoorState == DOOR_STATE_AJAR );
}
bool CBasePropDoor::IsDoorOpening()
{
return m_eDoorState == DOOR_STATE_OPENING;
}
bool CBasePropDoor::IsDoorClosed()
{
return m_eDoorState == DOOR_STATE_CLOSED;
}
bool CBasePropDoor::IsDoorClosing()
{
return m_eDoorState == DOOR_STATE_CLOSING;
}
bool CBasePropDoor::IsDoorLocked()
{
return m_bLocked;
}
CBaseEntity *CBasePropDoor::GetActivator()
{
return m_hActivator;
}
bool CBasePropDoor::IsDoorBlocked() const
{
return ( m_hBlocker != NULL );
}
bool CBasePropDoor::IsNPCOpening( CAI_BaseNPC *pNPC )
{
return ( pNPC == ( CAI_BaseNPC * )GetActivator() );
}
inline bool CBasePropDoor::IsPlayerOpening()
{
return ( GetActivator() && GetActivator()->IsPlayer() );
}
inline bool CBasePropDoor::IsOpener(CBaseEntity *pEnt)
{
return ( GetActivator() == pEnt );
}
#endif // BASEPROPDOOR_H

View File

@@ -0,0 +1,267 @@
//========= 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" ),
#ifdef MAPBASE
DEFINE_KEYFIELD( m_BoneTarget, FIELD_STRING, "BoneTarget" ),
#endif
DEFINE_INPUTFUNC( FIELD_VOID, "Enable", InputEnable ),
DEFINE_INPUTFUNC( FIELD_VOID, "Disable", InputDisable ),
#ifdef MAPBASE
DEFINE_OUTPUT( m_OnUsed, "OnUsed" ),
#endif
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.
//-----------------------------------------------------------------------------
#ifdef MAPBASE
Vector CRagdollMagnet::GetForceVector( CBaseEntity *pNPC, int *pBone )
#else
Vector CRagdollMagnet::GetForceVector( CBaseEntity *pNPC )
#endif
{
Vector vecForceToApply;
#ifdef MAPBASE
Vector vecNPCPos = pNPC->WorldSpaceCenter();
if (pBone)
{
CBaseAnimating *pAnimating = pNPC->GetBaseAnimating();
Assert( pAnimating != NULL );
const char *szBoneTarget = BoneTarget();
Assert( szBoneTarget != NULL );
int iBone = pAnimating->LookupBone( szBoneTarget );
if (iBone != -1)
{
matrix3x4_t bonetoworld;
pAnimating->GetBoneTransform( iBone, bonetoworld );
MatrixPosition( bonetoworld, vecNPCPos );
*pBone = iBone;
}
}
#endif
if( IsBarMagnet() )
{
CPlane axis;
Vector vecForceDir;
Vector vecClosest;
#ifdef MAPBASE
CalcClosestPointOnLineSegment( vecNPCPos, GetAbsOrigin(), m_axis, vecClosest, NULL );
vecForceDir = (vecClosest - vecNPCPos );
VectorNormalize( vecForceDir );
#else
CalcClosestPointOnLineSegment( pNPC->WorldSpaceCenter(), GetAbsOrigin(), m_axis, vecClosest, NULL );
vecForceDir = (vecClosest - pNPC->WorldSpaceCenter() );
VectorNormalize( vecForceDir );
#endif
vecForceToApply = vecForceDir * m_force;
}
else
{
Vector vecForce;
#ifdef MAPBASE
vecForce = GetAbsOrigin() - vecNPCPos;
#else
vecForce = GetAbsOrigin() - pNPC->WorldSpaceCenter();
#endif
VectorNormalize( vecForce );
vecForceToApply = vecForce * m_force;
}
if( ai_debug_ragdoll_magnets.GetBool() )
{
IPhysicsObject *pPhysObject;
pPhysObject = pNPC->VPhysicsGetObject();
if( pPhysObject )
{
Msg("Ragdoll magnet adding %f inches/sec to %s\n", m_force/pPhysObject->GetMass(), pNPC->GetClassname() );
}
}
return vecForceToApply;
}
//-----------------------------------------------------------------------------
// Purpose: How far away is this point? This is different for point and bar magnets
// Input : &vecPoint - the point
// Output : float - the dist
//-----------------------------------------------------------------------------
float CRagdollMagnet::DistToPoint( const Vector &vecPoint )
{
if( IsBarMagnet() )
{
// I'm a bar magnet, so the point's distance is really the plane constant.
// A bar magnet is a cylinder who's length is AbsOrigin() to m_axis, and whose
// diameter is m_radius.
// first we build two planes. The TOP and BOTTOM planes.
// the idea is that vecPoint must be on the right side of both
// planes to be affected by this particular magnet.
// TOP and BOTTOM planes can be visualized as the 'caps' of the cylinder
// that describes the bar magnet, and they point towards each other.
// We're making sure vecPoint is between the caps.
Vector vecAxis;
vecAxis = GetAxisVector();
VectorNormalize( vecAxis );
CPlane top, bottom;
bottom.InitializePlane( -vecAxis, m_axis );
top.InitializePlane( vecAxis, GetAbsOrigin() );
if( top.PointInFront( vecPoint ) && bottom.PointInFront( vecPoint ) )
{
// This point is between the two caps, so calculate the distance
// of vecPoint from the axis of the bar magnet
CPlane axis;
Vector vecUp;
Vector vecRight;
// Horizontal and Vertical distances.
float hDist, vDist;
// Need to get a vector that's right-hand to m_axis
VectorVectors( vecAxis, vecRight, vecUp );
//CrossProduct( vecAxis, vecUp, vecRight );
//VectorNormalize( vecRight );
//VectorNormalize( vecUp );
// Set up the plane to measure horizontal dist.
axis.InitializePlane( vecRight, GetAbsOrigin() );
hDist = fabs( axis.PointDist( vecPoint ) );
axis.InitializePlane( vecUp, GetAbsOrigin() );
vDist = fabs( axis.PointDist( vecPoint ) );
return MAX( hDist, vDist );
}
else
{
return FLT_MAX;
}
}
else
{
// I'm a point magnet. Just return dist
return ( GetAbsOrigin() - vecPoint ).Length();
}
}

View File

@@ -0,0 +1,58 @@
//========= 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();
#ifdef MAPBASE
Vector GetForceVector( CBaseEntity *pNPC, int *pBone = NULL );
#else
Vector GetForceVector( CBaseEntity *pNPC );
#endif
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 );
#ifdef MAPBASE
const char *BoneTarget() { return STRING(m_BoneTarget); }
COutputVector m_OnUsed;
#endif
private:
bool m_bDisabled;
float m_radius;
float m_force;
Vector m_axis;
#ifdef MAPBASE
string_t m_BoneTarget;
#endif
};
#endif //CRAGDOLLMAGNET_H

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +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;
}

View File

@@ -0,0 +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 );
}

View File

@@ -0,0 +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

View File

@@ -0,0 +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 );
}

View File

@@ -0,0 +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

View File

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

View File

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

View File

@@ -0,0 +1,826 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Implements visual effects entities: sprites, beams, bubbles, etc.
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "beam_shared.h"
#include "ndebugoverlay.h"
#include "filters.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
// Keeps us from doing strcmps in the tracefilter.
string_t g_iszPhysicsPropClassname;
enum Touch_t
{
touch_none = 0,
touch_player_only,
touch_npc_only,
touch_player_or_npc,
touch_player_or_npc_or_physicsprop,
};
class CEnvBeam : public CBeam
{
public:
DECLARE_CLASS( CEnvBeam, CBeam );
void Spawn( void );
void Precache( void );
void Activate( void );
void StrikeThink( void );
void UpdateThink( void );
void RandomArea( void );
void RandomPoint( const Vector &vecSrc );
void Zap( const Vector &vecSrc, const Vector &vecDest );
void Strike( void );
bool PassesTouchFilters(CBaseEntity *pOther);
void InputTurnOn( inputdata_t &inputdata );
void InputTurnOff( inputdata_t &inputdata );
void InputToggle( inputdata_t &inputdata );
void InputStrikeOnce( inputdata_t &inputdata );
#ifdef MAPBASE
void InputAmplitude( inputdata_t &inputdata );
void InputSetStartEntity( inputdata_t &inputdata ) { m_iszStartEntity = inputdata.value.StringID(); BeamUpdateVars(); }
void InputSetEndEntity( inputdata_t &inputdata ) { m_iszEndEntity = inputdata.value.StringID(); BeamUpdateVars(); }
#endif
void TurnOn( void );
void TurnOff( void );
void Toggle( void );
const char *GetDecalName( void ){ return STRING( m_iszDecal );}
inline bool ServerSide( void )
{
if ( m_life == 0 && !HasSpawnFlags(SF_BEAM_RING) )
return true;
return false;
}
DECLARE_DATADESC();
void BeamUpdateVars( void );
int m_active;
int m_spriteTexture;
string_t m_iszStartEntity;
string_t m_iszEndEntity;
float m_life;
float m_boltWidth;
float m_noiseAmplitude;
int m_speed;
float m_restrike;
string_t m_iszSpriteName;
int m_frameStart;
float m_radius;
Touch_t m_TouchType;
string_t m_iFilterName;
EHANDLE m_hFilter;
string_t m_iszDecal;
COutputEvent m_OnTouchedByEntity;
};
LINK_ENTITY_TO_CLASS( env_beam, CEnvBeam );
BEGIN_DATADESC( CEnvBeam )
DEFINE_FIELD( m_active, FIELD_INTEGER ),
DEFINE_FIELD( m_spriteTexture, FIELD_INTEGER ),
DEFINE_KEYFIELD( m_iszStartEntity, FIELD_STRING, "LightningStart" ),
DEFINE_KEYFIELD( m_iszEndEntity, FIELD_STRING, "LightningEnd" ),
DEFINE_KEYFIELD( m_life, FIELD_FLOAT, "life" ),
DEFINE_KEYFIELD( m_boltWidth, FIELD_FLOAT, "BoltWidth" ),
DEFINE_KEYFIELD( m_noiseAmplitude, FIELD_FLOAT, "NoiseAmplitude" ),
DEFINE_KEYFIELD( m_speed, FIELD_INTEGER, "TextureScroll" ),
DEFINE_KEYFIELD( m_restrike, FIELD_FLOAT, "StrikeTime" ),
DEFINE_KEYFIELD( m_iszSpriteName, FIELD_STRING, "texture" ),
DEFINE_KEYFIELD( m_frameStart, FIELD_INTEGER, "framestart" ),
DEFINE_KEYFIELD( m_radius, FIELD_FLOAT, "Radius" ),
DEFINE_KEYFIELD( m_TouchType, FIELD_INTEGER, "TouchType" ),
DEFINE_KEYFIELD( m_iFilterName, FIELD_STRING, "filtername" ),
DEFINE_KEYFIELD( m_iszDecal, FIELD_STRING, "decalname" ),
DEFINE_FIELD( m_hFilter, FIELD_EHANDLE ),
// Function Pointers
DEFINE_FUNCTION( StrikeThink ),
DEFINE_FUNCTION( UpdateThink ),
// Input functions
DEFINE_INPUTFUNC( FIELD_VOID, "TurnOn", InputTurnOn ),
DEFINE_INPUTFUNC( FIELD_VOID, "TurnOff", InputTurnOff ),
DEFINE_INPUTFUNC( FIELD_VOID, "Toggle", InputToggle ),
DEFINE_INPUTFUNC( FIELD_VOID, "StrikeOnce", InputStrikeOnce ),
#ifdef MAPBASE
DEFINE_INPUTFUNC( FIELD_FLOAT, "Amplitude", InputAmplitude ),
DEFINE_INPUTFUNC( FIELD_STRING, "SetStartEntity", InputSetStartEntity ),
DEFINE_INPUTFUNC( FIELD_STRING, "SetEndEntity", InputSetEndEntity ),
#endif
DEFINE_OUTPUT( m_OnTouchedByEntity, "OnTouchedByEntity" ),
END_DATADESC()
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CEnvBeam::Spawn( void )
{
if ( !m_iszSpriteName )
{
SetThink( &CEnvBeam::SUB_Remove );
return;
}
BaseClass::Spawn();
m_noiseAmplitude = MIN(MAX_BEAM_NOISEAMPLITUDE, m_noiseAmplitude);
// Check for tapering
if ( HasSpawnFlags( SF_BEAM_TAPEROUT ) )
{
SetWidth( m_boltWidth );
SetEndWidth( 0 );
}
else
{
SetWidth( m_boltWidth );
SetEndWidth( GetWidth() ); // Note: EndWidth is not scaled
}
if ( ServerSide() )
{
SetThink( &CEnvBeam::UpdateThink );
SetNextThink( gpGlobals->curtime );
SetFireTime( gpGlobals->curtime );
if ( GetEntityName() != NULL_STRING )
{
if ( !(m_spawnflags & SF_BEAM_STARTON) )
{
AddEffects( EF_NODRAW );
m_active = 0;
SetNextThink( TICK_NEVER_THINK );
}
else
{
m_active = 1;
}
}
}
else
{
m_active = 0;
if ( !GetEntityName() || FBitSet(m_spawnflags, SF_BEAM_STARTON) )
{
SetThink( &CEnvBeam::StrikeThink );
SetNextThink( gpGlobals->curtime + 1.0f );
}
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CEnvBeam::Precache( void )
{
if ( !Q_stristr( STRING(m_iszSpriteName), ".vmt" ) )
{
// HACK/YWB: This was almost always the laserbeam.spr, so alloc'ing the name a second time with the proper extension isn't going to
// kill us on memrory.
//Warning( "Level Design Error: %s (%i:%s) Sprite name (%s) missing .vmt extension!\n",
// STRING( m_iClassname ), entindex(), GetEntityName(), STRING(m_iszSpriteName) );
char fixedname[ 512 ];
Q_strncpy( fixedname, STRING( m_iszSpriteName ), sizeof( fixedname ) );
Q_SetExtension( fixedname, ".vmt", sizeof( fixedname ) );
m_iszSpriteName = AllocPooledString( fixedname );
}
g_iszPhysicsPropClassname = AllocPooledString( "prop_physics" );
m_spriteTexture = PrecacheModel( STRING(m_iszSpriteName) );
BaseClass::Precache();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CEnvBeam::Activate( void )
{
// Get a handle to my filter entity if there is one
if (m_iFilterName != NULL_STRING)
{
m_hFilter = dynamic_cast<CBaseFilter *>(gEntList.FindEntityByName( NULL, m_iFilterName ));
}
BaseClass::Activate();
if ( ServerSide() )
BeamUpdateVars();
}
//-----------------------------------------------------------------------------
// Purpose: Input handler to turn the lightning on either continually or for
// interval refiring.
//-----------------------------------------------------------------------------
void CEnvBeam::InputTurnOn( inputdata_t &inputdata )
{
if ( !m_active )
{
TurnOn();
}
}
//-----------------------------------------------------------------------------
// Purpose: Input handler to turn the lightning off.
//-----------------------------------------------------------------------------
void CEnvBeam::InputTurnOff( inputdata_t &inputdata )
{
if ( m_active )
{
TurnOff();
}
}
//-----------------------------------------------------------------------------
// Purpose: Input handler to toggle the lightning on/off.
//-----------------------------------------------------------------------------
void CEnvBeam::InputToggle( inputdata_t &inputdata )
{
if ( m_active )
{
TurnOff();
}
else
{
TurnOn();
}
}
//-----------------------------------------------------------------------------
// Purpose: Input handler for making the beam strike once. This will not affect
// any interval refiring that might be going on. If the lifetime is set
// to zero (infinite) it will turn on and stay on.
//-----------------------------------------------------------------------------
void CEnvBeam::InputStrikeOnce( inputdata_t &inputdata )
{
Strike();
}
#ifdef MAPBASE
//-----------------------------------------------------------------------------
// Purpose: Input handler for amplitude
//-----------------------------------------------------------------------------
void CEnvBeam::InputAmplitude( inputdata_t &inputdata )
{
m_noiseAmplitude = inputdata.value.Float();
}
#endif
//-----------------------------------------------------------------------------
// Purpose: Turns the lightning on. If it is set for interval refiring, it will
// begin doing so. If it is set to be continually on, it will do so.
//-----------------------------------------------------------------------------
void CEnvBeam::TurnOn( void )
{
m_active = 1;
if ( ServerSide() )
{
RemoveEffects( EF_NODRAW );
DoSparks( GetAbsStartPos(), GetAbsEndPos() );
SetThink( &CEnvBeam::UpdateThink );
SetNextThink( gpGlobals->curtime );
SetFireTime( gpGlobals->curtime );
}
else
{
SetThink( &CEnvBeam::StrikeThink );
SetNextThink( gpGlobals->curtime );
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CEnvBeam::TurnOff( void )
{
m_active = 0;
if ( ServerSide() )
{
AddEffects( EF_NODRAW );
}
SetNextThink( TICK_NEVER_THINK );
SetThink( NULL );
}
//-----------------------------------------------------------------------------
// Purpose: Think function for striking at intervals.
//-----------------------------------------------------------------------------
void CEnvBeam::StrikeThink( void )
{
if ( m_life != 0 )
{
if ( m_spawnflags & SF_BEAM_RANDOM )
SetNextThink( gpGlobals->curtime + m_life + random->RandomFloat( 0, m_restrike ) );
else
SetNextThink( gpGlobals->curtime + m_life + m_restrike );
}
m_active = 1;
if (!m_iszEndEntity)
{
if (!m_iszStartEntity)
{
RandomArea( );
}
else
{
CBaseEntity *pStart = RandomTargetname( STRING(m_iszStartEntity) );
if (pStart != NULL)
{
RandomPoint( pStart->GetAbsOrigin() );
}
else
{
Msg( "env_beam: unknown entity \"%s\"\n", STRING(m_iszStartEntity) );
}
}
return;
}
Strike();
}
//-----------------------------------------------------------------------------
// Purpose: Strikes once for its configured lifetime.
//-----------------------------------------------------------------------------
void CEnvBeam::Strike( void )
{
CBroadcastRecipientFilter filter;
CBaseEntity *pStart = RandomTargetname( STRING(m_iszStartEntity) );
CBaseEntity *pEnd = RandomTargetname( STRING(m_iszEndEntity) );
if ( pStart == NULL || pEnd == NULL )
return;
m_speed = clamp( (int) m_speed, 0, (int) MAX_BEAM_SCROLLSPEED );
#ifdef MAPBASE
bool pointStart = IsStaticPointEntity( pStart );
bool pointEnd = IsStaticPointEntity( pEnd );
#else
int pointStart = IsStaticPointEntity( pStart );
int pointEnd = IsStaticPointEntity( pEnd );
#endif
if ( pointStart || pointEnd )
{
#ifdef MAPBASE
if ( m_spawnflags & SF_BEAM_RING )
{
te->BeamRing( filter, 0.0,
pStart->entindex(),
pEnd->entindex(),
m_spriteTexture,
0, // No halo
m_frameStart,
(int)m_flFrameRate,
m_life,
m_boltWidth,
0, // No spread
m_noiseAmplitude,
m_clrRender->r, m_clrRender->g, m_clrRender->b, m_clrRender->a,
m_speed );
}
else
{
te->BeamEntPoint( filter, 0.0,
pStart->entindex(),
&pStart->GetAbsOrigin(),
pEnd->entindex(),
&pEnd->GetAbsOrigin(),
m_spriteTexture,
0, // No halo
m_frameStart,
(int)m_flFrameRate,
m_life,
m_boltWidth,
m_boltWidth, // End width
0, // No fade
m_noiseAmplitude,
m_clrRender->r, m_clrRender->g, m_clrRender->b, m_clrRender->a,
m_speed );
}
#else
if ( m_spawnflags & SF_BEAM_RING )
{
// don't work
return;
}
te->BeamEntPoint( filter, 0.0,
pointStart ? 0 : pStart->entindex(),
pointStart ? &pStart->GetAbsOrigin() : NULL,
pointEnd ? 0 : pEnd->entindex(),
pointEnd ? &pEnd->GetAbsOrigin() : NULL,
m_spriteTexture,
0, // No halo
m_frameStart,
(int)m_flFrameRate,
m_life,
m_boltWidth,
m_boltWidth, // End width
0, // No fade
m_noiseAmplitude,
m_clrRender->r, m_clrRender->g, m_clrRender->b, m_clrRender->a,
m_speed );
#endif
}
else
{
if ( m_spawnflags & SF_BEAM_RING)
{
te->BeamRing( filter, 0.0,
pStart->entindex(),
pEnd->entindex(),
m_spriteTexture,
0, // No halo
m_frameStart,
(int)m_flFrameRate,
m_life,
m_boltWidth,
0, // No spread
m_noiseAmplitude,
m_clrRender->r,
m_clrRender->g,
m_clrRender->b,
m_clrRender->a,
m_speed );
}
else
{
te->BeamEnts( filter, 0.0,
pStart->entindex(),
pEnd->entindex(),
m_spriteTexture,
0, // No halo
m_frameStart,
(int)m_flFrameRate,
m_life,
m_boltWidth,
m_boltWidth, // End width
0, // No fade
m_noiseAmplitude,
m_clrRender->r,
m_clrRender->g,
m_clrRender->b,
m_clrRender->a,
m_speed );
}
}
DoSparks( pStart->GetAbsOrigin(), pEnd->GetAbsOrigin() );
if ( m_flDamage > 0 )
{
trace_t tr;
UTIL_TraceLine( pStart->GetAbsOrigin(), pEnd->GetAbsOrigin(), MASK_SOLID, NULL, COLLISION_GROUP_NONE, &tr );
BeamDamageInstant( &tr, m_flDamage );
}
}
class CTraceFilterPlayersNPCs : public ITraceFilter
{
public:
bool ShouldHitEntity( IHandleEntity *pServerEntity, int contentsMask )
{
CBaseEntity *pEntity = EntityFromEntityHandle( pServerEntity );
if ( pEntity )
{
if ( pEntity->IsPlayer() || pEntity->MyNPCPointer() )
return true;
}
return false;
}
virtual TraceType_t GetTraceType() const
{
return TRACE_ENTITIES_ONLY;
}
};
class CTraceFilterPlayersNPCsPhysicsProps : public ITraceFilter
{
public:
bool ShouldHitEntity( IHandleEntity *pServerEntity, int contentsMask )
{
CBaseEntity *pEntity = EntityFromEntityHandle( pServerEntity );
if ( pEntity )
{
if ( pEntity->IsPlayer() || pEntity->MyNPCPointer() || pEntity->m_iClassname == g_iszPhysicsPropClassname )
return true;
}
return false;
}
virtual TraceType_t GetTraceType() const
{
return TRACE_ENTITIES_ONLY;
}
};
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
bool CEnvBeam::PassesTouchFilters(CBaseEntity *pOther)
{
bool fPassedSoFar = false;
// Touched some player or NPC!
if( m_TouchType != touch_npc_only )
{
if( pOther->IsPlayer() )
{
fPassedSoFar = true;
}
}
if( m_TouchType != touch_player_only )
{
if( pOther->IsNPC() )
{
fPassedSoFar = true;
}
}
if( m_TouchType == touch_player_or_npc_or_physicsprop )
{
if( pOther->m_iClassname == g_iszPhysicsPropClassname )
{
fPassedSoFar = true;
}
}
if( fPassedSoFar )
{
CBaseFilter* pFilter = (CBaseFilter*)(m_hFilter.Get());
return (!pFilter) ? true : pFilter->PassesFilter( this, pOther );
}
return false;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CEnvBeam::UpdateThink( void )
{
// Apply damage every 1/10th of a second.
if ( ( m_flDamage > 0 ) && ( gpGlobals->curtime >= m_flFireTime + 0.1 ) )
{
trace_t tr;
UTIL_TraceLine( GetAbsStartPos(), GetAbsEndPos(), MASK_SOLID, NULL, COLLISION_GROUP_NONE, &tr );
BeamDamage( &tr );
// BeamDamage calls RelinkBeam, so no need to call it again.
}
else
{
RelinkBeam();
}
if( m_TouchType != touch_none )
{
trace_t tr;
Ray_t ray;
ray.Init( GetAbsStartPos(), GetAbsEndPos() );
if( m_TouchType == touch_player_or_npc_or_physicsprop )
{
CTraceFilterPlayersNPCsPhysicsProps traceFilter;
enginetrace->TraceRay( ray, MASK_SHOT, &traceFilter, &tr );
}
else
{
CTraceFilterPlayersNPCs traceFilter;
enginetrace->TraceRay( ray, MASK_SHOT, &traceFilter, &tr );
}
if( tr.fraction != 1.0 && PassesTouchFilters( tr.m_pEnt ) )
{
m_OnTouchedByEntity.FireOutput( tr.m_pEnt, this, 0 );
return;
}
}
SetNextThink( gpGlobals->curtime );
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : &vecSrc -
// &vecDest -
//-----------------------------------------------------------------------------
void CEnvBeam::Zap( const Vector &vecSrc, const Vector &vecDest )
{
CBroadcastRecipientFilter filter;
te->BeamPoints( filter, 0.0,
&vecSrc,
&vecDest,
m_spriteTexture,
0, // No halo
m_frameStart,
(int)m_flFrameRate,
m_life,
m_boltWidth,
m_boltWidth, // End width
0, // No fade
m_noiseAmplitude,
m_clrRender->r,
m_clrRender->g,
m_clrRender->b,
m_clrRender->a,
m_speed );
DoSparks( vecSrc, vecDest );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CEnvBeam::RandomArea( void )
{
int iLoops = 0;
for (iLoops = 0; iLoops < 10; iLoops++)
{
Vector vecSrc = GetAbsOrigin();
Vector vecDir1 = Vector( random->RandomFloat( -1.0, 1.0 ), random->RandomFloat( -1.0, 1.0 ),random->RandomFloat( -1.0, 1.0 ) );
VectorNormalize( vecDir1 );
trace_t tr1;
UTIL_TraceLine( vecSrc, vecSrc + vecDir1 * m_radius, MASK_SOLID_BRUSHONLY, this, COLLISION_GROUP_NONE, &tr1 );
if (tr1.fraction == 1.0)
continue;
Vector vecDir2;
do {
vecDir2 = Vector( random->RandomFloat( -1.0, 1.0 ), random->RandomFloat( -1.0, 1.0 ),random->RandomFloat( -1.0, 1.0 ) );
} while (DotProduct(vecDir1, vecDir2 ) > 0);
VectorNormalize( vecDir2 );
trace_t tr2;
UTIL_TraceLine( vecSrc, vecSrc + vecDir2 * m_radius, MASK_SOLID_BRUSHONLY, this, COLLISION_GROUP_NONE, &tr2 );
if (tr2.fraction == 1.0)
continue;
if ((tr1.endpos - tr2.endpos).Length() < m_radius * 0.1)
continue;
UTIL_TraceLine( tr1.endpos, tr2.endpos, MASK_SOLID_BRUSHONLY, this, COLLISION_GROUP_NONE, &tr2 );
if (tr2.fraction != 1.0)
continue;
Zap( tr1.endpos, tr2.endpos );
break;
}
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : vecSrc -
//-----------------------------------------------------------------------------
void CEnvBeam::RandomPoint( const Vector &vecSrc )
{
int iLoops = 0;
for (iLoops = 0; iLoops < 10; iLoops++)
{
Vector vecDir1 = Vector( random->RandomFloat( -1.0, 1.0 ), random->RandomFloat( -1.0, 1.0 ),random->RandomFloat( -1.0, 1.0 ) );
VectorNormalize( vecDir1 );
trace_t tr1;
UTIL_TraceLine( vecSrc, vecSrc + vecDir1 * m_radius, MASK_SOLID_BRUSHONLY, this, COLLISION_GROUP_NONE, &tr1 );
if ((tr1.endpos - vecSrc).Length() < m_radius * 0.1)
continue;
if (tr1.fraction == 1.0)
continue;
Zap( vecSrc, tr1.endpos );
break;
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CEnvBeam::BeamUpdateVars( void )
{
CBaseEntity *pStart = gEntList.FindEntityByName( NULL, m_iszStartEntity );
CBaseEntity *pEnd = gEntList.FindEntityByName( NULL, m_iszEndEntity );
if (( pStart == NULL ) || ( pEnd == NULL ))
{
return;
}
m_nNumBeamEnts = 2;
m_speed = clamp( (int) m_speed, 0, (int) MAX_BEAM_SCROLLSPEED );
// NOTE: If the end entity is the beam itself (and the start entity
// isn't *also* the beam itself, we've got problems. This is a problem
// because SetAbsStartPos actually sets the entity's origin.
if ( ( pEnd == this ) && ( pStart != this ) )
{
DevMsg("env_beams cannot have the end entity be the beam itself\n"
"unless the start entity is also the beam itself!\n" );
Assert(0);
}
SetModelName( m_iszSpriteName );
SetTexture( m_spriteTexture );
SetType( BEAM_ENTPOINT );
if ( IsStaticPointEntity( pStart ) )
{
SetAbsStartPos( pStart->GetAbsOrigin() );
}
else
{
SetStartEntity( pStart );
}
if ( IsStaticPointEntity( pEnd ) )
{
SetAbsEndPos( pEnd->GetAbsOrigin() );
}
else
{
SetEndEntity( pEnd );
}
RelinkBeam();
SetWidth( MIN(MAX_BEAM_WIDTH, m_boltWidth) );
SetNoise( MIN(MAX_BEAM_NOISEAMPLITUDE, m_noiseAmplitude) );
SetFrame( m_frameStart );
SetScrollRate( m_speed );
if ( m_spawnflags & SF_BEAM_SHADEIN )
{
SetBeamFlags( FBEAM_SHADEIN );
}
else if ( m_spawnflags & SF_BEAM_SHADEOUT )
{
SetBeamFlags( FBEAM_SHADEOUT );
}
}

View File

@@ -0,0 +1,214 @@
//========= 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
#ifdef MAPBASE
#define SF_FADE_DONT_PURGE 0x0016
#endif
//-----------------------------------------------------------------------------
// 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;
}
#ifdef MAPBASE
if ( !HasSpawnFlags(SF_FADE_DONT_PURGE) )
{
fadeFlags |= FFADE_PURGE;
}
#endif
if ( m_spawnflags & SF_FADE_ONLYONE )
{
if ( inputdata.pActivator && inputdata.pActivator->IsNetClient() )
{
UTIL_ScreenFade( inputdata.pActivator, m_clrRender, Duration(), HoldTime(), fadeFlags );
}
}
else
{
#ifdef MAPBASE
UTIL_ScreenFadeAll( m_clrRender, Duration(), HoldTime(), fadeFlags );
#else
UTIL_ScreenFadeAll( m_clrRender, Duration(), HoldTime(), fadeFlags|FFADE_PURGE );
#endif
}
m_OnBeginFade.FireOutput( inputdata.pActivator, this );
}
//-----------------------------------------------------------------------------
// Purpose: Fetches the arguments from the command line for the fadein and fadeout
// console commands.
// Input : flTime - Returns the fade time in seconds (the time to fade in or out)
// clrFade - Returns the color to fade to or from.
//-----------------------------------------------------------------------------
static void GetFadeParms( const CCommand &args, float &flTime, color32 &clrFade)
{
flTime = 2.0f;
if ( args.ArgC() > 1 )
{
flTime = atof( args[1] );
}
clrFade.r = 0;
clrFade.g = 0;
clrFade.b = 0;
clrFade.a = 255;
if ( args.ArgC() > 4 )
{
clrFade.r = atoi( args[2] );
clrFade.g = atoi( args[3] );
clrFade.b = atoi( args[4] );
if ( args.ArgC() == 5 )
{
clrFade.a = atoi( args[5] );
}
}
}
//-----------------------------------------------------------------------------
// Purpose: Console command to fade out to a given color.
//-----------------------------------------------------------------------------
static void CC_FadeOut( const CCommand &args )
{
float flTime;
color32 clrFade;
GetFadeParms( args, flTime, clrFade );
CBasePlayer *pPlayer = UTIL_GetCommandClient();
UTIL_ScreenFade( pPlayer, clrFade, flTime, 0, FFADE_OUT | FFADE_PURGE | FFADE_STAYOUT );
}
static ConCommand fadeout("fadeout", CC_FadeOut, "fadeout {time r g b}: Fades the screen to black or to the specified color over the given number of seconds.", FCVAR_CHEAT );
//-----------------------------------------------------------------------------
// Purpose: Console command to fade in from a given color.
//-----------------------------------------------------------------------------
static void CC_FadeIn( const CCommand &args )
{
float flTime;
color32 clrFade;
GetFadeParms( args, flTime, clrFade );
CBasePlayer *pPlayer = UTIL_GetCommandClient();
UTIL_ScreenFade( pPlayer, clrFade, flTime, 0, FFADE_IN | FFADE_PURGE );
}
static ConCommand fadein("fadein", CC_FadeIn, "fadein {time r g b}: Fades the screen in from black or from the specified color over the given number of seconds.", FCVAR_CHEAT );
//-----------------------------------------------------------------------------
// Purpose: Draw any debug text overlays
// Output : Current text offset from the top
//-----------------------------------------------------------------------------
int CEnvFade::DrawDebugTextOverlays( void )
{
int text_offset = BaseClass::DrawDebugTextOverlays();
if (m_debugOverlays & OVERLAY_TEXT_BIT)
{
char tempstr[512];
// print duration
Q_snprintf(tempstr,sizeof(tempstr)," duration: %f", m_Duration);
EntityText(text_offset,tempstr,0);
text_offset++;
// print hold time
Q_snprintf(tempstr,sizeof(tempstr)," hold time: %f", m_HoldTime);
EntityText(text_offset,tempstr,0);
text_offset++;
}
return text_offset;
}

View File

@@ -0,0 +1,157 @@
//========= 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 );
#ifdef MAPBASE
void InputSetHudHint( inputdata_t &inputdata );
#endif
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 ),
#ifdef MAPBASE
DEFINE_INPUTFUNC( FIELD_STRING, "SetHudHint", InputSetHudHint ),
#endif
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();
}
}
#ifdef MAPBASE
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CEnvHudHint::InputSetHudHint( inputdata_t &inputdata )
{
m_iszMessage = inputdata.value.StringID();
}
#endif

View File

@@ -0,0 +1,260 @@
//========= 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 ),
#ifdef MAPBASE
DEFINE_OUTPUT( m_OnTouchedByEntity, "OnTouchedByEntity" ),
#endif
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 )
{
#ifdef MAPBASE
if ( tr.fraction != 1.0 && tr.m_pEnt && !tr.m_pEnt->IsWorld() )
{
m_OnTouchedByEntity.FireOutput( tr.m_pEnt, this );
}
#endif
BeamDamage( &tr );
DoSparks( GetAbsStartPos(), tr.endpos );
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CEnvLaser::StrikeThink( void )
{
CBaseEntity *pEnd = RandomTargetname( STRING( m_iszLaserTarget ) );
Vector vecFireAt = GetAbsEndPos();
if ( pEnd )
{
vecFireAt = pEnd->GetAbsOrigin();
}
trace_t tr;
UTIL_TraceLine( GetAbsOrigin(), vecFireAt, MASK_SOLID, NULL, COLLISION_GROUP_NONE, &tr );
FireAtPoint( tr );
SetNextThink( gpGlobals->curtime );
}

View File

@@ -0,0 +1,58 @@
//========= 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 );
#ifdef MAPBASE
void InputSetTarget( inputdata_t &inputdata ) { m_iszLaserTarget = inputdata.value.StringID(); }
#endif
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;
#ifdef MAPBASE
COutputEvent m_OnTouchedByEntity;
#endif
float m_flStartFrame;
};
#endif // ENVLASER_H

View File

@@ -0,0 +1,307 @@
//========= 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;
#ifdef MAPBASE
// Custom credits.txt, defaults to that
string_t m_iszCreditsFile;
#endif
};
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"),
#ifdef MAPBASE
DEFINE_KEYFIELD( m_iszCreditsFile, FIELD_STRING, "CreditsFile" ),
#endif
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;
#ifdef MAPBASE
extern int Mapbase_GetChapterCount();
#endif
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()
{
#ifdef MAPBASE
// Don't set this if we're using Mapbase chapters or if sv_unlockedchapters is already greater than 15
if (Mapbase_GetChapterCount() <= 0 && sv_unlockedchapters.GetInt() < 15)
#endif
sv_unlockedchapters.SetValue( "15" );
CBasePlayer *pPlayer = UTIL_GetLocalPlayer();
CSingleUserRecipientFilter user( pPlayer );
user.MakeReliable();
UserMessageBegin( user, "CreditsMsg" );
WRITE_BYTE( 3 );
#ifdef MAPBASE
WRITE_STRING( STRING(m_iszCreditsFile) );
#endif
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 );
#ifdef MAPBASE
WRITE_STRING( STRING(m_iszCreditsFile) );
#endif
MessageEnd();
}
else
{
UserMessageBegin( user, "CreditsMsg" );
WRITE_BYTE( 1 );
#ifdef MAPBASE
WRITE_STRING( STRING(m_iszCreditsFile) );
#endif
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 );
#ifdef MAPBASE
WRITE_STRING( STRING(m_iszCreditsFile) );
#endif
MessageEnd();
}

View File

@@ -0,0 +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

View File

@@ -0,0 +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 );

View File

@@ -0,0 +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 );
}
}

View File

@@ -0,0 +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();
}

View File

@@ -0,0 +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

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +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;
}

View File

@@ -0,0 +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() );
}

View File

@@ -0,0 +1,529 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Used to fire events based on the orientation of a given entity.
//
// Looks at its target's anglular velocity every frame and fires outputs
// as the angular velocity passes a given threshold value.
//
//=============================================================================//
#include "cbase.h"
#include "entityinput.h"
#include "entityoutput.h"
#include "eventqueue.h"
#include "mathlib/mathlib.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
enum
{
AVELOCITY_SENSOR_NO_LAST_RESULT = -2
};
ConVar g_debug_angularsensor( "g_debug_angularsensor", "0", FCVAR_CHEAT );
class CPointAngularVelocitySensor : public CPointEntity
{
DECLARE_CLASS( CPointAngularVelocitySensor, CPointEntity );
public:
CPointAngularVelocitySensor();
void Activate(void);
void Spawn(void);
void Think(void);
private:
float SampleAngularVelocity(CBaseEntity *pEntity);
int CompareToThreshold(CBaseEntity *pEntity, float flThreshold, bool bFireVelocityOutput);
void FireCompareOutput(int nCompareResult, CBaseEntity *pActivator);
void DrawDebugLines( void );
// Input handlers
void InputTest( inputdata_t &inputdata );
void InputTestWithInterval( inputdata_t &inputdata );
EHANDLE m_hTargetEntity; // Entity whose angles are being monitored.
float m_flThreshold; // The threshold angular velocity that we are looking for.
int m_nLastCompareResult; // The comparison result from our last measurement, expressed as -1, 0, or 1
int m_nLastFireResult; // The last result for which we fire the output.
float m_flFireTime;
float m_flFireInterval;
float m_flLastAngVelocity;
QAngle m_lastOrientation;
Vector m_vecAxis;
bool m_bUseHelper;
// Outputs
COutputFloat m_AngularVelocity;
// Compare the target's angular velocity to the threshold velocity and fire the appropriate output.
// These outputs are filtered by m_flFireInterval to ignore excessive oscillations.
COutputEvent m_OnLessThan;
COutputEvent m_OnLessThanOrEqualTo;
COutputEvent m_OnGreaterThan;
COutputEvent m_OnGreaterThanOrEqualTo;
COutputEvent m_OnEqualTo;
DECLARE_DATADESC();
};
LINK_ENTITY_TO_CLASS(point_angularvelocitysensor, CPointAngularVelocitySensor);
BEGIN_DATADESC( CPointAngularVelocitySensor )
// Fields
DEFINE_FIELD( m_hTargetEntity, FIELD_EHANDLE ),
DEFINE_KEYFIELD(m_flThreshold, FIELD_FLOAT, "threshold"),
DEFINE_FIELD(m_nLastCompareResult, FIELD_INTEGER),
DEFINE_FIELD( m_nLastFireResult, FIELD_INTEGER ),
DEFINE_FIELD( m_flFireTime, FIELD_TIME ),
DEFINE_KEYFIELD( m_flFireInterval, FIELD_FLOAT, "fireinterval" ),
DEFINE_FIELD( m_flLastAngVelocity, FIELD_FLOAT ),
DEFINE_FIELD( m_lastOrientation, FIELD_VECTOR ),
// Inputs
DEFINE_INPUTFUNC(FIELD_VOID, "Test", InputTest),
DEFINE_INPUTFUNC(FIELD_VOID, "TestWithInterval", InputTestWithInterval),
// Outputs
DEFINE_OUTPUT(m_OnLessThan, "OnLessThan"),
DEFINE_OUTPUT(m_OnLessThanOrEqualTo, "OnLessThanOrEqualTo"),
DEFINE_OUTPUT(m_OnGreaterThan, "OnGreaterThan"),
DEFINE_OUTPUT(m_OnGreaterThanOrEqualTo, "OnGreaterThanOrEqualTo"),
DEFINE_OUTPUT(m_OnEqualTo, "OnEqualTo"),
DEFINE_OUTPUT(m_AngularVelocity, "AngularVelocity"),
DEFINE_KEYFIELD( m_vecAxis, FIELD_VECTOR, "axis" ),
DEFINE_KEYFIELD( m_bUseHelper, FIELD_BOOLEAN, "usehelper" ),
END_DATADESC()
//-----------------------------------------------------------------------------
// Purpose: constructor provides default values
//-----------------------------------------------------------------------------
CPointAngularVelocitySensor::CPointAngularVelocitySensor()
{
m_flFireInterval = 0.2f;
}
//-----------------------------------------------------------------------------
// Purpose: Called when spawning after parsing keyvalues.
//-----------------------------------------------------------------------------
void CPointAngularVelocitySensor::Spawn(void)
{
m_flThreshold = fabs(m_flThreshold);
m_nLastFireResult = AVELOCITY_SENSOR_NO_LAST_RESULT;
m_nLastCompareResult = AVELOCITY_SENSOR_NO_LAST_RESULT;
// m_flFireInterval = 0.2;
m_lastOrientation = vec3_angle;
}
//-----------------------------------------------------------------------------
// Purpose: Called after all entities in the map have spawned.
//-----------------------------------------------------------------------------
void CPointAngularVelocitySensor::Activate(void)
{
BaseClass::Activate();
m_hTargetEntity = gEntList.FindEntityByName( NULL, m_target );
if (m_hTargetEntity)
{
SetNextThink( gpGlobals->curtime );
}
}
//-----------------------------------------------------------------------------
// Purpose: Draws magic lines...
//-----------------------------------------------------------------------------
void CPointAngularVelocitySensor::DrawDebugLines( void )
{
if ( m_hTargetEntity )
{
Vector vForward, vRight, vUp;
AngleVectors( m_hTargetEntity->GetAbsAngles(), &vForward, &vRight, &vUp );
NDebugOverlay::Line( GetAbsOrigin(), GetAbsOrigin() + vForward * 64, 255, 0, 0, false, 0 );
NDebugOverlay::Line( GetAbsOrigin(), GetAbsOrigin() + vRight * 64, 0, 255, 0, false, 0 );
NDebugOverlay::Line( GetAbsOrigin(), GetAbsOrigin() + vUp * 64, 0, 0, 255, false, 0 );
}
if ( m_bUseHelper == true )
{
QAngle Angles;
Vector vAxisForward, vAxisRight, vAxisUp;
Vector vLine = m_vecAxis - GetAbsOrigin();
VectorNormalize( vLine );
VectorAngles( vLine, Angles );
AngleVectors( Angles, &vAxisForward, &vAxisRight, &vAxisUp );
NDebugOverlay::Line( GetAbsOrigin(), GetAbsOrigin() + vAxisForward * 64, 255, 0, 0, false, 0 );
NDebugOverlay::Line( GetAbsOrigin(), GetAbsOrigin() + vAxisRight * 64, 0, 255, 0, false, 0 );
NDebugOverlay::Line( GetAbsOrigin(), GetAbsOrigin() + vAxisUp * 64, 0, 0, 255, false, 0 );
}
}
//-----------------------------------------------------------------------------
// Purpose: Returns the magnitude of the entity's angular velocity.
//-----------------------------------------------------------------------------
float CPointAngularVelocitySensor::SampleAngularVelocity(CBaseEntity *pEntity)
{
if (pEntity->GetMoveType() == MOVETYPE_VPHYSICS)
{
IPhysicsObject *pPhys = pEntity->VPhysicsGetObject();
if (pPhys != NULL)
{
Vector vecVelocity;
AngularImpulse vecAngVelocity;
pPhys->GetVelocity(&vecVelocity, &vecAngVelocity);
QAngle angles;
pPhys->GetPosition( NULL, &angles );
float dt = gpGlobals->curtime - GetLastThink();
if ( dt == 0 )
dt = 0.1;
// HACKHACK: We don't expect a real 'delta' orientation here, just enough of an error estimate to tell if this thing
// is trying to move, but failing.
QAngle delta = angles - m_lastOrientation;
if ( ( delta.Length() / dt ) < ( vecAngVelocity.Length() * 0.01 ) )
{
return 0.0f;
}
m_lastOrientation = angles;
if ( m_bUseHelper == false )
{
return vecAngVelocity.Length();
}
else
{
Vector vLine = m_vecAxis - GetAbsOrigin();
VectorNormalize( vLine );
Vector vecWorldAngVelocity;
pPhys->LocalToWorldVector( &vecWorldAngVelocity, vecAngVelocity );
float flDot = DotProduct( vecWorldAngVelocity, vLine );
return flDot;
}
}
}
else
{
QAngle vecAngVel = pEntity->GetLocalAngularVelocity();
float flMax = MAX(fabs(vecAngVel[PITCH]), fabs(vecAngVel[YAW]));
return MAX(flMax, fabs(vecAngVel[ROLL]));
}
return 0;
}
//-----------------------------------------------------------------------------
// Purpose: Compares the given entity's angular velocity to the threshold velocity.
// Input : pEntity - Entity whose angular velocity is being measured.
// flThreshold -
// Output : Returns -1 if less than, 0 if equal to, or 1 if greater than the threshold.
//-----------------------------------------------------------------------------
int CPointAngularVelocitySensor::CompareToThreshold(CBaseEntity *pEntity, float flThreshold, bool bFireVelocityOutput)
{
if (pEntity == NULL)
{
return 0;
}
float flAngVelocity = SampleAngularVelocity(pEntity);
if ( g_debug_angularsensor.GetBool() )
{
DrawDebugLines();
}
if (bFireVelocityOutput && (flAngVelocity != m_flLastAngVelocity))
{
m_AngularVelocity.Set(flAngVelocity, pEntity, this);
m_flLastAngVelocity = flAngVelocity;
}
if (flAngVelocity > flThreshold)
{
return 1;
}
if (flAngVelocity == flThreshold)
{
return 0;
}
return -1;
}
//-----------------------------------------------------------------------------
// Called every frame to sense the angular velocity of the target entity.
// Output is filtered by m_flFireInterval to ignore excessive oscillations.
//-----------------------------------------------------------------------------
void CPointAngularVelocitySensor::Think(void)
{
if (m_hTargetEntity != NULL)
{
//
// Check to see if the measure entity's angular velocity has been within
// tolerance of the threshold for the given period of time.
//
int nCompare = CompareToThreshold(m_hTargetEntity, m_flThreshold, true);
if (nCompare != m_nLastCompareResult)
{
// If we've oscillated back to where we last fired the output, don't
// fire the same output again.
if (nCompare == m_nLastFireResult)
{
m_flFireTime = 0;
}
else if (m_nLastCompareResult != AVELOCITY_SENSOR_NO_LAST_RESULT)
{
//
// The value has changed -- reset the timer. We'll fire the output if
// it stays at this value until the interval expires.
//
m_flFireTime = gpGlobals->curtime + m_flFireInterval;
}
m_nLastCompareResult = nCompare;
}
else if ((m_flFireTime != 0) && (gpGlobals->curtime >= m_flFireTime))
{
//
// The compare result has held steady long enough -- time to
// fire the output.
//
FireCompareOutput(nCompare, this);
m_nLastFireResult = nCompare;
m_flFireTime = 0;
}
SetNextThink( gpGlobals->curtime );
}
}
//-----------------------------------------------------------------------------
// Fires the output after the fire interval if the velocity is stable.
//-----------------------------------------------------------------------------
void CPointAngularVelocitySensor::InputTestWithInterval( inputdata_t &inputdata )
{
if (m_hTargetEntity != NULL)
{
m_flFireTime = gpGlobals->curtime + m_flFireInterval;
m_nLastFireResult = AVELOCITY_SENSOR_NO_LAST_RESULT;
m_nLastCompareResult = CompareToThreshold(m_hTargetEntity, m_flThreshold, true);
SetNextThink( gpGlobals->curtime );
}
}
//-----------------------------------------------------------------------------
// Purpose: Input handler for forcing an instantaneous test of the condition.
//-----------------------------------------------------------------------------
void CPointAngularVelocitySensor::InputTest( inputdata_t &inputdata )
{
int nCompareResult = CompareToThreshold(m_hTargetEntity, m_flThreshold, false);
FireCompareOutput(nCompareResult, inputdata.pActivator);
}
//-----------------------------------------------------------------------------
// Purpose: Fires the appropriate output based on the given comparison result.
// Input : nCompareResult -
// pActivator -
//-----------------------------------------------------------------------------
void CPointAngularVelocitySensor::FireCompareOutput( int nCompareResult, CBaseEntity *pActivator )
{
if (nCompareResult == -1)
{
m_OnLessThan.FireOutput(pActivator, this);
m_OnLessThanOrEqualTo.FireOutput(pActivator, this);
}
else if (nCompareResult == 1)
{
m_OnGreaterThan.FireOutput(pActivator, this);
m_OnGreaterThanOrEqualTo.FireOutput(pActivator, this);
}
else
{
m_OnEqualTo.FireOutput(pActivator, this);
m_OnLessThanOrEqualTo.FireOutput(pActivator, this);
m_OnGreaterThanOrEqualTo.FireOutput(pActivator, this);
}
}
// ============================================================================
//
// Simple velocity sensor
//
// ============================================================================
class CPointVelocitySensor : public CPointEntity
{
DECLARE_CLASS( CPointVelocitySensor, CPointEntity );
public:
void Spawn();
void Activate( void );
void Think( void );
private:
void SampleVelocity( void );
EHANDLE m_hTargetEntity; // Entity whose angles are being monitored.
Vector m_vecAxis; // Axis along which to measure the speed.
bool m_bEnabled; // Whether we're measuring or not
// Outputs
float m_fPrevVelocity; // stores velocity from last frame, so we only write the output if it has changed
COutputFloat m_Velocity;
void InputEnable( inputdata_t &inputdata );
void InputDisable( inputdata_t &inputdata );
DECLARE_DATADESC();
};
LINK_ENTITY_TO_CLASS( point_velocitysensor, CPointVelocitySensor );
BEGIN_DATADESC( CPointVelocitySensor )
// Fields
DEFINE_FIELD( m_hTargetEntity, FIELD_EHANDLE ),
DEFINE_KEYFIELD( m_vecAxis, FIELD_VECTOR, "axis" ),
DEFINE_KEYFIELD( m_bEnabled, FIELD_BOOLEAN, "enabled" ),
DEFINE_FIELD( m_fPrevVelocity, FIELD_FLOAT ),
// Outputs
DEFINE_OUTPUT( m_Velocity, "Velocity" ),
DEFINE_INPUTFUNC( FIELD_VOID, "Enable", InputEnable ),
DEFINE_INPUTFUNC( FIELD_VOID, "Disable", InputDisable ),
END_DATADESC()
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CPointVelocitySensor::Spawn()
{
Vector vLine = m_vecAxis - GetAbsOrigin();
VectorNormalize( vLine );
m_vecAxis = vLine;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CPointVelocitySensor::Activate( void )
{
BaseClass::Activate();
m_hTargetEntity = gEntList.FindEntityByName( NULL, m_target );
if ( m_bEnabled && m_hTargetEntity )
{
SetNextThink( gpGlobals->curtime );
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CPointVelocitySensor::InputEnable( inputdata_t &inputdata )
{
// Don't interrupt us if we're already enabled
if ( m_bEnabled )
return;
m_bEnabled = true;
if ( m_hTargetEntity )
{
SetNextThink( gpGlobals->curtime );
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CPointVelocitySensor::InputDisable( inputdata_t &inputdata )
{
m_bEnabled = false;
}
//-----------------------------------------------------------------------------
// Purpose: Called every frame
//-----------------------------------------------------------------------------
void CPointVelocitySensor::Think( void )
{
if ( m_hTargetEntity != NULL && m_bEnabled )
{
SampleVelocity();
SetNextThink( gpGlobals->curtime );
}
}
//-----------------------------------------------------------------------------
// Purpose: Returns the magnitude of the entity's angular velocity.
//-----------------------------------------------------------------------------
void CPointVelocitySensor::SampleVelocity( void )
{
if ( m_hTargetEntity == NULL )
return;
Vector vecVelocity;
if ( m_hTargetEntity->GetMoveType() == MOVETYPE_VPHYSICS )
{
IPhysicsObject *pPhys = m_hTargetEntity->VPhysicsGetObject();
if ( pPhys != NULL )
{
pPhys->GetVelocity( &vecVelocity, NULL );
}
}
else
{
vecVelocity = m_hTargetEntity->GetAbsVelocity();
}
/*
float flSpeed = VectorNormalize( vecVelocity );
float flDot = ( m_vecAxis != vec3_origin ) ? DotProduct( vecVelocity, m_vecAxis ) : 1.0f;
*/
// We want the component of the velocity vector in the direction of the axis, which since the
// axis is normalized is simply their dot product (eg V . A = |V|*|A|*cos(theta) )
m_fPrevVelocity = ( m_vecAxis != vec3_origin ) ? DotProduct( vecVelocity, m_vecAxis ) : 1.0f;
// if it's changed since the last frame, poke the output
if ( m_fPrevVelocity != m_Velocity.Get() )
{
m_Velocity.Set( m_fPrevVelocity, NULL, NULL );
}
}

View File

@@ -0,0 +1,478 @@
//========= 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"
#ifdef MAPBASE
#include "saverestore_utlvector.h"
#include "interval.h"
#endif
// 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 ),
#ifdef MAPBASE
DEFINE_FIELD( m_vecColor, FIELD_VECTOR ),
#endif
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,
#ifdef MAPBASE
float flStartTime, float flLengthTime, int nSpawnFlags, const Vector *vecColor )
#else
float flStartTime, float flLengthTime, int nSpawnFlags )
#endif
{
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 );
#ifdef MAPBASE
if (vecColor != NULL)
pBoogie->SetColor( *vecColor );
#endif
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;
#ifdef MAPBASE
if (!m_vecColor.IsZero())
{
data.m_bCustomColors = true;
data.m_CustomColors.m_vecColor1 = m_vecColor;
}
#endif
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 ) );
}
#ifdef MAPBASE
//-----------------------------------------------------------------------------
// Allows mappers to control ragdoll dancing
//-----------------------------------------------------------------------------
class CPointRagdollBoogie : public CBaseEntity
{
DECLARE_DATADESC();
DECLARE_CLASS( CPointRagdollBoogie, CBaseEntity );
public:
bool ApplyBoogie(CBaseEntity *pTarget, CBaseEntity *pActivator);
void InputActivate( inputdata_t &inputdata );
void InputDeactivate( inputdata_t &inputdata );
void InputBoogieTarget( inputdata_t &inputdata );
void InputSetZapColor( inputdata_t &inputdata );
bool KeyValue( const char *szKeyName, const char *szValue );
private:
float m_flStartTime;
interval_t m_BoogieLength;
float m_flMagnitude;
Vector m_vecZapColor;
// This allows us to change or remove active boogies later.
CUtlVector<CHandle<CRagdollBoogie>> m_Boogies;
};
//-----------------------------------------------------------------------------
// Save/load
//-----------------------------------------------------------------------------
BEGIN_DATADESC( CPointRagdollBoogie )
DEFINE_KEYFIELD( m_flStartTime, FIELD_FLOAT, "StartTime" ),
DEFINE_KEYFIELD( m_BoogieLength, FIELD_INTERVAL, "BoogieLength" ),
DEFINE_KEYFIELD( m_flMagnitude, FIELD_FLOAT, "Magnitude" ),
DEFINE_KEYFIELD( m_vecZapColor, FIELD_VECTOR, "ZapColor" ),
// Think this should be handled by StartTouch/etc.
// DEFINE_FIELD( m_nSuppressionCount, FIELD_INTEGER ),
DEFINE_UTLVECTOR( m_Boogies, FIELD_EHANDLE ),
// Inputs
DEFINE_INPUTFUNC( FIELD_VOID, "Activate", InputActivate ),
DEFINE_INPUTFUNC( FIELD_VOID, "Deactivate", InputDeactivate ),
DEFINE_INPUTFUNC( FIELD_STRING, "BoogieTarget", InputBoogieTarget ),
DEFINE_INPUTFUNC( FIELD_VECTOR, "SetZapColor", InputSetZapColor ),
END_DATADESC()
LINK_ENTITY_TO_CLASS( point_ragdollboogie, CPointRagdollBoogie );
//-----------------------------------------------------------------------------
// Purpose:
// Input : &inputdata -
//-----------------------------------------------------------------------------
bool CPointRagdollBoogie::ApplyBoogie( CBaseEntity *pTarget, CBaseEntity *pActivator )
{
if (dynamic_cast<CRagdollProp*>(pTarget))
{
m_Boogies.AddToTail(CRagdollBoogie::Create(pTarget, m_flMagnitude, gpGlobals->curtime + m_flStartTime, RandomInterval(m_BoogieLength), GetSpawnFlags(), &m_vecZapColor));
}
else if (pTarget->MyCombatCharacterPointer())
{
// Basically CBaseCombatCharacter::BecomeRagdollBoogie(), but adjusted to our needs
CTakeDamageInfo info(this, pActivator, 1.0f, DMG_GENERIC);
CBaseEntity *pRagdoll = CreateServerRagdoll(pTarget->MyCombatCharacterPointer(), 0, info, COLLISION_GROUP_INTERACTIVE_DEBRIS, true);
pRagdoll->SetCollisionBounds(CollisionProp()->OBBMins(), CollisionProp()->OBBMaxs());
m_Boogies.AddToTail(CRagdollBoogie::Create(pRagdoll, m_flMagnitude, gpGlobals->curtime + m_flStartTime, RandomInterval(m_BoogieLength), GetSpawnFlags(), &m_vecZapColor));
CTakeDamageInfo ragdollInfo(this, pActivator, 10000.0, DMG_GENERIC | DMG_REMOVENORAGDOLL);
ragdollInfo.SetDamagePosition(WorldSpaceCenter());
ragdollInfo.SetDamageForce(Vector(0, 0, 1));
ragdollInfo.SetForceFriendlyFire(true);
pTarget->TakeDamage(ragdollInfo);
}
else
{
return false;
}
return true;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : &inputdata -
//-----------------------------------------------------------------------------
void CPointRagdollBoogie::InputActivate( inputdata_t &inputdata )
{
CBaseEntity *pEnt = gEntList.FindEntityByName(NULL, STRING(m_target), this, inputdata.pActivator, inputdata.pCaller);
while (pEnt)
{
ApplyBoogie(pEnt, inputdata.pActivator);
pEnt = gEntList.FindEntityByName(pEnt, STRING(m_target), this, inputdata.pActivator, inputdata.pCaller);
}
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : &inputdata -
//-----------------------------------------------------------------------------
void CPointRagdollBoogie::InputDeactivate( inputdata_t &inputdata )
{
if (m_Boogies.Count() == 0)
return;
for (int i = 0; i < m_Boogies.Count(); i++)
{
UTIL_Remove(m_Boogies[i]);
}
m_Boogies.Purge();
//m_Boogies.RemoveAll();
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : &inputdata -
//-----------------------------------------------------------------------------
void CPointRagdollBoogie::InputBoogieTarget( inputdata_t &inputdata )
{
CBaseEntity *pEnt = gEntList.FindEntityByName(NULL, inputdata.value.String(), this, inputdata.pActivator, inputdata.pCaller);
while (pEnt)
{
if (!ApplyBoogie(pEnt, inputdata.pActivator))
{
Warning("%s was unable to apply ragdoll boogie to %s, classname %s.\n", GetDebugName(), pEnt->GetDebugName(), pEnt->GetClassname());
}
pEnt = gEntList.FindEntityByName(pEnt, inputdata.value.String(), this, inputdata.pActivator, inputdata.pCaller);
}
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : &inputdata -
//-----------------------------------------------------------------------------
void CPointRagdollBoogie::InputSetZapColor( inputdata_t &inputdata )
{
inputdata.value.Vector3D( m_vecZapColor );
if (!m_vecZapColor.IsZero())
{
// Turn into ratios of 255
m_vecZapColor /= 255.0f;
}
// Apply to existing boogies
for (int i = 0; i < m_Boogies.Count(); i++)
{
if (m_Boogies[i])
{
m_Boogies[i]->SetColor( m_vecZapColor );
}
}
}
//-----------------------------------------------------------------------------
// Purpose: Handles key values from the BSP before spawn is called.
//-----------------------------------------------------------------------------
bool CPointRagdollBoogie::KeyValue( const char *szKeyName, const char *szValue )
{
if ( FStrEq( szKeyName, "ZapColor" ) )
{
UTIL_StringToVector(m_vecZapColor.Base(), szValue);
if (!m_vecZapColor.IsZero())
{
// Turn into ratios of 255
m_vecZapColor /= 255.0f;
}
}
else
return BaseClass::KeyValue( szKeyName, szValue );
return true;
}
#endif

View File

@@ -0,0 +1,62 @@
//========= 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:
#ifdef MAPBASE
static CRagdollBoogie *Create( CBaseEntity *pTarget, float flMagnitude, float flStartTime, float flLengthTime = 0.0f, int nSpawnFlags = 0, const Vector *vecColor = NULL );
#else
static CRagdollBoogie *Create( CBaseEntity *pTarget, float flMagnitude, float flStartTime, float flLengthTime = 0.0f, int nSpawnFlags = 0 );
#endif
static void IncrementSuppressionCount( CBaseEntity *pTarget );
static void DecrementSuppressionCount( CBaseEntity *pTarget );
#ifdef MAPBASE
void SetColor( const Vector &vecColor ) { m_vecColor = vecColor; }
#endif
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;
#ifdef MAPBASE
Vector m_vecColor = Vector(1, 1, 1);
#endif
};
#endif // RAGDOLLBOOGIE_H

View File

@@ -0,0 +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;
}
}

View File

@@ -0,0 +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

View File

@@ -0,0 +1,462 @@
//========= 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;
#ifdef MAPBASE
CHandle<CSkyCamera> g_hActiveSkybox = NULL;
#endif
//-----------------------------------------------------------------------------
// Retrives the current skycamera
//-----------------------------------------------------------------------------
CSkyCamera* GetCurrentSkyCamera()
{
#ifdef MAPBASE
if ( g_hActiveSkybox.Get() == NULL )
{
g_hActiveSkybox = GetSkyCameraList();
}
return g_hActiveSkybox.Get();
#else
return g_SkyList.m_pClassList;
#endif
}
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 ),
#ifdef MAPBASE
DEFINE_FIELD( m_skyboxData.angles, FIELD_VECTOR ),
DEFINE_FIELD( m_skyboxData.skycamera, FIELD_EHANDLE ),
DEFINE_KEYFIELD( m_skyboxData.skycolor, FIELD_COLOR32, "skycolor" ),
DEFINE_KEYFIELD( m_bUseAnglesForSky, FIELD_BOOLEAN, "use_angles_for_sky" ),
#endif
// 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" ),
#ifdef MAPBASE
DEFINE_KEYFIELD( m_skyboxData.fog.farz, FIELD_FLOAT, "farz" ),
#endif
#ifdef MAPBASE
DEFINE_INPUTFUNC( FIELD_VOID, "ForceUpdate", InputForceUpdate ),
DEFINE_INPUTFUNC( FIELD_VOID, "StartUpdating", InputStartUpdating ),
DEFINE_INPUTFUNC( FIELD_VOID, "StopUpdating", InputStopUpdating ),
DEFINE_INPUTFUNC( FIELD_VOID, "ActivateSkybox", InputActivateSkybox ),
DEFINE_INPUTFUNC( FIELD_VOID, "DeactivateSkybox", InputDeactivateSkybox ),
DEFINE_INPUTFUNC( FIELD_FLOAT, "SetFogStartDist", InputSetFogStartDist ),
DEFINE_INPUTFUNC( FIELD_FLOAT, "SetFogEndDist", InputSetFogEndDist ),
DEFINE_INPUTFUNC( FIELD_FLOAT, "SetFogMaxDensity", InputSetFogMaxDensity ),
DEFINE_INPUTFUNC( FIELD_VOID, "TurnOnFog", InputTurnOnFog ),
DEFINE_INPUTFUNC( FIELD_VOID, "TurnOffFog", InputTurnOffFog ),
DEFINE_INPUTFUNC( FIELD_COLOR32, "SetFogColor", InputSetFogColor ),
DEFINE_INPUTFUNC( FIELD_COLOR32, "SetFogColorSecondary", InputSetFogColorSecondary ),
DEFINE_INPUTFUNC( FIELD_EHANDLE, "CopyFogController", InputCopyFogController ),
DEFINE_INPUTFUNC( FIELD_EHANDLE, "CopyFogControllerWithScale", InputCopyFogControllerWithScale ),
DEFINE_INPUTFUNC( FIELD_INTEGER, "SetFarZ", InputSetFarZ ),
DEFINE_INPUTFUNC( FIELD_COLOR32, "SetSkyColor", InputSetSkyColor ),
DEFINE_INPUTFUNC( FIELD_INTEGER, "SetScale", InputSetScale ),
DEFINE_THINKFUNC( UpdateThink ),
#endif
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;
#ifdef MAPBASE
m_skyboxData.skycolor.Init(0, 0, 0, 0);
#endif
}
CSkyCamera::~CSkyCamera()
{
g_SkyList.Remove( this );
}
void CSkyCamera::Spawn( void )
{
#ifdef MAPBASE
if (HasSpawnFlags(SF_SKY_MASTER))
g_hActiveSkybox = this;
if (HasSpawnFlags(SF_SKY_START_UPDATING))
{
SetCameraEntityMode();
SetThink( &CSkyCamera::UpdateThink );
SetNextThink( gpGlobals->curtime + TICK_INTERVAL );
}
else
{
SetCameraPositionMode();
}
#else
m_skyboxData.origin = GetLocalOrigin();
#endif
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
}
#ifdef MAPBASE
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
bool CSkyCamera::AcceptInput( const char *szInputName, CBaseEntity *pActivator, CBaseEntity *pCaller, variant_t Value, int outputID )
{
if (!BaseClass::AcceptInput( szInputName, pActivator, pCaller, Value, outputID ))
return false;
if (g_hActiveSkybox == this)
{
// Most inputs require an update
DoUpdate( true );
}
return true;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CSkyCamera::SetCameraEntityMode()
{
m_skyboxData.skycamera = this;
// Ensure the viewrender knows whether this should be using angles
if (m_bUseAnglesForSky)
m_skyboxData.angles.SetX( 1 );
else
m_skyboxData.angles.SetX( 0 );
}
void CSkyCamera::SetCameraPositionMode()
{
// Must be absolute now that the sky_camera can be parented
m_skyboxData.skycamera = NULL;
m_skyboxData.origin = GetAbsOrigin();
if (m_bUseAnglesForSky)
m_skyboxData.angles = GetAbsAngles();
}
//-----------------------------------------------------------------------------
// Purpose: Update sky position mid-game
//-----------------------------------------------------------------------------
bool CSkyCamera::DoUpdate( bool bUpdateData )
{
// Now that sky camera updating uses an entity handle directly transmitted to the client,
// this thinking is only used to update area and other parameters
// Getting into another area is unlikely, but if it's not expensive, I guess it's okay.
int area = engine->GetArea( GetAbsOrigin() );
if (m_skyboxData.area != area)
{
m_skyboxData.area = area;
bUpdateData = true;
}
if ( m_bUseAngles )
{
Vector fogForward;
AngleVectors( GetAbsAngles(), &fogForward );
fogForward *= -1.0f;
if ( m_skyboxData.fog.dirPrimary.Get() != fogForward )
{
m_skyboxData.fog.dirPrimary = fogForward;
bUpdateData = true;
}
}
if (bUpdateData)
{
// Updates client data, this completely ignores m_pOldSkyCamera
CBasePlayer *pPlayer = NULL;
for (int i = 1; i <= gpGlobals->maxClients; i++)
{
pPlayer = UTIL_PlayerByIndex(i);
if (pPlayer)
pPlayer->m_Local.m_skybox3d.CopyFrom(m_skyboxData);
}
}
// Needed for entity interpolation
SetSimulationTime( gpGlobals->curtime );
return bUpdateData;
}
void CSkyCamera::UpdateThink()
{
if (DoUpdate())
{
SetNextThink( gpGlobals->curtime + TICK_INTERVAL );
}
else
{
SetNextThink( gpGlobals->curtime + 0.2f );
}
}
void CSkyCamera::InputForceUpdate( inputdata_t &inputdata )
{
if (m_skyboxData.skycamera == NULL)
{
m_skyboxData.origin = GetAbsOrigin();
if (m_bUseAnglesForSky)
m_skyboxData.angles = GetAbsAngles();
}
DoUpdate( true );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CSkyCamera::InputStartUpdating( inputdata_t &inputdata )
{
if (GetCurrentSkyCamera() == this)
{
SetCameraEntityMode();
DoUpdate( true );
SetThink( &CSkyCamera::UpdateThink );
SetNextThink( gpGlobals->curtime + TICK_INTERVAL );
}
// If we become the current sky camera later, remember that we want to update
AddSpawnFlags( SF_SKY_START_UPDATING );
// Must update transmit state so we show up on the client
DispatchUpdateTransmitState();
}
void CSkyCamera::InputStopUpdating( inputdata_t &inputdata )
{
SetThink( NULL );
SetNextThink( TICK_NEVER_THINK );
RemoveSpawnFlags( SF_SKY_START_UPDATING );
DispatchUpdateTransmitState();
SetCameraPositionMode();
DoUpdate( true );
}
//-----------------------------------------------------------------------------
// Activate!
//-----------------------------------------------------------------------------
void CSkyCamera::InputActivateSkybox( inputdata_t &inputdata )
{
CSkyCamera *pActiveSky = GetCurrentSkyCamera();
if (pActiveSky && pActiveSky->GetNextThink() != TICK_NEVER_THINK && pActiveSky != this)
{
// Deactivate that skybox
pActiveSky->SetThink( NULL );
pActiveSky->SetNextThink( TICK_NEVER_THINK );
}
g_hActiveSkybox = this;
if (HasSpawnFlags( SF_SKY_START_UPDATING ))
InputStartUpdating( inputdata );
}
//-----------------------------------------------------------------------------
// Deactivate!
//-----------------------------------------------------------------------------
void CSkyCamera::InputDeactivateSkybox( inputdata_t &inputdata )
{
if (GetCurrentSkyCamera() == this)
{
g_hActiveSkybox = NULL;
// ClientData doesn't catch this immediately
CBasePlayer *pPlayer = NULL;
for (int i = 1; i <= gpGlobals->maxClients; i++)
{
pPlayer = UTIL_PlayerByIndex( i );
if (pPlayer)
pPlayer->m_Local.m_skybox3d.area = 255;
}
}
SetThink( NULL );
SetNextThink( TICK_NEVER_THINK );
}
//------------------------------------------------------------------------------
// Purpose: Input handlers for setting fog stuff.
//------------------------------------------------------------------------------
void CSkyCamera::InputSetFogStartDist( inputdata_t &inputdata ) { m_skyboxData.fog.start = inputdata.value.Float(); }
void CSkyCamera::InputSetFogEndDist( inputdata_t &inputdata ) { m_skyboxData.fog.end = inputdata.value.Float(); }
void CSkyCamera::InputSetFogMaxDensity( inputdata_t &inputdata ) { m_skyboxData.fog.maxdensity = inputdata.value.Float(); }
void CSkyCamera::InputTurnOnFog( inputdata_t &inputdata ) { m_skyboxData.fog.enable = true; }
void CSkyCamera::InputTurnOffFog( inputdata_t &inputdata ) { m_skyboxData.fog.enable = false; }
void CSkyCamera::InputSetFogColor( inputdata_t &inputdata ) { m_skyboxData.fog.colorPrimary = inputdata.value.Color32(); }
void CSkyCamera::InputSetFogColorSecondary( inputdata_t &inputdata ) { m_skyboxData.fog.colorSecondary = inputdata.value.Color32(); }
void CSkyCamera::InputSetFarZ( inputdata_t &inputdata ) { m_skyboxData.fog.farz = inputdata.value.Int(); }
void CSkyCamera::InputCopyFogController( inputdata_t &inputdata )
{
CFogController *pFogController = dynamic_cast<CFogController*>(inputdata.value.Entity().Get());
if (!pFogController)
return;
m_skyboxData.fog.dirPrimary = pFogController->m_fog.dirPrimary;
m_skyboxData.fog.colorPrimary = pFogController->m_fog.colorPrimary;
m_skyboxData.fog.colorSecondary = pFogController->m_fog.colorSecondary;
//m_skyboxData.fog.colorPrimaryLerpTo = pFogController->m_fog.colorPrimaryLerpTo;
//m_skyboxData.fog.colorSecondaryLerpTo = pFogController->m_fog.colorSecondaryLerpTo;
m_skyboxData.fog.start = pFogController->m_fog.start;
m_skyboxData.fog.end = pFogController->m_fog.end;
m_skyboxData.fog.farz = pFogController->m_fog.farz;
m_skyboxData.fog.maxdensity = pFogController->m_fog.maxdensity;
//m_skyboxData.fog.startLerpTo = pFogController->m_fog.startLerpTo;
//m_skyboxData.fog.endLerpTo = pFogController->m_fog.endLerpTo;
//m_skyboxData.fog.lerptime = pFogController->m_fog.lerptime;
//m_skyboxData.fog.duration = pFogController->m_fog.duration;
//m_skyboxData.fog.enable = pFogController->m_fog.enable;
m_skyboxData.fog.blend = pFogController->m_fog.blend;
}
void CSkyCamera::InputCopyFogControllerWithScale( inputdata_t &inputdata )
{
CFogController *pFogController = dynamic_cast<CFogController*>(inputdata.value.Entity().Get());
if (!pFogController)
return;
m_skyboxData.fog.dirPrimary = pFogController->m_fog.dirPrimary;
m_skyboxData.fog.colorPrimary = pFogController->m_fog.colorPrimary;
m_skyboxData.fog.colorSecondary = pFogController->m_fog.colorSecondary;
//m_skyboxData.fog.colorPrimaryLerpTo = pFogController->m_fog.colorPrimaryLerpTo;
//m_skyboxData.fog.colorSecondaryLerpTo = pFogController->m_fog.colorSecondaryLerpTo;
m_skyboxData.fog.start = pFogController->m_fog.start * m_skyboxData.scale;
m_skyboxData.fog.end = pFogController->m_fog.end * m_skyboxData.scale;
m_skyboxData.fog.farz = pFogController->m_fog.farz != -1 ? (pFogController->m_fog.farz * m_skyboxData.scale) : pFogController->m_fog.farz;
m_skyboxData.fog.maxdensity = pFogController->m_fog.maxdensity;
//m_skyboxData.fog.startLerpTo = pFogController->m_fog.startLerpTo;
//m_skyboxData.fog.endLerpTo = pFogController->m_fog.endLerpTo;
//m_skyboxData.fog.lerptime = pFogController->m_fog.lerptime;
//m_skyboxData.fog.duration = pFogController->m_fog.duration;
//m_skyboxData.fog.enable = pFogController->m_fog.enable;
m_skyboxData.fog.blend = pFogController->m_fog.blend;
}
#endif

View File

@@ -0,0 +1,103 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Resource collection entity
//
// $NoKeywords: $
//=============================================================================//
#ifndef SKYCAMERA_H
#define SKYCAMERA_H
#ifdef _WIN32
#pragma once
#endif
class CSkyCamera;
#ifdef MAPBASE
#define SF_SKY_MASTER (1 << 0)
#define SF_SKY_START_UPDATING (1 << 1)
//=============================================================================
//
// Sky Camera Class
// Now derived directly from CBaseEntity for parenting and angles! (please don't break anything)
//
//=============================================================================
class CSkyCamera : public CBaseEntity
#else
//=============================================================================
//
// Sky Camera Class
//
class CSkyCamera : public CLogicalEntity
#endif
{
#ifdef MAPBASE
DECLARE_CLASS( CSkyCamera, CBaseEntity );
#else
DECLARE_CLASS( CSkyCamera, CLogicalEntity );
#endif
public:
DECLARE_DATADESC();
CSkyCamera();
~CSkyCamera();
virtual void Spawn( void );
virtual void Activate();
#ifdef MAPBASE
bool AcceptInput( const char *szInputName, CBaseEntity *pActivator, CBaseEntity *pCaller, variant_t Value, int outputID );
int UpdateTransmitState() { return HasSpawnFlags( SF_SKY_START_UPDATING ) ? SetTransmitState( FL_EDICT_ALWAYS ) : BaseClass::UpdateTransmitState(); }
void SetCameraEntityMode();
void SetCameraPositionMode();
bool DoUpdate( bool bUpdateData = false );
void UpdateThink();
void InputForceUpdate( inputdata_t &inputdata );
void InputStartUpdating( inputdata_t &inputdata );
void InputStopUpdating( inputdata_t &inputdata );
void InputActivateSkybox( inputdata_t &inputdata );
void InputDeactivateSkybox( inputdata_t &inputdata );
void InputSetFogStartDist( inputdata_t &data );
void InputSetFogEndDist( inputdata_t &data );
void InputTurnOnFog( inputdata_t &data );
void InputTurnOffFog( inputdata_t &data );
void InputSetFogColor( inputdata_t &data );
void InputSetFogColorSecondary( inputdata_t &data );
void InputSetFogMaxDensity( inputdata_t &inputdata );
void InputCopyFogController( inputdata_t &inputdata );
void InputCopyFogControllerWithScale( inputdata_t &inputdata );
void InputSetFarZ( inputdata_t &data );
void InputSetSkyColor( inputdata_t &inputdata ) { m_skyboxData.skycolor = inputdata.value.Color32(); }
void InputSetScale( inputdata_t &inputdata ) { m_skyboxData.scale = inputdata.value.Int(); }
#endif
public:
sky3dparams_t m_skyboxData;
bool m_bUseAngles;
#ifdef MAPBASE
// Uses angles for actual skybox
bool m_bUseAnglesForSky;
#endif
CSkyCamera *m_pNext;
};
//-----------------------------------------------------------------------------
// Retrives the current skycamera
//-----------------------------------------------------------------------------
CSkyCamera* GetCurrentSkyCamera();
CSkyCamera* GetSkyCameraList();
#endif // SKYCAMERA_H

View File

@@ -0,0 +1,584 @@
//========= 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.
//
// Template entities are marked with a special spawnflag which causes
// them not to spawn, but to be saved as a string containing all the
// map data (keyvalues and I/O connections) from the BSP. Template
// entities are looked up by name by the spawner, which copies the
// map data into a local string (that's how the template data is saved
// and restored). Once all the entities in the map have been activated,
// the template database is freed.
//
//=============================================================================//
#include "cbase.h"
#include "igamesystem.h"
#include "mapentities_shared.h"
#include "point_template.h"
#include "eventqueue.h"
#include "TemplateEntities.h"
#include "utldict.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
ConVar template_debug( "template_debug", "0" );
// This is appended to key's values that will need to be unique in template instances
const char *ENTITYIO_FIXUP_STRING = "&0000";
int MapEntity_GetNumKeysInEntity( const char *pEntData );
struct TemplateEntityData_t
{
const char *pszName;
char *pszMapData;
string_t iszMapData;
int iMapDataLength;
bool bNeedsEntityIOFixup; // If true, this template has entity I/O in its mapdata that needs fixup before spawning.
char *pszFixedMapData; // A single copy of this template that we used to fix up the Entity I/O whenever someone wants a fixed version of this template
DECLARE_SIMPLE_DATADESC();
};
BEGIN_SIMPLE_DATADESC( TemplateEntityData_t )
//DEFINE_FIELD( pszName, FIELD_STRING ), // Saved custom, see below
//DEFINE_FIELD( pszMapData, FIELD_STRING ), // Saved custom, see below
DEFINE_FIELD( iszMapData, FIELD_STRING ),
DEFINE_FIELD( iMapDataLength, FIELD_INTEGER ),
DEFINE_FIELD( bNeedsEntityIOFixup, FIELD_BOOLEAN ),
//DEFINE_FIELD( pszFixedMapData, FIELD_STRING ), // Not saved at all
END_DATADESC()
struct grouptemplate_t
{
CEntityMapData *pMapDataParser;
char pszName[MAPKEY_MAXLENGTH];
int iIndex;
bool bChangeTargetname;
};
static CUtlVector<TemplateEntityData_t *> g_Templates;
int g_iCurrentTemplateInstance;
//-----------------------------------------------------------------------------
// Purpose: Saves the given entity's keyvalue data for later use by a spawner.
// Returns the index into the templates.
//-----------------------------------------------------------------------------
int Templates_Add(CBaseEntity *pEntity, const char *pszMapData, int nLen)
{
const char *pszName = STRING(pEntity->GetEntityName());
if ((!pszName) || (!strlen(pszName)))
{
DevWarning(1, "RegisterTemplateEntity: template entity with no name, class %s\n", pEntity->GetClassname());
return -1;
}
TemplateEntityData_t *pEntData = (TemplateEntityData_t *)malloc(sizeof(TemplateEntityData_t));
pEntData->pszName = strdup( pszName );
// We may modify the values of the keys in this mapdata chunk later on to fix Entity I/O
// connections. For this reason, we need to ensure we have enough memory to do that.
int iKeys = MapEntity_GetNumKeysInEntity( pszMapData );
int iExtraSpace = (strlen(ENTITYIO_FIXUP_STRING)+1) * iKeys;
// Extra 1 because the mapdata passed in isn't null terminated
pEntData->iMapDataLength = nLen + iExtraSpace + 1;
pEntData->pszMapData = (char *)malloc( pEntData->iMapDataLength );
memcpy(pEntData->pszMapData, pszMapData, nLen + 1);
pEntData->pszMapData[nLen] = '\0';
// We don't alloc these suckers right now because that gives us no time to
// tweak them for Entity I/O purposes.
pEntData->iszMapData = NULL_STRING;
pEntData->bNeedsEntityIOFixup = false;
pEntData->pszFixedMapData = NULL;
return g_Templates.AddToTail(pEntData);
}
//-----------------------------------------------------------------------------
// Purpose: Returns true if the specified index needs to be fixed up to be unique
// when the template is spawned.
//-----------------------------------------------------------------------------
bool Templates_IndexRequiresEntityIOFixup( int iIndex )
{
Assert( iIndex < g_Templates.Count() );
return g_Templates[iIndex]->bNeedsEntityIOFixup;
}
//-----------------------------------------------------------------------------
// Purpose: Looks up a template entity by its index in the templates
// Used by point_templates because they often have multiple templates with the same name
//-----------------------------------------------------------------------------
string_t Templates_FindByIndex( int iIndex )
{
Assert( iIndex < g_Templates.Count() );
// First time through we alloc the mapdata onto the pool.
// It's safe to do it now because this isn't called until post Entity I/O cleanup.
if ( g_Templates[iIndex]->iszMapData == NULL_STRING )
{
g_Templates[iIndex]->iszMapData = AllocPooledString( g_Templates[iIndex]->pszMapData );
}
return g_Templates[iIndex]->iszMapData;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
int Templates_GetStringSize( int iIndex )
{
Assert( iIndex < g_Templates.Count() );
return g_Templates[iIndex]->iMapDataLength;
}
//-----------------------------------------------------------------------------
// Purpose: Looks up a template entity by name, returning the map data blob as
// a null-terminated string containing key/value pairs.
// NOTE: This can't handle multiple templates with the same targetname.
//-----------------------------------------------------------------------------
string_t Templates_FindByTargetName(const char *pszName)
{
int nCount = g_Templates.Count();
for (int i = 0; i < nCount; i++)
{
TemplateEntityData_t *pTemplate = g_Templates.Element(i);
if ( !stricmp(pTemplate->pszName, pszName) )
return Templates_FindByIndex( i );
}
return NULL_STRING;
}
#ifdef MAPBASE
//-----------------------------------------------------------------------------
// Purpose: A new version of name fixup which targets all instances of a name
// in a keyvalue, including output parameters.
//-----------------------------------------------------------------------------
void Templates_NewNameFixup( CUtlVector< grouptemplate_t > &GroupTemplates, int i, int iCount, CEntityMapData *mapData, CUtlDict< int, int > &KeyInstanceCount, char *keyName, char *value )
{
do
{
// Ignore targetnames
if ( !stricmp( keyName, "targetname" ) )
continue;
// Add to the count for this
int idx = KeyInstanceCount.Find( keyName );
if ( idx == KeyInstanceCount.InvalidIndex() )
{
idx = KeyInstanceCount.Insert( keyName, 0 );
}
KeyInstanceCount[idx]++;
// Loop through our group templates
for ( int iTName = 0; iTName < iCount; iTName++ )
{
char *pName = GroupTemplates[iTName].pszName;
if (strstr( value, pName ) == NULL)
continue;
if ( template_debug.GetInt() )
{
Msg("Template Connection Found: Key %s (\"%s\") in entity named \"%s\"(%d) matches entity %d's targetname\n", keyName, value, GroupTemplates[i].pszName, i, iTName );
}
char newvalue[MAPKEY_MAXLENGTH];
char fixedup[MAPKEY_MAXLENGTH];
Q_strncpy( fixedup, pName, MAPKEY_MAXLENGTH );
Q_strncat( fixedup, ENTITYIO_FIXUP_STRING, sizeof( fixedup ), COPY_ALL_CHARACTERS );
// Get the current key instance. (-1 because it's this one we're changing)
int nKeyInstance = KeyInstanceCount[idx] - 1;
// Add our IO value to the targetname
V_StrSubst( value, pName, fixedup, newvalue, MAPKEY_MAXLENGTH );
if ( template_debug.GetInt() )
{
Msg(" Fixed up value: Key %s with \"%s\" in entity named \"%s\"(%d) has become \"%s\"\n", keyName, value, GroupTemplates[i].pszName, i, newvalue );
}
mapData->SetValue( keyName, newvalue, nKeyInstance );
Q_strncpy( value, newvalue, MAPKEY_MAXLENGTH );
// Remember we changed this targetname
GroupTemplates[iTName].bChangeTargetname = true;
// Set both entity's flags telling them their template needs fixup when it's spawned
g_Templates[ GroupTemplates[i].iIndex ]->bNeedsEntityIOFixup = true;
g_Templates[ GroupTemplates[iTName].iIndex ]->bNeedsEntityIOFixup = true;
}
}
while ( mapData->GetNextKey(keyName, value) );
}
#endif
//-----------------------------------------------------------------------------
// Purpose: A CPointTemplate has asked us to reconnect all the entity I/O links
// inside it's templates. Go through the keys and add look for values
// that match a name within the group's entity names. Append %d to any
// found values, which will later be filled out by a unique identifier
// whenever the template is instanced.
//-----------------------------------------------------------------------------
void Templates_ReconnectIOForGroup( CPointTemplate *pGroup )
{
int iCount = pGroup->GetNumTemplates();
if ( !iCount )
return;
// First assemble a list of the targetnames of all the templates in the group.
// We need to store off the original names here, because we're going to change
// them as we go along.
CUtlVector< grouptemplate_t > GroupTemplates;
int i;
for ( i = 0; i < iCount; i++ )
{
grouptemplate_t newGroupTemplate;
newGroupTemplate.iIndex = pGroup->GetTemplateIndexForTemplate(i);
newGroupTemplate.pMapDataParser = new CEntityMapData( g_Templates[ newGroupTemplate.iIndex ]->pszMapData, g_Templates[ newGroupTemplate.iIndex ]->iMapDataLength );
Assert( newGroupTemplate.pMapDataParser );
newGroupTemplate.pMapDataParser->ExtractValue( "targetname", newGroupTemplate.pszName );
newGroupTemplate.bChangeTargetname = false;
GroupTemplates.AddToTail( newGroupTemplate );
}
if (pGroup->AllowNameFixup())
{
char keyName[MAPKEY_MAXLENGTH];
char value[MAPKEY_MAXLENGTH];
char valueclipped[MAPKEY_MAXLENGTH];
// Now go through all the entities in the group and parse their mapdata keyvalues.
// We're looking for any values that match targetnames of any of the group entities.
for ( i = 0; i < iCount; i++ )
{
// We need to know what instance of each key we're changing.
// Store a table of the count of the keys we've run into.
CUtlDict< int, int > KeyInstanceCount;
CEntityMapData *mapData = GroupTemplates[i].pMapDataParser;
// Loop through our keys
if ( !mapData->GetFirstKey(keyName, value) )
continue;
#ifdef MAPBASE
if ( pGroup->NameFixupExpanded() )
{
Templates_NewNameFixup( GroupTemplates, i, iCount, mapData, KeyInstanceCount, keyName, value );
continue;
}
#endif
do
{
// Ignore targetnames
if ( !stricmp( keyName, "targetname" ) )
continue;
// Add to the count for this
int idx = KeyInstanceCount.Find( keyName );
if ( idx == KeyInstanceCount.InvalidIndex() )
{
idx = KeyInstanceCount.Insert( keyName, 0 );
}
KeyInstanceCount[idx]++;
// Entity I/O values are stored as "Targetname,<data>", so we need to see if there's a ',' in the string
char *sValue = value;
// FIXME: This is very brittle. Any key with a , will not be found.
char *s = strchr( value, ',' );
if ( s )
{
// Grab just the targetname of the receiver
Q_strncpy( valueclipped, value, (s - value+1) );
sValue = valueclipped;
}
// Loop through our group templates
for ( int iTName = 0; iTName < iCount; iTName++ )
{
char *pName = GroupTemplates[iTName].pszName;
if ( stricmp( pName, sValue ) )
continue;
if ( template_debug.GetInt() )
{
Msg("Template Connection Found: Key %s (\"%s\") in entity named \"%s\"(%d) matches entity %d's targetname\n", keyName, sValue, GroupTemplates[i].pszName, i, iTName );
}
char newvalue[MAPKEY_MAXLENGTH];
// Get the current key instance. (-1 because it's this one we're changing)
int nKeyInstance = KeyInstanceCount[idx] - 1;
// Add our IO value to the targetname
// We need to append it if this isn't an Entity I/O value, or prepend it to the ',' if it is
if ( s )
{
Q_strncpy( newvalue, valueclipped, MAPKEY_MAXLENGTH );
Q_strncat( newvalue, ENTITYIO_FIXUP_STRING, sizeof(newvalue), COPY_ALL_CHARACTERS );
Q_strncat( newvalue, s, sizeof(newvalue), COPY_ALL_CHARACTERS );
mapData->SetValue( keyName, newvalue, nKeyInstance );
}
else
{
Q_strncpy( newvalue, sValue, MAPKEY_MAXLENGTH );
Q_strncat( newvalue, ENTITYIO_FIXUP_STRING, sizeof(newvalue), COPY_ALL_CHARACTERS );
mapData->SetValue( keyName, newvalue, nKeyInstance );
}
// Remember we changed this targetname
GroupTemplates[iTName].bChangeTargetname = true;
// Set both entity's flags telling them their template needs fixup when it's spawned
g_Templates[ GroupTemplates[i].iIndex ]->bNeedsEntityIOFixup = true;
g_Templates[ GroupTemplates[iTName].iIndex ]->bNeedsEntityIOFixup = true;
}
}
while ( mapData->GetNextKey(keyName, value) );
}
// Now change targetnames for all entities that need them changed
for ( i = 0; i < iCount; i++ )
{
char value[MAPKEY_MAXLENGTH];
if ( GroupTemplates[i].bChangeTargetname )
{
CEntityMapData *mapData = GroupTemplates[i].pMapDataParser;
mapData->ExtractValue( "targetname", value );
Q_strncat( value, ENTITYIO_FIXUP_STRING, sizeof(value), COPY_ALL_CHARACTERS );
mapData->SetValue( "targetname", value );
}
}
}
// Delete our group parsers
for ( i = 0; i < iCount; i++ )
{
delete GroupTemplates[i].pMapDataParser;
}
GroupTemplates.Purge();
}
//-----------------------------------------------------------------------------
// Purpose: Someone's about to start instancing a new group of entities.
// Generate a unique identifier for this group.
//-----------------------------------------------------------------------------
void Templates_StartUniqueInstance( void )
{
g_iCurrentTemplateInstance++;
// Make sure there's enough room to fit it into the string
int iMax = pow(10.0f, (int)((strlen(ENTITYIO_FIXUP_STRING) - 1))); // -1 for the &
if ( g_iCurrentTemplateInstance >= iMax )
{
// We won't hit this.
Assert(0);
// Hopefully there were still be instance number 0 around.
g_iCurrentTemplateInstance = 0;
}
}
//-----------------------------------------------------------------------------
// Purpose: Someone wants to spawn an instance of a template that requires
// entity IO fixup. Fill out the pMapData with a copy of the template
// with unique key/values where the template requires them.
//-----------------------------------------------------------------------------
char *Templates_GetEntityIOFixedMapData( int iIndex )
{
#ifndef MAPBASE // This code also runs when the point_template's script scope is active
Assert( Templates_IndexRequiresEntityIOFixup( iIndex ) );
#endif
// First time through?
if ( !g_Templates[iIndex]->pszFixedMapData )
{
g_Templates[iIndex]->pszFixedMapData = new char[g_Templates[iIndex]->iMapDataLength];
Q_strncpy( g_Templates[iIndex]->pszFixedMapData, g_Templates[iIndex]->pszMapData, g_Templates[iIndex]->iMapDataLength );
}
int iFixupSize = strlen(ENTITYIO_FIXUP_STRING); // don't include \0 when copying in the fixup
char *sOurFixup = new char[iFixupSize+1]; // do alloc room here for the null terminator
Q_snprintf( sOurFixup, iFixupSize+1, "%c%.4d", ENTITYIO_FIXUP_STRING[0], g_iCurrentTemplateInstance );
// Now rip through the map data string and replace any instances of the fixup string with our unique identifier
char *c = g_Templates[iIndex]->pszFixedMapData;
do
{
if ( *c == ENTITYIO_FIXUP_STRING[0] )
{
// Make sure it's our fixup string
bool bValid = true;
for ( int i = 1; i < iFixupSize; i++ )
{
// Look for any number, because we've already used this string
if ( !(*(c+i) >= '0' && *(c+i) <= '9') )
{
// Some other string
bValid = false;
break;
}
}
// Stomp it with our unique string
if ( bValid )
{
memcpy( c, sOurFixup, iFixupSize );
c += iFixupSize;
}
}
c++;
} while (*c);
return g_Templates[iIndex]->pszFixedMapData;
}
//-----------------------------------------------------------------------------
// Purpose: Frees all the template data. Called on level shutdown.
//-----------------------------------------------------------------------------
void Templates_RemoveAll(void)
{
int nCount = g_Templates.Count();
for (int i = 0; i < nCount; i++)
{
TemplateEntityData_t *pTemplate = g_Templates.Element(i);
free((void *)pTemplate->pszName);
free(pTemplate->pszMapData);
if ( pTemplate->pszFixedMapData )
{
free(pTemplate->pszFixedMapData);
}
free(pTemplate);
}
g_Templates.RemoveAll();
}
//-----------------------------------------------------------------------------
// Purpose: Hooks in the template manager's callbacks.
//-----------------------------------------------------------------------------
class CTemplatesHook : public CAutoGameSystem
{
public:
CTemplatesHook( char const *name ) : CAutoGameSystem( name )
{
}
virtual void LevelShutdownPostEntity( void )
{
Templates_RemoveAll();
}
};
CTemplatesHook g_TemplateEntityHook( "CTemplatesHook" );
//-----------------------------------------------------------------------------
// TEMPLATE SAVE / RESTORE
//-----------------------------------------------------------------------------
static short TEMPLATE_SAVE_RESTORE_VERSION = 1;
class CTemplate_SaveRestoreBlockHandler : public CDefSaveRestoreBlockHandler
{
public:
const char *GetBlockName()
{
return "Templates";
}
//---------------------------------
void Save( ISave *pSave )
{
pSave->WriteInt( &g_iCurrentTemplateInstance );
short nCount = g_Templates.Count();
pSave->WriteShort( &nCount );
for ( int i = 0; i < nCount; i++ )
{
TemplateEntityData_t *pTemplate = g_Templates[i];
pSave->WriteAll( pTemplate );
pSave->WriteString( pTemplate->pszName );
pSave->WriteString( pTemplate->pszMapData );
}
}
//---------------------------------
void WriteSaveHeaders( ISave *pSave )
{
pSave->WriteShort( &TEMPLATE_SAVE_RESTORE_VERSION );
}
//---------------------------------
void ReadRestoreHeaders( IRestore *pRestore )
{
// No reason why any future version shouldn't try to retain backward compatability. The default here is to not do so.
short version;
pRestore->ReadShort( &version );
m_fDoLoad = ( version == TEMPLATE_SAVE_RESTORE_VERSION );
}
//---------------------------------
void Restore( IRestore *pRestore, bool createPlayers )
{
if ( m_fDoLoad )
{
Templates_RemoveAll();
g_Templates.Purge();
g_iCurrentTemplateInstance = pRestore->ReadInt();
int iTemplates = pRestore->ReadShort();
while ( iTemplates-- )
{
TemplateEntityData_t *pNewTemplate = (TemplateEntityData_t *)malloc(sizeof(TemplateEntityData_t));
pRestore->ReadAll( pNewTemplate );
int sizeData = 0;//pRestore->SkipHeader();
char szName[MAPKEY_MAXLENGTH];
pRestore->ReadString( szName, MAPKEY_MAXLENGTH, sizeData );
pNewTemplate->pszName = strdup( szName );
//sizeData = pRestore->SkipHeader();
pNewTemplate->pszMapData = (char *)malloc( pNewTemplate->iMapDataLength );
pRestore->ReadString( pNewTemplate->pszMapData, pNewTemplate->iMapDataLength, sizeData );
// Set this to NULL so it'll be created the first time it gets used
pNewTemplate->pszFixedMapData = NULL;
g_Templates.AddToTail( pNewTemplate );
}
}
}
private:
bool m_fDoLoad;
};
//-----------------------------------------------------------------------------
CTemplate_SaveRestoreBlockHandler g_Template_SaveRestoreBlockHandler;
//-------------------------------------
ISaveRestoreBlockHandler *GetTemplateSaveRestoreBlockHandler()
{
return &g_Template_SaveRestoreBlockHandler;
}

View File

@@ -0,0 +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

View File

@@ -0,0 +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() );
}

View File

@@ -0,0 +1,27 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#include "cbase.h"
#include "gameinterface.h"
#include "mapentities.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
void CServerGameClients::GetPlayerLimits( int& minplayers, int& maxplayers, int &defaultMaxPlayers ) const
{
minplayers = defaultMaxPlayers = 1;
maxplayers = MAX_PLAYERS;
}
// -------------------------------------------------------------------------------------------- //
// Mod-specific CServerGameDLL implementation.
// -------------------------------------------------------------------------------------------- //
void CServerGameDLL::LevelInit_ParseAllEntities( const char *pMapEntities )
{
}

View File

@@ -0,0 +1,60 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#include "cbase.h"
#include "base_transmit_proxy.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
CBaseTransmitProxy::CBaseTransmitProxy( CBaseEntity *pEnt )
{
m_hEnt = pEnt;
m_refCount = 0;
}
CBaseTransmitProxy::~CBaseTransmitProxy()
{
// Unlink from our parent entity.
if ( m_hEnt )
{
m_refCount = 0xFFFF; // Prevent us from deleting ourselves again.
// m_hEnt->NetworkProp()->SetTransmitProxy( NULL );
}
}
int CBaseTransmitProxy::ShouldTransmit( const CCheckTransmitInfo *pInfo, int nPrevShouldTransmitResult )
{
// Anyone implementing a transmit proxy should override this since that's the point!!
Assert( false );
return FL_EDICT_DONTSEND;
}
void CBaseTransmitProxy::AddRef()
{
m_refCount++;
}
void CBaseTransmitProxy::Release()
{
if ( m_refCount == 0xFFFF )
{
// This means we are inside our destructor already, so we don't want to do anything here.
}
else if ( m_refCount <= 1 )
{
delete this;
}
else
{
--m_refCount;
}
}

View File

@@ -0,0 +1,41 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#ifndef BASE_TRANSMIT_PROXY_H
#define BASE_TRANSMIT_PROXY_H
#ifdef _WIN32
#pragma once
#endif
#include "ehandle.h"
class CBaseEntity;
class CBaseTransmitProxy
{
public:
CBaseTransmitProxy( CBaseEntity *pEnt );
virtual ~CBaseTransmitProxy();
// Override this to control the ShouldTransmit behavior of whatever entity the proxy is attached to.
// bPrevShouldTransmitResult is what the proxy's entity's ShouldTransmit() returned.
virtual int ShouldTransmit( const CCheckTransmitInfo *pInfo, int nPrevShouldTransmitResult );
void AddRef();
void Release();
private:
EHANDLE m_hEnt;
unsigned short m_refCount;
};
#endif // BASE_TRANSMIT_PROXY_H

View File

@@ -0,0 +1,713 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Base combat character with no AI
//
// $NoKeywords: $
//=============================================================================//
#ifndef BASECOMBATCHARACTER_H
#define BASECOMBATCHARACTER_H
#include <limits.h>
#include "weapon_proficiency.h"
#ifdef _WIN32
#pragma once
#endif
#ifdef INVASION_DLL
#include "tf_shareddefs.h"
#define POWERUP_THINK_CONTEXT "PowerupThink"
#endif
#include "cbase.h"
#include "baseentity.h"
#include "baseflex.h"
#include "damagemodifier.h"
#include "utllinkedlist.h"
#include "ai_hull.h"
#include "ai_utils.h"
#include "physics_impact_damage.h"
class CNavArea;
class CScriptedTarget;
typedef CHandle<CBaseCombatWeapon> CBaseCombatWeaponHandle;
// -------------------------------------
// Capability Bits
// -------------------------------------
enum Capability_t
{
bits_CAP_MOVE_GROUND = 0x00000001, // walk/run
bits_CAP_MOVE_JUMP = 0x00000002, // jump/leap
bits_CAP_MOVE_FLY = 0x00000004, // can fly, move all around
bits_CAP_MOVE_CLIMB = 0x00000008, // climb ladders
bits_CAP_MOVE_SWIM = 0x00000010, // navigate in water // UNDONE - not yet implemented
bits_CAP_MOVE_CRAWL = 0x00000020, // crawl // UNDONE - not yet implemented
bits_CAP_MOVE_SHOOT = 0x00000040, // tries to shoot weapon while moving
bits_CAP_SKIP_NAV_GROUND_CHECK = 0x00000080, // optimization - skips ground tests while computing navigation
bits_CAP_USE = 0x00000100, // open doors/push buttons/pull levers
//bits_CAP_HEAR = 0x00000200, // can hear forced sounds
bits_CAP_AUTO_DOORS = 0x00000400, // can trigger auto doors
bits_CAP_OPEN_DOORS = 0x00000800, // can open manual doors
bits_CAP_TURN_HEAD = 0x00001000, // can turn head, always bone controller 0
bits_CAP_WEAPON_RANGE_ATTACK1 = 0x00002000, // can do a weapon range attack 1
bits_CAP_WEAPON_RANGE_ATTACK2 = 0x00004000, // can do a weapon range attack 2
bits_CAP_WEAPON_MELEE_ATTACK1 = 0x00008000, // can do a weapon melee attack 1
bits_CAP_WEAPON_MELEE_ATTACK2 = 0x00010000, // can do a weapon melee attack 2
bits_CAP_INNATE_RANGE_ATTACK1 = 0x00020000, // can do a innate range attack 1
bits_CAP_INNATE_RANGE_ATTACK2 = 0x00040000, // can do a innate range attack 1
bits_CAP_INNATE_MELEE_ATTACK1 = 0x00080000, // can do a innate melee attack 1
bits_CAP_INNATE_MELEE_ATTACK2 = 0x00100000, // can do a innate melee attack 1
bits_CAP_USE_WEAPONS = 0x00200000, // can use weapons (non-innate attacks)
//bits_CAP_STRAFE = 0x00400000, // strafe ( walk/run sideways)
bits_CAP_ANIMATEDFACE = 0x00800000, // has animated eyes/face
bits_CAP_USE_SHOT_REGULATOR = 0x01000000, // Uses the shot regulator for range attack1
bits_CAP_FRIENDLY_DMG_IMMUNE = 0x02000000, // don't take damage from npc's that are D_LI
bits_CAP_SQUAD = 0x04000000, // can form squads
bits_CAP_DUCK = 0x08000000, // cover and reload ducking
bits_CAP_NO_HIT_PLAYER = 0x10000000, // don't hit players
bits_CAP_AIM_GUN = 0x20000000, // Use arms to aim gun, not just body
bits_CAP_NO_HIT_SQUADMATES = 0x40000000, // none
bits_CAP_SIMPLE_RADIUS_DAMAGE = 0x80000000, // Do not use robust radius damage model on this character.
};
#define bits_CAP_DOORS_GROUP (bits_CAP_AUTO_DOORS | bits_CAP_OPEN_DOORS)
#define bits_CAP_RANGE_ATTACK_GROUP (bits_CAP_WEAPON_RANGE_ATTACK1 | bits_CAP_WEAPON_RANGE_ATTACK2)
#define bits_CAP_MELEE_ATTACK_GROUP (bits_CAP_WEAPON_MELEE_ATTACK1 | bits_CAP_WEAPON_MELEE_ATTACK2)
class CBaseCombatWeapon;
#define BCC_DEFAULT_LOOK_TOWARDS_TOLERANCE 0.9f
enum Disposition_t
{
D_ER, // Undefined - error
D_HT, // Hate
D_FR, // Fear
D_LI, // Like
D_NU // Neutral
};
const int DEF_RELATIONSHIP_PRIORITY = INT_MIN;
struct Relationship_t
{
EHANDLE entity; // Relationship to a particular entity
Class_T classType; // Relationship to a class CLASS_NONE = not class based (Def. in baseentity.h)
Disposition_t disposition; // D_HT (Hate), D_FR (Fear), D_LI (Like), D_NT (Neutral)
int priority; // Relative importance of this relationship (higher numbers mean more important)
DECLARE_SIMPLE_DATADESC();
};
//-----------------------------------------------------------------------------
// Purpose: This should contain all of the combat entry points / functionality
// that are common between NPCs and players
//-----------------------------------------------------------------------------
class CBaseCombatCharacter : public CBaseFlex
{
DECLARE_CLASS( CBaseCombatCharacter, CBaseFlex );
public:
CBaseCombatCharacter(void);
~CBaseCombatCharacter(void);
DECLARE_SERVERCLASS();
DECLARE_DATADESC();
DECLARE_PREDICTABLE();
#ifdef MAPBASE_VSCRIPT
DECLARE_ENT_SCRIPTDESC();
#endif
public:
virtual void Spawn( void );
virtual void Precache();
virtual int Restore( IRestore &restore );
virtual const impactdamagetable_t &GetPhysicsImpactDamageTable( void );
int TakeHealth( float flHealth, int bitsDamageType );
void CauseDeath( const CTakeDamageInfo &info );
virtual bool FVisible ( CBaseEntity *pEntity, int traceMask = MASK_BLOCKLOS, CBaseEntity **ppBlocker = NULL ); // true iff the parameter can be seen by me.
virtual bool FVisible( const Vector &vecTarget, int traceMask = MASK_BLOCKLOS, CBaseEntity **ppBlocker = NULL ) { return BaseClass::FVisible( vecTarget, traceMask, ppBlocker ); }
static void ResetVisibilityCache( CBaseCombatCharacter *pBCC = NULL );
#ifdef MAPBASE
virtual bool ShouldUseVisibilityCache( CBaseEntity *pEntity );
#endif
#ifdef PORTAL
virtual bool FVisibleThroughPortal( const CProp_Portal *pPortal, CBaseEntity *pEntity, int traceMask = MASK_BLOCKLOS, CBaseEntity **ppBlocker = NULL );
#endif
virtual bool FInViewCone( CBaseEntity *pEntity );
virtual bool FInViewCone( const Vector &vecSpot );
#ifdef PORTAL
virtual CProp_Portal* FInViewConeThroughPortal( CBaseEntity *pEntity );
virtual CProp_Portal* FInViewConeThroughPortal( const Vector &vecSpot );
#endif
virtual bool FInAimCone( CBaseEntity *pEntity );
virtual bool FInAimCone( const Vector &vecSpot );
virtual bool ShouldShootMissTarget( CBaseCombatCharacter *pAttacker );
virtual CBaseEntity *FindMissTarget( void );
#ifndef MAPBASE // This function now exists in CBaseEntity
// Do not call HandleInteraction directly, use DispatchInteraction
bool DispatchInteraction( int interactionType, void *data, CBaseCombatCharacter* sourceEnt ) { return ( interactionType > 0 ) ? HandleInteraction( interactionType, data, sourceEnt ) : false; }
#endif
virtual bool HandleInteraction( int interactionType, void *data, CBaseCombatCharacter* sourceEnt );
virtual QAngle BodyAngles();
virtual Vector BodyDirection2D( void );
virtual Vector BodyDirection3D( void );
virtual Vector HeadDirection2D( void ) { return BodyDirection2D( ); }; // No head motion so just return body dir
virtual Vector HeadDirection3D( void ) { return BodyDirection2D( ); }; // No head motion so just return body dir
virtual Vector EyeDirection2D( void ) { return HeadDirection2D( ); }; // No eye motion so just return head dir
virtual Vector EyeDirection3D( void ) { return HeadDirection3D( ); }; // No eye motion so just return head dir
virtual void SetTransmit( CCheckTransmitInfo *pInfo, bool bAlways );
// -----------------------
// Fog
// -----------------------
virtual bool IsHiddenByFog( const Vector &target ) const; ///< return true if given target cant be seen because of fog
virtual bool IsHiddenByFog( CBaseEntity *target ) const; ///< return true if given target cant be seen because of fog
virtual bool IsHiddenByFog( float range ) const; ///< return true if given distance is too far to see through the fog
virtual float GetFogObscuredRatio( const Vector &target ) const;///< return 0-1 ratio where zero is not obscured, and 1 is completely obscured
virtual float GetFogObscuredRatio( CBaseEntity *target ) const; ///< return 0-1 ratio where zero is not obscured, and 1 is completely obscured
virtual float GetFogObscuredRatio( float range ) const; ///< return 0-1 ratio where zero is not obscured, and 1 is completely obscured
// -----------------------
// Vision
// -----------------------
enum FieldOfViewCheckType { USE_FOV, DISREGARD_FOV };
// Visible starts with line of sight, and adds all the extra game checks like fog, smoke, camo...
bool IsAbleToSee( const CBaseEntity *entity, FieldOfViewCheckType checkFOV );
bool IsAbleToSee( CBaseCombatCharacter *pBCC, FieldOfViewCheckType checkFOV );
virtual bool IsLookingTowards( const CBaseEntity *target, float cosTolerance = BCC_DEFAULT_LOOK_TOWARDS_TOLERANCE ) const; // return true if our view direction is pointing at the given target, within the cosine of the angular tolerance. LINE OF SIGHT IS NOT CHECKED.
virtual bool IsLookingTowards( const Vector &target, float cosTolerance = BCC_DEFAULT_LOOK_TOWARDS_TOLERANCE ) const; // return true if our view direction is pointing at the given target, within the cosine of the angular tolerance. LINE OF SIGHT IS NOT CHECKED.
virtual bool IsInFieldOfView( CBaseEntity *entity ) const; // Calls IsLookingTowards with the current field of view.
virtual bool IsInFieldOfView( const Vector &pos ) const;
enum LineOfSightCheckType
{
IGNORE_NOTHING,
IGNORE_ACTORS
};
virtual bool IsLineOfSightClear( CBaseEntity *entity, LineOfSightCheckType checkType = IGNORE_NOTHING ) const;// strictly LOS check with no other considerations
virtual bool IsLineOfSightClear( const Vector &pos, LineOfSightCheckType checkType = IGNORE_NOTHING, CBaseEntity *entityToIgnore = NULL ) const;
// -----------------------
// Ammo
// -----------------------
virtual int GiveAmmo( int iCount, int iAmmoIndex, bool bSuppressSound = false );
int GiveAmmo( int iCount, const char *szName, bool bSuppressSound = false );
virtual void RemoveAmmo( int iCount, int iAmmoIndex );
virtual void RemoveAmmo( int iCount, const char *szName );
void RemoveAllAmmo( );
virtual int GetAmmoCount( int iAmmoIndex ) const;
int GetAmmoCount( char *szName ) const;
virtual Activity NPC_TranslateActivity( Activity baseAct );
// -----------------------
// Weapons
// -----------------------
CBaseCombatWeapon* Weapon_Create( const char *pWeaponName );
virtual Activity Weapon_TranslateActivity( Activity baseAct, bool *pRequired = NULL );
void Weapon_SetActivity( Activity newActivity, float duration );
virtual void Weapon_FrameUpdate( void );
virtual void Weapon_HandleAnimEvent( animevent_t *pEvent );
CBaseCombatWeapon* Weapon_OwnsThisType( const char *pszWeapon, int iSubType = 0 ) const; // True if already owns a weapon of this class
virtual bool Weapon_CanUse( CBaseCombatWeapon *pWeapon ); // True is allowed to use this class of weapon
#ifdef MAPBASE
virtual Activity Weapon_BackupActivity( Activity activity, bool weaponTranslationWasRequired = false, CBaseCombatWeapon *pSpecificWeapon = NULL );
virtual void Weapon_Equip( CBaseCombatWeapon *pWeapon ); // Adds weapon to player
virtual void Weapon_EquipHolstered( CBaseCombatWeapon *pWeapon ); // Pretty much only useful for NPCs
virtual void Weapon_HandleEquip( CBaseCombatWeapon *pWeapon );
#else
virtual void Weapon_Equip( CBaseCombatWeapon *pWeapon ); // Adds weapon to player
#endif
virtual bool Weapon_EquipAmmoOnly( CBaseCombatWeapon *pWeapon ); // Adds weapon ammo to player, leaves weapon
bool Weapon_Detach( CBaseCombatWeapon *pWeapon ); // Clear any pointers to the weapon.
virtual void Weapon_Drop( CBaseCombatWeapon *pWeapon, const Vector *pvecTarget = NULL, const Vector *pVelocity = NULL );
virtual bool Weapon_Switch( CBaseCombatWeapon *pWeapon, int viewmodelindex = 0 ); // Switch to given weapon if has ammo (false if failed)
virtual Vector Weapon_ShootPosition( ); // gun position at current position/orientation
bool Weapon_IsOnGround( CBaseCombatWeapon *pWeapon );
CBaseEntity* Weapon_FindUsable( const Vector &range ); // search for a usable weapon in this range
virtual bool Weapon_CanSwitchTo(CBaseCombatWeapon *pWeapon);
virtual bool Weapon_SlotOccupied( CBaseCombatWeapon *pWeapon );
virtual CBaseCombatWeapon *Weapon_GetSlot( int slot ) const;
CBaseCombatWeapon *Weapon_GetWpnForAmmo( int iAmmoIndex );
// For weapon strip
void Weapon_DropAll( bool bDisallowWeaponPickup = false );
virtual bool AddPlayerItem( CBaseCombatWeapon *pItem ) { return false; }
virtual bool RemovePlayerItem( CBaseCombatWeapon *pItem ) { return false; }
virtual bool CanBecomeServerRagdoll( void ) { return true; }
// -----------------------
// Damage
// -----------------------
// Don't override this for characters, override the per-life-state versions below
virtual int OnTakeDamage( const CTakeDamageInfo &info );
// Override these to control how your character takes damage in different states
virtual int OnTakeDamage_Alive( const CTakeDamageInfo &info );
virtual int OnTakeDamage_Dying( const CTakeDamageInfo &info );
virtual int OnTakeDamage_Dead( const CTakeDamageInfo &info );
virtual float GetAliveDuration( void ) const; // return time we have been alive (only valid when alive)
virtual void OnFriendDamaged( CBaseCombatCharacter *pSquadmate, CBaseEntity *pAttacker ) {}
virtual void NotifyFriendsOfDamage( CBaseEntity *pAttackerEntity ) {}
virtual bool HasEverBeenInjured( int team = TEAM_ANY ) const; // return true if we have ever been injured by a member of the given team
virtual float GetTimeSinceLastInjury( int team = TEAM_ANY ) const; // return time since we were hurt by a member of the given team
virtual void OnPlayerKilledOther( CBaseEntity *pVictim, const CTakeDamageInfo &info ) {}
// utility function to calc damage force
Vector CalcDamageForceVector( const CTakeDamageInfo &info );
virtual int BloodColor();
virtual Activity GetDeathActivity( void );
virtual bool CorpseGib( const CTakeDamageInfo &info );
virtual void CorpseFade( void ); // Called instead of GibNPC() when gibs are disabled
virtual bool HasHumanGibs( void );
virtual bool HasAlienGibs( void );
virtual bool ShouldGib( const CTakeDamageInfo &info ) { return false; } // Always ragdoll, unless specified by the leaf class
float GetDamageAccumulator() { return m_flDamageAccumulator; }
int GetDamageCount( void ) { return m_iDamageCount; } // # of times NPC has been damaged. used for tracking 1-shot kills.
// Character killed (only fired once)
virtual void Event_Killed( const CTakeDamageInfo &info );
// Killed a character
void InputKilledNPC( inputdata_t &inputdata );
#ifdef MAPBASE
void InputGiveWeapon( inputdata_t &inputdata );
void InputDropWeapon( inputdata_t &inputdata );
void InputPickupWeaponInstant( inputdata_t &inputdata );
COutputEvent m_OnWeaponEquip;
COutputEvent m_OnWeaponDrop;
virtual void InputHolsterWeapon( inputdata_t &inputdata );
virtual void InputHolsterAndDestroyWeapon( inputdata_t &inputdata );
virtual void InputUnholsterWeapon( inputdata_t &inputdata );
void InputSwitchToWeapon( inputdata_t &inputdata );
COutputEHANDLE m_OnKilledEnemy;
COutputEHANDLE m_OnKilledPlayer;
virtual void OnKilledNPC( CBaseCombatCharacter *pKilled );
virtual CBaseEntity *FindNamedEntity( const char *pszName, IEntityFindFilter *pFilter = NULL );
COutputFloat m_OnHealthChanged;
#else
virtual void OnKilledNPC( CBaseCombatCharacter *pKilled ) {};
#endif
// Exactly one of these happens immediately after killed (gibbed may happen later when the corpse gibs)
// Character gibbed or faded out (violence controls) (only fired once)
// returns true if gibs were spawned
virtual bool Event_Gibbed( const CTakeDamageInfo &info );
// Character entered the dying state without being gibbed (only fired once)
virtual void Event_Dying( const CTakeDamageInfo &info );
virtual void Event_Dying();
// character died and should become a ragdoll now
// return true if converted to a ragdoll, false to use AI death
virtual bool BecomeRagdoll( const CTakeDamageInfo &info, const Vector &forceVector );
virtual void FixupBurningServerRagdoll( CBaseEntity *pRagdoll );
virtual bool BecomeRagdollBoogie( CBaseEntity *pKiller, const Vector &forceVector, float duration, int flags );
#ifdef MAPBASE
// A version of BecomeRagdollBoogie() that allows the color to change and returns the entity itself instead.
// In order to avoid breaking anything, it doesn't change the original function.
virtual CBaseEntity *BecomeRagdollBoogie( CBaseEntity *pKiller, const Vector &forceVector, float duration, int flags, const Vector *vecColor );
#endif
CBaseEntity *FindHealthItem( const Vector &vecPosition, const Vector &range );
virtual CBaseEntity *CheckTraceHullAttack( float flDist, const Vector &mins, const Vector &maxs, int iDamage, int iDmgType, float forceScale = 1.0f, bool bDamageAnyNPC = false );
virtual CBaseEntity *CheckTraceHullAttack( const Vector &vStart, const Vector &vEnd, const Vector &mins, const Vector &maxs, int iDamage, int iDmgType, float flForceScale = 1.0f, bool bDamageAnyNPC = false );
virtual CBaseCombatCharacter *MyCombatCharacterPointer( void ) { return this; }
// VPHYSICS
virtual void VPhysicsShadowCollision( int index, gamevcollisionevent_t *pEvent );
virtual void VPhysicsUpdate( IPhysicsObject *pPhysics );
float CalculatePhysicsStressDamage( vphysics_objectstress_t *pStressOut, IPhysicsObject *pPhysics );
void ApplyStressDamage( IPhysicsObject *pPhysics, bool bRequireLargeObject );
virtual void PushawayTouch( CBaseEntity *pOther ) {}
void SetImpactEnergyScale( float fScale ) { m_impactEnergyScale = fScale; }
virtual void UpdateOnRemove( void );
virtual Disposition_t IRelationType( CBaseEntity *pTarget );
virtual int IRelationPriority( CBaseEntity *pTarget );
#ifdef MAPBASE
void AddRelationship( const char *pszRelationship, CBaseEntity *pActivator );
void InputSetRelationship( inputdata_t &inputdata );
#endif
virtual void SetLightingOriginRelative( CBaseEntity *pLightingOrigin );
protected:
Relationship_t *FindEntityRelationship( CBaseEntity *pTarget );
public:
// Vehicle queries
virtual bool IsInAVehicle( void ) const { return false; }
virtual IServerVehicle *GetVehicle( void ) { return NULL; }
virtual CBaseEntity *GetVehicleEntity( void ) { return NULL; }
virtual bool ExitVehicle( void ) { return false; }
// Blood color (see BLOOD_COLOR_* macros in baseentity.h)
void SetBloodColor( int nBloodColor );
#ifdef MAPBASE
void InputSetBloodColor( inputdata_t &inputdata );
#endif
// Weapons..
CBaseCombatWeapon* GetActiveWeapon() const;
int WeaponCount() const;
CBaseCombatWeapon* GetWeapon( int i ) const;
bool RemoveWeapon( CBaseCombatWeapon *pWeapon );
virtual void RemoveAllWeapons();
WeaponProficiency_t GetCurrentWeaponProficiency()
{
#ifdef MAPBASE
// Mapbase adds proficiency override
return (m_ProficiencyOverride > WEAPON_PROFICIENCY_INVALID) ? m_ProficiencyOverride : m_CurrentWeaponProficiency;
#else
return m_CurrentWeaponProficiency;
#endif
}
void SetCurrentWeaponProficiency( WeaponProficiency_t iProficiency ) { m_CurrentWeaponProficiency = iProficiency; }
virtual WeaponProficiency_t CalcWeaponProficiency( CBaseCombatWeapon *pWeapon );
virtual Vector GetAttackSpread( CBaseCombatWeapon *pWeapon, CBaseEntity *pTarget = NULL );
virtual float GetSpreadBias( CBaseCombatWeapon *pWeapon, CBaseEntity *pTarget );
virtual void DoMuzzleFlash();
#ifdef MAPBASE_VSCRIPT
HSCRIPT GetScriptActiveWeapon();
HSCRIPT GetScriptWeaponIndex( int i );
HSCRIPT GetScriptWeaponByType( const char *pszWeapon, int iSubType = 0 );
void GetScriptAllWeapons( HSCRIPT hTable );
int ScriptGetCurrentWeaponProficiency() { return GetCurrentWeaponProficiency(); }
void ScriptDropWeapon( HSCRIPT hWeapon );
void ScriptEquipWeapon( HSCRIPT hWeapon );
int ScriptGetAmmoCount( int iType ) const;
void ScriptSetAmmoCount( int iType, int iCount );
const Vector& ScriptGetAttackSpread( HSCRIPT hWeapon, HSCRIPT hTarget );
float ScriptGetSpreadBias( HSCRIPT hWeapon, HSCRIPT hTarget );
int ScriptRelationType( HSCRIPT pTarget );
int ScriptRelationPriority( HSCRIPT pTarget );
void ScriptSetRelationship( HSCRIPT pTarget, int disposition, int priority );
HSCRIPT GetScriptVehicleEntity();
bool ScriptInViewCone( const Vector &vecSpot ) { return FInViewCone( vecSpot ); }
bool ScriptEntInViewCone( HSCRIPT pEntity ) { return FInViewCone( ToEnt( pEntity ) ); }
bool ScriptInAimCone( const Vector &vecSpot ) { return FInAimCone( vecSpot ); }
bool ScriptEntInAimCone( HSCRIPT pEntity ) { return FInAimCone( ToEnt( pEntity ) ); }
const Vector& ScriptBodyAngles( void ) { static Vector vec; QAngle qa = BodyAngles(); vec.x = qa.x; vec.y = qa.y; vec.z = qa.z; return vec; }
#endif
// Interactions
static void InitInteractionSystem();
// Relationships
static void AllocateDefaultRelationships( );
static void SetDefaultRelationship( Class_T nClass, Class_T nClassTarget, Disposition_t nDisposition, int nPriority );
#ifdef MAPBASE
static Disposition_t GetDefaultRelationshipDisposition( Class_T nClassSource, Class_T nClassTarget );
static int GetDefaultRelationshipPriority( Class_T nClassSource, Class_T nClassTarget );
int GetDefaultRelationshipPriority( Class_T nClassTarget );
#endif
Disposition_t GetDefaultRelationshipDisposition( Class_T nClassTarget );
virtual void AddEntityRelationship( CBaseEntity *pEntity, Disposition_t nDisposition, int nPriority );
virtual bool RemoveEntityRelationship( CBaseEntity *pEntity );
virtual void AddClassRelationship( Class_T nClass, Disposition_t nDisposition, int nPriority );
#ifdef MAPBASE
virtual bool RemoveClassRelationship( Class_T nClass );
#endif
virtual void ChangeTeam( int iTeamNum );
// Nav hull type
Hull_t GetHullType() const { return m_eHull; }
void SetHullType( Hull_t hullType ) { m_eHull = hullType; }
// FIXME: The following 3 methods are backdoor hack methods
// This is a sort of hack back-door only used by physgun!
void SetAmmoCount( int iCount, int iAmmoIndex );
// This is a hack to blat out the current active weapon...
// Used by weapon_slam + game_ui
void SetActiveWeapon( CBaseCombatWeapon *pNewWeapon );
void ClearActiveWeapon() { SetActiveWeapon( NULL ); }
virtual void OnChangeActiveWeapon( CBaseCombatWeapon *pOldWeapon, CBaseCombatWeapon *pNewWeapon ) {}
// I can't use my current weapon anymore. Switch me to the next best weapon.
bool SwitchToNextBestWeapon(CBaseCombatWeapon *pCurrent);
// This is a hack to copy the relationship strings used by monstermaker
void SetRelationshipString( string_t theString ) { m_RelationshipString = theString; }
float GetNextAttack() const { return m_flNextAttack; }
void SetNextAttack( float flWait ) { m_flNextAttack = flWait; }
bool m_bForceServerRagdoll;
// Pickup prevention
bool IsAllowedToPickupWeapons( void ) { return !m_bPreventWeaponPickup; }
void SetPreventWeaponPickup( bool bPrevent ) { m_bPreventWeaponPickup = bPrevent; }
bool m_bPreventWeaponPickup;
virtual CNavArea *GetLastKnownArea( void ) const { return m_lastNavArea; } // return the last nav area the player occupied - NULL if unknown
virtual bool IsAreaTraversable( const CNavArea *area ) const; // return true if we can use the given area
virtual void ClearLastKnownArea( void );
virtual void UpdateLastKnownArea( void ); // invoke this to update our last known nav area (since there is no think method chained to CBaseCombatCharacter)
virtual void OnNavAreaChanged( CNavArea *enteredArea, CNavArea *leftArea ) { } // invoked (by UpdateLastKnownArea) when we enter a new nav area (or it is reset to NULL)
virtual void OnNavAreaRemoved( CNavArea *removedArea );
// -----------------------
// Notification from INextBots.
// -----------------------
virtual void OnPursuedBy( INextBot * RESTRICT pPursuer ){} // called every frame while pursued by a bot in DirectChase.
#ifdef GLOWS_ENABLE
// Glows
void AddGlowEffect( void );
void RemoveGlowEffect( void );
bool IsGlowEffectActive( void );
#endif // GLOWS_ENABLE
#ifdef INVASION_DLL
public:
// TF2 Powerups
virtual bool CanBePoweredUp( void );
bool HasPowerup( int iPowerup );
virtual bool CanPowerupNow( int iPowerup ); // Return true if I can be powered by this powerup right now
virtual bool CanPowerupEver( int iPowerup ); // Return true if I ever accept this powerup type
void SetPowerup( int iPowerup, bool bState, float flTime = 0, float flAmount = 0, CBaseEntity *pAttacker = NULL, CDamageModifier *pDamageModifier = NULL );
virtual bool AttemptToPowerup( int iPowerup, float flTime, float flAmount = 0, CBaseEntity *pAttacker = NULL, CDamageModifier *pDamageModifier = NULL );
virtual float PowerupDuration( int iPowerup, float flTime );
virtual void PowerupStart( int iPowerup, float flAmount = 0, CBaseEntity *pAttacker = NULL, CDamageModifier *pDamageModifier = NULL );
virtual void PowerupEnd( int iPowerup );
void PowerupThink( void );
virtual void PowerupThink( int iPowerup );
public:
CNetworkVar( int, m_iPowerups );
float m_flPowerupAttemptTimes[ MAX_POWERUPS ];
float m_flPowerupEndTimes[ MAX_POWERUPS ];
float m_flFractionalBoost; // POWERUP_BOOST health fraction - specific powerup data
#endif
public:
// returns the last body region that took damage
int LastHitGroup() const { return m_LastHitGroup; }
#ifndef MAPBASE // For filter_damage_transfer
protected:
#endif
void SetLastHitGroup( int nHitGroup ) { m_LastHitGroup = nHitGroup; }
public:
CNetworkVar( float, m_flNextAttack ); // cannot attack again until this time
#ifdef GLOWS_ENABLE
protected:
CNetworkVar( bool, m_bGlowEnabled );
#endif // GLOWS_ENABLE
private:
Hull_t m_eHull;
void UpdateGlowEffect( void );
void DestroyGlowEffect( void );
protected:
int m_bloodColor; // color of blood particless
// -------------------
// combat ability data
// -------------------
float m_flFieldOfView; // cosine of field of view for this character
Vector m_HackedGunPos; // HACK until we can query end of gun
string_t m_RelationshipString; // Used to load up relationship keyvalues
float m_impactEnergyScale;// scale the amount of energy used to calculate damage this ent takes due to physics
public:
static int GetInteractionID(); // Returns the next interaction #
#ifdef MAPBASE
// Mapbase's new method for adding interactions which allows them to be handled with their names, currently for VScript
static void AddInteractionWithString( int &interaction, const char *szName );
#endif
protected:
// Visibility-related stuff
bool ComputeLOS( const Vector &vecEyePosition, const Vector &vecTarget ) const;
private:
// For weapon strip
void ThrowDirForWeaponStrip( CBaseCombatWeapon *pWeapon, const Vector &vecForward, Vector *pVecThrowDir );
void DropWeaponForWeaponStrip( CBaseCombatWeapon *pWeapon, const Vector &vecForward, const QAngle &vecAngles, float flDiameter );
friend class CScriptedTarget; // needs to access GetInteractionID()
static int m_lastInteraction; // Last registered interaction #
static Relationship_t** m_DefaultRelationship;
// attack/damage
int m_LastHitGroup; // the last body region that took damage
float m_flDamageAccumulator; // so very small amounts of damage do not get lost.
int m_iDamageCount; // # of times NPC has been damaged. used for tracking 1-shot kills.
// Weapon proficiency gets calculated each time an NPC changes his weapon, and then
// cached off as the CurrentWeaponProficiency.
WeaponProficiency_t m_CurrentWeaponProficiency;
#ifdef MAPBASE
// Weapon proficiency can be overridden with this.
WeaponProficiency_t m_ProficiencyOverride = WEAPON_PROFICIENCY_INVALID;
#endif
// ---------------
// Relationships
// ---------------
CUtlVector<Relationship_t> m_Relationship; // Array of relationships
protected:
// shared ammo slots
CNetworkArrayForDerived( int, m_iAmmo, MAX_AMMO_SLOTS );
// Usable character items
CNetworkArray( CBaseCombatWeaponHandle, m_hMyWeapons, MAX_WEAPONS );
CNetworkHandle( CBaseCombatWeapon, m_hActiveWeapon );
friend class CCleanupDefaultRelationShips;
IntervalTimer m_aliveTimer;
unsigned int m_hasBeenInjured; // bitfield corresponding to team ID that did the injury
// we do this because MAX_TEAMS is 32, which is wasteful for most games
enum { MAX_DAMAGE_TEAMS = 4 };
struct DamageHistory
{
int team; // which team hurt us (TEAM_INVALID means slot unused)
IntervalTimer interval; // how long has it been
};
DamageHistory m_damageHistory[ MAX_DAMAGE_TEAMS ];
// last known navigation area of player - NULL if unknown
CNavArea *m_lastNavArea;
CAI_MoveMonitor m_NavAreaUpdateMonitor;
int m_registeredNavTeam; // ugly, but needed to clean up player team counts in nav mesh
};
inline float CBaseCombatCharacter::GetAliveDuration( void ) const
{
return m_aliveTimer.GetElapsedTime();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
inline int CBaseCombatCharacter::WeaponCount() const
{
return MAX_WEAPONS;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : i -
//-----------------------------------------------------------------------------
inline CBaseCombatWeapon *CBaseCombatCharacter::GetWeapon( int i ) const
{
Assert( (i >= 0) && (i < MAX_WEAPONS) );
return m_hMyWeapons[i].Get();
}
#ifdef INVASION_DLL
// Powerup Inlines
inline bool CBaseCombatCharacter::CanBePoweredUp( void ) { return true; }
inline float CBaseCombatCharacter::PowerupDuration( int iPowerup, float flTime ) { return flTime; }
inline void CBaseCombatCharacter::PowerupEnd( int iPowerup ) { return; }
inline void CBaseCombatCharacter::PowerupThink( int iPowerup ) { return; }
#endif
EXTERN_SEND_TABLE(DT_BaseCombatCharacter);
void RadiusDamage( const CTakeDamageInfo &info, const Vector &vecSrc, float flRadius, int iClassIgnore, CBaseEntity *pEntityIgnore );
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
class CTraceFilterMelee : public CTraceFilterEntitiesOnly
{
public:
// It does have a base, but we'll never network anything below here..
DECLARE_CLASS_NOBASE( CTraceFilterMelee );
CTraceFilterMelee( const IHandleEntity *passentity, int collisionGroup, CTakeDamageInfo *dmgInfo, float flForceScale, bool bDamageAnyNPC )
: m_pPassEnt(passentity), m_collisionGroup(collisionGroup), m_dmgInfo(dmgInfo), m_pHit(NULL), m_flForceScale(flForceScale), m_bDamageAnyNPC(bDamageAnyNPC)
{
}
virtual bool ShouldHitEntity( IHandleEntity *pHandleEntity, int contentsMask );
public:
const IHandleEntity *m_pPassEnt;
int m_collisionGroup;
CTakeDamageInfo *m_dmgInfo;
CBaseEntity *m_pHit;
float m_flForceScale;
bool m_bDamageAnyNPC;
};
#endif // BASECOMBATCHARACTER_H

View File

@@ -0,0 +1,747 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#include "cbase.h"
#include "ai_basenpc.h"
#include "animation.h"
#include "basecombatweapon.h"
#include "player.h" // For gEvilImpulse101 / CBasePlayer
#include "gamerules.h" // For g_pGameRules
#include <KeyValues.h>
#include "ammodef.h"
#include "baseviewmodel.h"
#include "in_buttons.h"
#include "soundent.h"
#include "weapon_parse.h"
#include "game.h"
#include "engine/IEngineSound.h"
#include "sendproxy.h"
#include "tier1/strtools.h"
#include "vphysics/constraints.h"
#include "npcevent.h"
#include "igamesystem.h"
#include "collisionutils.h"
#include "iservervehicle.h"
#include "func_break.h"
#ifdef HL2MP
#include "hl2mp_gamerules.h"
#endif
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
extern int gEvilImpulse101; // In Player.h
// -----------------------------------------
// Sprite Index info
// -----------------------------------------
short g_sModelIndexLaser; // holds the index for the laser beam
const char *g_pModelNameLaser = "sprites/laserbeam.vmt";
short g_sModelIndexLaserDot; // holds the index for the laser beam dot
short g_sModelIndexFireball; // holds the index for the fireball
short g_sModelIndexSmoke; // holds the index for the smoke cloud
short g_sModelIndexWExplosion; // holds the index for the underwater explosion
short g_sModelIndexBubbles; // holds the index for the bubbles model
short g_sModelIndexBloodDrop; // holds the sprite index for the initial blood
short g_sModelIndexBloodSpray; // holds the sprite index for splattered blood
ConVar weapon_showproficiency( "weapon_showproficiency", "0" );
extern ConVar ai_debug_shoot_positions;
//-----------------------------------------------------------------------------
// Purpose: Precache global weapon sounds
//-----------------------------------------------------------------------------
void W_Precache(void)
{
PrecacheFileWeaponInfoDatabase( filesystem, g_pGameRules->GetEncryptionKey() );
#ifdef HL1_DLL
g_sModelIndexWExplosion = CBaseEntity::PrecacheModel ("sprites/WXplo1.vmt");// underwater fireball
g_sModelIndexBloodSpray = CBaseEntity::PrecacheModel ("sprites/bloodspray.vmt"); // initial blood
g_sModelIndexBloodDrop = CBaseEntity::PrecacheModel ("sprites/blood.vmt"); // splattered blood
g_sModelIndexLaserDot = CBaseEntity::PrecacheModel("sprites/laserdot.vmt");
#endif // HL1_DLL
#ifndef TF_DLL
g_sModelIndexFireball = CBaseEntity::PrecacheModel ("sprites/zerogxplode.vmt");// fireball
g_sModelIndexSmoke = CBaseEntity::PrecacheModel ("sprites/steam1.vmt");// smoke
g_sModelIndexBubbles = CBaseEntity::PrecacheModel ("sprites/bubble.vmt");//bubbles
g_sModelIndexLaser = CBaseEntity::PrecacheModel( (char *)g_pModelNameLaser );
PrecacheParticleSystem( "blood_impact_red_01" );
PrecacheParticleSystem( "blood_impact_green_01" );
PrecacheParticleSystem( "blood_impact_yellow_01" );
CBaseEntity::PrecacheModel ("effects/bubble.vmt");//bubble trails
CBaseEntity::PrecacheModel("models/weapons/w_bullet.mdl");
#endif
CBaseEntity::PrecacheScriptSound( "BaseCombatWeapon.WeaponDrop" );
CBaseEntity::PrecacheScriptSound( "BaseCombatWeapon.WeaponMaterialize" );
}
//-----------------------------------------------------------------------------
// Purpose: Transmit weapon data
//-----------------------------------------------------------------------------
int CBaseCombatWeapon::UpdateTransmitState( void)
{
// If the weapon is being carried by a CBaseCombatCharacter, let the combat character do the logic
// about whether or not to transmit it.
if ( GetOwner() )
{
return SetTransmitState( FL_EDICT_PVSCHECK );
}
else
{
// If it's just lying around, then use CBaseEntity's visibility test to see if it should be sent.
return BaseClass::UpdateTransmitState();
}
}
void CBaseCombatWeapon::Operator_FrameUpdate( CBaseCombatCharacter *pOperator )
{
StudioFrameAdvance( ); // animate
if ( IsSequenceFinished() )
{
if ( SequenceLoops() )
{
// animation does loop, which means we're playing subtle idle. Might need to fidget.
int iSequence = SelectWeightedSequence( GetActivity() );
if ( iSequence != ACTIVITY_NOT_AVAILABLE )
{
ResetSequence( iSequence ); // Set to new anim (if it's there)
}
}
#if 0
else
{
// animation that just ended doesn't loop! That means we just finished a fidget
// and should return to our heaviest weighted idle (the subtle one)
SelectHeaviestSequence( GetActivity() );
}
#endif
}
// Animation events are passed back to the weapon's owner/operator
DispatchAnimEvents( pOperator );
// Update and dispatch the viewmodel events
CBasePlayer *pOwner = ToBasePlayer( GetOwner() );
if ( pOwner == NULL )
return;
CBaseViewModel *vm = pOwner->GetViewModel( m_nViewModelIndex );
if ( vm != NULL )
{
vm->StudioFrameAdvance();
vm->DispatchAnimEvents( this );
}
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : *pEvent -
// *pOperator -
//-----------------------------------------------------------------------------
void CBaseCombatWeapon::Operator_HandleAnimEvent( animevent_t *pEvent, CBaseCombatCharacter *pOperator )
{
if ( (pEvent->type & AE_TYPE_NEWEVENTSYSTEM) && (pEvent->type & AE_TYPE_SERVER) )
{
if ( pEvent->event == AE_NPC_WEAPON_FIRE )
{
bool bSecondary = (atoi( pEvent->options ) != 0);
Operator_ForceNPCFire( pOperator, bSecondary );
return;
}
else if ( pEvent->event == AE_WPN_PLAYWPNSOUND )
{
int iSnd = GetWeaponSoundFromString(pEvent->options);
if ( iSnd != -1 )
{
WeaponSound( (WeaponSound_t)iSnd );
}
}
}
DevWarning( 2, "Unhandled animation event %d from %s --> %s\n", pEvent->event, pOperator->GetClassname(), GetClassname() );
}
// NOTE: This should never be called when a character is operating the weapon. Animation events should be
// routed through the character, and then back into CharacterAnimEvent()
void CBaseCombatWeapon::HandleAnimEvent( animevent_t *pEvent )
{
//If the player is receiving this message, pass it through
CBasePlayer *pOwner = ToBasePlayer( GetOwner() );
if ( pOwner != NULL )
{
Operator_HandleAnimEvent( pEvent, pOwner );
}
}
//-----------------------------------------------------------------------------
// Purpose: Make the weapon visible and tangible
//-----------------------------------------------------------------------------
CBaseEntity* CBaseCombatWeapon::Respawn( void )
{
// make a copy of this weapon that is invisible and inaccessible to players (no touch function). The weapon spawn/respawn code
// will decide when to make the weapon visible and touchable.
CBaseEntity *pNewWeapon = CBaseEntity::Create( GetClassname(), g_pGameRules->VecWeaponRespawnSpot( this ), GetLocalAngles(), GetOwnerEntity() );
if ( pNewWeapon )
{
pNewWeapon->AddEffects( EF_NODRAW );// invisible for now
pNewWeapon->SetTouch( NULL );// no touch
pNewWeapon->SetThink( &CBaseCombatWeapon::AttemptToMaterialize );
UTIL_DropToFloor( this, MASK_SOLID );
// not a typo! We want to know when the weapon the player just picked up should respawn! This new entity we created is the replacement,
// but when it should respawn is based on conditions belonging to the weapon that was taken.
pNewWeapon->SetNextThink( gpGlobals->curtime + g_pGameRules->FlWeaponRespawnTime( this ) );
}
else
{
Warning("Respawn failed to create %s!\n", GetClassname() );
}
return pNewWeapon;
}
//-----------------------------------------------------------------------------
// Purpose: Weapons ignore other weapons when LOS tracing
//-----------------------------------------------------------------------------
class CWeaponLOSFilter : public CTraceFilterSkipTwoEntities
{
DECLARE_CLASS( CWeaponLOSFilter, CTraceFilterSkipTwoEntities );
public:
CWeaponLOSFilter( IHandleEntity *pHandleEntity, IHandleEntity *pHandleEntity2, int collisionGroup ) :
CTraceFilterSkipTwoEntities( pHandleEntity, pHandleEntity2, collisionGroup ), m_pVehicle( NULL )
{
// If the tracing entity is in a vehicle, then ignore it
if ( pHandleEntity != NULL )
{
CBaseCombatCharacter *pBCC = ((CBaseEntity *)pHandleEntity)->MyCombatCharacterPointer();
if ( pBCC != NULL )
{
m_pVehicle = pBCC->GetVehicleEntity();
}
}
}
virtual bool ShouldHitEntity( IHandleEntity *pServerEntity, int contentsMask )
{
CBaseEntity *pEntity = (CBaseEntity *)pServerEntity;
if ( pEntity->GetCollisionGroup() == COLLISION_GROUP_WEAPON )
return false;
// Don't collide with the tracing entity's vehicle (if it exists)
if ( pServerEntity == m_pVehicle )
return false;
if ( pEntity->GetHealth() > 0 )
{
CBreakable *pBreakable = dynamic_cast<CBreakable *>(pEntity);
if ( pBreakable && pBreakable->IsBreakable() && pBreakable->GetMaterialType() == matGlass)
{
return false;
}
}
return BaseClass::ShouldHitEntity( pServerEntity, contentsMask );
}
private:
CBaseEntity *m_pVehicle;
};
//-----------------------------------------------------------------------------
// Purpose: Check the weapon LOS for an owner at an arbitrary position
// If bSetConditions is true, LOS related conditions will also be set
//-----------------------------------------------------------------------------
bool CBaseCombatWeapon::WeaponLOSCondition( const Vector &ownerPos, const Vector &targetPos, bool bSetConditions )
{
// --------------------
// Check for occlusion
// --------------------
CAI_BaseNPC* npcOwner = m_hOwner.Get()->MyNPCPointer();
// Find its relative shoot position
Vector vecRelativeShootPosition;
VectorSubtract( npcOwner->Weapon_ShootPosition(), npcOwner->GetAbsOrigin(), vecRelativeShootPosition );
Vector barrelPos = ownerPos + vecRelativeShootPosition;
// FIXME: If we're in a vehicle, we need some sort of way to handle shooting out of them
// Use the custom LOS trace filter
CWeaponLOSFilter traceFilter( m_hOwner.Get(), npcOwner->GetEnemy(), COLLISION_GROUP_BREAKABLE_GLASS );
trace_t tr;
UTIL_TraceLine( barrelPos, targetPos, MASK_SHOT, &traceFilter, &tr );
// See if we completed the trace without interruption
if ( tr.fraction == 1.0 )
{
if ( ai_debug_shoot_positions.GetBool() )
{
NDebugOverlay::Line( barrelPos, targetPos, 0, 255, 0, false, 1.0 );
}
return true;
}
CBaseEntity *pHitEnt = tr.m_pEnt;
CBasePlayer *pEnemyPlayer = ToBasePlayer( npcOwner->GetEnemy() );
// is player in a vehicle? if so, verify vehicle is target and return if so (so npc shoots at vehicle)
if ( pEnemyPlayer && pEnemyPlayer->IsInAVehicle() )
{
// Ok, player in vehicle, check if vehicle is target we're looking at, fire if it is
// Also, check to see if the owner of the entity is the vehicle, in which case it's valid too.
// This catches vehicles that use bone followers.
CBaseEntity *pVehicle = pEnemyPlayer->GetVehicle()->GetVehicleEnt();
if ( pHitEnt == pVehicle || pHitEnt->GetOwnerEntity() == pVehicle )
return true;
}
// Hitting our enemy is a success case
if ( pHitEnt == npcOwner->GetEnemy() )
{
if ( ai_debug_shoot_positions.GetBool() )
{
NDebugOverlay::Line( barrelPos, targetPos, 0, 255, 0, false, 1.0 );
}
return true;
}
// If a vehicle is blocking the view, grab its driver and use that as the combat character
CBaseCombatCharacter *pBCC;
IServerVehicle *pVehicle = pHitEnt->GetServerVehicle();
if ( pVehicle )
{
pBCC = pVehicle->GetPassenger( );
}
else
{
pBCC = ToBaseCombatCharacter( pHitEnt );
}
if ( pBCC )
{
#ifdef MAPBASE
if ( npcOwner->IRelationType( pBCC ) <= D_FR )
#else
if ( npcOwner->IRelationType( pBCC ) == D_HT )
#endif
return true;
if ( bSetConditions )
{
npcOwner->SetCondition( COND_WEAPON_BLOCKED_BY_FRIEND );
}
}
else if ( bSetConditions )
{
npcOwner->SetCondition( COND_WEAPON_SIGHT_OCCLUDED );
npcOwner->SetEnemyOccluder( pHitEnt );
if( ai_debug_shoot_positions.GetBool() )
{
NDebugOverlay::Line( tr.startpos, tr.endpos, 255, 0, 0, false, 1.0 );
}
}
return false;
}
//-----------------------------------------------------------------------------
// Purpose: Base class always returns not bits
//-----------------------------------------------------------------------------
int CBaseCombatWeapon::WeaponRangeAttack1Condition( float flDot, float flDist )
{
if ( UsesPrimaryAmmo() && !HasPrimaryAmmo() )
{
return COND_NO_PRIMARY_AMMO;
}
else if ( flDist < m_fMinRange1)
{
return COND_TOO_CLOSE_TO_ATTACK;
}
else if (flDist > m_fMaxRange1)
{
return COND_TOO_FAR_TO_ATTACK;
}
else if (flDot < 0.5) // UNDONE: Why check this here? Isn't the AI checking this already?
{
return COND_NOT_FACING_ATTACK;
}
return COND_CAN_RANGE_ATTACK1;
}
//-----------------------------------------------------------------------------
// Purpose: Base class always returns not bits
//-----------------------------------------------------------------------------
int CBaseCombatWeapon::WeaponRangeAttack2Condition( float flDot, float flDist )
{
// currently disabled
return COND_NONE;
if ( m_bReloadsSingly )
{
if (m_iClip2 <=0)
{
return COND_NO_SECONDARY_AMMO;
}
else if ( flDist < m_fMinRange2)
{
return COND_TOO_CLOSE_TO_ATTACK;
}
else if (flDist > m_fMaxRange2)
{
return COND_TOO_FAR_TO_ATTACK;
}
else if (flDot < 0.5)
{
return COND_NOT_FACING_ATTACK;
}
return COND_CAN_RANGE_ATTACK2;
}
return COND_NONE;
}
//-----------------------------------------------------------------------------
// Purpose: Base class always returns not bits
//-----------------------------------------------------------------------------
int CBaseCombatWeapon::WeaponMeleeAttack1Condition( float flDot, float flDist )
{
return COND_NONE;
}
//-----------------------------------------------------------------------------
// Purpose: Base class always returns not bits
//-----------------------------------------------------------------------------
int CBaseCombatWeapon::WeaponMeleeAttack2Condition( float flDot, float flDist )
{
return COND_NONE;
}
//====================================================================================
// WEAPON DROPPING / DESTRUCTION
//====================================================================================
void CBaseCombatWeapon::Delete( void )
{
SetTouch( NULL );
// FIXME: why doesn't this just remove itself now?
SetThink(&CBaseCombatWeapon::SUB_Remove);
SetNextThink( gpGlobals->curtime + 0.1f );
}
void CBaseCombatWeapon::DestroyItem( void )
{
CBaseCombatCharacter *pOwner = m_hOwner.Get();
if ( pOwner )
{
// if attached to a player, remove.
pOwner->RemovePlayerItem( this );
}
Kill( );
}
void CBaseCombatWeapon::Kill( void )
{
SetTouch( NULL );
// FIXME: why doesn't this just remove itself now?
// FIXME: how is this different than Delete(), and why do they have the same code in them?
SetThink(&CBaseCombatWeapon::SUB_Remove);
SetNextThink( gpGlobals->curtime + 0.1f );
}
//====================================================================================
// FALL TO GROUND
//====================================================================================
//-----------------------------------------------------------------------------
// Purpose: Setup for the fall
//-----------------------------------------------------------------------------
void CBaseCombatWeapon::FallInit( void )
{
SetModel( GetWorldModel() );
VPhysicsDestroyObject();
if ( !VPhysicsInitNormal( SOLID_BBOX, GetSolidFlags() | FSOLID_TRIGGER, false ) )
{
SetMoveType( MOVETYPE_FLYGRAVITY );
SetSolid( SOLID_BBOX );
AddSolidFlags( FSOLID_TRIGGER );
}
else
{
#if !defined( CLIENT_DLL )
// Constrained start?
if ( HasSpawnFlags( SF_WEAPON_START_CONSTRAINED ) )
{
//Constrain the weapon in place
IPhysicsObject *pReferenceObject, *pAttachedObject;
pReferenceObject = g_PhysWorldObject;
pAttachedObject = VPhysicsGetObject();
if ( pReferenceObject && pAttachedObject )
{
constraint_fixedparams_t fixed;
fixed.Defaults();
fixed.InitWithCurrentObjectState( pReferenceObject, pAttachedObject );
fixed.constraint.forceLimit = lbs2kg( 10000 );
fixed.constraint.torqueLimit = lbs2kg( 10000 );
m_pConstraint = physenv->CreateFixedConstraint( pReferenceObject, pAttachedObject, NULL, fixed );
m_pConstraint->SetGameData( (void *) this );
}
}
#endif //CLIENT_DLL
}
SetPickupTouch();
SetThink( &CBaseCombatWeapon::FallThink );
SetNextThink( gpGlobals->curtime + 0.1f );
}
//-----------------------------------------------------------------------------
// Purpose: Items that have just spawned run this think to catch them when
// they hit the ground. Once we're sure that the object is grounded,
// we change its solid type to trigger and set it in a large box that
// helps the player get it.
//-----------------------------------------------------------------------------
void CBaseCombatWeapon::FallThink ( void )
{
SetNextThink( gpGlobals->curtime + 0.1f );
bool shouldMaterialize = false;
IPhysicsObject *pPhysics = VPhysicsGetObject();
if ( pPhysics )
{
shouldMaterialize = pPhysics->IsAsleep();
}
else
{
shouldMaterialize = (GetFlags() & FL_ONGROUND) ? true : false;
}
if ( shouldMaterialize )
{
// clatter if we have an owner (i.e., dropped by someone)
// don't clatter if the gun is waiting to respawn (if it's waiting, it is invisible!)
if ( GetOwnerEntity() )
{
EmitSound( "BaseCombatWeapon.WeaponDrop" );
}
Materialize();
}
}
//====================================================================================
// WEAPON SPAWNING
//====================================================================================
//-----------------------------------------------------------------------------
// Purpose: Make a weapon visible and tangible
//-----------------------------------------------------------------------------//
void CBaseCombatWeapon::Materialize( void )
{
if ( IsEffectActive( EF_NODRAW ) )
{
// changing from invisible state to visible.
#ifdef HL2MP
EmitSound( "AlyxEmp.Charge" );
#else
EmitSound( "BaseCombatWeapon.WeaponMaterialize" );
#endif
RemoveEffects( EF_NODRAW );
DoMuzzleFlash();
}
#ifdef HL2MP
if ( HasSpawnFlags( SF_NORESPAWN ) == false )
{
VPhysicsInitNormal( SOLID_BBOX, GetSolidFlags() | FSOLID_TRIGGER, false );
SetMoveType( MOVETYPE_VPHYSICS );
HL2MPRules()->AddLevelDesignerPlacedObject( this );
}
#else
SetSolid( SOLID_BBOX );
AddSolidFlags( FSOLID_TRIGGER );
#endif
SetPickupTouch();
SetThink (NULL);
}
//-----------------------------------------------------------------------------
// Purpose: See if the game rules will let this weapon respawn
//-----------------------------------------------------------------------------
void CBaseCombatWeapon::AttemptToMaterialize( void )
{
float time = g_pGameRules->FlWeaponTryRespawn( this );
if ( time == 0 )
{
Materialize();
return;
}
SetNextThink( gpGlobals->curtime + time );
}
//-----------------------------------------------------------------------------
// Purpose: Weapon has been picked up, should it respawn?
//-----------------------------------------------------------------------------
void CBaseCombatWeapon::CheckRespawn( void )
{
switch ( g_pGameRules->WeaponShouldRespawn( this ) )
{
case GR_WEAPON_RESPAWN_YES:
Respawn();
break;
case GR_WEAPON_RESPAWN_NO:
return;
break;
}
}
class CWeaponList : public CAutoGameSystem
{
public:
CWeaponList( char const *name ) : CAutoGameSystem( name )
{
}
virtual void LevelShutdownPostEntity()
{
m_list.Purge();
}
void AddWeapon( CBaseCombatWeapon *pWeapon )
{
m_list.AddToTail( pWeapon );
}
void RemoveWeapon( CBaseCombatWeapon *pWeapon )
{
m_list.FindAndRemove( pWeapon );
}
CUtlLinkedList< CBaseCombatWeapon * > m_list;
};
CWeaponList g_WeaponList( "CWeaponList" );
void OnBaseCombatWeaponCreated( CBaseCombatWeapon *pWeapon )
{
g_WeaponList.AddWeapon( pWeapon );
}
void OnBaseCombatWeaponDestroyed( CBaseCombatWeapon *pWeapon )
{
g_WeaponList.RemoveWeapon( pWeapon );
}
int CBaseCombatWeapon::GetAvailableWeaponsInBox( CBaseCombatWeapon **pList, int listMax, const Vector &mins, const Vector &maxs )
{
// linear search all weapons
int count = 0;
int index = g_WeaponList.m_list.Head();
while ( index != g_WeaponList.m_list.InvalidIndex() )
{
CBaseCombatWeapon *pWeapon = g_WeaponList.m_list[index];
// skip any held weapon
if ( !pWeapon->GetOwner() )
{
// restrict to mins/maxs
if ( IsPointInBox( pWeapon->GetAbsOrigin(), mins, maxs ) )
{
if ( count < listMax )
{
pList[count] = pWeapon;
count++;
}
}
}
index = g_WeaponList.m_list.Next( index );
}
return count;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
int CBaseCombatWeapon::ObjectCaps( void )
{
int caps = BaseClass::ObjectCaps();
if ( !IsFollowingEntity() && !HasSpawnFlags(SF_WEAPON_NO_PLAYER_PICKUP) )
{
caps |= FCAP_IMPULSE_USE;
}
return caps;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CBaseCombatWeapon::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
{
CBasePlayer *pPlayer = ToBasePlayer( pActivator );
if ( pPlayer )
{
m_OnPlayerUse.FireOutput( pActivator, pCaller );
#ifdef MAPBASE
// Mark that we're being +USE'd, not bumped
AddSpawnFlags(SF_WEAPON_USED);
#endif
//
// Bump the weapon to try equipping it before picking it up physically. This is
// important in a few spots in the game where the player could potentially +use pickup
// and then THROW AWAY a vital weapon, rendering them unable to continue the game.
//
if ( pPlayer->BumpWeapon( this ) )
{
OnPickedUp( pPlayer );
}
else
{
pPlayer->PickupObject( this );
}
#ifdef MAPBASE
RemoveSpawnFlags(SF_WEAPON_USED);
#endif
}
}

View File

@@ -0,0 +1,30 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $Workfile: $
// $NoKeywords: $
//=============================================================================//
#ifndef COMBATWEAPON_H
#define COMBATWEAPON_H
#ifdef _WIN32
#pragma once
#endif
#include "entityoutput.h"
#include "basecombatweapon_shared.h"
//-----------------------------------------------------------------------------
// Bullet types
//-----------------------------------------------------------------------------
// -----------------------------------------
// Sounds
// -----------------------------------------
struct animevent_t;
extern void SpawnBlood(Vector vecSpot, const Vector &vecDir, int bloodColor, float flDamage);
#endif // COMBATWEAPON_H

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,324 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#ifndef BASEFLEX_H
#define BASEFLEX_H
#ifdef _WIN32
#pragma once
#endif
#include "BaseAnimatingOverlay.h"
#include "utlvector.h"
#include "utlrbtree.h"
#include "sceneentity_shared.h"
struct flexsettinghdr_t;
struct flexsetting_t;
class AI_Response;
//-----------------------------------------------------------------------------
// Purpose: A .vfe referenced by a scene during .vcd playback
//-----------------------------------------------------------------------------
class CFlexSceneFile
{
public:
enum
{
MAX_FLEX_FILENAME = 128,
};
char filename[ MAX_FLEX_FILENAME ];
void *buffer;
};
//-----------------------------------------------------------------------------
// Purpose: Animated characters who have vertex flex capability (e.g., facial expressions)
//-----------------------------------------------------------------------------
class CBaseFlex : public CBaseAnimatingOverlay
{
DECLARE_CLASS( CBaseFlex, CBaseAnimatingOverlay );
public:
DECLARE_SERVERCLASS();
DECLARE_DATADESC();
DECLARE_PREDICTABLE();
// script description
DECLARE_ENT_SCRIPTDESC();
// Construction
CBaseFlex( void );
~CBaseFlex( void );
virtual void SetModel( const char *szModelName );
void Blink( );
virtual void SetViewtarget( const Vector &viewtarget );
const Vector &GetViewtarget( void ) const;
void SetFlexWeight( char *szName, float value );
void SetFlexWeight( LocalFlexController_t index, float value );
float GetFlexWeight( char *szName );
float GetFlexWeight( LocalFlexController_t index );
// Look up flex controller index by global name
LocalFlexController_t FindFlexController( const char *szName );
void EnsureTranslations( const flexsettinghdr_t *pSettinghdr );
// Keep track of what scenes are being played
void StartChoreoScene( CChoreoScene *scene );
void RemoveChoreoScene( CChoreoScene *scene, bool canceled = false );
// Start the specifics of an scene event
#ifdef MAPBASE
virtual bool StartSceneEvent( CSceneEventInfo *info, CChoreoScene *scene, CChoreoEvent *event, CChoreoActor *actor, CBaseEntity *pTarget, CSceneEntity *pSceneEnt = NULL );
#else
virtual bool StartSceneEvent( CSceneEventInfo *info, CChoreoScene *scene, CChoreoEvent *event, CChoreoActor *actor, CBaseEntity *pTarget );
#endif
// Manipulation of events for the object
// Should be called by think function to process all scene events
// The default implementation resets m_flexWeight array and calls
// AddSceneEvents
virtual void ProcessSceneEvents( void );
// Assumes m_flexWeight array has been set up, this adds the actual currently playing
// expressions to the flex weights and adds other scene events as needed
virtual bool ProcessSceneEvent( CSceneEventInfo *info, CChoreoScene *scene, CChoreoEvent *event );
// Remove all playing events
void ClearSceneEvents( CChoreoScene *scene, bool canceled );
// Stop specifics of event
virtual bool ClearSceneEvent( CSceneEventInfo *info, bool fastKill, bool canceled );
// Add the event to the queue for this actor
#ifdef MAPBASE
void AddSceneEvent( CChoreoScene *scene, CChoreoEvent *event, CBaseEntity *pTarget = NULL, CSceneEntity *pSceneEnt = NULL );
#else
void AddSceneEvent( CChoreoScene *scene, CChoreoEvent *event, CBaseEntity *pTarget = NULL );
#endif
// Remove the event from the queue for this actor
void RemoveSceneEvent( CChoreoScene *scene, CChoreoEvent *event, bool fastKill );
// Checks to see if the event should be considered "completed"
bool CheckSceneEvent( float currenttime, CChoreoScene *scene, CChoreoEvent *event );
// Checks to see if a event should be considered "completed"
virtual bool CheckSceneEventCompletion( CSceneEventInfo *info, float currenttime, CChoreoScene *scene, CChoreoEvent *event );
// Finds the layer priority of the current scene
int GetScenePriority( CChoreoScene *scene );
// Returns true if the actor is not currently in a scene OR if the actor
// is in a scene, but a PERMIT_RESPONSES event is active and the permit time
// period has enough time remaining to handle the response in full.
bool PermitResponse( float response_length );
// Set response end time (0 to clear response blocking)
void SetPermitResponse( float endtime );
void SentenceStop( void ) { EmitSound( "AI_BaseNPC.SentenceStop" ); }
virtual float PlayScene( const char *pszScene, float flDelay = 0.0f, AI_Response *response = NULL, IRecipientFilter *filter = NULL );
#ifdef MAPBASE
virtual float PlayAutoGeneratedSoundScene( const char *soundname, float flDelay = 0.0f, AI_Response *response = NULL, IRecipientFilter *filter = NULL );
#else
virtual float PlayAutoGeneratedSoundScene( const char *soundname );
#endif
// Returns the script instance of the scene entity associated with our oldest ("top level") scene event
virtual HSCRIPT ScriptGetOldestScene( void );
virtual HSCRIPT ScriptGetSceneByIndex( int index );
virtual int GetSpecialDSP( void ) { return 0; }
#ifdef MAPBASE
virtual bool GetGameTextSpeechParams( hudtextparms_t &params );
#endif
protected:
// For handling .vfe files
// Search list, or add if not in list
const void *FindSceneFile( const char *filename );
// Find setting by name
const flexsetting_t *FindNamedSetting( const flexsettinghdr_t *pSettinghdr, const char *expr );
// Called at the lowest level to actually apply an expression
void AddFlexSetting( const char *expr, float scale, const flexsettinghdr_t *pSettinghdr, bool newexpression );
// Called at the lowest level to actually apply a flex animation
void AddFlexAnimation( CSceneEventInfo *info );
bool HasSceneEvents() const;
bool IsRunningSceneMoveToEvent();
LocalFlexController_t FlexControllerLocalToGlobal( const flexsettinghdr_t *pSettinghdr, int key );
private:
// Starting various expression types
bool RequestStartSequenceSceneEvent( CSceneEventInfo *info, CChoreoScene *scene, CChoreoEvent *event, CChoreoActor *actor, CBaseEntity *pTarget );
bool RequestStartGestureSceneEvent( CSceneEventInfo *info, CChoreoScene *scene, CChoreoEvent *event, CChoreoActor *actor, CBaseEntity *pTarget );
bool HandleStartSequenceSceneEvent( CSceneEventInfo *info, CChoreoScene *scene, CChoreoEvent *event, CChoreoActor *actor );
bool HandleStartGestureSceneEvent( CSceneEventInfo *info, CChoreoScene *scene, CChoreoEvent *event, CChoreoActor *actor );
bool StartFacingSceneEvent( CSceneEventInfo *info, CChoreoScene *scene, CChoreoEvent *event, CChoreoActor *actor, CBaseEntity *pTarget );
bool StartMoveToSceneEvent( CSceneEventInfo *info, CChoreoScene *scene, CChoreoEvent *event, CChoreoActor *actor, CBaseEntity *pTarget );
// Processing various expression types
bool ProcessFlexAnimationSceneEvent( CSceneEventInfo *info, CChoreoScene *scene, CChoreoEvent *event );
bool ProcessFlexSettingSceneEvent( CSceneEventInfo *info, CChoreoScene *scene, CChoreoEvent *event );
bool ProcessSequenceSceneEvent( CSceneEventInfo *info, CChoreoScene *scene, CChoreoEvent *event );
bool ProcessGestureSceneEvent( CSceneEventInfo *info, CChoreoScene *scene, CChoreoEvent *event );
bool ProcessFacingSceneEvent( CSceneEventInfo *info, CChoreoScene *scene, CChoreoEvent *event );
bool ProcessMoveToSceneEvent( CSceneEventInfo *info, CChoreoScene *scene, CChoreoEvent *event );
bool ProcessLookAtSceneEvent( CSceneEventInfo *info, CChoreoScene *scene, CChoreoEvent *event );
// Set playing the scene sequence
public:
bool EnterSceneSequence( CChoreoScene *scene, CChoreoEvent *event, bool bRestart = false );
private:
bool ExitSceneSequence( void );
private:
CNetworkArray( float, m_flexWeight, MAXSTUDIOFLEXCTRL ); // indexed by model local flexcontroller
// Vector from actor to eye target
CNetworkVector( m_viewtarget );
// Blink state
CNetworkVar( int, m_blinktoggle );
// Array of active SceneEvents, in order oldest to newest
CUtlVector < CSceneEventInfo > m_SceneEvents;
// Mapping for each loaded scene file used by this actor
struct FS_LocalToGlobal_t
{
explicit FS_LocalToGlobal_t() :
m_Key( 0 ),
m_nCount( 0 ),
m_Mapping( 0 )
{
}
explicit FS_LocalToGlobal_t( const flexsettinghdr_t *key ) :
m_Key( key ),
m_nCount( 0 ),
m_Mapping( 0 )
{
}
void SetCount( int count )
{
Assert( !m_Mapping );
Assert( count > 0 );
m_nCount = count;
m_Mapping = new LocalFlexController_t[ m_nCount ];
Q_memset( m_Mapping, 0, m_nCount * sizeof( int ) );
}
FS_LocalToGlobal_t( const FS_LocalToGlobal_t& src )
{
m_Key = src.m_Key;
delete m_Mapping;
m_Mapping = new LocalFlexController_t[ src.m_nCount ];
Q_memcpy( m_Mapping, src.m_Mapping, src.m_nCount * sizeof( int ) );
m_nCount = src.m_nCount;
}
~FS_LocalToGlobal_t()
{
delete m_Mapping;
m_nCount = 0;
m_Mapping = 0;
}
const flexsettinghdr_t *m_Key;
int m_nCount;
LocalFlexController_t *m_Mapping;
};
static bool FlexSettingLessFunc( const FS_LocalToGlobal_t& lhs, const FS_LocalToGlobal_t& rhs );
CUtlRBTree< FS_LocalToGlobal_t, unsigned short > m_LocalToGlobal;
// The NPC is in a scene, but another .vcd (such as a short wave to say in response to the player doing something )
// can be layered on top of this actor (assuming duration matches, etc.
float m_flAllowResponsesEndTime;
// List of actively playing scenes
CUtlVector < CChoreoScene * > m_ActiveChoreoScenes;
bool m_bUpdateLayerPriorities;
public:
bool IsSuppressedFlexAnimation( CSceneEventInfo *info );
private:
// last time a foreground flex animation was played
float m_flLastFlexAnimationTime;
public:
void DoBodyLean( void );
virtual void Teleport( const Vector *newPosition, const QAngle *newAngles, const Vector *newVelocity );
#ifdef HL2_DLL
Vector m_vecPrevOrigin;
Vector m_vecPrevVelocity;
CNetworkVector( m_vecLean );
CNetworkVector( m_vecShift );
#endif
};
//-----------------------------------------------------------------------------
// For toggling blinking
//-----------------------------------------------------------------------------
inline void CBaseFlex::Blink()
{
m_blinktoggle = !m_blinktoggle;
}
//-----------------------------------------------------------------------------
// Do we have active expressions?
//-----------------------------------------------------------------------------
inline bool CBaseFlex::HasSceneEvents() const
{
return m_SceneEvents.Count() != 0;
}
//-----------------------------------------------------------------------------
// Other inlines
//-----------------------------------------------------------------------------
inline const Vector &CBaseFlex::GetViewtarget( ) const
{
return m_viewtarget.Get(); // bah
}
inline void CBaseFlex::SetFlexWeight( char *szName, float value )
{
SetFlexWeight( FindFlexController( szName ), value );
}
inline float CBaseFlex::GetFlexWeight( char *szName )
{
return GetFlexWeight( FindFlexController( szName ) );
}
EXTERN_SEND_TABLE(DT_BaseFlex);
#endif // BASEFLEX_H

View File

@@ -0,0 +1,131 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "baseentity.h"
#include "basegrenade_shared.h"
#include "soundent.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
class CBaseGrenadeConcussion : public CBaseGrenade
{
DECLARE_DATADESC();
public:
DECLARE_CLASS( CBaseGrenadeConcussion, CBaseGrenade );
void Spawn( void );
void Precache( void );
void FallThink(void);
void ExplodeConcussion( CBaseEntity *pOther );
protected:
static int m_nTrailSprite;
};
int CBaseGrenadeConcussion::m_nTrailSprite = 0;
LINK_ENTITY_TO_CLASS( npc_concussiongrenade, CBaseGrenadeConcussion );
BEGIN_DATADESC( CBaseGrenadeConcussion )
DEFINE_THINKFUNC( FallThink ),
DEFINE_ENTITYFUNC( ExplodeConcussion ),
END_DATADESC()
void CBaseGrenadeConcussion::FallThink(void)
{
if (!IsInWorld())
{
Remove( );
return;
}
CSoundEnt::InsertSound ( SOUND_DANGER, GetAbsOrigin() + GetAbsVelocity() * 0.5, GetAbsVelocity().Length( ), 0.2 );
SetNextThink( gpGlobals->curtime + random->RandomFloat(0.05, 0.1) );
if (GetWaterLevel() != 0)
{
SetAbsVelocity( GetAbsVelocity() * 0.5 );
}
Vector pos = GetAbsOrigin() + Vector(random->RandomFloat(-4, 4), random->RandomFloat(-4, 4), random->RandomFloat(-4, 4));
CPVSFilter filter( GetAbsOrigin() );
te->Sprite( filter, 0.0,
&pos,
m_nTrailSprite,
random->RandomFloat(0.5, 0.8),
200 );
}
//
// Contact grenade, explode when it touches something
//
void CBaseGrenadeConcussion::ExplodeConcussion( CBaseEntity *pOther )
{
trace_t tr;
Vector vecSpot;// trace starts here!
Vector velDir = GetAbsVelocity();
VectorNormalize( velDir );
vecSpot = GetAbsOrigin() - velDir * 32;
UTIL_TraceLine( vecSpot, vecSpot + velDir * 64, MASK_SOLID_BRUSHONLY, this, COLLISION_GROUP_NONE, &tr );
Explode( &tr, DMG_BLAST );
}
void CBaseGrenadeConcussion::Spawn( void )
{
// point sized, solid, bouncing
SetMoveType( MOVETYPE_FLYGRAVITY, MOVECOLLIDE_FLY_BOUNCE );
SetSolid( SOLID_BBOX );
SetCollisionGroup( COLLISION_GROUP_PROJECTILE );
SetModel( "models/weapons/w_grenade.mdl" ); // BUG: wrong model
UTIL_SetSize(this, vec3_origin, vec3_origin);
// contact grenades arc lower
SetGravity( UTIL_ScaleForGravity( 400 ) ); // use a lower gravity for grenades to make them easier to see
QAngle angles;
VectorAngles(GetAbsVelocity(), angles );
SetLocalAngles( angles );
m_nRenderFX = kRenderFxGlowShell;
SetRenderColor( 200, 200, 20, 255 );
// make NPCs afaid of it while in the air
SetThink( &CBaseGrenadeConcussion::FallThink );
SetNextThink( gpGlobals->curtime );
// Tumble in air
QAngle vecAngVel( random->RandomFloat ( -100, -500 ), 0, 0 );
SetLocalAngularVelocity( vecAngVel );
// Explode on contact
SetTouch( &CBaseGrenadeConcussion::ExplodeConcussion );
m_flDamage = 80;
// Allow player to blow this puppy up in the air
m_takedamage = DAMAGE_YES;
}
void CBaseGrenadeConcussion::Precache( void )
{
BaseClass::Precache( );
PrecacheModel("models/weapons/w_grenade.mdl");
m_nTrailSprite = PrecacheModel("sprites/twinkle01.vmt");
}

View File

@@ -0,0 +1,71 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "basegrenade_shared.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
extern ConVar sk_plr_dmg_grenade;
// ==========================================================================================
class CBaseGrenadeContact : public CBaseGrenade
{
DECLARE_CLASS( CBaseGrenadeContact, CBaseGrenade );
public:
void Spawn( void );
void Precache( void );
};
LINK_ENTITY_TO_CLASS( npc_contactgrenade, CBaseGrenadeContact );
void CBaseGrenadeContact::Spawn( void )
{
// point sized, solid, bouncing
SetMoveType( MOVETYPE_FLYGRAVITY, MOVECOLLIDE_FLY_BOUNCE );
SetSolid( SOLID_BBOX );
SetCollisionGroup( COLLISION_GROUP_PROJECTILE );
SetModel( "models/weapons/w_grenade.mdl" ); // BUG: wrong model
UTIL_SetSize(this, vec3_origin, vec3_origin);
// contact grenades arc lower
SetGravity( UTIL_ScaleForGravity( 400 ) ); // use a lower gravity for grenades to make them easier to see
QAngle angles;
VectorAngles(GetAbsVelocity(), angles);
SetLocalAngles( angles );
// make NPCs afaid of it while in the air
SetThink( &CBaseGrenadeContact::DangerSoundThink );
SetNextThink( gpGlobals->curtime );
// Tumble in air
QAngle vecAngVelocity( random->RandomFloat ( -100, -500 ), 0, 0 );
SetLocalAngularVelocity( vecAngVelocity );
// Explode on contact
SetTouch( &CBaseGrenadeContact::ExplodeTouch );
m_flDamage = sk_plr_dmg_grenade.GetFloat();
// Allow player to blow this puppy up in the air
m_takedamage = DAMAGE_YES;
m_iszBounceSound = NULL_STRING;
}
void CBaseGrenadeContact::Precache( void )
{
BaseClass::Precache( );
PrecacheModel("models/weapons/w_grenade.mdl");
}

View File

@@ -0,0 +1,73 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "basegrenade_shared.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
class CBaseGrenadeTimed : public CBaseGrenade
{
public:
DECLARE_CLASS( CBaseGrenadeTimed, CBaseGrenade );
void Spawn( void );
void Precache( void );
};
LINK_ENTITY_TO_CLASS( npc_handgrenade, CBaseGrenadeTimed );
void CBaseGrenadeTimed::Spawn( void )
{
SetMoveType( MOVETYPE_FLYGRAVITY, MOVECOLLIDE_FLY_BOUNCE );
SetSolid( SOLID_BBOX );
SetCollisionGroup( COLLISION_GROUP_PROJECTILE );
SetModel( "models/Weapons/w_grenade.mdl" );
UTIL_SetSize(this, Vector( -4, -4, -4), Vector(4, 4, 4));
QAngle angles;
Vector vel = GetAbsVelocity();
VectorAngles( vel, angles );
SetLocalAngles( angles );
SetTouch( &CBaseGrenadeTimed::BounceTouch ); // Bounce if touched
// Take one second off of the desired detonation time and set the think to PreDetonate. PreDetonate
// will insert a DANGER sound into the world sound list and delay detonation for one second so that
// the grenade explodes after the exact amount of time specified in the call to ShootTimed().
SetThink( &CBaseGrenadeTimed::TumbleThink );
SetNextThink( gpGlobals->curtime + 0.1f );
// if the delay is < 0.1 seconds, don't fly anywhere
if ((m_flDetonateTime - gpGlobals->curtime) < 0.1)
{
SetNextThink( gpGlobals->curtime );
SetAbsVelocity( vec3_origin );
}
// Tumble through the air
// pGrenade->m_vecAngVelocity.x = -400;
SetGravity(1.0); // Don't change or throw calculations will be off!
SetFriction(0.8);
m_flDamage = 100; // ????
m_takedamage = DAMAGE_NO;
}
void CBaseGrenadeTimed::Precache( void )
{
BaseClass::Precache( );
PrecacheModel("models/weapons/w_grenade.mdl");
}

View File

@@ -0,0 +1,349 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================
#include "cbase.h"
#include "mp_shareddefs.h"
#include "basemultiplayerplayer.h"
// Minimum interval between rate-limited commands that players can run.
#define COMMAND_MAX_RATE 0.3
CBaseMultiplayerPlayer::CBaseMultiplayerPlayer()
{
m_iCurrentConcept = MP_CONCEPT_NONE;
m_flLastForcedChangeTeamTime = -1;
m_iBalanceScore = 0;
m_flConnectionTime = gpGlobals->curtime;
// per life achievement counters
m_pAchievementKV = new KeyValues( "achievement_counts" );
m_flAreaCaptureScoreAccumulator = 0.0f;
}
CBaseMultiplayerPlayer::~CBaseMultiplayerPlayer()
{
m_pAchievementKV->deleteThis();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
CAI_Expresser *CBaseMultiplayerPlayer::CreateExpresser( void )
{
m_pExpresser = new CMultiplayer_Expresser(this);
if ( !m_pExpresser)
return NULL;
m_pExpresser->Connect(this);
return m_pExpresser;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CBaseMultiplayerPlayer::PostConstructor( const char *szClassname )
{
BaseClass::PostConstructor( szClassname );
CreateExpresser();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CBaseMultiplayerPlayer::ModifyOrAppendCriteria( AI_CriteriaSet& criteriaSet )
{
BaseClass::ModifyOrAppendCriteria( criteriaSet );
ModifyOrAppendPlayerCriteria( criteriaSet );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
bool CBaseMultiplayerPlayer::SpeakIfAllowed( AIConcept_t concept, const char *modifiers, char *pszOutResponseChosen, size_t bufsize, IRecipientFilter *filter )
{
if ( !IsAlive() )
return false;
//if ( IsAllowedToSpeak( concept, bRespondingToPlayer ) )
return Speak( concept, modifiers, pszOutResponseChosen, bufsize, filter );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
IResponseSystem *CBaseMultiplayerPlayer::GetResponseSystem()
{
return BaseClass::GetResponseSystem();
// NOTE: This is where you would hook your custom responses.
// return <*>GameRules()->m_ResponseRules[iIndex].m_ResponseSystems[m_iCurrentConcept];
}
//-----------------------------------------------------------------------------
// Purpose: Doesn't actually speak the concept. Just finds a response in the system. You then have to play it yourself.
//-----------------------------------------------------------------------------
AI_Response *CBaseMultiplayerPlayer::SpeakConcept( int iConcept )
{
m_iCurrentConcept = iConcept;
return SpeakFindResponse( g_pszMPConcepts[iConcept] );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
bool CBaseMultiplayerPlayer::SpeakConceptIfAllowed( int iConcept, const char *modifiers, char *pszOutResponseChosen, size_t bufsize, IRecipientFilter *filter )
{
// Save the current concept.
m_iCurrentConcept = iConcept;
return SpeakIfAllowed( g_pszMPConcepts[iConcept], modifiers, pszOutResponseChosen, bufsize, filter );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
bool CBaseMultiplayerPlayer::CanHearAndReadChatFrom( CBasePlayer *pPlayer )
{
// can always hear the console unless we're ignoring all chat
if ( !pPlayer )
return m_iIgnoreGlobalChat != CHAT_IGNORE_ALL;
// check if we're ignoring all chat
if ( m_iIgnoreGlobalChat == CHAT_IGNORE_ALL )
return false;
// check if we're ignoring all but teammates
if ( m_iIgnoreGlobalChat == CHAT_IGNORE_TEAM && g_pGameRules->PlayerRelationship( this, pPlayer ) != GR_TEAMMATE )
return false;
// can't hear dead players if we're alive
if ( pPlayer->m_lifeState != LIFE_ALIVE && m_lifeState == LIFE_ALIVE )
return false;
return true;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
bool CBaseMultiplayerPlayer::ShouldRunRateLimitedCommand( const CCommand &args )
{
return ShouldRunRateLimitedCommand( args[0] );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
bool CBaseMultiplayerPlayer::ShouldRunRateLimitedCommand( const char *pszCommand )
{
const char *pcmd = pszCommand;
int i = m_RateLimitLastCommandTimes.Find( pcmd );
if ( i == m_RateLimitLastCommandTimes.InvalidIndex() )
{
m_RateLimitLastCommandTimes.Insert( pcmd, gpGlobals->curtime );
return true;
}
else if ( (gpGlobals->curtime - m_RateLimitLastCommandTimes[i]) < COMMAND_MAX_RATE )
{
// Too fast.
return false;
}
else
{
m_RateLimitLastCommandTimes[i] = gpGlobals->curtime;
return true;
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
bool CBaseMultiplayerPlayer::ClientCommand( const CCommand &args )
{
const char *pcmd = args[0];
if ( FStrEq( pcmd, "ignoremsg" ) )
{
if ( ShouldRunRateLimitedCommand( args ) )
{
m_iIgnoreGlobalChat = (m_iIgnoreGlobalChat + 1) % 3;
switch( m_iIgnoreGlobalChat )
{
case CHAT_IGNORE_NONE:
ClientPrint( this, HUD_PRINTTALK, "#Accept_All_Messages" );
break;
case CHAT_IGNORE_ALL:
ClientPrint( this, HUD_PRINTTALK, "#Ignore_Broadcast_Messages" );
break;
case CHAT_IGNORE_TEAM:
ClientPrint( this, HUD_PRINTTALK, "#Ignore_Broadcast_Team_Messages" );
break;
default:
break;
}
}
return true;
}
return BaseClass::ClientCommand( args );
}
bool CBaseMultiplayerPlayer::ShouldShowVoiceSubtitleToEnemy( void )
{
return false;
}
//-----------------------------------------------------------------------------
// calculate a score for this player. higher is more likely to be switched
//-----------------------------------------------------------------------------
int CBaseMultiplayerPlayer::CalculateTeamBalanceScore( void )
{
// base score is 0 - ( seconds on server )
float flTimeConnected = gpGlobals->curtime - m_flConnectionTime;
int iScore = 0 - (int)flTimeConnected;
// if we were switched recently, score us way down
float flLastSwitchedTime = GetLastForcedChangeTeamTime();
if ( flLastSwitchedTime > 0 && ( gpGlobals->curtime - flLastSwitchedTime ) < 300 )
{
iScore -= 10000;
}
return iScore;
}
void CBaseMultiplayerPlayer::Spawn( void )
{
ResetPerLifeCounters();
StopScoringEscortPoints();
BaseClass::Spawn();
}
void CBaseMultiplayerPlayer::AwardAchievement( int iAchievement, int iCount )
{
Assert( iAchievement >= 0 && iAchievement < 0xFFFF ); // must fit in short
CSingleUserRecipientFilter filter( this );
UserMessageBegin( filter, "AchievementEvent" );
WRITE_SHORT( iAchievement );
WRITE_SHORT( iCount );
MessageEnd();
}
#ifdef _DEBUG
#include "utlbuffer.h"
void DumpAchievementCounters( const CCommand &args )
{
int iPlayerIndex = 1;
if ( args.ArgC() >= 2 )
{
iPlayerIndex = atoi( args[1] );
}
CBaseMultiplayerPlayer *pPlayer = ToBaseMultiplayerPlayer( UTIL_PlayerByIndex( iPlayerIndex ) );
if ( pPlayer && pPlayer->GetPerLifeCounterKeys() )
{
CUtlBuffer buf( 0, 0, CUtlBuffer::TEXT_BUFFER );
pPlayer->GetPerLifeCounterKeys()->RecursiveSaveToFile( buf, 0 );
char szBuf[1024];
// probably not the best way to print out a CUtlBuffer
int pos = 0;
while ( buf.PeekStringLength() )
{
szBuf[pos] = buf.GetChar();
pos++;
}
szBuf[pos] = '\0';
Msg( "%s\n", szBuf );
}
}
ConCommand dump_achievement_counters( "dump_achievement_counters", DumpAchievementCounters, "Spew the per-life achievement counters for multiplayer players", FCVAR_CHEAT | FCVAR_DEVELOPMENTONLY );
#endif // _DEBUG
int CBaseMultiplayerPlayer::GetPerLifeCounterKV( const char *name )
{
return m_pAchievementKV->GetInt( name, 0 );
}
void CBaseMultiplayerPlayer::SetPerLifeCounterKV( const char *name, int value )
{
m_pAchievementKV->SetInt( name, value );
}
void CBaseMultiplayerPlayer::ResetPerLifeCounters( void )
{
m_pAchievementKV->Clear();
}
ConVar tf_escort_score_rate( "tf_escort_score_rate", "1", FCVAR_CHEAT, "Score for escorting the train, in points per second" );
#define ESCORT_SCORE_CONTEXT "AreaScoreContext"
#define ESCORT_SCORE_INTERVAL 0.1
//-----------------------------------------------------------------------------
// Purpose: think to accumulate and award points for escorting the train
//-----------------------------------------------------------------------------
void CBaseMultiplayerPlayer::EscortScoringThink( void )
{
m_flAreaCaptureScoreAccumulator += ESCORT_SCORE_INTERVAL;
if ( m_flCapPointScoreRate > 0 )
{
float flTimeForOnePoint = 1.0f / m_flCapPointScoreRate;
int iPoints = 0;
while ( m_flAreaCaptureScoreAccumulator >= flTimeForOnePoint )
{
m_flAreaCaptureScoreAccumulator -= flTimeForOnePoint;
iPoints++;
}
if ( iPoints > 0 )
{
IGameEvent *event = gameeventmanager->CreateEvent( "player_escort_score" );
if ( event )
{
event->SetInt( "player", entindex() );
event->SetInt( "points", iPoints );
gameeventmanager->FireEvent( event, true /* only to server */ );
}
}
}
SetContextThink( &CBaseMultiplayerPlayer::EscortScoringThink, gpGlobals->curtime + ESCORT_SCORE_INTERVAL, ESCORT_SCORE_CONTEXT );
}
//-----------------------------------------------------------------------------
// Purpose: We're escorting the train, start giving points
//-----------------------------------------------------------------------------
void CBaseMultiplayerPlayer::StartScoringEscortPoints( float flRate )
{
Assert( flRate > 0.0f );
m_flCapPointScoreRate = flRate;
SetContextThink( &CBaseMultiplayerPlayer::EscortScoringThink, gpGlobals->curtime + ESCORT_SCORE_INTERVAL, ESCORT_SCORE_CONTEXT );
}
//-----------------------------------------------------------------------------
// Purpose: Stopped escorting the train
//-----------------------------------------------------------------------------
void CBaseMultiplayerPlayer::StopScoringEscortPoints( void )
{
SetContextThink( NULL, 0, ESCORT_SCORE_CONTEXT );
}

View File

@@ -0,0 +1,127 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
//=============================================================================
#ifndef BASEMULTIPLAYERPLAYER_H
#define BASEMULTIPLAYERPLAYER_H
#pragma once
#include "player.h"
#include "ai_speech.h"
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
class CBaseMultiplayerPlayer : public CAI_ExpresserHost<CBasePlayer>
{
DECLARE_CLASS( CBaseMultiplayerPlayer, CAI_ExpresserHost<CBasePlayer> );
public:
CBaseMultiplayerPlayer();
~CBaseMultiplayerPlayer();
virtual void Spawn( void );
virtual void PostConstructor( const char *szClassname );
virtual void ModifyOrAppendCriteria( AI_CriteriaSet& criteriaSet );
virtual bool SpeakIfAllowed( AIConcept_t concept, const char *modifiers = NULL, char *pszOutResponseChosen = NULL, size_t bufsize = 0, IRecipientFilter *filter = NULL );
virtual IResponseSystem *GetResponseSystem();
AI_Response *SpeakConcept( int iConcept );
virtual bool SpeakConceptIfAllowed( int iConcept, const char *modifiers = NULL, char *pszOutResponseChosen = NULL, size_t bufsize = 0, IRecipientFilter *filter = NULL );
virtual bool CanHearAndReadChatFrom( CBasePlayer *pPlayer );
virtual bool CanSpeak( void ) { return true; }
virtual bool CanBeAutobalanced() { return true; }
virtual void Precache( void )
{
PrecacheParticleSystem( "achieved" );
BaseClass::Precache();
}
virtual bool ClientCommand( const CCommand &args );
virtual bool CanSpeakVoiceCommand( void ) { return true; }
virtual bool ShouldShowVoiceSubtitleToEnemy( void );
virtual void NoteSpokeVoiceCommand( const char *pszScenePlayed ) {}
virtual void OnAchievementEarned( int iAchievement ) {}
enum
{
CHAT_IGNORE_NONE = 0,
CHAT_IGNORE_ALL,
CHAT_IGNORE_TEAM,
};
int m_iIgnoreGlobalChat;
//---------------------------------
// Speech support
virtual CAI_Expresser *GetExpresser() { return m_pExpresser; }
virtual CMultiplayer_Expresser *GetMultiplayerExpresser() { return m_pExpresser; }
void SetLastForcedChangeTeamTimeToNow( void ) { m_flLastForcedChangeTeamTime = gpGlobals->curtime; }
float GetLastForcedChangeTeamTime( void ) { return m_flLastForcedChangeTeamTime; }
void SetTeamBalanceScore( int iScore ) { m_iBalanceScore = iScore; }
int GetTeamBalanceScore( void ) { return m_iBalanceScore; }
virtual int CalculateTeamBalanceScore( void );
void AwardAchievement( int iAchievement, int iCount = 1 );
int GetPerLifeCounterKV( const char *name );
void SetPerLifeCounterKV( const char *name, int value );
void ResetPerLifeCounters( void );
KeyValues *GetPerLifeCounterKeys( void ) { return m_pAchievementKV; }
void EscortScoringThink( void );
void StartScoringEscortPoints( float flRate );
void StopScoringEscortPoints( void );
float m_flAreaCaptureScoreAccumulator;
float m_flCapPointScoreRate;
float GetConnectionTime( void ) { return m_flConnectionTime; }
// Command rate limiting.
bool ShouldRunRateLimitedCommand( const CCommand &args );
bool ShouldRunRateLimitedCommand( const char *pszCommand );
protected:
virtual CAI_Expresser *CreateExpresser( void );
int m_iCurrentConcept;
private:
//---------------------------------
CMultiplayer_Expresser *m_pExpresser;
float m_flConnectionTime;
float m_flLastForcedChangeTeamTime;
int m_iBalanceScore; // a score used to determine which players are switched to balance the teams
KeyValues *m_pAchievementKV;
// This lets us rate limit the commands the players can execute so they don't overflow things like reliable buffers.
CUtlDict<float,int> m_RateLimitLastCommandTimes;
};
//-----------------------------------------------------------------------------
// Inline methods
//-----------------------------------------------------------------------------
inline CBaseMultiplayerPlayer *ToBaseMultiplayerPlayer( CBaseEntity *pEntity )
{
if ( !pEntity || !pEntity->IsPlayer() )
return NULL;
#if _DEBUG
return dynamic_cast<CBaseMultiplayerPlayer *>( pEntity );
#else
return static_cast<CBaseMultiplayerPlayer *>( pEntity );
#endif
}
#endif // BASEMULTIPLAYERPLAYER_H

View File

@@ -0,0 +1,126 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $Workfile: $
// $Date: $
//
//-----------------------------------------------------------------------------
// $Log: $
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "mathlib/mathlib.h"
#include "basetempentity.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
IMPLEMENT_SERVERCLASS_ST_NOBASE(CBaseTempEntity, DT_BaseTempEntity)
END_SEND_TABLE()
// Global list of temp entity event classes
CBaseTempEntity *CBaseTempEntity::s_pTempEntities = NULL;
//-----------------------------------------------------------------------------
// Purpose: Returns head of list
// Output : CBaseTempEntity * -- head of list
//-----------------------------------------------------------------------------
CBaseTempEntity *CBaseTempEntity::GetList( void )
{
return s_pTempEntities;
}
//-----------------------------------------------------------------------------
// Purpose: Creates temp entity, sets name, adds to global list
// Input : *name -
//-----------------------------------------------------------------------------
CBaseTempEntity::CBaseTempEntity( const char *name )
{
m_pszName = name;
Assert( m_pszName );
// Add to list
m_pNext = s_pTempEntities;
s_pTempEntities = this;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
CBaseTempEntity::~CBaseTempEntity( void )
{
}
//-----------------------------------------------------------------------------
// Purpose: Get the name of this temp entity
// Output : const char *
//-----------------------------------------------------------------------------
const char *CBaseTempEntity::GetName( void )
{
return m_pszName ? m_pszName : "Unnamed";
}
//-----------------------------------------------------------------------------
// Purpose: Get next temp ent in chain
// Output : CBaseTempEntity *
//-----------------------------------------------------------------------------
CBaseTempEntity *CBaseTempEntity::GetNext( void )
{
return m_pNext;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CBaseTempEntity::Precache( void )
{
// Nothing...
}
//-----------------------------------------------------------------------------
// Purpose: Default test implementation. Should only be called by derived classes
// Input : *current_origin -
// *current_angles -
//-----------------------------------------------------------------------------
void CBaseTempEntity::Test( const Vector& current_origin, const QAngle& current_angles )
{
Vector origin, forward;
Msg( "%s\n", m_pszName );
AngleVectors( current_angles, &forward );
VectorMA( current_origin, 20, forward, origin );
CBroadcastRecipientFilter filter;
Create( filter, 0.0 );
}
//-----------------------------------------------------------------------------
// Purpose: Called at startup to allow temp entities to precache any models/sounds that they need
//-----------------------------------------------------------------------------
void CBaseTempEntity::PrecacheTempEnts( void )
{
CBaseTempEntity *te = GetList();
while ( te )
{
te->Precache();
te = te->GetNext();
}
}
void CBaseTempEntity::Create( IRecipientFilter& filter, float delay )
{
// temp entities can't be reliable or part of the signon message, use real entities instead
Assert( !filter.IsReliable() && !filter.IsInitMessage() );
Assert( delay >= -1 && delay <= 1); // 1 second max delay
engine->PlaybackTempEntity( filter, delay,
(void *)this, GetServerClass()->m_pTable, GetServerClass()->m_ClassID );
}

View File

@@ -0,0 +1,65 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $Workfile: $
// $Date: $
//
//-----------------------------------------------------------------------------
// $Log: $
//
// $NoKeywords: $
//=============================================================================//
#if !defined( BASETEMPENTITY_H )
#define BASETEMPENTITY_H
#ifdef _WIN32
#pragma once
#endif
#include "edict.h"
// This is the base class for TEMP ENTITIES that use the
// event system to propagate
class CBaseTempEntity
{
public:
DECLARE_CLASS_NOBASE( CBaseTempEntity );
DECLARE_SERVERCLASS();
CBaseTempEntity( const char *name );
virtual ~CBaseTempEntity( void );
const char *GetName( void );
// Force all derived classes to implement a test
virtual void Test( const Vector& current_origin, const QAngle& current_angles );
virtual void Create( IRecipientFilter& filter, float delay = 0.0 );
virtual void Precache( void );
CBaseTempEntity *GetNext( void );
// Get list of tempentities
static CBaseTempEntity *GetList( void );
// Called at startup to allow temp entities to precache any models/sounds that they need
static void PrecacheTempEnts( void );
void NetworkStateChanged() {} // TE's are sent out right away so we don't track whether state changes or not,
// but we want to allow CNetworkVars.
void NetworkStateChanged( void *pVar ) {}
private:
// Descriptive name, for when running tests
const char *m_pszName;
// Next in chain
CBaseTempEntity *m_pNext;
// ConVars add themselves to this list for the executable. Then ConVarMgr::Init() runs through
// all the console variables and registers them.
static CBaseTempEntity *s_pTempEntities;
};
#endif // BASETEMPENTITY_H

View File

@@ -0,0 +1,69 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: For the slow removing of the CBaseToggle entity
// only old entities that need it for backwards-compatibility should
// include this file
//=============================================================================//
#ifndef BASETOGGLE_H
#define BASETOGGLE_H
#pragma once
#include "baseentity.h"
class CBaseToggle : public CBaseEntity
{
DECLARE_CLASS( CBaseToggle, CBaseEntity );
public:
CBaseToggle();
virtual bool KeyValue( const char *szKeyName, const char *szValue );
virtual bool KeyValue( const char *szKeyName, Vector vec ) { return BaseClass::KeyValue( szKeyName, vec ); };
virtual bool KeyValue( const char *szKeyName, float flValue ) { return BaseClass::KeyValue( szKeyName, flValue ); };
TOGGLE_STATE m_toggle_state;
float m_flMoveDistance;// how far a door should slide or rotate
float m_flWait;
float m_flLip;
Vector m_vecPosition1;
Vector m_vecPosition2;
QAngle m_vecMoveAng;
QAngle m_vecAngle1;
QAngle m_vecAngle2;
float m_flHeight;
EHANDLE m_hActivator;
Vector m_vecFinalDest;
QAngle m_vecFinalAngle;
int m_movementType;
DECLARE_DATADESC();
virtual float GetDelay( void ) { return m_flWait; }
// common member functions
void LinearMove( const Vector &vecDest, float flSpeed );
void LinearMoveDone( void );
void AngularMove( const QAngle &vecDestAngle, float flSpeed );
void AngularMoveDone( void );
bool IsLockedByMaster( void );
virtual void MoveDone( void );
static float AxisValue( int flags, const QAngle &angles );
void AxisDir( void );
static float AxisDelta( int flags, const QAngle &angle1, const QAngle &angle2 );
string_t m_sMaster; // If this button has a master switch, this is the targetname.
// A master switch must be of the multisource type. If all
// of the switches in the multisource have been triggered, then
// the button will be allowed to operate. Otherwise, it will be
// deactivated.
};
#endif // BASETOGGLE_H

View File

@@ -0,0 +1,116 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $Workfile: $
// $Date: $
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "animation.h"
#include "baseviewmodel.h"
#include "player.h"
#include <KeyValues.h>
#include "studio.h"
#include "vguiscreen.h"
#include "saverestore_utlvector.h"
#include "hltvdirector.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
void SendProxy_AnimTime( const void *pStruct, const void *pVarData, DVariant *pOut, int iElement, int objectID );
void SendProxy_SequenceChanged( const void *pStruct, const void *pVarData, DVariant *pOut, int iElement, int objectID );
//-----------------------------------------------------------------------------
// Purpose: Save Data for Base Weapon object
//-----------------------------------------------------------------------------//
BEGIN_DATADESC( CBaseViewModel )
DEFINE_FIELD( m_hOwner, FIELD_EHANDLE ),
// Client only
// DEFINE_FIELD( m_LagAnglesHistory, CInterpolatedVar < QAngle > ),
// DEFINE_FIELD( m_vLagAngles, FIELD_VECTOR ),
DEFINE_FIELD( m_nViewModelIndex, FIELD_INTEGER ),
DEFINE_FIELD( m_flTimeWeaponIdle, FIELD_FLOAT ),
DEFINE_FIELD( m_nAnimationParity, FIELD_INTEGER ),
// Client only
// DEFINE_FIELD( m_nOldAnimationParity, FIELD_INTEGER ),
DEFINE_FIELD( m_vecLastFacing, FIELD_VECTOR ),
DEFINE_FIELD( m_hWeapon, FIELD_EHANDLE ),
DEFINE_UTLVECTOR( m_hScreens, FIELD_EHANDLE ),
// Read from weapons file
// DEFINE_FIELD( m_sVMName, FIELD_STRING ),
// DEFINE_FIELD( m_sAnimationPrefix, FIELD_STRING ),
// ---------------------------------------------------------------------
// Don't save these, init to 0 and regenerate
// DEFINE_FIELD( m_Activity, FIELD_INTEGER ),
END_DATADESC()
int CBaseViewModel::UpdateTransmitState()
{
if ( IsEffectActive( EF_NODRAW ) )
{
return SetTransmitState( FL_EDICT_DONTSEND );
}
return SetTransmitState( FL_EDICT_FULLCHECK );
}
int CBaseViewModel::ShouldTransmit( const CCheckTransmitInfo *pInfo )
{
// check if receipient owns this weapon viewmodel
CBasePlayer *pOwner = ToBasePlayer( m_hOwner );
if ( pOwner && pOwner->edict() == pInfo->m_pClientEnt )
{
return FL_EDICT_ALWAYS;
}
// check if recipient spectates the own of this viewmodel
CBaseEntity *pRecipientEntity = CBaseEntity::Instance( pInfo->m_pClientEnt );
if ( pRecipientEntity->IsPlayer() )
{
CBasePlayer *pPlayer = static_cast<CBasePlayer*>( pRecipientEntity );
#ifndef _XBOX
if ( pPlayer->IsHLTV() || pPlayer->IsReplay() )
{
// if this is the HLTV client, transmit all viewmodels in our PVS
return FL_EDICT_PVSCHECK;
}
#endif
if ( (pPlayer->GetObserverMode() == OBS_MODE_IN_EYE) && (pPlayer->GetObserverTarget() == pOwner) )
{
return FL_EDICT_ALWAYS;
}
}
// Don't send to anyone else except the local player or his spectators
return FL_EDICT_DONTSEND;
}
void CBaseViewModel::SetTransmit( CCheckTransmitInfo *pInfo, bool bAlways )
{
// Are we already marked for transmission?
if ( pInfo->m_pTransmitEdict->Get( entindex() ) )
return;
BaseClass::SetTransmit( pInfo, bAlways );
// Force our screens to be sent too.
for ( int i=0; i < m_hScreens.Count(); i++ )
{
CVGuiScreen *pScreen = m_hScreens[i].Get();
if ( pScreen )
pScreen->SetTransmit( pInfo, bAlways );
}
}

View File

@@ -0,0 +1,17 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Server side view model object
//
// $Workfile: $
// $Date: $
// $NoKeywords: $
//=============================================================================//
#if !defined( BASEVIEWMODEL_H )
#define BASEVIEWMODEL_H
#ifdef _WIN32
#pragma once
#endif
#include "baseviewmodel_shared.h"
#endif // BASEVIEWMODEL_H

View File

@@ -0,0 +1,27 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Arbitrary length bit string
// ** NOTE: This class does NOT override the bitwise operators
// as doing so would require overriding the operators
// to allocate memory for the returned bitstring. This method
// would be prone to memory leaks as the calling party
// would have to remember to delete the memory. Funtions
// are used instead to require the calling party to allocate
// and destroy their own memory
//
// $Workfile: $
// $Date: $
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include <limits.h>
#include "bitstring.h"
#include "utlbuffer.h"
#include "tier0/dbg.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"

View File

@@ -0,0 +1,28 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Arbitrary length bit string
// ** NOTE: This class does NOT override the bitwise operators
// as doing so would require overriding the operators
// to allocate memory for the returned bitstring. This method
// would be prone to memory leaks as the calling party
// would have to remember to delete the memory. Funtions
// are used instead to require the calling party to allocate
// and destroy their own memory
//
// $Workfile: $
// $Date: $
//
//-----------------------------------------------------------------------------
// $Log: $
//
// $NoKeywords: $
//=============================================================================//
#ifndef BITSTRING_H
#define BITSTRING_H
#pragma once
#include "bitvec.h"
#endif // BITSTRING_H

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,172 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================
#ifndef BUTTONS_H
#define BUTTONS_H
#ifdef _WIN32
#pragma once
#endif
class CBaseButton : public CBaseToggle
{
public:
DECLARE_CLASS( CBaseButton, CBaseToggle );
void Spawn( void );
virtual void Precache( void );
bool CreateVPhysics();
void RotSpawn( void );
bool KeyValue( const char *szKeyName, const char *szValue );
int DrawDebugTextOverlays();
protected:
void ButtonActivate( );
void SparkSoundCache( void );
void ButtonTouch( ::CBaseEntity *pOther );
void ButtonSpark ( void );
void TriggerAndWait( void );
void ButtonReturn( void );
void ButtonBackHome( void );
void ButtonUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
bool OnUseLocked( CBaseEntity *pActivator );
virtual void Lock();
virtual void Unlock();
// Input handlers
void InputLock( inputdata_t &inputdata );
void InputUnlock( inputdata_t &inputdata );
void InputPress( inputdata_t &inputdata );
void InputPressIn( inputdata_t &inputdata );
void InputPressOut( inputdata_t &inputdata );
virtual int OnTakeDamage( const CTakeDamageInfo &info );
enum BUTTON_CODE { BUTTON_NOTHING, BUTTON_ACTIVATE, BUTTON_RETURN, BUTTON_PRESS };
BUTTON_CODE ButtonResponseToTouch( void );
void Press( CBaseEntity *pActivator, BUTTON_CODE eCode );
DECLARE_DATADESC();
virtual int ObjectCaps(void);
Vector m_vecMoveDir;
bool m_fStayPushed; // button stays pushed in until touched again?
bool m_fRotating; // a rotating button? default is a sliding button.
locksound_t m_ls; // door lock sounds
byte m_bLockedSound; // ordinals from entity selection
byte m_bLockedSentence;
byte m_bUnlockedSound;
byte m_bUnlockedSentence;
bool m_bLocked;
int m_sounds;
float m_flUseLockedTime; // Controls how often we fire the OnUseLocked output.
bool m_bSolidBsp;
string_t m_sNoise; // The actual WAV file name of the sound.
COutputEvent m_OnDamaged;
COutputEvent m_OnPressed;
COutputEvent m_OnUseLocked;
COutputEvent m_OnIn;
COutputEvent m_OnOut;
int m_nState;
};
//
// Rotating button (aka "lever")
//
class CRotButton : public CBaseButton
{
public:
DECLARE_CLASS( CRotButton, CBaseButton );
void Spawn( void );
bool CreateVPhysics( void );
};
class CMomentaryRotButton : public CRotButton
{
DECLARE_CLASS( CMomentaryRotButton, CRotButton );
public:
void Spawn ( void );
bool CreateVPhysics( void );
virtual int ObjectCaps( void );
void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
void UseMoveDone( void );
void ReturnMoveDone( void );
void OutputMovementComplete(void);
void SetPositionMoveDone(void);
void UpdateSelf( float value, bool bPlaySound );
void PlaySound( void );
void UpdateTarget( float value, CBaseEntity *pActivator );
int DrawDebugTextOverlays(void);
static CMomentaryRotButton *Instance( edict_t *pent ) { return (CMomentaryRotButton *)GetContainingEntity(pent); }
float GetPos(const QAngle &vecAngles);
DECLARE_DATADESC();
virtual void Lock();
virtual void Unlock();
// Input handlers
void InputSetPosition( inputdata_t &inputdata );
void InputSetPositionImmediately( inputdata_t &inputdata );
void InputDisableUpdateTarget( inputdata_t &inputdata );
void InputEnableUpdateTarget( inputdata_t &inputdata );
void InputEnable( inputdata_t &inputdata );
void InputDisable( inputdata_t &inputdata );
virtual void Enable( void );
virtual void Disable( void );
bool m_bDisabled;
COutputFloat m_Position;
COutputEvent m_OnUnpressed;
COutputEvent m_OnFullyOpen;
COutputEvent m_OnFullyClosed;
COutputEvent m_OnReachedPosition;
int m_lastUsed;
QAngle m_start;
QAngle m_end;
float m_IdealYaw;
string_t m_sNoise;
bool m_bUpdateTarget; // Used when jiggling so that we don't jiggle the target (door, etc)
int m_direction;
float m_returnSpeed;
float m_flStartPosition;
protected:
void UpdateThink( void );
};
#endif // BUTTONS_H

2199
sp/src/game/server/cbase.cpp Normal file

File diff suppressed because it is too large Load Diff

157
sp/src/game/server/cbase.h Normal file
View File

@@ -0,0 +1,157 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#ifndef CBASE_H
#define CBASE_H
#ifdef _WIN32
#pragma once
#endif
#ifdef _WIN32
// Silence certain warnings
#pragma warning(disable : 4244) // int or float down-conversion
#pragma warning(disable : 4305) // int or float data truncation
#pragma warning(disable : 4201) // nameless struct/union
#pragma warning(disable : 4511) // copy constructor could not be generated
#pragma warning(disable : 4675) // resolved overload was found by argument dependent lookup
#endif
#ifdef _DEBUG
#define DEBUG 1
#endif
// Misc C-runtime library headers
#include <math.h>
#include <stdio.h>
// tier 0
#include "tier0/dbg.h"
#include "tier0/platform.h"
#include "basetypes.h"
// tier 1
#include "tier1/strtools.h"
#include "utlvector.h"
#include "mathlib/vmatrix.h"
// tier 2
#include "string_t.h"
// tier 3
#include "vphysics_interface.h"
// Shared engine/DLL constants
#include "const.h"
#include "edict.h"
// Shared header describing protocol between engine and DLLs
#include "eiface.h"
#include "iserverentity.h"
#include "dt_send.h"
// Shared header between the client DLL and the game DLLs
#include "shareddefs.h"
#include "ehandle.h"
// app
#if defined(_X360)
#define DISABLE_DEBUG_HISTORY 1
#endif
#include "datamap.h"
#include "util.h"
#include "predictable_entity.h"
#include "predictableid.h"
#include "variant_t.h"
#include "takedamageinfo.h"
#include "utllinkedlist.h"
#include "touchlink.h"
#include "groundlink.h"
#include "base_transmit_proxy.h"
#include "soundflags.h"
#include "networkvar.h"
#include "baseentity_shared.h"
#include "basetoggle.h"
#include "igameevents.h"
#ifdef MAPBASE
#include "tier1/mapbase_con_groups.h"
#endif
// saverestore.h declarations
class ISave;
class IRestore;
// maximum number of targets a single multi_manager entity may be assigned.
#define MAX_MULTI_TARGETS 16
// NPCEvent.h declarations
struct animevent_t;
struct studiohdr_t;
class CStudioHdr;
extern void FireTargets( const char *targetName, CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
// people gib if their health is <= this at the time of death
#define GIB_HEALTH_VALUE -30
#define MAX_OLD_ENEMIES 4 // how many old enemies to remember
// used by suit voice to indicate damage sustained and repaired type to player
enum
{
itbd_Paralyze = 0,
itbd_NerveGas,
itbd_PoisonRecover,
itbd_Radiation,
itbd_DrownRecover,
itbd_Acid,
itbd_SlowBurn,
itbd_SlowFreeze,
// Must be last!
CDMG_TIMEBASED
};
// when calling KILLED(), a value that governs gib behavior is expected to be
// one of these three values
#define GIB_NORMAL 0// gib if entity was overkilled
#define GIB_NEVER 1// never gib, no matter how much death damage is done ( freezing, etc )
#define GIB_ALWAYS 2// always gib
class CAI_BaseNPC;
class CAI_ScriptedSequence;
class CSound;
#ifdef _XBOX
//#define FUNCTANK_AUTOUSE We haven't made the decision to use this yet (sjb)
#else
#undef FUNCTANK_AUTOUSE
#endif//_XBOX
// This is a precompiled header. Include a bunch of common stuff.
// This is kind of ugly in that it adds a bunch of dependency where it isn't needed.
// But on balance, the compile time is much lower (even incrementally) once the precompiled
// headers contain these headers.
#include "precache_register.h"
#include "baseanimating.h"
#include "basecombatweapon.h"
#include "basecombatcharacter.h"
#include "gamerules.h"
#include "entitylist.h"
#include "basetempentity.h"
#include "player.h"
#include "te.h"
#include "physics.h"
#include "ndebugoverlay.h"
#include "recipientfilter.h"
#endif // CBASE_H

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,32 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//
//=============================================================================//
#ifndef CLIENT_H
#define CLIENT_H
#ifdef _WIN32
#pragma once
#endif
class CCommand;
class CUserCmd;
class CBasePlayer;
void ClientActive( edict_t *pEdict, bool bLoadGame );
void ClientPutInServer( edict_t *pEdict, const char *playername );
void ClientCommand( CBasePlayer *pSender, const CCommand &args );
void ClientPrecache( void );
// Game specific precaches
void ClientGamePrecache( void );
const char *GetGameDescription( void );
void Host_Say( edict_t *pEdict, bool teamonly );
#endif // CLIENT_H

View File

@@ -0,0 +1,314 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Color correction entity.
//
// $NoKeywords: $
//===========================================================================//
#include <string.h>
#include "cbase.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
#define COLOR_CORRECTION_ENT_THINK_RATE TICK_INTERVAL
static const char *s_pFadeInContextThink = "ColorCorrectionFadeInThink";
static const char *s_pFadeOutContextThink = "ColorCorrectionFadeOutThink";
//------------------------------------------------------------------------------
// FIXME: This really should inherit from something more lightweight
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
// Purpose : Shadow control entity
//------------------------------------------------------------------------------
class CColorCorrection : public CBaseEntity
{
DECLARE_CLASS( CColorCorrection, CBaseEntity );
public:
DECLARE_SERVERCLASS();
DECLARE_DATADESC();
CColorCorrection();
void Spawn( void );
int UpdateTransmitState();
void Activate( void );
virtual int ObjectCaps( void ) { return BaseClass::ObjectCaps() & ~FCAP_ACROSS_TRANSITION; }
// Inputs
void InputEnable( inputdata_t &inputdata );
void InputDisable( inputdata_t &inputdata );
void InputSetFadeInDuration ( inputdata_t &inputdata );
void InputSetFadeOutDuration ( inputdata_t &inputdata );
private:
void FadeIn ( void );
void FadeOut ( void );
void FadeInThink( void ); // Fades lookup weight from Cur->MaxWeight
void FadeOutThink( void ); // Fades lookup weight from CurWeight->0.0
float m_flFadeInDuration; // Duration for a full 0->MaxWeight transition
float m_flFadeOutDuration; // Duration for a full Max->0 transition
float m_flStartFadeInWeight;
float m_flStartFadeOutWeight;
float m_flTimeStartFadeIn;
float m_flTimeStartFadeOut;
float m_flMaxWeight;
bool m_bStartDisabled;
CNetworkVar( bool, m_bEnabled );
CNetworkVar( float, m_MinFalloff );
CNetworkVar( float, m_MaxFalloff );
CNetworkVar( float, m_flCurWeight );
CNetworkString( m_netlookupFilename, MAX_PATH );
string_t m_lookupFilename;
};
LINK_ENTITY_TO_CLASS(color_correction, CColorCorrection);
BEGIN_DATADESC( CColorCorrection )
DEFINE_THINKFUNC( FadeInThink ),
DEFINE_THINKFUNC( FadeOutThink ),
DEFINE_FIELD( m_flCurWeight, FIELD_FLOAT ),
DEFINE_FIELD( m_flTimeStartFadeIn, FIELD_FLOAT ),
DEFINE_FIELD( m_flTimeStartFadeOut, FIELD_FLOAT ),
DEFINE_FIELD( m_flStartFadeInWeight, FIELD_FLOAT ),
DEFINE_FIELD( m_flStartFadeOutWeight, FIELD_FLOAT ),
DEFINE_KEYFIELD( m_MinFalloff, FIELD_FLOAT, "minfalloff" ),
DEFINE_KEYFIELD( m_MaxFalloff, FIELD_FLOAT, "maxfalloff" ),
DEFINE_KEYFIELD( m_flMaxWeight, FIELD_FLOAT, "maxweight" ),
DEFINE_KEYFIELD( m_flFadeInDuration, FIELD_FLOAT, "fadeInDuration" ),
DEFINE_KEYFIELD( m_flFadeOutDuration, FIELD_FLOAT, "fadeOutDuration" ),
DEFINE_KEYFIELD( m_lookupFilename, FIELD_STRING, "filename" ),
DEFINE_KEYFIELD( m_bEnabled, FIELD_BOOLEAN, "enabled" ),
DEFINE_KEYFIELD( m_bStartDisabled, FIELD_BOOLEAN, "StartDisabled" ),
// DEFINE_ARRAY( m_netlookupFilename, FIELD_CHARACTER, MAX_PATH ),
DEFINE_INPUTFUNC( FIELD_VOID, "Enable", InputEnable ),
DEFINE_INPUTFUNC( FIELD_VOID, "Disable", InputDisable ),
DEFINE_INPUTFUNC( FIELD_FLOAT, "SetFadeInDuration", InputSetFadeInDuration ),
DEFINE_INPUTFUNC( FIELD_FLOAT, "SetFadeOutDuration", InputSetFadeOutDuration ),
END_DATADESC()
extern void SendProxy_Origin( const SendProp *pProp, const void *pStruct, const void *pData, DVariant *pOut, int iElement, int objectID );
IMPLEMENT_SERVERCLASS_ST_NOBASE(CColorCorrection, DT_ColorCorrection)
SendPropVector( SENDINFO(m_vecOrigin), -1, SPROP_NOSCALE, 0.0f, HIGH_DEFAULT, SendProxy_Origin ),
SendPropFloat( SENDINFO(m_MinFalloff) ),
SendPropFloat( SENDINFO(m_MaxFalloff) ),
SendPropFloat( SENDINFO(m_flCurWeight) ),
SendPropString( SENDINFO(m_netlookupFilename) ),
SendPropBool( SENDINFO(m_bEnabled) ),
END_SEND_TABLE()
CColorCorrection::CColorCorrection() : BaseClass()
{
m_bEnabled = true;
m_MinFalloff = 0.0f;
m_MaxFalloff = 1000.0f;
m_flMaxWeight = 1.0f;
m_flCurWeight.Set( 0.0f );
m_flFadeInDuration = 0.0f;
m_flFadeOutDuration = 0.0f;
m_flStartFadeInWeight = 0.0f;
m_flStartFadeOutWeight = 0.0f;
m_flTimeStartFadeIn = 0.0f;
m_flTimeStartFadeOut = 0.0f;
m_netlookupFilename.GetForModify()[0] = 0;
m_lookupFilename = NULL_STRING;
}
//------------------------------------------------------------------------------
// Purpose : Send even though we don't have a model
//------------------------------------------------------------------------------
int CColorCorrection::UpdateTransmitState()
{
// ALWAYS transmit to all clients.
return SetTransmitState( FL_EDICT_ALWAYS );
}
//------------------------------------------------------------------------------
// Purpose :
//------------------------------------------------------------------------------
void CColorCorrection::Spawn( void )
{
AddEFlags( EFL_FORCE_CHECK_TRANSMIT | EFL_DIRTY_ABSTRANSFORM );
Precache();
SetSolid( SOLID_NONE );
// To fade in/out the weight.
SetContextThink( &CColorCorrection::FadeInThink, TICK_NEVER_THINK, s_pFadeInContextThink );
SetContextThink( &CColorCorrection::FadeOutThink, TICK_NEVER_THINK, s_pFadeOutContextThink );
if( m_bStartDisabled )
{
m_bEnabled = false;
m_flCurWeight.Set ( 0.0f );
}
else
{
m_bEnabled = true;
m_flCurWeight.Set ( 1.0f );
}
BaseClass::Spawn();
}
void CColorCorrection::Activate( void )
{
BaseClass::Activate();
Q_strncpy( m_netlookupFilename.GetForModify(), STRING( m_lookupFilename ), MAX_PATH );
}
//-----------------------------------------------------------------------------
// Purpose: Sets up internal vars needed for fade in lerping
//-----------------------------------------------------------------------------
void CColorCorrection::FadeIn ( void )
{
m_bEnabled = true;
m_flTimeStartFadeIn = gpGlobals->curtime;
m_flStartFadeInWeight = m_flCurWeight;
SetNextThink ( gpGlobals->curtime + COLOR_CORRECTION_ENT_THINK_RATE, s_pFadeInContextThink );
}
//-----------------------------------------------------------------------------
// Purpose: Sets up internal vars needed for fade out lerping
//-----------------------------------------------------------------------------
void CColorCorrection::FadeOut ( void )
{
m_bEnabled = false;
m_flTimeStartFadeOut = gpGlobals->curtime;
m_flStartFadeOutWeight = m_flCurWeight;
SetNextThink ( gpGlobals->curtime + COLOR_CORRECTION_ENT_THINK_RATE, s_pFadeOutContextThink );
}
//-----------------------------------------------------------------------------
// Purpose: Fades lookup weight from CurWeight->MaxWeight
//-----------------------------------------------------------------------------
void CColorCorrection::FadeInThink( void )
{
// Check for conditions where we shouldnt fade in
if ( m_flFadeInDuration <= 0 || // not set to fade in
m_flCurWeight >= m_flMaxWeight || // already past max weight
!m_bEnabled || // fade in/out mutex
m_flMaxWeight == 0.0f || // min==max
m_flStartFadeInWeight >= m_flMaxWeight ) // already at max weight
{
SetNextThink ( TICK_NEVER_THINK, s_pFadeInContextThink );
return;
}
// If we started fading in without fully fading out, use a truncated duration
float flTimeToFade = m_flFadeInDuration;
if ( m_flStartFadeInWeight > 0.0f )
{
float flWeightRatio = m_flStartFadeInWeight / m_flMaxWeight;
flWeightRatio = clamp ( flWeightRatio, 0.0f, 0.99f );
flTimeToFade = m_flFadeInDuration * (1.0 - flWeightRatio);
}
Assert ( flTimeToFade > 0.0f );
float flFadeRatio = (gpGlobals->curtime - m_flTimeStartFadeIn) / flTimeToFade;
flFadeRatio = clamp ( flFadeRatio, 0.0f, 1.0f );
m_flStartFadeInWeight = clamp ( m_flStartFadeInWeight, 0.0f, 1.0f );
m_flCurWeight = Lerp( flFadeRatio, m_flStartFadeInWeight, m_flMaxWeight );
SetNextThink( gpGlobals->curtime + COLOR_CORRECTION_ENT_THINK_RATE, s_pFadeInContextThink );
}
//-----------------------------------------------------------------------------
// Purpose: Fades lookup weight from CurWeight->0.0
//-----------------------------------------------------------------------------
void CColorCorrection::FadeOutThink( void )
{
// Check for conditions where we shouldn't fade out
if ( m_flFadeOutDuration <= 0 || // not set to fade out
m_flCurWeight <= 0.0f || // already faded out
m_bEnabled || // fade in/out mutex
m_flMaxWeight == 0.0f || // min==max
m_flStartFadeOutWeight <= 0.0f )// already at min weight
{
SetNextThink ( TICK_NEVER_THINK, s_pFadeOutContextThink );
return;
}
// If we started fading out without fully fading in, use a truncated duration
float flTimeToFade = m_flFadeOutDuration;
if ( m_flStartFadeOutWeight < m_flMaxWeight )
{
float flWeightRatio = m_flStartFadeOutWeight / m_flMaxWeight;
flWeightRatio = clamp ( flWeightRatio, 0.01f, 1.0f );
flTimeToFade = m_flFadeOutDuration * flWeightRatio;
}
Assert ( flTimeToFade > 0.0f );
float flFadeRatio = (gpGlobals->curtime - m_flTimeStartFadeOut) / flTimeToFade;
flFadeRatio = clamp ( flFadeRatio, 0.0f, 1.0f );
m_flStartFadeOutWeight = clamp ( m_flStartFadeOutWeight, 0.0f, 1.0f );
m_flCurWeight = Lerp( 1.0f - flFadeRatio, 0.0f, m_flStartFadeOutWeight );
SetNextThink( gpGlobals->curtime + COLOR_CORRECTION_ENT_THINK_RATE, s_pFadeOutContextThink );
}
//------------------------------------------------------------------------------
// Purpose : Input handlers
//------------------------------------------------------------------------------
void CColorCorrection::InputEnable( inputdata_t &inputdata )
{
m_bEnabled = true;
if ( m_flFadeInDuration > 0.0f )
{
FadeIn();
}
else
{
m_flCurWeight = m_flMaxWeight;
}
}
void CColorCorrection::InputDisable( inputdata_t &inputdata )
{
m_bEnabled = false;
if ( m_flFadeOutDuration > 0.0f )
{
FadeOut();
}
else
{
m_flCurWeight = 0.0f;
}
}
void CColorCorrection::InputSetFadeInDuration( inputdata_t& inputdata )
{
m_flFadeInDuration = inputdata.value.Float();
}
void CColorCorrection::InputSetFadeOutDuration( inputdata_t& inputdata )
{
m_flFadeOutDuration = inputdata.value.Float();
}

View File

@@ -0,0 +1,236 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Color correction entity.
//
// $NoKeywords: $
//=============================================================================//
#include <string.h>
#include "cbase.h"
#include "triggers.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 : Shadow control entity
//------------------------------------------------------------------------------
class CColorCorrectionVolume : public CBaseTrigger
{
DECLARE_CLASS( CColorCorrectionVolume, CBaseTrigger );
public:
DECLARE_SERVERCLASS();
DECLARE_DATADESC();
CColorCorrectionVolume();
void Spawn( void );
bool KeyValue( const char *szKeyName, const char *szValue );
int UpdateTransmitState();
void ThinkFunc();
virtual bool PassesTriggerFilters(CBaseEntity *pOther);
virtual void StartTouch( CBaseEntity *pEntity );
virtual void EndTouch( CBaseEntity *pEntity );
virtual int ObjectCaps( void ) { return BaseClass::ObjectCaps() & ~FCAP_ACROSS_TRANSITION; }
// Inputs
void InputEnable( inputdata_t &inputdata );
void InputDisable( inputdata_t &inputdata );
private:
bool m_bEnabled;
bool m_bStartDisabled;
CNetworkVar( float, m_Weight );
CNetworkVar( float, m_MaxWeight );
CNetworkString( m_lookupFilename, MAX_PATH );
float m_LastEnterWeight;
float m_LastEnterTime;
float m_LastExitWeight;
float m_LastExitTime;
float m_FadeDuration;
};
LINK_ENTITY_TO_CLASS(color_correction_volume, CColorCorrectionVolume);
BEGIN_DATADESC( CColorCorrectionVolume )
DEFINE_THINKFUNC( ThinkFunc ),
DEFINE_KEYFIELD( m_FadeDuration, FIELD_FLOAT, "fadeDuration" ),
DEFINE_KEYFIELD( m_MaxWeight, FIELD_FLOAT, "maxweight" ),
DEFINE_AUTO_ARRAY_KEYFIELD( m_lookupFilename, FIELD_CHARACTER, "filename" ),
DEFINE_KEYFIELD( m_bEnabled, FIELD_BOOLEAN, "enabled" ),
DEFINE_KEYFIELD( m_bStartDisabled, FIELD_BOOLEAN, "StartDisabled" ),
DEFINE_FIELD( m_Weight, FIELD_FLOAT ),
DEFINE_FIELD( m_LastEnterWeight, FIELD_FLOAT ),
DEFINE_FIELD( m_LastEnterTime, FIELD_FLOAT ),
DEFINE_FIELD( m_LastExitWeight, FIELD_FLOAT ),
DEFINE_FIELD( m_LastExitTime, FIELD_FLOAT ),
DEFINE_INPUTFUNC( FIELD_VOID, "Enable", InputEnable ),
DEFINE_INPUTFUNC( FIELD_VOID, "Disable", InputDisable ),
END_DATADESC()
IMPLEMENT_SERVERCLASS_ST_NOBASE(CColorCorrectionVolume, DT_ColorCorrectionVolume)
SendPropFloat( SENDINFO(m_Weight) ),
SendPropString( SENDINFO(m_lookupFilename) ),
END_SEND_TABLE()
CColorCorrectionVolume::CColorCorrectionVolume() : BaseClass()
{
m_bEnabled = true;
m_MaxWeight = 1.0f;
m_lookupFilename.GetForModify()[0] = 0;
}
//------------------------------------------------------------------------------
// Purpose : Send even though we don't have a model
//------------------------------------------------------------------------------
int CColorCorrectionVolume::UpdateTransmitState()
{
// ALWAYS transmit to all clients.
return SetTransmitState( FL_EDICT_ALWAYS );
}
bool CColorCorrectionVolume::KeyValue( const char *szKeyName, const char *szValue )
{
if ( FStrEq( szKeyName, "filename" ) )
{
Q_strncpy( m_lookupFilename.GetForModify(), szValue, MAX_PATH );
return true;
}
else if ( FStrEq( szKeyName, "maxweight" ) )
{
float max_weight;
sscanf( szValue, "%f", &max_weight );
m_MaxWeight = max_weight;
return true;
}
return BaseClass::KeyValue( szKeyName, szValue );
}
//------------------------------------------------------------------------------
// Purpose :
//------------------------------------------------------------------------------
void CColorCorrectionVolume::Spawn( void )
{
BaseClass::Spawn();
AddEFlags( EFL_FORCE_CHECK_TRANSMIT | EFL_DIRTY_ABSTRANSFORM );
Precache();
SetSolid( SOLID_BSP );
SetSolidFlags( FSOLID_TRIGGER | FSOLID_NOT_SOLID );
SetModel( STRING( GetModelName() ) );
SetThink( &CColorCorrectionVolume::ThinkFunc );
SetNextThink( gpGlobals->curtime + 0.01f );
if( m_bStartDisabled )
{
m_bEnabled = false;
}
else
{
m_bEnabled = true;
}
}
bool CColorCorrectionVolume::PassesTriggerFilters( CBaseEntity *pEntity )
{
if( pEntity == UTIL_GetLocalPlayer() )
return true;
return false;
}
void CColorCorrectionVolume::StartTouch( CBaseEntity *pEntity )
{
m_LastEnterTime = gpGlobals->curtime;
m_LastEnterWeight = m_Weight;
}
void CColorCorrectionVolume::EndTouch( CBaseEntity *pEntity )
{
m_LastExitTime = gpGlobals->curtime;
m_LastExitWeight = m_Weight;
}
void CColorCorrectionVolume::ThinkFunc( )
{
if( !m_bEnabled )
{
m_Weight.Set( 0.0f );
}
else
{
if( m_LastEnterTime > m_LastExitTime )
{
// we most recently entered the volume
if( m_Weight < 1.0f )
{
float dt = gpGlobals->curtime - m_LastEnterTime;
float weight = m_LastEnterWeight + dt / ((1.0f-m_LastEnterWeight)*m_FadeDuration);
if( weight>1.0f )
weight = 1.0f;
m_Weight = weight;
}
}
else
{
// we most recently exitted the volume
if( m_Weight > 0.0f )
{
float dt = gpGlobals->curtime - m_LastExitTime;
float weight = (1.0f-m_LastExitWeight) + dt / (m_LastExitWeight*m_FadeDuration);
if( weight>1.0f )
weight = 1.0f;
m_Weight = 1.0f - weight;
}
}
}
SetNextThink( gpGlobals->curtime + 0.01f );
}
//------------------------------------------------------------------------------
// Purpose : Input handlers
//------------------------------------------------------------------------------
void CColorCorrectionVolume::InputEnable( inputdata_t &inputdata )
{
m_bEnabled = true;
}
void CColorCorrectionVolume::InputDisable( inputdata_t &inputdata )
{
m_bEnabled = false;
}

View File

@@ -0,0 +1,146 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: contains entities who have no physical representation in the game, and who
// must be triggered by other entities to cause their effects.
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "player.h"
#include "tier1/strtools.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
//-----------------------------------------------------------------------------
// Purpose: when fired, it changes which track the CD is playing
//-----------------------------------------------------------------------------
class CTargetCDAudioRep : public CPointEntity
{
public:
DECLARE_CLASS( CTargetCDAudioRep, CPointEntity );
void InputChangeCDTrack( inputdata_t &inputdata );
DECLARE_DATADESC();
private:
int m_iTrack; // CD track to change to when fired
};
LINK_ENTITY_TO_CLASS( target_cdaudio, CTargetCDAudioRep );
BEGIN_DATADESC( CTargetCDAudioRep )
DEFINE_KEYFIELD( m_iTrack, FIELD_INTEGER, "track" ),
DEFINE_INPUTFUNC( FIELD_VOID, "ChangeCDTrack", InputChangeCDTrack ),
END_DATADESC()
//-----------------------------------------------------------------------------
// Purpose: Changes the current playing CD track
//-----------------------------------------------------------------------------
void CTargetCDAudioRep::InputChangeCDTrack( inputdata_t &inputdata )
{
int iTrack = m_iTrack;
edict_t *pClient = NULL;
if ( gpGlobals->maxClients == 1 )
{
pClient = engine->PEntityOfEntIndex( 1 );
}
else
{
// In multiplayer, send it back to the activator
CBasePlayer *player = dynamic_cast< CBasePlayer * >( inputdata.pActivator );
if ( player )
{
pClient = player->edict();
}
}
// Can't play if the client is not connected!
if ( !pClient )
return;
if ( iTrack < -1 || iTrack > 30 )
{
Warning( "TargetCDAudio - Track %d out of range\n", iTrack );
return;
}
if ( iTrack == -1 )
{
engine->ClientCommand( pClient, "cd pause\n" );
}
else
{
engine->ClientCommand ( pClient, "cd play %3d\n", iTrack );
}
}
//-----------------------------------------------------------------------------
// Purpose: changes the gravity of the player who activates this entity
//-----------------------------------------------------------------------------
class CTargetChangeGravity : public CPointEntity
{
public:
DECLARE_CLASS( CTargetChangeGravity, CPointEntity );
DECLARE_DATADESC();
void InputChangeGrav( inputdata_t &inputdata );
void InputResetGrav( inputdata_t &inputdata );
int m_iGravity;
int m_iOldGrav;
};
LINK_ENTITY_TO_CLASS( target_changegravity, CTargetChangeGravity );
BEGIN_DATADESC( CTargetChangeGravity )
DEFINE_KEYFIELD( m_iGravity, FIELD_INTEGER, "gravity" ),
DEFINE_FIELD( m_iOldGrav, FIELD_INTEGER ),
DEFINE_INPUTFUNC( FIELD_VOID, "ChangeGrav", InputChangeGrav ),
DEFINE_INPUTFUNC( FIELD_VOID, "ResetGrav", InputResetGrav ),
END_DATADESC()
//-----------------------------------------------------------------------------
// Purpose: Input handler for changing the activator's gravity.
//-----------------------------------------------------------------------------
void CTargetChangeGravity::InputChangeGrav( inputdata_t &inputdata )
{
CBasePlayer *pl = ToBasePlayer( inputdata.pActivator );
if ( !pl )
return;
// Save the gravity to restore it in InputResetGrav
if ( m_iOldGrav )
m_iOldGrav = pl->GetGravity();
pl->SetGravity(m_iGravity);
}
//-----------------------------------------------------------------------------
// Purpose: Input handler for resetting the activator's gravity.
//-----------------------------------------------------------------------------
void CTargetChangeGravity::InputResetGrav( inputdata_t &inputdata )
{
CBasePlayer *pl = ToBasePlayer( inputdata.pActivator );
if ( !pl )
return;
pl->SetGravity(m_iOldGrav);
}

View File

@@ -0,0 +1,71 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "game.h"
#include "cplane.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
//=========================================================
// Plane
//=========================================================
CPlane::CPlane ( void )
{
m_fInitialized = FALSE;
}
//=========================================================
// InitializePlane - Takes a normal for the plane and a
// point on the plane and
//=========================================================
void CPlane::InitializePlane ( const Vector &vecNormal, const Vector &vecPoint )
{
m_vecNormal = vecNormal;
m_flDist = DotProduct ( m_vecNormal, vecPoint );
m_fInitialized = TRUE;
}
//=========================================================
// PointInFront - determines whether the given vector is
// in front of the plane.
//=========================================================
bool CPlane::PointInFront ( const Vector &vecPoint )
{
float flFace;
if ( !m_fInitialized )
{
return FALSE;
}
flFace = DotProduct ( m_vecNormal, vecPoint ) - m_flDist;
if ( flFace >= 0 )
{
return TRUE;
}
return FALSE;
}
//=========================================================
//=========================================================
float CPlane::PointDist ( const Vector &vecPoint )
{
float flDist;
if ( !m_fInitialized )
{
return FALSE;
}
flDist = DotProduct ( m_vecNormal, vecPoint ) - m_flDist;
return flDist;
}

View File

@@ -0,0 +1,44 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//
//=============================================================================//
#pragma once
#ifndef CPLANE_H
#define CPLANE_H
//=========================================================
// Plane
//=========================================================
class CPlane
{
public:
CPlane ( void );
//=========================================================
// InitializePlane - Takes a normal for the plane and a
// point on the plane and
//=========================================================
void InitializePlane ( const Vector &vecNormal, const Vector &vecPoint );
//=========================================================
// PointInFront - determines whether the given vector is
// in front of the plane.
//=========================================================
bool PointInFront ( const Vector &vecPoint );
//=========================================================
// How far off the plane is this point?
//=========================================================
float PointDist( const Vector &vecPoint );
private:
Vector m_vecNormal;
float m_flDist;
bool m_fInitialized;
};
#endif //CPLANE_H

View File

@@ -0,0 +1,9 @@
$Project
{
$Folder "Source Files"
{
$File "env_cascade_light.cpp"
}
}

View File

@@ -0,0 +1,85 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "damagemodifier.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
CDamageModifier::CDamageModifier()
{
m_flModifier = 1;
m_bDoneToMe = false;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CDamageModifier::AddModifierToEntity( CBaseEntity *pEntity )
{
RemoveModifier();
pEntity->m_DamageModifiers.AddToTail( this );
m_hEnt = pEntity;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CDamageModifier::RemoveModifier()
{
if ( m_hEnt.Get() )
{
m_hEnt->m_DamageModifiers.FindAndRemove( this );
m_hEnt = 0;
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CDamageModifier::SetModifier( float flScale )
{
m_flModifier = flScale;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
float CDamageModifier::GetModifier() const
{
return m_flModifier;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
CBaseEntity* CDamageModifier::GetCharacter() const
{
return m_hEnt.Get();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CDamageModifier::SetDoneToMe( bool bDoneToMe )
{
m_bDoneToMe = bDoneToMe;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
bool CDamageModifier::IsDamageDoneToMe() const
{
return m_bDoneToMe;
}

View File

@@ -0,0 +1,46 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#ifndef DAMAGEMODIFIER_H
#define DAMAGEMODIFIER_H
#ifdef _WIN32
#pragma once
#endif
class CBaseEntity;
#include "ehandle.h"
//-----------------------------------------------------------------------------
// Purpose: Class handling generic damage modification to & from a player
//-----------------------------------------------------------------------------
class CDamageModifier
{
public:
CDamageModifier();
void AddModifierToEntity( CBaseEntity *pChar );
void RemoveModifier();
void SetModifier( float flDamageScale );
float GetModifier() const;
void SetDoneToMe( bool bDoneToMe );
bool IsDamageDoneToMe() const;
CBaseEntity *GetCharacter() const;
private:
float m_flModifier;
CHandle<CBaseEntity> m_hEnt;
bool m_bDoneToMe; // True = modifies damage done to the entity, false = damage done by the entity
};
#endif // DAMAGEMODIFIER_H

View File

@@ -0,0 +1,66 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//
//=============================================================================//
// data_collector.cpp
// Data collection system
// Author: Michael S. Booth, June 2004
#include "cbase.h"
#include "data_collector.h"
static CDataCollector *collector = NULL;
//----------------------------------------------------------------------------------------------------------------------
void StartDataCollection( void )
{
if (collector)
{
// already collecting
return;
}
collector = new CDataCollector;
Msg( "Data colletion started.\n" );
}
ConCommand data_collection_start( "data_collection_start", StartDataCollection, "Start collecting game event data." );
//----------------------------------------------------------------------------------------------------------------------
void StopDataCollection( void )
{
if (collector)
{
delete collector;
collector = NULL;
Msg( "Data collection stopped.\n" );
}
}
ConCommand data_collection_stop( "data_collection_stop", StopDataCollection, "Stop collecting game event data." );
//----------------------------------------------------------------------------------------------------------------------
CDataCollector::CDataCollector( void )
{
// register for all events
gameeventmanager->AddListener( this, true );
}
//----------------------------------------------------------------------------------------------------------------------
CDataCollector::~CDataCollector()
{
gameeventmanager->RemoveListener( this );
}
//----------------------------------------------------------------------------------------------------------------------
/**
* This is invoked for each event that occurs in the game
*/
void CDataCollector::FireGameEvent( KeyValues *event )
{
DevMsg( "Collected event '%s'\n", event->GetName() );
}

View File

@@ -0,0 +1,37 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//
//=============================================================================//
// data_collector.h
// Data collection system
// Author: Michael S. Booth, June 2004
#ifndef _DATA_COLLECTOR_H_
#define _DATA_COLLECTOR_H_
#include <igameevents.h>
#include <KeyValues.h>
/**
* This class is used to monitor the event stream and
* store interesting events to disk for later analysis.
*/
class CDataCollector : public IGameEventListener
{
public:
CDataCollector( void );
~CDataCollector();
// IGameEventListener
virtual void FireGameEvent( KeyValues *event );
};
extern void StartDataCollection( void );
extern void StopDataCollection( void );
#endif // _DATA_COLLECTOR_H_

1433
sp/src/game/server/doors.cpp Normal file

File diff suppressed because it is too large Load Diff

162
sp/src/game/server/doors.h Normal file
View File

@@ -0,0 +1,162 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#ifndef DOORS_H
#define DOORS_H
#pragma once
#include "locksounds.h"
#include "entityoutput.h"
//Since I'm here, might as well explain how these work. Base.fgd is the file that connects
//flags to entities. It is full of lines with this number, a label, and a default value.
//Voila, dynamicly generated checkboxes on the Flags tab of Entity Properties.
// doors
#define SF_DOOR_ROTATE_YAW 0 // yaw by default
#define SF_DOOR_START_OPEN_OBSOLETE 1
#define SF_DOOR_ROTATE_BACKWARDS 2
#define SF_DOOR_NONSOLID_TO_PLAYER 4
#define SF_DOOR_PASSABLE 8
#define SF_DOOR_ONEWAY 16
#define SF_DOOR_NO_AUTO_RETURN 32
#define SF_DOOR_ROTATE_ROLL 64
#define SF_DOOR_ROTATE_PITCH 128
#define SF_DOOR_PUSE 256 // door can be opened by player's use button.
#define SF_DOOR_NONPCS 512 // NPC can't open
#define SF_DOOR_PTOUCH 1024 // player touch opens
#define SF_DOOR_LOCKED 2048 // Door is initially locked
#define SF_DOOR_SILENT 4096 // Door plays no audible sound, and does not alert NPCs when opened
#define SF_DOOR_USE_CLOSES 8192 // Door can be +used to close before its autoreturn delay has expired.
#define SF_DOOR_SILENT_TO_NPCS 16384 // Does not alert NPC's when opened.
#define SF_DOOR_IGNORE_USE 32768 // Completely ignores player +use commands.
#define SF_DOOR_NEW_USE_RULES 65536 // For func_door entities, behave more like prop_door_rotating with respect to +USE (changelist 242482)
enum FuncDoorSpawnPos_t
{
FUNC_DOOR_SPAWN_CLOSED = 0,
FUNC_DOOR_SPAWN_OPEN,
};
class CBaseDoor : public CBaseToggle
{
public:
DECLARE_CLASS( CBaseDoor, CBaseToggle );
DECLARE_SERVERCLASS();
void Spawn( void );
void Precache( void );
bool CreateVPhysics();
bool KeyValue( const char *szKeyName, const char *szValue );
virtual void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
virtual void StartBlocked( CBaseEntity *pOther );
virtual void Blocked( CBaseEntity *pOther );
virtual void EndBlocked( void );
void Activate( void );
virtual int ObjectCaps( void )
{
int flags = BaseClass::ObjectCaps();
if ( HasSpawnFlags( SF_DOOR_PUSE ) )
return flags | FCAP_IMPULSE_USE | FCAP_USE_IN_RADIUS;
return flags;
};
DECLARE_DATADESC();
// This is ONLY used by the node graph to test movement through a door
void InputSetToggleState( inputdata_t &inputdata );
virtual void SetToggleState( int state );
virtual bool IsRotatingDoor() { return false; }
virtual bool ShouldSavePhysics();
// used to selectivly override defaults
void DoorTouch( CBaseEntity *pOther );
// local functions
int DoorActivate( );
void DoorGoUp( void );
void DoorGoDown( void );
void DoorHitTop( void );
void DoorHitBottom( void );
void UpdateAreaPortals( bool isOpen );
void Unlock( void );
void Lock( void );
int GetDoorMovementGroup( CBaseDoor *pDoorList[], int listMax );
// Input handlers
void InputClose( inputdata_t &inputdata );
void InputLock( inputdata_t &inputdata );
void InputOpen( inputdata_t &inputdata );
void InputToggle( inputdata_t &inputdata );
void InputUnlock( inputdata_t &inputdata );
void InputSetSpeed( inputdata_t &inputdata );
Vector m_vecMoveDir; // The direction of motion for linear moving doors.
locksound_t m_ls; // door lock sounds
byte m_bLockedSentence;
byte m_bUnlockedSentence;
bool m_bForceClosed; // If set, always close, even if we're blocked.
bool m_bDoorGroup;
bool m_bLocked; // Whether the door is locked
bool m_bIgnoreDebris;
bool m_bIgnoreNonPlayerEntsOnBlock; // Non-player entities should never block. This variable needs more letters.
FuncDoorSpawnPos_t m_eSpawnPosition;
float m_flBlockDamage; // Damage inflicted when blocked.
string_t m_NoiseMoving; //Start/Looping sound
string_t m_NoiseArrived; //End sound
string_t m_NoiseMovingClosed; //Start/Looping sound
string_t m_NoiseArrivedClosed; //End sound
string_t m_ChainTarget; ///< Entity name to pass Touch and Use events to
CNetworkVar( float, m_flWaveHeight );
// 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 StartMovingSound( void );
virtual void StopMovingSound( void );
void MovingSoundThink( void );
#ifdef HL1_DLL
bool PassesBlockTouchFilter(CBaseEntity *pOther);
string_t m_iBlockFilterName;
EHANDLE m_hBlockFilter;
#endif
bool ShouldLoopMoveSound( void ) { return m_bLoopMoveSound; }
bool m_bLoopMoveSound; // Move sound loops until stopped
private:
void ChainUse( void ); ///< Chains +use on through to m_ChainTarget
void ChainTouch( CBaseEntity *pOther ); ///< Chains touch on through to m_ChainTarget
void SetChaining( bool chaining ) { m_isChaining = chaining; } ///< Latch to prevent recursion
bool m_isChaining;
void CloseAreaPortalsThink( void ); ///< Delays turning off area portals when closing doors to prevent visual artifacts
};
#endif // DOORS_H

View File

@@ -0,0 +1,203 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Dynamic light.
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "dlight.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
#define NUM_DL_EXPONENT_BITS 8
#define MIN_DL_EXPONENT_VALUE -((1 << (NUM_DL_EXPONENT_BITS-1)) - 1)
#define MAX_DL_EXPONENT_VALUE ((1 << (NUM_DL_EXPONENT_BITS-1)) - 1)
class CDynamicLight : public CBaseEntity
{
public:
DECLARE_CLASS( CDynamicLight, CBaseEntity );
void Spawn( void );
void DynamicLightThink( void );
bool KeyValue( const char *szKeyName, const char *szValue );
DECLARE_SERVERCLASS();
DECLARE_DATADESC();
// Turn on and off the light
void InputTurnOn( inputdata_t &inputdata );
void InputTurnOff( inputdata_t &inputdata );
void InputToggle( inputdata_t &inputdata );
public:
unsigned char m_ActualFlags;
CNetworkVar( unsigned char, m_Flags );
CNetworkVar( unsigned char, m_LightStyle );
bool m_On;
CNetworkVar( float, m_Radius );
CNetworkVar( int, m_Exponent );
CNetworkVar( float, m_InnerAngle );
CNetworkVar( float, m_OuterAngle );
CNetworkVar( float, m_SpotRadius );
};
LINK_ENTITY_TO_CLASS(light_dynamic, CDynamicLight);
BEGIN_DATADESC( CDynamicLight )
DEFINE_FIELD( m_ActualFlags, FIELD_CHARACTER ),
DEFINE_FIELD( m_Flags, FIELD_CHARACTER ),
DEFINE_FIELD( m_On, FIELD_BOOLEAN ),
DEFINE_THINKFUNC( DynamicLightThink ),
// Inputs
DEFINE_INPUT( m_Radius, FIELD_FLOAT, "distance" ),
DEFINE_INPUT( m_Exponent, FIELD_INTEGER, "brightness" ),
DEFINE_INPUT( m_InnerAngle, FIELD_FLOAT, "_inner_cone" ),
DEFINE_INPUT( m_OuterAngle, FIELD_FLOAT, "_cone" ),
DEFINE_INPUT( m_SpotRadius, FIELD_FLOAT, "spotlight_radius" ),
DEFINE_INPUT( m_LightStyle, FIELD_CHARACTER,"style" ),
// Input functions
DEFINE_INPUTFUNC( FIELD_VOID, "TurnOn", InputTurnOn ),
DEFINE_INPUTFUNC( FIELD_VOID, "TurnOff", InputTurnOff ),
DEFINE_INPUTFUNC( FIELD_VOID, "Toggle", InputToggle ),
END_DATADESC()
IMPLEMENT_SERVERCLASS_ST(CDynamicLight, DT_DynamicLight)
SendPropInt( SENDINFO(m_Flags), 4, SPROP_UNSIGNED ),
SendPropInt( SENDINFO(m_LightStyle), 4, SPROP_UNSIGNED ),
SendPropFloat( SENDINFO(m_Radius), 0, SPROP_NOSCALE),
SendPropInt( SENDINFO(m_Exponent), NUM_DL_EXPONENT_BITS),
SendPropFloat( SENDINFO(m_InnerAngle), 8, 0, 0.0, 360.0f ),
SendPropFloat( SENDINFO(m_OuterAngle), 8, 0, 0.0, 360.0f ),
SendPropFloat( SENDINFO(m_SpotRadius), 0, SPROP_NOSCALE),
END_SEND_TABLE()
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
bool CDynamicLight::KeyValue( const char *szKeyName, const char *szValue )
{
if ( FStrEq( szKeyName, "_light" ) )
{
color32 tmp;
UTIL_StringToColor32( &tmp, szValue );
SetRenderColor( tmp.r, tmp.g, tmp.b );
}
else if ( FStrEq( szKeyName, "pitch" ) )
{
float angle = atof(szValue);
if ( angle )
{
QAngle angles = GetAbsAngles();
angles[PITCH] = -angle;
SetAbsAngles( angles );
}
}
else if ( FStrEq( szKeyName, "spawnflags" ) )
{
m_ActualFlags = m_Flags = atoi(szValue);
}
else
{
return BaseClass::KeyValue( szKeyName, szValue );
}
return true;
}
//------------------------------------------------------------------------------
// Turn on and off the light
//------------------------------------------------------------------------------
void CDynamicLight::InputTurnOn( inputdata_t &inputdata )
{
m_Flags = m_ActualFlags;
m_On = true;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : &inputdata -
//-----------------------------------------------------------------------------
void CDynamicLight::InputTurnOff( inputdata_t &inputdata )
{
// This basically shuts it off
m_Flags = DLIGHT_NO_MODEL_ILLUMINATION | DLIGHT_NO_WORLD_ILLUMINATION;
m_On = false;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : &inputdata -
//-----------------------------------------------------------------------------
void CDynamicLight::InputToggle( inputdata_t &inputdata )
{
if (m_On)
{
InputTurnOff( inputdata );
}
else
{
InputTurnOn( inputdata );
}
}
//------------------------------------------------------------------------------
// Purpose :
//------------------------------------------------------------------------------
void CDynamicLight::Spawn( void )
{
Precache();
SetSolid( SOLID_NONE );
m_On = true;
UTIL_SetSize( this, vec3_origin, vec3_origin );
AddEFlags( EFL_FORCE_CHECK_TRANSMIT );
// If we have a target, think so we can orient towards it
if ( m_target != NULL_STRING )
{
SetThink( &CDynamicLight::DynamicLightThink );
SetNextThink( gpGlobals->curtime + 0.1 );
}
int clampedExponent = clamp( (int) m_Exponent, MIN_DL_EXPONENT_VALUE, MAX_DL_EXPONENT_VALUE );
if ( m_Exponent != clampedExponent )
{
Warning( "light_dynamic at [%d %d %d] has invalid exponent value (%d must be between %d and %d).\n",
(int)GetAbsOrigin().x, (int)GetAbsOrigin().x, (int)GetAbsOrigin().x,
m_Exponent.Get(),
MIN_DL_EXPONENT_VALUE,
MAX_DL_EXPONENT_VALUE );
m_Exponent = clampedExponent;
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CDynamicLight::DynamicLightThink( void )
{
if ( m_target == NULL_STRING )
return;
CBaseEntity *pEntity = GetNextTarget();
if ( pEntity )
{
Vector vecToTarget = (pEntity->GetAbsOrigin() - GetAbsOrigin());
QAngle vecAngles;
VectorAngles( vecToTarget, vecAngles );
SetAbsAngles( vecAngles );
}
SetNextThink( gpGlobals->curtime + 0.1 );
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,68 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#ifndef EFFECTS_H
#define EFFECTS_H
#ifdef _WIN32
#pragma once
#endif
class CBaseEntity;
class Vector;
//-----------------------------------------------------------------------------
// The rotor wash shooter. It emits gibs when pushed by a rotor wash
//-----------------------------------------------------------------------------
abstract_class IRotorWashShooter
{
public:
virtual CBaseEntity *DoWashPush( float flWashStartTime, const Vector &vecForce ) = 0;
};
//-----------------------------------------------------------------------------
// Gets at the interface if the entity supports it
//-----------------------------------------------------------------------------
IRotorWashShooter *GetRotorWashShooter( CBaseEntity *pEntity );
class CEnvQuadraticBeam : public CPointEntity
{
DECLARE_CLASS( CEnvQuadraticBeam, CPointEntity );
public:
void Spawn();
void SetSpline( const Vector &control, const Vector &target )
{
m_targetPosition = target;
m_controlPosition = control;
}
void SetScrollRate( float rate )
{
m_scrollRate = rate;
}
void SetWidth( float width )
{
m_flWidth = width;
}
private:
CNetworkVector( m_targetPosition );
CNetworkVector( m_controlPosition );
CNetworkVar( float, m_scrollRate );
CNetworkVar( float, m_flWidth );
DECLARE_DATADESC();
DECLARE_SERVERCLASS();
};
CEnvQuadraticBeam *CreateQuadraticBeam( const char *pSpriteName, const Vector &start, const Vector &control, const Vector &end, float width, CBaseEntity *pOwner );
#endif // EFFECTS_H

View File

@@ -0,0 +1,147 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//
//===========================================================================//
#ifndef ENGINECALLBACK_H
#define ENGINECALLBACK_H
#define EIFACEV21
#ifndef EIFACE_H
#include "eiface.h"
#endif
#ifdef EIFACEV21
#include "eifacev21.h"
#endif
#ifdef EIFACEV21
class IVEngineServerV21; // this class from eifacev21.h
#endif
class IFileSystem; // include filesystem.h
class IEngineSound; // include engine/IEngineSound.h
class IVEngineServer;
class IVoiceServer;
class IStaticPropMgrServer;
class ISpatialPartition;
class IVModelInfo;
class IEngineTrace;
class IGameEventManager2;
class IVDebugOverlay;
class IDataCache;
class IMDLCache;
class IServerEngineTools;
class IXboxSystem;
class IScriptManager;
class CSteamAPIContext;
class CSteamGameServerAPIContext;
#ifdef EIFACEV21
extern IVEngineServerV21 *engineV21; // i hate this
#endif
extern IVEngineServer *engine;
extern IVoiceServer *g_pVoiceServer;
extern IFileSystem *filesystem;
extern IStaticPropMgrServer *staticpropmgr;
extern ISpatialPartition *partition;
extern IEngineSound *enginesound;
extern IVModelInfo *modelinfo;
extern IEngineTrace *enginetrace;
extern IGameEventManager2 *gameeventmanager;
extern IVDebugOverlay *debugoverlay;
extern IDataCache *datacache;
extern IMDLCache *mdlcache;
extern IServerEngineTools *serverenginetools;
extern IXboxSystem *xboxsystem; // 360 only
extern IScriptManager *scriptmanager;
extern CSteamAPIContext *steamapicontext; // available on game clients
extern CSteamGameServerAPIContext *steamgameserverapicontext; //available on game servers
//-----------------------------------------------------------------------------
// Precaches a material
//-----------------------------------------------------------------------------
void PrecacheMaterial( const char *pMaterialName );
//-----------------------------------------------------------------------------
// Converts a previously precached material into an index
//-----------------------------------------------------------------------------
int GetMaterialIndex( const char *pMaterialName );
//-----------------------------------------------------------------------------
// Converts a previously precached material index into a string
//-----------------------------------------------------------------------------
const char *GetMaterialNameFromIndex( int nMaterialIndex );
//-----------------------------------------------------------------------------
// Precache-related methods for particle systems
//-----------------------------------------------------------------------------
void PrecacheParticleSystem( const char *pParticleSystemName );
int GetParticleSystemIndex( const char *pParticleSystemName );
const char *GetParticleSystemNameFromIndex( int nIndex );
class IRecipientFilter;
void EntityMessageBegin( CBaseEntity * entity, bool reliable = false );
void UserMessageBegin( IRecipientFilter& filter, const char *messagename );
void MessageEnd( void );
// bytewise
void MessageWriteByte( int iValue);
void MessageWriteChar( int iValue);
void MessageWriteShort( int iValue);
void MessageWriteWord( int iValue );
void MessageWriteLong( int iValue);
void MessageWriteFloat( float flValue);
void MessageWriteAngle( float flValue);
void MessageWriteCoord( float flValue);
void MessageWriteVec3Coord( const Vector& rgflValue);
void MessageWriteVec3Normal( const Vector& rgflValue);
void MessageWriteAngles( const QAngle& rgflValue);
void MessageWriteString( const char *sz );
void MessageWriteEntity( int iValue);
void MessageWriteEHandle( CBaseEntity *pEntity ); //encoded as a long
// bitwise
void MessageWriteBool( bool bValue );
void MessageWriteUBitLong( unsigned int data, int numbits );
void MessageWriteSBitLong( int data, int numbits );
void MessageWriteBits( const void *pIn, int nBits );
#ifndef NO_STEAM
/// Returns Steam ID, given player index. Returns an invalid SteamID upon
/// failure
extern CSteamID GetSteamIDForPlayerIndex( int iPlayerIndex );
#endif
// Bytewise
#define WRITE_BYTE (MessageWriteByte)
#define WRITE_CHAR (MessageWriteChar)
#define WRITE_SHORT (MessageWriteShort)
#define WRITE_WORD (MessageWriteWord)
#define WRITE_LONG (MessageWriteLong)
#define WRITE_FLOAT (MessageWriteFloat)
#define WRITE_ANGLE (MessageWriteAngle)
#define WRITE_COORD (MessageWriteCoord)
#define WRITE_VEC3COORD (MessageWriteVec3Coord)
#define WRITE_VEC3NORMAL (MessageWriteVec3Normal)
#define WRITE_ANGLES (MessageWriteAngles)
#define WRITE_STRING (MessageWriteString)
#define WRITE_ENTITY (MessageWriteEntity)
#define WRITE_EHANDLE (MessageWriteEHandle)
// Bitwise
#define WRITE_BOOL (MessageWriteBool)
#define WRITE_UBITLONG (MessageWriteUBitLong)
#define WRITE_SBITLONG (MessageWriteSBitLong)
#define WRITE_BITS (MessageWriteBits)
#endif //ENGINECALLBACK_H

View File

@@ -0,0 +1,458 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================
#include "cbase.h"
#include "const.h"
#include "toolframework/itoolentity.h"
#include "entitylist.h"
#include "toolframework/itoolsystem.h"
#include "KeyValues.h"
#include "icliententity.h"
#include "iserverentity.h"
#include "sceneentity.h"
#include "particles/particles.h"
//-----------------------------------------------------------------------------
// Interface from engine to tools for manipulating entities
//-----------------------------------------------------------------------------
class CServerTools : public IServerTools
{
public:
// Inherited from IServerTools
virtual IServerEntity *GetIServerEntity( IClientEntity *pClientEntity );
virtual bool GetPlayerPosition( Vector &org, QAngle &ang, IClientEntity *pClientPlayer = NULL );
virtual bool SnapPlayerToPosition( const Vector &org, const QAngle &ang, IClientEntity *pClientPlayer = NULL );
virtual int GetPlayerFOV( IClientEntity *pClientPlayer = NULL );
virtual bool SetPlayerFOV( int fov, IClientEntity *pClientPlayer = NULL );
virtual bool IsInNoClipMode( IClientEntity *pClientPlayer = NULL );
virtual CBaseEntity *FirstEntity( void );
virtual CBaseEntity *NextEntity( CBaseEntity *pEntity );
virtual CBaseEntity *FindEntityByHammerID( int iHammerID );
virtual bool GetKeyValue( CBaseEntity *pEntity, const char *szField, char *szValue, int iMaxLen );
virtual bool SetKeyValue( CBaseEntity *pEntity, const char *szField, const char *szValue );
virtual bool SetKeyValue( CBaseEntity *pEntity, const char *szField, float flValue );
virtual bool SetKeyValue( CBaseEntity *pEntity, const char *szField, const Vector &vecValue );
virtual CBaseEntity *CreateEntityByName( const char *szClassName );
virtual void DispatchSpawn( CBaseEntity *pEntity );
virtual void ReloadParticleDefintions( const char *pFileName, const void *pBufData, int nLen );
virtual void AddOriginToPVS( const Vector &org );
virtual void MoveEngineViewTo( const Vector &vPos, const QAngle &vAngles );
virtual bool DestroyEntityByHammerId( int iHammerID );
virtual CBaseEntity *GetBaseEntityByEntIndex( int iEntIndex );
virtual void RemoveEntity( CBaseEntity *pEntity );
virtual void RemoveEntityImmediate( CBaseEntity *pEntity );
virtual IEntityFactoryDictionary *GetEntityFactoryDictionary( void );
virtual void SetMoveType( CBaseEntity *pEntity, int val );
virtual void SetMoveType( CBaseEntity *pEntity, int val, int moveCollide );
virtual void ResetSequence( CBaseAnimating *pEntity, int nSequence );
virtual void ResetSequenceInfo( CBaseAnimating *pEntity );
virtual void ClearMultiDamage( void );
virtual void ApplyMultiDamage( void );
virtual void AddMultiDamage( const CTakeDamageInfo &pTakeDamageInfo, CBaseEntity *pEntity );
virtual void RadiusDamage( const CTakeDamageInfo &info, const Vector &vecSrc, float flRadius, int iClassIgnore, CBaseEntity *pEntityIgnore );
virtual ITempEntsSystem *GetTempEntsSystem( void );
};
//-----------------------------------------------------------------------------
// Singleton
//-----------------------------------------------------------------------------
static CServerTools g_ServerTools;
// VSERVERTOOLS_INTERFACE_VERSION_1 is compatible with the latest since we're only adding things to the end, so expose that as well.
EXPOSE_SINGLE_INTERFACE_GLOBALVAR( CServerTools, IServerTools001, VSERVERTOOLS_INTERFACE_VERSION_1, g_ServerTools );
EXPOSE_SINGLE_INTERFACE_GLOBALVAR( CServerTools, IServerTools, VSERVERTOOLS_INTERFACE_VERSION, g_ServerTools );
// When bumping the version to this interface, check that our assumption is still valid and expose the older version in the same way
COMPILE_TIME_ASSERT( VSERVERTOOLS_INTERFACE_VERSION_INT == 2 );
IServerEntity *CServerTools::GetIServerEntity( IClientEntity *pClientEntity )
{
if ( pClientEntity == NULL )
return NULL;
CBaseHandle ehandle = pClientEntity->GetRefEHandle();
if ( ehandle.GetEntryIndex() >= MAX_EDICTS )
return NULL; // the first MAX_EDICTS entities are networked, the rest are client or server only
#if 0
// this fails, since the server entities have extra bits in their serial numbers,
// since 20 bits are reserved for serial numbers, except for networked entities, which are restricted to 10
// Brian believes that everything should just restrict itself to 10 to make things simpler,
// so if/when he changes NUM_SERIAL_NUM_BITS to 10, we can switch back to this simpler code
IServerNetworkable *pNet = gEntList.GetServerNetworkable( ehandle );
if ( pNet == NULL )
return NULL;
CBaseEntity *pServerEnt = pNet->GetBaseEntity();
return pServerEnt;
#else
IHandleEntity *pEnt = gEntList.LookupEntityByNetworkIndex( ehandle.GetEntryIndex() );
if ( pEnt == NULL )
return NULL;
CBaseHandle h = gEntList.GetNetworkableHandle( ehandle.GetEntryIndex() );
const int mask = ( 1 << NUM_NETWORKED_EHANDLE_SERIAL_NUMBER_BITS ) - 1;
if ( !h.IsValid() || ( ( h.GetSerialNumber() & mask ) != ( ehandle.GetSerialNumber() & mask ) ) )
return NULL;
IServerUnknown *pUnk = static_cast< IServerUnknown* >( pEnt );
return pUnk->GetBaseEntity();
#endif
}
bool CServerTools::GetPlayerPosition( Vector &org, QAngle &ang, IClientEntity *pClientPlayer )
{
IServerEntity *pServerPlayer = GetIServerEntity( pClientPlayer );
CBasePlayer *pPlayer = pServerPlayer ? ( CBasePlayer* )pServerPlayer : UTIL_GetLocalPlayer();
if ( pPlayer == NULL )
return false;
org = pPlayer->EyePosition();
ang = pPlayer->EyeAngles();
return true;
}
bool CServerTools::SnapPlayerToPosition( const Vector &org, const QAngle &ang, IClientEntity *pClientPlayer )
{
IServerEntity *pServerPlayer = GetIServerEntity( pClientPlayer );
CBasePlayer *pPlayer = pServerPlayer ? ( CBasePlayer* )pServerPlayer : UTIL_GetLocalPlayer();
if ( pPlayer == NULL )
return false;
pPlayer->SetAbsOrigin( org - pPlayer->GetViewOffset() );
pPlayer->SnapEyeAngles( ang );
// Disengage from hierarchy
pPlayer->SetParent( NULL );
return true;
}
int CServerTools::GetPlayerFOV( IClientEntity *pClientPlayer )
{
IServerEntity *pServerPlayer = GetIServerEntity( pClientPlayer );
CBasePlayer *pPlayer = pServerPlayer ? ( CBasePlayer* )pServerPlayer : UTIL_GetLocalPlayer();
if ( pPlayer == NULL )
return 0;
return pPlayer->GetFOV();
}
bool CServerTools::SetPlayerFOV( int fov, IClientEntity *pClientPlayer )
{
IServerEntity *pServerPlayer = GetIServerEntity( pClientPlayer );
CBasePlayer *pPlayer = pServerPlayer ? ( CBasePlayer* )pServerPlayer : UTIL_GetLocalPlayer();
if ( pPlayer == NULL )
return false;
pPlayer->SetDefaultFOV( fov );
CBaseEntity *pFOVOwner = pPlayer->GetFOVOwner();
return pPlayer->SetFOV( pFOVOwner ? pFOVOwner : pPlayer, fov );
}
bool CServerTools::IsInNoClipMode( IClientEntity *pClientPlayer )
{
IServerEntity *pServerPlayer = GetIServerEntity( pClientPlayer );
CBasePlayer *pPlayer = pServerPlayer ? ( CBasePlayer* )pServerPlayer : UTIL_GetLocalPlayer();
if ( pPlayer == NULL )
return true;
return pPlayer->GetMoveType() == MOVETYPE_NOCLIP;
}
CBaseEntity *CServerTools::FirstEntity( void )
{
return gEntList.FirstEnt();
}
CBaseEntity *CServerTools::NextEntity( CBaseEntity *pEntity )
{
CBaseEntity *pEnt;
if ( pEntity == NULL )
{
pEnt = gEntList.FirstEnt();
}
else
{
pEnt = gEntList.NextEnt( (CBaseEntity *)pEntity );
}
return pEnt;
}
CBaseEntity *CServerTools::FindEntityByHammerID( int iHammerID )
{
CBaseEntity *pEntity = gEntList.FirstEnt();
while (pEntity)
{
if (pEntity->m_iHammerID == iHammerID)
return pEntity;
pEntity = gEntList.NextEnt( pEntity );
}
return NULL;
}
bool CServerTools::GetKeyValue( CBaseEntity *pEntity, const char *szField, char *szValue, int iMaxLen )
{
return pEntity->GetKeyValue( szField, szValue, iMaxLen );
}
bool CServerTools::SetKeyValue( CBaseEntity *pEntity, const char *szField, const char *szValue )
{
return pEntity->KeyValue( szField, szValue );
}
bool CServerTools::SetKeyValue( CBaseEntity *pEntity, const char *szField, float flValue )
{
return pEntity->KeyValue( szField, flValue );
}
bool CServerTools::SetKeyValue( CBaseEntity *pEntity, const char *szField, const Vector &vecValue )
{
return pEntity->KeyValue( szField, vecValue );
}
//-----------------------------------------------------------------------------
// entity spawning
//-----------------------------------------------------------------------------
CBaseEntity *CServerTools::CreateEntityByName( const char *szClassName )
{
return ::CreateEntityByName( szClassName );
}
void CServerTools::DispatchSpawn( CBaseEntity *pEntity )
{
::DispatchSpawn( pEntity );
}
//-----------------------------------------------------------------------------
// Reload particle definitions
//-----------------------------------------------------------------------------
void CServerTools::ReloadParticleDefintions( const char *pFileName, const void *pBufData, int nLen )
{
// FIXME: Use file name to determine if we care about this data
CUtlBuffer buf( pBufData, nLen, CUtlBuffer::READ_ONLY );
g_pParticleSystemMgr->ReadParticleConfigFile( buf, true );
}
void CServerTools::AddOriginToPVS( const Vector &org )
{
engine->AddOriginToPVS( org );
}
void CServerTools::MoveEngineViewTo( const Vector &vPos, const QAngle &vAngles )
{
CBasePlayer *pPlayer = UTIL_GetListenServerHost();
if ( !pPlayer )
return;
extern void EnableNoClip( CBasePlayer *pPlayer );
EnableNoClip( pPlayer );
Vector zOffset = pPlayer->EyePosition() - pPlayer->GetAbsOrigin();
pPlayer->SetAbsOrigin( vPos - zOffset );
pPlayer->SnapEyeAngles( vAngles );
}
bool CServerTools::DestroyEntityByHammerId( int iHammerID )
{
CBaseEntity *pEntity = (CBaseEntity*)FindEntityByHammerID( iHammerID );
if ( !pEntity )
return false;
UTIL_Remove( pEntity );
return true;
}
void CServerTools::RemoveEntity( CBaseEntity *pEntity )
{
UTIL_Remove( pEntity );
}
void CServerTools::RemoveEntityImmediate( CBaseEntity *pEntity )
{
UTIL_RemoveImmediate( pEntity );
}
CBaseEntity *CServerTools::GetBaseEntityByEntIndex( int iEntIndex )
{
edict_t *pEdict = INDEXENT( iEntIndex );
if ( pEdict )
return CBaseEntity::Instance( pEdict );
else
return NULL;
}
IEntityFactoryDictionary *CServerTools::GetEntityFactoryDictionary( void )
{
return ::EntityFactoryDictionary();
}
void CServerTools::SetMoveType( CBaseEntity *pEntity, int val )
{
pEntity->SetMoveType( (MoveType_t)val );
}
void CServerTools::SetMoveType( CBaseEntity *pEntity, int val, int moveCollide )
{
pEntity->SetMoveType( (MoveType_t)val, (MoveCollide_t)moveCollide );
}
void CServerTools::ResetSequence( CBaseAnimating *pEntity, int nSequence )
{
pEntity->ResetSequence( nSequence );
}
void CServerTools::ResetSequenceInfo( CBaseAnimating *pEntity )
{
pEntity->ResetSequenceInfo();
}
void CServerTools::ClearMultiDamage( void )
{
::ClearMultiDamage();
}
void CServerTools::ApplyMultiDamage( void )
{
::ApplyMultiDamage();
}
void CServerTools::AddMultiDamage( const CTakeDamageInfo &pTakeDamageInfo, CBaseEntity *pEntity )
{
::AddMultiDamage( pTakeDamageInfo, pEntity );
}
void CServerTools::RadiusDamage( const CTakeDamageInfo &info, const Vector &vecSrc, float flRadius, int iClassIgnore, CBaseEntity *pEntityIgnore )
{
::RadiusDamage( info, vecSrc, flRadius, iClassIgnore, pEntityIgnore );
}
ITempEntsSystem *CServerTools::GetTempEntsSystem( void )
{
return (ITempEntsSystem *)te;
}
// Interface from engine to tools for manipulating entities
class CServerChoreoTools : public IServerChoreoTools
{
public:
// Iterates through ALL entities (separate list for client vs. server)
virtual EntitySearchResult NextChoreoEntity( EntitySearchResult currentEnt )
{
CBaseEntity *ent = reinterpret_cast< CBaseEntity* >( currentEnt );
ent = gEntList.FindEntityByClassname( ent, "logic_choreographed_scene" );
return reinterpret_cast< EntitySearchResult >( ent );
}
virtual const char *GetSceneFile( EntitySearchResult sr )
{
CBaseEntity *ent = reinterpret_cast< CBaseEntity* >( sr );
if ( !sr )
return "";
if ( Q_stricmp( ent->GetClassname(), "logic_choreographed_scene" ) )
return "";
return GetSceneFilename( ent );
}
// For interactive editing
virtual int GetEntIndex( EntitySearchResult sr )
{
CBaseEntity *ent = reinterpret_cast< CBaseEntity* >( sr );
if ( !ent )
return -1;
return ent->entindex();
}
virtual void ReloadSceneFromDisk( int entindex )
{
CBaseEntity *ent = CBaseEntity::Instance( entindex );
if ( !ent )
return;
::ReloadSceneFromDisk( ent );
}
};
static CServerChoreoTools g_ServerChoreoTools;
EXPOSE_SINGLE_INTERFACE_GLOBALVAR( CServerChoreoTools, IServerChoreoTools, VSERVERCHOREOTOOLS_INTERFACE_VERSION, g_ServerChoreoTools );
//------------------------------------------------------------------------------
// Applies keyvalues to the entity by hammer ID.
//------------------------------------------------------------------------------
void CC_Ent_Keyvalue( const CCommand &args )
{
// Must have an odd number of arguments.
if ( ( args.ArgC() < 4 ) || ( args.ArgC() & 1 ) )
{
Msg( "Format: ent_keyvalue <entity id> \"key1\" \"value1\" \"key2\" \"value2\" ... \"keyN\" \"valueN\"\n" );
return;
}
CBasePlayer *pPlayer = ToBasePlayer( UTIL_GetCommandClient() );
CBaseEntity *pEnt;
if ( FStrEq( args[1], "" ) || FStrEq( args[1], "!picker" ) )
{
if (!pPlayer)
return;
extern CBaseEntity *FindPickerEntity( CBasePlayer *pPlayer );
pEnt = FindPickerEntity( pPlayer );
if ( !pEnt )
{
ClientPrint( pPlayer, HUD_PRINTCONSOLE, "No entity in front of player.\n" );
return;
}
}
else if ( FStrEq( args[1], "!self" ) || FStrEq( args[1], "!caller" ) || FStrEq( args[1], "!activator" ) )
{
if (!pPlayer)
return;
pEnt = pPlayer;
}
else
{
int nID = atoi( args[1] );
pEnt = g_ServerTools.FindEntityByHammerID( nID );
if ( !pEnt )
{
Msg( "Entity ID %d not found.\n", nID );
return;
}
}
int nArg = 2;
while ( nArg < args.ArgC() )
{
const char *pszKey = args[ nArg ];
const char *pszValue = args[ nArg + 1 ];
nArg += 2;
g_ServerTools.SetKeyValue( pEnt, pszKey, pszValue );
}
}
static ConCommand ent_keyvalue("ent_keyvalue", CC_Ent_Keyvalue, "Applies the comma delimited key=value pairs to the entity with the given Hammer ID.\n\tFormat: ent_keyvalue <entity id> <key1> <value1> <key2> <value2> ... <keyN> <valueN>\n", FCVAR_CHEAT);

View File

@@ -0,0 +1,33 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//
//=============================================================================//
#ifndef ENTITYAPI_H
#define ENTITYAPI_H
class SendTable;
extern void LoadMapEntities( const char *pMapEntities );
extern void DispatchObjectCollisionBox( edict_t *pent );
extern float DispatchObjectPhysicsVelocity( edict_t *pent, float moveTime );
extern ServerClass* DispatchGetObjectServerClass(edict_t *pent);
extern ServerClass* GetAllServerClasses();
extern void SaveWriteFields( CSaveRestoreData *pSaveData, const char *pname, void *pBaseData, datamap_t *pMap, typedescription_t *pFields, int fieldCount );
extern void SaveReadFields( CSaveRestoreData *pSaveData, const char *pname, void *pBaseData, datamap_t *pMap, typedescription_t *pFields, int fieldCount );
extern void SaveGlobalState( CSaveRestoreData *pSaveData );
extern void RestoreGlobalState( CSaveRestoreData *pSaveData );
extern void ResetGlobalState( void );
extern CSaveRestoreData *SaveInit( int size );
extern int CreateEntityTransitionList( CSaveRestoreData *pSaveData, int levelMask );
extern void ClearEntities( void );
extern void FreeContainingEntity( edict_t *ed );
class ISaveRestoreBlockHandler;
ISaveRestoreBlockHandler *GetEntitySaveRestoreBlockHandler();
#endif // ENTITYAPI_H

View File

@@ -0,0 +1,76 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#include "cbase.h"
#include "entityblocker.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
LINK_ENTITY_TO_CLASS( entity_blocker, CEntityBlocker );
//-----------------------------------------------------------------------------
// Purpose:
// Input : &origin -
// &mins -
// &maxs -
// NULL -
// Output : CEntityBlocker
//-----------------------------------------------------------------------------
CEntityBlocker *CEntityBlocker::Create( const Vector &origin, const Vector &mins, const Vector &maxs, CBaseEntity *pOwner, bool bBlockPhysics )
{
CEntityBlocker *pBlocker = (CEntityBlocker *) CBaseEntity::Create( "entity_blocker", origin, vec3_angle, pOwner );
if ( pBlocker != NULL )
{
pBlocker->SetSize( mins, maxs );
if ( bBlockPhysics )
{
pBlocker->VPhysicsInitStatic();
}
}
return pBlocker;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CEntityBlocker::Spawn( void )
{
SetSolid( SOLID_BBOX );
AddSolidFlags( FSOLID_CUSTOMRAYTEST );
}
//-----------------------------------------------------------------------------
// Purpose: Entity blockers don't block tracelines so they don't screw up weapon fire, etc
//-----------------------------------------------------------------------------
bool CEntityBlocker::TestCollision( const Ray_t &ray, unsigned int mask, trace_t& trace )
{
return false;
}
//------------------------------------------------------------------------------
// Purpose :
// Input :
// Output :
//------------------------------------------------------------------------------
void CC_Test_Entity_Blocker( void )
{
CBasePlayer *pPlayer = UTIL_GetCommandClient();
Vector vecForward;
pPlayer->GetVectors( &vecForward, NULL, NULL );
trace_t tr;
Vector vecOrigin = pPlayer->GetAbsOrigin() + (vecForward * 256);
UTIL_TraceHull( vecOrigin + Vector(0,0,256), vecOrigin - Vector(0,0,256), VEC_HULL_MIN_SCALED( pPlayer ), VEC_HULL_MAX_SCALED( pPlayer ), MASK_SOLID, pPlayer, COLLISION_GROUP_NONE, &tr );
if ( !tr.allsolid && !tr.startsolid )
{
CEntityBlocker::Create( tr.endpos, VEC_HULL_MIN_SCALED( pPlayer ), VEC_HULL_MAX_SCALED( pPlayer ), NULL, true );
NDebugOverlay::Box( tr.endpos, VEC_HULL_MIN_SCALED( pPlayer ), VEC_HULL_MAX_SCALED( pPlayer ), 0, 255, 0, 64, 1000.0 );
}
}
static ConCommand test_entity_blocker("test_entity_blocker", CC_Test_Entity_Blocker, "Test command that drops an entity blocker out in front of the player.", FCVAR_CHEAT );

View File

@@ -0,0 +1,28 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#ifndef ENTITYBLOCKER_H
#define ENTITYBLOCKER_H
#ifdef _WIN32
#pragma once
#endif
//==================================================================================================================
// Entity Blocker
//==================================================================================================================
class CEntityBlocker : public CBaseEntity
{
DECLARE_CLASS( CEntityBlocker, CBaseEntity );
public:
static CEntityBlocker *Create( const Vector &origin, const Vector &mins, const Vector &maxs, CBaseEntity *pOwner = NULL, bool bBlockPhysics = false );
void Spawn( void );
bool TestCollision( const Ray_t &ray, unsigned int mask, trace_t& trace );
};
#endif // ENTITYBLOCKER_H

View File

@@ -0,0 +1,50 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//
//=============================================================================//
#ifndef INPUTVAR_H
#define INPUTVAR_H
#ifdef _WIN32
#pragma once
#endif
#include "baseentity.h"
#include "entitylist.h"
//-----------------------------------------------------------------------------
// Purpose: Used to request a value, or a set of values, from a set of entities.
// used when a multi-input variable needs to refresh it's inputs
//-----------------------------------------------------------------------------
class CMultiInputVar
{
public:
CMultiInputVar() : m_InputList(NULL) {}
~CMultiInputVar();
struct inputitem_t
{
variant_t value; // local copy of variable (maybe make this a variant?)
int outputID; // the ID number of the output that sent this
inputitem_t *next;
// allocate and free from MPool memory
static void *operator new( size_t stAllocBlock );
static void *operator new( size_t stAllocateBlock, int nBlockUse, const char *pFileName, int nLine );
static void operator delete( void *pMem );
static void operator delete( void *pMem, int nBlockUse, const char *pFileName, int nLine ) { operator delete(pMem); }
};
inputitem_t *m_InputList; // list of data
int m_bUpdatedThisFrame;
void AddValue( variant_t newVal, int outputID );
DECLARE_SIMPLE_DATADESC();
};
#endif // INPUTVAR_H

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,382 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//
//=============================================================================//
#ifndef ENTITYLIST_H
#define ENTITYLIST_H
#ifdef _WIN32
#pragma once
#endif
#include "baseentity.h"
class IEntityListener;
abstract_class CBaseEntityClassList
{
public:
CBaseEntityClassList();
~CBaseEntityClassList();
virtual void LevelShutdownPostEntity() = 0;
CBaseEntityClassList *m_pNextClassList;
};
template< class T >
class CEntityClassList : public CBaseEntityClassList
{
public:
virtual void LevelShutdownPostEntity() { m_pClassList = NULL; }
void Insert( T *pEntity )
{
pEntity->m_pNext = m_pClassList;
m_pClassList = pEntity;
}
void Remove( T *pEntity )
{
T **pPrev = &m_pClassList;
T *pCur = *pPrev;
while ( pCur )
{
if ( pCur == pEntity )
{
*pPrev = pCur->m_pNext;
return;
}
pPrev = &pCur->m_pNext;
pCur = *pPrev;
}
}
static T *m_pClassList;
};
// Derive a class from this if you want to filter entity list searches
abstract_class IEntityFindFilter
{
public:
virtual bool ShouldFindEntity( CBaseEntity *pEntity ) = 0;
virtual CBaseEntity *GetFilterResult( void ) = 0;
};
#ifdef MAPBASE
// Returns false every time. Created for some sick hack involving FindEntityProcedural looking at FindNamedEntity.
class CNullEntityFilter : public IEntityFindFilter
{
public:
virtual bool ShouldFindEntity( CBaseEntity *pEntity ) { return false; }
virtual CBaseEntity *GetFilterResult( void ) { return NULL; }
};
#endif
//-----------------------------------------------------------------------------
// Purpose: a global list of all the entities in the game. All iteration through
// entities is done through this object.
//-----------------------------------------------------------------------------
class CGlobalEntityList : public CBaseEntityList
{
public:
private:
int m_iHighestEnt; // the topmost used array index
int m_iNumEnts;
int m_iNumEdicts;
bool m_bClearingEntities;
CUtlVector<IEntityListener *> m_entityListeners;
public:
IServerNetworkable* GetServerNetworkable( CBaseHandle hEnt ) const;
CBaseNetworkable* GetBaseNetworkable( CBaseHandle hEnt ) const;
CBaseEntity* GetBaseEntity( CBaseHandle hEnt ) const;
edict_t* GetEdict( CBaseHandle hEnt ) const;
int NumberOfEntities( void );
int NumberOfEdicts( void );
// mark an entity as deleted
void AddToDeleteList( IServerNetworkable *ent );
// call this before and after each frame to delete all of the marked entities.
void CleanupDeleteList( void );
int ResetDeleteList( void );
// frees all entities in the game
void Clear( void );
// Returns true while in the Clear() call.
bool IsClearingEntities() {return m_bClearingEntities;}
// add a class that gets notified of entity events
void AddListenerEntity( IEntityListener *pListener );
void RemoveListenerEntity( IEntityListener *pListener );
void ReportEntityFlagsChanged( CBaseEntity *pEntity, unsigned int flagsOld, unsigned int flagsNow );
// entity is about to be removed, notify the listeners
void NotifyCreateEntity( CBaseEntity *pEnt );
void NotifySpawn( CBaseEntity *pEnt );
void NotifyRemoveEntity( CBaseHandle hEnt );
// iteration functions
// returns the next entity after pCurrentEnt; if pCurrentEnt is NULL, return the first entity
CBaseEntity *NextEnt( CBaseEntity *pCurrentEnt );
CBaseEntity *FirstEnt() { return NextEnt(NULL); }
// returns the next entity of the specified class, using RTTI
template< class T >
T *NextEntByClass( T *start )
{
for ( CBaseEntity *x = NextEnt( start ); x; x = NextEnt( x ) )
{
start = dynamic_cast<T*>( x );
if ( start )
return start;
}
return NULL;
}
// search functions
bool IsEntityPtr( void *pTest );
#ifdef MAPBASE
CBaseEntity *FindEntityByClassname( CBaseEntity *pStartEntity, const char *szName, IEntityFindFilter *pFilter = NULL );
#else
CBaseEntity *FindEntityByClassname( CBaseEntity *pStartEntity, const char *szName );
#endif
CBaseEntity *FindEntityByName( CBaseEntity *pStartEntity, const char *szName, CBaseEntity *pSearchingEntity = NULL, CBaseEntity *pActivator = NULL, CBaseEntity *pCaller = NULL, IEntityFindFilter *pFilter = NULL );
CBaseEntity *FindEntityByName( CBaseEntity *pStartEntity, string_t iszName, CBaseEntity *pSearchingEntity = NULL, CBaseEntity *pActivator = NULL, CBaseEntity *pCaller = NULL, IEntityFindFilter *pFilter = NULL )
{
return FindEntityByName( pStartEntity, STRING(iszName), pSearchingEntity, pActivator, pCaller, pFilter );
}
CBaseEntity *FindEntityInSphere( CBaseEntity *pStartEntity, const Vector &vecCenter, float flRadius );
CBaseEntity *FindEntityByTarget( CBaseEntity *pStartEntity, const char *szName );
CBaseEntity *FindEntityByModel( CBaseEntity *pStartEntity, const char *szModelName );
CBaseEntity *FindEntityByNameNearest( const char *szName, const Vector &vecSrc, float flRadius, CBaseEntity *pSearchingEntity = NULL, CBaseEntity *pActivator = NULL, CBaseEntity *pCaller = NULL );
CBaseEntity *FindEntityByNameWithin( CBaseEntity *pStartEntity, const char *szName, const Vector &vecSrc, float flRadius, CBaseEntity *pSearchingEntity = NULL, CBaseEntity *pActivator = NULL, CBaseEntity *pCaller = NULL );
CBaseEntity *FindEntityByClassnameNearest( const char *szName, const Vector &vecSrc, float flRadius );
CBaseEntity *FindEntityByClassnameWithin( CBaseEntity *pStartEntity , const char *szName, const Vector &vecSrc, float flRadius );
CBaseEntity *FindEntityByClassnameWithin( CBaseEntity *pStartEntity , const char *szName, const Vector &vecMins, const Vector &vecMaxs );
#ifdef MAPBASE
CBaseEntity *FindEntityGeneric( CBaseEntity *pStartEntity, const char *szName, CBaseEntity *pSearchingEntity = NULL, CBaseEntity *pActivator = NULL, CBaseEntity *pCaller = NULL, IEntityFindFilter *pFilter = NULL );
#else
CBaseEntity *FindEntityGeneric( CBaseEntity *pStartEntity, const char *szName, CBaseEntity *pSearchingEntity = NULL, CBaseEntity *pActivator = NULL, CBaseEntity *pCaller = NULL );
#endif
CBaseEntity *FindEntityGenericWithin( CBaseEntity *pStartEntity, const char *szName, const Vector &vecSrc, float flRadius, CBaseEntity *pSearchingEntity = NULL, CBaseEntity *pActivator = NULL, CBaseEntity *pCaller = NULL );
CBaseEntity *FindEntityGenericNearest( const char *szName, const Vector &vecSrc, float flRadius, CBaseEntity *pSearchingEntity = NULL, CBaseEntity *pActivator = NULL, CBaseEntity *pCaller = NULL );
CBaseEntity *FindEntityNearestFacing( const Vector &origin, const Vector &facing, float threshold);
CBaseEntity *FindEntityClassNearestFacing( const Vector &origin, const Vector &facing, float threshold, char *classname);
CBaseEntity *FindEntityByNetname( CBaseEntity *pStartEntity, const char *szModelName );
CBaseEntity *FindEntityProcedural( const char *szName, CBaseEntity *pSearchingEntity = NULL, CBaseEntity *pActivator = NULL, CBaseEntity *pCaller = NULL );
CGlobalEntityList();
// CBaseEntityList overrides.
protected:
virtual void OnAddEntity( IHandleEntity *pEnt, CBaseHandle handle );
virtual void OnRemoveEntity( IHandleEntity *pEnt, CBaseHandle handle );
};
extern CGlobalEntityList gEntList;
//-----------------------------------------------------------------------------
// Inlines.
//-----------------------------------------------------------------------------
inline edict_t* CGlobalEntityList::GetEdict( CBaseHandle hEnt ) const
{
IServerUnknown *pUnk = static_cast<IServerUnknown*>(LookupEntity( hEnt ));
if ( pUnk )
return pUnk->GetNetworkable()->GetEdict();
else
return NULL;
}
inline CBaseNetworkable* CGlobalEntityList::GetBaseNetworkable( CBaseHandle hEnt ) const
{
IServerUnknown *pUnk = static_cast<IServerUnknown*>(LookupEntity( hEnt ));
if ( pUnk )
return pUnk->GetNetworkable()->GetBaseNetworkable();
else
return NULL;
}
inline IServerNetworkable* CGlobalEntityList::GetServerNetworkable( CBaseHandle hEnt ) const
{
IServerUnknown *pUnk = static_cast<IServerUnknown*>(LookupEntity( hEnt ));
if ( pUnk )
return pUnk->GetNetworkable();
else
return NULL;
}
inline CBaseEntity* CGlobalEntityList::GetBaseEntity( CBaseHandle hEnt ) const
{
IServerUnknown *pUnk = static_cast<IServerUnknown*>(LookupEntity( hEnt ));
if ( pUnk )
return pUnk->GetBaseEntity();
else
return NULL;
}
//-----------------------------------------------------------------------------
// Common finds
#if 0
template <class ENT_TYPE>
inline bool FindEntityByName( const char *pszName, ENT_TYPE **ppResult)
{
CBaseEntity *pBaseEntity = gEntList.FindEntityByName( NULL, pszName );
if ( pBaseEntity )
*ppResult = dynamic_cast<ENT_TYPE *>( pBaseEntity );
else
*ppResult = NULL;
return ( *ppResult != NULL );
}
template <>
inline bool FindEntityByName<CBaseEntity>( const char *pszName, CBaseEntity **ppResult)
{
*ppResult = gEntList.FindEntityByName( NULL, pszName );
return ( *ppResult != NULL );
}
template <>
inline bool FindEntityByName<CAI_BaseNPC>( const char *pszName, CAI_BaseNPC **ppResult)
{
CBaseEntity *pBaseEntity = gEntList.FindEntityByName( NULL, pszName );
if ( pBaseEntity )
*ppResult = pBaseEntity->MyNPCPointer();
else
*ppResult = NULL;
return ( *ppResult != NULL );
}
#endif
//-----------------------------------------------------------------------------
// Purpose: Simple object for storing a list of objects
//-----------------------------------------------------------------------------
struct entitem_t
{
EHANDLE hEnt;
struct entitem_t *pNext;
// uses pool memory
static void* operator new( size_t stAllocateBlock );
static void *operator new( size_t stAllocateBlock, int nBlockUse, const char *pFileName, int nLine );
static void operator delete( void *pMem );
static void operator delete( void *pMem, int nBlockUse, const char *pFileName, int nLine ) { operator delete( pMem ); }
};
class CEntityList
{
public:
CEntityList();
~CEntityList();
int m_iNumItems;
entitem_t *m_pItemList; // null terminated singly-linked list
void AddEntity( CBaseEntity * );
void DeleteEntity( CBaseEntity * );
};
enum notify_system_event_t
{
NOTIFY_EVENT_TELEPORT = 0,
NOTIFY_EVENT_DESTROY,
};
struct notify_teleport_params_t
{
Vector prevOrigin;
QAngle prevAngles;
bool physicsRotate;
};
struct notify_destroy_params_t
{
};
struct notify_system_event_params_t
{
union
{
const notify_teleport_params_t *pTeleport;
const notify_destroy_params_t *pDestroy;
};
notify_system_event_params_t( const notify_teleport_params_t *pInTeleport ) { pTeleport = pInTeleport; }
notify_system_event_params_t( const notify_destroy_params_t *pInDestroy ) { pDestroy = pInDestroy; }
};
abstract_class INotify
{
public:
// Add notification for an entity
virtual void AddEntity( CBaseEntity *pNotify, CBaseEntity *pWatched ) = 0;
// Remove notification for an entity
virtual void RemoveEntity( CBaseEntity *pNotify, CBaseEntity *pWatched ) = 0;
// Call the named input in each entity who is watching pEvent's status
virtual void ReportNamedEvent( CBaseEntity *pEntity, const char *pEventName ) = 0;
// System events don't make sense as inputs, so are handled through a generic notify function
virtual void ReportSystemEvent( CBaseEntity *pEntity, notify_system_event_t eventType, const notify_system_event_params_t &params ) = 0;
inline void ReportDestroyEvent( CBaseEntity *pEntity )
{
notify_destroy_params_t destroy;
ReportSystemEvent( pEntity, NOTIFY_EVENT_DESTROY, notify_system_event_params_t(&destroy) );
}
inline void ReportTeleportEvent( CBaseEntity *pEntity, const Vector &prevOrigin, const QAngle &prevAngles, bool physicsRotate )
{
notify_teleport_params_t teleport;
teleport.prevOrigin = prevOrigin;
teleport.prevAngles = prevAngles;
teleport.physicsRotate = physicsRotate;
ReportSystemEvent( pEntity, NOTIFY_EVENT_TELEPORT, notify_system_event_params_t(&teleport) );
}
// Remove this entity from the notify list
virtual void ClearEntity( CBaseEntity *pNotify ) = 0;
};
// Implement this class and register with gEntList to receive entity create/delete notification
class IEntityListener
{
public:
virtual void OnEntityCreated( CBaseEntity *pEntity ) {};
virtual void OnEntitySpawned( CBaseEntity *pEntity ) {};
virtual void OnEntityDeleted( CBaseEntity *pEntity ) {};
};
// singleton
extern INotify *g_pNotify;
void EntityTouch_Add( CBaseEntity *pEntity );
int AimTarget_ListCount();
int AimTarget_ListCopy( CBaseEntity *pList[], int listMax );
void AimTarget_ForceRepopulateList();
void SimThink_EntityChanged( CBaseEntity *pEntity );
int SimThink_ListCount();
int SimThink_ListCopy( CBaseEntity *pList[], int listMax );
#endif // ENTITYLIST_H

View File

@@ -0,0 +1,225 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Declares basic entity communications classes, for input/output of data
// between entities
//
// $NoKeywords: $
//=============================================================================//
#ifndef ENTITYOUTPUT_H
#define ENTITYOUTPUT_H
#ifdef _WIN32
#pragma once
#endif
#include "baseentity.h"
#define EVENT_FIRE_ALWAYS -1
//-----------------------------------------------------------------------------
// Purpose: A COutputEvent consists of an array of these CEventActions.
// Each CEventAction holds the information to fire a single input in
// a target entity, after a specific delay.
//-----------------------------------------------------------------------------
class CEventAction
{
public:
CEventAction( const char *ActionData = NULL );
string_t m_iTarget; // name of the entity(s) to cause the action in
string_t m_iTargetInput; // the name of the action to fire
string_t m_iParameter; // parameter to send, 0 if none
float m_flDelay; // the number of seconds to wait before firing the action
int m_nTimesToFire; // The number of times to fire this event, or EVENT_FIRE_ALWAYS.
int m_iIDStamp; // unique identifier stamp
static int s_iNextIDStamp;
CEventAction *m_pNext;
// allocates memory from engine.MPool/g_EntityListPool
static void *operator new( size_t stAllocateBlock );
static void *operator new( size_t stAllocateBlock, int nBlockUse, const char *pFileName, int nLine );
static void operator delete( void *pMem );
static void operator delete( void *pMem , int nBlockUse, const char *pFileName, int nLine ) { operator delete(pMem); }
DECLARE_SIMPLE_DATADESC();
};
//-----------------------------------------------------------------------------
// Purpose: Stores a list of connections to other entities, for data/commands to be
// communicated along.
//-----------------------------------------------------------------------------
class CBaseEntityOutput
{
public:
~CBaseEntityOutput();
void ParseEventAction( const char *EventData );
void AddEventAction( CEventAction *pEventAction );
void RemoveEventAction( CEventAction *pEventAction );
int Save( ISave &save );
int Restore( IRestore &restore, int elementCount );
int NumberOfElements( void );
float GetMaxDelay( void );
fieldtype_t ValueFieldType() { return m_Value.FieldType(); }
void FireOutput( variant_t Value, CBaseEntity *pActivator, CBaseEntity *pCaller, float fDelay = 0 );
/// Delete every single action in the action list.
void DeleteAllElements( void ) ;
#ifdef MAPBASE
// Needed for ReplaceOutput, hopefully not bad
CEventAction *GetActionList() { return m_ActionList; }
void SetActionList(CEventAction *newlist) { m_ActionList = newlist; }
#endif
protected:
variant_t m_Value;
CEventAction *m_ActionList;
DECLARE_SIMPLE_DATADESC();
CBaseEntityOutput() {} // this class cannot be created, only it's children
private:
CBaseEntityOutput( CBaseEntityOutput& ); // protect from accidental copying
};
//-----------------------------------------------------------------------------
// Purpose: wraps variant_t data handling in convenient, compiler type-checked template
//-----------------------------------------------------------------------------
template< class Type, fieldtype_t fieldType >
class CEntityOutputTemplate : public CBaseEntityOutput
{
public:
//
// Sets an initial value without firing the output.
//
void Init( Type value )
{
m_Value.Set( fieldType, &value );
}
//
// Sets a value and fires the output.
//
void Set( Type value, CBaseEntity *pActivator, CBaseEntity *pCaller )
{
m_Value.Set( fieldType, &value );
FireOutput( m_Value, pActivator, pCaller );
}
//
// Returns the current value.
//
Type Get( void )
{
return *((Type*)&m_Value);
}
};
//
// Template specializations for type Vector, so we can implement Get, Set, and Init differently.
//
template<>
class CEntityOutputTemplate<class Vector, FIELD_VECTOR> : public CBaseEntityOutput
{
public:
void Init( const Vector &value )
{
m_Value.SetVector3D( value );
}
void Set( const Vector &value, CBaseEntity *pActivator, CBaseEntity *pCaller )
{
m_Value.SetVector3D( value );
FireOutput( m_Value, pActivator, pCaller );
}
void Get( Vector &vec )
{
m_Value.Vector3D(vec);
}
#ifdef MAPBASE
// Shortcut to using QAngles in Vector outputs, makes it look cleaner and allows easy modification
void Init( const QAngle &value )
{
// reinterpret_cast<const Vector&>(value)
m_Value.SetAngle3D( value );
}
// Shortcut to using QAngles in Vector outputs, makes it look cleaner and allows easy modification
void Set( const QAngle &value, CBaseEntity *pActivator, CBaseEntity *pCaller )
{
// reinterpret_cast<const Vector&>(value)
m_Value.SetAngle3D( value );
FireOutput( m_Value, pActivator, pCaller );
}
// Shortcut to using QAngles in Vector outputs, makes it look cleaner and allows easy modification
void Get( QAngle &ang )
{
m_Value.Angle3D(ang);
}
#endif
};
template<>
class CEntityOutputTemplate<class Vector, FIELD_POSITION_VECTOR> : public CBaseEntityOutput
{
public:
void Init( const Vector &value )
{
m_Value.SetPositionVector3D( value );
}
void Set( const Vector &value, CBaseEntity *pActivator, CBaseEntity *pCaller )
{
m_Value.SetPositionVector3D( value );
FireOutput( m_Value, pActivator, pCaller );
}
void Get( Vector &vec )
{
m_Value.Vector3D(vec);
}
};
//-----------------------------------------------------------------------------
// Purpose: parameterless entity event
//-----------------------------------------------------------------------------
class COutputEvent : public CBaseEntityOutput
{
public:
// void Firing, no parameter
void FireOutput( CBaseEntity *pActivator, CBaseEntity *pCaller, float fDelay = 0 );
};
// useful typedefs for allowed output data types
typedef CEntityOutputTemplate<variant_t,FIELD_INPUT> COutputVariant;
typedef CEntityOutputTemplate<int,FIELD_INTEGER> COutputInt;
typedef CEntityOutputTemplate<float,FIELD_FLOAT> COutputFloat;
typedef CEntityOutputTemplate<string_t,FIELD_STRING> COutputString;
typedef CEntityOutputTemplate<EHANDLE,FIELD_EHANDLE> COutputEHANDLE;
typedef CEntityOutputTemplate<Vector,FIELD_VECTOR> COutputVector;
typedef CEntityOutputTemplate<Vector,FIELD_POSITION_VECTOR> COutputPositionVector;
typedef CEntityOutputTemplate<color32,FIELD_COLOR32> COutputColor32;
#endif // ENTITYOUTPUT_H

View File

@@ -0,0 +1,505 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Entity to control screen overlays on a player
//
//=============================================================================
#include "cbase.h"
#include "shareddefs.h"
#include "lights.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
#define ENV_CASCADE_STARTON (1<<0)
static ConVar defdist("csm_default_distance", "1000", FCVAR_DEVELOPMENTONLY, "Default Z distance. Used for some fov calculations. Please dont change");
static ConVar curdist("csm_current_distance","14000", 0, "Current Z distance. You can change it.");
static ConVar defFOV("csm_default_fov","15", FCVAR_DEVELOPMENTONLY, "Default FOV. Used for some fov calculations. Please dont change");
static ConVar curFOV("csm_current_fov","15", 0, "Current FOV. You can change it");
static ConVar csm_second_fov("csm_second_fov", "26", FCVAR_NONE ,"FOV of the second csm.");
class CLightOrigin : public CPointEntity
{
DECLARE_CLASS(CLightOrigin, CPointEntity);
public:
DECLARE_DATADESC();
DECLARE_SERVERCLASS();
void Spawn();
CLightOrigin();
bool angFEnv = false;
void InitialThink(void);
private:
CNetworkVector(LightEnvVector);
};
LINK_ENTITY_TO_CLASS(csmorigin, CLightOrigin);
BEGIN_DATADESC(CLightOrigin)
DEFINE_FIELD(LightEnvVector, FIELD_VECTOR),
DEFINE_THINKFUNC(InitialThink)
END_DATADESC()
IMPLEMENT_SERVERCLASS_ST(CLightOrigin, DT_LightOrigin)
SendPropVector(SENDINFO(LightEnvVector))
END_SEND_TABLE()
CLightOrigin::CLightOrigin()
{
}
void CLightOrigin::Spawn()
{
if (angFEnv)
{
CBaseEntity* pEntity = NULL;
pEntity = gEntList.FindEntityByClassname(pEntity, "light_environment");
if (pEntity)
{
CEnvLight* pEnv = dynamic_cast<CEnvLight*>(pEntity);
QAngle bb = pEnv->GetAbsAngles();
bb.x = bb.x;
SetAbsAngles(bb);
ConColorMsg(Color(0,230,0), "light_environment Founded!\n");
}
else
{
//Msg("What the fuck? Map dont have light_environment with targetname!");
ConColorMsg(Color(230, 0, 0), "What the fuck? Map dont have light_environment with targetname!\n");
}
}
}
void CLightOrigin::InitialThink()
{
}
//-----------------------------------------------------------------------------
// Purpose: second csm
//-----------------------------------------------------------------------------
class CEnvCascadeLightSecond : public CPointEntity
{
DECLARE_CLASS(CEnvCascadeLightSecond, CPointEntity);
public:
DECLARE_DATADESC();
DECLARE_SERVERCLASS();
CEnvCascadeLightSecond();
bool KeyValue(const char* szKeyName, const char* szValue);
// Always transmit to clients
virtual int UpdateTransmitState();
virtual void Activate(void);
void InitialThink(void);
CNetworkHandle(CBaseEntity, m_hTargetEntity);
CNetworkVector(m_LinearFloatLightColor);
private:
CNetworkVar(bool, m_bState);
CNetworkVar(float, m_flLightFOV);
CNetworkVar(bool, m_bEnableShadows);
CNetworkVar(bool, m_bLightOnlyTarget);
CNetworkVar(bool, m_bLightWorld);
CNetworkVar(bool, m_bCameraSpace);
CNetworkVar(float, m_flAmbient);
CNetworkString(m_SpotlightTextureName, MAX_PATH);
CNetworkVar(int, m_nSpotlightTextureFrame);
CNetworkVar(float, m_flNearZ);
CNetworkVar(float, m_flFarZ);
CNetworkVar(int, m_nShadowQuality);
};
LINK_ENTITY_TO_CLASS(second_csm, CEnvCascadeLightSecond);
BEGIN_DATADESC(CEnvCascadeLightSecond)
DEFINE_FIELD(m_hTargetEntity, FIELD_EHANDLE),
DEFINE_FIELD(m_bState, FIELD_BOOLEAN),
DEFINE_KEYFIELD(m_flLightFOV, FIELD_FLOAT, "lightfov"),
DEFINE_KEYFIELD(m_bEnableShadows, FIELD_BOOLEAN, "enableshadows"),
DEFINE_KEYFIELD(m_bLightOnlyTarget, FIELD_BOOLEAN, "lightonlytarget"),
DEFINE_KEYFIELD(m_bLightWorld, FIELD_BOOLEAN, "lightworld"),
DEFINE_KEYFIELD(m_bCameraSpace, FIELD_BOOLEAN, "cameraspace"),
DEFINE_KEYFIELD(m_flAmbient, FIELD_FLOAT, "ambient"),
DEFINE_AUTO_ARRAY_KEYFIELD(m_SpotlightTextureName, FIELD_CHARACTER, "texturename"),
DEFINE_KEYFIELD(m_nSpotlightTextureFrame, FIELD_INTEGER, "textureframe"),
DEFINE_KEYFIELD(m_flNearZ, FIELD_FLOAT, "nearz"),
DEFINE_KEYFIELD(m_flFarZ, FIELD_FLOAT, "farz"),
DEFINE_KEYFIELD(m_nShadowQuality, FIELD_INTEGER, "shadowquality"),
DEFINE_FIELD(m_LinearFloatLightColor, FIELD_VECTOR),
DEFINE_THINKFUNC(InitialThink),
END_DATADESC()
IMPLEMENT_SERVERCLASS_ST(CEnvCascadeLightSecond, DT_EnvCascadeLightSecond)
SendPropEHandle(SENDINFO(m_hTargetEntity)),
SendPropBool(SENDINFO(m_bState)),
SendPropFloat(SENDINFO(m_flLightFOV)),
SendPropBool(SENDINFO(m_bEnableShadows)),
SendPropBool(SENDINFO(m_bLightOnlyTarget)),
SendPropBool(SENDINFO(m_bLightWorld)),
SendPropBool(SENDINFO(m_bCameraSpace)),
SendPropVector(SENDINFO(m_LinearFloatLightColor)),
SendPropFloat(SENDINFO(m_flAmbient)),
SendPropString(SENDINFO(m_SpotlightTextureName)),
SendPropInt(SENDINFO(m_nSpotlightTextureFrame)),
SendPropFloat(SENDINFO(m_flNearZ), 16, SPROP_ROUNDDOWN, 0.0f, 500.0f),
SendPropFloat(SENDINFO(m_flFarZ), 18, SPROP_ROUNDDOWN, 0.0f, 1500.0f),
SendPropInt(SENDINFO(m_nShadowQuality), 1, SPROP_UNSIGNED) // Just one bit for now
END_SEND_TABLE()
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
CEnvCascadeLightSecond::CEnvCascadeLightSecond(void)
{
m_bState = true;
m_flLightFOV = 45.0f;
m_bEnableShadows = true;
m_bLightOnlyTarget = false;
m_bLightWorld = true;
m_bCameraSpace = false;
Q_strcpy(m_SpotlightTextureName.GetForModify(), "tools\\fakecsm\\mask_ring");
m_nSpotlightTextureFrame = 0;
m_LinearFloatLightColor.Init(1.0f, 1.0f, 1.0f);
m_flAmbient = 0.0f;
m_flNearZ = 8000.0f;
m_flFarZ = 16000.0f;
m_nShadowQuality = 0;
}
void UTIL_ColorStringToLinearFloatColorCSMFakeSecond(Vector& color, const char* pString)
{
float tmp[4];
UTIL_StringToFloatArray(tmp, 4, pString);
if (tmp[3] <= 0.0f)
{
tmp[3] = 255.0f;
}
tmp[3] *= (1.0f / 255.0f);
color.x = GammaToLinear(tmp[0] * (1.0f / 255.0f)) * tmp[3];
color.y = GammaToLinear(tmp[1] * (1.0f / 255.0f)) * tmp[3];
color.z = GammaToLinear(tmp[2] * (1.0f / 255.0f)) * tmp[3];
}
bool CEnvCascadeLightSecond::KeyValue(const char* szKeyName, const char* szValue)
{
if (FStrEq(szKeyName, "lightcolor"))
{
Vector tmp;
UTIL_ColorStringToLinearFloatColorCSMFakeSecond(tmp, szValue);
m_LinearFloatLightColor = tmp;
}
else
{
return BaseClass::KeyValue(szKeyName, szValue);
}
return true;
}
void CEnvCascadeLightSecond::Activate(void)
{
if (GetSpawnFlags() & ENV_CASCADE_STARTON)
{
m_bState = true;
}
SetThink(&CEnvCascadeLightSecond::InitialThink);
SetNextThink(gpGlobals->curtime + 0.1f);
BaseClass::Activate();
}
void CEnvCascadeLightSecond::InitialThink(void)
{
float bibigon = defdist.GetFloat() / curdist.GetFloat();
m_flLightFOV = csm_second_fov.GetFloat() * bibigon;
m_hTargetEntity = gEntList.FindEntityByName(NULL, m_target);
}
int CEnvCascadeLightSecond::UpdateTransmitState()
{
return SetTransmitState(FL_EDICT_ALWAYS);
}
//-----------------------------------------------------------------------------
// Purpose: main csm code
//-----------------------------------------------------------------------------
class CEnvCascadeLight : public CPointEntity
{
DECLARE_CLASS(CEnvCascadeLight, CPointEntity);
public:
DECLARE_DATADESC();
DECLARE_SERVERCLASS();
CEnvCascadeLight();
bool KeyValue(const char* szKeyName, const char* szValue);
// Always transmit to clients
virtual int UpdateTransmitState();
virtual void Activate(void);
void Spawn();
void Preparation();
void InputTurnOn(inputdata_t& inputdata);
void InputTurnOff(inputdata_t& inputdata);
void InputSetEnableShadows(inputdata_t& inputdata);
void InputSetLightColor( inputdata_t &inputdata );
void InputSetSpotlightTexture(inputdata_t& inputdata);
void InputSetAmbient(inputdata_t& inputdata);
void InitialThink(void);
CNetworkHandle(CBaseEntity, m_hTargetEntity);
private:
CLightOrigin* pEnv;
CNetworkVar(bool, m_bState);
CNetworkVar(float, m_flLightFOV);
CNetworkVar(bool, EnableAngleFromEnv);
CNetworkVar(bool, m_bEnableShadows);
CNetworkVar(bool, m_bLightOnlyTarget);
CNetworkVar(bool, m_bLightWorld);
CNetworkVar(bool, m_bCameraSpace);
CNetworkVector(m_LinearFloatLightColor);
CNetworkVar(float, m_flAmbient);
CNetworkString(m_SpotlightTextureName, MAX_PATH);
CNetworkVar(int, m_nSpotlightTextureFrame);
CNetworkVar(float, m_flNearZ);
CNetworkVar(float, m_flFarZ);
CNetworkVar(int, m_nShadowQuality);
};
LINK_ENTITY_TO_CLASS(env_cascade_light, CEnvCascadeLight);
BEGIN_DATADESC(CEnvCascadeLight)
DEFINE_FIELD(m_hTargetEntity, FIELD_EHANDLE),
DEFINE_FIELD(m_bState, FIELD_BOOLEAN),
DEFINE_KEYFIELD(m_bEnableShadows, FIELD_BOOLEAN, "enableshadows"),
DEFINE_KEYFIELD(m_bLightOnlyTarget, FIELD_BOOLEAN, "lightonlytarget"),
DEFINE_KEYFIELD(m_bLightWorld, FIELD_BOOLEAN, "lightworld"),
DEFINE_KEYFIELD(m_bCameraSpace, FIELD_BOOLEAN, "cameraspace"),
DEFINE_KEYFIELD(m_flAmbient, FIELD_FLOAT, "ambient"),
DEFINE_AUTO_ARRAY_KEYFIELD(m_SpotlightTextureName, FIELD_CHARACTER, "texturename"),
DEFINE_KEYFIELD(m_nSpotlightTextureFrame, FIELD_INTEGER, "textureframe"),
DEFINE_KEYFIELD(m_flNearZ, FIELD_FLOAT, "nearz"),
DEFINE_KEYFIELD(m_flFarZ, FIELD_FLOAT, "farz"),
DEFINE_KEYFIELD(m_nShadowQuality, FIELD_INTEGER, "shadowquality"),
DEFINE_FIELD(m_LinearFloatLightColor, FIELD_VECTOR),
DEFINE_KEYFIELD(EnableAngleFromEnv, FIELD_BOOLEAN, "uselightenvangles"),
DEFINE_INPUTFUNC(FIELD_VOID, "TurnOn", InputTurnOn),
DEFINE_INPUTFUNC(FIELD_VOID, "TurnOff", InputTurnOff),
DEFINE_INPUTFUNC(FIELD_BOOLEAN, "EnableShadows", InputSetEnableShadows),
// this is broken . . need to be able to set color and intensity like light_dynamic
// DEFINE_INPUTFUNC( FIELD_COLOR32, "LightColor", InputSetLightColor ),
DEFINE_INPUTFUNC(FIELD_FLOAT, "Ambient", InputSetAmbient),
DEFINE_INPUTFUNC(FIELD_STRING, "SpotlightTexture", InputSetSpotlightTexture),
DEFINE_THINKFUNC(InitialThink),
END_DATADESC()
IMPLEMENT_SERVERCLASS_ST(CEnvCascadeLight, DT_EnvCascadeLight)
SendPropEHandle(SENDINFO(m_hTargetEntity)),
SendPropBool(SENDINFO(m_bState)),
SendPropFloat(SENDINFO(m_flLightFOV)),
SendPropBool(SENDINFO(m_bEnableShadows)),
SendPropBool(SENDINFO(m_bLightOnlyTarget)),
SendPropBool(SENDINFO(m_bLightWorld)),
SendPropBool(SENDINFO(m_bCameraSpace)),
SendPropVector(SENDINFO(m_LinearFloatLightColor)),
SendPropFloat(SENDINFO(m_flAmbient)),
SendPropString(SENDINFO(m_SpotlightTextureName)),
SendPropInt(SENDINFO(m_nSpotlightTextureFrame)),
SendPropFloat(SENDINFO(m_flNearZ), 16, SPROP_ROUNDDOWN, 0.0f, 500.0f),
SendPropFloat(SENDINFO(m_flFarZ), 18, SPROP_ROUNDDOWN, 0.0f, 1500.0f),
SendPropInt(SENDINFO(m_nShadowQuality), 1, SPROP_UNSIGNED) // Just one bit for now
END_SEND_TABLE()
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
CEnvCascadeLight::CEnvCascadeLight(void)
{
m_bState = true;
m_flLightFOV = 45.0f;
m_bEnableShadows = true;
m_bLightOnlyTarget = false;
m_bLightWorld = true;
m_bCameraSpace = false;
EnableAngleFromEnv = false;
Q_strcpy(m_SpotlightTextureName.GetForModify(), "tools\\fakecsm\\mask_center");
m_nSpotlightTextureFrame = 0;
m_LinearFloatLightColor.Init(1.0f, 1.0f, 1.0f);
m_flAmbient = 0.0f;
m_flNearZ = 8000.0f;
m_flFarZ = 16000.0f;
m_nShadowQuality = 0;
}
ConVar csm_second_intensity("csm_second_intensity", "2");
void CEnvCascadeLight::Preparation()
{
CreateEntityByName("csmorigin");
CreateEntityByName("second_csm");
defFOV.SetValue(m_flLightFOV);
CBaseEntity* CSMOrigin = NULL;
CBaseEntity* CSMSecond = NULL;
CSMOrigin = gEntList.FindEntityByClassname(CSMOrigin, "csmorigin");
//if origin is exist
if (CSMOrigin)
{
pEnv = dynamic_cast<CLightOrigin*>(CSMOrigin);
CSMSecond = gEntList.FindEntityByClassname(CSMSecond, "second_csm");
//if second csm is exist
if (CSMSecond)
{
CEnvCascadeLightSecond* SecondCSM = dynamic_cast<CEnvCascadeLightSecond*>(CSMSecond);
SecondCSM->SetAbsAngles(GetAbsAngles());
SecondCSM->SetAbsOrigin(GetAbsOrigin());
SecondCSM->SetParent(GetBaseEntity());
SecondCSM->m_LinearFloatLightColor = m_LinearFloatLightColor * csm_second_intensity.GetFloat();
DispatchSpawn(SecondCSM);
}
SetParent(pEnv, 1);
SetAbsOrigin(Vector(pEnv->GetAbsOrigin().x, pEnv->GetAbsOrigin().y, pEnv->GetAbsOrigin().z + curdist.GetInt()));
if (EnableAngleFromEnv)
{
pEnv->angFEnv = true;
SetLocalAngles(QAngle(90, 0, 0));
}
else
{
pEnv->SetAbsAngles(QAngle((GetLocalAngles().x - 90), GetLocalAngles().y, -GetLocalAngles().z));
Msg("pEnv local angle = %f %f %f \n", pEnv->GetLocalAngles().x, pEnv->GetLocalAngles().y, pEnv->GetLocalAngles().z);
SetLocalAngles(QAngle(90, 0, 0));
DevMsg("CSM using light_environment \n");
}
//DispatchSpawn(CSMSecond);
DispatchSpawn(CSMOrigin);
}
else
{
Msg("Main csm entity can't find \"csmorigin\" entity!");
}
}
void CEnvCascadeLight::Spawn()
{
Preparation();
}
void UTIL_ColorStringToLinearFloatColorCSMFake(Vector& color, const char* pString)
{
float tmp[4];
UTIL_StringToFloatArray(tmp, 4, pString);
if (tmp[3] <= 0.0f)
{
tmp[3] = 255.0f;
}
tmp[3] *= (1.0f / 255.0f);
color.x = GammaToLinear(tmp[0] * (1.0f / 255.0f)) * tmp[3];
color.y = GammaToLinear(tmp[1] * (1.0f / 255.0f)) * tmp[3];
color.z = GammaToLinear(tmp[2] * (1.0f / 255.0f)) * tmp[3];
}
bool CEnvCascadeLight::KeyValue(const char* szKeyName, const char* szValue)
{
if (FStrEq(szKeyName, "lightcolor"))
{
Vector tmp;
UTIL_ColorStringToLinearFloatColorCSMFake(tmp, szValue);
m_LinearFloatLightColor = tmp;
}
else
{
return BaseClass::KeyValue(szKeyName, szValue);
}
return true;
}
void CEnvCascadeLight::InputTurnOn(inputdata_t& inputdata)
{
m_bState = true;
}
void CEnvCascadeLight::InputTurnOff(inputdata_t& inputdata)
{
m_bState = false;
}
void CEnvCascadeLight::InputSetEnableShadows(inputdata_t& inputdata)
{
m_bEnableShadows = inputdata.value.Bool();
}
//void CEnvProjectedTexture::InputSetLightColor( inputdata_t &inputdata )
//{
//m_cLightColor = inputdata.value.Color32();
//}
void CEnvCascadeLight::InputSetAmbient(inputdata_t& inputdata)
{
m_flAmbient = inputdata.value.Float();
}
void CEnvCascadeLight::InputSetSpotlightTexture(inputdata_t& inputdata)
{
Q_strcpy(m_SpotlightTextureName.GetForModify(), inputdata.value.String());
}
void CEnvCascadeLight::Activate(void)
{
if (GetSpawnFlags() & ENV_CASCADE_STARTON)
{
m_bState = true;
}
SetThink(&CEnvCascadeLight::InitialThink);
SetNextThink(gpGlobals->curtime + 0.1f);
BaseClass::Activate();
}
void CEnvCascadeLight::InitialThink(void)
{
m_hTargetEntity = gEntList.FindEntityByName(NULL, m_target);
float bibigon = defdist.GetFloat() / curdist.GetFloat();
curFOV.SetValue(defFOV.GetFloat() * bibigon);
m_flLightFOV = curFOV.GetFloat();
//if(pEnv != NULL)
//SetAbsOrigin(Vector(pEnv->GetAbsOrigin().x, pEnv->GetAbsOrigin().y, pEnv->GetAbsOrigin().z + curdist.GetInt()));
}
int CEnvCascadeLight::UpdateTransmitState()
{
return SetTransmitState(FL_EDICT_ALWAYS);
}

View File

@@ -0,0 +1,367 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================
#include "cbase.h"
#include "isaverestore.h"
#include "env_debughistory.h"
#include "tier0/vprof.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
// Number of characters worth of debug to use per history category
#define DEBUG_HISTORY_VERSION 6
#define DEBUG_HISTORY_FIRST_VERSIONED 5
#define MAX_DEBUG_HISTORY_LINE_LENGTH 256
#define MAX_DEBUG_HISTORY_LENGTH (1000 * MAX_DEBUG_HISTORY_LINE_LENGTH)
//-----------------------------------------------------------------------------
// Purpose: Stores debug history in savegame files for debugging reference
//-----------------------------------------------------------------------------
class CDebugHistory : public CBaseEntity
{
DECLARE_CLASS( CDebugHistory, CBaseEntity );
public:
DECLARE_DATADESC();
void Spawn();
void AddDebugHistoryLine( int iCategory, const char *szLine );
void ClearHistories( void );
void DumpDebugHistory( int iCategory );
int Save( ISave &save );
int Restore( IRestore &restore );
private:
char m_DebugLines[MAX_HISTORY_CATEGORIES][MAX_DEBUG_HISTORY_LENGTH];
char *m_DebugLineEnd[MAX_HISTORY_CATEGORIES];
};
BEGIN_DATADESC( CDebugHistory )
//DEFINE_FIELD( m_DebugLines, FIELD_CHARACTER ), // Not saved because we write it out manually
//DEFINE_FIELD( m_DebugLineEnd, FIELD_CHARACTER ),
END_DATADESC()
LINK_ENTITY_TO_CLASS( env_debughistory, CDebugHistory );
// The handle to the debug history singleton. Created on first access via GetDebugHistory.
static CHandle< CDebugHistory > s_DebugHistory;
//-----------------------------------------------------------------------------
// Spawn
//-----------------------------------------------------------------------------
void CDebugHistory::Spawn()
{
BaseClass::Spawn();
#ifdef DISABLE_DEBUG_HISTORY
UTIL_Remove( this );
#else
if ( g_pGameRules && g_pGameRules->IsMultiplayer() )
{
UTIL_Remove( this );
}
else
{
Warning( "DEBUG HISTORY IS ENABLED. Disable before release (in env_debughistory.h).\n" );
}
#endif
ClearHistories();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CDebugHistory::AddDebugHistoryLine( int iCategory, const char *szLine )
{
if ( iCategory < 0 || iCategory >= MAX_HISTORY_CATEGORIES )
{
Warning("Attempted to add a debughistory line to category %d. Valid categories are %d to %d.\n", iCategory, 0, (MAX_HISTORY_CATEGORIES-1) );
return;
}
// Don't do debug history before the singleton is properly set up.
if ( !m_DebugLineEnd[iCategory] )
return;
const char *pszRemaining = szLine;
int iCharsToWrite = strlen( pszRemaining ) + 1; // Add 1 so that we copy the null terminator
// Clip the line if it's too long. Wasteful doing it this way, but keeps code below nice & simple.
char szTmpBuffer[MAX_DEBUG_HISTORY_LINE_LENGTH];
if ( iCharsToWrite > MAX_DEBUG_HISTORY_LINE_LENGTH)
{
memcpy( szTmpBuffer, szLine, sizeof(szTmpBuffer) );
szTmpBuffer[MAX_DEBUG_HISTORY_LINE_LENGTH-1] = '\0';
pszRemaining = szTmpBuffer;
iCharsToWrite = MAX_DEBUG_HISTORY_LINE_LENGTH;
}
while ( iCharsToWrite )
{
int iCharsLeftBeforeLoop = sizeof(m_DebugLines[iCategory]) - (m_DebugLineEnd[iCategory] - m_DebugLines[iCategory]);
// Write into the buffer
int iWrote = MIN( iCharsToWrite, iCharsLeftBeforeLoop );
memcpy( m_DebugLineEnd[iCategory], pszRemaining, iWrote );
m_DebugLineEnd[iCategory] += iWrote;
pszRemaining += iWrote;
// Did we loop?
if ( iWrote == iCharsLeftBeforeLoop )
{
m_DebugLineEnd[iCategory] = m_DebugLines[iCategory];
}
iCharsToWrite -= iWrote;
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CDebugHistory::DumpDebugHistory( int iCategory )
{
if ( iCategory < 0 || iCategory >= MAX_HISTORY_CATEGORIES )
{
Warning("Attempted to dump a history for category %d. Valid categories are %d to %d.\n", iCategory, 0, (MAX_HISTORY_CATEGORIES-1) );
return;
}
// Find the start of the oldest whole debug line.
const char *pszLine = m_DebugLineEnd[iCategory] + 1;
if ( (pszLine - m_DebugLines[iCategory]) >= sizeof(m_DebugLines[iCategory]) )
{
pszLine = m_DebugLines[iCategory];
}
// Are we at the start of a line? If there's a null terminator before us, then we're good to go.
while ( (!( pszLine == m_DebugLines[iCategory] && *(m_DebugLines[iCategory]+sizeof(m_DebugLines[iCategory])-1) == '\0' ) &&
!( pszLine != m_DebugLines[iCategory] && *(pszLine-1) == '\0' ))
|| *pszLine == '\0' )
{
pszLine++;
// Have we looped?
if ( (pszLine - m_DebugLines[iCategory]) >= sizeof(m_DebugLines[iCategory]) )
{
pszLine = m_DebugLines[iCategory];
}
if ( pszLine == m_DebugLineEnd[iCategory] )
{
// We looped through the entire history, and found nothing.
Msg( "Debug History of Category %d is EMPTY\n", iCategory );
return;
}
}
// Now print everything up till the end
char szMsgBuffer[MAX_DEBUG_HISTORY_LINE_LENGTH];
char *pszMsg = szMsgBuffer;
Msg( "Starting Debug History Dump of Category %d\n", iCategory );
while ( pszLine != m_DebugLineEnd[iCategory] )
{
*pszMsg = *pszLine;
if ( *pszLine == '\0' )
{
if ( szMsgBuffer[0] != '\0' )
{
// Found a full line, so print it
Msg( "%s", szMsgBuffer );
}
// Clear the buffer
pszMsg = szMsgBuffer;
*pszMsg = '\0';
}
else
{
pszMsg++;
}
pszLine++;
// Have we looped?
if ( (pszLine - m_DebugLines[iCategory]) >= sizeof(m_DebugLines[iCategory]) )
{
pszLine = m_DebugLines[iCategory];
}
}
Msg("Ended Debug History Dump of Category %d\n", iCategory );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CDebugHistory::ClearHistories( void )
{
for ( int i = 0; i < MAX_HISTORY_CATEGORIES; i++ )
{
memset( m_DebugLines[i], 0, sizeof(m_DebugLines[i]) );
m_DebugLineEnd[i] = m_DebugLines[i];
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
int CDebugHistory::Save( ISave &save )
{
int iVersion = DEBUG_HISTORY_VERSION;
save.WriteInt( &iVersion );
int iMaxCategorys = MAX_HISTORY_CATEGORIES;
save.WriteInt( &iMaxCategorys );
for ( int iCategory = 0; iCategory < MAX_HISTORY_CATEGORIES; iCategory++ )
{
int iEnd = m_DebugLineEnd[iCategory] - m_DebugLines[iCategory];
save.WriteInt( &iEnd );
save.WriteData( m_DebugLines[iCategory], MAX_DEBUG_HISTORY_LENGTH );
}
return BaseClass::Save(save);
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
int CDebugHistory::Restore( IRestore &restore )
{
ClearHistories();
int iVersion = restore.ReadInt();
if ( iVersion >= DEBUG_HISTORY_FIRST_VERSIONED )
{
int iMaxCategorys = restore.ReadInt();
for ( int iCategory = 0; iCategory < MIN(iMaxCategorys,MAX_HISTORY_CATEGORIES); iCategory++ )
{
int iEnd = restore.ReadInt();
m_DebugLineEnd[iCategory] = m_DebugLines[iCategory] + iEnd;
restore.ReadData( m_DebugLines[iCategory], sizeof(m_DebugLines[iCategory]), 0 );
}
}
else
{
int iMaxCategorys = iVersion;
for ( int iCategory = 0; iCategory < MIN(iMaxCategorys,MAX_HISTORY_CATEGORIES); iCategory++ )
{
int iEnd = restore.ReadInt();
m_DebugLineEnd[iCategory] = m_DebugLines[iCategory] + iEnd;
restore.ReadData( m_DebugLines[iCategory], sizeof(m_DebugLines[iCategory]), 0 );
}
}
return BaseClass::Restore(restore);
}
//-----------------------------------------------------------------------------
// Purpose: Singleton debug history. Created by first usage.
//-----------------------------------------------------------------------------
CDebugHistory *GetDebugHistory()
{
#ifdef DISABLE_DEBUG_HISTORY
return NULL;
#endif
if ( g_pGameRules && g_pGameRules->IsMultiplayer() )
return NULL;
if ( s_DebugHistory == NULL )
{
CBaseEntity *pEnt = gEntList.FindEntityByClassname( NULL, "env_debughistory" );
if ( pEnt )
{
s_DebugHistory = dynamic_cast<CDebugHistory*>(pEnt);
}
else
{
s_DebugHistory = ( CDebugHistory * )CreateEntityByName( "env_debughistory" );
if ( s_DebugHistory )
{
s_DebugHistory->Spawn();
}
}
}
Assert( s_DebugHistory );
return s_DebugHistory;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void AddDebugHistoryLine( int iCategory, const char *pszLine )
{
#ifdef DISABLE_DEBUG_HISTORY
return;
#else
if ( g_pGameRules && g_pGameRules->IsMultiplayer() )
return;
if ( !GetDebugHistory() )
{
Warning("Failed to find or create an env_debughistory.\n" );
return;
}
GetDebugHistory()->AddDebugHistoryLine( iCategory, pszLine );
#endif
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CC_DebugHistory_AddLine( const CCommand &args )
{
if ( !UTIL_IsCommandIssuedByServerAdmin() )
return;
if ( args.ArgC() < 3 )
{
Warning("Incorrect parameters. Format: <category id> <line>\n");
return;
}
int iCategory = atoi(args[ 1 ]);
const char *pszLine = args[ 2 ];
AddDebugHistoryLine( iCategory, pszLine );
}
static ConCommand dbghist_addline( "dbghist_addline", CC_DebugHistory_AddLine, "Add a line to the debug history. Format: <category id> <line>", FCVAR_NONE );
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CC_DebugHistory_Dump( const CCommand &args )
{
if ( !UTIL_IsCommandIssuedByServerAdmin() )
return;
if ( args.ArgC() < 2 )
{
Warning("Incorrect parameters. Format: <category id>\n");
return;
}
if ( GetDebugHistory() )
{
int iCategory = atoi(args[ 1 ]);
GetDebugHistory()->DumpDebugHistory( iCategory );
}
}
static ConCommand dbghist_dump("dbghist_dump", CC_DebugHistory_Dump,
"Dump the debug history to the console. Format: <category id>\n"
" Categories:\n"
" 0: Entity I/O\n"
" 1: AI Decisions\n"
" 2: Scene Print\n"
" 3: Alyx Blind\n"
" 4: Log of damage done to player",
FCVAR_NONE );

View File

@@ -0,0 +1,35 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================
#ifndef ENV_DEBUGHISTORY_H
#define ENV_DEBUGHISTORY_H
#ifdef _WIN32
#pragma once
#endif
enum debughistorycategories_t
{
HISTORY_ENTITY_IO,
HISTORY_AI_DECISIONS,
HISTORY_SCENE_PRINT,
HISTORY_ALYX_BLIND, // TEMP: until we find and fix this bug
HISTORY_PLAYER_DAMAGE, // record all damage done to the player
// Add new categories here
MAX_HISTORY_CATEGORIES,
};
#define DISABLE_DEBUG_HISTORY
#if defined(DISABLE_DEBUG_HISTORY)
#define ADD_DEBUG_HISTORY( category, line ) ((void)0)
#else
#define ADD_DEBUG_HISTORY( category, line ) AddDebugHistoryLine( category, line )
void AddDebugHistoryLine( int iCategory, const char *pszLine );
#endif
#endif // ENV_DEBUGHISTORY_H

View File

@@ -0,0 +1,186 @@
//====== Copyright <20> 1996-2004, Valve Corporation, All rights reserved. =======
//
// Purpose: Depth of field controller entity
//
//=============================================================================
#include "cbase.h"
#include "baseentity.h"
#include "entityoutput.h"
#include "env_dof_controller.h"
#include "ai_utils.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
LINK_ENTITY_TO_CLASS( env_dof_controller, CEnvDOFController );
BEGIN_DATADESC( CEnvDOFController )
DEFINE_KEYFIELD( m_bDOFEnabled, FIELD_BOOLEAN, "enabled" ),
DEFINE_KEYFIELD( m_flNearBlurDepth, FIELD_FLOAT, "near_blur" ),
DEFINE_KEYFIELD( m_flNearFocusDepth, FIELD_FLOAT, "near_focus" ),
DEFINE_KEYFIELD( m_flFarFocusDepth, FIELD_FLOAT, "far_focus" ),
DEFINE_KEYFIELD( m_flFarBlurDepth, FIELD_FLOAT, "far_blur" ),
DEFINE_KEYFIELD( m_flNearBlurRadius, FIELD_FLOAT, "near_radius" ),
DEFINE_KEYFIELD( m_flFarBlurRadius, FIELD_FLOAT, "far_radius" ),
DEFINE_KEYFIELD( m_strFocusTargetName, FIELD_STRING, "focus_target" ),
DEFINE_KEYFIELD( m_flFocusTargetRange, FIELD_FLOAT, "focus_range" ),
DEFINE_FIELD( m_hFocusTarget, FIELD_EHANDLE ),
DEFINE_THINKFUNC( UpdateParamBlend ),
// Inputs
DEFINE_INPUTFUNC( FIELD_FLOAT, "SetNearBlurDepth", InputSetNearBlurDepth ),
DEFINE_INPUTFUNC( FIELD_FLOAT, "SetNearFocusDepth", InputSetNearFocusDepth ),
DEFINE_INPUTFUNC( FIELD_FLOAT, "SetFarFocusDepth", InputSetFarFocusDepth ),
DEFINE_INPUTFUNC( FIELD_FLOAT, "SetFarBlurDepth", InputSetFarBlurDepth ),
DEFINE_INPUTFUNC( FIELD_FLOAT, "SetNearBlurRadius", InputSetNearBlurRadius ),
DEFINE_INPUTFUNC( FIELD_FLOAT, "SetFarBlurRadius", InputSetFarBlurRadius ),
DEFINE_INPUTFUNC( FIELD_STRING, "SetFocusTarget", InputSetFocusTarget ),
DEFINE_INPUTFUNC( FIELD_FLOAT, "SetFocusTargetRange", InputSetFocusTargetRange ),
END_DATADESC()
IMPLEMENT_SERVERCLASS_ST( CEnvDOFController, DT_EnvDOFController )
SendPropInt( SENDINFO(m_bDOFEnabled), 1, SPROP_UNSIGNED ),
SendPropFloat( SENDINFO(m_flNearBlurDepth), 0, SPROP_NOSCALE),
SendPropFloat( SENDINFO(m_flNearFocusDepth), 0, SPROP_NOSCALE),
SendPropFloat( SENDINFO(m_flFarFocusDepth), 0, SPROP_NOSCALE),
SendPropFloat( SENDINFO(m_flFarBlurDepth), 0, SPROP_NOSCALE),
SendPropFloat( SENDINFO(m_flNearBlurRadius), 0, SPROP_NOSCALE),
SendPropFloat( SENDINFO(m_flFarBlurRadius), 0, SPROP_NOSCALE),
END_SEND_TABLE()
void CEnvDOFController::Spawn()
{
SetSolid( SOLID_NONE );
SetMoveType( MOVETYPE_NONE );
#ifdef MAPBASE
// Find our target entity and hold on to it
m_hFocusTarget = gEntList.FindEntityByName( NULL, m_strFocusTargetName, this );
// Update if we have a focal target
if ( m_hFocusTarget )
{
SetThink( &CEnvDOFController::UpdateParamBlend );
SetNextThink( gpGlobals->curtime + 0.1f );
}
#endif
}
void CEnvDOFController::Activate()
{
BaseClass::Activate();
#ifndef MAPBASE // Mapbase moves this to Spawn() to avoid issues with save/restore and entities set via the SetFocusTarget input
// Find our target entity and hold on to it
m_hFocusTarget = gEntList.FindEntityByName( NULL, m_strFocusTargetName );
// Update if we have a focal target
if ( m_hFocusTarget )
{
SetThink( &CEnvDOFController::UpdateParamBlend );
SetNextThink( gpGlobals->curtime + 0.1f );
}
#endif
}
int CEnvDOFController::UpdateTransmitState()
{
return SetTransmitState( FL_EDICT_ALWAYS );
}
void CEnvDOFController::InputSetNearBlurDepth( inputdata_t &inputdata )
{
m_flNearBlurDepth = inputdata.value.Float();
}
void CEnvDOFController::InputSetNearFocusDepth( inputdata_t &inputdata )
{
m_flNearFocusDepth = inputdata.value.Float();
}
void CEnvDOFController::InputSetFarFocusDepth( inputdata_t &inputdata )
{
m_flFarFocusDepth = inputdata.value.Float();
}
void CEnvDOFController::InputSetFarBlurDepth( inputdata_t &inputdata )
{
m_flFarBlurDepth = inputdata.value.Float();
}
void CEnvDOFController::InputSetNearBlurRadius( inputdata_t &inputdata )
{
m_flNearBlurRadius = inputdata.value.Float();
m_bDOFEnabled = ( m_flNearBlurRadius > 0.0f ) || ( m_flFarBlurRadius > 0.0f );
}
void CEnvDOFController::InputSetFarBlurRadius( inputdata_t &inputdata )
{
m_flFarBlurRadius = inputdata.value.Float();
m_bDOFEnabled = ( m_flNearBlurRadius > 0.0f ) || ( m_flFarBlurRadius > 0.0f );
}
void CEnvDOFController::SetControllerState( DOFControlSettings_t setting )
{
m_flNearBlurDepth = setting.flNearBlurDepth;
m_flNearBlurRadius = setting.flNearBlurRadius;
m_flNearFocusDepth = setting.flNearFocusDistance;
m_flFarBlurDepth = setting.flFarBlurDepth;
m_flFarBlurRadius = setting.flFarBlurRadius;
m_flFarFocusDepth = setting.flFarFocusDistance;
m_bDOFEnabled = ( m_flNearBlurRadius > 0.0f ) || ( m_flFarBlurRadius > 0.0f );
}
#define BLUR_DEPTH 500.0f
//-----------------------------------------------------------------------------
// Purpose: Blend the parameters to the specified value
//-----------------------------------------------------------------------------
void CEnvDOFController::UpdateParamBlend()
{
// Update our focal target if we have one
if ( m_hFocusTarget )
{
CBasePlayer *pPlayer = AI_GetSinglePlayer();
float flDistToFocus = ( m_hFocusTarget->GetAbsOrigin() - pPlayer->GetAbsOrigin() ).Length();
m_flFarFocusDepth.GetForModify() = flDistToFocus + m_flFocusTargetRange;
m_flFarBlurDepth.GetForModify() = m_flFarFocusDepth + BLUR_DEPTH;
SetThink( &CEnvDOFController::UpdateParamBlend );
SetNextThink( gpGlobals->curtime + 0.1f );
}
}
//-----------------------------------------------------------------------------
// Purpose: Set the "focus" target entity
//-----------------------------------------------------------------------------
void CEnvDOFController::InputSetFocusTarget( inputdata_t &inputdata )
{
#ifdef MAPBASE
m_hFocusTarget = gEntList.FindEntityByName( NULL, inputdata.value.String(), this, inputdata.pActivator, inputdata.pCaller );
#else
m_hFocusTarget = gEntList.FindEntityByName( NULL, inputdata.value.String() );
#endif
// Update if we have a focal target
if ( m_hFocusTarget )
{
SetThink( &CEnvDOFController::UpdateParamBlend );
SetNextThink( gpGlobals->curtime + 0.1f );
}
}
//-----------------------------------------------------------------------------
// Purpose: Set the range behind the focus entity that we'll blur (in units)
//-----------------------------------------------------------------------------
void CEnvDOFController::InputSetFocusTargetRange( inputdata_t &inputdata )
{
m_flFocusTargetRange = inputdata.value.Float();
}

View File

@@ -0,0 +1,56 @@
#pragma once
struct DOFControlSettings_t
{
// Near plane
float flNearBlurDepth;
float flNearBlurRadius;
float flNearFocusDistance;
// Far plane
float flFarBlurDepth;
float flFarBlurRadius;
float flFarFocusDistance;
};
//-----------------------------------------------------------------------------
// Purpose: Entity that controls depth of field postprocessing
//-----------------------------------------------------------------------------
class CEnvDOFController : public CPointEntity
{
DECLARE_CLASS( CEnvDOFController, CPointEntity );
public:
DECLARE_DATADESC();
DECLARE_SERVERCLASS();
virtual void Spawn();
virtual void Activate();
virtual int UpdateTransmitState();
void SetControllerState( DOFControlSettings_t setting );
void UpdateParamBlend();
// Inputs
void InputSetNearBlurDepth( inputdata_t &inputdata );
void InputSetNearFocusDepth( inputdata_t &inputdata );
void InputSetFarFocusDepth( inputdata_t &inputdata );
void InputSetFarBlurDepth( inputdata_t &inputdata );
void InputSetNearBlurRadius( inputdata_t &inputdata );
void InputSetFarBlurRadius( inputdata_t &inputdata );
void InputSetFocusTarget( inputdata_t &inputdata );
void InputSetFocusTargetRange( inputdata_t &inputdata );
private:
float m_flFocusTargetRange;
string_t m_strFocusTargetName; // Name of the entity to focus on
EHANDLE m_hFocusTarget;
CNetworkVar( bool, m_bDOFEnabled );
CNetworkVar( float, m_flNearBlurDepth );
CNetworkVar( float, m_flNearFocusDepth );
CNetworkVar( float, m_flFarFocusDepth );
CNetworkVar( float, m_flFarBlurDepth );
CNetworkVar( float, m_flNearBlurRadius );
CNetworkVar( float, m_flFarBlurRadius );
};

View File

@@ -0,0 +1,542 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "baseanimating.h"
#include "Sprite.h"
#include "SpriteTrail.h"
#include <ctype.h>
#include "animation.h"
#include "eventlist.h"
#include "npcevent.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
enum EffectType
{
EFFECT_TYPE_TRAIL = 1,
EFFECT_TYPE_SPRITE
};
bool g_bUnget = false;
unsigned char *buffer;
char name[ 256 ];
const char *currenttoken;
int tokencount;
char token[ 1204 ];
class CEffectScriptElement
{
public:
CEffectScriptElement();
char m_szEffectName[128];
CHandle<CSpriteTrail> m_pTrail;
CHandle<CSprite> m_pSprite;
int m_iType;
int m_iRenderType;
int m_iR;
int m_iG;
int m_iB;
int m_iA;
char m_szAttachment[128];
char m_szMaterial[128];
float m_flScale;
float m_flFadeTime;
float m_flTextureRes;
bool m_bStopFollowOnKill;
bool IsActive( void ) { return m_bActive; }
void Activate( void ) { m_bActive = true; }
void Deactivate( void ) { m_bActive = false; }
private:
bool m_bActive;
};
CEffectScriptElement::CEffectScriptElement()
{
m_pTrail = NULL;
m_pSprite = NULL;
m_iType = 0;
Deactivate();
m_iRenderType = kRenderTransAdd;
m_iR = 255;
m_iG = 0;
m_iB = 0;
m_iA = 255;
m_flScale = 1.0f;
m_flFadeTime = 1.0f;
m_flTextureRes = -1.0f;
m_bStopFollowOnKill = false;
}
//-----------------------------------------------------------------------------
// An entity which emits other entities at points
//-----------------------------------------------------------------------------
class CEnvEffectsScript : public CBaseAnimating
{
public:
DECLARE_CLASS( CEnvEffectsScript, CBaseAnimating );
DECLARE_DATADESC();
virtual void Precache();
virtual void Spawn();
virtual int UpdateTransmitState();
void InputSetSequence( inputdata_t &inputdata );
void ParseScriptFile( void );
void LoadFromBuffer( const char *scriptfile, const char *buffer );
virtual void Think( void );
void ParseNewEffect( void );
const char *GetScriptFile( void )
{
return STRING( m_iszScriptName );
}
void HandleAnimEvent ( animevent_t *pEvent );
void TrailEffectEvent( CEffectScriptElement *pEffect );
void SpriteEffectEvent( CEffectScriptElement *pEffect );
CEffectScriptElement *GetScriptElementByName( const char *pName );
private:
string_t m_iszScriptName;
CUtlVector< CEffectScriptElement > m_ScriptElements;
//-----------------------------------------------------------------------------
// Purpose:
// Output : Returns true on success, false on failure.
//-----------------------------------------------------------------------------
bool IsRootCommand( void )
{
if ( !Q_stricmp( token, "effect" ) )
return true;
return false;
}
};
inline bool ParseToken( void )
{
if ( g_bUnget )
{
g_bUnget = false;
return true;
}
currenttoken = engine->ParseFile( currenttoken, token, sizeof( token ) );
tokencount++;
return currenttoken != NULL ? true : false;
}
inline void Unget()
{
g_bUnget = true;
}
inline bool TokenWaiting( void )
{
const char *p = currenttoken;
while ( *p && *p!='\n')
{
// Special handler for // comment blocks
if ( *p == '/' && *(p+1) == '/' )
return false;
if ( !V_isspace( *p ) || V_isalnum( *p ) )
return true;
p++;
}
return false;
}
//-----------------------------------------------------------------------------
// Save/load
//-----------------------------------------------------------------------------
BEGIN_DATADESC( CEnvEffectsScript )
// Inputs
DEFINE_INPUTFUNC( FIELD_STRING, "SetSequence", InputSetSequence ),
DEFINE_KEYFIELD( m_iszScriptName, FIELD_STRING, "scriptfile" ),
// DEFINE_FIELD( m_ScriptElements, CUtlVector < CEffectScriptElement > ),
DEFINE_FUNCTION( Think ),
END_DATADESC()
LINK_ENTITY_TO_CLASS( env_effectscript, CEnvEffectsScript );
//-----------------------------------------------------------------------------
// Should we transmit it to the client?
//-----------------------------------------------------------------------------
int CEnvEffectsScript::UpdateTransmitState()
{
return SetTransmitState( FL_EDICT_ALWAYS );
}
//-----------------------------------------------------------------------------
// Precache
//-----------------------------------------------------------------------------
void CEnvEffectsScript::Precache()
{
BaseClass::Precache();
PrecacheModel( STRING( GetModelName() ) );
if ( m_iszScriptName != NULL_STRING )
ParseScriptFile();
else
Warning( "CEnvEffectsScript with no script!\n" );
}
//-----------------------------------------------------------------------------
// Spawn
//-----------------------------------------------------------------------------
void CEnvEffectsScript::Spawn()
{
Precache();
BaseClass::Spawn();
// We need a model for its animation sequences even though we don't render it
SetModel( STRING( GetModelName() ) );
AddEffects( EF_NODRAW );
SetThink( &CEnvEffectsScript::Think );
SetNextThink( gpGlobals->curtime + 0.1f );
}
void CEnvEffectsScript::Think( void )
{
StudioFrameAdvance();
DispatchAnimEvents( this );
SetNextThink( gpGlobals->curtime + 0.1f );
}
void CEnvEffectsScript::TrailEffectEvent( CEffectScriptElement *pEffect )
{
if ( pEffect->IsActive() == false )
{
//Only one type of this effect active at a time.
if ( pEffect->m_pTrail == NULL )
{
pEffect->m_pTrail = CSpriteTrail::SpriteTrailCreate( pEffect->m_szMaterial, GetAbsOrigin(), true );
pEffect->m_pTrail->FollowEntity( this );
pEffect->m_pTrail->SetTransparency( pEffect->m_iRenderType, pEffect->m_iR, pEffect->m_iG, pEffect->m_iB, pEffect->m_iA, kRenderFxNone );
pEffect->m_pTrail->SetStartWidth( pEffect->m_flScale );
if ( pEffect->m_flTextureRes < 0.0f )
{
pEffect->m_pTrail->SetTextureResolution( 1.0f / ( 16.0f * pEffect->m_flScale ) );
}
else
{
pEffect->m_pTrail->SetTextureResolution( pEffect->m_flTextureRes );
}
pEffect->m_pTrail->SetLifeTime( pEffect->m_flFadeTime );
pEffect->m_pTrail->TurnOn();
pEffect->m_pTrail->SetAttachment( this, LookupAttachment( pEffect->m_szAttachment ) );
pEffect->Activate();
}
}
}
void CEnvEffectsScript::SpriteEffectEvent( CEffectScriptElement *pEffect )
{
if ( pEffect->IsActive() == false )
{
//Only one type of this effect active at a time.
if ( pEffect->m_pSprite == NULL )
{
pEffect->m_pSprite = CSprite::SpriteCreate( pEffect->m_szMaterial, GetAbsOrigin(), true );
pEffect->m_pSprite->FollowEntity( this );
pEffect->m_pSprite->SetTransparency( pEffect->m_iRenderType, pEffect->m_iR, pEffect->m_iG, pEffect->m_iB, pEffect->m_iA, kRenderFxNone );
pEffect->m_pSprite->SetScale( pEffect->m_flScale );
pEffect->m_pSprite->TurnOn();
pEffect->m_pSprite->SetAttachment( this, LookupAttachment( pEffect->m_szAttachment ) );
pEffect->Activate();
}
}
}
void CEnvEffectsScript::HandleAnimEvent ( animevent_t *pEvent )
{
if ( pEvent->event == AE_START_SCRIPTED_EFFECT )
{
CEffectScriptElement *pCurrent = GetScriptElementByName( pEvent->options );
if ( pCurrent )
{
if ( pCurrent->m_iType == EFFECT_TYPE_TRAIL )
TrailEffectEvent( pCurrent );
else if ( pCurrent->m_iType == EFFECT_TYPE_SPRITE )
SpriteEffectEvent( pCurrent );
}
return;
}
if ( pEvent->event == AE_STOP_SCRIPTED_EFFECT )
{
CEffectScriptElement *pCurrent = GetScriptElementByName( pEvent->options );
if ( pCurrent && pCurrent->IsActive() )
{
pCurrent->Deactivate();
if ( pCurrent->m_iType == EFFECT_TYPE_TRAIL )
{
if ( pCurrent->m_bStopFollowOnKill == true )
{
Vector vOrigin;
GetAttachment( pCurrent->m_pTrail->m_nAttachment, vOrigin );
pCurrent->m_pTrail->StopFollowingEntity();
pCurrent->m_pTrail->m_hAttachedToEntity = NULL;
pCurrent->m_pTrail->m_nAttachment = 0;
pCurrent->m_pTrail->SetAbsOrigin( vOrigin);
}
pCurrent->m_pTrail->FadeAndDie( pCurrent->m_flFadeTime );
pCurrent->m_pTrail = NULL;
}
else if ( pCurrent->m_iType == EFFECT_TYPE_SPRITE )
{
if ( pCurrent->m_bStopFollowOnKill == true )
{
Vector vOrigin;
GetAttachment( pCurrent->m_pSprite->m_nAttachment, vOrigin );
pCurrent->m_pSprite->StopFollowingEntity();
pCurrent->m_pSprite->m_hAttachedToEntity = NULL;
pCurrent->m_pSprite->m_nAttachment = 0;
pCurrent->m_pSprite->SetAbsOrigin( vOrigin);
}
pCurrent->m_pSprite->FadeAndDie( pCurrent->m_flFadeTime );
pCurrent->m_pSprite = NULL;
}
}
return;
}
BaseClass::HandleAnimEvent( pEvent );
}
//-----------------------------------------------------------------------------
// Purpose: Input that sets the sequence of the entity
//-----------------------------------------------------------------------------
void CEnvEffectsScript::InputSetSequence( inputdata_t &inputdata )
{
if ( inputdata.value.StringID() != NULL_STRING )
{
int nSequence = LookupSequence( STRING( inputdata.value.StringID() ) );
if ( nSequence != ACT_INVALID )
{
SetSequence( nSequence );
ResetSequenceInfo();
SetCycle( 0.0f );
m_flPlaybackRate = 1.0f;
}
}
}
void CEnvEffectsScript::ParseScriptFile( void )
{
int length = 0;
m_ScriptElements.RemoveAll();
const char *pScriptName = GetScriptFile();
//Reset everything.
g_bUnget = false;
currenttoken = NULL;
tokencount = 0;
memset( token, 0, 1204 );
memset( name, 0, 256 );
unsigned char *buffer = (unsigned char *)UTIL_LoadFileForMe( pScriptName, &length );
if ( length <= 0 || !buffer )
{
DevMsg( 1, "CEnvEffectsScript: failed to load %s\n", pScriptName );
return;
}
currenttoken = (const char *)buffer;
LoadFromBuffer( pScriptName, (const char *)buffer );
UTIL_FreeFile( buffer );
}
void CEnvEffectsScript::LoadFromBuffer( const char *scriptfile, const char *buffer )
{
while ( 1 )
{
ParseToken();
if ( !token[0] )
{
break;
}
if ( !Q_stricmp( token, "effect" ) )
{
ParseNewEffect();
}
else
{
Warning( "CEnvEffectsScript: Unknown entry type '%s'\n", token );
break;
}
}
}
void CEnvEffectsScript::ParseNewEffect( void )
{
//Add a new effect to the list.
CEffectScriptElement NewElement;
// Effect Group Name
ParseToken();
Q_strncpy( NewElement.m_szEffectName, token, sizeof( NewElement.m_szEffectName ) );
while ( 1 )
{
ParseToken();
// Oops, part of next definition
if( IsRootCommand() )
{
Unget();
break;
}
if ( !Q_stricmp( token, "{" ) )
{
while ( 1 )
{
ParseToken();
if ( !Q_stricmp( token, "}" ) )
break;
if ( !Q_stricmp( token, "type" ) )
{
ParseToken();
if ( !Q_stricmp( token, "trail" ) )
NewElement.m_iType = EFFECT_TYPE_TRAIL;
else if ( !Q_stricmp( token, "sprite" ) )
NewElement.m_iType = EFFECT_TYPE_SPRITE;
continue;
}
if ( !Q_stricmp( token, "material" ) )
{
ParseToken();
Q_strncpy( NewElement.m_szMaterial, token, sizeof( NewElement.m_szMaterial ) );
PrecacheModel( NewElement.m_szMaterial );
continue;
}
if ( !Q_stricmp( token, "attachment" ) )
{
ParseToken();
Q_strncpy( NewElement.m_szAttachment, token, sizeof( NewElement.m_szAttachment ) );
continue;
}
if ( !Q_stricmp( token, "color" ) )
{
ParseToken();
sscanf( token, "%i %i %i %i", &NewElement.m_iR, &NewElement.m_iG, &NewElement.m_iB, &NewElement.m_iA );
continue;
}
if ( !Q_stricmp( token, "scale" ) )
{
ParseToken();
NewElement.m_flScale = atof( token );
continue;
}
if ( !Q_stricmp( token, "texturescale" ) )
{
ParseToken();
float flTextureScale = atof( token );
NewElement.m_flTextureRes = (flTextureScale > 0.0f) ? 1.0f / flTextureScale : 0.0f;
continue;
}
if ( !Q_stricmp( token, "fadetime" ) )
{
ParseToken();
NewElement.m_flFadeTime = atof( token );
continue;
}
if ( !Q_stricmp( token, "stopfollowonkill" ) )
{
ParseToken();
NewElement.m_bStopFollowOnKill = !!atoi( token );
continue;
}
}
break;
}
}
m_ScriptElements.AddToTail( NewElement );
}
CEffectScriptElement *CEnvEffectsScript::GetScriptElementByName( const char *pName )
{
for ( int i = 0; i < m_ScriptElements.Count(); i++ )
{
CEffectScriptElement *pCurrent = &m_ScriptElements.Element( i );
if ( pCurrent && !Q_stricmp( pCurrent->m_szEffectName, pName ) )
{
return pCurrent;
}
}
return NULL;
}

View File

@@ -0,0 +1,475 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//
//=============================================================================//
#include "cbase.h"
#include "entityoutput.h"
#include "TemplateEntities.h"
#include "point_template.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
#define SF_ENTMAKER_AUTOSPAWN 0x0001
#define SF_ENTMAKER_WAITFORDESTRUCTION 0x0002
#define SF_ENTMAKER_IGNOREFACING 0x0004
#define SF_ENTMAKER_CHECK_FOR_SPACE 0x0008
#define SF_ENTMAKER_CHECK_PLAYER_LOOKING 0x0010
//-----------------------------------------------------------------------------
// Purpose: An entity that mapmakers can use to ensure there's a required entity never runs out.
// i.e. physics cannisters that need to be used.
//-----------------------------------------------------------------------------
class CEnvEntityMaker : public CPointEntity
{
DECLARE_CLASS( CEnvEntityMaker, CPointEntity );
public:
DECLARE_DATADESC();
DECLARE_ENT_SCRIPTDESC();
virtual void Spawn( void );
virtual void Activate( void );
void SpawnEntity( Vector vecAlternateOrigin = vec3_invalid, QAngle vecAlternateAngles = vec3_angle );
void CheckSpawnThink( void );
void InputForceSpawn( inputdata_t &inputdata );
void InputForceSpawnAtEntityOrigin( inputdata_t &inputdata );
#ifdef MAPBASE
void InputForceSpawnAtEntityCenter( inputdata_t &inputdata );
void InputForceSpawnAtPosition( inputdata_t &inputdata );
#endif
void SpawnEntityFromScript();
void SpawnEntityAtEntityOriginFromScript(HSCRIPT hEntity);
void SpawnEntityAtNamedEntityOriginFromScript(const char* pszName);
void SpawnEntityAtLocationFromScript(const Vector& vecAlternateOrigin, const Vector& vecAlternateAngles);
private:
CPointTemplate *FindTemplate();
bool HasRoomToSpawn();
bool IsPlayerLooking();
Vector m_vecEntityMins;
Vector m_vecEntityMaxs;
EHANDLE m_hCurrentInstance;
EHANDLE m_hCurrentBlocker; // Last entity that blocked us spawning something
Vector m_vecBlockerOrigin;
// Movement after spawn
QAngle m_angPostSpawnDirection;
float m_flPostSpawnDirectionVariance;
float m_flPostSpawnSpeed;
bool m_bPostSpawnUseAngles;
string_t m_iszTemplate;
COutputEvent m_pOutputOnSpawned;
COutputEvent m_pOutputOnFailedSpawn;
#ifdef MAPBASE
COutputEHANDLE m_pOutputOutEntity;
#endif
};
BEGIN_DATADESC( CEnvEntityMaker )
// DEFINE_FIELD( m_vecEntityMins, FIELD_VECTOR ),
// DEFINE_FIELD( m_vecEntityMaxs, FIELD_VECTOR ),
DEFINE_FIELD( m_hCurrentInstance, FIELD_EHANDLE ),
DEFINE_FIELD( m_hCurrentBlocker, FIELD_EHANDLE ),
DEFINE_FIELD( m_vecBlockerOrigin, FIELD_VECTOR ),
DEFINE_KEYFIELD( m_iszTemplate, FIELD_STRING, "EntityTemplate" ),
DEFINE_KEYFIELD( m_angPostSpawnDirection, FIELD_VECTOR, "PostSpawnDirection" ),
DEFINE_KEYFIELD( m_flPostSpawnDirectionVariance, FIELD_FLOAT, "PostSpawnDirectionVariance" ),
DEFINE_KEYFIELD( m_flPostSpawnSpeed, FIELD_FLOAT, "PostSpawnSpeed" ),
DEFINE_KEYFIELD( m_bPostSpawnUseAngles, FIELD_BOOLEAN, "PostSpawnInheritAngles" ),
// Outputs
DEFINE_OUTPUT( m_pOutputOnSpawned, "OnEntitySpawned" ),
DEFINE_OUTPUT( m_pOutputOnFailedSpawn, "OnEntityFailedSpawn" ),
#ifdef MAPBASE
DEFINE_OUTPUT( m_pOutputOutEntity, "OutSpawnedEntity" ),
#endif
// Inputs
DEFINE_INPUTFUNC( FIELD_VOID, "ForceSpawn", InputForceSpawn ),
DEFINE_INPUTFUNC( FIELD_STRING, "ForceSpawnAtEntityOrigin", InputForceSpawnAtEntityOrigin ),
#ifdef MAPBASE
DEFINE_INPUTFUNC( FIELD_STRING, "ForceSpawnAtEntityCenter", InputForceSpawnAtEntityCenter ),
DEFINE_INPUTFUNC( FIELD_VECTOR, "ForceSpawnAtPosition", InputForceSpawnAtPosition ),
#endif
// Functions
DEFINE_THINKFUNC( CheckSpawnThink ),
END_DATADESC()
BEGIN_ENT_SCRIPTDESC( CEnvEntityMaker, CBaseEntity, "env_entity_maker" )
DEFINE_SCRIPTFUNC_NAMED( SpawnEntityFromScript, "SpawnEntity", "Create an entity at the location of the maker" )
DEFINE_SCRIPTFUNC_NAMED( SpawnEntityAtEntityOriginFromScript, "SpawnEntityAtEntityOrigin", "Create an entity at the location of a specified entity instance" )
DEFINE_SCRIPTFUNC_NAMED( SpawnEntityAtNamedEntityOriginFromScript, "SpawnEntityAtNamedEntityOrigin", "Create an entity at the location of a named entity" )
DEFINE_SCRIPTFUNC_NAMED( SpawnEntityAtLocationFromScript, "SpawnEntityAtLocation", "Create an entity at a specified location and orientaton, orientation is Euler angle in degrees (pitch, yaw, roll)" )
END_SCRIPTDESC()
LINK_ENTITY_TO_CLASS( env_entity_maker, CEnvEntityMaker );
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CEnvEntityMaker::Spawn( void )
{
m_vecEntityMins = vec3_origin;
m_vecEntityMaxs = vec3_origin;
m_hCurrentInstance = NULL;
m_hCurrentBlocker = NULL;
m_vecBlockerOrigin = vec3_origin;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CEnvEntityMaker::Activate( void )
{
BaseClass::Activate();
// check for valid template
if ( m_iszTemplate == NULL_STRING )
{
Warning( "env_entity_maker %s has no template entity!\n", GetEntityName().ToCStr() );
UTIL_Remove( this );
return;
}
// Spawn an instance
if ( m_spawnflags & SF_ENTMAKER_AUTOSPAWN )
{
SpawnEntity();
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
CPointTemplate *CEnvEntityMaker::FindTemplate()
{
// Find our point_template
CPointTemplate *pTemplate = dynamic_cast<CPointTemplate *>(gEntList.FindEntityByName( NULL, STRING(m_iszTemplate) ));
if ( !pTemplate )
{
Warning( "env_entity_maker %s failed to find template %s.\n", GetEntityName().ToCStr(), STRING(m_iszTemplate) );
}
return pTemplate;
}
//-----------------------------------------------------------------------------
// Purpose: Spawn an instance of the entity
//-----------------------------------------------------------------------------
void CEnvEntityMaker::SpawnEntity( Vector vecAlternateOrigin, QAngle vecAlternateAngles )
{
CPointTemplate *pTemplate = FindTemplate();
if (!pTemplate)
return;
// Spawn our template
Vector vecSpawnOrigin = GetAbsOrigin();
QAngle vecSpawnAngles = GetAbsAngles();
if( vecAlternateOrigin != vec3_invalid )
{
// We have a valid alternate origin and angles. Use those instead
// of spawning the items at my own origin and angles.
vecSpawnOrigin = vecAlternateOrigin;
vecSpawnAngles = vecAlternateAngles;
}
CUtlVector<CBaseEntity*> hNewEntities;
if ( !pTemplate->CreateInstance( vecSpawnOrigin, vecSpawnAngles, &hNewEntities ) )
return;
//Adrian: oops we couldn't spawn the entity (or entities) for some reason!
if ( hNewEntities.Count() == 0 )
return;
m_hCurrentInstance = hNewEntities[0];
// Assume it'll block us
m_hCurrentBlocker = m_hCurrentInstance;
m_vecBlockerOrigin = m_hCurrentBlocker->GetAbsOrigin();
// Store off the mins & maxs the first time we spawn
if ( m_vecEntityMins == vec3_origin )
{
m_hCurrentInstance->CollisionProp()->WorldSpaceAABB( &m_vecEntityMins, &m_vecEntityMaxs );
m_vecEntityMins -= m_hCurrentInstance->GetAbsOrigin();
m_vecEntityMaxs -= m_hCurrentInstance->GetAbsOrigin();
}
// Fire our output
m_pOutputOnSpawned.FireOutput( this, this );
// Start thinking
if ( m_spawnflags & SF_ENTMAKER_AUTOSPAWN )
{
SetThink( &CEnvEntityMaker::CheckSpawnThink );
SetNextThink( gpGlobals->curtime + 0.5f );
}
// If we have a specified post spawn speed, apply it to all spawned entities
if ( m_flPostSpawnSpeed )
{
for ( int i = 0; i < hNewEntities.Count(); i++ )
{
CBaseEntity *pEntity = hNewEntities[i];
#ifdef MAPBASE
m_pOutputOutEntity.Set(pEntity, pEntity, this);
#endif
if ( pEntity->GetMoveType() == MOVETYPE_NONE )
continue;
// Calculate a velocity for this entity
Vector vForward,vRight,vUp;
QAngle angSpawnDir( m_angPostSpawnDirection );
if ( m_bPostSpawnUseAngles )
{
if ( GetParent() )
{
angSpawnDir += GetParent()->GetAbsAngles();
}
else
{
angSpawnDir += GetAbsAngles();
}
}
AngleVectors( angSpawnDir, &vForward, &vRight, &vUp );
Vector vecShootDir = vForward;
vecShootDir += vRight * random->RandomFloat(-1, 1) * m_flPostSpawnDirectionVariance;
vecShootDir += vForward * random->RandomFloat(-1, 1) * m_flPostSpawnDirectionVariance;
vecShootDir += vUp * random->RandomFloat(-1, 1) * m_flPostSpawnDirectionVariance;
VectorNormalize( vecShootDir );
vecShootDir *= m_flPostSpawnSpeed;
// Apply it to the entity
IPhysicsObject *pPhysicsObject = pEntity->VPhysicsGetObject();
if ( pPhysicsObject )
{
pPhysicsObject->AddVelocity(&vecShootDir, NULL);
}
else
{
pEntity->SetAbsVelocity( vecShootDir );
}
}
}
#ifdef MAPBASE
else
{
for ( int i = 0; i < hNewEntities.Count(); i++ )
{
m_pOutputOutEntity.Set(hNewEntities[i], hNewEntities[i], this);
}
}
#endif
pTemplate->CreationComplete( hNewEntities );
}
//-----------------------------------------------------------------------------
// Purpose: Spawn an instance of the entity
//-----------------------------------------------------------------------------
void CEnvEntityMaker::SpawnEntityFromScript()
{
SpawnEntity();
}
//-----------------------------------------------------------------------------
// Purpose: Spawn an instance of the entity
//-----------------------------------------------------------------------------
void CEnvEntityMaker::SpawnEntityAtEntityOriginFromScript( HSCRIPT hEntity )
{
CBaseEntity *pTargetEntity = ToEnt( hEntity );
if ( pTargetEntity )
{
SpawnEntity( pTargetEntity->GetAbsOrigin(), pTargetEntity->GetAbsAngles() );
}
}
//-----------------------------------------------------------------------------
// Purpose: Spawn an instance of the entity
//-----------------------------------------------------------------------------
void CEnvEntityMaker::SpawnEntityAtNamedEntityOriginFromScript( const char *pszName )
{
CBaseEntity *pTargetEntity = gEntList.FindEntityByName( NULL, pszName, this, NULL, NULL );
if( pTargetEntity )
{
SpawnEntity( pTargetEntity->GetAbsOrigin(), pTargetEntity->GetAbsAngles() );
}
}
//-----------------------------------------------------------------------------
// Purpose: Spawn an instance of the entity
//-----------------------------------------------------------------------------
void CEnvEntityMaker::SpawnEntityAtLocationFromScript( const Vector &vecAlternateOrigin, const Vector &vecAlternateAngles )
{
SpawnEntity( vecAlternateOrigin, *((QAngle *)&vecAlternateAngles) );
}
//-----------------------------------------------------------------------------
// Purpose: Returns whether or not the template entities can fit if spawned.
// Input : pBlocker - Returns blocker unless NULL.
//-----------------------------------------------------------------------------
bool CEnvEntityMaker::HasRoomToSpawn()
{
// Do we have a blocker from last time?
if ( m_hCurrentBlocker )
{
// If it hasn't moved, abort immediately
if ( m_vecBlockerOrigin == m_hCurrentBlocker->GetAbsOrigin() )
{
return false;
}
}
// Check to see if there's enough room to spawn
trace_t tr;
UTIL_TraceHull( GetAbsOrigin(), GetAbsOrigin(), m_vecEntityMins, m_vecEntityMaxs, MASK_SOLID, this, COLLISION_GROUP_NONE, &tr );
if ( tr.m_pEnt || tr.startsolid )
{
// Store off our blocker to check later
m_hCurrentBlocker = tr.m_pEnt;
if ( m_hCurrentBlocker )
{
m_vecBlockerOrigin = m_hCurrentBlocker->GetAbsOrigin();
}
return false;
}
return true;
}
//-----------------------------------------------------------------------------
// Purpose: Returns true if the player is looking towards us.
//-----------------------------------------------------------------------------
bool CEnvEntityMaker::IsPlayerLooking()
{
for ( int i = 1; i <= gpGlobals->maxClients; i++ )
{
CBasePlayer *pPlayer = UTIL_PlayerByIndex( i );
if ( pPlayer )
{
// Only spawn if the player's looking away from me
Vector vLookDir = pPlayer->EyeDirection3D();
Vector vTargetDir = GetAbsOrigin() - pPlayer->EyePosition();
VectorNormalize( vTargetDir );
float fDotPr = DotProduct( vLookDir,vTargetDir );
if ( fDotPr > 0 )
return true;
}
}
return false;
}
//-----------------------------------------------------------------------------
// Purpose: Check to see if we should spawn another instance
//-----------------------------------------------------------------------------
void CEnvEntityMaker::CheckSpawnThink( void )
{
SetNextThink( gpGlobals->curtime + 0.5f );
// Do we have an instance?
if ( m_hCurrentInstance )
{
// If Wait-For-Destruction is set, abort immediately
if ( m_spawnflags & SF_ENTMAKER_WAITFORDESTRUCTION )
return;
}
// Check to see if there's enough room to spawn
if ( !HasRoomToSpawn() )
return;
// We're clear, now check to see if the player's looking
if ( !( HasSpawnFlags( SF_ENTMAKER_IGNOREFACING ) ) && IsPlayerLooking() )
return;
// Clear, no player watching, so spawn!
SpawnEntity();
}
//-----------------------------------------------------------------------------
// Purpose: Spawns the entities, checking for space if flagged to do so.
//-----------------------------------------------------------------------------
void CEnvEntityMaker::InputForceSpawn( inputdata_t &inputdata )
{
CPointTemplate *pTemplate = FindTemplate();
if (!pTemplate)
return;
if ( HasSpawnFlags( SF_ENTMAKER_CHECK_FOR_SPACE ) && !HasRoomToSpawn() )
{
m_pOutputOnFailedSpawn.FireOutput( this, this );
return;
}
if ( HasSpawnFlags( SF_ENTMAKER_CHECK_PLAYER_LOOKING ) && IsPlayerLooking() )
{
m_pOutputOnFailedSpawn.FireOutput( this, this );
return;
}
SpawnEntity();
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CEnvEntityMaker::InputForceSpawnAtEntityOrigin( inputdata_t &inputdata )
{
CBaseEntity *pTargetEntity = gEntList.FindEntityByName( NULL, inputdata.value.String(), this, inputdata.pActivator, inputdata.pCaller );
if( pTargetEntity )
{
SpawnEntity( pTargetEntity->GetAbsOrigin(), pTargetEntity->GetAbsAngles() );
}
}
#ifdef MAPBASE
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CEnvEntityMaker::InputForceSpawnAtEntityCenter( inputdata_t &inputdata )
{
CBaseEntity *pTargetEntity = gEntList.FindEntityByName( NULL, inputdata.value.String(), this, inputdata.pActivator, inputdata.pCaller );
if( pTargetEntity )
{
SpawnEntity( pTargetEntity->WorldSpaceCenter(), pTargetEntity->GetAbsAngles() );
}
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CEnvEntityMaker::InputForceSpawnAtPosition(inputdata_t &inputdata)
{
Vector vecPos;
inputdata.value.Vector3D(vecPos);
if (vecPos != vec3_origin && vecPos.IsValid())
{
SpawnEntity(vecPos, GetLocalAngles());
}
}
#endif // MAPBASE

View File

@@ -0,0 +1,336 @@
//========= Copyright 1996-2010, Valve Corporation, All rights reserved. ============//
//
// Purpose: global dynamic light. Ported from Insolence's port of Alien Swarm's env_global_light.
//
// $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 : Sunlight shadow control entity
//------------------------------------------------------------------------------
class CGlobalLight : public CBaseEntity
{
public:
DECLARE_CLASS( CGlobalLight, CBaseEntity );
CGlobalLight();
void Spawn( void );
bool KeyValue( const char *szKeyName, const char *szValue );
virtual bool GetKeyValue( const char *szKeyName, char *szValue, int iMaxLen );
int UpdateTransmitState();
// Inputs
void InputSetAngles( inputdata_t &inputdata );
void InputEnable( inputdata_t &inputdata );
void InputDisable( inputdata_t &inputdata );
void InputSetTexture( inputdata_t &inputdata );
void InputSetEnableShadows( inputdata_t &inputdata );
void InputSetLightColor( inputdata_t &inputdata );
#ifdef MAPBASE
void InputSetBrightness( inputdata_t &inputdata );
void InputSetColorTransitionTime( inputdata_t &inputdata );
void InputSetXOffset( inputdata_t &inputdata ) { m_flEastOffset = inputdata.value.Float(); }
void InputSetYOffset( inputdata_t &inputdata ) { m_flForwardOffset = inputdata.value.Float(); }
void InputSetOrthoSize( inputdata_t &inputdata ) { m_flOrthoSize = inputdata.value.Float(); }
void InputSetDistance( inputdata_t &inputdata ) { m_flSunDistance = inputdata.value.Float(); }
void InputSetFOV( inputdata_t &inputdata ) { m_flFOV = inputdata.value.Float(); }
void InputSetNearZDistance( inputdata_t &inputdata ) { m_flNearZ = inputdata.value.Float(); }
void InputSetNorthOffset( inputdata_t &inputdata ) { m_flNorthOffset = inputdata.value.Float(); }
#endif
virtual int ObjectCaps( void ) { return BaseClass::ObjectCaps() & ~FCAP_ACROSS_TRANSITION; }
DECLARE_SERVERCLASS();
DECLARE_DATADESC();
private:
CNetworkVector( m_shadowDirection );
CNetworkVar( bool, m_bEnabled );
CNetworkString( m_TextureName, MAX_PATH );
#ifdef MAPBASE
CNetworkVar( int, m_nSpotlightTextureFrame );
#endif
CNetworkColor32( m_LightColor );
#ifdef MAPBASE
CNetworkVar( float, m_flBrightnessScale );
#endif
CNetworkVar( float, m_flColorTransitionTime );
CNetworkVar( float, m_flSunDistance );
CNetworkVar( float, m_flFOV );
CNetworkVar( float, m_flNearZ );
CNetworkVar( float, m_flNorthOffset );
#ifdef MAPBASE
CNetworkVar( float, m_flEastOffset ); // xoffset
CNetworkVar( float, m_flForwardOffset ); // yoffset
CNetworkVar( float, m_flOrthoSize );
#endif
CNetworkVar( bool, m_bEnableShadows );
};
LINK_ENTITY_TO_CLASS(env_global_light, CGlobalLight);
BEGIN_DATADESC( CGlobalLight )
DEFINE_KEYFIELD( m_bEnabled, FIELD_BOOLEAN, "enabled" ),
DEFINE_AUTO_ARRAY_KEYFIELD( m_TextureName, FIELD_CHARACTER, "texturename" ),
#ifdef MAPBASE
DEFINE_KEYFIELD( m_nSpotlightTextureFrame, FIELD_INTEGER, "textureframe" ),
#endif
DEFINE_KEYFIELD( m_flSunDistance, FIELD_FLOAT, "distance" ),
DEFINE_KEYFIELD( m_flFOV, FIELD_FLOAT, "fov" ),
DEFINE_KEYFIELD( m_flNearZ, FIELD_FLOAT, "nearz" ),
DEFINE_KEYFIELD( m_flNorthOffset, FIELD_FLOAT, "northoffset" ),
#ifdef MAPBASE
DEFINE_KEYFIELD( m_flEastOffset, FIELD_FLOAT, "eastoffset" ),
DEFINE_KEYFIELD( m_flForwardOffset, FIELD_FLOAT, "forwardoffset" ),
DEFINE_KEYFIELD( m_flOrthoSize, FIELD_FLOAT, "orthosize" ),
#endif
DEFINE_KEYFIELD( m_bEnableShadows, FIELD_BOOLEAN, "enableshadows" ),
DEFINE_FIELD( m_LightColor, FIELD_COLOR32 ),
#ifdef MAPBASE
DEFINE_KEYFIELD( m_flBrightnessScale, FIELD_FLOAT, "brightnessscale" ),
#endif
DEFINE_KEYFIELD( m_flColorTransitionTime, FIELD_FLOAT, "colortransitiontime" ),
DEFINE_FIELD( m_shadowDirection, FIELD_VECTOR ),
// Inputs
#ifdef MAPBASE
DEFINE_INPUTFUNC( FIELD_FLOAT, "SetXOffset", InputSetXOffset ),
DEFINE_INPUTFUNC( FIELD_FLOAT, "SetYOffset", InputSetYOffset ),
DEFINE_INPUTFUNC( FIELD_FLOAT, "SetOrthoSize", InputSetOrthoSize ),
DEFINE_INPUTFUNC( FIELD_FLOAT, "SetDistance", InputSetDistance ),
DEFINE_INPUTFUNC( FIELD_FLOAT, "SetFOV", InputSetFOV ),
DEFINE_INPUTFUNC( FIELD_FLOAT, "SetNearZDistance", InputSetNearZDistance ),
DEFINE_INPUTFUNC( FIELD_FLOAT, "SetNorthOffset", InputSetNorthOffset ),
#else
DEFINE_INPUT( m_flSunDistance, FIELD_FLOAT, "SetDistance" ),
DEFINE_INPUT( m_flFOV, FIELD_FLOAT, "SetFOV" ),
DEFINE_INPUT( m_flNearZ, FIELD_FLOAT, "SetNearZDistance" ),
DEFINE_INPUT( m_flNorthOffset, FIELD_FLOAT, "SetNorthOffset" ),
#endif
DEFINE_INPUTFUNC( FIELD_COLOR32, "LightColor", InputSetLightColor ),
DEFINE_INPUTFUNC( FIELD_STRING, "SetAngles", InputSetAngles ),
DEFINE_INPUTFUNC( FIELD_VOID, "Enable", InputEnable ),
DEFINE_INPUTFUNC( FIELD_VOID, "Disable", InputDisable ),
DEFINE_INPUTFUNC( FIELD_STRING, "SetTexture", InputSetTexture ),
DEFINE_INPUTFUNC( FIELD_BOOLEAN, "EnableShadows", InputSetEnableShadows ),
#ifdef MAPBASE
DEFINE_INPUTFUNC( FIELD_FLOAT, "SetBrightness", InputSetBrightness ),
DEFINE_INPUTFUNC( FIELD_FLOAT, "SetColorTransitionTime", InputSetColorTransitionTime ),
#endif
END_DATADESC()
IMPLEMENT_SERVERCLASS_ST_NOBASE(CGlobalLight, DT_GlobalLight)
SendPropVector(SENDINFO(m_shadowDirection), -1, SPROP_NOSCALE ),
SendPropBool(SENDINFO(m_bEnabled) ),
SendPropString(SENDINFO(m_TextureName)),
#ifdef MAPBASE
SendPropInt(SENDINFO(m_nSpotlightTextureFrame)),
#endif
/*SendPropInt(SENDINFO (m_LightColor ), 32, SPROP_UNSIGNED, SendProxy_Color32ToInt32 ),*/
SendPropInt(SENDINFO (m_LightColor ), 32, SPROP_UNSIGNED, SendProxy_Color32ToInt ),
#ifdef MAPBASE
SendPropFloat( SENDINFO( m_flBrightnessScale ) ),
#endif
SendPropFloat( SENDINFO( m_flColorTransitionTime ) ),
SendPropFloat(SENDINFO(m_flSunDistance), 0, SPROP_NOSCALE ),
SendPropFloat(SENDINFO(m_flFOV), 0, SPROP_NOSCALE ),
SendPropFloat(SENDINFO(m_flNearZ), 0, SPROP_NOSCALE ),
SendPropFloat(SENDINFO(m_flNorthOffset), 0, SPROP_NOSCALE ),
#ifdef MAPBASE
SendPropFloat(SENDINFO(m_flEastOffset), 0, SPROP_NOSCALE ),
SendPropFloat(SENDINFO(m_flForwardOffset), 0, SPROP_NOSCALE ),
SendPropFloat(SENDINFO(m_flOrthoSize), 0, SPROP_NOSCALE ),
#endif
SendPropBool( SENDINFO( m_bEnableShadows ) ),
END_SEND_TABLE()
CGlobalLight::CGlobalLight()
{
#if defined( _X360 )
Q_strcpy( m_TextureName.GetForModify(), "effects/flashlight_border" );
#else
Q_strcpy( m_TextureName.GetForModify(), "effects/flashlight001" );
#endif
#ifdef MAPBASE
m_LightColor.Init( 255, 255, 255, 255 );
#else
m_LightColor.Init( 255, 255, 255, 1 );
#endif
m_flColorTransitionTime = 0.5f;
m_flSunDistance = 10000.0f;
m_flFOV = 5.0f;
m_bEnableShadows = false;
#ifdef MAPBASE
m_nSpotlightTextureFrame = 0;
m_flBrightnessScale = 1.0f;
m_flOrthoSize = 1000.0f;
#endif
m_bEnabled = true;
}
//------------------------------------------------------------------------------
// Purpose : Send even though we don't have a model
//------------------------------------------------------------------------------
int CGlobalLight::UpdateTransmitState()
{
// ALWAYS transmit to all clients.
return SetTransmitState( FL_EDICT_ALWAYS );
}
bool CGlobalLight::KeyValue( const char *szKeyName, const char *szValue )
{
#ifdef MAPBASE
if ( FStrEq( szKeyName, "lightcolor" ) || FStrEq( szKeyName, "color" ) )
#else
if ( FStrEq( szKeyName, "color" ) )
#endif
{
float tmp[4];
UTIL_StringToFloatArray( tmp, 4, szValue );
m_LightColor.SetR( tmp[0] );
m_LightColor.SetG( tmp[1] );
m_LightColor.SetB( tmp[2] );
m_LightColor.SetA( tmp[3] );
}
else if ( FStrEq( szKeyName, "angles" ) )
{
QAngle angles;
UTIL_StringToVector( angles.Base(), szValue );
if (angles == vec3_angle)
{
angles.Init( 80, 30, 0 );
}
Vector vForward;
AngleVectors( angles, &vForward );
m_shadowDirection = vForward;
return true;
}
else if ( FStrEq( szKeyName, "texturename" ) )
{
#if defined( _X360 )
if ( Q_strcmp( szValue, "effects/flashlight001" ) == 0 )
{
// Use this as the default for Xbox
Q_strcpy( m_TextureName.GetForModify(), "effects/flashlight_border" );
}
else
{
Q_strcpy( m_TextureName.GetForModify(), szValue );
}
#else
Q_strcpy( m_TextureName.GetForModify(), szValue );
#endif
}
else if ( FStrEq( szKeyName, "StartDisabled" ) )
{
m_bEnabled.Set( atoi( szValue ) <= 0 );
}
return BaseClass::KeyValue( szKeyName, szValue );
}
bool CGlobalLight::GetKeyValue( const char *szKeyName, char *szValue, int iMaxLen )
{
if ( FStrEq( szKeyName, "color" ) )
{
Q_snprintf( szValue, iMaxLen, "%d %d %d %d", m_LightColor.GetR(), m_LightColor.GetG(), m_LightColor.GetB(), m_LightColor.GetA() );
return true;
}
else if ( FStrEq( szKeyName, "texturename" ) )
{
Q_snprintf( szValue, iMaxLen, "%s", m_TextureName.Get() );
return true;
}
else if ( FStrEq( szKeyName, "StartDisabled" ) )
{
Q_snprintf( szValue, iMaxLen, "%d", !m_bEnabled.Get() );
return true;
}
return BaseClass::GetKeyValue( szKeyName, szValue, iMaxLen );
}
//------------------------------------------------------------------------------
// Purpose :
//------------------------------------------------------------------------------
void CGlobalLight::Spawn( void )
{
Precache();
SetSolid( SOLID_NONE );
}
//------------------------------------------------------------------------------
// Input values
//------------------------------------------------------------------------------
void CGlobalLight::InputSetAngles( inputdata_t &inputdata )
{
const char *pAngles = inputdata.value.String();
QAngle angles;
UTIL_StringToVector( angles.Base(), pAngles );
Vector vTemp;
AngleVectors( angles, &vTemp );
m_shadowDirection = vTemp;
}
//------------------------------------------------------------------------------
// Purpose : Input handlers
//------------------------------------------------------------------------------
void CGlobalLight::InputEnable( inputdata_t &inputdata )
{
m_bEnabled = true;
}
void CGlobalLight::InputDisable( inputdata_t &inputdata )
{
m_bEnabled = false;
}
void CGlobalLight::InputSetTexture( inputdata_t &inputdata )
{
Q_strcpy( m_TextureName.GetForModify(), inputdata.value.String() );
}
void CGlobalLight::InputSetEnableShadows( inputdata_t &inputdata )
{
m_bEnableShadows = inputdata.value.Bool();
}
void CGlobalLight::InputSetLightColor( inputdata_t &inputdata )
{
m_LightColor = inputdata.value.Color32();
}
#ifdef MAPBASE
void CGlobalLight::InputSetBrightness( inputdata_t &inputdata )
{
m_flBrightnessScale = inputdata.value.Float();
}
void CGlobalLight::InputSetColorTransitionTime( inputdata_t &inputdata )
{
m_flColorTransitionTime = inputdata.value.Float();
}
#endif

View File

@@ -0,0 +1,229 @@
//========= Copyright <20> 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose: An entity for creating instructor hints entirely with map logic
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "baseentity.h"
#include "world.h"
#ifdef INFESTED_DLL
#include "asw_marine.h"
#include "asw_player.h"
#endif
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
class CEnvInstructorHint : public CPointEntity
{
public:
DECLARE_CLASS( CEnvInstructorHint, CPointEntity );
DECLARE_DATADESC();
private:
void InputShowHint( inputdata_t &inputdata );
void InputEndHint( inputdata_t &inputdata );
#ifdef MAPBASE
void InputSetCaption( inputdata_t &inputdata ) { m_iszCaption = inputdata.value.StringID(); }
#endif
string_t m_iszReplace_Key;
string_t m_iszHintTargetEntity;
int m_iTimeout;
string_t m_iszIcon_Onscreen;
string_t m_iszIcon_Offscreen;
string_t m_iszCaption;
string_t m_iszActivatorCaption;
color32 m_Color;
float m_fIconOffset;
float m_fRange;
uint8 m_iPulseOption;
uint8 m_iAlphaOption;
uint8 m_iShakeOption;
bool m_bStatic;
bool m_bNoOffscreen;
bool m_bForceCaption;
string_t m_iszBinding;
bool m_bAllowNoDrawTarget;
bool m_bLocalPlayerOnly;
#ifdef MAPBASE
string_t m_iszStartSound;
int m_iHintTargetPos;
#endif
};
LINK_ENTITY_TO_CLASS( env_instructor_hint, CEnvInstructorHint );
BEGIN_DATADESC( CEnvInstructorHint )
DEFINE_KEYFIELD( m_iszReplace_Key, FIELD_STRING, "hint_replace_key" ),
DEFINE_KEYFIELD( m_iszHintTargetEntity, FIELD_STRING, "hint_target" ),
DEFINE_KEYFIELD( m_iTimeout, FIELD_INTEGER, "hint_timeout" ),
DEFINE_KEYFIELD( m_iszIcon_Onscreen, FIELD_STRING, "hint_icon_onscreen" ),
DEFINE_KEYFIELD( m_iszIcon_Offscreen, FIELD_STRING, "hint_icon_offscreen" ),
DEFINE_KEYFIELD( m_iszCaption, FIELD_STRING, "hint_caption" ),
DEFINE_KEYFIELD( m_iszActivatorCaption, FIELD_STRING, "hint_activator_caption" ),
DEFINE_KEYFIELD( m_Color, FIELD_COLOR32, "hint_color" ),
DEFINE_KEYFIELD( m_fIconOffset, FIELD_FLOAT, "hint_icon_offset" ),
DEFINE_KEYFIELD( m_fRange, FIELD_FLOAT, "hint_range" ),
DEFINE_KEYFIELD( m_iPulseOption, FIELD_CHARACTER, "hint_pulseoption" ),
DEFINE_KEYFIELD( m_iAlphaOption, FIELD_CHARACTER, "hint_alphaoption" ),
DEFINE_KEYFIELD( m_iShakeOption, FIELD_CHARACTER, "hint_shakeoption" ),
DEFINE_KEYFIELD( m_bStatic, FIELD_BOOLEAN, "hint_static" ),
DEFINE_KEYFIELD( m_bNoOffscreen, FIELD_BOOLEAN, "hint_nooffscreen" ),
DEFINE_KEYFIELD( m_bForceCaption, FIELD_BOOLEAN, "hint_forcecaption" ),
DEFINE_KEYFIELD( m_iszBinding, FIELD_STRING, "hint_binding" ),
DEFINE_KEYFIELD( m_bAllowNoDrawTarget, FIELD_BOOLEAN, "hint_allow_nodraw_target" ),
DEFINE_KEYFIELD( m_bLocalPlayerOnly, FIELD_BOOLEAN, "hint_local_player_only" ),
#ifdef MAPBASE
DEFINE_KEYFIELD( m_iszStartSound, FIELD_STRING, "hint_start_sound" ),
DEFINE_KEYFIELD( m_iHintTargetPos, FIELD_INTEGER, "hint_target_pos" ),
#endif
DEFINE_INPUTFUNC( FIELD_STRING, "ShowHint", InputShowHint ),
DEFINE_INPUTFUNC( FIELD_VOID, "EndHint", InputEndHint ),
#ifdef MAPBASE
DEFINE_INPUTFUNC( FIELD_STRING, "SetCaption", InputSetCaption ),
#endif
END_DATADESC()
#define LOCATOR_ICON_FX_PULSE_SLOW 0x00000001
#define LOCATOR_ICON_FX_ALPHA_SLOW 0x00000008
#define LOCATOR_ICON_FX_SHAKE_NARROW 0x00000040
#define LOCATOR_ICON_FX_STATIC 0x00000100 // This icon draws at a fixed location on the HUD.
//-----------------------------------------------------------------------------
// Purpose: Input handler for showing the message and/or playing the sound.
//-----------------------------------------------------------------------------
void CEnvInstructorHint::InputShowHint( inputdata_t &inputdata )
{
IGameEvent * event = gameeventmanager->CreateEvent( "instructor_server_hint_create", false );
if ( event )
{
CBaseEntity *pTargetEntity = gEntList.FindEntityByName( NULL, m_iszHintTargetEntity );
if( pTargetEntity == NULL && !m_bStatic )
pTargetEntity = inputdata.pActivator;
if( pTargetEntity == NULL )
pTargetEntity = GetWorldEntity();
char szColorString[128];
Q_snprintf( szColorString, sizeof( szColorString ), "%.3d,%.3d,%.3d", m_Color.r, m_Color.g, m_Color.b );
int iFlags = 0;
iFlags |= (m_iPulseOption == 0) ? 0 : (LOCATOR_ICON_FX_PULSE_SLOW << (m_iPulseOption - 1));
iFlags |= (m_iAlphaOption == 0) ? 0 : (LOCATOR_ICON_FX_ALPHA_SLOW << (m_iAlphaOption - 1));
iFlags |= (m_iShakeOption == 0) ? 0 : (LOCATOR_ICON_FX_SHAKE_NARROW << (m_iShakeOption - 1));
iFlags |= m_bStatic ? LOCATOR_ICON_FX_STATIC : 0;
CBasePlayer *pActivator = NULL;
bool bFilterByActivator = m_bLocalPlayerOnly;
#ifdef INFESTED_DLL
CASW_Marine *pMarine = dynamic_cast<CASW_Marine*>( inputdata.pActivator );
if ( pMarine )
{
pActivator = pMarine->GetCommander();
}
#else
if ( inputdata.value.StringID() != NULL_STRING )
{
CBaseEntity *pTarget = gEntList.FindEntityByName( NULL, inputdata.value.String() );
pActivator = dynamic_cast<CBasePlayer*>( pTarget );
if ( pActivator )
{
bFilterByActivator = true;
}
}
else
{
if ( GameRules()->IsMultiplayer() == false )
{
pActivator = UTIL_GetLocalPlayer();
}
else
{
Warning( "Failed to play server side instructor hint: no player specified for hint\n" );
Assert( 0 );
}
}
#endif
const char *pActivatorCaption = m_iszActivatorCaption.ToCStr();
if ( !pActivatorCaption || pActivatorCaption[ 0 ] == '\0' )
{
pActivatorCaption = m_iszCaption.ToCStr();
}
event->SetString( "hint_name", GetEntityName().ToCStr() );
event->SetString( "hint_replace_key", m_iszReplace_Key.ToCStr() );
event->SetInt( "hint_target", pTargetEntity->entindex() );
event->SetInt( "hint_activator_userid", ( pActivator ? pActivator->GetUserID() : 0 ) );
event->SetInt( "hint_timeout", m_iTimeout );
event->SetString( "hint_icon_onscreen", m_iszIcon_Onscreen.ToCStr() );
event->SetString( "hint_icon_offscreen", m_iszIcon_Offscreen.ToCStr() );
event->SetString( "hint_caption", m_iszCaption.ToCStr() );
event->SetString( "hint_activator_caption", pActivatorCaption );
event->SetString( "hint_color", szColorString );
event->SetFloat( "hint_icon_offset", m_fIconOffset );
event->SetFloat( "hint_range", m_fRange );
event->SetInt( "hint_flags", iFlags );
event->SetString( "hint_binding", m_iszBinding.ToCStr() );
event->SetBool( "hint_allow_nodraw_target", m_bAllowNoDrawTarget );
event->SetBool( "hint_nooffscreen", m_bNoOffscreen );
event->SetBool( "hint_forcecaption", m_bForceCaption );
event->SetBool( "hint_local_player_only", bFilterByActivator );
#ifdef MAPBASE
event->SetString( "hint_start_sound", m_iszStartSound.ToCStr() );
event->SetInt( "hint_target_pos", m_iHintTargetPos );
#endif
gameeventmanager->FireEvent( event );
}
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CEnvInstructorHint::InputEndHint( inputdata_t &inputdata )
{
IGameEvent * event = gameeventmanager->CreateEvent( "instructor_server_hint_stop", false );
if ( event )
{
event->SetString( "hint_name", GetEntityName().ToCStr() );
gameeventmanager->FireEvent( event );
}
}
//-----------------------------------------------------------------------------
// Purpose: A generic target entity that gets replicated to the client for instructor hint targetting
//-----------------------------------------------------------------------------
class CInfoInstructorHintTarget : public CPointEntity
{
public:
DECLARE_CLASS( CInfoInstructorHintTarget, CPointEntity );
virtual int UpdateTransmitState( void ) // set transmit filter to transmit always
{
return SetTransmitState( FL_EDICT_ALWAYS );
}
DECLARE_DATADESC();
};
LINK_ENTITY_TO_CLASS( info_target_instructor_hint, CInfoInstructorHintTarget );
BEGIN_DATADESC( CInfoInstructorHintTarget )
END_DATADESC()

View File

@@ -0,0 +1,193 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "baseanimating.h"
#include "SkyCamera.h"
#include "studio.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
// HACK HACK: Must match cl_dll/cl_animevent.h!!!!
#define CL_EVENT_SPRITEGROUP_CREATE 6002
//-----------------------------------------------------------------------------
// An entity which emits other entities at points
//-----------------------------------------------------------------------------
class CEnvParticleScript : public CBaseAnimating
{
public:
DECLARE_CLASS( CEnvParticleScript, CBaseAnimating );
DECLARE_SERVERCLASS();
DECLARE_DATADESC();
CEnvParticleScript();
virtual void Precache();
virtual void Spawn();
virtual void Activate();
virtual int UpdateTransmitState();
void InputSetSequence( inputdata_t &inputdata );
private:
void PrecacheAnimationEventMaterials();
CNetworkVar( float, m_flSequenceScale );
};
//-----------------------------------------------------------------------------
// Save/load
//-----------------------------------------------------------------------------
BEGIN_DATADESC( CEnvParticleScript )
DEFINE_FIELD( m_flSequenceScale, FIELD_FLOAT ),
// Inputs
DEFINE_INPUTFUNC( FIELD_STRING, "SetSequence", InputSetSequence ),
END_DATADESC()
LINK_ENTITY_TO_CLASS( env_particlescript, CEnvParticleScript );
//-----------------------------------------------------------------------------
// Datatable
//-----------------------------------------------------------------------------
IMPLEMENT_SERVERCLASS_ST( CEnvParticleScript, DT_EnvParticleScript )
SendPropFloat(SENDINFO(m_flSequenceScale), 0, SPROP_NOSCALE),
END_SEND_TABLE()
//-----------------------------------------------------------------------------
// Constructor
//-----------------------------------------------------------------------------
CEnvParticleScript::CEnvParticleScript()
{
UseClientSideAnimation();
}
void CEnvParticleScript::PrecacheAnimationEventMaterials()
{
CStudioHdr *hdr = GetModelPtr();
if ( hdr )
{
int numseq = hdr->GetNumSeq();
for ( int i = 0; i < numseq; ++i )
{
mstudioseqdesc_t& seqdesc = hdr->pSeqdesc( i );
int ecount = seqdesc.numevents;
for ( int j = 0 ; j < ecount; ++j )
{
const mstudioevent_t* event = seqdesc.pEvent( j );
if ( event->event == CL_EVENT_SPRITEGROUP_CREATE )
{
char pAttachmentName[256];
char pSpriteName[256];
int nArgs = sscanf( event->pszOptions(), "%255s %255s", pAttachmentName, pSpriteName );
if ( nArgs == 2 )
{
PrecacheMaterial( pSpriteName );
}
}
}
}
}
}
//-----------------------------------------------------------------------------
// Precache
//-----------------------------------------------------------------------------
void CEnvParticleScript::Precache()
{
BaseClass::Precache();
PrecacheModel( STRING( GetModelName() ) );
// We need a model for its animation sequences even though we don't render it
SetModel( STRING( GetModelName() ) );
PrecacheAnimationEventMaterials();
}
//-----------------------------------------------------------------------------
// Spawn
//-----------------------------------------------------------------------------
void CEnvParticleScript::Spawn()
{
Precache();
BaseClass::Spawn();
AddEffects( EF_NOSHADOW );
// We need a model for its animation sequences even though we don't render it
SetModel( STRING( GetModelName() ) );
}
//-----------------------------------------------------------------------------
// Activate
//-----------------------------------------------------------------------------
void CEnvParticleScript::Activate()
{
BaseClass::Activate();
DetectInSkybox();
CSkyCamera *pCamera = GetEntitySkybox();
if ( pCamera )
{
float flSkyboxScale = pCamera->m_skyboxData.scale;
if ( flSkyboxScale == 0.0f )
{
flSkyboxScale = 1.0f;
}
m_flSequenceScale = flSkyboxScale;
}
else
{
m_flSequenceScale = 1.0f;
}
m_flPlaybackRate = 1.0f;
}
//-----------------------------------------------------------------------------
// Should we transmit it to the client?
//-----------------------------------------------------------------------------
int CEnvParticleScript::UpdateTransmitState()
{
if ( IsEffectActive( EF_NODRAW ) )
{
return SetTransmitState( FL_EDICT_DONTSEND );
}
if ( IsEFlagSet( EFL_IN_SKYBOX ) )
{
return SetTransmitState( FL_EDICT_ALWAYS );
}
return SetTransmitState( FL_EDICT_PVSCHECK );
}
//-----------------------------------------------------------------------------
// Purpose: Input that sets the sequence of the entity
//-----------------------------------------------------------------------------
void CEnvParticleScript::InputSetSequence( inputdata_t &inputdata )
{
if ( inputdata.value.StringID() != NULL_STRING )
{
int nSequence = LookupSequence( STRING( inputdata.value.StringID() ) );
if ( nSequence != ACT_INVALID )
{
SetSequence( nSequence );
}
}
}

View File

@@ -0,0 +1,135 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#include "cbase.h"
#include "decals.h"
#include "env_player_surface_trigger.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
LINK_ENTITY_TO_CLASS( env_player_surface_trigger, CEnvPlayerSurfaceTrigger );
BEGIN_DATADESC( CEnvPlayerSurfaceTrigger )
DEFINE_KEYFIELD( m_iTargetGameMaterial, FIELD_INTEGER, "gamematerial" ),
DEFINE_FIELD( m_iCurrentGameMaterial, FIELD_INTEGER ),
DEFINE_FIELD( m_bDisabled, FIELD_BOOLEAN ),
DEFINE_THINKFUNC( UpdateMaterialThink ),
// Inputs
DEFINE_INPUTFUNC( FIELD_VOID, "Disable", InputDisable ),
DEFINE_INPUTFUNC( FIELD_VOID, "Enable", InputEnable ),
// Outputs
DEFINE_OUTPUT(m_OnSurfaceChangedToTarget, "OnSurfaceChangedToTarget"),
DEFINE_OUTPUT(m_OnSurfaceChangedFromTarget, "OnSurfaceChangedFromTarget"),
END_DATADESC()
// Global list of surface triggers
CUtlVector< CHandle<CEnvPlayerSurfaceTrigger> > g_PlayerSurfaceTriggers;
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
CEnvPlayerSurfaceTrigger::~CEnvPlayerSurfaceTrigger( void )
{
g_PlayerSurfaceTriggers.FindAndRemove( this );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CEnvPlayerSurfaceTrigger::Spawn( void )
{
SetSolid( SOLID_NONE );
SetMoveType( MOVETYPE_NONE );
m_iCurrentGameMaterial = 0;
m_bDisabled = false;
g_PlayerSurfaceTriggers.AddToTail( this );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CEnvPlayerSurfaceTrigger::OnRestore( void )
{
BaseClass::OnRestore();
g_PlayerSurfaceTriggers.AddToTail( this );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CEnvPlayerSurfaceTrigger::SetPlayerSurface( CBasePlayer *pPlayer, char gameMaterial )
{
// Ignore players in the air (stops bunny hoppers escaping triggers)
if ( gameMaterial == 0 )
return;
// Loop through the surface triggers and tell them all about the change
int iCount = g_PlayerSurfaceTriggers.Count();
for ( int i = 0; i < iCount; i++ )
{
g_PlayerSurfaceTriggers[i]->PlayerSurfaceChanged( pPlayer, gameMaterial );
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CEnvPlayerSurfaceTrigger::PlayerSurfaceChanged( CBasePlayer *pPlayer, char gameMaterial )
{
if ( m_bDisabled )
return;
// Fire the output if we've changed, but only if it involves the target material
if ( gameMaterial != (char)m_iCurrentGameMaterial &&
( gameMaterial == m_iTargetGameMaterial || m_iCurrentGameMaterial == m_iTargetGameMaterial ) )
{
DevMsg( 2, "Player changed material to %d (was %d)\n", gameMaterial, m_iCurrentGameMaterial );
m_iCurrentGameMaterial = (int)gameMaterial;
SetThink( &CEnvPlayerSurfaceTrigger::UpdateMaterialThink );
SetNextThink( gpGlobals->curtime );
}
}
//-----------------------------------------------------------------------------
// Purpose: Think function to fire outputs. Done this way so that sv_alternate ticks
// doesn't allow multiple surface changes in the same tick to fire outputs.
//-----------------------------------------------------------------------------
void CEnvPlayerSurfaceTrigger::UpdateMaterialThink( void )
{
if ( m_iCurrentGameMaterial == m_iTargetGameMaterial )
{
m_OnSurfaceChangedToTarget.FireOutput( NULL, this );
}
else
{
m_OnSurfaceChangedFromTarget.FireOutput( NULL, this );
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CEnvPlayerSurfaceTrigger::InputDisable( inputdata_t &inputdata )
{
m_bDisabled = true;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CEnvPlayerSurfaceTrigger::InputEnable( inputdata_t &inputdata )
{
m_bDisabled = false;
}

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