//========= Copyright Valve Corporation, All rights reserved. ============// // // Purpose: Implements doors that move when you look at them. // // $NoKeywords: $ //=============================================================================// #include "cbase.h" #include "basecombatcharacter.h" #include "entitylist.h" #include "func_movelinear.h" // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" #define SF_LDOOR_THRESHOLD 8192 #define SF_LDOOR_INVERT 16384 #define SF_LDOOR_FROM_OPEN 32768 class CLookDoor : public CFuncMoveLinear { public: DECLARE_CLASS( CLookDoor, CFuncMoveLinear ); void Spawn( void ); void MoveThink( void ); // Inputs void InputInvertOn( inputdata_t &inputdata ); void InputInvertOff( inputdata_t &inputdata ); float m_flProximityDistance; // How far before I start reacting float m_flProximityOffset; float m_flFieldOfView; EHANDLE m_hLooker; // Who is looking DECLARE_DATADESC(); }; class CLookDoorThinker : public CLogicalEntity { public: DECLARE_CLASS( CLookDoorThinker, CLogicalEntity ); void LookThink( void ); EHANDLE m_hLookDoor; // Who owns me DECLARE_DATADESC(); }; BEGIN_DATADESC( CLookDoorThinker ) DEFINE_FIELD( m_hLookDoor, FIELD_EHANDLE ), // Function Pointers DEFINE_FUNCTION(LookThink), END_DATADESC() LINK_ENTITY_TO_CLASS( lookdoorthinker, CLookDoorThinker ); //------------------------------------------------------------------------------ // Purpose : //------------------------------------------------------------------------------ void CLookDoorThinker::LookThink(void) { if (m_hLookDoor) { ((CLookDoor*)(CBaseEntity*)m_hLookDoor)->MoveThink(); SetNextThink( gpGlobals->curtime + 0.01f ); } else { UTIL_Remove(this); } } BEGIN_DATADESC( CLookDoor ) DEFINE_KEYFIELD( m_flProximityDistance, FIELD_FLOAT, "ProximityDistance"), DEFINE_KEYFIELD( m_flProximityOffset, FIELD_FLOAT, "ProximityOffset"), DEFINE_KEYFIELD( m_flFieldOfView, FIELD_FLOAT, "FieldOfView" ), DEFINE_FIELD(m_hLooker, FIELD_EHANDLE), // Inputs DEFINE_INPUTFUNC( FIELD_VOID, "InvertOn", InputInvertOn ), DEFINE_INPUTFUNC( FIELD_VOID, "InvertOff", InputInvertOff ), // Function Pointers DEFINE_FUNCTION(MoveThink), END_DATADESC() LINK_ENTITY_TO_CLASS( func_lookdoor, CLookDoor ); //------------------------------------------------------------------------------ // Purpose : Input handlers. //------------------------------------------------------------------------------ void CLookDoor::InputInvertOn( inputdata_t &inputdata ) { m_spawnflags |= SF_LDOOR_INVERT; } void CLookDoor::InputInvertOff( inputdata_t &inputdata ) { m_spawnflags &= ~SF_LDOOR_INVERT; } //------------------------------------------------------------------------------ // Purpose : //------------------------------------------------------------------------------ void CLookDoor::Spawn(void) { BaseClass::Spawn(); if (m_target == NULL_STRING) { Warning( "ERROR: DoorLook (%s) given no target. Rejecting spawn.\n",GetDebugName()); return; } CLookDoorThinker* pLookThinker = (CLookDoorThinker*)CreateEntityByName("lookdoorthinker"); if (pLookThinker) { pLookThinker->SetThink(&CLookDoorThinker::LookThink); pLookThinker->m_hLookDoor = this; pLookThinker->SetNextThink( gpGlobals->curtime + 0.1f ); } } //------------------------------------------------------------------------------ // Purpose : //------------------------------------------------------------------------------ void CLookDoor::MoveThink(void) { // -------------------------------- // Make sure we have a looker // -------------------------------- if (m_hLooker == NULL) { m_hLooker = (CBaseEntity*)gEntList.FindEntityByName( NULL, m_target ); if (m_hLooker == NULL) { return; } } //-------------------------------------- // Calculate an orgin for the door //-------------------------------------- Vector vOrigin = WorldSpaceCenter() - GetAbsOrigin(); // If FROM_OPEN flag is set, door proximity is measured // from the open and not the closed position if (FBitSet (m_spawnflags, SF_LDOOR_FROM_OPEN)) { vOrigin += m_vecPosition2; } // ------------------------------------------------------ // First add movement based on proximity // ------------------------------------------------------ float flProxMove = 0; if (m_flProximityDistance > 0) { float flDist = (m_hLooker->GetAbsOrigin() - vOrigin).Length()-m_flProximityOffset; if (flDist < 0) flDist = 0; if (flDist < m_flProximityDistance) { if (FBitSet (m_spawnflags, SF_LDOOR_THRESHOLD)) { flProxMove = 1.0; } else { flProxMove = 1-flDist/m_flProximityDistance; } } } // ------------------------------------------------------ // Then add movement based on view angle // ------------------------------------------------------ float flViewMove = 0; if (m_flFieldOfView > 0) { // ---------------------------------------- // Check that toucher is facing the target // ---------------------------------------- Assert( dynamic_cast< CBaseCombatCharacter* >( m_hLooker.Get() ) ); CBaseCombatCharacter* pBCC = (CBaseCombatCharacter*)m_hLooker.Get(); Vector vTouchDir = pBCC->EyeDirection3D( ); Vector vTargetDir = vOrigin - pBCC->EyePosition(); VectorNormalize(vTargetDir); float flDotPr = DotProduct(vTouchDir,vTargetDir); if (flDotPr < m_flFieldOfView) { flViewMove = 0.0; } else { flViewMove = (flDotPr-m_flFieldOfView)/(1.0 - m_flFieldOfView); } } //--------------------------------------- // Summate the two moves //--------------------------------------- float flMove = flProxMove + flViewMove; if (flMove > 1.0) { flMove = 1.0; } // If behavior is inverted do the reverse if (FBitSet (m_spawnflags, SF_LDOOR_INVERT)) { flMove = 1-flMove; } // Move the door SetPosition( flMove ); }