|
|
|
|
//========= Copyright <EFBFBD> 1996-2005, Valve Corporation, All rights reserved. ============//
|
|
|
|
|
//
|
|
|
|
|
// Purpose:
|
|
|
|
|
//
|
|
|
|
|
//=============================================================================//
|
|
|
|
|
|
|
|
|
|
#include "cbase.h"
|
|
|
|
|
#include "entityoutput.h"
|
|
|
|
|
#include "ndebugoverlay.h"
|
|
|
|
|
#include "modelentities.h"
|
|
|
|
|
|
|
|
|
|
// memdbgon must be the last include file in a .cpp file!!!
|
|
|
|
|
#include "tier0/memdbgon.h"
|
|
|
|
|
|
|
|
|
|
extern ConVar ent_debugkeys;
|
|
|
|
|
extern ConVar showtriggers;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
LINK_ENTITY_TO_CLASS( func_brush, CFuncBrush );
|
|
|
|
|
|
|
|
|
|
BEGIN_DATADESC( CFuncBrush )
|
|
|
|
|
|
|
|
|
|
DEFINE_INPUTFUNC( FIELD_VOID, "Enable", InputTurnOn ),
|
|
|
|
|
DEFINE_INPUTFUNC( FIELD_VOID, "Disable", InputTurnOff ),
|
|
|
|
|
DEFINE_INPUTFUNC( FIELD_VOID, "Toggle", InputToggle ),
|
|
|
|
|
DEFINE_KEYFIELD( m_iDisabled, FIELD_INTEGER, "StartDisabled" ),
|
|
|
|
|
DEFINE_KEYFIELD( m_iSolidity, FIELD_INTEGER, "Solidity" ),
|
|
|
|
|
DEFINE_KEYFIELD( m_bSolidBsp, FIELD_BOOLEAN, "solidbsp" ),
|
|
|
|
|
DEFINE_KEYFIELD( m_iszExcludedClass, FIELD_STRING, "excludednpc" ),
|
|
|
|
|
DEFINE_KEYFIELD( m_bInvertExclusion, FIELD_BOOLEAN, "invert_exclusion" ),
|
|
|
|
|
|
|
|
|
|
DEFINE_INPUTFUNC( FIELD_STRING, "SetExcluded", InputSetExcluded ),
|
|
|
|
|
DEFINE_INPUTFUNC( FIELD_BOOLEAN, "SetInvert", InputSetInvert ),
|
|
|
|
|
|
|
|
|
|
END_DATADESC()
|
|
|
|
|
|
|
|
|
|
IMPLEMENT_SERVERCLASS_ST(CFuncBrush, DT_FuncBrush)
|
|
|
|
|
END_SEND_TABLE()
|
|
|
|
|
|
|
|
|
|
void CFuncBrush::Spawn( void )
|
|
|
|
|
{
|
|
|
|
|
SetMoveType( MOVETYPE_PUSH ); // so it doesn't get pushed by anything
|
|
|
|
|
|
|
|
|
|
SetSolid( SOLID_VPHYSICS );
|
|
|
|
|
AddEFlags( EFL_USE_PARTITION_WHEN_NOT_SOLID );
|
|
|
|
|
|
|
|
|
|
if ( m_iSolidity == BRUSHSOLID_NEVER )
|
|
|
|
|
{
|
|
|
|
|
AddSolidFlags( FSOLID_NOT_SOLID );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SetModel( STRING( GetModelName() ) );
|
|
|
|
|
|
|
|
|
|
if ( m_iDisabled )
|
|
|
|
|
TurnOff();
|
|
|
|
|
|
|
|
|
|
// If it can't move/go away, it's really part of the world
|
|
|
|
|
if ( !GetEntityName() || !m_iParent )
|
|
|
|
|
AddFlag( FL_WORLDBRUSH );
|
|
|
|
|
|
|
|
|
|
CreateVPhysics();
|
|
|
|
|
|
|
|
|
|
// Slam the object back to solid - if we really want it to be solid.
|
|
|
|
|
if ( m_bSolidBsp )
|
|
|
|
|
{
|
|
|
|
|
SetSolid( SOLID_BSP );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
bool CFuncBrush::CreateVPhysics( void )
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
// NOTE: Don't init this static. It's pretty common for these to be constrained
|
|
|
|
|
// and dynamically parented. Initing shadow avoids having to destroy the physics
|
|
|
|
|
// object later and lose the constraints.
|
|
|
|
|
IPhysicsObject *pPhys = VPhysicsInitShadow(false, false);
|
|
|
|
|
if ( pPhys )
|
|
|
|
|
{
|
|
|
|
|
int contents = modelinfo->GetModelContents( GetModelIndex() );
|
|
|
|
|
if ( ! (contents & (MASK_SOLID|MASK_PLAYERSOLID|MASK_NPCSOLID)) )
|
|
|
|
|
{
|
|
|
|
|
// leave the physics shadow there in case it has crap constrained to it
|
|
|
|
|
// but disable collisions with it
|
|
|
|
|
pPhys->EnableCollisions( false );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
// Purpose:
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
int CFuncBrush::DrawDebugTextOverlays( void )
|
|
|
|
|
{
|
|
|
|
|
int nOffset = BaseClass::DrawDebugTextOverlays();
|
|
|
|
|
|
|
|
|
|
if (m_debugOverlays & OVERLAY_TEXT_BIT)
|
|
|
|
|
{
|
|
|
|
|
char tempstr[512];
|
|
|
|
|
Q_snprintf( tempstr,sizeof(tempstr), "angles: %g %g %g", (double)GetLocalAngles()[PITCH], (double)GetLocalAngles()[YAW], (double)GetLocalAngles()[ROLL] );
|
|
|
|
|
EntityText( nOffset, tempstr, 0 );
|
|
|
|
|
nOffset++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return nOffset;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
// Purpose: Input handler for toggling the hidden/shown state of the brush.
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
void CFuncBrush::InputToggle( inputdata_t &inputdata )
|
|
|
|
|
{
|
|
|
|
|
if ( IsOn() )
|
|
|
|
|
{
|
|
|
|
|
TurnOff();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TurnOn();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
// Purpose: Input handler for hiding the brush.
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
void CFuncBrush::InputTurnOff( inputdata_t &inputdata )
|
|
|
|
|
{
|
|
|
|
|
TurnOff();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
// Purpose: Input handler for showing the brush.
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
void CFuncBrush::InputTurnOn( inputdata_t &inputdata )
|
|
|
|
|
{
|
|
|
|
|
TurnOn();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
//
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
void CFuncBrush::InputSetExcluded( inputdata_t &inputdata )
|
|
|
|
|
{
|
|
|
|
|
m_iszExcludedClass = inputdata.value.StringID();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
//
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
void CFuncBrush::InputSetInvert( inputdata_t &inputdata )
|
|
|
|
|
{
|
|
|
|
|
m_bInvertExclusion = inputdata.value.Bool();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
// Purpose: Hides the brush.
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
void CFuncBrush::TurnOff( void )
|
|
|
|
|
{
|
|
|
|
|
if ( !IsOn() )
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if ( m_iSolidity != BRUSHSOLID_ALWAYS )
|
|
|
|
|
{
|
|
|
|
|
AddSolidFlags( FSOLID_NOT_SOLID );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
AddEffects( EF_NODRAW );
|
|
|
|
|
m_iDisabled = TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
// Purpose: Shows the brush.
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
void CFuncBrush::TurnOn( void )
|
|
|
|
|
{
|
|
|
|
|
if ( IsOn() )
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if ( m_iSolidity != BRUSHSOLID_NEVER )
|
|
|
|
|
{
|
|
|
|
|
RemoveSolidFlags( FSOLID_NOT_SOLID );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
RemoveEffects( EF_NODRAW );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bool CFuncBrush::IsOn( void )
|
|
|
|
|
{
|
|
|
|
|
return !IsEffectActive( EF_NODRAW );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
// Purpose: Invisible field that activates when touched
|
|
|
|
|
// All inputs are passed up to the main entity, unless filtered out
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
// DVS TODO: obsolete, remove
|
|
|
|
|
class CTriggerBrush : public CBaseEntity
|
|
|
|
|
{
|
|
|
|
|
//
|
|
|
|
|
// Filters controlling what this trigger responds to.
|
|
|
|
|
//
|
|
|
|
|
enum TriggerFilters_e
|
|
|
|
|
{
|
|
|
|
|
TRIGGER_IGNOREPLAYERS = 0x01,
|
|
|
|
|
TRIGGER_IGNORENPCS = 0x02,
|
|
|
|
|
TRIGGER_IGNOREPUSHABLES = 0x04,
|
|
|
|
|
TRIGGER_IGNORETOUCH = 0x08,
|
|
|
|
|
TRIGGER_IGNOREUSE = 0x10,
|
|
|
|
|
TRIGGER_IGNOREALL = 0x20,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
DECLARE_CLASS( CTriggerBrush, CBaseEntity );
|
|
|
|
|
|
|
|
|
|
// engine inputs
|
|
|
|
|
void Spawn( void );
|
|
|
|
|
void StartTouch( CBaseEntity *pOther );
|
|
|
|
|
void EndTouch( CBaseEntity *pOther );
|
|
|
|
|
void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
|
|
|
|
|
|
|
|
|
|
// input filtering (use/touch/blocked)
|
|
|
|
|
bool PassesInputFilter( CBaseEntity *pOther, int filter );
|
|
|
|
|
|
|
|
|
|
// input functions
|
|
|
|
|
void InputEnable( inputdata_t &inputdata )
|
|
|
|
|
{
|
|
|
|
|
RemoveFlag( FL_DONTTOUCH );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void InputDisable( inputdata_t &inputdata )
|
|
|
|
|
{
|
|
|
|
|
// this ensures that all the remaining EndTouch() calls still get passed through
|
|
|
|
|
AddFlag( FL_DONTTOUCH );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// outputs
|
|
|
|
|
COutputEvent m_OnStartTouch;
|
|
|
|
|
COutputEvent m_OnEndTouch;
|
|
|
|
|
COutputEvent m_OnUse;
|
|
|
|
|
|
|
|
|
|
// data
|
|
|
|
|
int m_iInputFilter;
|
|
|
|
|
int m_iDontMessageParent;
|
|
|
|
|
|
|
|
|
|
DECLARE_DATADESC();
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
LINK_ENTITY_TO_CLASS( trigger_brush, CTriggerBrush );
|
|
|
|
|
|
|
|
|
|
BEGIN_DATADESC( CTriggerBrush )
|
|
|
|
|
|
|
|
|
|
DEFINE_KEYFIELD( m_iInputFilter, FIELD_INTEGER, "InputFilter" ),
|
|
|
|
|
DEFINE_KEYFIELD( m_iDontMessageParent, FIELD_INTEGER, "DontMessageParent" ),
|
|
|
|
|
|
|
|
|
|
DEFINE_OUTPUT( m_OnStartTouch, "OnStartTouch" ),
|
|
|
|
|
DEFINE_OUTPUT( m_OnEndTouch, "OnEndTouch" ),
|
|
|
|
|
DEFINE_OUTPUT( m_OnUse, "OnUse" ),
|
|
|
|
|
|
|
|
|
|
DEFINE_INPUTFUNC( FIELD_VOID, "Disable", InputDisable ),
|
|
|
|
|
DEFINE_INPUTFUNC( FIELD_VOID, "Enable", InputEnable ),
|
|
|
|
|
|
|
|
|
|
END_DATADESC()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void CTriggerBrush::Spawn( void )
|
|
|
|
|
{
|
|
|
|
|
SetSolid( SOLID_BSP );
|
|
|
|
|
AddSolidFlags( FSOLID_TRIGGER );
|
|
|
|
|
SetMoveType( MOVETYPE_NONE );
|
|
|
|
|
|
|
|
|
|
SetModel( STRING( GetModelName() ) ); // set size and link into world
|
|
|
|
|
|
|
|
|
|
if ( !showtriggers.GetInt() )
|
|
|
|
|
{
|
|
|
|
|
AddEffects( EF_NODRAW );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
// Purpose: Called when an entity starts touching us.
|
|
|
|
|
// Input : pOther - the entity that is now touching us.
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
void CTriggerBrush::StartTouch( CBaseEntity *pOther )
|
|
|
|
|
{
|
|
|
|
|
if ( PassesInputFilter(pOther, m_iInputFilter) && !(m_iInputFilter & TRIGGER_IGNORETOUCH) )
|
|
|
|
|
{
|
|
|
|
|
m_OnStartTouch.FireOutput( pOther, this );
|
|
|
|
|
if ( !m_iDontMessageParent )
|
|
|
|
|
BaseClass::StartTouch( pOther );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
// Purpose: Called when an entity stops touching us.
|
|
|
|
|
// Input : pOther - the entity that was touching us.
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
void CTriggerBrush::EndTouch( CBaseEntity *pOther )
|
|
|
|
|
{
|
|
|
|
|
if ( PassesInputFilter(pOther, m_iInputFilter) && !(m_iInputFilter & TRIGGER_IGNORETOUCH) )
|
|
|
|
|
{
|
|
|
|
|
m_OnEndTouch.FireOutput( pOther, this );
|
|
|
|
|
|
|
|
|
|
if ( !m_iDontMessageParent )
|
|
|
|
|
BaseClass::EndTouch( pOther );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
// Purpose: Called when we are triggered by another entity or used by the player.
|
|
|
|
|
// Input : pActivator -
|
|
|
|
|
// pCaller -
|
|
|
|
|
// useType -
|
|
|
|
|
// value -
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
void CTriggerBrush::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
|
|
|
|
|
{
|
|
|
|
|
if ( PassesInputFilter(pActivator, m_iInputFilter) && !(m_iInputFilter & TRIGGER_IGNOREUSE) )
|
|
|
|
|
{
|
|
|
|
|
m_OnUse.FireOutput( pActivator, this );
|
|
|
|
|
if ( !m_iDontMessageParent )
|
|
|
|
|
{
|
|
|
|
|
BaseClass::Use( pActivator, pCaller, useType, value );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
// Purpose: Checks an entity input, against a filter and the current entity
|
|
|
|
|
// Input : *pOther - the entity that is part of the input (touch/untouch/block/use)
|
|
|
|
|
// filter - a field of standard filters (TriggerFilters_e)
|
|
|
|
|
// Output : Returns true if the input passes, false if it should be ignored
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
bool CTriggerBrush::PassesInputFilter( CBaseEntity *pOther, int filter )
|
|
|
|
|
{
|
|
|
|
|
if ( !filter )
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
// check for players
|
|
|
|
|
if ( (filter & TRIGGER_IGNOREPLAYERS) && pOther->IsPlayer() )
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
// NPCs
|
|
|
|
|
if ( (filter & TRIGGER_IGNORENPCS) && pOther->edict() && (pOther->GetFlags() & FL_NPC) )
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
// pushables
|
|
|
|
|
if ( (filter & TRIGGER_IGNOREPUSHABLES) && FStrEq(STRING(pOther->m_iClassname), "func_pushable") )
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|