aboutsummaryrefslogtreecommitdiff
path: root/mp/src/game/server/doors.cpp
diff options
context:
space:
mode:
authorJørgen P. Tjernø <[email protected]>2013-12-02 19:31:46 -0800
committerJørgen P. Tjernø <[email protected]>2013-12-02 19:46:31 -0800
commitf56bb35301836e56582a575a75864392a0177875 (patch)
treede61ddd39de3e7df52759711950b4c288592f0dc /mp/src/game/server/doors.cpp
parentMark some more files as text. (diff)
downloadsource-sdk-2013-f56bb35301836e56582a575a75864392a0177875.tar.xz
source-sdk-2013-f56bb35301836e56582a575a75864392a0177875.zip
Fix line endings. WHAMMY.
Diffstat (limited to 'mp/src/game/server/doors.cpp')
-rw-r--r--mp/src/game/server/doors.cpp2866
1 files changed, 1433 insertions, 1433 deletions
diff --git a/mp/src/game/server/doors.cpp b/mp/src/game/server/doors.cpp
index d8f06c49..e76ba199 100644
--- a/mp/src/game/server/doors.cpp
+++ b/mp/src/game/server/doors.cpp
@@ -1,1433 +1,1433 @@
-//========= Copyright Valve Corporation, All rights reserved. ============//
-//
-// Purpose: Implements two types of doors: linear and rotating.
-//
-// $NoKeywords: $
-//=============================================================================//
-
-#include "cbase.h"
-#include "doors.h"
-#include "entitylist.h"
-#include "physics.h"
-#include "ndebugoverlay.h"
-#include "engine/IEngineSound.h"
-#include "physics_npc_solver.h"
-
-#ifdef HL1_DLL
-#include "filters.h"
-#endif
-
-#ifdef CSTRIKE_DLL
-#include "KeyValues.h"
-#endif
-
-#ifdef TF_DLL
-#include "tf_gamerules.h"
-#endif // TF_DLL
-
-// memdbgon must be the last include file in a .cpp file!!!
-#include "tier0/memdbgon.h"
-
-#define CLOSE_AREAPORTAL_THINK_CONTEXT "CloseAreaportalThink"
-
-BEGIN_DATADESC( CBaseDoor )
-
- DEFINE_KEYFIELD( m_vecMoveDir, FIELD_VECTOR, "movedir" ),
-
- DEFINE_FIELD( m_bLockedSentence, FIELD_CHARACTER ),
- DEFINE_FIELD( m_bUnlockedSentence, FIELD_CHARACTER ),
- DEFINE_KEYFIELD( m_NoiseMoving, FIELD_SOUNDNAME, "noise1" ),
- DEFINE_KEYFIELD( m_NoiseArrived, FIELD_SOUNDNAME, "noise2" ),
- DEFINE_KEYFIELD( m_NoiseMovingClosed, FIELD_SOUNDNAME, "startclosesound" ),
- DEFINE_KEYFIELD( m_NoiseArrivedClosed, FIELD_SOUNDNAME, "closesound" ),
- DEFINE_KEYFIELD( m_ChainTarget, FIELD_STRING, "chainstodoor" ),
- // DEFINE_FIELD( m_isChaining, FIELD_BOOLEAN ),
- // DEFINE_FIELD( m_ls, locksound_t ),
-// DEFINE_FIELD( m_isChaining, FIELD_BOOLEAN ),
- DEFINE_KEYFIELD( m_ls.sLockedSound, FIELD_SOUNDNAME, "locked_sound" ),
- DEFINE_KEYFIELD( m_ls.sUnlockedSound, FIELD_SOUNDNAME, "unlocked_sound" ),
- DEFINE_FIELD( m_bLocked, FIELD_BOOLEAN ),
- DEFINE_KEYFIELD( m_flWaveHeight, FIELD_FLOAT, "WaveHeight" ),
- DEFINE_KEYFIELD( m_flBlockDamage, FIELD_FLOAT, "dmg" ),
- DEFINE_KEYFIELD( m_eSpawnPosition, FIELD_INTEGER, "spawnpos" ),
-
- DEFINE_KEYFIELD( m_bForceClosed, FIELD_BOOLEAN, "forceclosed" ),
- DEFINE_FIELD( m_bDoorGroup, FIELD_BOOLEAN ),
-
-#ifdef HL1_DLL
- DEFINE_KEYFIELD( m_iBlockFilterName, FIELD_STRING, "filtername" ),
- DEFINE_FIELD( m_hBlockFilter, FIELD_EHANDLE ),
-#endif
-
- DEFINE_KEYFIELD( m_bLoopMoveSound, FIELD_BOOLEAN, "loopmovesound" ),
- DEFINE_KEYFIELD( m_bIgnoreDebris, FIELD_BOOLEAN, "ignoredebris" ),
-
- DEFINE_INPUTFUNC( FIELD_VOID, "Open", InputOpen ),
- DEFINE_INPUTFUNC( FIELD_VOID, "Close", InputClose ),
- DEFINE_INPUTFUNC( FIELD_VOID, "Toggle", InputToggle ),
- DEFINE_INPUTFUNC( FIELD_VOID, "Lock", InputLock ),
- DEFINE_INPUTFUNC( FIELD_VOID, "Unlock", InputUnlock ),
- DEFINE_INPUTFUNC( FIELD_FLOAT, "SetSpeed", InputSetSpeed ),
- DEFINE_INPUTFUNC( FIELD_FLOAT, "SetToggleState", InputSetToggleState ),
-
- DEFINE_OUTPUT( m_OnBlockedOpening, "OnBlockedOpening" ),
- DEFINE_OUTPUT( m_OnBlockedClosing, "OnBlockedClosing" ),
- DEFINE_OUTPUT( m_OnUnblockedOpening, "OnUnblockedOpening" ),
- DEFINE_OUTPUT( m_OnUnblockedClosing, "OnUnblockedClosing" ),
- DEFINE_OUTPUT( m_OnFullyClosed, "OnFullyClosed" ),
- DEFINE_OUTPUT( m_OnFullyOpen, "OnFullyOpen" ),
- DEFINE_OUTPUT( m_OnClose, "OnClose" ),
- DEFINE_OUTPUT( m_OnOpen, "OnOpen" ),
- DEFINE_OUTPUT( m_OnLockedUse, "OnLockedUse" ),
-
- // Function Pointers
- DEFINE_FUNCTION( DoorTouch ),
- DEFINE_FUNCTION( DoorGoUp ),
- DEFINE_FUNCTION( DoorGoDown ),
- DEFINE_FUNCTION( DoorHitTop ),
- DEFINE_FUNCTION( DoorHitBottom ),
- DEFINE_THINKFUNC( MovingSoundThink ),
- DEFINE_THINKFUNC( CloseAreaPortalsThink ),
-
-END_DATADESC()
-
-
-LINK_ENTITY_TO_CLASS( func_door, CBaseDoor );
-
-//
-// func_water is implemented as a linear door so we can raise/lower the water level.
-//
-LINK_ENTITY_TO_CLASS( func_water, CBaseDoor );
-
-
-// SendTable stuff.
-IMPLEMENT_SERVERCLASS_ST(CBaseDoor, DT_BaseDoor)
- SendPropFloat (SENDINFO(m_flWaveHeight), 8, SPROP_ROUNDUP, 0.0f, 8.0f),
-END_SEND_TABLE()
-
-#define DOOR_SENTENCEWAIT 6
-#define DOOR_SOUNDWAIT 1
-#define BUTTON_SOUNDWAIT 0.5
-
-
-//-----------------------------------------------------------------------------
-// Purpose: play door or button locked or unlocked sounds.
-// NOTE: this routine is shared by doors and buttons
-// Input : pEdict -
-// pls -
-// flocked - if true, play 'door is locked' sound, otherwise play 'door
-// is unlocked' sound.
-// fbutton -
-//-----------------------------------------------------------------------------
-void PlayLockSounds(CBaseEntity *pEdict, locksound_t *pls, int flocked, int fbutton)
-{
- if ( pEdict->HasSpawnFlags( SF_DOOR_SILENT ) )
- {
- return;
- }
- float flsoundwait = ( fbutton ) ? BUTTON_SOUNDWAIT : DOOR_SOUNDWAIT;
-
- if ( flocked )
- {
- int fplaysound = (pls->sLockedSound != NULL_STRING && gpGlobals->curtime > pls->flwaitSound);
- int fplaysentence = (pls->sLockedSentence != NULL_STRING && !pls->bEOFLocked && gpGlobals->curtime > pls->flwaitSentence);
- float fvol = ( fplaysound && fplaysentence ) ? 0.25f : 1.0f;
-
- // if there is a locked sound, and we've debounced, play sound
- if (fplaysound)
- {
- // play 'door locked' sound
- CPASAttenuationFilter filter( pEdict );
-
- EmitSound_t ep;
- ep.m_nChannel = CHAN_ITEM;
- ep.m_pSoundName = (char*)STRING(pls->sLockedSound);
- ep.m_flVolume = fvol;
- ep.m_SoundLevel = SNDLVL_NORM;
-
- CBaseEntity::EmitSound( filter, pEdict->entindex(), ep );
- pls->flwaitSound = gpGlobals->curtime + flsoundwait;
- }
-
- // if there is a sentence, we've not played all in list, and we've debounced, play sound
- if (fplaysentence)
- {
- // play next 'door locked' sentence in group
- int iprev = pls->iLockedSentence;
-
- pls->iLockedSentence = SENTENCEG_PlaySequentialSz( pEdict->edict(),
- STRING(pls->sLockedSentence),
- 0.85f,
- SNDLVL_NORM,
- 0,
- 100,
- pls->iLockedSentence,
- FALSE);
- pls->iUnlockedSentence = 0;
-
- // make sure we don't keep calling last sentence in list
- pls->bEOFLocked = (iprev == pls->iLockedSentence);
-
- pls->flwaitSentence = gpGlobals->curtime + DOOR_SENTENCEWAIT;
- }
- }
- else
- {
- // UNLOCKED SOUND
-
- int fplaysound = (pls->sUnlockedSound != NULL_STRING && gpGlobals->curtime > pls->flwaitSound);
- int fplaysentence = (pls->sUnlockedSentence != NULL_STRING && !pls->bEOFUnlocked && gpGlobals->curtime > pls->flwaitSentence);
- float fvol;
-
- // if playing both sentence and sound, lower sound volume so we hear sentence
- fvol = ( fplaysound && fplaysentence ) ? 0.25f : 1.0f;
-
- // play 'door unlocked' sound if set
- if (fplaysound)
- {
- CPASAttenuationFilter filter( pEdict );
-
- EmitSound_t ep;
- ep.m_nChannel = CHAN_ITEM;
- ep.m_pSoundName = (char*)STRING(pls->sUnlockedSound);
- ep.m_flVolume = fvol;
- ep.m_SoundLevel = SNDLVL_NORM;
-
- CBaseEntity::EmitSound( filter, pEdict->entindex(), ep );
- pls->flwaitSound = gpGlobals->curtime + flsoundwait;
- }
-
- // play next 'door unlocked' sentence in group
- if (fplaysentence)
- {
- int iprev = pls->iUnlockedSentence;
-
- pls->iUnlockedSentence = SENTENCEG_PlaySequentialSz(pEdict->edict(), STRING(pls->sUnlockedSentence),
- 0.85, SNDLVL_NORM, 0, 100, pls->iUnlockedSentence, FALSE);
- pls->iLockedSentence = 0;
-
- // make sure we don't keep calling last sentence in list
- pls->bEOFUnlocked = (iprev == pls->iUnlockedSentence);
- pls->flwaitSentence = gpGlobals->curtime + DOOR_SENTENCEWAIT;
- }
- }
-}
-
-
-//-----------------------------------------------------------------------------
-// Purpose: Cache user-entity-field values until spawn is called.
-// Input : szKeyName -
-// szValue -
-// Output : Returns true.
-//-----------------------------------------------------------------------------
-bool CBaseDoor::KeyValue( const char *szKeyName, const char *szValue )
-{
- if (FStrEq(szKeyName, "locked_sentence"))
- {
- m_bLockedSentence = atof(szValue);
- }
- else if (FStrEq(szKeyName, "unlocked_sentence"))
- {
- m_bUnlockedSentence = atof(szValue);
- }
- else
- return BaseClass::KeyValue( szKeyName, szValue );
-
- return true;
-}
-
-
-//-----------------------------------------------------------------------------
-// Purpose:
-//-----------------------------------------------------------------------------
-void CBaseDoor::Spawn()
-{
- Precache();
-
-#ifdef HL1_DLL
- SetSolid( SOLID_BSP );
-#else
- if ( GetMoveParent() && GetRootMoveParent()->GetSolid() == SOLID_BSP )
- {
- SetSolid( SOLID_BSP );
- }
- else
- {
- SetSolid( SOLID_VPHYSICS );
- }
-#endif
-
- // Convert movedir from angles to a vector
- QAngle angMoveDir = QAngle( m_vecMoveDir.x, m_vecMoveDir.y, m_vecMoveDir.z );
- AngleVectors( angMoveDir, &m_vecMoveDir );
-
- SetModel( STRING( GetModelName() ) );
- m_vecPosition1 = GetLocalOrigin();
-
- // Subtract 2 from size because the engine expands bboxes by 1 in all directions making the size too big
- Vector vecOBB = CollisionProp()->OBBSize();
- vecOBB -= Vector( 2, 2, 2 );
- m_vecPosition2 = m_vecPosition1 + (m_vecMoveDir * (DotProductAbs( m_vecMoveDir, vecOBB ) - m_flLip));
-
- if ( !IsRotatingDoor() )
- {
- if ( ( m_eSpawnPosition == FUNC_DOOR_SPAWN_OPEN ) || HasSpawnFlags( SF_DOOR_START_OPEN_OBSOLETE ) )
- { // swap pos1 and pos2, put door at pos2
- UTIL_SetOrigin( this, m_vecPosition2);
- m_toggle_state = TS_AT_TOP;
- }
- else
- {
- m_toggle_state = TS_AT_BOTTOM;
- }
- }
-
- if (HasSpawnFlags(SF_DOOR_LOCKED))
- {
- m_bLocked = true;
- }
-
- SetMoveType( MOVETYPE_PUSH );
-
- if (m_flSpeed == 0)
- {
- m_flSpeed = 100;
- }
-
- SetTouch( &CBaseDoor::DoorTouch );
-
- if ( !FClassnameIs( this, "func_water" ) )
- {
- if ( HasSpawnFlags(SF_DOOR_PASSABLE) )
- {
- //normal door
- AddEFlags( EFL_USE_PARTITION_WHEN_NOT_SOLID );
- AddSolidFlags( FSOLID_NOT_SOLID );
- }
-
- if ( HasSpawnFlags( SF_DOOR_NONSOLID_TO_PLAYER ) )
- {
- SetCollisionGroup( COLLISION_GROUP_PASSABLE_DOOR );
- // HACKHACK: Set this hoping that any children of the door that get blocked by the player
- // will get fixed up by vphysics
- // NOTE: We could decouple this as a separate behavior, but managing player collisions is already complex enough.
- // NOTE: This is necessary to prevent the player from blocking the wrecked train car in ep2_outland_01
- AddFlag( FL_UNBLOCKABLE_BY_PLAYER );
- }
- if ( m_bIgnoreDebris )
- {
- // both of these flags want to set the collision group and
- // there isn't a combo group
- Assert( !HasSpawnFlags( SF_DOOR_NONSOLID_TO_PLAYER ) );
- if ( HasSpawnFlags( SF_DOOR_NONSOLID_TO_PLAYER ) )
- {
- Warning("Door %s with conflicting collision settings, removing ignoredebris\n", GetDebugName() );
- }
- else
- {
- SetCollisionGroup( COLLISION_GROUP_INTERACTIVE );
- }
- }
- }
-
- if ( ( m_eSpawnPosition == FUNC_DOOR_SPAWN_OPEN ) && HasSpawnFlags( SF_DOOR_START_OPEN_OBSOLETE ) )
- {
- Warning("Door %s using obsolete 'Start Open' spawnflag with 'Spawn Position' set to 'Open'. Reverting to old behavior.\n", GetDebugName() );
- }
-
- CreateVPhysics();
-
-#ifdef TF_DLL
- if ( TFGameRules() && TFGameRules()->IsMultiplayer() )
- {
- // Never block doors in TF2 - to prevent various exploits.
- m_bIgnoreNonPlayerEntsOnBlock = true;
- }
-#else
- m_bIgnoreNonPlayerEntsOnBlock = false;
-#endif // TF_DLL
-}
-
-void CBaseDoor::MovingSoundThink( void )
-{
- CPASAttenuationFilter filter( this );
- filter.MakeReliable();
-
- EmitSound_t ep;
- ep.m_nChannel = CHAN_STATIC;
- if ( m_NoiseMovingClosed == NULL_STRING || m_toggle_state == TS_GOING_DOWN || m_toggle_state == TS_AT_BOTTOM )
- {
- ep.m_pSoundName = (char*)STRING(m_NoiseMoving);
- }
- else
- {
- ep.m_pSoundName = (char*)STRING(m_NoiseMovingClosed);
- }
- ep.m_flVolume = 1;
- ep.m_SoundLevel = SNDLVL_NORM;
-
- EmitSound( filter, entindex(), ep );
-
- //Only loop sounds in HL1 to maintain HL2 behavior
- if( ShouldLoopMoveSound() )
- {
- float duration = enginesound->GetSoundDuration( ep.m_pSoundName );
- SetContextThink( &CBaseDoor::MovingSoundThink, gpGlobals->curtime + duration, "MovingSound" );
- }
-}
-
-void CBaseDoor::StartMovingSound( void )
-{
- MovingSoundThink();
-
-#ifdef CSTRIKE_DLL // this event is only used by CS:S bots
-
- CBasePlayer *player = ToBasePlayer(m_hActivator);
- IGameEvent * event = gameeventmanager->CreateEvent( "door_moving" );
- if( event )
- {
- event->SetInt( "entindex", entindex() );
- event->SetInt( "userid", (player)?player->GetUserID():0 );
- gameeventmanager->FireEvent( event );
- }
-
-#endif
-}
-
-void CBaseDoor::StopMovingSound(void)
-{
- SetContextThink( NULL, gpGlobals->curtime, "MovingSound" );
- char *pSoundName;
- if ( m_NoiseMovingClosed == NULL_STRING || m_toggle_state == TS_GOING_UP || m_toggle_state == TS_AT_TOP )
- {
- pSoundName = (char*)STRING(m_NoiseMoving);
- }
- else
- {
- pSoundName = (char*)STRING(m_NoiseMovingClosed);
- }
- StopSound( entindex(), CHAN_STATIC, pSoundName );
-}
-
-
-bool CBaseDoor::ShouldSavePhysics()
-{
- // don't save physics if you're func_water
- return !FClassnameIs( this, "func_water" );
-}
-
-//-----------------------------------------------------------------------------
-bool CBaseDoor::CreateVPhysics( )
-{
- if ( !FClassnameIs( this, "func_water" ) )
- {
- //normal door
- // NOTE: Create this even when the door is not solid to support constraints.
- VPhysicsInitShadow( false, false );
- }
- else
- {
- // special contents
- AddSolidFlags( FSOLID_VOLUME_CONTENTS );
- SETBITS( m_spawnflags, SF_DOOR_SILENT ); // water is silent for now
-
- IPhysicsObject *pPhysics = VPhysicsInitShadow( false, false );
- fluidparams_t fluid;
-
- Assert( CollisionProp()->GetCollisionAngles() == vec3_angle );
- fluid.damping = 0.01f;
- fluid.surfacePlane[0] = 0;
- fluid.surfacePlane[1] = 0;
- fluid.surfacePlane[2] = 1;
- fluid.surfacePlane[3] = CollisionProp()->GetCollisionOrigin().z + CollisionProp()->OBBMaxs().z - 1;
- fluid.currentVelocity.Init(0,0,0);
- fluid.torqueFactor = 0.1f;
- fluid.viscosityFactor = 0.01f;
- fluid.pGameData = static_cast<void *>(this);
-
- //FIXME: Currently there's no way to specify that you want slime
- fluid.contents = CONTENTS_WATER;
-
- physenv->CreateFluidController( pPhysics, &fluid );
- }
- return true;
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-//-----------------------------------------------------------------------------
-void CBaseDoor::Activate( void )
-{
- BaseClass::Activate();
-
- CBaseDoor *pDoorList[64];
- m_bDoorGroup = true;
-
- // force movement groups to sync!!!
- int doorCount = GetDoorMovementGroup( pDoorList, ARRAYSIZE(pDoorList) );
- for ( int i = 0; i < doorCount; i++ )
- {
- if ( pDoorList[i]->m_vecMoveDir == m_vecMoveDir )
- {
- bool error = false;
- if ( pDoorList[i]->IsRotatingDoor() )
- {
- error = ( pDoorList[i]->GetLocalAngles() != GetLocalAngles() ) ? true : false;
- }
- else
- {
- error = ( pDoorList[i]->GetLocalOrigin() != GetLocalOrigin() ) ? true : false;
- }
- if ( error )
- {
- // don't do group blocking
- m_bDoorGroup = false;
-#ifdef HL1_DLL
- // UNDONE: This should probably fixup m_vecPosition1 & m_vecPosition2
- Warning("Door group %s has misaligned origin!\n", STRING(GetEntityName()) );
-#endif
- }
- }
- }
-
- switch ( m_toggle_state )
- {
- case TS_AT_TOP:
- UpdateAreaPortals( true );
- break;
- case TS_AT_BOTTOM:
- UpdateAreaPortals( false );
- break;
- }
-
-#ifdef HL1_DLL
- // Get a handle to my filter entity if there is one
- if (m_iBlockFilterName != NULL_STRING)
- {
- m_hBlockFilter = dynamic_cast<CBaseFilter *>(gEntList.FindEntityByName( NULL, m_iBlockFilterName, NULL ));
- }
-#endif
-}
-
-
-//-----------------------------------------------------------------------------
-// Purpose:
-// Input : state -
-//-----------------------------------------------------------------------------
-// This is ONLY used by the node graph to test movement through a door
-void CBaseDoor::InputSetToggleState( inputdata_t &inputdata )
-{
- SetToggleState( inputdata.value.Int() );
-}
-
-void CBaseDoor::SetToggleState( int state )
-{
- if ( state == TS_AT_TOP )
- UTIL_SetOrigin( this, m_vecPosition2 );
- else
- UTIL_SetOrigin( this, m_vecPosition1 );
-}
-
-
-//-----------------------------------------------------------------------------
-// Purpose:
-//-----------------------------------------------------------------------------
-void CBaseDoor::Precache( void )
-{
- //Fill in a default value if necessary
- if ( IsRotatingDoor() )
- {
- UTIL_ValidateSoundName( m_NoiseMoving, "RotDoorSound.DefaultMove" );
- UTIL_ValidateSoundName( m_NoiseArrived, "RotDoorSound.DefaultArrive" );
- UTIL_ValidateSoundName( m_ls.sLockedSound, "RotDoorSound.DefaultLocked" );
- UTIL_ValidateSoundName( m_ls.sUnlockedSound,"DoorSound.Null" );
- }
- else
- {
- UTIL_ValidateSoundName( m_NoiseMoving, "DoorSound.DefaultMove" );
- UTIL_ValidateSoundName( m_NoiseArrived, "DoorSound.DefaultArrive" );
-#ifndef HL1_DLL
- UTIL_ValidateSoundName( m_ls.sLockedSound, "DoorSound.DefaultLocked" );
-#endif
- UTIL_ValidateSoundName( m_ls.sUnlockedSound,"DoorSound.Null" );
- }
-
-#ifdef HL1_DLL
- if( m_ls.sLockedSound != NULL_STRING && strlen((char*)STRING(m_ls.sLockedSound)) < 4 )
- {
- // Too short to be ANYTHING ".wav", so it must be an old index into a long-lost
- // array of sound choices. slam it to a known "deny" sound. We lose the designer's
- // original selection, but we don't get unresponsive doors.
- m_ls.sLockedSound = AllocPooledString("buttons/button2.wav");
- }
-#endif//HL1_DLL
-
- //Precache them all
- PrecacheScriptSound( (char *) STRING(m_NoiseMoving) );
- PrecacheScriptSound( (char *) STRING(m_NoiseArrived) );
- PrecacheScriptSound( (char *) STRING(m_NoiseMovingClosed) );
- PrecacheScriptSound( (char *) STRING(m_NoiseArrivedClosed) );
- PrecacheScriptSound( (char *) STRING(m_ls.sLockedSound) );
- PrecacheScriptSound( (char *) STRING(m_ls.sUnlockedSound) );
-
- //Get sentence group names, for doors which are directly 'touched' to open
- switch (m_bLockedSentence)
- {
- case 1: m_ls.sLockedSentence = AllocPooledString("NA"); break; // access denied
- case 2: m_ls.sLockedSentence = AllocPooledString("ND"); break; // security lockout
- case 3: m_ls.sLockedSentence = AllocPooledString("NF"); break; // blast door
- case 4: m_ls.sLockedSentence = AllocPooledString("NFIRE"); break; // fire door
- case 5: m_ls.sLockedSentence = AllocPooledString("NCHEM"); break; // chemical door
- case 6: m_ls.sLockedSentence = AllocPooledString("NRAD"); break; // radiation door
- case 7: m_ls.sLockedSentence = AllocPooledString("NCON"); break; // gen containment
- case 8: m_ls.sLockedSentence = AllocPooledString("NH"); break; // maintenance door
- case 9: m_ls.sLockedSentence = AllocPooledString("NG"); break; // broken door
-
- default: m_ls.sLockedSentence = NULL_STRING; break;
- }
-
- switch (m_bUnlockedSentence)
- {
- case 1: m_ls.sUnlockedSentence = AllocPooledString("EA"); break; // access granted
- case 2: m_ls.sUnlockedSentence = AllocPooledString("ED"); break; // security door
- case 3: m_ls.sUnlockedSentence = AllocPooledString("EF"); break; // blast door
- case 4: m_ls.sUnlockedSentence = AllocPooledString("EFIRE"); break; // fire door
- case 5: m_ls.sUnlockedSentence = AllocPooledString("ECHEM"); break; // chemical door
- case 6: m_ls.sUnlockedSentence = AllocPooledString("ERAD"); break; // radiation door
- case 7: m_ls.sUnlockedSentence = AllocPooledString("ECON"); break; // gen containment
- case 8: m_ls.sUnlockedSentence = AllocPooledString("EH"); break; // maintenance door
-
- default: m_ls.sUnlockedSentence = NULL_STRING; break;
- }
-}
-
-
-//-----------------------------------------------------------------------------
-// Purpose: Doors not tied to anything (e.g. button, another door) can be touched,
-// to make them activate.
-// Input : *pOther -
-//-----------------------------------------------------------------------------
-void CBaseDoor::DoorTouch( CBaseEntity *pOther )
-{
- if( m_ChainTarget != NULL_STRING )
- ChainTouch( pOther );
-
- // Ignore touches by anything but players.
- if ( !pOther->IsPlayer() )
- {
-#ifdef HL1_DLL
- if( PassesBlockTouchFilter( pOther ) && m_toggle_state == TS_GOING_DOWN )
- {
- DoorGoUp();
- }
-#endif
- return;
- }
-
- // If door is not opened by touch, do nothing.
- if ( !HasSpawnFlags(SF_DOOR_PTOUCH) )
- {
-#ifdef HL1_DLL
- if( m_toggle_state == TS_AT_BOTTOM )
- {
- PlayLockSounds(this, &m_ls, TRUE, FALSE);
- }
-#endif//HL1_DLL
-
- return;
- }
-
- // If door has master, and it's not ready to trigger,
- // play 'locked' sound.
- if (m_sMaster != NULL_STRING && !UTIL_IsMasterTriggered(m_sMaster, pOther))
- {
- PlayLockSounds(this, &m_ls, TRUE, FALSE);
- }
-
- if (m_bLocked)
- {
- m_OnLockedUse.FireOutput( pOther, pOther );
- PlayLockSounds(this, &m_ls, TRUE, FALSE);
- return;
- }
-
- // Remember who activated the door.
- m_hActivator = pOther;
-
- if (DoorActivate( ))
- {
- // Temporarily disable the touch function, until movement is finished.
- SetTouch( NULL );
- }
-}
-
-#ifdef HL1_DLL
-bool CBaseDoor::PassesBlockTouchFilter(CBaseEntity *pOther)
-{
- CBaseFilter* pFilter = (CBaseFilter*)(m_hBlockFilter.Get());
- return ( pFilter && pFilter->PassesFilter( this, pOther ) );
-}
-#endif
-
-
-//-----------------------------------------------------------------------------
-// Purpose: Delays turning off area portals when closing doors to prevent visual artifacts
-//-----------------------------------------------------------------------------
-void CBaseDoor::CloseAreaPortalsThink( void )
-{
- UpdateAreaPortals( false );
- SetContextThink( NULL, gpGlobals->curtime, CLOSE_AREAPORTAL_THINK_CONTEXT );
-}
-
-
-//-----------------------------------------------------------------------------
-// Purpose:
-// Input : isOpen -
-//-----------------------------------------------------------------------------
-void CBaseDoor::UpdateAreaPortals( bool isOpen )
-{
- // cancel pending close
- SetContextThink( NULL, gpGlobals->curtime, CLOSE_AREAPORTAL_THINK_CONTEXT );
-
- if ( IsRotatingDoor() && HasSpawnFlags(SF_DOOR_START_OPEN_OBSOLETE) ) // logic inverted when using rot doors that start open
- isOpen = !isOpen;
-
- string_t name = GetEntityName();
- if ( !name )
- return;
-
- CBaseEntity *pPortal = NULL;
- while ( ( pPortal = gEntList.FindEntityByClassname( pPortal, "func_areaportal" ) ) != NULL )
- {
- if ( pPortal->HasTarget( name ) )
- {
- // USE_ON means open the portal, off means close it
- pPortal->Use( this, this, isOpen?USE_ON:USE_OFF, 0 );
- }
- }
-}
-
-
-//-----------------------------------------------------------------------------
-// Purpose: Called when the player uses the door.
-// Input : pActivator -
-// pCaller -
-// useType -
-// value -
-//-----------------------------------------------------------------------------
-void CBaseDoor::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
-{
- m_hActivator = pActivator;
-
- if( m_ChainTarget != NULL_STRING )
- ChainUse();
-
- // We can't +use this if it can't be +used
- if ( m_hActivator != NULL && m_hActivator->IsPlayer() && HasSpawnFlags( SF_DOOR_PUSE ) == false )
- {
- PlayLockSounds( this, &m_ls, TRUE, FALSE );
- return;
- }
-
- bool bAllowUse = false;
-
- // if not ready to be used, ignore "use" command.
- if( HasSpawnFlags(SF_DOOR_NEW_USE_RULES) )
- {
- //New behavior:
- // If not ready to be used, ignore "use" command.
- // Allow use in these cases:
- // - when the door is closed/closing
- // - when the door is open/opening and can be manually closed
- if ( ( m_toggle_state == TS_AT_BOTTOM || m_toggle_state == TS_GOING_DOWN ) || ( HasSpawnFlags(SF_DOOR_NO_AUTO_RETURN) && ( m_toggle_state == TS_AT_TOP || m_toggle_state == TS_GOING_UP ) ) )
- bAllowUse = true;
- }
- else
- {
- // Legacy behavior:
- if (m_toggle_state == TS_AT_BOTTOM || (HasSpawnFlags(SF_DOOR_NO_AUTO_RETURN) && m_toggle_state == TS_AT_TOP) )
- bAllowUse = true;
- }
-
- if( bAllowUse )
- {
- if (m_bLocked)
- {
- m_OnLockedUse.FireOutput( pActivator, pCaller );
- PlayLockSounds(this, &m_ls, TRUE, FALSE);
- }
- else
- {
- DoorActivate();
- }
- }
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: Passes Use along to certain named doors.
-//-----------------------------------------------------------------------------
-void CBaseDoor::ChainUse( void )
-{
- if ( m_isChaining )
- return;
-
- CBaseEntity *ent = NULL;
- while ( ( ent = gEntList.FindEntityByName( ent, m_ChainTarget, NULL ) ) != NULL )
- {
- if ( ent == this )
- continue;
-
- CBaseDoor *door = dynamic_cast< CBaseDoor * >( ent );
- if ( door )
- {
- door->SetChaining( true );
- door->Use( m_hActivator, NULL, USE_TOGGLE, 0.0f ); // only the first param is used
- door->SetChaining( false );
- }
- }
-}
-
-
-//-----------------------------------------------------------------------------
-// Purpose: Passes Touch along to certain named doors.
-//-----------------------------------------------------------------------------
-void CBaseDoor::ChainTouch( CBaseEntity *pOther )
-{
- if ( m_isChaining )
- return;
-
- CBaseEntity *ent = NULL;
- while ( ( ent = gEntList.FindEntityByName( ent, m_ChainTarget, NULL ) ) != NULL )
- {
- if ( ent == this )
- continue;
-
- CBaseDoor *door = dynamic_cast< CBaseDoor * >( ent );
- if ( door )
- {
- door->SetChaining( true );
- door->Touch( pOther );
- door->SetChaining( false );
- }
- }
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: Closes the door if it is not already closed.
-//-----------------------------------------------------------------------------
-void CBaseDoor::InputClose( inputdata_t &inputdata )
-{
- if ( m_toggle_state != TS_AT_BOTTOM )
- {
- DoorGoDown();
- }
-}
-
-
-//-----------------------------------------------------------------------------
-// Purpose: Input handler that locks the door.
-//-----------------------------------------------------------------------------
-void CBaseDoor::InputLock( inputdata_t &inputdata )
-{
- Lock();
-}
-
-
-//-----------------------------------------------------------------------------
-// Purpose: Opens the door if it is not already open.
-//-----------------------------------------------------------------------------
-void CBaseDoor::InputOpen( inputdata_t &inputdata )
-{
- if (m_toggle_state != TS_AT_TOP && m_toggle_state != TS_GOING_UP )
- {
- // I'm locked, can't open
- if (m_bLocked)
- return;
-
- // Play door unlock sounds.
- PlayLockSounds(this, &m_ls, false, false);
- DoorGoUp();
- }
-}
-
-
-//-----------------------------------------------------------------------------
-// Purpose: Opens the door if it is not already open.
-//-----------------------------------------------------------------------------
-void CBaseDoor::InputToggle( inputdata_t &inputdata )
-{
- // I'm locked, can't open
- if (m_bLocked)
- return;
-
- if (m_toggle_state == TS_AT_BOTTOM)
- {
- DoorGoUp();
- }
- else if (m_toggle_state == TS_AT_TOP)
- {
- DoorGoDown();
- }
-}
-
-
-//-----------------------------------------------------------------------------
-// Purpose: Input handler that unlocks the door.
-//-----------------------------------------------------------------------------
-void CBaseDoor::InputUnlock( inputdata_t &inputdata )
-{
- Unlock();
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-//-----------------------------------------------------------------------------
-void CBaseDoor::InputSetSpeed( inputdata_t &inputdata )
-{
- m_flSpeed = inputdata.value.Float();
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: Locks the door so that it cannot be opened.
-//-----------------------------------------------------------------------------
-void CBaseDoor::Lock( void )
-{
- m_bLocked = true;
-}
-
-
-//-----------------------------------------------------------------------------
-// Purpose: Unlocks the door so that it can be opened.
-//-----------------------------------------------------------------------------
-void CBaseDoor::Unlock( void )
-{
- m_bLocked = false;
-}
-
-
-//-----------------------------------------------------------------------------
-// Purpose: Causes the door to "do its thing", i.e. start moving, and cascade activation.
-// Output : int
-//-----------------------------------------------------------------------------
-int CBaseDoor::DoorActivate( )
-{
- if (!UTIL_IsMasterTriggered(m_sMaster, m_hActivator))
- return 0;
-
- if (HasSpawnFlags(SF_DOOR_NO_AUTO_RETURN) && m_toggle_state == TS_AT_TOP)
- {
- // door should close
- DoorGoDown();
- }
- else
- {
- // door should open
- // play door unlock sounds
- PlayLockSounds(this, &m_ls, FALSE, FALSE);
-
- if ( m_toggle_state != TS_AT_TOP && m_toggle_state != TS_GOING_UP )
- {
- DoorGoUp();
- }
- }
-
- return 1;
-}
-
-
-//-----------------------------------------------------------------------------
-// Purpose: Starts the door going to its "up" position (simply ToggleData->vecPosition2).
-//-----------------------------------------------------------------------------
-void CBaseDoor::DoorGoUp( void )
-{
- edict_t *pevActivator;
-
- UpdateAreaPortals( true );
- // It could be going-down, if blocked.
- ASSERT(m_toggle_state == TS_AT_BOTTOM || m_toggle_state == TS_GOING_DOWN);
-
- // emit door moving and stop sounds on CHAN_STATIC so that the multicast doesn't
- // filter them out and leave a client stuck with looping door sounds!
- if ( !HasSpawnFlags(SF_DOOR_SILENT ) )
- {
- // If we're not moving already, start the moving noise
- if ( m_toggle_state != TS_GOING_UP && m_toggle_state != TS_GOING_DOWN )
- {
- StartMovingSound();
- }
- }
-
- m_toggle_state = TS_GOING_UP;
-
- SetMoveDone( &CBaseDoor::DoorHitTop );
- if ( IsRotatingDoor() ) // !!! BUGBUG Triggered doors don't work with this yet
- {
- float sign = 1.0;
-
- if ( m_hActivator != NULL )
- {
- pevActivator = m_hActivator->edict();
-
- if ( !HasSpawnFlags( SF_DOOR_ONEWAY ) && m_vecMoveAng.y ) // Y axis rotation, move away from the player
- {
- // Positive is CCW, negative is CW, so make 'sign' 1 or -1 based on which way we want to open.
- // Important note: All doors face East at all times, and twist their local angle to open.
- // So you can't look at the door's facing to determine which way to open.
-
- Vector nearestPoint;
- CollisionProp()->CalcNearestPoint( m_hActivator->GetAbsOrigin(), &nearestPoint );
- Vector activatorToNearestPoint = nearestPoint - m_hActivator->GetAbsOrigin();
- activatorToNearestPoint.z = 0;
-
- Vector activatorToOrigin = GetAbsOrigin() - m_hActivator->GetAbsOrigin();
- activatorToOrigin.z = 0;
-
- // Point right hand at door hinge, curl hand towards closest spot on door, if thumb
- // is up, open door CW. -- Department of Basic Cross Product Understanding for Noobs
- Vector cross = activatorToOrigin.Cross( activatorToNearestPoint );
-
- if( cross.z > 0.0f )
- {
- sign = -1.0f;
- }
- }
- }
- AngularMove(m_vecAngle2*sign, m_flSpeed);
- }
- else
- {
- LinearMove(m_vecPosition2, m_flSpeed);
- }
-
- //Fire our open ouput
- m_OnOpen.FireOutput( this, this );
-}
-
-
-//-----------------------------------------------------------------------------
-// Purpose: The door has reached the "up" position. Either go back down, or
-// wait for another activation.
-//-----------------------------------------------------------------------------
-void CBaseDoor::DoorHitTop( void )
-{
- if ( !HasSpawnFlags( SF_DOOR_SILENT ) )
- {
- CPASAttenuationFilter filter( this );
- filter.MakeReliable();
- StopMovingSound();
-
- EmitSound_t ep;
- ep.m_nChannel = CHAN_STATIC;
- ep.m_pSoundName = (char*)STRING(m_NoiseArrived);
- ep.m_flVolume = 1;
- ep.m_SoundLevel = SNDLVL_NORM;
-
- EmitSound( filter, entindex(), ep );
- }
-
- ASSERT(m_toggle_state == TS_GOING_UP);
- m_toggle_state = TS_AT_TOP;
-
- // toggle-doors don't come down automatically, they wait for refire.
- if (HasSpawnFlags( SF_DOOR_NO_AUTO_RETURN))
- {
- // Re-instate touch method, movement is complete
- SetTouch( &CBaseDoor::DoorTouch );
- }
- else
- {
- // In flWait seconds, DoorGoDown will fire, unless wait is -1, then door stays open
- SetMoveDoneTime( m_flWait );
- SetMoveDone( &CBaseDoor::DoorGoDown );
-
- if ( m_flWait == -1 )
- {
- SetNextThink( TICK_NEVER_THINK );
- }
- }
-
- if (HasSpawnFlags(SF_DOOR_START_OPEN_OBSOLETE) )
- {
- m_OnFullyClosed.FireOutput(this, this);
- }
- else
- {
- m_OnFullyOpen.FireOutput(this, this);
- }
-}
-
-
-//-----------------------------------------------------------------------------
-// Purpose: Starts the door going to its "down" position (simply ToggleData->vecPosition1).
-//-----------------------------------------------------------------------------
-void CBaseDoor::DoorGoDown( void )
-{
- if ( !HasSpawnFlags( SF_DOOR_SILENT ) )
- {
- // If we're not moving already, start the moving noise
- if ( m_toggle_state != TS_GOING_UP && m_toggle_state != TS_GOING_DOWN )
- {
- StartMovingSound();
- }
- }
-
-#ifdef DOOR_ASSERT
- ASSERT(m_toggle_state == TS_AT_TOP);
-#endif // DOOR_ASSERT
- m_toggle_state = TS_GOING_DOWN;
-
- SetMoveDone( &CBaseDoor::DoorHitBottom );
- if ( IsRotatingDoor() )//rotating door
- AngularMove( m_vecAngle1, m_flSpeed);
- else
- LinearMove( m_vecPosition1, m_flSpeed);
-
- //Fire our closed output
- m_OnClose.FireOutput( this, this );
-}
-
-
-//-----------------------------------------------------------------------------
-// Purpose: The door has reached the "down" position. Back to quiescence.
-//-----------------------------------------------------------------------------
-void CBaseDoor::DoorHitBottom( void )
-{
- if ( !HasSpawnFlags( SF_DOOR_SILENT ) )
- {
- CPASAttenuationFilter filter( this );
- filter.MakeReliable();
-
- StopMovingSound();
-
- EmitSound_t ep;
- ep.m_nChannel = CHAN_STATIC;
- if ( m_NoiseArrivedClosed == NULL_STRING )
- ep.m_pSoundName = (char*)STRING(m_NoiseArrived);
- else
- ep.m_pSoundName = (char*)STRING(m_NoiseArrivedClosed);
- ep.m_flVolume = 1;
- ep.m_SoundLevel = SNDLVL_NORM;
-
- EmitSound( filter, entindex(), ep );
- }
-
- ASSERT(m_toggle_state == TS_GOING_DOWN);
- m_toggle_state = TS_AT_BOTTOM;
-
- // Re-instate touch method, cycle is complete
- SetTouch( &CBaseDoor::DoorTouch );
-
- if (HasSpawnFlags(SF_DOOR_START_OPEN_OBSOLETE))
- {
- m_OnFullyOpen.FireOutput(m_hActivator, this);
- }
- else
- {
- m_OnFullyClosed.FireOutput(m_hActivator, this);
- }
-
- // Close the area portals just after the door closes, to prevent visual artifacts in multiplayer games
- SetContextThink( &CBaseDoor::CloseAreaPortalsThink, gpGlobals->curtime + 0.5f, CLOSE_AREAPORTAL_THINK_CONTEXT );
-}
-
-
-// Lists all doors in the same movement group as this one
-int CBaseDoor::GetDoorMovementGroup( CBaseDoor *pDoorList[], int listMax )
-{
- int count = 0;
- CBaseEntity *pTarget = NULL;
-
- // Block all door pieces with the same targetname here.
- if ( GetEntityName() != NULL_STRING )
- {
- for (;;)
- {
- pTarget = gEntList.FindEntityByName( pTarget, GetEntityName(), NULL );
-
- if ( pTarget != this )
- {
- if ( !pTarget )
- break;
-
- CBaseDoor *pDoor = dynamic_cast<CBaseDoor *>(pTarget);
-
- if ( pDoor && count < listMax )
- {
- pDoorList[count] = pDoor;
- count++;
- }
- }
- }
- }
-
- return count;
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: Called the first frame that the door is blocked while opening or closing.
-// Input : pOther - The blocking entity.
-//-----------------------------------------------------------------------------
-void CBaseDoor::StartBlocked( CBaseEntity *pOther )
-{
- //
- // Fire whatever events we need to due to our blocked state.
- //
- if (m_toggle_state == TS_GOING_DOWN)
- {
- m_OnBlockedClosing.FireOutput(pOther, this);
- }
- else
- {
- m_OnBlockedOpening.FireOutput(pOther, this);
- }
-}
-
-
-//-----------------------------------------------------------------------------
-// Purpose: Called every frame when the door is blocked while opening or closing.
-// Input : pOther - The blocking entity.
-//-----------------------------------------------------------------------------
-void CBaseDoor::Blocked( CBaseEntity *pOther )
-{
- // Hurt the blocker a little.
- if ( m_flBlockDamage )
- {
- // if the door is marked "force closed" or it has a negative wait, then there's nothing to do but
- // push/damage the object.
- // If block damage is set, but this object is a physics prop that can't be damaged, just
- // give up and disable collisions
- if ( (m_bForceClosed || m_flWait < 0) && pOther->GetMoveType() == MOVETYPE_VPHYSICS &&
- (pOther->m_takedamage == DAMAGE_NO || pOther->m_takedamage == DAMAGE_EVENTS_ONLY) )
- {
- EntityPhysics_CreateSolver( this, pOther, true, 4.0f );
- }
- else
- {
- pOther->TakeDamage( CTakeDamageInfo( this, this, m_flBlockDamage, DMG_CRUSH ) );
- }
- }
- // If set, ignore non-player ents that block us. Mainly of use in multiplayer to prevent exploits.
- else if ( pOther && !pOther->IsPlayer() && m_bIgnoreNonPlayerEntsOnBlock )
- {
- return;
- }
-
- // If we're set to force ourselves closed, keep going
- if ( m_bForceClosed )
- return;
-
- // if a door has a negative wait, it would never come back if blocked,
- // so let it just squash the object to death real fast
- if (m_flWait >= 0)
- {
- if (m_toggle_state == TS_GOING_DOWN)
- {
- DoorGoUp();
- }
- else
- {
- DoorGoDown();
- }
- }
-
- // Block all door pieces with the same targetname here.
- if ( GetEntityName() != NULL_STRING )
- {
- CBaseDoor *pDoorList[64];
- int doorCount = GetDoorMovementGroup( pDoorList, ARRAYSIZE(pDoorList) );
-
- for ( int i = 0; i < doorCount; i++ )
- {
- CBaseDoor *pDoor = pDoorList[i];
-
- if ( pDoor->m_flWait >= 0)
- {
- if (m_bDoorGroup && pDoor->m_vecMoveDir == m_vecMoveDir && pDoor->GetAbsVelocity() == GetAbsVelocity() && pDoor->GetLocalAngularVelocity() == GetLocalAngularVelocity())
- {
- pDoor->m_nSimulationTick = m_nSimulationTick; // don't run simulation this frame if you haven't run yet
-
- // this is the most hacked, evil, bastardized thing I've ever seen. kjb
- if ( !pDoor->IsRotatingDoor() )
- {// set origin to realign normal doors
- pDoor->SetLocalOrigin( GetLocalOrigin() );
- pDoor->SetAbsVelocity( vec3_origin );// stop!
-
- }
- else
- {// set angles to realign rotating doors
- pDoor->SetLocalAngles( GetLocalAngles() );
- pDoor->SetLocalAngularVelocity( vec3_angle );
- }
- }
-
- if ( pDoor->m_toggle_state == TS_GOING_DOWN)
- pDoor->DoorGoUp();
- else
- pDoor->DoorGoDown();
- }
- }
- }
-}
-
-
-//-----------------------------------------------------------------------------
-// Purpose: Called the first frame that the door is unblocked while opening or closing.
-//-----------------------------------------------------------------------------
-void CBaseDoor::EndBlocked( void )
-{
- //
- // Fire whatever events we need to due to our unblocked state.
- //
- if (m_toggle_state == TS_GOING_DOWN)
- {
- m_OnUnblockedClosing.FireOutput(this, this);
- }
- else
- {
- m_OnUnblockedOpening.FireOutput(this, this);
- }
-}
-
-
-/*func_door_rotating
-
-TOGGLE causes the door to wait in both the start and end states for
-a trigger event.
-
-START_OPEN causes the door to move to its destination when spawned,
-and operate in reverse. It is used to temporarily or permanently
-close off an area when triggered (not usefull for touch or
-takedamage doors).
-
-You need to have an origin brush as part of this entity. The
-center of that brush will be
-the point around which it is rotated. It will rotate around the Z
-axis by default. You can
-check either the X_AXIS or Y_AXIS box to change that.
-
-"distance" is how many degrees the door will be rotated.
-"speed" determines how fast the door moves; default value is 100.
-
-REVERSE will cause the door to rotate in the opposite direction.
-
-"angle" determines the opening direction
-"targetname" if set, no touch field will be spawned and a remote
-button or trigger field activates the door.
-"health" if set, door must be shot open
-"speed" movement speed (100 default)
-"wait" wait before returning (3 default, -1 = never return)
-"dmg" damage to inflict when blocked (2 default)
-*/
-
-//==================================================
-// CRotDoor
-//==================================================
-
-class CRotDoor : public CBaseDoor
-{
-public:
- DECLARE_CLASS( CRotDoor, CBaseDoor );
-
- void Spawn( void );
- bool CreateVPhysics();
- // This is ONLY used by the node graph to test movement through a door
- virtual void SetToggleState( int state );
- virtual bool IsRotatingDoor() { return true; }
-
- bool m_bSolidBsp;
-
- DECLARE_DATADESC();
-};
-
-LINK_ENTITY_TO_CLASS( func_door_rotating, CRotDoor );
-
-BEGIN_DATADESC( CRotDoor )
- DEFINE_KEYFIELD( m_bSolidBsp, FIELD_BOOLEAN, "solidbsp" ),
-END_DATADESC()
-
-//-----------------------------------------------------------------------------
-// Purpose:
-//-----------------------------------------------------------------------------
-void CRotDoor::Spawn( void )
-{
- BaseClass::Spawn();
-
- // set the axis of rotation
- CBaseToggle::AxisDir();
-
- // check for clockwise rotation
- if ( HasSpawnFlags(SF_DOOR_ROTATE_BACKWARDS) )
- m_vecMoveAng = m_vecMoveAng * -1;
-
- //m_flWait = 2; who the hell did this? (sjb)
- m_vecAngle1 = GetLocalAngles();
- m_vecAngle2 = GetLocalAngles() + m_vecMoveAng * m_flMoveDistance;
-
- ASSERTSZ(m_vecAngle1 != m_vecAngle2, "rotating door start/end positions are equal\n");
-
- // Starting open allows a func_door to be lighted in the closed position but
- // spawn in the open position
- //
- // SF_DOOR_START_OPEN_OBSOLETE is an old broken way of spawning open that has
- // been deprecated.
- if ( HasSpawnFlags(SF_DOOR_START_OPEN_OBSOLETE) )
- {
- // swap pos1 and pos2, put door at pos2, invert movement direction
- QAngle vecNewAngles = m_vecAngle2;
- m_vecAngle2 = m_vecAngle1;
- m_vecAngle1 = vecNewAngles;
- m_vecMoveAng = -m_vecMoveAng;
-
- // We've already had our physics setup in BaseClass::Spawn, so teleport to our
- // current position. If we don't do this, our vphysics shadow will not update.
- Teleport( NULL, &m_vecAngle1, NULL );
-
- m_toggle_state = TS_AT_BOTTOM;
- }
- else if ( m_eSpawnPosition == FUNC_DOOR_SPAWN_OPEN )
- {
- // We've already had our physics setup in BaseClass::Spawn, so teleport to our
- // current position. If we don't do this, our vphysics shadow will not update.
- Teleport( NULL, &m_vecAngle2, NULL );
- m_toggle_state = TS_AT_TOP;
- }
- else
- {
- m_toggle_state = TS_AT_BOTTOM;
- }
-
-#ifdef HL1_DLL
- SetSolid( SOLID_VPHYSICS );
-#endif
-
- // Slam the object back to solid - if we really want it to be solid.
- if ( m_bSolidBsp )
- {
- SetSolid( SOLID_BSP );
- }
-}
-
-//-----------------------------------------------------------------------------
-
-bool CRotDoor::CreateVPhysics()
-{
- if ( !IsSolidFlagSet( FSOLID_NOT_SOLID ) )
- {
- VPhysicsInitShadow( false, false );
- }
-
- return true;
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-// Input : state -
-//-----------------------------------------------------------------------------
-// This is ONLY used by the node graph to test movement through a door
-void CRotDoor::SetToggleState( int state )
-{
- if ( state == TS_AT_TOP )
- SetLocalAngles( m_vecAngle2 );
- else
- SetLocalAngles( m_vecAngle1 );
-}
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Implements two types of doors: linear and rotating.
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#include "cbase.h"
+#include "doors.h"
+#include "entitylist.h"
+#include "physics.h"
+#include "ndebugoverlay.h"
+#include "engine/IEngineSound.h"
+#include "physics_npc_solver.h"
+
+#ifdef HL1_DLL
+#include "filters.h"
+#endif
+
+#ifdef CSTRIKE_DLL
+#include "KeyValues.h"
+#endif
+
+#ifdef TF_DLL
+#include "tf_gamerules.h"
+#endif // TF_DLL
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+#define CLOSE_AREAPORTAL_THINK_CONTEXT "CloseAreaportalThink"
+
+BEGIN_DATADESC( CBaseDoor )
+
+ DEFINE_KEYFIELD( m_vecMoveDir, FIELD_VECTOR, "movedir" ),
+
+ DEFINE_FIELD( m_bLockedSentence, FIELD_CHARACTER ),
+ DEFINE_FIELD( m_bUnlockedSentence, FIELD_CHARACTER ),
+ DEFINE_KEYFIELD( m_NoiseMoving, FIELD_SOUNDNAME, "noise1" ),
+ DEFINE_KEYFIELD( m_NoiseArrived, FIELD_SOUNDNAME, "noise2" ),
+ DEFINE_KEYFIELD( m_NoiseMovingClosed, FIELD_SOUNDNAME, "startclosesound" ),
+ DEFINE_KEYFIELD( m_NoiseArrivedClosed, FIELD_SOUNDNAME, "closesound" ),
+ DEFINE_KEYFIELD( m_ChainTarget, FIELD_STRING, "chainstodoor" ),
+ // DEFINE_FIELD( m_isChaining, FIELD_BOOLEAN ),
+ // DEFINE_FIELD( m_ls, locksound_t ),
+// DEFINE_FIELD( m_isChaining, FIELD_BOOLEAN ),
+ DEFINE_KEYFIELD( m_ls.sLockedSound, FIELD_SOUNDNAME, "locked_sound" ),
+ DEFINE_KEYFIELD( m_ls.sUnlockedSound, FIELD_SOUNDNAME, "unlocked_sound" ),
+ DEFINE_FIELD( m_bLocked, FIELD_BOOLEAN ),
+ DEFINE_KEYFIELD( m_flWaveHeight, FIELD_FLOAT, "WaveHeight" ),
+ DEFINE_KEYFIELD( m_flBlockDamage, FIELD_FLOAT, "dmg" ),
+ DEFINE_KEYFIELD( m_eSpawnPosition, FIELD_INTEGER, "spawnpos" ),
+
+ DEFINE_KEYFIELD( m_bForceClosed, FIELD_BOOLEAN, "forceclosed" ),
+ DEFINE_FIELD( m_bDoorGroup, FIELD_BOOLEAN ),
+
+#ifdef HL1_DLL
+ DEFINE_KEYFIELD( m_iBlockFilterName, FIELD_STRING, "filtername" ),
+ DEFINE_FIELD( m_hBlockFilter, FIELD_EHANDLE ),
+#endif
+
+ DEFINE_KEYFIELD( m_bLoopMoveSound, FIELD_BOOLEAN, "loopmovesound" ),
+ DEFINE_KEYFIELD( m_bIgnoreDebris, FIELD_BOOLEAN, "ignoredebris" ),
+
+ DEFINE_INPUTFUNC( FIELD_VOID, "Open", InputOpen ),
+ DEFINE_INPUTFUNC( FIELD_VOID, "Close", InputClose ),
+ DEFINE_INPUTFUNC( FIELD_VOID, "Toggle", InputToggle ),
+ DEFINE_INPUTFUNC( FIELD_VOID, "Lock", InputLock ),
+ DEFINE_INPUTFUNC( FIELD_VOID, "Unlock", InputUnlock ),
+ DEFINE_INPUTFUNC( FIELD_FLOAT, "SetSpeed", InputSetSpeed ),
+ DEFINE_INPUTFUNC( FIELD_FLOAT, "SetToggleState", InputSetToggleState ),
+
+ DEFINE_OUTPUT( m_OnBlockedOpening, "OnBlockedOpening" ),
+ DEFINE_OUTPUT( m_OnBlockedClosing, "OnBlockedClosing" ),
+ DEFINE_OUTPUT( m_OnUnblockedOpening, "OnUnblockedOpening" ),
+ DEFINE_OUTPUT( m_OnUnblockedClosing, "OnUnblockedClosing" ),
+ DEFINE_OUTPUT( m_OnFullyClosed, "OnFullyClosed" ),
+ DEFINE_OUTPUT( m_OnFullyOpen, "OnFullyOpen" ),
+ DEFINE_OUTPUT( m_OnClose, "OnClose" ),
+ DEFINE_OUTPUT( m_OnOpen, "OnOpen" ),
+ DEFINE_OUTPUT( m_OnLockedUse, "OnLockedUse" ),
+
+ // Function Pointers
+ DEFINE_FUNCTION( DoorTouch ),
+ DEFINE_FUNCTION( DoorGoUp ),
+ DEFINE_FUNCTION( DoorGoDown ),
+ DEFINE_FUNCTION( DoorHitTop ),
+ DEFINE_FUNCTION( DoorHitBottom ),
+ DEFINE_THINKFUNC( MovingSoundThink ),
+ DEFINE_THINKFUNC( CloseAreaPortalsThink ),
+
+END_DATADESC()
+
+
+LINK_ENTITY_TO_CLASS( func_door, CBaseDoor );
+
+//
+// func_water is implemented as a linear door so we can raise/lower the water level.
+//
+LINK_ENTITY_TO_CLASS( func_water, CBaseDoor );
+
+
+// SendTable stuff.
+IMPLEMENT_SERVERCLASS_ST(CBaseDoor, DT_BaseDoor)
+ SendPropFloat (SENDINFO(m_flWaveHeight), 8, SPROP_ROUNDUP, 0.0f, 8.0f),
+END_SEND_TABLE()
+
+#define DOOR_SENTENCEWAIT 6
+#define DOOR_SOUNDWAIT 1
+#define BUTTON_SOUNDWAIT 0.5
+
+
+//-----------------------------------------------------------------------------
+// Purpose: play door or button locked or unlocked sounds.
+// NOTE: this routine is shared by doors and buttons
+// Input : pEdict -
+// pls -
+// flocked - if true, play 'door is locked' sound, otherwise play 'door
+// is unlocked' sound.
+// fbutton -
+//-----------------------------------------------------------------------------
+void PlayLockSounds(CBaseEntity *pEdict, locksound_t *pls, int flocked, int fbutton)
+{
+ if ( pEdict->HasSpawnFlags( SF_DOOR_SILENT ) )
+ {
+ return;
+ }
+ float flsoundwait = ( fbutton ) ? BUTTON_SOUNDWAIT : DOOR_SOUNDWAIT;
+
+ if ( flocked )
+ {
+ int fplaysound = (pls->sLockedSound != NULL_STRING && gpGlobals->curtime > pls->flwaitSound);
+ int fplaysentence = (pls->sLockedSentence != NULL_STRING && !pls->bEOFLocked && gpGlobals->curtime > pls->flwaitSentence);
+ float fvol = ( fplaysound && fplaysentence ) ? 0.25f : 1.0f;
+
+ // if there is a locked sound, and we've debounced, play sound
+ if (fplaysound)
+ {
+ // play 'door locked' sound
+ CPASAttenuationFilter filter( pEdict );
+
+ EmitSound_t ep;
+ ep.m_nChannel = CHAN_ITEM;
+ ep.m_pSoundName = (char*)STRING(pls->sLockedSound);
+ ep.m_flVolume = fvol;
+ ep.m_SoundLevel = SNDLVL_NORM;
+
+ CBaseEntity::EmitSound( filter, pEdict->entindex(), ep );
+ pls->flwaitSound = gpGlobals->curtime + flsoundwait;
+ }
+
+ // if there is a sentence, we've not played all in list, and we've debounced, play sound
+ if (fplaysentence)
+ {
+ // play next 'door locked' sentence in group
+ int iprev = pls->iLockedSentence;
+
+ pls->iLockedSentence = SENTENCEG_PlaySequentialSz( pEdict->edict(),
+ STRING(pls->sLockedSentence),
+ 0.85f,
+ SNDLVL_NORM,
+ 0,
+ 100,
+ pls->iLockedSentence,
+ FALSE);
+ pls->iUnlockedSentence = 0;
+
+ // make sure we don't keep calling last sentence in list
+ pls->bEOFLocked = (iprev == pls->iLockedSentence);
+
+ pls->flwaitSentence = gpGlobals->curtime + DOOR_SENTENCEWAIT;
+ }
+ }
+ else
+ {
+ // UNLOCKED SOUND
+
+ int fplaysound = (pls->sUnlockedSound != NULL_STRING && gpGlobals->curtime > pls->flwaitSound);
+ int fplaysentence = (pls->sUnlockedSentence != NULL_STRING && !pls->bEOFUnlocked && gpGlobals->curtime > pls->flwaitSentence);
+ float fvol;
+
+ // if playing both sentence and sound, lower sound volume so we hear sentence
+ fvol = ( fplaysound && fplaysentence ) ? 0.25f : 1.0f;
+
+ // play 'door unlocked' sound if set
+ if (fplaysound)
+ {
+ CPASAttenuationFilter filter( pEdict );
+
+ EmitSound_t ep;
+ ep.m_nChannel = CHAN_ITEM;
+ ep.m_pSoundName = (char*)STRING(pls->sUnlockedSound);
+ ep.m_flVolume = fvol;
+ ep.m_SoundLevel = SNDLVL_NORM;
+
+ CBaseEntity::EmitSound( filter, pEdict->entindex(), ep );
+ pls->flwaitSound = gpGlobals->curtime + flsoundwait;
+ }
+
+ // play next 'door unlocked' sentence in group
+ if (fplaysentence)
+ {
+ int iprev = pls->iUnlockedSentence;
+
+ pls->iUnlockedSentence = SENTENCEG_PlaySequentialSz(pEdict->edict(), STRING(pls->sUnlockedSentence),
+ 0.85, SNDLVL_NORM, 0, 100, pls->iUnlockedSentence, FALSE);
+ pls->iLockedSentence = 0;
+
+ // make sure we don't keep calling last sentence in list
+ pls->bEOFUnlocked = (iprev == pls->iUnlockedSentence);
+ pls->flwaitSentence = gpGlobals->curtime + DOOR_SENTENCEWAIT;
+ }
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Cache user-entity-field values until spawn is called.
+// Input : szKeyName -
+// szValue -
+// Output : Returns true.
+//-----------------------------------------------------------------------------
+bool CBaseDoor::KeyValue( const char *szKeyName, const char *szValue )
+{
+ if (FStrEq(szKeyName, "locked_sentence"))
+ {
+ m_bLockedSentence = atof(szValue);
+ }
+ else if (FStrEq(szKeyName, "unlocked_sentence"))
+ {
+ m_bUnlockedSentence = atof(szValue);
+ }
+ else
+ return BaseClass::KeyValue( szKeyName, szValue );
+
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CBaseDoor::Spawn()
+{
+ Precache();
+
+#ifdef HL1_DLL
+ SetSolid( SOLID_BSP );
+#else
+ if ( GetMoveParent() && GetRootMoveParent()->GetSolid() == SOLID_BSP )
+ {
+ SetSolid( SOLID_BSP );
+ }
+ else
+ {
+ SetSolid( SOLID_VPHYSICS );
+ }
+#endif
+
+ // Convert movedir from angles to a vector
+ QAngle angMoveDir = QAngle( m_vecMoveDir.x, m_vecMoveDir.y, m_vecMoveDir.z );
+ AngleVectors( angMoveDir, &m_vecMoveDir );
+
+ SetModel( STRING( GetModelName() ) );
+ m_vecPosition1 = GetLocalOrigin();
+
+ // Subtract 2 from size because the engine expands bboxes by 1 in all directions making the size too big
+ Vector vecOBB = CollisionProp()->OBBSize();
+ vecOBB -= Vector( 2, 2, 2 );
+ m_vecPosition2 = m_vecPosition1 + (m_vecMoveDir * (DotProductAbs( m_vecMoveDir, vecOBB ) - m_flLip));
+
+ if ( !IsRotatingDoor() )
+ {
+ if ( ( m_eSpawnPosition == FUNC_DOOR_SPAWN_OPEN ) || HasSpawnFlags( SF_DOOR_START_OPEN_OBSOLETE ) )
+ { // swap pos1 and pos2, put door at pos2
+ UTIL_SetOrigin( this, m_vecPosition2);
+ m_toggle_state = TS_AT_TOP;
+ }
+ else
+ {
+ m_toggle_state = TS_AT_BOTTOM;
+ }
+ }
+
+ if (HasSpawnFlags(SF_DOOR_LOCKED))
+ {
+ m_bLocked = true;
+ }
+
+ SetMoveType( MOVETYPE_PUSH );
+
+ if (m_flSpeed == 0)
+ {
+ m_flSpeed = 100;
+ }
+
+ SetTouch( &CBaseDoor::DoorTouch );
+
+ if ( !FClassnameIs( this, "func_water" ) )
+ {
+ if ( HasSpawnFlags(SF_DOOR_PASSABLE) )
+ {
+ //normal door
+ AddEFlags( EFL_USE_PARTITION_WHEN_NOT_SOLID );
+ AddSolidFlags( FSOLID_NOT_SOLID );
+ }
+
+ if ( HasSpawnFlags( SF_DOOR_NONSOLID_TO_PLAYER ) )
+ {
+ SetCollisionGroup( COLLISION_GROUP_PASSABLE_DOOR );
+ // HACKHACK: Set this hoping that any children of the door that get blocked by the player
+ // will get fixed up by vphysics
+ // NOTE: We could decouple this as a separate behavior, but managing player collisions is already complex enough.
+ // NOTE: This is necessary to prevent the player from blocking the wrecked train car in ep2_outland_01
+ AddFlag( FL_UNBLOCKABLE_BY_PLAYER );
+ }
+ if ( m_bIgnoreDebris )
+ {
+ // both of these flags want to set the collision group and
+ // there isn't a combo group
+ Assert( !HasSpawnFlags( SF_DOOR_NONSOLID_TO_PLAYER ) );
+ if ( HasSpawnFlags( SF_DOOR_NONSOLID_TO_PLAYER ) )
+ {
+ Warning("Door %s with conflicting collision settings, removing ignoredebris\n", GetDebugName() );
+ }
+ else
+ {
+ SetCollisionGroup( COLLISION_GROUP_INTERACTIVE );
+ }
+ }
+ }
+
+ if ( ( m_eSpawnPosition == FUNC_DOOR_SPAWN_OPEN ) && HasSpawnFlags( SF_DOOR_START_OPEN_OBSOLETE ) )
+ {
+ Warning("Door %s using obsolete 'Start Open' spawnflag with 'Spawn Position' set to 'Open'. Reverting to old behavior.\n", GetDebugName() );
+ }
+
+ CreateVPhysics();
+
+#ifdef TF_DLL
+ if ( TFGameRules() && TFGameRules()->IsMultiplayer() )
+ {
+ // Never block doors in TF2 - to prevent various exploits.
+ m_bIgnoreNonPlayerEntsOnBlock = true;
+ }
+#else
+ m_bIgnoreNonPlayerEntsOnBlock = false;
+#endif // TF_DLL
+}
+
+void CBaseDoor::MovingSoundThink( void )
+{
+ CPASAttenuationFilter filter( this );
+ filter.MakeReliable();
+
+ EmitSound_t ep;
+ ep.m_nChannel = CHAN_STATIC;
+ if ( m_NoiseMovingClosed == NULL_STRING || m_toggle_state == TS_GOING_DOWN || m_toggle_state == TS_AT_BOTTOM )
+ {
+ ep.m_pSoundName = (char*)STRING(m_NoiseMoving);
+ }
+ else
+ {
+ ep.m_pSoundName = (char*)STRING(m_NoiseMovingClosed);
+ }
+ ep.m_flVolume = 1;
+ ep.m_SoundLevel = SNDLVL_NORM;
+
+ EmitSound( filter, entindex(), ep );
+
+ //Only loop sounds in HL1 to maintain HL2 behavior
+ if( ShouldLoopMoveSound() )
+ {
+ float duration = enginesound->GetSoundDuration( ep.m_pSoundName );
+ SetContextThink( &CBaseDoor::MovingSoundThink, gpGlobals->curtime + duration, "MovingSound" );
+ }
+}
+
+void CBaseDoor::StartMovingSound( void )
+{
+ MovingSoundThink();
+
+#ifdef CSTRIKE_DLL // this event is only used by CS:S bots
+
+ CBasePlayer *player = ToBasePlayer(m_hActivator);
+ IGameEvent * event = gameeventmanager->CreateEvent( "door_moving" );
+ if( event )
+ {
+ event->SetInt( "entindex", entindex() );
+ event->SetInt( "userid", (player)?player->GetUserID():0 );
+ gameeventmanager->FireEvent( event );
+ }
+
+#endif
+}
+
+void CBaseDoor::StopMovingSound(void)
+{
+ SetContextThink( NULL, gpGlobals->curtime, "MovingSound" );
+ char *pSoundName;
+ if ( m_NoiseMovingClosed == NULL_STRING || m_toggle_state == TS_GOING_UP || m_toggle_state == TS_AT_TOP )
+ {
+ pSoundName = (char*)STRING(m_NoiseMoving);
+ }
+ else
+ {
+ pSoundName = (char*)STRING(m_NoiseMovingClosed);
+ }
+ StopSound( entindex(), CHAN_STATIC, pSoundName );
+}
+
+
+bool CBaseDoor::ShouldSavePhysics()
+{
+ // don't save physics if you're func_water
+ return !FClassnameIs( this, "func_water" );
+}
+
+//-----------------------------------------------------------------------------
+bool CBaseDoor::CreateVPhysics( )
+{
+ if ( !FClassnameIs( this, "func_water" ) )
+ {
+ //normal door
+ // NOTE: Create this even when the door is not solid to support constraints.
+ VPhysicsInitShadow( false, false );
+ }
+ else
+ {
+ // special contents
+ AddSolidFlags( FSOLID_VOLUME_CONTENTS );
+ SETBITS( m_spawnflags, SF_DOOR_SILENT ); // water is silent for now
+
+ IPhysicsObject *pPhysics = VPhysicsInitShadow( false, false );
+ fluidparams_t fluid;
+
+ Assert( CollisionProp()->GetCollisionAngles() == vec3_angle );
+ fluid.damping = 0.01f;
+ fluid.surfacePlane[0] = 0;
+ fluid.surfacePlane[1] = 0;
+ fluid.surfacePlane[2] = 1;
+ fluid.surfacePlane[3] = CollisionProp()->GetCollisionOrigin().z + CollisionProp()->OBBMaxs().z - 1;
+ fluid.currentVelocity.Init(0,0,0);
+ fluid.torqueFactor = 0.1f;
+ fluid.viscosityFactor = 0.01f;
+ fluid.pGameData = static_cast<void *>(this);
+
+ //FIXME: Currently there's no way to specify that you want slime
+ fluid.contents = CONTENTS_WATER;
+
+ physenv->CreateFluidController( pPhysics, &fluid );
+ }
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CBaseDoor::Activate( void )
+{
+ BaseClass::Activate();
+
+ CBaseDoor *pDoorList[64];
+ m_bDoorGroup = true;
+
+ // force movement groups to sync!!!
+ int doorCount = GetDoorMovementGroup( pDoorList, ARRAYSIZE(pDoorList) );
+ for ( int i = 0; i < doorCount; i++ )
+ {
+ if ( pDoorList[i]->m_vecMoveDir == m_vecMoveDir )
+ {
+ bool error = false;
+ if ( pDoorList[i]->IsRotatingDoor() )
+ {
+ error = ( pDoorList[i]->GetLocalAngles() != GetLocalAngles() ) ? true : false;
+ }
+ else
+ {
+ error = ( pDoorList[i]->GetLocalOrigin() != GetLocalOrigin() ) ? true : false;
+ }
+ if ( error )
+ {
+ // don't do group blocking
+ m_bDoorGroup = false;
+#ifdef HL1_DLL
+ // UNDONE: This should probably fixup m_vecPosition1 & m_vecPosition2
+ Warning("Door group %s has misaligned origin!\n", STRING(GetEntityName()) );
+#endif
+ }
+ }
+ }
+
+ switch ( m_toggle_state )
+ {
+ case TS_AT_TOP:
+ UpdateAreaPortals( true );
+ break;
+ case TS_AT_BOTTOM:
+ UpdateAreaPortals( false );
+ break;
+ }
+
+#ifdef HL1_DLL
+ // Get a handle to my filter entity if there is one
+ if (m_iBlockFilterName != NULL_STRING)
+ {
+ m_hBlockFilter = dynamic_cast<CBaseFilter *>(gEntList.FindEntityByName( NULL, m_iBlockFilterName, NULL ));
+ }
+#endif
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : state -
+//-----------------------------------------------------------------------------
+// This is ONLY used by the node graph to test movement through a door
+void CBaseDoor::InputSetToggleState( inputdata_t &inputdata )
+{
+ SetToggleState( inputdata.value.Int() );
+}
+
+void CBaseDoor::SetToggleState( int state )
+{
+ if ( state == TS_AT_TOP )
+ UTIL_SetOrigin( this, m_vecPosition2 );
+ else
+ UTIL_SetOrigin( this, m_vecPosition1 );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CBaseDoor::Precache( void )
+{
+ //Fill in a default value if necessary
+ if ( IsRotatingDoor() )
+ {
+ UTIL_ValidateSoundName( m_NoiseMoving, "RotDoorSound.DefaultMove" );
+ UTIL_ValidateSoundName( m_NoiseArrived, "RotDoorSound.DefaultArrive" );
+ UTIL_ValidateSoundName( m_ls.sLockedSound, "RotDoorSound.DefaultLocked" );
+ UTIL_ValidateSoundName( m_ls.sUnlockedSound,"DoorSound.Null" );
+ }
+ else
+ {
+ UTIL_ValidateSoundName( m_NoiseMoving, "DoorSound.DefaultMove" );
+ UTIL_ValidateSoundName( m_NoiseArrived, "DoorSound.DefaultArrive" );
+#ifndef HL1_DLL
+ UTIL_ValidateSoundName( m_ls.sLockedSound, "DoorSound.DefaultLocked" );
+#endif
+ UTIL_ValidateSoundName( m_ls.sUnlockedSound,"DoorSound.Null" );
+ }
+
+#ifdef HL1_DLL
+ if( m_ls.sLockedSound != NULL_STRING && strlen((char*)STRING(m_ls.sLockedSound)) < 4 )
+ {
+ // Too short to be ANYTHING ".wav", so it must be an old index into a long-lost
+ // array of sound choices. slam it to a known "deny" sound. We lose the designer's
+ // original selection, but we don't get unresponsive doors.
+ m_ls.sLockedSound = AllocPooledString("buttons/button2.wav");
+ }
+#endif//HL1_DLL
+
+ //Precache them all
+ PrecacheScriptSound( (char *) STRING(m_NoiseMoving) );
+ PrecacheScriptSound( (char *) STRING(m_NoiseArrived) );
+ PrecacheScriptSound( (char *) STRING(m_NoiseMovingClosed) );
+ PrecacheScriptSound( (char *) STRING(m_NoiseArrivedClosed) );
+ PrecacheScriptSound( (char *) STRING(m_ls.sLockedSound) );
+ PrecacheScriptSound( (char *) STRING(m_ls.sUnlockedSound) );
+
+ //Get sentence group names, for doors which are directly 'touched' to open
+ switch (m_bLockedSentence)
+ {
+ case 1: m_ls.sLockedSentence = AllocPooledString("NA"); break; // access denied
+ case 2: m_ls.sLockedSentence = AllocPooledString("ND"); break; // security lockout
+ case 3: m_ls.sLockedSentence = AllocPooledString("NF"); break; // blast door
+ case 4: m_ls.sLockedSentence = AllocPooledString("NFIRE"); break; // fire door
+ case 5: m_ls.sLockedSentence = AllocPooledString("NCHEM"); break; // chemical door
+ case 6: m_ls.sLockedSentence = AllocPooledString("NRAD"); break; // radiation door
+ case 7: m_ls.sLockedSentence = AllocPooledString("NCON"); break; // gen containment
+ case 8: m_ls.sLockedSentence = AllocPooledString("NH"); break; // maintenance door
+ case 9: m_ls.sLockedSentence = AllocPooledString("NG"); break; // broken door
+
+ default: m_ls.sLockedSentence = NULL_STRING; break;
+ }
+
+ switch (m_bUnlockedSentence)
+ {
+ case 1: m_ls.sUnlockedSentence = AllocPooledString("EA"); break; // access granted
+ case 2: m_ls.sUnlockedSentence = AllocPooledString("ED"); break; // security door
+ case 3: m_ls.sUnlockedSentence = AllocPooledString("EF"); break; // blast door
+ case 4: m_ls.sUnlockedSentence = AllocPooledString("EFIRE"); break; // fire door
+ case 5: m_ls.sUnlockedSentence = AllocPooledString("ECHEM"); break; // chemical door
+ case 6: m_ls.sUnlockedSentence = AllocPooledString("ERAD"); break; // radiation door
+ case 7: m_ls.sUnlockedSentence = AllocPooledString("ECON"); break; // gen containment
+ case 8: m_ls.sUnlockedSentence = AllocPooledString("EH"); break; // maintenance door
+
+ default: m_ls.sUnlockedSentence = NULL_STRING; break;
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Doors not tied to anything (e.g. button, another door) can be touched,
+// to make them activate.
+// Input : *pOther -
+//-----------------------------------------------------------------------------
+void CBaseDoor::DoorTouch( CBaseEntity *pOther )
+{
+ if( m_ChainTarget != NULL_STRING )
+ ChainTouch( pOther );
+
+ // Ignore touches by anything but players.
+ if ( !pOther->IsPlayer() )
+ {
+#ifdef HL1_DLL
+ if( PassesBlockTouchFilter( pOther ) && m_toggle_state == TS_GOING_DOWN )
+ {
+ DoorGoUp();
+ }
+#endif
+ return;
+ }
+
+ // If door is not opened by touch, do nothing.
+ if ( !HasSpawnFlags(SF_DOOR_PTOUCH) )
+ {
+#ifdef HL1_DLL
+ if( m_toggle_state == TS_AT_BOTTOM )
+ {
+ PlayLockSounds(this, &m_ls, TRUE, FALSE);
+ }
+#endif//HL1_DLL
+
+ return;
+ }
+
+ // If door has master, and it's not ready to trigger,
+ // play 'locked' sound.
+ if (m_sMaster != NULL_STRING && !UTIL_IsMasterTriggered(m_sMaster, pOther))
+ {
+ PlayLockSounds(this, &m_ls, TRUE, FALSE);
+ }
+
+ if (m_bLocked)
+ {
+ m_OnLockedUse.FireOutput( pOther, pOther );
+ PlayLockSounds(this, &m_ls, TRUE, FALSE);
+ return;
+ }
+
+ // Remember who activated the door.
+ m_hActivator = pOther;
+
+ if (DoorActivate( ))
+ {
+ // Temporarily disable the touch function, until movement is finished.
+ SetTouch( NULL );
+ }
+}
+
+#ifdef HL1_DLL
+bool CBaseDoor::PassesBlockTouchFilter(CBaseEntity *pOther)
+{
+ CBaseFilter* pFilter = (CBaseFilter*)(m_hBlockFilter.Get());
+ return ( pFilter && pFilter->PassesFilter( this, pOther ) );
+}
+#endif
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Delays turning off area portals when closing doors to prevent visual artifacts
+//-----------------------------------------------------------------------------
+void CBaseDoor::CloseAreaPortalsThink( void )
+{
+ UpdateAreaPortals( false );
+ SetContextThink( NULL, gpGlobals->curtime, CLOSE_AREAPORTAL_THINK_CONTEXT );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : isOpen -
+//-----------------------------------------------------------------------------
+void CBaseDoor::UpdateAreaPortals( bool isOpen )
+{
+ // cancel pending close
+ SetContextThink( NULL, gpGlobals->curtime, CLOSE_AREAPORTAL_THINK_CONTEXT );
+
+ if ( IsRotatingDoor() && HasSpawnFlags(SF_DOOR_START_OPEN_OBSOLETE) ) // logic inverted when using rot doors that start open
+ isOpen = !isOpen;
+
+ string_t name = GetEntityName();
+ if ( !name )
+ return;
+
+ CBaseEntity *pPortal = NULL;
+ while ( ( pPortal = gEntList.FindEntityByClassname( pPortal, "func_areaportal" ) ) != NULL )
+ {
+ if ( pPortal->HasTarget( name ) )
+ {
+ // USE_ON means open the portal, off means close it
+ pPortal->Use( this, this, isOpen?USE_ON:USE_OFF, 0 );
+ }
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Called when the player uses the door.
+// Input : pActivator -
+// pCaller -
+// useType -
+// value -
+//-----------------------------------------------------------------------------
+void CBaseDoor::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
+{
+ m_hActivator = pActivator;
+
+ if( m_ChainTarget != NULL_STRING )
+ ChainUse();
+
+ // We can't +use this if it can't be +used
+ if ( m_hActivator != NULL && m_hActivator->IsPlayer() && HasSpawnFlags( SF_DOOR_PUSE ) == false )
+ {
+ PlayLockSounds( this, &m_ls, TRUE, FALSE );
+ return;
+ }
+
+ bool bAllowUse = false;
+
+ // if not ready to be used, ignore "use" command.
+ if( HasSpawnFlags(SF_DOOR_NEW_USE_RULES) )
+ {
+ //New behavior:
+ // If not ready to be used, ignore "use" command.
+ // Allow use in these cases:
+ // - when the door is closed/closing
+ // - when the door is open/opening and can be manually closed
+ if ( ( m_toggle_state == TS_AT_BOTTOM || m_toggle_state == TS_GOING_DOWN ) || ( HasSpawnFlags(SF_DOOR_NO_AUTO_RETURN) && ( m_toggle_state == TS_AT_TOP || m_toggle_state == TS_GOING_UP ) ) )
+ bAllowUse = true;
+ }
+ else
+ {
+ // Legacy behavior:
+ if (m_toggle_state == TS_AT_BOTTOM || (HasSpawnFlags(SF_DOOR_NO_AUTO_RETURN) && m_toggle_state == TS_AT_TOP) )
+ bAllowUse = true;
+ }
+
+ if( bAllowUse )
+ {
+ if (m_bLocked)
+ {
+ m_OnLockedUse.FireOutput( pActivator, pCaller );
+ PlayLockSounds(this, &m_ls, TRUE, FALSE);
+ }
+ else
+ {
+ DoorActivate();
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Passes Use along to certain named doors.
+//-----------------------------------------------------------------------------
+void CBaseDoor::ChainUse( void )
+{
+ if ( m_isChaining )
+ return;
+
+ CBaseEntity *ent = NULL;
+ while ( ( ent = gEntList.FindEntityByName( ent, m_ChainTarget, NULL ) ) != NULL )
+ {
+ if ( ent == this )
+ continue;
+
+ CBaseDoor *door = dynamic_cast< CBaseDoor * >( ent );
+ if ( door )
+ {
+ door->SetChaining( true );
+ door->Use( m_hActivator, NULL, USE_TOGGLE, 0.0f ); // only the first param is used
+ door->SetChaining( false );
+ }
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Passes Touch along to certain named doors.
+//-----------------------------------------------------------------------------
+void CBaseDoor::ChainTouch( CBaseEntity *pOther )
+{
+ if ( m_isChaining )
+ return;
+
+ CBaseEntity *ent = NULL;
+ while ( ( ent = gEntList.FindEntityByName( ent, m_ChainTarget, NULL ) ) != NULL )
+ {
+ if ( ent == this )
+ continue;
+
+ CBaseDoor *door = dynamic_cast< CBaseDoor * >( ent );
+ if ( door )
+ {
+ door->SetChaining( true );
+ door->Touch( pOther );
+ door->SetChaining( false );
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Closes the door if it is not already closed.
+//-----------------------------------------------------------------------------
+void CBaseDoor::InputClose( inputdata_t &inputdata )
+{
+ if ( m_toggle_state != TS_AT_BOTTOM )
+ {
+ DoorGoDown();
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Input handler that locks the door.
+//-----------------------------------------------------------------------------
+void CBaseDoor::InputLock( inputdata_t &inputdata )
+{
+ Lock();
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Opens the door if it is not already open.
+//-----------------------------------------------------------------------------
+void CBaseDoor::InputOpen( inputdata_t &inputdata )
+{
+ if (m_toggle_state != TS_AT_TOP && m_toggle_state != TS_GOING_UP )
+ {
+ // I'm locked, can't open
+ if (m_bLocked)
+ return;
+
+ // Play door unlock sounds.
+ PlayLockSounds(this, &m_ls, false, false);
+ DoorGoUp();
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Opens the door if it is not already open.
+//-----------------------------------------------------------------------------
+void CBaseDoor::InputToggle( inputdata_t &inputdata )
+{
+ // I'm locked, can't open
+ if (m_bLocked)
+ return;
+
+ if (m_toggle_state == TS_AT_BOTTOM)
+ {
+ DoorGoUp();
+ }
+ else if (m_toggle_state == TS_AT_TOP)
+ {
+ DoorGoDown();
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Input handler that unlocks the door.
+//-----------------------------------------------------------------------------
+void CBaseDoor::InputUnlock( inputdata_t &inputdata )
+{
+ Unlock();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CBaseDoor::InputSetSpeed( inputdata_t &inputdata )
+{
+ m_flSpeed = inputdata.value.Float();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Locks the door so that it cannot be opened.
+//-----------------------------------------------------------------------------
+void CBaseDoor::Lock( void )
+{
+ m_bLocked = true;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Unlocks the door so that it can be opened.
+//-----------------------------------------------------------------------------
+void CBaseDoor::Unlock( void )
+{
+ m_bLocked = false;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Causes the door to "do its thing", i.e. start moving, and cascade activation.
+// Output : int
+//-----------------------------------------------------------------------------
+int CBaseDoor::DoorActivate( )
+{
+ if (!UTIL_IsMasterTriggered(m_sMaster, m_hActivator))
+ return 0;
+
+ if (HasSpawnFlags(SF_DOOR_NO_AUTO_RETURN) && m_toggle_state == TS_AT_TOP)
+ {
+ // door should close
+ DoorGoDown();
+ }
+ else
+ {
+ // door should open
+ // play door unlock sounds
+ PlayLockSounds(this, &m_ls, FALSE, FALSE);
+
+ if ( m_toggle_state != TS_AT_TOP && m_toggle_state != TS_GOING_UP )
+ {
+ DoorGoUp();
+ }
+ }
+
+ return 1;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Starts the door going to its "up" position (simply ToggleData->vecPosition2).
+//-----------------------------------------------------------------------------
+void CBaseDoor::DoorGoUp( void )
+{
+ edict_t *pevActivator;
+
+ UpdateAreaPortals( true );
+ // It could be going-down, if blocked.
+ ASSERT(m_toggle_state == TS_AT_BOTTOM || m_toggle_state == TS_GOING_DOWN);
+
+ // emit door moving and stop sounds on CHAN_STATIC so that the multicast doesn't
+ // filter them out and leave a client stuck with looping door sounds!
+ if ( !HasSpawnFlags(SF_DOOR_SILENT ) )
+ {
+ // If we're not moving already, start the moving noise
+ if ( m_toggle_state != TS_GOING_UP && m_toggle_state != TS_GOING_DOWN )
+ {
+ StartMovingSound();
+ }
+ }
+
+ m_toggle_state = TS_GOING_UP;
+
+ SetMoveDone( &CBaseDoor::DoorHitTop );
+ if ( IsRotatingDoor() ) // !!! BUGBUG Triggered doors don't work with this yet
+ {
+ float sign = 1.0;
+
+ if ( m_hActivator != NULL )
+ {
+ pevActivator = m_hActivator->edict();
+
+ if ( !HasSpawnFlags( SF_DOOR_ONEWAY ) && m_vecMoveAng.y ) // Y axis rotation, move away from the player
+ {
+ // Positive is CCW, negative is CW, so make 'sign' 1 or -1 based on which way we want to open.
+ // Important note: All doors face East at all times, and twist their local angle to open.
+ // So you can't look at the door's facing to determine which way to open.
+
+ Vector nearestPoint;
+ CollisionProp()->CalcNearestPoint( m_hActivator->GetAbsOrigin(), &nearestPoint );
+ Vector activatorToNearestPoint = nearestPoint - m_hActivator->GetAbsOrigin();
+ activatorToNearestPoint.z = 0;
+
+ Vector activatorToOrigin = GetAbsOrigin() - m_hActivator->GetAbsOrigin();
+ activatorToOrigin.z = 0;
+
+ // Point right hand at door hinge, curl hand towards closest spot on door, if thumb
+ // is up, open door CW. -- Department of Basic Cross Product Understanding for Noobs
+ Vector cross = activatorToOrigin.Cross( activatorToNearestPoint );
+
+ if( cross.z > 0.0f )
+ {
+ sign = -1.0f;
+ }
+ }
+ }
+ AngularMove(m_vecAngle2*sign, m_flSpeed);
+ }
+ else
+ {
+ LinearMove(m_vecPosition2, m_flSpeed);
+ }
+
+ //Fire our open ouput
+ m_OnOpen.FireOutput( this, this );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: The door has reached the "up" position. Either go back down, or
+// wait for another activation.
+//-----------------------------------------------------------------------------
+void CBaseDoor::DoorHitTop( void )
+{
+ if ( !HasSpawnFlags( SF_DOOR_SILENT ) )
+ {
+ CPASAttenuationFilter filter( this );
+ filter.MakeReliable();
+ StopMovingSound();
+
+ EmitSound_t ep;
+ ep.m_nChannel = CHAN_STATIC;
+ ep.m_pSoundName = (char*)STRING(m_NoiseArrived);
+ ep.m_flVolume = 1;
+ ep.m_SoundLevel = SNDLVL_NORM;
+
+ EmitSound( filter, entindex(), ep );
+ }
+
+ ASSERT(m_toggle_state == TS_GOING_UP);
+ m_toggle_state = TS_AT_TOP;
+
+ // toggle-doors don't come down automatically, they wait for refire.
+ if (HasSpawnFlags( SF_DOOR_NO_AUTO_RETURN))
+ {
+ // Re-instate touch method, movement is complete
+ SetTouch( &CBaseDoor::DoorTouch );
+ }
+ else
+ {
+ // In flWait seconds, DoorGoDown will fire, unless wait is -1, then door stays open
+ SetMoveDoneTime( m_flWait );
+ SetMoveDone( &CBaseDoor::DoorGoDown );
+
+ if ( m_flWait == -1 )
+ {
+ SetNextThink( TICK_NEVER_THINK );
+ }
+ }
+
+ if (HasSpawnFlags(SF_DOOR_START_OPEN_OBSOLETE) )
+ {
+ m_OnFullyClosed.FireOutput(this, this);
+ }
+ else
+ {
+ m_OnFullyOpen.FireOutput(this, this);
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Starts the door going to its "down" position (simply ToggleData->vecPosition1).
+//-----------------------------------------------------------------------------
+void CBaseDoor::DoorGoDown( void )
+{
+ if ( !HasSpawnFlags( SF_DOOR_SILENT ) )
+ {
+ // If we're not moving already, start the moving noise
+ if ( m_toggle_state != TS_GOING_UP && m_toggle_state != TS_GOING_DOWN )
+ {
+ StartMovingSound();
+ }
+ }
+
+#ifdef DOOR_ASSERT
+ ASSERT(m_toggle_state == TS_AT_TOP);
+#endif // DOOR_ASSERT
+ m_toggle_state = TS_GOING_DOWN;
+
+ SetMoveDone( &CBaseDoor::DoorHitBottom );
+ if ( IsRotatingDoor() )//rotating door
+ AngularMove( m_vecAngle1, m_flSpeed);
+ else
+ LinearMove( m_vecPosition1, m_flSpeed);
+
+ //Fire our closed output
+ m_OnClose.FireOutput( this, this );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: The door has reached the "down" position. Back to quiescence.
+//-----------------------------------------------------------------------------
+void CBaseDoor::DoorHitBottom( void )
+{
+ if ( !HasSpawnFlags( SF_DOOR_SILENT ) )
+ {
+ CPASAttenuationFilter filter( this );
+ filter.MakeReliable();
+
+ StopMovingSound();
+
+ EmitSound_t ep;
+ ep.m_nChannel = CHAN_STATIC;
+ if ( m_NoiseArrivedClosed == NULL_STRING )
+ ep.m_pSoundName = (char*)STRING(m_NoiseArrived);
+ else
+ ep.m_pSoundName = (char*)STRING(m_NoiseArrivedClosed);
+ ep.m_flVolume = 1;
+ ep.m_SoundLevel = SNDLVL_NORM;
+
+ EmitSound( filter, entindex(), ep );
+ }
+
+ ASSERT(m_toggle_state == TS_GOING_DOWN);
+ m_toggle_state = TS_AT_BOTTOM;
+
+ // Re-instate touch method, cycle is complete
+ SetTouch( &CBaseDoor::DoorTouch );
+
+ if (HasSpawnFlags(SF_DOOR_START_OPEN_OBSOLETE))
+ {
+ m_OnFullyOpen.FireOutput(m_hActivator, this);
+ }
+ else
+ {
+ m_OnFullyClosed.FireOutput(m_hActivator, this);
+ }
+
+ // Close the area portals just after the door closes, to prevent visual artifacts in multiplayer games
+ SetContextThink( &CBaseDoor::CloseAreaPortalsThink, gpGlobals->curtime + 0.5f, CLOSE_AREAPORTAL_THINK_CONTEXT );
+}
+
+
+// Lists all doors in the same movement group as this one
+int CBaseDoor::GetDoorMovementGroup( CBaseDoor *pDoorList[], int listMax )
+{
+ int count = 0;
+ CBaseEntity *pTarget = NULL;
+
+ // Block all door pieces with the same targetname here.
+ if ( GetEntityName() != NULL_STRING )
+ {
+ for (;;)
+ {
+ pTarget = gEntList.FindEntityByName( pTarget, GetEntityName(), NULL );
+
+ if ( pTarget != this )
+ {
+ if ( !pTarget )
+ break;
+
+ CBaseDoor *pDoor = dynamic_cast<CBaseDoor *>(pTarget);
+
+ if ( pDoor && count < listMax )
+ {
+ pDoorList[count] = pDoor;
+ count++;
+ }
+ }
+ }
+ }
+
+ return count;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Called the first frame that the door is blocked while opening or closing.
+// Input : pOther - The blocking entity.
+//-----------------------------------------------------------------------------
+void CBaseDoor::StartBlocked( CBaseEntity *pOther )
+{
+ //
+ // Fire whatever events we need to due to our blocked state.
+ //
+ if (m_toggle_state == TS_GOING_DOWN)
+ {
+ m_OnBlockedClosing.FireOutput(pOther, this);
+ }
+ else
+ {
+ m_OnBlockedOpening.FireOutput(pOther, this);
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Called every frame when the door is blocked while opening or closing.
+// Input : pOther - The blocking entity.
+//-----------------------------------------------------------------------------
+void CBaseDoor::Blocked( CBaseEntity *pOther )
+{
+ // Hurt the blocker a little.
+ if ( m_flBlockDamage )
+ {
+ // if the door is marked "force closed" or it has a negative wait, then there's nothing to do but
+ // push/damage the object.
+ // If block damage is set, but this object is a physics prop that can't be damaged, just
+ // give up and disable collisions
+ if ( (m_bForceClosed || m_flWait < 0) && pOther->GetMoveType() == MOVETYPE_VPHYSICS &&
+ (pOther->m_takedamage == DAMAGE_NO || pOther->m_takedamage == DAMAGE_EVENTS_ONLY) )
+ {
+ EntityPhysics_CreateSolver( this, pOther, true, 4.0f );
+ }
+ else
+ {
+ pOther->TakeDamage( CTakeDamageInfo( this, this, m_flBlockDamage, DMG_CRUSH ) );
+ }
+ }
+ // If set, ignore non-player ents that block us. Mainly of use in multiplayer to prevent exploits.
+ else if ( pOther && !pOther->IsPlayer() && m_bIgnoreNonPlayerEntsOnBlock )
+ {
+ return;
+ }
+
+ // If we're set to force ourselves closed, keep going
+ if ( m_bForceClosed )
+ return;
+
+ // if a door has a negative wait, it would never come back if blocked,
+ // so let it just squash the object to death real fast
+ if (m_flWait >= 0)
+ {
+ if (m_toggle_state == TS_GOING_DOWN)
+ {
+ DoorGoUp();
+ }
+ else
+ {
+ DoorGoDown();
+ }
+ }
+
+ // Block all door pieces with the same targetname here.
+ if ( GetEntityName() != NULL_STRING )
+ {
+ CBaseDoor *pDoorList[64];
+ int doorCount = GetDoorMovementGroup( pDoorList, ARRAYSIZE(pDoorList) );
+
+ for ( int i = 0; i < doorCount; i++ )
+ {
+ CBaseDoor *pDoor = pDoorList[i];
+
+ if ( pDoor->m_flWait >= 0)
+ {
+ if (m_bDoorGroup && pDoor->m_vecMoveDir == m_vecMoveDir && pDoor->GetAbsVelocity() == GetAbsVelocity() && pDoor->GetLocalAngularVelocity() == GetLocalAngularVelocity())
+ {
+ pDoor->m_nSimulationTick = m_nSimulationTick; // don't run simulation this frame if you haven't run yet
+
+ // this is the most hacked, evil, bastardized thing I've ever seen. kjb
+ if ( !pDoor->IsRotatingDoor() )
+ {// set origin to realign normal doors
+ pDoor->SetLocalOrigin( GetLocalOrigin() );
+ pDoor->SetAbsVelocity( vec3_origin );// stop!
+
+ }
+ else
+ {// set angles to realign rotating doors
+ pDoor->SetLocalAngles( GetLocalAngles() );
+ pDoor->SetLocalAngularVelocity( vec3_angle );
+ }
+ }
+
+ if ( pDoor->m_toggle_state == TS_GOING_DOWN)
+ pDoor->DoorGoUp();
+ else
+ pDoor->DoorGoDown();
+ }
+ }
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Called the first frame that the door is unblocked while opening or closing.
+//-----------------------------------------------------------------------------
+void CBaseDoor::EndBlocked( void )
+{
+ //
+ // Fire whatever events we need to due to our unblocked state.
+ //
+ if (m_toggle_state == TS_GOING_DOWN)
+ {
+ m_OnUnblockedClosing.FireOutput(this, this);
+ }
+ else
+ {
+ m_OnUnblockedOpening.FireOutput(this, this);
+ }
+}
+
+
+/*func_door_rotating
+
+TOGGLE causes the door to wait in both the start and end states for
+a trigger event.
+
+START_OPEN causes the door to move to its destination when spawned,
+and operate in reverse. It is used to temporarily or permanently
+close off an area when triggered (not usefull for touch or
+takedamage doors).
+
+You need to have an origin brush as part of this entity. The
+center of that brush will be
+the point around which it is rotated. It will rotate around the Z
+axis by default. You can
+check either the X_AXIS or Y_AXIS box to change that.
+
+"distance" is how many degrees the door will be rotated.
+"speed" determines how fast the door moves; default value is 100.
+
+REVERSE will cause the door to rotate in the opposite direction.
+
+"angle" determines the opening direction
+"targetname" if set, no touch field will be spawned and a remote
+button or trigger field activates the door.
+"health" if set, door must be shot open
+"speed" movement speed (100 default)
+"wait" wait before returning (3 default, -1 = never return)
+"dmg" damage to inflict when blocked (2 default)
+*/
+
+//==================================================
+// CRotDoor
+//==================================================
+
+class CRotDoor : public CBaseDoor
+{
+public:
+ DECLARE_CLASS( CRotDoor, CBaseDoor );
+
+ void Spawn( void );
+ bool CreateVPhysics();
+ // This is ONLY used by the node graph to test movement through a door
+ virtual void SetToggleState( int state );
+ virtual bool IsRotatingDoor() { return true; }
+
+ bool m_bSolidBsp;
+
+ DECLARE_DATADESC();
+};
+
+LINK_ENTITY_TO_CLASS( func_door_rotating, CRotDoor );
+
+BEGIN_DATADESC( CRotDoor )
+ DEFINE_KEYFIELD( m_bSolidBsp, FIELD_BOOLEAN, "solidbsp" ),
+END_DATADESC()
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CRotDoor::Spawn( void )
+{
+ BaseClass::Spawn();
+
+ // set the axis of rotation
+ CBaseToggle::AxisDir();
+
+ // check for clockwise rotation
+ if ( HasSpawnFlags(SF_DOOR_ROTATE_BACKWARDS) )
+ m_vecMoveAng = m_vecMoveAng * -1;
+
+ //m_flWait = 2; who the hell did this? (sjb)
+ m_vecAngle1 = GetLocalAngles();
+ m_vecAngle2 = GetLocalAngles() + m_vecMoveAng * m_flMoveDistance;
+
+ ASSERTSZ(m_vecAngle1 != m_vecAngle2, "rotating door start/end positions are equal\n");
+
+ // Starting open allows a func_door to be lighted in the closed position but
+ // spawn in the open position
+ //
+ // SF_DOOR_START_OPEN_OBSOLETE is an old broken way of spawning open that has
+ // been deprecated.
+ if ( HasSpawnFlags(SF_DOOR_START_OPEN_OBSOLETE) )
+ {
+ // swap pos1 and pos2, put door at pos2, invert movement direction
+ QAngle vecNewAngles = m_vecAngle2;
+ m_vecAngle2 = m_vecAngle1;
+ m_vecAngle1 = vecNewAngles;
+ m_vecMoveAng = -m_vecMoveAng;
+
+ // We've already had our physics setup in BaseClass::Spawn, so teleport to our
+ // current position. If we don't do this, our vphysics shadow will not update.
+ Teleport( NULL, &m_vecAngle1, NULL );
+
+ m_toggle_state = TS_AT_BOTTOM;
+ }
+ else if ( m_eSpawnPosition == FUNC_DOOR_SPAWN_OPEN )
+ {
+ // We've already had our physics setup in BaseClass::Spawn, so teleport to our
+ // current position. If we don't do this, our vphysics shadow will not update.
+ Teleport( NULL, &m_vecAngle2, NULL );
+ m_toggle_state = TS_AT_TOP;
+ }
+ else
+ {
+ m_toggle_state = TS_AT_BOTTOM;
+ }
+
+#ifdef HL1_DLL
+ SetSolid( SOLID_VPHYSICS );
+#endif
+
+ // Slam the object back to solid - if we really want it to be solid.
+ if ( m_bSolidBsp )
+ {
+ SetSolid( SOLID_BSP );
+ }
+}
+
+//-----------------------------------------------------------------------------
+
+bool CRotDoor::CreateVPhysics()
+{
+ if ( !IsSolidFlagSet( FSOLID_NOT_SOLID ) )
+ {
+ VPhysicsInitShadow( false, false );
+ }
+
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : state -
+//-----------------------------------------------------------------------------
+// This is ONLY used by the node graph to test movement through a door
+void CRotDoor::SetToggleState( int state )
+{
+ if ( state == TS_AT_TOP )
+ SetLocalAngles( m_vecAngle2 );
+ else
+ SetLocalAngles( m_vecAngle1 );
+}