Portable Half-Life SDK. GoldSource and Xash3D. Crossplatform.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1133 lines
29 KiB

9 years ago
/***
*
* Copyright (c) 1996-2002, Valve LLC. All rights reserved.
*
* This product contains software technology licensed from Id
* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc.
* All Rights Reserved.
*
* Use, distribution, and modification of this source code and/or resulting
* object code is restricted to non-commercial enhancements to products from
* Valve LLC. All other use, distribution, or modification is prohibited
* without written permission from Valve LLC.
*
****/
/*
===== doors.cpp ========================================================
*/
#include "extdll.h"
#include "util.h"
#include "cbase.h"
#include "doors.h"
#include "game.h"
#include "weapons.h"
9 years ago
8 years ago
extern void SetMovedir( entvars_t *ev );
9 years ago
#define noiseMoving noise1
#define noiseArrived noise2
class CBaseDoor : public CBaseToggle
{
public:
void Spawn( void );
void Precache( void );
virtual void KeyValue( KeyValueData *pkvd );
virtual void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
virtual void Blocked( CBaseEntity *pOther );
8 years ago
virtual int ObjectCaps( void )
9 years ago
{
8 years ago
if( pev->spawnflags & SF_ITEM_USE_ONLY )
return ( CBaseToggle::ObjectCaps() & ~FCAP_ACROSS_TRANSITION ) | FCAP_IMPULSE_USE;
9 years ago
else
return (CBaseToggle::ObjectCaps() & ~FCAP_ACROSS_TRANSITION);
};
8 years ago
virtual int Save( CSave &save );
virtual int Restore( CRestore &restore );
static TYPEDESCRIPTION m_SaveData[];
9 years ago
virtual void SetToggleState( int state );
// used to selectivly override defaults
void EXPORT DoorTouch( CBaseEntity *pOther );
// local functions
8 years ago
int DoorActivate();
9 years ago
void EXPORT DoorGoUp( void );
void EXPORT DoorGoDown( void );
void EXPORT DoorHitTop( void );
void EXPORT DoorHitBottom( void );
8 years ago
BYTE m_bHealthValue;// some doors are medi-kit doors, they give players health
BYTE m_bMoveSnd; // sound a door makes while moving
BYTE m_bStopSnd; // sound a door makes when it stops
9 years ago
locksound_t m_ls; // door lock sounds
8 years ago
BYTE m_bLockedSound; // ordinals from entity selection
BYTE m_bLockedSentence;
BYTE m_bUnlockedSound;
BYTE m_bUnlockedSentence;
9 years ago
};
TYPEDESCRIPTION CBaseDoor::m_SaveData[] =
9 years ago
{
DEFINE_FIELD( CBaseDoor, m_bHealthValue, FIELD_CHARACTER ),
DEFINE_FIELD( CBaseDoor, m_bMoveSnd, FIELD_CHARACTER ),
DEFINE_FIELD( CBaseDoor, m_bStopSnd, FIELD_CHARACTER ),
8 years ago
9 years ago
DEFINE_FIELD( CBaseDoor, m_bLockedSound, FIELD_CHARACTER ),
DEFINE_FIELD( CBaseDoor, m_bLockedSentence, FIELD_CHARACTER ),
8 years ago
DEFINE_FIELD( CBaseDoor, m_bUnlockedSound, FIELD_CHARACTER ),
DEFINE_FIELD( CBaseDoor, m_bUnlockedSentence, FIELD_CHARACTER ),
9 years ago
};
IMPLEMENT_SAVERESTORE( CBaseDoor, CBaseToggle )
9 years ago
#define DOOR_SENTENCEWAIT 6
#define DOOR_SOUNDWAIT 3
#define BUTTON_SOUNDWAIT 0.5
// play door or button locked or unlocked sounds.
// pass in pointer to valid locksound struct.
// if flocked is true, play 'door is locked' sound,
// otherwise play 'door is unlocked' sound
// NOTE: this routine is shared by doors and buttons
8 years ago
void PlayLockSounds( entvars_t *pev, locksound_t *pls, int flocked, int fbutton )
9 years ago
{
// LOCKED SOUND
8 years ago
9 years ago
// CONSIDER: consolidate the locksound_t struct (all entries are duplicates for lock/unlock)
// CONSIDER: and condense this code.
float flsoundwait;
8 years ago
if( fbutton )
9 years ago
flsoundwait = BUTTON_SOUNDWAIT;
else
flsoundwait = DOOR_SOUNDWAIT;
8 years ago
if( flocked )
9 years ago
{
8 years ago
int fplaysound = ( pls->sLockedSound && gpGlobals->time > pls->flwaitSound );
int fplaysentence = ( pls->sLockedSentence && !pls->bEOFLocked && gpGlobals->time > pls->flwaitSentence );
9 years ago
float fvol;
8 years ago
if( fplaysound && fplaysentence )
9 years ago
fvol = 0.25;
else
fvol = 1.0;
// if there is a locked sound, and we've debounced, play sound
8 years ago
if( fplaysound )
9 years ago
{
// play 'door locked' sound
EMIT_SOUND( ENT( pev ), CHAN_ITEM, STRING( pls->sLockedSound ), fvol, ATTN_NORM );
9 years ago
pls->flwaitSound = gpGlobals->time + flsoundwait;
}
// if there is a sentence, we've not played all in list, and we've debounced, play sound
8 years ago
if( fplaysentence )
9 years ago
{
// play next 'door locked' sentence in group
int iprev = pls->iLockedSentence;
8 years ago
pls->iLockedSentence = SENTENCEG_PlaySequentialSz( ENT( pev ), STRING( pls->sLockedSentence ),
0.85, ATTN_NORM, 0, 100, pls->iLockedSentence, FALSE );
9 years ago
pls->iUnlockedSentence = 0;
// make sure we don't keep calling last sentence in list
8 years ago
pls->bEOFLocked = ( iprev == pls->iLockedSentence );
9 years ago
pls->flwaitSentence = gpGlobals->time + DOOR_SENTENCEWAIT;
}
}
else
{
// UNLOCKED SOUND
8 years ago
int fplaysound = ( pls->sUnlockedSound && gpGlobals->time > pls->flwaitSound );
int fplaysentence = ( pls->sUnlockedSentence && !pls->bEOFUnlocked && gpGlobals->time > pls->flwaitSentence );
9 years ago
float fvol;
// if playing both sentence and sound, lower sound volume so we hear sentence
8 years ago
if( fplaysound && fplaysentence )
9 years ago
fvol = 0.25;
else
fvol = 1.0;
// play 'door unlocked' sound if set
8 years ago
if( fplaysound )
9 years ago
{
EMIT_SOUND( ENT( pev ), CHAN_ITEM, STRING( pls->sUnlockedSound ), fvol, ATTN_NORM );
9 years ago
pls->flwaitSound = gpGlobals->time + flsoundwait;
}
// play next 'door unlocked' sentence in group
8 years ago
if( fplaysentence )
9 years ago
{
int iprev = pls->iUnlockedSentence;
8 years ago
pls->iUnlockedSentence = SENTENCEG_PlaySequentialSz( ENT( pev ), STRING( pls->sUnlockedSentence ),
0.85, ATTN_NORM, 0, 100, pls->iUnlockedSentence, FALSE );
9 years ago
pls->iLockedSentence = 0;
// make sure we don't keep calling last sentence in list
8 years ago
pls->bEOFUnlocked = ( iprev == pls->iUnlockedSentence );
9 years ago
pls->flwaitSentence = gpGlobals->time + DOOR_SENTENCEWAIT;
}
}
}
//
// Cache user-entity-field values until spawn is called.
//
void CBaseDoor::KeyValue( KeyValueData *pkvd )
{
8 years ago
if( FStrEq( pkvd->szKeyName, "skin" ) )//skin is used for content type
9 years ago
{
pev->skin = atoi( pkvd->szValue );
9 years ago
pkvd->fHandled = TRUE;
}
8 years ago
else if( FStrEq( pkvd->szKeyName, "movesnd" ) )
9 years ago
{
m_bMoveSnd = atoi( pkvd->szValue );
9 years ago
pkvd->fHandled = TRUE;
}
8 years ago
else if( FStrEq( pkvd->szKeyName, "stopsnd" ) )
9 years ago
{
m_bStopSnd = atoi( pkvd->szValue );
9 years ago
pkvd->fHandled = TRUE;
}
8 years ago
else if( FStrEq( pkvd->szKeyName, "healthvalue" ) )
9 years ago
{
m_bHealthValue = atoi( pkvd->szValue );
9 years ago
pkvd->fHandled = TRUE;
}
8 years ago
else if( FStrEq( pkvd->szKeyName, "locked_sound" ) )
9 years ago
{
m_bLockedSound = atoi( pkvd->szValue );
9 years ago
pkvd->fHandled = TRUE;
}
8 years ago
else if( FStrEq( pkvd->szKeyName, "locked_sentence" ) )
9 years ago
{
m_bLockedSentence = atoi( pkvd->szValue );
9 years ago
pkvd->fHandled = TRUE;
}
8 years ago
else if( FStrEq( pkvd->szKeyName, "unlocked_sound" ) )
9 years ago
{
m_bUnlockedSound = atoi( pkvd->szValue );
9 years ago
pkvd->fHandled = TRUE;
}
8 years ago
else if( FStrEq( pkvd->szKeyName, "unlocked_sentence" ) )
9 years ago
{
m_bUnlockedSentence = atoi( pkvd->szValue );
9 years ago
pkvd->fHandled = TRUE;
}
8 years ago
else if( FStrEq( pkvd->szKeyName, "WaveHeight" ) )
9 years ago
{
8 years ago
pev->scale = atof( pkvd->szValue ) * ( 1.0 / 8.0 );
9 years ago
pkvd->fHandled = TRUE;
}
else
CBaseToggle::KeyValue( pkvd );
}
/*QUAKED func_door (0 .5 .8) ? START_OPEN x DOOR_DONT_LINK TOGGLE
if two doors touch, they are assumed to be connected and operate as a unit.
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).
"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)
"lip" lip remaining at end of move (8 default)
"dmg" damage to inflict when blocked (2 default)
"sounds"
0) no sound
1) stone
2) base
3) stone chain
4) screechy metal
*/
LINK_ENTITY_TO_CLASS( func_door, CBaseDoor )
9 years ago
//
// func_water - same as a door.
//
LINK_ENTITY_TO_CLASS( func_water, CBaseDoor )
9 years ago
8 years ago
void CBaseDoor::Spawn()
9 years ago
{
Precache();
8 years ago
SetMovedir( pev );
9 years ago
8 years ago
if( pev->skin == 0 )
{
//normal door
8 years ago
if( FBitSet( pev->spawnflags, SF_DOOR_PASSABLE ) )
pev->solid = SOLID_NOT;
9 years ago
else
8 years ago
pev->solid = SOLID_BSP;
9 years ago
}
else
{
// special contents
8 years ago
pev->solid = SOLID_NOT;
9 years ago
SetBits( pev->spawnflags, SF_DOOR_SILENT ); // water is silent for now
}
8 years ago
pev->movetype = MOVETYPE_PUSH;
UTIL_SetOrigin( pev, pev->origin );
SET_MODEL( ENT( pev ), STRING( pev->model ) );
if( pev->speed == 0 )
9 years ago
pev->speed = 100;
8 years ago
m_vecPosition1 = pev->origin;
9 years ago
// Subtract 2 from size because the engine expands bboxes by 1 in all directions making the size too big
8 years ago
m_vecPosition2 = m_vecPosition1 + ( pev->movedir * ( fabs( pev->movedir.x * ( pev->size.x - 2 ) ) + fabs( pev->movedir.y * ( pev->size.y - 2 ) ) + fabs( pev->movedir.z * ( pev->size.z - 2 ) ) - m_flLip ) );
ASSERTSZ( m_vecPosition1 != m_vecPosition2, "door start/end positions are equal" );
if( FBitSet( pev->spawnflags, SF_DOOR_START_OPEN ) )
{
// swap pos1 and pos2, put door at pos2
8 years ago
UTIL_SetOrigin( pev, m_vecPosition2 );
9 years ago
m_vecPosition2 = m_vecPosition1;
m_vecPosition1 = pev->origin;
}
m_toggle_state = TS_AT_BOTTOM;
8 years ago
9 years ago
// if the door is flagged for USE button activation only, use NULL touch function
8 years ago
if( FBitSet( pev->spawnflags, SF_DOOR_USE_ONLY ) )
9 years ago
{
SetTouch( NULL );
}
else // touchable button
SetTouch( &CBaseDoor::DoorTouch );
}
8 years ago
void CBaseDoor::SetToggleState( int state )
9 years ago
{
8 years ago
if( state == TS_AT_TOP )
9 years ago
UTIL_SetOrigin( pev, m_vecPosition2 );
else
UTIL_SetOrigin( pev, m_vecPosition1 );
}
void CBaseDoor::Precache( void )
{
const char *pszSound;
BOOL NullSound = FALSE;
9 years ago
// set the door's "in-motion" sound
8 years ago
switch( m_bMoveSnd )
9 years ago
{
8 years ago
case 1:
pszSound = "doors/doormove1.wav";
8 years ago
break;
case 2:
pszSound = "doors/doormove2.wav";
8 years ago
break;
case 3:
pszSound = "doors/doormove3.wav";
8 years ago
break;
case 4:
pszSound = "doors/doormove4.wav";
8 years ago
break;
case 5:
pszSound = "doors/doormove5.wav";
8 years ago
break;
case 6:
pszSound = "doors/doormove6.wav";
8 years ago
break;
case 7:
pszSound = "doors/doormove7.wav";
8 years ago
break;
case 8:
pszSound = "doors/doormove8.wav";
8 years ago
break;
case 9:
pszSound = "doors/doormove9.wav";
8 years ago
break;
case 10:
pszSound = "doors/doormove10.wav";
8 years ago
break;
case 0:
8 years ago
default:
pszSound = "common/null.wav";
NullSound = TRUE;
8 years ago
break;
9 years ago
}
if( !NullSound )
PRECACHE_SOUND( pszSound );
pev->noiseMoving = MAKE_STRING( pszSound );
NullSound = FALSE;
// set the door's 'reached destination' stop sound
8 years ago
switch( m_bStopSnd )
9 years ago
{
8 years ago
case 1:
pszSound = "doors/doorstop1.wav";
8 years ago
break;
case 2:
pszSound = "doors/doorstop2.wav";
8 years ago
break;
case 3:
pszSound = "doors/doorstop3.wav";
8 years ago
break;
case 4:
pszSound = "doors/doorstop4.wav";
8 years ago
break;
case 5:
pszSound = "doors/doorstop5.wav";
8 years ago
break;
case 6:
pszSound = "doors/doorstop6.wav";
8 years ago
break;
case 7:
pszSound = "doors/doorstop7.wav";
8 years ago
break;
case 8:
pszSound = "doors/doorstop8.wav";
8 years ago
break;
case 0:
8 years ago
default:
pszSound = "common/null.wav";
NullSound = TRUE;
8 years ago
break;
9 years ago
}
if( !NullSound )
PRECACHE_SOUND( pszSound );
pev->noiseArrived = MAKE_STRING( pszSound );
9 years ago
// get door button sounds, for doors which are directly 'touched' to open
8 years ago
if( m_bLockedSound )
9 years ago
{
pszSound = ButtonSound( (int)m_bLockedSound );
8 years ago
PRECACHE_SOUND( pszSound );
m_ls.sLockedSound = MAKE_STRING( pszSound );
9 years ago
}
8 years ago
if( m_bUnlockedSound )
9 years ago
{
pszSound = ButtonSound( (int)m_bUnlockedSound );
8 years ago
PRECACHE_SOUND( pszSound );
m_ls.sUnlockedSound = MAKE_STRING( pszSound );
9 years ago
}
// get sentence group names, for doors which are directly 'touched' to open
8 years ago
switch( m_bLockedSentence )
9 years ago
{
8 years ago
case 1:
// access denied
m_ls.sLockedSentence = MAKE_STRING( "NA" );
8 years ago
break;
case 2:
// security lockout
m_ls.sLockedSentence = MAKE_STRING( "ND" );
8 years ago
break;
case 3:
// blast door
m_ls.sLockedSentence = MAKE_STRING( "NF" );
8 years ago
break;
case 4:
// fire door
m_ls.sLockedSentence = MAKE_STRING( "NFIRE" );
8 years ago
break;
case 5:
// chemical door
m_ls.sLockedSentence = MAKE_STRING( "NCHEM" );
8 years ago
break;
case 6:
// radiation door
m_ls.sLockedSentence = MAKE_STRING( "NRAD" );
8 years ago
break;
case 7:
// gen containment
m_ls.sLockedSentence = MAKE_STRING( "NCON" );
8 years ago
break;
case 8:
// maintenance door
m_ls.sLockedSentence = MAKE_STRING( "NH" );
8 years ago
break;
case 9:
// broken door
m_ls.sLockedSentence = MAKE_STRING( "NG" );
8 years ago
break;
default:
m_ls.sLockedSentence = 0;
break;
9 years ago
}
8 years ago
switch( m_bUnlockedSentence )
9 years ago
{
8 years ago
case 1:
// access granted
m_ls.sUnlockedSentence = MAKE_STRING( "EA" );
8 years ago
break;
case 2:
// security door
m_ls.sUnlockedSentence = MAKE_STRING( "ED" );
8 years ago
break;
case 3:
// blast door
m_ls.sUnlockedSentence = MAKE_STRING( "EF" );
8 years ago
break;
case 4:
// fire door
m_ls.sUnlockedSentence = MAKE_STRING( "EFIRE" );
8 years ago
break;
case 5:
// chemical door
m_ls.sUnlockedSentence = MAKE_STRING( "ECHEM" );
8 years ago
break;
case 6:
// radiation door
m_ls.sUnlockedSentence = MAKE_STRING( "ERAD" );
8 years ago
break;
case 7:
// gen containment
m_ls.sUnlockedSentence = MAKE_STRING( "ECON" );
8 years ago
break;
case 8:
// maintenance door
m_ls.sUnlockedSentence = MAKE_STRING( "EH" );
8 years ago
break;
default:
m_ls.sUnlockedSentence = 0;
break;
9 years ago
}
}
//
// Doors not tied to anything (e.g. button, another door) can be touched, to make them activate.
//
void CBaseDoor::DoorTouch( CBaseEntity *pOther )
{
8 years ago
entvars_t *pevToucher = pOther->pev;
9 years ago
// Ignore touches by anything but players
8 years ago
if( !FClassnameIs( pevToucher, "player" ) )
9 years ago
return;
// If door has master, and it's not ready to trigger,
// play 'locked' sound
8 years ago
if( m_sMaster && !UTIL_IsMasterTriggered( m_sMaster, pOther ) )
PlayLockSounds( pev, &m_ls, TRUE, FALSE );
9 years ago
// If door is somebody's target, then touching does nothing.
// You have to activate the owner (e.g. button).
8 years ago
if( !FStringNull( pev->targetname ) )
9 years ago
{
// play locked sound
8 years ago
PlayLockSounds( pev, &m_ls, TRUE, FALSE );
9 years ago
return;
}
8 years ago
9 years ago
m_hActivator = pOther;// remember who activated the door
8 years ago
if( DoorActivate())
9 years ago
SetTouch( NULL ); // Temporarily disable the touch function, until movement is finished.
}
//
// Used by SUB_UseTargets, when a door is the target of a button.
//
void CBaseDoor::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
{
m_hActivator = pActivator;
// if not ready to be used, ignore "use" command.
8 years ago
if( m_toggle_state == TS_AT_BOTTOM || ( FBitSet( pev->spawnflags, SF_DOOR_NO_AUTO_RETURN ) && m_toggle_state == TS_AT_TOP ) )
9 years ago
DoorActivate();
}
//
// Causes the door to "do its thing", i.e. start moving, and cascade activation.
//
8 years ago
int CBaseDoor::DoorActivate()
9 years ago
{
8 years ago
if( !UTIL_IsMasterTriggered( m_sMaster, m_hActivator ) )
9 years ago
return 0;
8 years ago
if( FBitSet( pev->spawnflags, SF_DOOR_NO_AUTO_RETURN ) && m_toggle_state == TS_AT_TOP )
{
// door should close
9 years ago
DoorGoDown();
}
else
{
// door should open
if( m_hActivator != 0 && m_hActivator->IsPlayer() )
{
// give health if player opened the door (medikit)
//VARS( m_eoActivator )->health += m_bHealthValue;
9 years ago
8 years ago
m_hActivator->TakeHealth( m_bHealthValue, DMG_GENERIC );
9 years ago
}
// play door unlock sounds
8 years ago
PlayLockSounds( pev, &m_ls, FALSE, FALSE );
9 years ago
DoorGoUp();
}
return 1;
}
extern Vector VecBModelOrigin( entvars_t* pevBModel );
//
// Starts the door going to its "up" position (simply ToggleData->vecPosition2).
//
void CBaseDoor::DoorGoUp( void )
{
8 years ago
entvars_t *pevActivator;
9 years ago
// It could be going-down, if blocked.
8 years ago
ASSERT( m_toggle_state == TS_AT_BOTTOM || m_toggle_state == TS_GOING_DOWN );
9 years ago
// 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!
8 years ago
if( !FBitSet( pev->spawnflags, SF_DOOR_SILENT ) )
if( m_toggle_state != TS_GOING_UP && m_toggle_state != TS_GOING_DOWN )
EMIT_SOUND( ENT( pev ), CHAN_STATIC, STRING( pev->noiseMoving ), 1, ATTN_NORM );
9 years ago
m_toggle_state = TS_GOING_UP;
8 years ago
9 years ago
SetMoveDone( &CBaseDoor::DoorHitTop );
8 years ago
if( FClassnameIs( pev, "func_door_rotating" ) ) // !!! BUGBUG Triggered doors don't work with this yet
9 years ago
{
8 years ago
float sign = 1.0;
9 years ago
if( m_hActivator != 0 )
9 years ago
{
pevActivator = m_hActivator->pev;
8 years ago
if( !FBitSet( pev->spawnflags, SF_DOOR_ONEWAY ) && pev->movedir.y ) // Y axis rotation, move away from the player
9 years ago
{
Vector vec = pevActivator->origin - pev->origin;
Vector angles = pevActivator->angles;
angles.x = 0;
angles.z = 0;
8 years ago
UTIL_MakeVectors( angles );
//Vector vnext = ( pevToucher->origin + ( pevToucher->velocity * 10 ) ) - pev->origin;
UTIL_MakeVectors( pevActivator->angles );
Vector vnext = ( pevActivator->origin + ( gpGlobals->v_forward * 10 ) ) - pev->origin;
if( ( vec.x * vnext.y - vec.y * vnext.x ) < 0 )
9 years ago
sign = -1.0;
}
}
8 years ago
AngularMove( m_vecAngle2*sign, pev->speed );
9 years ago
}
else
8 years ago
LinearMove( m_vecPosition2, pev->speed );
9 years ago
}
//
// The door has reached the "up" position. Either go back down, or wait for another activation.
//
void CBaseDoor::DoorHitTop( void )
{
8 years ago
if( !FBitSet( pev->spawnflags, SF_DOOR_SILENT ) )
9 years ago
{
STOP_SOUND( ENT( pev ), CHAN_STATIC, STRING( pev->noiseMoving ) );
EMIT_SOUND( ENT( pev ), CHAN_STATIC, STRING( pev->noiseArrived ), 1, ATTN_NORM );
9 years ago
}
8 years ago
ASSERT( m_toggle_state == TS_GOING_UP );
9 years ago
m_toggle_state = TS_AT_TOP;
8 years ago
9 years ago
// toggle-doors don't come down automatically, they wait for refire.
8 years ago
if( FBitSet( pev->spawnflags, SF_DOOR_NO_AUTO_RETURN ) )
9 years ago
{
// Re-instate touch method, movement is complete
8 years ago
if( !FBitSet( pev->spawnflags, SF_DOOR_USE_ONLY ) )
9 years ago
SetTouch( &CBaseDoor::DoorTouch );
}
else
{
// In flWait seconds, DoorGoDown will fire, unless wait is -1, then door stays open
pev->nextthink = pev->ltime + m_flWait;
SetThink( &CBaseDoor::DoorGoDown );
8 years ago
if( m_flWait == -1 )
9 years ago
{
pev->nextthink = -1;
}
}
// Fire the close target (if startopen is set, then "top" is closed) - netname is the close target
8 years ago
if( pev->netname && ( pev->spawnflags & SF_DOOR_START_OPEN ) )
FireTargets( STRING( pev->netname ), m_hActivator, this, USE_TOGGLE, 0 );
9 years ago
SUB_UseTargets( m_hActivator, USE_TOGGLE, 0 ); // this isn't finished
}
//
// Starts the door going to its "down" position (simply ToggleData->vecPosition1).
//
void CBaseDoor::DoorGoDown( void )
{
8 years ago
if( !FBitSet( pev->spawnflags, SF_DOOR_SILENT ) )
if( m_toggle_state != TS_GOING_UP && m_toggle_state != TS_GOING_DOWN )
EMIT_SOUND( ENT( pev ), CHAN_STATIC, STRING( pev->noiseMoving ), 1, ATTN_NORM );
9 years ago
#ifdef DOOR_ASSERT
8 years ago
ASSERT( m_toggle_state == TS_AT_TOP );
9 years ago
#endif // DOOR_ASSERT
m_toggle_state = TS_GOING_DOWN;
SetMoveDone( &CBaseDoor::DoorHitBottom );
8 years ago
if( FClassnameIs( pev, "func_door_rotating" ) )//rotating door
AngularMove( m_vecAngle1, pev->speed );
9 years ago
else
8 years ago
LinearMove( m_vecPosition1, pev->speed );
9 years ago
}
//
// The door has reached the "down" position. Back to quiescence.
//
void CBaseDoor::DoorHitBottom( void )
{
8 years ago
if( !FBitSet( pev->spawnflags, SF_DOOR_SILENT ) )
9 years ago
{
STOP_SOUND( ENT( pev ), CHAN_STATIC, STRING( pev->noiseMoving ) );
EMIT_SOUND( ENT( pev ), CHAN_STATIC, STRING( pev->noiseArrived ), 1, ATTN_NORM );
9 years ago
}
8 years ago
ASSERT( m_toggle_state == TS_GOING_DOWN );
9 years ago
m_toggle_state = TS_AT_BOTTOM;
// Re-instate touch method, cycle is complete
8 years ago
if( FBitSet( pev->spawnflags, SF_DOOR_USE_ONLY ) )
{
// use only door
9 years ago
SetTouch( NULL );
}
else // touchable door
SetTouch( &CBaseDoor::DoorTouch );
SUB_UseTargets( m_hActivator, USE_TOGGLE, 0 ); // this isn't finished
// Fire the close target (if startopen is set, then "top" is closed) - netname is the close target
8 years ago
if( pev->netname && !( pev->spawnflags & SF_DOOR_START_OPEN ) )
FireTargets( STRING( pev->netname ), m_hActivator, this, USE_TOGGLE, 0 );
9 years ago
}
void CBaseDoor::Blocked( CBaseEntity *pOther )
{
edict_t *pentTarget = NULL;
CBaseDoor *pDoor = NULL;
9 years ago
// Hurt the blocker a little.
8 years ago
if( pev->dmg )
9 years ago
pOther->TakeDamage( pev, pev, pev->dmg, DMG_CRUSH );
if( satchelfix.value )
{
// Detonate satchels
if( !strcmp( "monster_satchel", STRING( pOther->pev->classname ) ) )
( (CPipebomb*)pOther )->Use( this, this, USE_ON, 0 );
}
9 years ago
// 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
8 years ago
if( m_flWait >= 0 )
9 years ago
{
// BMod Start - Door sound fix.
if( !FBitSet( pev->spawnflags, SF_DOOR_SILENT ) )
STOP_SOUND( ENT( pev ), CHAN_STATIC, STRING( pev->noiseMoving ) );
// BMod End
8 years ago
if( m_toggle_state == TS_GOING_DOWN )
9 years ago
{
DoorGoUp();
}
else
{
DoorGoDown();
}
}
// Block all door pieces with the same targetname here.
8 years ago
if( !FStringNull( pev->targetname ) )
9 years ago
{
for( ; ; )
9 years ago
{
8 years ago
pentTarget = FIND_ENTITY_BY_TARGETNAME( pentTarget, STRING( pev->targetname ) );
9 years ago
8 years ago
if( VARS( pentTarget ) != pev )
9 years ago
{
8 years ago
if( FNullEnt( pentTarget ) )
9 years ago
break;
8 years ago
if( FClassnameIs( pentTarget, "func_door" ) || FClassnameIs( pentTarget, "func_door_rotating" ) )
9 years ago
{
8 years ago
pDoor = GetClassPtr( (CBaseDoor *)VARS( pentTarget ) );
9 years ago
8 years ago
if( pDoor->m_flWait >= 0 )
9 years ago
{
8 years ago
if( pDoor->pev->velocity == pev->velocity && pDoor->pev->avelocity == pev->velocity )
9 years ago
{
// this is the most hacked, evil, bastardized thing I've ever seen. kjb
8 years ago
if( FClassnameIs( pentTarget, "func_door" ) )
{
// set origin to realign normal doors
9 years ago
pDoor->pev->origin = pev->origin;
pDoor->pev->velocity = g_vecZero;// stop!
}
else
8 years ago
{
// set angles to realign rotating doors
9 years ago
pDoor->pev->angles = pev->angles;
pDoor->pev->avelocity = g_vecZero;
}
}
8 years ago
if( !FBitSet( pev->spawnflags, SF_DOOR_SILENT ) )
STOP_SOUND( ENT( pev ), CHAN_STATIC, STRING( pev->noiseMoving ) );
8 years ago
if( pDoor->m_toggle_state == TS_GOING_DOWN )
9 years ago
pDoor->DoorGoUp();
else
pDoor->DoorGoDown();
}
}
}
}
}
}
/*QUAKED FuncRotDoorSpawn (0 .5 .8) ? START_OPEN REVERSE
DOOR_DONT_LINK TOGGLE X_AXIS Y_AXIS
if two doors touch, they are assumed to be connected and operate as
a unit.
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)
"sounds"
0) no sound
1) stone
2) base
3) stone chain
4) screechy metal
*/
9 years ago
class CRotDoor : public CBaseDoor
{
public:
void Spawn( void );
virtual void SetToggleState( int state );
};
LINK_ENTITY_TO_CLASS( func_door_rotating, CRotDoor )
9 years ago
void CRotDoor::Spawn( void )
{
Precache();
// set the axis of rotation
CBaseToggle::AxisDir( pev );
// check for clockwise rotation
8 years ago
if( FBitSet( pev->spawnflags, SF_DOOR_ROTATE_BACKWARDS ) )
9 years ago
pev->movedir = pev->movedir * -1;
8 years ago
//m_flWait = 2; who the hell did this? (sjb)
m_vecAngle1 = pev->angles;
m_vecAngle2 = pev->angles + pev->movedir * m_flMoveDistance;
9 years ago
8 years ago
ASSERTSZ( m_vecAngle1 != m_vecAngle2, "rotating door start/end positions are equal" );
if( FBitSet( pev->spawnflags, SF_DOOR_PASSABLE ) )
pev->solid = SOLID_NOT;
9 years ago
else
8 years ago
pev->solid = SOLID_BSP;
9 years ago
8 years ago
pev->movetype = MOVETYPE_PUSH;
UTIL_SetOrigin( pev, pev->origin );
SET_MODEL( ENT( pev ), STRING( pev->model ) );
9 years ago
8 years ago
if( pev->speed == 0 )
9 years ago
pev->speed = 100;
8 years ago
// DOOR_START_OPEN is to allow an entity to be lighted in the closed position
// but spawn in the open position
8 years ago
if( FBitSet( pev->spawnflags, SF_DOOR_START_OPEN ) )
{
// swap pos1 and pos2, put door at pos2, invert movement direction
9 years ago
pev->angles = m_vecAngle2;
Vector vecSav = m_vecAngle1;
m_vecAngle2 = m_vecAngle1;
m_vecAngle1 = vecSav;
pev->movedir = pev->movedir * -1;
}
m_toggle_state = TS_AT_BOTTOM;
8 years ago
if( FBitSet( pev->spawnflags, SF_DOOR_USE_ONLY ) )
9 years ago
{
SetTouch( NULL );
}
else // touchable button
SetTouch( &CBaseDoor::DoorTouch );
}
8 years ago
void CRotDoor::SetToggleState( int state )
9 years ago
{
8 years ago
if( state == TS_AT_TOP )
9 years ago
pev->angles = m_vecAngle2;
else
pev->angles = m_vecAngle1;
UTIL_SetOrigin( pev, pev->origin );
}
class CMomentaryDoor : public CBaseToggle
{
public:
8 years ago
void Spawn( void );
9 years ago
void Precache( void );
void EXPORT MomentaryMoveDone( void );
void EXPORT StopMoveSound( void );
9 years ago
8 years ago
void KeyValue( KeyValueData *pkvd );
void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
virtual int ObjectCaps( void ) { return CBaseToggle::ObjectCaps() & ~FCAP_ACROSS_TRANSITION; }
9 years ago
8 years ago
virtual int Save( CSave &save );
virtual int Restore( CRestore &restore );
static TYPEDESCRIPTION m_SaveData[];
9 years ago
8 years ago
BYTE m_bMoveSnd; // sound a door makes while moving
BYTE m_bStopSnd; // sound a door makes when it stops
9 years ago
};
LINK_ENTITY_TO_CLASS( momentary_door, CMomentaryDoor )
9 years ago
8 years ago
TYPEDESCRIPTION CMomentaryDoor::m_SaveData[] =
9 years ago
{
DEFINE_FIELD( CMomentaryDoor, m_bMoveSnd, FIELD_CHARACTER ),
DEFINE_FIELD( CMomentaryDoor, m_bStopSnd, FIELD_CHARACTER ),
};
IMPLEMENT_SAVERESTORE( CMomentaryDoor, CBaseToggle )
9 years ago
void CMomentaryDoor::Spawn( void )
{
8 years ago
SetMovedir( pev );
9 years ago
8 years ago
pev->solid = SOLID_BSP;
pev->movetype = MOVETYPE_PUSH;
9 years ago
8 years ago
UTIL_SetOrigin( pev, pev->origin );
SET_MODEL( ENT( pev ), STRING( pev->model ) );
if( pev->speed == 0 )
9 years ago
pev->speed = 100;
8 years ago
if( pev->dmg == 0 )
9 years ago
pev->dmg = 2;
8 years ago
m_vecPosition1 = pev->origin;
9 years ago
// Subtract 2 from size because the engine expands bboxes by 1 in all directions making the size too big
8 years ago
m_vecPosition2 = m_vecPosition1 + ( pev->movedir * ( fabs( pev->movedir.x * ( pev->size.x - 2 ) ) + fabs( pev->movedir.y * ( pev->size.y - 2 ) ) + fabs( pev->movedir.z * ( pev->size.z - 2 ) ) - m_flLip ) );
ASSERTSZ( m_vecPosition1 != m_vecPosition2, "door start/end positions are equal" );
9 years ago
8 years ago
if( FBitSet( pev->spawnflags, SF_DOOR_START_OPEN ) )
9 years ago
{ // swap pos1 and pos2, put door at pos2
8 years ago
UTIL_SetOrigin( pev, m_vecPosition2 );
9 years ago
m_vecPosition2 = m_vecPosition1;
m_vecPosition1 = pev->origin;
}
SetTouch( NULL );
8 years ago
9 years ago
Precache();
}
9 years ago
void CMomentaryDoor::Precache( void )
{
const char *pszSound;
BOOL NullSound = FALSE;
// set the door's "in-motion" sound
8 years ago
switch( m_bMoveSnd )
9 years ago
{
8 years ago
case 1:
pszSound = "doors/doormove1.wav";
9 years ago
break;
8 years ago
case 2:
pszSound = "doors/doormove2.wav";
9 years ago
break;
8 years ago
case 3:
pszSound = "doors/doormove3.wav";
9 years ago
break;
8 years ago
case 4:
pszSound = "doors/doormove4.wav";
9 years ago
break;
8 years ago
case 5:
pszSound = "doors/doormove5.wav";
9 years ago
break;
8 years ago
case 6:
pszSound = "doors/doormove6.wav";
9 years ago
break;
8 years ago
case 7:
pszSound = "doors/doormove7.wav";
9 years ago
break;
8 years ago
case 8:
pszSound = "doors/doormove8.wav";
9 years ago
break;
case 0:
9 years ago
default:
pszSound = "common/null.wav";
NullSound = TRUE;
9 years ago
break;
}
if( !NullSound )
PRECACHE_SOUND( pszSound );
pev->noiseMoving = MAKE_STRING( pszSound );
NullSound = FALSE;
// set the door's 'reached destination' stop sound
8 years ago
switch( m_bStopSnd )
9 years ago
{
8 years ago
case 1:
pszSound = "doors/doorstop1.wav";
9 years ago
break;
8 years ago
case 2:
pszSound = "doors/doorstop2.wav";
9 years ago
break;
8 years ago
case 3:
pszSound = "doors/doorstop3.wav";
9 years ago
break;
8 years ago
case 4:
pszSound = "doors/doorstop4.wav";
9 years ago
break;
8 years ago
case 5:
pszSound = "doors/doorstop5.wav";
9 years ago
break;
8 years ago
case 6:
pszSound = "doors/doorstop6.wav";
9 years ago
break;
8 years ago
case 7:
pszSound = "doors/doorstop7.wav";
9 years ago
break;
8 years ago
case 8:
pszSound = "doors/doorstop8.wav";
9 years ago
break;
case 0:
9 years ago
default:
pszSound = "common/null.wav";
NullSound = TRUE;
9 years ago
break;
}
if( !NullSound )
PRECACHE_SOUND( pszSound );
pev->noiseArrived = MAKE_STRING( pszSound );
9 years ago
}
void CMomentaryDoor::KeyValue( KeyValueData *pkvd )
{
8 years ago
if( FStrEq( pkvd->szKeyName, "movesnd" ) )
9 years ago
{
m_bMoveSnd = atoi( pkvd->szValue );
9 years ago
pkvd->fHandled = TRUE;
}
8 years ago
else if( FStrEq( pkvd->szKeyName, "stopsnd" ) )
9 years ago
{
8 years ago
m_bStopSnd = atof( pkvd->szValue );
9 years ago
pkvd->fHandled = TRUE;
}
8 years ago
else if( FStrEq( pkvd->szKeyName, "healthvalue" ) )
9 years ago
{
8 years ago
//m_bHealthValue = atof( pkvd->szValue );
9 years ago
pkvd->fHandled = TRUE;
}
else
CBaseToggle::KeyValue( pkvd );
}
void CMomentaryDoor::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
{
8 years ago
if( useType != USE_SET ) // Momentary buttons will pass down a float in here
9 years ago
return;
8 years ago
if( value > 1.0 )
9 years ago
value = 1.0;
8 years ago
if( value < 0.0 )
value = 0.0;
8 years ago
Vector move = m_vecPosition1 + ( value * ( m_vecPosition2 - m_vecPosition1 ) );
9 years ago
Vector delta = move - pev->origin;
//float speed = delta.Length() * 10;
float speed = delta.Length() / 0.1; // move there in 0.1 sec
9 years ago
8 years ago
if( speed != 0 )
9 years ago
{
// This entity only thinks when it moves, so if it's thinking, it's in the process of moving
// play the sound when it starts moving(not yet thinking)
8 years ago
if( pev->nextthink < pev->ltime || pev->nextthink == 0 )
EMIT_SOUND( ENT( pev ), CHAN_STATIC, STRING( pev->noiseMoving ), 1, ATTN_NORM );
// If we already moving to designated point, return
else if( move == m_vecFinalDest )
return;
9 years ago
LinearMove( move, speed );
SetMoveDone( &CMomentaryDoor::MomentaryMoveDone );
}
}
void CMomentaryDoor::MomentaryMoveDone( void )
{
SetThink(&CMomentaryDoor::StopMoveSound);
pev->nextthink = pev->ltime + 0.1;
}
void CMomentaryDoor::StopMoveSound()
9 years ago
{
STOP_SOUND( ENT( pev ), CHAN_STATIC, STRING( pev->noiseMoving ) );
EMIT_SOUND( ENT( pev ), CHAN_STATIC, STRING( pev->noiseArrived ), 1, ATTN_NORM );
pev->nextthink = -1;
ResetThink();
}