From f56bb35301836e56582a575a75864392a0177875 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B8rgen=20P=2E=20Tjern=C3=B8?= Date: Mon, 2 Dec 2013 19:31:46 -0800 Subject: Fix line endings. WHAMMY. --- mp/src/game/server/buttons.cpp | 3172 ++++++++++++++++++++-------------------- 1 file changed, 1586 insertions(+), 1586 deletions(-) (limited to 'mp/src/game/server/buttons.cpp') diff --git a/mp/src/game/server/buttons.cpp b/mp/src/game/server/buttons.cpp index caab769d..af46d0c4 100644 --- a/mp/src/game/server/buttons.cpp +++ b/mp/src/game/server/buttons.cpp @@ -1,1587 +1,1587 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// -// -// Purpose: Implements buttons. -// -//============================================================================= - -#include "cbase.h" -#include "doors.h" -#include "ndebugoverlay.h" -#include "spark.h" -#include "vstdlib/random.h" -#include "engine/IEngineSound.h" -#include "tier1/strtools.h" -#include "buttons.h" -#include "eventqueue.h" - -// memdbgon must be the last include file in a .cpp file!!! -#include "tier0/memdbgon.h" - -void PlayLockSounds( CBaseEntity *pEdict, locksound_t *pls, int flocked, int fbutton ); -string_t MakeButtonSound( int sound ); // get string of button sound number - - -#define SF_BUTTON_DONTMOVE 1 -#define SF_ROTBUTTON_NOTSOLID 1 -#define SF_BUTTON_TOGGLE 32 // button stays pushed until reactivated -#define SF_BUTTON_TOUCH_ACTIVATES 256 // Button fires when touched. -#define SF_BUTTON_DAMAGE_ACTIVATES 512 // Button fires when damaged. -#define SF_BUTTON_USE_ACTIVATES 1024 // Button fires when used. -#define SF_BUTTON_LOCKED 2048 // Whether the button is initially locked. -#define SF_BUTTON_SPARK_IF_OFF 4096 // button sparks in OFF state -#define SF_BUTTON_JIGGLE_ON_USE_LOCKED 8192 // whether to jiggle if someone uses us when we're locked - -BEGIN_DATADESC( CBaseButton ) - - DEFINE_KEYFIELD( m_vecMoveDir, FIELD_VECTOR, "movedir" ), - DEFINE_FIELD( m_fStayPushed, FIELD_BOOLEAN ), - DEFINE_FIELD( m_fRotating, FIELD_BOOLEAN ), - - DEFINE_FIELD( m_bLockedSound, FIELD_CHARACTER ), - DEFINE_FIELD( m_bLockedSentence, FIELD_CHARACTER ), - DEFINE_FIELD( m_bUnlockedSound, FIELD_CHARACTER ), - DEFINE_FIELD( m_bUnlockedSentence, FIELD_CHARACTER ), - DEFINE_FIELD( m_bLocked, FIELD_BOOLEAN ), - DEFINE_FIELD( m_sNoise, FIELD_SOUNDNAME ), - DEFINE_FIELD( m_flUseLockedTime, FIELD_TIME ), - DEFINE_FIELD( m_bSolidBsp, FIELD_BOOLEAN ), - - DEFINE_KEYFIELD( m_sounds, FIELD_INTEGER, "sounds" ), - -// DEFINE_FIELD( m_ls, FIELD_SOUNDNAME ), // This is restored in Precache() -// DEFINE_FIELD( m_nState, FIELD_INTEGER ), - - // Function Pointers - DEFINE_FUNCTION( ButtonTouch ), - DEFINE_FUNCTION( ButtonSpark ), - DEFINE_FUNCTION( TriggerAndWait ), - DEFINE_FUNCTION( ButtonReturn ), - DEFINE_FUNCTION( ButtonBackHome ), - DEFINE_FUNCTION( ButtonUse ), - - // Inputs - DEFINE_INPUTFUNC( FIELD_VOID, "Lock", InputLock ), - DEFINE_INPUTFUNC( FIELD_VOID, "Unlock", InputUnlock ), - DEFINE_INPUTFUNC( FIELD_VOID, "Press", InputPress ), - DEFINE_INPUTFUNC( FIELD_VOID, "PressIn", InputPressIn ), - DEFINE_INPUTFUNC( FIELD_VOID, "PressOut", InputPressOut ), - - // Outputs - DEFINE_OUTPUT( m_OnDamaged, "OnDamaged" ), - DEFINE_OUTPUT( m_OnPressed, "OnPressed" ), - DEFINE_OUTPUT( m_OnUseLocked, "OnUseLocked" ), - DEFINE_OUTPUT( m_OnIn, "OnIn" ), - DEFINE_OUTPUT( m_OnOut, "OnOut" ), - -END_DATADESC() - - -LINK_ENTITY_TO_CLASS( func_button, CBaseButton ); - - - -void CBaseButton::Precache( void ) -{ - // get door button sounds, for doors which require buttons to open - if (m_bLockedSound) - { - m_ls.sLockedSound = MakeButtonSound( (int)m_bLockedSound ); - PrecacheScriptSound(m_ls.sLockedSound.ToCStr()); - } - - if (m_bUnlockedSound) - { - m_ls.sUnlockedSound = MakeButtonSound( (int)m_bUnlockedSound ); - PrecacheScriptSound(m_ls.sUnlockedSound.ToCStr()); - } - - // get sentence group names, for doors which are directly 'touched' to open - - switch (m_bLockedSentence) - { - case 1: m_ls.sLockedSentence = MAKE_STRING("NA"); break; // access denied - case 2: m_ls.sLockedSentence = MAKE_STRING("ND"); break; // security lockout - case 3: m_ls.sLockedSentence = MAKE_STRING("NF"); break; // blast door - case 4: m_ls.sLockedSentence = MAKE_STRING("NFIRE"); break; // fire door - case 5: m_ls.sLockedSentence = MAKE_STRING("NCHEM"); break; // chemical door - case 6: m_ls.sLockedSentence = MAKE_STRING("NRAD"); break; // radiation door - case 7: m_ls.sLockedSentence = MAKE_STRING("NCON"); break; // gen containment - case 8: m_ls.sLockedSentence = MAKE_STRING("NH"); break; // maintenance door - case 9: m_ls.sLockedSentence = MAKE_STRING("NG"); break; // broken door - - default: m_ls.sLockedSentence = NULL_STRING; break; - } - - switch (m_bUnlockedSentence) - { - case 1: m_ls.sUnlockedSentence = MAKE_STRING("EA"); break; // access granted - case 2: m_ls.sUnlockedSentence = MAKE_STRING("ED"); break; // security door - case 3: m_ls.sUnlockedSentence = MAKE_STRING("EF"); break; // blast door - case 4: m_ls.sUnlockedSentence = MAKE_STRING("EFIRE"); break; // fire door - case 5: m_ls.sUnlockedSentence = MAKE_STRING("ECHEM"); break; // chemical door - case 6: m_ls.sUnlockedSentence = MAKE_STRING("ERAD"); break; // radiation door - case 7: m_ls.sUnlockedSentence = MAKE_STRING("ECON"); break; // gen containment - case 8: m_ls.sUnlockedSentence = MAKE_STRING("EH"); break; // maintenance door - - default: m_ls.sUnlockedSentence = NULL_STRING; break; - } - - if ( m_sNoise != NULL_STRING ) - { - PrecacheScriptSound( STRING( m_sNoise ) ); - } -} - - -//----------------------------------------------------------------------------- -// Purpose: Cache user-entity-field values until spawn is called. -// Input : szKeyName - -// szValue - -// Output : Returns true if handled, false if not. -//----------------------------------------------------------------------------- -bool CBaseButton::KeyValue( const char *szKeyName, const char *szValue ) -{ - if (FStrEq(szKeyName, "locked_sound")) - { - m_bLockedSound = atof(szValue); - } - else if (FStrEq(szKeyName, "locked_sentence")) - { - m_bLockedSentence = atof(szValue); - } - else if (FStrEq(szKeyName, "unlocked_sound")) - { - m_bUnlockedSound = atof(szValue); - } - else if (FStrEq(szKeyName, "unlocked_sentence")) - { - m_bUnlockedSentence = atof(szValue); - } - else - { - return BaseClass::KeyValue( szKeyName, szValue ); - } - - return true; -} - - -//----------------------------------------------------------------------------- -// Purpose: Locks the button. If locked, the button will play the locked sound -// when the player tries to use it. -//----------------------------------------------------------------------------- -void CBaseButton::Lock() -{ - m_bLocked = true; -} - - -//----------------------------------------------------------------------------- -// Purpose: Unlocks the button, making it able to be pressed again. -//----------------------------------------------------------------------------- -void CBaseButton::Unlock() -{ - m_bLocked = false; -} - - -//----------------------------------------------------------------------------- -// Purpose: Locks the button. If locked, the button will play the locked sound -// when the player tries to use it. -//----------------------------------------------------------------------------- -void CBaseButton::InputLock( inputdata_t &inputdata ) -{ - Lock(); -} - - -//----------------------------------------------------------------------------- -// Purpose: Unlocks the button, making it able to be pressed again. -//----------------------------------------------------------------------------- -void CBaseButton::InputUnlock( inputdata_t &inputdata ) -{ - Unlock(); -} - - -//----------------------------------------------------------------------------- -// Presses or unpresses the button. -//----------------------------------------------------------------------------- -void CBaseButton::Press( CBaseEntity *pActivator, BUTTON_CODE eCode ) -{ - if ( ( eCode == BUTTON_PRESS ) && ( m_toggle_state == TS_GOING_UP || m_toggle_state == TS_GOING_DOWN ) ) - { - return; - } - - if ( ( eCode == BUTTON_ACTIVATE ) && ( m_toggle_state == TS_GOING_UP || m_toggle_state == TS_AT_TOP ) ) - { - return; - } - - if ( ( eCode == BUTTON_RETURN ) && ( m_toggle_state == TS_GOING_DOWN || m_toggle_state == TS_AT_BOTTOM ) ) - { - return; - } - - // FIXME: consolidate all the button press code into one place! - if (m_bLocked) - { - // play button locked sound - PlayLockSounds(this, &m_ls, TRUE, TRUE); - return; - } - - // Temporarily disable the touch function, until movement is finished. - SetTouch( NULL ); - - if ( ( ( eCode == BUTTON_PRESS ) && ( m_toggle_state == TS_AT_TOP ) ) || - ( ( eCode == BUTTON_RETURN ) && ( m_toggle_state == TS_AT_TOP || m_toggle_state == TS_GOING_UP ) ) ) - { - if ( m_sNoise != NULL_STRING ) - { - CPASAttenuationFilter filter( this ); - - EmitSound_t ep; - ep.m_nChannel = CHAN_VOICE; - ep.m_pSoundName = (char*)STRING(m_sNoise); - ep.m_flVolume = 1; - ep.m_SoundLevel = SNDLVL_NORM; - - EmitSound( filter, entindex(), ep ); - } - - m_OnPressed.FireOutput(pActivator, this); - ButtonReturn(); - } - else if ( ( eCode == BUTTON_PRESS ) || - ( ( eCode == BUTTON_ACTIVATE ) && ( m_toggle_state == TS_AT_BOTTOM || m_toggle_state == TS_GOING_DOWN ) ) ) - { - m_OnPressed.FireOutput(pActivator, this); - ButtonActivate(); - } -} - - -//----------------------------------------------------------------------------- -// Presses the button. -//----------------------------------------------------------------------------- -void CBaseButton::InputPress( inputdata_t &inputdata ) -{ - Press( inputdata.pActivator, BUTTON_PRESS ); -} - - -//----------------------------------------------------------------------------- -// Presses the button, sending it to the top/pressed position. -//----------------------------------------------------------------------------- -void CBaseButton::InputPressIn( inputdata_t &inputdata ) -{ - Press( inputdata.pActivator, BUTTON_ACTIVATE ); -} - - -//----------------------------------------------------------------------------- -// Unpresses the button, sending it to the unpressed/bottom position. -//----------------------------------------------------------------------------- -void CBaseButton::InputPressOut( inputdata_t &inputdata ) -{ - Press( inputdata.pActivator, BUTTON_RETURN ); -} - - -//----------------------------------------------------------------------------- -// Purpose: We have been damaged. Possibly activate, depending on our flags. -// Input : pInflictor - -// pAttacker - -// flDamage - -// bitsDamageType - -// Output : -//----------------------------------------------------------------------------- -int CBaseButton::OnTakeDamage( const CTakeDamageInfo &info ) -{ - m_OnDamaged.FireOutput(m_hActivator, this); - - // dvsents2: remove obselete health keyvalue from func_button - if (!HasSpawnFlags(SF_BUTTON_DAMAGE_ACTIVATES) && (m_iHealth == 0)) - { - return(0); - } - - BUTTON_CODE code = ButtonResponseToTouch(); - - if ( code == BUTTON_NOTHING ) - return 0; - - m_hActivator = info.GetAttacker(); - - // dvsents2: why would activator be NULL here? - if ( m_hActivator == NULL ) - return 0; - - if (m_bLocked) - { - return(0); - } - - // Temporarily disable the touch function, until movement is finished. - SetTouch( NULL ); - - if ( code == BUTTON_RETURN ) - { - if ( m_sNoise != NULL_STRING ) - { - CPASAttenuationFilter filter( this ); - - EmitSound_t ep; - ep.m_nChannel = CHAN_VOICE; - ep.m_pSoundName = (char*)STRING(m_sNoise); - ep.m_flVolume = 1; - ep.m_SoundLevel = SNDLVL_NORM; - - EmitSound( filter, entindex(), ep ); - } - - m_OnPressed.FireOutput(m_hActivator, this); - ButtonReturn(); - } - else - { - // code == BUTTON_ACTIVATE - m_OnPressed.FireOutput(m_hActivator, this); - ButtonActivate( ); - } - - return 0; -} - - -void CBaseButton::Spawn( ) -{ - //---------------------------------------------------- - //determine sounds for buttons - //a sound of 0 should not make a sound - //---------------------------------------------------- - if ( m_sounds ) - { - m_sNoise = MakeButtonSound( m_sounds ); - PrecacheScriptSound(m_sNoise.ToCStr()); - } - else - { - m_sNoise = NULL_STRING; - } - - Precache(); - - if ( HasSpawnFlags( SF_BUTTON_SPARK_IF_OFF ) )// this button should spark in OFF state - { - SetThink ( &CBaseButton::ButtonSpark ); - SetNextThink( gpGlobals->curtime + 0.5f );// no hurry, make sure everything else spawns - } - - // Convert movedir from angles to a vector - QAngle angMoveDir = QAngle( m_vecMoveDir.x, m_vecMoveDir.y, m_vecMoveDir.z ); - AngleVectors( angMoveDir, &m_vecMoveDir ); - - SetMoveType( MOVETYPE_PUSH ); - SetSolid( SOLID_BSP ); - SetModel( STRING( GetModelName() ) ); - - if (m_flSpeed == 0) - { - m_flSpeed = 40; - } - - m_takedamage = DAMAGE_YES; - - if (m_flWait == 0) - { - m_flWait = 1; - } - - if (m_flLip == 0) - { - m_flLip = 4; - } - - m_toggle_state = TS_AT_BOTTOM; - m_vecPosition1 = GetLocalOrigin(); - - // Subtract 2 from size because the engine expands bboxes by 1 in all directions making the size too big - Vector vecButtonOBB = CollisionProp()->OBBSize(); - vecButtonOBB -= Vector( 2, 2, 2 ); - m_vecPosition2 = m_vecPosition1 + (m_vecMoveDir * (DotProductAbs( m_vecMoveDir, vecButtonOBB ) - m_flLip)); - - // Is this a non-moving button? - if ( ((m_vecPosition2 - m_vecPosition1).Length() < 1) || HasSpawnFlags(SF_BUTTON_DONTMOVE) ) - { - m_vecPosition2 = m_vecPosition1; - } - - m_fStayPushed = (m_flWait == -1 ? TRUE : FALSE); - m_fRotating = FALSE; - - if (HasSpawnFlags(SF_BUTTON_LOCKED)) - { - m_bLocked = true; - } - - // - // If using activates the button, set its use function. - // - if (HasSpawnFlags(SF_BUTTON_USE_ACTIVATES)) - { - SetUse(&CBaseButton::ButtonUse); - } - else - { - SetUse(NULL); - } - - // - // If touching activates the button, set its touch function. - // - if (HasSpawnFlags(SF_BUTTON_TOUCH_ACTIVATES)) - { - SetTouch( &CBaseButton::ButtonTouch ); - } - else - { - SetTouch ( NULL ); - } - - CreateVPhysics(); -} - -//----------------------------------------------------------------------------- - -bool CBaseButton::CreateVPhysics() -{ - VPhysicsInitShadow( false, false ); - return true; -} - - -//----------------------------------------------------------------------------- -// Purpose: Button sound table. -// Also used by CBaseDoor to get 'touched' door lock/unlock sounds -// Input : sound - index of sound to look up. -// Output : Returns a pointer to the corresponding sound file. -//----------------------------------------------------------------------------- -string_t MakeButtonSound( int sound ) -{ - char tmp[1024]; - Q_snprintf( tmp, sizeof(tmp), "Buttons.snd%d", sound ); - return AllocPooledString(tmp); -} - - -//----------------------------------------------------------------------------- -// Purpose: Think function that emits sparks at random intervals. -//----------------------------------------------------------------------------- -void CBaseButton::ButtonSpark ( void ) -{ - SetThink ( &CBaseButton::ButtonSpark ); - SetNextThink( gpGlobals->curtime + 0.1 + random->RandomFloat ( 0, 1.5 ) );// spark again at random interval - - DoSpark( this, WorldSpaceCenter(), 1, 1, true, vec3_origin ); -} - - -//----------------------------------------------------------------------------- -// Purpose: Called when someone uses us whilst we are locked. -//----------------------------------------------------------------------------- -bool CBaseButton::OnUseLocked( CBaseEntity *pActivator ) -{ - PlayLockSounds(this, &m_ls, TRUE, TRUE); - - if ( gpGlobals->curtime > m_flUseLockedTime ) - { - m_OnUseLocked.FireOutput( pActivator, this ); - m_flUseLockedTime = gpGlobals->curtime + 0.5; - return true; - } - - return false; -} - - -//----------------------------------------------------------------------------- -// Purpose: Use function that starts the button moving. -// Input : pActivator - -// pCaller - -// useType - -// value - -//----------------------------------------------------------------------------- -void CBaseButton::ButtonUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - // Ignore touches if button is moving, or pushed-in and waiting to auto-come-out. - // UNDONE: Should this use ButtonResponseToTouch() too? - if (m_toggle_state == TS_GOING_UP || m_toggle_state == TS_GOING_DOWN ) - return; - - if (m_bLocked) - { - OnUseLocked( pActivator ); - return; - } - - m_hActivator = pActivator; - - if ( m_toggle_state == TS_AT_TOP) - { - // - // If it's a toggle button it can return now. Otherwise, it will either - // return on its own or will stay pressed indefinitely. - // - if ( HasSpawnFlags(SF_BUTTON_TOGGLE)) - { - if ( m_sNoise != NULL_STRING ) - { - CPASAttenuationFilter filter( this ); - - EmitSound_t ep; - ep.m_nChannel = CHAN_VOICE; - ep.m_pSoundName = (char*)STRING(m_sNoise); - ep.m_flVolume = 1; - ep.m_SoundLevel = SNDLVL_NORM; - - EmitSound( filter, entindex(), ep ); - } - - m_OnPressed.FireOutput(m_hActivator, this); - ButtonReturn(); - } - } - else - { - m_OnPressed.FireOutput(m_hActivator, this); - ButtonActivate( ); - } -} - - -//----------------------------------------------------------------------------- -// Purpose: Returns a code indicating how the button should respond to being touched. -// Output : Returns one of the following: -// BUTTON_NOTHING - do nothing -// BUTTON_RETURN - -// BUTTON_ACTIVATE - act as if pressed -//----------------------------------------------------------------------------- -CBaseButton::BUTTON_CODE CBaseButton::ButtonResponseToTouch( void ) -{ - // Ignore touches if button is moving, or pushed-in and waiting to auto-come-out. - if (m_toggle_state == TS_GOING_UP || - m_toggle_state == TS_GOING_DOWN || - (m_toggle_state == TS_AT_TOP && !m_fStayPushed && !HasSpawnFlags(SF_BUTTON_TOGGLE) ) ) - return BUTTON_NOTHING; - - if (m_toggle_state == TS_AT_TOP) - { - if ( HasSpawnFlags(SF_BUTTON_TOGGLE) && !m_fStayPushed) - { - return BUTTON_RETURN; - } - } - else - return BUTTON_ACTIVATE; - - return BUTTON_NOTHING; -} - - -//----------------------------------------------------------------------------- -// Purpose: Touch function that activates the button if it responds to touch. -// Input : pOther - The entity that touched us. -//----------------------------------------------------------------------------- -void CBaseButton::ButtonTouch( CBaseEntity *pOther ) -{ - // Ignore touches by anything but players - if ( !pOther->IsPlayer() ) - return; - - m_hActivator = pOther; - - BUTTON_CODE code = ButtonResponseToTouch(); - - if ( code == BUTTON_NOTHING ) - return; - - if (!UTIL_IsMasterTriggered(m_sMaster, pOther) || m_bLocked) - { - // play button locked sound - PlayLockSounds(this, &m_ls, TRUE, TRUE); - return; - } - - // Temporarily disable the touch function, until movement is finished. - SetTouch( NULL ); - - if ( code == BUTTON_RETURN ) - { - if ( m_sNoise != NULL_STRING ) - { - CPASAttenuationFilter filter( this ); - - EmitSound_t ep; - ep.m_nChannel = CHAN_VOICE; - ep.m_pSoundName = (char*)STRING(m_sNoise); - ep.m_flVolume = 1; - ep.m_SoundLevel = SNDLVL_NORM; - - EmitSound( filter, entindex(), ep ); - } - - m_OnPressed.FireOutput(m_hActivator, this); - ButtonReturn(); - } - else - { - // code == BUTTON_ACTIVATE - m_OnPressed.FireOutput(m_hActivator, this); - ButtonActivate( ); - } -} - - -//----------------------------------------------------------------------------- -// Purpose: Starts the button moving "in/up". -// Input : *pOther - -//----------------------------------------------------------------------------- -void CBaseButton::ButtonActivate( void ) -{ - if ( m_sNoise != NULL_STRING ) - { - CPASAttenuationFilter filter( this ); - - EmitSound_t ep; - ep.m_nChannel = CHAN_VOICE; - ep.m_pSoundName = (char*)STRING(m_sNoise); - ep.m_flVolume = 1; - ep.m_SoundLevel = SNDLVL_NORM; - - EmitSound( filter, entindex(), ep ); - } - - if (!UTIL_IsMasterTriggered(m_sMaster, m_hActivator) || m_bLocked) - { - // button is locked, play locked sound - PlayLockSounds(this, &m_ls, TRUE, TRUE); - return; - } - else - { - // button is unlocked, play unlocked sound - PlayLockSounds(this, &m_ls, FALSE, TRUE); - } - - ASSERT(m_toggle_state == TS_AT_BOTTOM); - m_toggle_state = TS_GOING_UP; - - SetMoveDone( &CBaseButton::TriggerAndWait ); - if (!m_fRotating) - LinearMove( m_vecPosition2, m_flSpeed); - else - AngularMove( m_vecAngle2, m_flSpeed); -} - - -//----------------------------------------------------------------------------- -// Purpose: Enables or disables the use capability based on our spawnflags. -//----------------------------------------------------------------------------- -int CBaseButton::ObjectCaps(void) -{ - return((BaseClass::ObjectCaps() & ~FCAP_ACROSS_TRANSITION) | - (HasSpawnFlags(SF_BUTTON_USE_ACTIVATES) ? (FCAP_IMPULSE_USE | FCAP_USE_IN_RADIUS) : 0)); -} - - -//----------------------------------------------------------------------------- -// Purpose: Button has reached the "pressed/top" position. Fire its OnIn output, -// and pause before returning to "unpressed/bottom". -//----------------------------------------------------------------------------- -void CBaseButton::TriggerAndWait( void ) -{ - ASSERT(m_toggle_state == TS_GOING_UP); - - if (!UTIL_IsMasterTriggered(m_sMaster, m_hActivator) || m_bLocked) - { - return; - } - - m_toggle_state = TS_AT_TOP; - - // - // Re-instate touches if the button is of the toggle variety. - // - if (m_fStayPushed || HasSpawnFlags(SF_BUTTON_TOGGLE ) ) - { - if (HasSpawnFlags(SF_BUTTON_TOUCH_ACTIVATES)) - { - SetTouch(&CBaseButton::ButtonTouch); - } - else - { - // BUGBUG: ALL buttons no longer respond to touch - SetTouch (NULL); - } - } - - // - // If button automatically comes back out, start it moving out. - // - else - { - SetNextThink( gpGlobals->curtime + m_flWait ); - SetThink( &CBaseButton::ButtonReturn ); - } - - m_nState = 1; // use alternate textures - - m_OnIn.FireOutput(m_hActivator, this); -} - - -//----------------------------------------------------------------------------- -// Purpose: Starts the button moving "out/down". -//----------------------------------------------------------------------------- -void CBaseButton::ButtonReturn( void ) -{ - ASSERT(m_toggle_state == TS_AT_TOP); - m_toggle_state = TS_GOING_DOWN; - - SetMoveDone( &CBaseButton::ButtonBackHome ); - if (!m_fRotating) - LinearMove( m_vecPosition1, m_flSpeed); - else - AngularMove( m_vecAngle1, m_flSpeed); - - m_nState = 0; // use normal textures -} - - -//----------------------------------------------------------------------------- -// Purpose: Button has returned to the "unpressed/bottom" position. Fire its -// OnOut output and stop moving. -//----------------------------------------------------------------------------- -void CBaseButton::ButtonBackHome( void ) -{ - ASSERT(m_toggle_state == TS_GOING_DOWN); - m_toggle_state = TS_AT_BOTTOM; - - m_OnOut.FireOutput(m_hActivator, this); - - // - // Re-instate touch method, movement cycle is complete. - // - if (HasSpawnFlags(SF_BUTTON_TOUCH_ACTIVATES)) - { - SetTouch( &CBaseButton::ButtonTouch ); - } - else - { - // BUGBUG: ALL buttons no longer respond to touch - SetTouch ( NULL ); - } - - // reset think for a sparking button - if (HasSpawnFlags( SF_BUTTON_SPARK_IF_OFF ) ) - { - SetThink ( &CBaseButton::ButtonSpark ); - SetNextThink( gpGlobals->curtime + 0.5f );// no hurry - } -} - - -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- -int CBaseButton::DrawDebugTextOverlays() -{ - int text_offset = BaseClass::DrawDebugTextOverlays(); - - if (m_debugOverlays & OVERLAY_TEXT_BIT) - { - static const char *pszStates[] = - { - "Pressed", - "Unpressed", - "Pressing...", - "Unpressing...", - "", - }; - - char tempstr[255]; - - int nState = m_toggle_state; - if ( ( nState < 0 ) || ( nState > 3 ) ) - { - nState = 4; - } - - Q_snprintf( tempstr, sizeof(tempstr), "State: %s", pszStates[nState] ); - EntityText( text_offset, tempstr, 0 ); - text_offset++; - - Q_snprintf( tempstr, sizeof(tempstr), "%s", m_bLocked ? "Locked" : "Unlocked" ); - EntityText( text_offset, tempstr, 0 ); - text_offset++; - } - return text_offset; -} - - -// -// Rotating button (aka "lever") -// -LINK_ENTITY_TO_CLASS( func_rot_button, CRotButton ); - - -void CRotButton::Spawn( void ) -{ - //---------------------------------------------------- - //determine sounds for buttons - //a sound of 0 should not make a sound - //---------------------------------------------------- - if ( m_sounds ) - { - m_sNoise = MakeButtonSound( m_sounds ); - PrecacheScriptSound(m_sNoise.ToCStr()); - } - else - { - m_sNoise = NULL_STRING; - } - - // set the axis of rotation - CBaseToggle::AxisDir(); - - // check for clockwise rotation - if ( HasSpawnFlags( SF_DOOR_ROTATE_BACKWARDS) ) - { - m_vecMoveAng = m_vecMoveAng * -1; - } - - SetMoveType( MOVETYPE_PUSH ); - -#ifdef HL1_DLL - SetSolid( SOLID_BSP ); -#else - SetSolid( SOLID_VPHYSICS ); -#endif - if ( HasSpawnFlags( SF_ROTBUTTON_NOTSOLID ) ) - { - AddEFlags( EFL_USE_PARTITION_WHEN_NOT_SOLID ); - AddSolidFlags( FSOLID_NOT_SOLID ); - } - - SetModel( STRING( GetModelName() ) ); - - if (m_flSpeed == 0) - m_flSpeed = 40; - - if (m_flWait == 0) - m_flWait = 1; - - if (m_iHealth > 0) - { - m_takedamage = DAMAGE_YES; - } - - m_toggle_state = TS_AT_BOTTOM; - m_vecAngle1 = GetLocalAngles(); - m_vecAngle2 = GetLocalAngles() + m_vecMoveAng * m_flMoveDistance; - ASSERTSZ(m_vecAngle1 != m_vecAngle2, "rotating button start/end positions are equal\n"); - - m_fStayPushed = (m_flWait == -1 ? TRUE : FALSE); - m_fRotating = TRUE; - - SetUse(&CRotButton::ButtonUse); - - // - // If touching activates the button, set its touch function. - // - if (!HasSpawnFlags(SF_BUTTON_TOUCH_ACTIVATES)) - { - SetTouch ( NULL ); - } - else - { - SetTouch( &CRotButton::ButtonTouch ); - } - - CreateVPhysics(); -} - - -bool CRotButton::CreateVPhysics( void ) -{ - VPhysicsInitShadow( false, false ); - return true; -} - - -//----------------------------------------------------------------------------- -// CMomentaryRotButton spawnflags -//----------------------------------------------------------------------------- -#define SF_MOMENTARY_DOOR 1 -#define SF_MOMENTARY_NOT_USABLE 2 -#define SF_MOMENTARY_AUTO_RETURN 16 - - -BEGIN_DATADESC( CMomentaryRotButton ) - - DEFINE_FIELD( m_lastUsed, FIELD_INTEGER ), - DEFINE_FIELD( m_start, FIELD_VECTOR ), - DEFINE_FIELD( m_end, FIELD_VECTOR ), - DEFINE_FIELD( m_IdealYaw, FIELD_FLOAT ), - DEFINE_FIELD( m_sNoise, FIELD_SOUNDNAME ), - DEFINE_FIELD( m_bUpdateTarget, FIELD_BOOLEAN ), - - DEFINE_KEYFIELD( m_direction, FIELD_INTEGER, "StartDirection" ), - DEFINE_KEYFIELD( m_returnSpeed, FIELD_FLOAT, "returnspeed" ), - DEFINE_KEYFIELD( m_flStartPosition, FIELD_FLOAT, "StartPosition"), - DEFINE_KEYFIELD( m_bSolidBsp, FIELD_BOOLEAN, "solidbsp" ), - - // Function Pointers - DEFINE_FUNCTION( UseMoveDone ), - DEFINE_FUNCTION( ReturnMoveDone ), - DEFINE_FUNCTION( SetPositionMoveDone ), - DEFINE_FUNCTION( UpdateThink ), - - // Inputs - DEFINE_INPUTFUNC( FIELD_FLOAT, "SetPosition", InputSetPosition ), - DEFINE_INPUTFUNC( FIELD_FLOAT, "SetPositionImmediately", InputSetPositionImmediately ), - DEFINE_INPUTFUNC( FIELD_VOID, "_DisableUpdateTarget", InputDisableUpdateTarget ), - DEFINE_INPUTFUNC( FIELD_VOID, "_EnableUpdateTarget", InputEnableUpdateTarget ), - - // Outputs - DEFINE_OUTPUT( m_Position, "Position" ), - DEFINE_OUTPUT( m_OnUnpressed, "OnUnpressed" ), - DEFINE_OUTPUT( m_OnFullyClosed, "OnFullyClosed" ), - DEFINE_OUTPUT( m_OnFullyOpen, "OnFullyOpen" ), - DEFINE_OUTPUT( m_OnReachedPosition, "OnReachedPosition" ), - - DEFINE_INPUTFUNC( FIELD_VOID, "Enable", InputEnable ), - DEFINE_INPUTFUNC( FIELD_VOID, "Disable", InputDisable ), - DEFINE_FIELD( m_bDisabled, FIELD_BOOLEAN ) - -END_DATADESC() - - -LINK_ENTITY_TO_CLASS( momentary_rot_button, CMomentaryRotButton ); - - -//----------------------------------------------------------------------------- -// Purpose: Called when spawning, after keyvalues have been handled. -//----------------------------------------------------------------------------- -void CMomentaryRotButton::Spawn( void ) -{ - CBaseToggle::AxisDir(); - - m_bUpdateTarget = true; - - if ( m_flSpeed == 0 ) - { - m_flSpeed = 100; - } - - // Clamp start position and issue bounds warning - if (m_flStartPosition < 0.0f || m_flStartPosition > 1.0f) - { - Warning("WARNING: Momentary door (%s) start position not between 0 and 1. Clamping.\n",GetDebugName()); - m_flStartPosition = clamp(m_IdealYaw, 0.f, 1.f); - } - - // Check direction fields (for backward compatibility) - if (m_direction != 1 && m_direction != -1) - { - m_direction = 1; - } - - if (m_flMoveDistance < 0) - { - m_vecMoveAng = m_vecMoveAng * -1; - m_flMoveDistance = -m_flMoveDistance; - } - - m_start = GetLocalAngles() - m_vecMoveAng * m_flMoveDistance * m_flStartPosition; - m_end = GetLocalAngles() + m_vecMoveAng * m_flMoveDistance * (1-m_flStartPosition); - - m_IdealYaw = m_flStartPosition; - - // Force start direction at end points - if (m_flStartPosition == 0.0) - { - m_direction = -1; - } - else if (m_flStartPosition == 1.0) - { - m_direction = 1; - } - - if (HasSpawnFlags(SF_BUTTON_LOCKED)) - { - m_bLocked = true; - } - - if ( HasSpawnFlags( SF_BUTTON_USE_ACTIVATES ) ) - { - if ( m_sounds ) - { - m_sNoise = MakeButtonSound( m_sounds ); - PrecacheScriptSound(m_sNoise.ToCStr()); - } - else - { - m_sNoise = NULL_STRING; - } - - m_lastUsed = 0; - UpdateTarget(0,this); - } - -#ifdef HL1_DLL - SetSolid( SOLID_BSP ); -#else - SetSolid( SOLID_VPHYSICS ); -#endif - if (HasSpawnFlags(SF_ROTBUTTON_NOTSOLID)) - { - AddEFlags( EFL_USE_PARTITION_WHEN_NOT_SOLID ); - AddSolidFlags( FSOLID_NOT_SOLID ); - } - - SetMoveType( MOVETYPE_PUSH ); - SetModel( STRING( GetModelName() ) ); - - CreateVPhysics(); - - // Slam the object back to solid - if we really want it to be solid. - if ( m_bSolidBsp ) - { - SetSolid( SOLID_BSP ); - } - - m_bDisabled = false; -} - -int CMomentaryRotButton::ObjectCaps( void ) -{ - int flags = BaseClass::ObjectCaps(); - if (!HasSpawnFlags(SF_BUTTON_USE_ACTIVATES)) - { - return flags; - } - else - { - return (flags | FCAP_CONTINUOUS_USE | FCAP_USE_IN_RADIUS); - } -} - - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -bool CMomentaryRotButton::CreateVPhysics( void ) -{ - VPhysicsInitShadow( false, false ); - - return true; -} - - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void CMomentaryRotButton::PlaySound( void ) -{ - if ( m_sNoise == NULL_STRING ) - return; - - CPASAttenuationFilter filter( this ); - - EmitSound_t ep; - ep.m_nChannel = CHAN_VOICE; - ep.m_pSoundName = (char*)STRING(m_sNoise); - ep.m_flVolume = 1; - ep.m_SoundLevel = SNDLVL_NORM; - - EmitSound( filter, entindex(), ep ); -} - - -//----------------------------------------------------------------------------- -// Purpose: Returns a given angular position as a value along our motion from 0 to 1. -// Input : vecAngles - -//----------------------------------------------------------------------------- -float CMomentaryRotButton::GetPos( const QAngle &vecAngles ) -{ - float flScale = 1; - if (( m_vecMoveAng[0] < 0 ) || ( m_vecMoveAng[1] < 0 ) || ( m_vecMoveAng[2] < 0 )) - { - flScale = -1; - } - - float flPos = flScale * CBaseToggle::AxisDelta( m_spawnflags, vecAngles, m_start ) / m_flMoveDistance; - return( clamp( flPos, 0.f, 1.f )); -} - - -//------------------------------------------------------------------------------ -// Purpose : -// Input : flPosition -//------------------------------------------------------------------------------ -void CMomentaryRotButton::InputSetPosition( inputdata_t &inputdata ) -{ - m_IdealYaw = clamp( inputdata.value.Float(), 0.f, 1.f ); - - float flCurPos = GetPos( GetLocalAngles() ); - if ( flCurPos < m_IdealYaw ) - { - // Moving forward (from start to end). - SetLocalAngularVelocity( m_flSpeed * m_vecMoveAng ); - m_direction = 1; - } - else if ( flCurPos > m_IdealYaw ) - { - // Moving backward (from end to start). - SetLocalAngularVelocity( -m_flSpeed * m_vecMoveAng ); - m_direction = -1; - } - else - { - // We're there already; nothing to do. - SetLocalAngularVelocity( vec3_angle ); - return; - } - - SetMoveDone( &CMomentaryRotButton::SetPositionMoveDone ); - - SetThink( &CMomentaryRotButton::UpdateThink ); - SetNextThink( gpGlobals->curtime ); - - // - // Think again in 0.1 seconds or the time that it will take us to reach our movement goal, - // whichever is the shorter interval. This prevents us from overshooting and stuttering when we - // are told to change position in very small increments. - // - QAngle vecNewAngles = m_start + m_vecMoveAng * ( m_IdealYaw * m_flMoveDistance ); - float flAngleDelta = fabs( AxisDelta( m_spawnflags, vecNewAngles, GetLocalAngles() )); - float dt = flAngleDelta / m_flSpeed; - if ( dt < TICK_INTERVAL ) - { - dt = TICK_INTERVAL; - float speed = flAngleDelta / TICK_INTERVAL; - SetLocalAngularVelocity( speed * m_vecMoveAng * m_direction ); - } - dt = clamp( dt, TICK_INTERVAL, TICK_INTERVAL * 6); - - SetMoveDoneTime( dt ); -} - - -//------------------------------------------------------------------------------ -// Purpose : -// Input : flPosition -//------------------------------------------------------------------------------ -void CMomentaryRotButton::InputSetPositionImmediately( inputdata_t &inputdata ) -{ - m_IdealYaw = clamp( inputdata.value.Float(), 0.f, 1.f ); - SetLocalAngles( m_start + m_vecMoveAng * ( m_IdealYaw * m_flMoveDistance ) ); -} - - -//------------------------------------------------------------------------------ -// Purpose: Turns off target updates so that we can change the wheel's position -// without changing the target's position. Used for jiggling when locked. -//------------------------------------------------------------------------------ -void CMomentaryRotButton::InputDisableUpdateTarget( inputdata_t &inputdata ) -{ - m_bUpdateTarget = false; -} - - -//------------------------------------------------------------------------------ -// Purpose: Turns target updates back on (after jiggling). -//------------------------------------------------------------------------------ -void CMomentaryRotButton::InputEnableUpdateTarget( inputdata_t &inputdata ) -{ - m_bUpdateTarget = true; -} - - -//----------------------------------------------------------------------------- -// Purpose: Locks the button. If locked, the button will play the locked sound -// when the player tries to use it. -//----------------------------------------------------------------------------- -void CMomentaryRotButton::Lock() -{ - BaseClass::Lock(); - - SetLocalAngularVelocity( vec3_angle ); - SetMoveDoneTime( -1 ); - SetMoveDone( NULL ); - - SetNextThink( TICK_NEVER_THINK ); - SetThink( NULL ); -} - - -//----------------------------------------------------------------------------- -// Purpose: Unlocks the button, making it able to be pressed again. -//----------------------------------------------------------------------------- -void CMomentaryRotButton::Unlock() -{ - BaseClass::Unlock(); - - SetMoveDone( &CMomentaryRotButton::ReturnMoveDone ); - - // Delay before autoreturn. - SetMoveDoneTime( 0.1f ); -} - - -//----------------------------------------------------------------------------- -// Purpose: Fires the appropriate outputs at the extremes of motion. -//----------------------------------------------------------------------------- -void CMomentaryRotButton::OutputMovementComplete( void ) -{ - if (m_IdealYaw == 1.0) - { - m_OnFullyClosed.FireOutput(this, this); - } - else if (m_IdealYaw == 0.0) - { - m_OnFullyOpen.FireOutput(this, this); - } - - m_OnReachedPosition.FireOutput( this, this ); -} - - -//------------------------------------------------------------------------------ -// Purpose: MoveDone function for the SetPosition input handler. Tracks our -// progress toward a movement goal and updates our outputs. -//------------------------------------------------------------------------------ -void CMomentaryRotButton::SetPositionMoveDone(void) -{ - float flCurPos = GetPos( GetLocalAngles() ); - - if ((( flCurPos >= m_IdealYaw ) && ( m_direction == 1 )) || - (( flCurPos <= m_IdealYaw ) && ( m_direction == -1 ))) - { - // - // We reached or surpassed our movement goal. - // - SetLocalAngularVelocity( vec3_angle ); - // BUGBUG: Won't this get the player stuck? - SetLocalAngles( m_start + m_vecMoveAng * ( m_IdealYaw * m_flMoveDistance ) ); - SetNextThink( TICK_NEVER_THINK ); - SetMoveDoneTime( -1 ); - UpdateTarget( m_IdealYaw, this ); - OutputMovementComplete(); - return; - } - - // TODO: change this to use a Think function like ReturnThink. - QAngle vecNewAngles = m_start + m_vecMoveAng * ( m_IdealYaw * m_flMoveDistance ); - float flAngleDelta = fabs( AxisDelta( m_spawnflags, vecNewAngles, GetLocalAngles() )); - float dt = flAngleDelta / m_flSpeed; - if ( dt < TICK_INTERVAL ) - { - dt = TICK_INTERVAL; - float speed = flAngleDelta / TICK_INTERVAL; - SetLocalAngularVelocity( speed * m_vecMoveAng * m_direction ); - } - dt = clamp( dt, TICK_INTERVAL, TICK_INTERVAL * 6); - - SetMoveDoneTime( dt ); -} - - -//----------------------------------------------------------------------------- -// Purpose: -// Input : pActivator - -// pCaller - -// useType - -// value - -//----------------------------------------------------------------------------- -void CMomentaryRotButton::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - if ( m_bDisabled == true ) - return; - - if (m_bLocked) - { - if ( OnUseLocked( pActivator ) && HasSpawnFlags( SF_BUTTON_JIGGLE_ON_USE_LOCKED ) ) - { - // Jiggle two degrees. - float flDist = 2.0 / m_flMoveDistance; - - // Must be first! - g_EventQueue.AddEvent( this, "_DisableUpdateTarget", 0, this, this ); - - variant_t value; - value.SetFloat( flDist ); - g_EventQueue.AddEvent( this, "SetPosition", value, 0.01, this, this ); - - value.SetFloat( 0.0 ); - g_EventQueue.AddEvent( this, "SetPosition", value, 0.1, this, this ); - - value.SetFloat( 0.5 * flDist ); - g_EventQueue.AddEvent( this, "SetPosition", value, 0.2, this, this ); - - value.SetFloat( 0.0 ); - g_EventQueue.AddEvent( this, "SetPosition", value, 0.3, this, this ); - - // Must be last! And must be late enough to cover the settling time. - g_EventQueue.AddEvent( this, "_EnableUpdateTarget", 0.5, this, this ); - } - - return; - } - - // - // Reverse our direction and play movement sound every time the player - // pauses between uses. - // - bool bPlaySound = false; - - if ( !m_lastUsed ) - { - bPlaySound = true; - m_direction = -m_direction; - - //Alert that we've been pressed - m_OnPressed.FireOutput( m_hActivator, this ); - } - - m_lastUsed = 1; - - float flPos = GetPos( GetLocalAngles() ); - UpdateSelf( flPos, bPlaySound ); - - // - // Think every frame while we are moving. - // HACK: Don't reset the think time if we already have a pending think. - // This works around an issue with host_thread_mode > 0 when the player's - // clock runs ahead of the server. - // - if ( !m_pfnThink ) - { - SetThink( &CMomentaryRotButton::UpdateThink ); - SetNextThink( gpGlobals->curtime ); - } -} - - -//----------------------------------------------------------------------------- -// Purpose: Handles changing direction at the extremes of our range of motion -// and updating our avelocity while being used by the player. -// Input : value - Number from 0 to 1 indicating our desired position within -// our range of motion, 0 = start, 1 = end. -//----------------------------------------------------------------------------- -void CMomentaryRotButton::UpdateSelf( float value, bool bPlaySound ) -{ - // - // Set our move clock to 0.1 seconds in the future so we stop spinning unless we are - // used again before then. - // - SetMoveDoneTime( 0.1 ); - - // - // If we hit the end, zero our avelocity and snap to the end angles. - // - if ( m_direction > 0 && value >= 1.0 ) - { - SetLocalAngularVelocity( vec3_angle ); - SetLocalAngles( m_end ); - - m_OnFullyClosed.FireOutput(this, this); - return; - } - // - // If we returned to the start, zero our avelocity and snap to the start angles. - // - else if ( m_direction < 0 && value <= 0 ) - { - SetLocalAngularVelocity( vec3_angle ); - SetLocalAngles( m_start ); - - m_OnFullyOpen.FireOutput(this, this); - return; - } - - if ( bPlaySound ) - { - PlaySound(); - } - - SetLocalAngularVelocity( ( m_direction * m_flSpeed ) * m_vecMoveAng ); - SetMoveDone( &CMomentaryRotButton::UseMoveDone ); -} - - -//----------------------------------------------------------------------------- -// Purpose: Updates the value of our position, firing any targets. -// Input : value - New position, from 0 - 1. -//----------------------------------------------------------------------------- -void CMomentaryRotButton::UpdateTarget( float value, CBaseEntity *pActivator ) -{ - if ( !m_bUpdateTarget ) - return; - - if (m_Position.Get() != value) - { - m_Position.Set(value, pActivator, this); - } -} - - -//----------------------------------------------------------------------------- -// Purpose: Handles the end of motion caused by player use. -//----------------------------------------------------------------------------- -void CMomentaryRotButton::UseMoveDone( void ) -{ - SetLocalAngularVelocity( vec3_angle ); - - // Make sure our targets stop where we stopped. - float flPos = GetPos( GetLocalAngles() ); - UpdateTarget( flPos, this ); - - // Alert that we've been unpressed - m_OnUnpressed.FireOutput( m_hActivator, this ); - - m_lastUsed = 0; - - if ( !HasSpawnFlags( SF_BUTTON_TOGGLE ) && m_returnSpeed > 0 ) - { - SetMoveDone( &CMomentaryRotButton::ReturnMoveDone ); - m_direction = -1; - - // Delay before autoreturn. - SetMoveDoneTime( 0.1f ); - } - else - { - SetThink( NULL ); - SetMoveDone( NULL ); - } -} - - -//----------------------------------------------------------------------------- -// Purpose: MoveDone function for rotating back to the start position. -//----------------------------------------------------------------------------- -void CMomentaryRotButton::ReturnMoveDone( void ) -{ - float value = GetPos( GetLocalAngles() ); - if ( value <= 0 ) - { - // - // Got back to the start, stop spinning. - // - SetLocalAngularVelocity( vec3_angle ); - SetLocalAngles( m_start ); - - UpdateTarget( 0, NULL ); - - SetMoveDoneTime( -1 ); - SetMoveDone( NULL ); - - SetNextThink( TICK_NEVER_THINK ); - SetThink( NULL ); - } - else - { - SetLocalAngularVelocity( -m_returnSpeed * m_vecMoveAng ); - SetMoveDoneTime( 0.1f ); - - SetThink( &CMomentaryRotButton::UpdateThink ); - SetNextThink( gpGlobals->curtime + 0.01f ); - } -} - - -//----------------------------------------------------------------------------- -// Purpose: Think function for updating target as we move. -//----------------------------------------------------------------------------- -void CMomentaryRotButton::UpdateThink( void ) -{ - float value = GetPos( GetLocalAngles() ); - UpdateTarget( value, NULL ); - SetNextThink( gpGlobals->curtime ); -} - - -//----------------------------------------------------------------------------- -// Purpose: Draw any debug text overlays -// Output : Current text offset from the top -//----------------------------------------------------------------------------- -int CMomentaryRotButton::DrawDebugTextOverlays(void) -{ - int text_offset = BaseClass::DrawDebugTextOverlays(); - - if (m_debugOverlays & OVERLAY_TEXT_BIT) - { - char tempstr[255]; - - Q_snprintf(tempstr,sizeof(tempstr),"QAngle: %.2f %.2f %.2f", GetLocalAngles()[0], GetLocalAngles()[1], GetLocalAngles()[2]); - EntityText(text_offset,tempstr,0); - text_offset++; - - Q_snprintf(tempstr,sizeof(tempstr),"AVelocity: %.2f %.2f %.2f", GetLocalAngularVelocity()[0], GetLocalAngularVelocity()[1], GetLocalAngularVelocity()[2]); - EntityText(text_offset,tempstr,0); - text_offset++; - - Q_snprintf(tempstr,sizeof(tempstr),"Target Pos: %3.3f",m_IdealYaw); - EntityText(text_offset,tempstr,0); - text_offset++; - - float flCurPos = GetPos(GetLocalAngles()); - Q_snprintf(tempstr,sizeof(tempstr),"Current Pos: %3.3f",flCurPos); - EntityText(text_offset,tempstr,0); - text_offset++; - - Q_snprintf(tempstr,sizeof(tempstr),"Direction: %s",(m_direction == 1) ? "Forward" : "Backward"); - EntityText(text_offset,tempstr,0); - text_offset++; - - } - return text_offset; -} - -//----------------------------------------------------------------------------- -// Purpose: Input hander that starts the spawner -//----------------------------------------------------------------------------- -void CMomentaryRotButton::InputEnable( inputdata_t &inputdata ) -{ - Enable(); -} - - -//----------------------------------------------------------------------------- -// Purpose: Input hander that stops the spawner -//----------------------------------------------------------------------------- -void CMomentaryRotButton::InputDisable( inputdata_t &inputdata ) -{ - Disable(); -} - -//----------------------------------------------------------------------------- -// Purpose: Start the spawner -//----------------------------------------------------------------------------- -void CMomentaryRotButton::Enable( void ) -{ - m_bDisabled = false; -} - - -//----------------------------------------------------------------------------- -// Purpose: Stop the spawner -//----------------------------------------------------------------------------- -void CMomentaryRotButton::Disable( void ) -{ - m_bDisabled = true; +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Implements buttons. +// +//============================================================================= + +#include "cbase.h" +#include "doors.h" +#include "ndebugoverlay.h" +#include "spark.h" +#include "vstdlib/random.h" +#include "engine/IEngineSound.h" +#include "tier1/strtools.h" +#include "buttons.h" +#include "eventqueue.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +void PlayLockSounds( CBaseEntity *pEdict, locksound_t *pls, int flocked, int fbutton ); +string_t MakeButtonSound( int sound ); // get string of button sound number + + +#define SF_BUTTON_DONTMOVE 1 +#define SF_ROTBUTTON_NOTSOLID 1 +#define SF_BUTTON_TOGGLE 32 // button stays pushed until reactivated +#define SF_BUTTON_TOUCH_ACTIVATES 256 // Button fires when touched. +#define SF_BUTTON_DAMAGE_ACTIVATES 512 // Button fires when damaged. +#define SF_BUTTON_USE_ACTIVATES 1024 // Button fires when used. +#define SF_BUTTON_LOCKED 2048 // Whether the button is initially locked. +#define SF_BUTTON_SPARK_IF_OFF 4096 // button sparks in OFF state +#define SF_BUTTON_JIGGLE_ON_USE_LOCKED 8192 // whether to jiggle if someone uses us when we're locked + +BEGIN_DATADESC( CBaseButton ) + + DEFINE_KEYFIELD( m_vecMoveDir, FIELD_VECTOR, "movedir" ), + DEFINE_FIELD( m_fStayPushed, FIELD_BOOLEAN ), + DEFINE_FIELD( m_fRotating, FIELD_BOOLEAN ), + + DEFINE_FIELD( m_bLockedSound, FIELD_CHARACTER ), + DEFINE_FIELD( m_bLockedSentence, FIELD_CHARACTER ), + DEFINE_FIELD( m_bUnlockedSound, FIELD_CHARACTER ), + DEFINE_FIELD( m_bUnlockedSentence, FIELD_CHARACTER ), + DEFINE_FIELD( m_bLocked, FIELD_BOOLEAN ), + DEFINE_FIELD( m_sNoise, FIELD_SOUNDNAME ), + DEFINE_FIELD( m_flUseLockedTime, FIELD_TIME ), + DEFINE_FIELD( m_bSolidBsp, FIELD_BOOLEAN ), + + DEFINE_KEYFIELD( m_sounds, FIELD_INTEGER, "sounds" ), + +// DEFINE_FIELD( m_ls, FIELD_SOUNDNAME ), // This is restored in Precache() +// DEFINE_FIELD( m_nState, FIELD_INTEGER ), + + // Function Pointers + DEFINE_FUNCTION( ButtonTouch ), + DEFINE_FUNCTION( ButtonSpark ), + DEFINE_FUNCTION( TriggerAndWait ), + DEFINE_FUNCTION( ButtonReturn ), + DEFINE_FUNCTION( ButtonBackHome ), + DEFINE_FUNCTION( ButtonUse ), + + // Inputs + DEFINE_INPUTFUNC( FIELD_VOID, "Lock", InputLock ), + DEFINE_INPUTFUNC( FIELD_VOID, "Unlock", InputUnlock ), + DEFINE_INPUTFUNC( FIELD_VOID, "Press", InputPress ), + DEFINE_INPUTFUNC( FIELD_VOID, "PressIn", InputPressIn ), + DEFINE_INPUTFUNC( FIELD_VOID, "PressOut", InputPressOut ), + + // Outputs + DEFINE_OUTPUT( m_OnDamaged, "OnDamaged" ), + DEFINE_OUTPUT( m_OnPressed, "OnPressed" ), + DEFINE_OUTPUT( m_OnUseLocked, "OnUseLocked" ), + DEFINE_OUTPUT( m_OnIn, "OnIn" ), + DEFINE_OUTPUT( m_OnOut, "OnOut" ), + +END_DATADESC() + + +LINK_ENTITY_TO_CLASS( func_button, CBaseButton ); + + + +void CBaseButton::Precache( void ) +{ + // get door button sounds, for doors which require buttons to open + if (m_bLockedSound) + { + m_ls.sLockedSound = MakeButtonSound( (int)m_bLockedSound ); + PrecacheScriptSound(m_ls.sLockedSound.ToCStr()); + } + + if (m_bUnlockedSound) + { + m_ls.sUnlockedSound = MakeButtonSound( (int)m_bUnlockedSound ); + PrecacheScriptSound(m_ls.sUnlockedSound.ToCStr()); + } + + // get sentence group names, for doors which are directly 'touched' to open + + switch (m_bLockedSentence) + { + case 1: m_ls.sLockedSentence = MAKE_STRING("NA"); break; // access denied + case 2: m_ls.sLockedSentence = MAKE_STRING("ND"); break; // security lockout + case 3: m_ls.sLockedSentence = MAKE_STRING("NF"); break; // blast door + case 4: m_ls.sLockedSentence = MAKE_STRING("NFIRE"); break; // fire door + case 5: m_ls.sLockedSentence = MAKE_STRING("NCHEM"); break; // chemical door + case 6: m_ls.sLockedSentence = MAKE_STRING("NRAD"); break; // radiation door + case 7: m_ls.sLockedSentence = MAKE_STRING("NCON"); break; // gen containment + case 8: m_ls.sLockedSentence = MAKE_STRING("NH"); break; // maintenance door + case 9: m_ls.sLockedSentence = MAKE_STRING("NG"); break; // broken door + + default: m_ls.sLockedSentence = NULL_STRING; break; + } + + switch (m_bUnlockedSentence) + { + case 1: m_ls.sUnlockedSentence = MAKE_STRING("EA"); break; // access granted + case 2: m_ls.sUnlockedSentence = MAKE_STRING("ED"); break; // security door + case 3: m_ls.sUnlockedSentence = MAKE_STRING("EF"); break; // blast door + case 4: m_ls.sUnlockedSentence = MAKE_STRING("EFIRE"); break; // fire door + case 5: m_ls.sUnlockedSentence = MAKE_STRING("ECHEM"); break; // chemical door + case 6: m_ls.sUnlockedSentence = MAKE_STRING("ERAD"); break; // radiation door + case 7: m_ls.sUnlockedSentence = MAKE_STRING("ECON"); break; // gen containment + case 8: m_ls.sUnlockedSentence = MAKE_STRING("EH"); break; // maintenance door + + default: m_ls.sUnlockedSentence = NULL_STRING; break; + } + + if ( m_sNoise != NULL_STRING ) + { + PrecacheScriptSound( STRING( m_sNoise ) ); + } +} + + +//----------------------------------------------------------------------------- +// Purpose: Cache user-entity-field values until spawn is called. +// Input : szKeyName - +// szValue - +// Output : Returns true if handled, false if not. +//----------------------------------------------------------------------------- +bool CBaseButton::KeyValue( const char *szKeyName, const char *szValue ) +{ + if (FStrEq(szKeyName, "locked_sound")) + { + m_bLockedSound = atof(szValue); + } + else if (FStrEq(szKeyName, "locked_sentence")) + { + m_bLockedSentence = atof(szValue); + } + else if (FStrEq(szKeyName, "unlocked_sound")) + { + m_bUnlockedSound = atof(szValue); + } + else if (FStrEq(szKeyName, "unlocked_sentence")) + { + m_bUnlockedSentence = atof(szValue); + } + else + { + return BaseClass::KeyValue( szKeyName, szValue ); + } + + return true; +} + + +//----------------------------------------------------------------------------- +// Purpose: Locks the button. If locked, the button will play the locked sound +// when the player tries to use it. +//----------------------------------------------------------------------------- +void CBaseButton::Lock() +{ + m_bLocked = true; +} + + +//----------------------------------------------------------------------------- +// Purpose: Unlocks the button, making it able to be pressed again. +//----------------------------------------------------------------------------- +void CBaseButton::Unlock() +{ + m_bLocked = false; +} + + +//----------------------------------------------------------------------------- +// Purpose: Locks the button. If locked, the button will play the locked sound +// when the player tries to use it. +//----------------------------------------------------------------------------- +void CBaseButton::InputLock( inputdata_t &inputdata ) +{ + Lock(); +} + + +//----------------------------------------------------------------------------- +// Purpose: Unlocks the button, making it able to be pressed again. +//----------------------------------------------------------------------------- +void CBaseButton::InputUnlock( inputdata_t &inputdata ) +{ + Unlock(); +} + + +//----------------------------------------------------------------------------- +// Presses or unpresses the button. +//----------------------------------------------------------------------------- +void CBaseButton::Press( CBaseEntity *pActivator, BUTTON_CODE eCode ) +{ + if ( ( eCode == BUTTON_PRESS ) && ( m_toggle_state == TS_GOING_UP || m_toggle_state == TS_GOING_DOWN ) ) + { + return; + } + + if ( ( eCode == BUTTON_ACTIVATE ) && ( m_toggle_state == TS_GOING_UP || m_toggle_state == TS_AT_TOP ) ) + { + return; + } + + if ( ( eCode == BUTTON_RETURN ) && ( m_toggle_state == TS_GOING_DOWN || m_toggle_state == TS_AT_BOTTOM ) ) + { + return; + } + + // FIXME: consolidate all the button press code into one place! + if (m_bLocked) + { + // play button locked sound + PlayLockSounds(this, &m_ls, TRUE, TRUE); + return; + } + + // Temporarily disable the touch function, until movement is finished. + SetTouch( NULL ); + + if ( ( ( eCode == BUTTON_PRESS ) && ( m_toggle_state == TS_AT_TOP ) ) || + ( ( eCode == BUTTON_RETURN ) && ( m_toggle_state == TS_AT_TOP || m_toggle_state == TS_GOING_UP ) ) ) + { + if ( m_sNoise != NULL_STRING ) + { + CPASAttenuationFilter filter( this ); + + EmitSound_t ep; + ep.m_nChannel = CHAN_VOICE; + ep.m_pSoundName = (char*)STRING(m_sNoise); + ep.m_flVolume = 1; + ep.m_SoundLevel = SNDLVL_NORM; + + EmitSound( filter, entindex(), ep ); + } + + m_OnPressed.FireOutput(pActivator, this); + ButtonReturn(); + } + else if ( ( eCode == BUTTON_PRESS ) || + ( ( eCode == BUTTON_ACTIVATE ) && ( m_toggle_state == TS_AT_BOTTOM || m_toggle_state == TS_GOING_DOWN ) ) ) + { + m_OnPressed.FireOutput(pActivator, this); + ButtonActivate(); + } +} + + +//----------------------------------------------------------------------------- +// Presses the button. +//----------------------------------------------------------------------------- +void CBaseButton::InputPress( inputdata_t &inputdata ) +{ + Press( inputdata.pActivator, BUTTON_PRESS ); +} + + +//----------------------------------------------------------------------------- +// Presses the button, sending it to the top/pressed position. +//----------------------------------------------------------------------------- +void CBaseButton::InputPressIn( inputdata_t &inputdata ) +{ + Press( inputdata.pActivator, BUTTON_ACTIVATE ); +} + + +//----------------------------------------------------------------------------- +// Unpresses the button, sending it to the unpressed/bottom position. +//----------------------------------------------------------------------------- +void CBaseButton::InputPressOut( inputdata_t &inputdata ) +{ + Press( inputdata.pActivator, BUTTON_RETURN ); +} + + +//----------------------------------------------------------------------------- +// Purpose: We have been damaged. Possibly activate, depending on our flags. +// Input : pInflictor - +// pAttacker - +// flDamage - +// bitsDamageType - +// Output : +//----------------------------------------------------------------------------- +int CBaseButton::OnTakeDamage( const CTakeDamageInfo &info ) +{ + m_OnDamaged.FireOutput(m_hActivator, this); + + // dvsents2: remove obselete health keyvalue from func_button + if (!HasSpawnFlags(SF_BUTTON_DAMAGE_ACTIVATES) && (m_iHealth == 0)) + { + return(0); + } + + BUTTON_CODE code = ButtonResponseToTouch(); + + if ( code == BUTTON_NOTHING ) + return 0; + + m_hActivator = info.GetAttacker(); + + // dvsents2: why would activator be NULL here? + if ( m_hActivator == NULL ) + return 0; + + if (m_bLocked) + { + return(0); + } + + // Temporarily disable the touch function, until movement is finished. + SetTouch( NULL ); + + if ( code == BUTTON_RETURN ) + { + if ( m_sNoise != NULL_STRING ) + { + CPASAttenuationFilter filter( this ); + + EmitSound_t ep; + ep.m_nChannel = CHAN_VOICE; + ep.m_pSoundName = (char*)STRING(m_sNoise); + ep.m_flVolume = 1; + ep.m_SoundLevel = SNDLVL_NORM; + + EmitSound( filter, entindex(), ep ); + } + + m_OnPressed.FireOutput(m_hActivator, this); + ButtonReturn(); + } + else + { + // code == BUTTON_ACTIVATE + m_OnPressed.FireOutput(m_hActivator, this); + ButtonActivate( ); + } + + return 0; +} + + +void CBaseButton::Spawn( ) +{ + //---------------------------------------------------- + //determine sounds for buttons + //a sound of 0 should not make a sound + //---------------------------------------------------- + if ( m_sounds ) + { + m_sNoise = MakeButtonSound( m_sounds ); + PrecacheScriptSound(m_sNoise.ToCStr()); + } + else + { + m_sNoise = NULL_STRING; + } + + Precache(); + + if ( HasSpawnFlags( SF_BUTTON_SPARK_IF_OFF ) )// this button should spark in OFF state + { + SetThink ( &CBaseButton::ButtonSpark ); + SetNextThink( gpGlobals->curtime + 0.5f );// no hurry, make sure everything else spawns + } + + // Convert movedir from angles to a vector + QAngle angMoveDir = QAngle( m_vecMoveDir.x, m_vecMoveDir.y, m_vecMoveDir.z ); + AngleVectors( angMoveDir, &m_vecMoveDir ); + + SetMoveType( MOVETYPE_PUSH ); + SetSolid( SOLID_BSP ); + SetModel( STRING( GetModelName() ) ); + + if (m_flSpeed == 0) + { + m_flSpeed = 40; + } + + m_takedamage = DAMAGE_YES; + + if (m_flWait == 0) + { + m_flWait = 1; + } + + if (m_flLip == 0) + { + m_flLip = 4; + } + + m_toggle_state = TS_AT_BOTTOM; + m_vecPosition1 = GetLocalOrigin(); + + // Subtract 2 from size because the engine expands bboxes by 1 in all directions making the size too big + Vector vecButtonOBB = CollisionProp()->OBBSize(); + vecButtonOBB -= Vector( 2, 2, 2 ); + m_vecPosition2 = m_vecPosition1 + (m_vecMoveDir * (DotProductAbs( m_vecMoveDir, vecButtonOBB ) - m_flLip)); + + // Is this a non-moving button? + if ( ((m_vecPosition2 - m_vecPosition1).Length() < 1) || HasSpawnFlags(SF_BUTTON_DONTMOVE) ) + { + m_vecPosition2 = m_vecPosition1; + } + + m_fStayPushed = (m_flWait == -1 ? TRUE : FALSE); + m_fRotating = FALSE; + + if (HasSpawnFlags(SF_BUTTON_LOCKED)) + { + m_bLocked = true; + } + + // + // If using activates the button, set its use function. + // + if (HasSpawnFlags(SF_BUTTON_USE_ACTIVATES)) + { + SetUse(&CBaseButton::ButtonUse); + } + else + { + SetUse(NULL); + } + + // + // If touching activates the button, set its touch function. + // + if (HasSpawnFlags(SF_BUTTON_TOUCH_ACTIVATES)) + { + SetTouch( &CBaseButton::ButtonTouch ); + } + else + { + SetTouch ( NULL ); + } + + CreateVPhysics(); +} + +//----------------------------------------------------------------------------- + +bool CBaseButton::CreateVPhysics() +{ + VPhysicsInitShadow( false, false ); + return true; +} + + +//----------------------------------------------------------------------------- +// Purpose: Button sound table. +// Also used by CBaseDoor to get 'touched' door lock/unlock sounds +// Input : sound - index of sound to look up. +// Output : Returns a pointer to the corresponding sound file. +//----------------------------------------------------------------------------- +string_t MakeButtonSound( int sound ) +{ + char tmp[1024]; + Q_snprintf( tmp, sizeof(tmp), "Buttons.snd%d", sound ); + return AllocPooledString(tmp); +} + + +//----------------------------------------------------------------------------- +// Purpose: Think function that emits sparks at random intervals. +//----------------------------------------------------------------------------- +void CBaseButton::ButtonSpark ( void ) +{ + SetThink ( &CBaseButton::ButtonSpark ); + SetNextThink( gpGlobals->curtime + 0.1 + random->RandomFloat ( 0, 1.5 ) );// spark again at random interval + + DoSpark( this, WorldSpaceCenter(), 1, 1, true, vec3_origin ); +} + + +//----------------------------------------------------------------------------- +// Purpose: Called when someone uses us whilst we are locked. +//----------------------------------------------------------------------------- +bool CBaseButton::OnUseLocked( CBaseEntity *pActivator ) +{ + PlayLockSounds(this, &m_ls, TRUE, TRUE); + + if ( gpGlobals->curtime > m_flUseLockedTime ) + { + m_OnUseLocked.FireOutput( pActivator, this ); + m_flUseLockedTime = gpGlobals->curtime + 0.5; + return true; + } + + return false; +} + + +//----------------------------------------------------------------------------- +// Purpose: Use function that starts the button moving. +// Input : pActivator - +// pCaller - +// useType - +// value - +//----------------------------------------------------------------------------- +void CBaseButton::ButtonUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) +{ + // Ignore touches if button is moving, or pushed-in and waiting to auto-come-out. + // UNDONE: Should this use ButtonResponseToTouch() too? + if (m_toggle_state == TS_GOING_UP || m_toggle_state == TS_GOING_DOWN ) + return; + + if (m_bLocked) + { + OnUseLocked( pActivator ); + return; + } + + m_hActivator = pActivator; + + if ( m_toggle_state == TS_AT_TOP) + { + // + // If it's a toggle button it can return now. Otherwise, it will either + // return on its own or will stay pressed indefinitely. + // + if ( HasSpawnFlags(SF_BUTTON_TOGGLE)) + { + if ( m_sNoise != NULL_STRING ) + { + CPASAttenuationFilter filter( this ); + + EmitSound_t ep; + ep.m_nChannel = CHAN_VOICE; + ep.m_pSoundName = (char*)STRING(m_sNoise); + ep.m_flVolume = 1; + ep.m_SoundLevel = SNDLVL_NORM; + + EmitSound( filter, entindex(), ep ); + } + + m_OnPressed.FireOutput(m_hActivator, this); + ButtonReturn(); + } + } + else + { + m_OnPressed.FireOutput(m_hActivator, this); + ButtonActivate( ); + } +} + + +//----------------------------------------------------------------------------- +// Purpose: Returns a code indicating how the button should respond to being touched. +// Output : Returns one of the following: +// BUTTON_NOTHING - do nothing +// BUTTON_RETURN - +// BUTTON_ACTIVATE - act as if pressed +//----------------------------------------------------------------------------- +CBaseButton::BUTTON_CODE CBaseButton::ButtonResponseToTouch( void ) +{ + // Ignore touches if button is moving, or pushed-in and waiting to auto-come-out. + if (m_toggle_state == TS_GOING_UP || + m_toggle_state == TS_GOING_DOWN || + (m_toggle_state == TS_AT_TOP && !m_fStayPushed && !HasSpawnFlags(SF_BUTTON_TOGGLE) ) ) + return BUTTON_NOTHING; + + if (m_toggle_state == TS_AT_TOP) + { + if ( HasSpawnFlags(SF_BUTTON_TOGGLE) && !m_fStayPushed) + { + return BUTTON_RETURN; + } + } + else + return BUTTON_ACTIVATE; + + return BUTTON_NOTHING; +} + + +//----------------------------------------------------------------------------- +// Purpose: Touch function that activates the button if it responds to touch. +// Input : pOther - The entity that touched us. +//----------------------------------------------------------------------------- +void CBaseButton::ButtonTouch( CBaseEntity *pOther ) +{ + // Ignore touches by anything but players + if ( !pOther->IsPlayer() ) + return; + + m_hActivator = pOther; + + BUTTON_CODE code = ButtonResponseToTouch(); + + if ( code == BUTTON_NOTHING ) + return; + + if (!UTIL_IsMasterTriggered(m_sMaster, pOther) || m_bLocked) + { + // play button locked sound + PlayLockSounds(this, &m_ls, TRUE, TRUE); + return; + } + + // Temporarily disable the touch function, until movement is finished. + SetTouch( NULL ); + + if ( code == BUTTON_RETURN ) + { + if ( m_sNoise != NULL_STRING ) + { + CPASAttenuationFilter filter( this ); + + EmitSound_t ep; + ep.m_nChannel = CHAN_VOICE; + ep.m_pSoundName = (char*)STRING(m_sNoise); + ep.m_flVolume = 1; + ep.m_SoundLevel = SNDLVL_NORM; + + EmitSound( filter, entindex(), ep ); + } + + m_OnPressed.FireOutput(m_hActivator, this); + ButtonReturn(); + } + else + { + // code == BUTTON_ACTIVATE + m_OnPressed.FireOutput(m_hActivator, this); + ButtonActivate( ); + } +} + + +//----------------------------------------------------------------------------- +// Purpose: Starts the button moving "in/up". +// Input : *pOther - +//----------------------------------------------------------------------------- +void CBaseButton::ButtonActivate( void ) +{ + if ( m_sNoise != NULL_STRING ) + { + CPASAttenuationFilter filter( this ); + + EmitSound_t ep; + ep.m_nChannel = CHAN_VOICE; + ep.m_pSoundName = (char*)STRING(m_sNoise); + ep.m_flVolume = 1; + ep.m_SoundLevel = SNDLVL_NORM; + + EmitSound( filter, entindex(), ep ); + } + + if (!UTIL_IsMasterTriggered(m_sMaster, m_hActivator) || m_bLocked) + { + // button is locked, play locked sound + PlayLockSounds(this, &m_ls, TRUE, TRUE); + return; + } + else + { + // button is unlocked, play unlocked sound + PlayLockSounds(this, &m_ls, FALSE, TRUE); + } + + ASSERT(m_toggle_state == TS_AT_BOTTOM); + m_toggle_state = TS_GOING_UP; + + SetMoveDone( &CBaseButton::TriggerAndWait ); + if (!m_fRotating) + LinearMove( m_vecPosition2, m_flSpeed); + else + AngularMove( m_vecAngle2, m_flSpeed); +} + + +//----------------------------------------------------------------------------- +// Purpose: Enables or disables the use capability based on our spawnflags. +//----------------------------------------------------------------------------- +int CBaseButton::ObjectCaps(void) +{ + return((BaseClass::ObjectCaps() & ~FCAP_ACROSS_TRANSITION) | + (HasSpawnFlags(SF_BUTTON_USE_ACTIVATES) ? (FCAP_IMPULSE_USE | FCAP_USE_IN_RADIUS) : 0)); +} + + +//----------------------------------------------------------------------------- +// Purpose: Button has reached the "pressed/top" position. Fire its OnIn output, +// and pause before returning to "unpressed/bottom". +//----------------------------------------------------------------------------- +void CBaseButton::TriggerAndWait( void ) +{ + ASSERT(m_toggle_state == TS_GOING_UP); + + if (!UTIL_IsMasterTriggered(m_sMaster, m_hActivator) || m_bLocked) + { + return; + } + + m_toggle_state = TS_AT_TOP; + + // + // Re-instate touches if the button is of the toggle variety. + // + if (m_fStayPushed || HasSpawnFlags(SF_BUTTON_TOGGLE ) ) + { + if (HasSpawnFlags(SF_BUTTON_TOUCH_ACTIVATES)) + { + SetTouch(&CBaseButton::ButtonTouch); + } + else + { + // BUGBUG: ALL buttons no longer respond to touch + SetTouch (NULL); + } + } + + // + // If button automatically comes back out, start it moving out. + // + else + { + SetNextThink( gpGlobals->curtime + m_flWait ); + SetThink( &CBaseButton::ButtonReturn ); + } + + m_nState = 1; // use alternate textures + + m_OnIn.FireOutput(m_hActivator, this); +} + + +//----------------------------------------------------------------------------- +// Purpose: Starts the button moving "out/down". +//----------------------------------------------------------------------------- +void CBaseButton::ButtonReturn( void ) +{ + ASSERT(m_toggle_state == TS_AT_TOP); + m_toggle_state = TS_GOING_DOWN; + + SetMoveDone( &CBaseButton::ButtonBackHome ); + if (!m_fRotating) + LinearMove( m_vecPosition1, m_flSpeed); + else + AngularMove( m_vecAngle1, m_flSpeed); + + m_nState = 0; // use normal textures +} + + +//----------------------------------------------------------------------------- +// Purpose: Button has returned to the "unpressed/bottom" position. Fire its +// OnOut output and stop moving. +//----------------------------------------------------------------------------- +void CBaseButton::ButtonBackHome( void ) +{ + ASSERT(m_toggle_state == TS_GOING_DOWN); + m_toggle_state = TS_AT_BOTTOM; + + m_OnOut.FireOutput(m_hActivator, this); + + // + // Re-instate touch method, movement cycle is complete. + // + if (HasSpawnFlags(SF_BUTTON_TOUCH_ACTIVATES)) + { + SetTouch( &CBaseButton::ButtonTouch ); + } + else + { + // BUGBUG: ALL buttons no longer respond to touch + SetTouch ( NULL ); + } + + // reset think for a sparking button + if (HasSpawnFlags( SF_BUTTON_SPARK_IF_OFF ) ) + { + SetThink ( &CBaseButton::ButtonSpark ); + SetNextThink( gpGlobals->curtime + 0.5f );// no hurry + } +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +int CBaseButton::DrawDebugTextOverlays() +{ + int text_offset = BaseClass::DrawDebugTextOverlays(); + + if (m_debugOverlays & OVERLAY_TEXT_BIT) + { + static const char *pszStates[] = + { + "Pressed", + "Unpressed", + "Pressing...", + "Unpressing...", + "", + }; + + char tempstr[255]; + + int nState = m_toggle_state; + if ( ( nState < 0 ) || ( nState > 3 ) ) + { + nState = 4; + } + + Q_snprintf( tempstr, sizeof(tempstr), "State: %s", pszStates[nState] ); + EntityText( text_offset, tempstr, 0 ); + text_offset++; + + Q_snprintf( tempstr, sizeof(tempstr), "%s", m_bLocked ? "Locked" : "Unlocked" ); + EntityText( text_offset, tempstr, 0 ); + text_offset++; + } + return text_offset; +} + + +// +// Rotating button (aka "lever") +// +LINK_ENTITY_TO_CLASS( func_rot_button, CRotButton ); + + +void CRotButton::Spawn( void ) +{ + //---------------------------------------------------- + //determine sounds for buttons + //a sound of 0 should not make a sound + //---------------------------------------------------- + if ( m_sounds ) + { + m_sNoise = MakeButtonSound( m_sounds ); + PrecacheScriptSound(m_sNoise.ToCStr()); + } + else + { + m_sNoise = NULL_STRING; + } + + // set the axis of rotation + CBaseToggle::AxisDir(); + + // check for clockwise rotation + if ( HasSpawnFlags( SF_DOOR_ROTATE_BACKWARDS) ) + { + m_vecMoveAng = m_vecMoveAng * -1; + } + + SetMoveType( MOVETYPE_PUSH ); + +#ifdef HL1_DLL + SetSolid( SOLID_BSP ); +#else + SetSolid( SOLID_VPHYSICS ); +#endif + if ( HasSpawnFlags( SF_ROTBUTTON_NOTSOLID ) ) + { + AddEFlags( EFL_USE_PARTITION_WHEN_NOT_SOLID ); + AddSolidFlags( FSOLID_NOT_SOLID ); + } + + SetModel( STRING( GetModelName() ) ); + + if (m_flSpeed == 0) + m_flSpeed = 40; + + if (m_flWait == 0) + m_flWait = 1; + + if (m_iHealth > 0) + { + m_takedamage = DAMAGE_YES; + } + + m_toggle_state = TS_AT_BOTTOM; + m_vecAngle1 = GetLocalAngles(); + m_vecAngle2 = GetLocalAngles() + m_vecMoveAng * m_flMoveDistance; + ASSERTSZ(m_vecAngle1 != m_vecAngle2, "rotating button start/end positions are equal\n"); + + m_fStayPushed = (m_flWait == -1 ? TRUE : FALSE); + m_fRotating = TRUE; + + SetUse(&CRotButton::ButtonUse); + + // + // If touching activates the button, set its touch function. + // + if (!HasSpawnFlags(SF_BUTTON_TOUCH_ACTIVATES)) + { + SetTouch ( NULL ); + } + else + { + SetTouch( &CRotButton::ButtonTouch ); + } + + CreateVPhysics(); +} + + +bool CRotButton::CreateVPhysics( void ) +{ + VPhysicsInitShadow( false, false ); + return true; +} + + +//----------------------------------------------------------------------------- +// CMomentaryRotButton spawnflags +//----------------------------------------------------------------------------- +#define SF_MOMENTARY_DOOR 1 +#define SF_MOMENTARY_NOT_USABLE 2 +#define SF_MOMENTARY_AUTO_RETURN 16 + + +BEGIN_DATADESC( CMomentaryRotButton ) + + DEFINE_FIELD( m_lastUsed, FIELD_INTEGER ), + DEFINE_FIELD( m_start, FIELD_VECTOR ), + DEFINE_FIELD( m_end, FIELD_VECTOR ), + DEFINE_FIELD( m_IdealYaw, FIELD_FLOAT ), + DEFINE_FIELD( m_sNoise, FIELD_SOUNDNAME ), + DEFINE_FIELD( m_bUpdateTarget, FIELD_BOOLEAN ), + + DEFINE_KEYFIELD( m_direction, FIELD_INTEGER, "StartDirection" ), + DEFINE_KEYFIELD( m_returnSpeed, FIELD_FLOAT, "returnspeed" ), + DEFINE_KEYFIELD( m_flStartPosition, FIELD_FLOAT, "StartPosition"), + DEFINE_KEYFIELD( m_bSolidBsp, FIELD_BOOLEAN, "solidbsp" ), + + // Function Pointers + DEFINE_FUNCTION( UseMoveDone ), + DEFINE_FUNCTION( ReturnMoveDone ), + DEFINE_FUNCTION( SetPositionMoveDone ), + DEFINE_FUNCTION( UpdateThink ), + + // Inputs + DEFINE_INPUTFUNC( FIELD_FLOAT, "SetPosition", InputSetPosition ), + DEFINE_INPUTFUNC( FIELD_FLOAT, "SetPositionImmediately", InputSetPositionImmediately ), + DEFINE_INPUTFUNC( FIELD_VOID, "_DisableUpdateTarget", InputDisableUpdateTarget ), + DEFINE_INPUTFUNC( FIELD_VOID, "_EnableUpdateTarget", InputEnableUpdateTarget ), + + // Outputs + DEFINE_OUTPUT( m_Position, "Position" ), + DEFINE_OUTPUT( m_OnUnpressed, "OnUnpressed" ), + DEFINE_OUTPUT( m_OnFullyClosed, "OnFullyClosed" ), + DEFINE_OUTPUT( m_OnFullyOpen, "OnFullyOpen" ), + DEFINE_OUTPUT( m_OnReachedPosition, "OnReachedPosition" ), + + DEFINE_INPUTFUNC( FIELD_VOID, "Enable", InputEnable ), + DEFINE_INPUTFUNC( FIELD_VOID, "Disable", InputDisable ), + DEFINE_FIELD( m_bDisabled, FIELD_BOOLEAN ) + +END_DATADESC() + + +LINK_ENTITY_TO_CLASS( momentary_rot_button, CMomentaryRotButton ); + + +//----------------------------------------------------------------------------- +// Purpose: Called when spawning, after keyvalues have been handled. +//----------------------------------------------------------------------------- +void CMomentaryRotButton::Spawn( void ) +{ + CBaseToggle::AxisDir(); + + m_bUpdateTarget = true; + + if ( m_flSpeed == 0 ) + { + m_flSpeed = 100; + } + + // Clamp start position and issue bounds warning + if (m_flStartPosition < 0.0f || m_flStartPosition > 1.0f) + { + Warning("WARNING: Momentary door (%s) start position not between 0 and 1. Clamping.\n",GetDebugName()); + m_flStartPosition = clamp(m_IdealYaw, 0.f, 1.f); + } + + // Check direction fields (for backward compatibility) + if (m_direction != 1 && m_direction != -1) + { + m_direction = 1; + } + + if (m_flMoveDistance < 0) + { + m_vecMoveAng = m_vecMoveAng * -1; + m_flMoveDistance = -m_flMoveDistance; + } + + m_start = GetLocalAngles() - m_vecMoveAng * m_flMoveDistance * m_flStartPosition; + m_end = GetLocalAngles() + m_vecMoveAng * m_flMoveDistance * (1-m_flStartPosition); + + m_IdealYaw = m_flStartPosition; + + // Force start direction at end points + if (m_flStartPosition == 0.0) + { + m_direction = -1; + } + else if (m_flStartPosition == 1.0) + { + m_direction = 1; + } + + if (HasSpawnFlags(SF_BUTTON_LOCKED)) + { + m_bLocked = true; + } + + if ( HasSpawnFlags( SF_BUTTON_USE_ACTIVATES ) ) + { + if ( m_sounds ) + { + m_sNoise = MakeButtonSound( m_sounds ); + PrecacheScriptSound(m_sNoise.ToCStr()); + } + else + { + m_sNoise = NULL_STRING; + } + + m_lastUsed = 0; + UpdateTarget(0,this); + } + +#ifdef HL1_DLL + SetSolid( SOLID_BSP ); +#else + SetSolid( SOLID_VPHYSICS ); +#endif + if (HasSpawnFlags(SF_ROTBUTTON_NOTSOLID)) + { + AddEFlags( EFL_USE_PARTITION_WHEN_NOT_SOLID ); + AddSolidFlags( FSOLID_NOT_SOLID ); + } + + SetMoveType( MOVETYPE_PUSH ); + SetModel( STRING( GetModelName() ) ); + + CreateVPhysics(); + + // Slam the object back to solid - if we really want it to be solid. + if ( m_bSolidBsp ) + { + SetSolid( SOLID_BSP ); + } + + m_bDisabled = false; +} + +int CMomentaryRotButton::ObjectCaps( void ) +{ + int flags = BaseClass::ObjectCaps(); + if (!HasSpawnFlags(SF_BUTTON_USE_ACTIVATES)) + { + return flags; + } + else + { + return (flags | FCAP_CONTINUOUS_USE | FCAP_USE_IN_RADIUS); + } +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +bool CMomentaryRotButton::CreateVPhysics( void ) +{ + VPhysicsInitShadow( false, false ); + + return true; +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CMomentaryRotButton::PlaySound( void ) +{ + if ( m_sNoise == NULL_STRING ) + return; + + CPASAttenuationFilter filter( this ); + + EmitSound_t ep; + ep.m_nChannel = CHAN_VOICE; + ep.m_pSoundName = (char*)STRING(m_sNoise); + ep.m_flVolume = 1; + ep.m_SoundLevel = SNDLVL_NORM; + + EmitSound( filter, entindex(), ep ); +} + + +//----------------------------------------------------------------------------- +// Purpose: Returns a given angular position as a value along our motion from 0 to 1. +// Input : vecAngles - +//----------------------------------------------------------------------------- +float CMomentaryRotButton::GetPos( const QAngle &vecAngles ) +{ + float flScale = 1; + if (( m_vecMoveAng[0] < 0 ) || ( m_vecMoveAng[1] < 0 ) || ( m_vecMoveAng[2] < 0 )) + { + flScale = -1; + } + + float flPos = flScale * CBaseToggle::AxisDelta( m_spawnflags, vecAngles, m_start ) / m_flMoveDistance; + return( clamp( flPos, 0.f, 1.f )); +} + + +//------------------------------------------------------------------------------ +// Purpose : +// Input : flPosition +//------------------------------------------------------------------------------ +void CMomentaryRotButton::InputSetPosition( inputdata_t &inputdata ) +{ + m_IdealYaw = clamp( inputdata.value.Float(), 0.f, 1.f ); + + float flCurPos = GetPos( GetLocalAngles() ); + if ( flCurPos < m_IdealYaw ) + { + // Moving forward (from start to end). + SetLocalAngularVelocity( m_flSpeed * m_vecMoveAng ); + m_direction = 1; + } + else if ( flCurPos > m_IdealYaw ) + { + // Moving backward (from end to start). + SetLocalAngularVelocity( -m_flSpeed * m_vecMoveAng ); + m_direction = -1; + } + else + { + // We're there already; nothing to do. + SetLocalAngularVelocity( vec3_angle ); + return; + } + + SetMoveDone( &CMomentaryRotButton::SetPositionMoveDone ); + + SetThink( &CMomentaryRotButton::UpdateThink ); + SetNextThink( gpGlobals->curtime ); + + // + // Think again in 0.1 seconds or the time that it will take us to reach our movement goal, + // whichever is the shorter interval. This prevents us from overshooting and stuttering when we + // are told to change position in very small increments. + // + QAngle vecNewAngles = m_start + m_vecMoveAng * ( m_IdealYaw * m_flMoveDistance ); + float flAngleDelta = fabs( AxisDelta( m_spawnflags, vecNewAngles, GetLocalAngles() )); + float dt = flAngleDelta / m_flSpeed; + if ( dt < TICK_INTERVAL ) + { + dt = TICK_INTERVAL; + float speed = flAngleDelta / TICK_INTERVAL; + SetLocalAngularVelocity( speed * m_vecMoveAng * m_direction ); + } + dt = clamp( dt, TICK_INTERVAL, TICK_INTERVAL * 6); + + SetMoveDoneTime( dt ); +} + + +//------------------------------------------------------------------------------ +// Purpose : +// Input : flPosition +//------------------------------------------------------------------------------ +void CMomentaryRotButton::InputSetPositionImmediately( inputdata_t &inputdata ) +{ + m_IdealYaw = clamp( inputdata.value.Float(), 0.f, 1.f ); + SetLocalAngles( m_start + m_vecMoveAng * ( m_IdealYaw * m_flMoveDistance ) ); +} + + +//------------------------------------------------------------------------------ +// Purpose: Turns off target updates so that we can change the wheel's position +// without changing the target's position. Used for jiggling when locked. +//------------------------------------------------------------------------------ +void CMomentaryRotButton::InputDisableUpdateTarget( inputdata_t &inputdata ) +{ + m_bUpdateTarget = false; +} + + +//------------------------------------------------------------------------------ +// Purpose: Turns target updates back on (after jiggling). +//------------------------------------------------------------------------------ +void CMomentaryRotButton::InputEnableUpdateTarget( inputdata_t &inputdata ) +{ + m_bUpdateTarget = true; +} + + +//----------------------------------------------------------------------------- +// Purpose: Locks the button. If locked, the button will play the locked sound +// when the player tries to use it. +//----------------------------------------------------------------------------- +void CMomentaryRotButton::Lock() +{ + BaseClass::Lock(); + + SetLocalAngularVelocity( vec3_angle ); + SetMoveDoneTime( -1 ); + SetMoveDone( NULL ); + + SetNextThink( TICK_NEVER_THINK ); + SetThink( NULL ); +} + + +//----------------------------------------------------------------------------- +// Purpose: Unlocks the button, making it able to be pressed again. +//----------------------------------------------------------------------------- +void CMomentaryRotButton::Unlock() +{ + BaseClass::Unlock(); + + SetMoveDone( &CMomentaryRotButton::ReturnMoveDone ); + + // Delay before autoreturn. + SetMoveDoneTime( 0.1f ); +} + + +//----------------------------------------------------------------------------- +// Purpose: Fires the appropriate outputs at the extremes of motion. +//----------------------------------------------------------------------------- +void CMomentaryRotButton::OutputMovementComplete( void ) +{ + if (m_IdealYaw == 1.0) + { + m_OnFullyClosed.FireOutput(this, this); + } + else if (m_IdealYaw == 0.0) + { + m_OnFullyOpen.FireOutput(this, this); + } + + m_OnReachedPosition.FireOutput( this, this ); +} + + +//------------------------------------------------------------------------------ +// Purpose: MoveDone function for the SetPosition input handler. Tracks our +// progress toward a movement goal and updates our outputs. +//------------------------------------------------------------------------------ +void CMomentaryRotButton::SetPositionMoveDone(void) +{ + float flCurPos = GetPos( GetLocalAngles() ); + + if ((( flCurPos >= m_IdealYaw ) && ( m_direction == 1 )) || + (( flCurPos <= m_IdealYaw ) && ( m_direction == -1 ))) + { + // + // We reached or surpassed our movement goal. + // + SetLocalAngularVelocity( vec3_angle ); + // BUGBUG: Won't this get the player stuck? + SetLocalAngles( m_start + m_vecMoveAng * ( m_IdealYaw * m_flMoveDistance ) ); + SetNextThink( TICK_NEVER_THINK ); + SetMoveDoneTime( -1 ); + UpdateTarget( m_IdealYaw, this ); + OutputMovementComplete(); + return; + } + + // TODO: change this to use a Think function like ReturnThink. + QAngle vecNewAngles = m_start + m_vecMoveAng * ( m_IdealYaw * m_flMoveDistance ); + float flAngleDelta = fabs( AxisDelta( m_spawnflags, vecNewAngles, GetLocalAngles() )); + float dt = flAngleDelta / m_flSpeed; + if ( dt < TICK_INTERVAL ) + { + dt = TICK_INTERVAL; + float speed = flAngleDelta / TICK_INTERVAL; + SetLocalAngularVelocity( speed * m_vecMoveAng * m_direction ); + } + dt = clamp( dt, TICK_INTERVAL, TICK_INTERVAL * 6); + + SetMoveDoneTime( dt ); +} + + +//----------------------------------------------------------------------------- +// Purpose: +// Input : pActivator - +// pCaller - +// useType - +// value - +//----------------------------------------------------------------------------- +void CMomentaryRotButton::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) +{ + if ( m_bDisabled == true ) + return; + + if (m_bLocked) + { + if ( OnUseLocked( pActivator ) && HasSpawnFlags( SF_BUTTON_JIGGLE_ON_USE_LOCKED ) ) + { + // Jiggle two degrees. + float flDist = 2.0 / m_flMoveDistance; + + // Must be first! + g_EventQueue.AddEvent( this, "_DisableUpdateTarget", 0, this, this ); + + variant_t value; + value.SetFloat( flDist ); + g_EventQueue.AddEvent( this, "SetPosition", value, 0.01, this, this ); + + value.SetFloat( 0.0 ); + g_EventQueue.AddEvent( this, "SetPosition", value, 0.1, this, this ); + + value.SetFloat( 0.5 * flDist ); + g_EventQueue.AddEvent( this, "SetPosition", value, 0.2, this, this ); + + value.SetFloat( 0.0 ); + g_EventQueue.AddEvent( this, "SetPosition", value, 0.3, this, this ); + + // Must be last! And must be late enough to cover the settling time. + g_EventQueue.AddEvent( this, "_EnableUpdateTarget", 0.5, this, this ); + } + + return; + } + + // + // Reverse our direction and play movement sound every time the player + // pauses between uses. + // + bool bPlaySound = false; + + if ( !m_lastUsed ) + { + bPlaySound = true; + m_direction = -m_direction; + + //Alert that we've been pressed + m_OnPressed.FireOutput( m_hActivator, this ); + } + + m_lastUsed = 1; + + float flPos = GetPos( GetLocalAngles() ); + UpdateSelf( flPos, bPlaySound ); + + // + // Think every frame while we are moving. + // HACK: Don't reset the think time if we already have a pending think. + // This works around an issue with host_thread_mode > 0 when the player's + // clock runs ahead of the server. + // + if ( !m_pfnThink ) + { + SetThink( &CMomentaryRotButton::UpdateThink ); + SetNextThink( gpGlobals->curtime ); + } +} + + +//----------------------------------------------------------------------------- +// Purpose: Handles changing direction at the extremes of our range of motion +// and updating our avelocity while being used by the player. +// Input : value - Number from 0 to 1 indicating our desired position within +// our range of motion, 0 = start, 1 = end. +//----------------------------------------------------------------------------- +void CMomentaryRotButton::UpdateSelf( float value, bool bPlaySound ) +{ + // + // Set our move clock to 0.1 seconds in the future so we stop spinning unless we are + // used again before then. + // + SetMoveDoneTime( 0.1 ); + + // + // If we hit the end, zero our avelocity and snap to the end angles. + // + if ( m_direction > 0 && value >= 1.0 ) + { + SetLocalAngularVelocity( vec3_angle ); + SetLocalAngles( m_end ); + + m_OnFullyClosed.FireOutput(this, this); + return; + } + // + // If we returned to the start, zero our avelocity and snap to the start angles. + // + else if ( m_direction < 0 && value <= 0 ) + { + SetLocalAngularVelocity( vec3_angle ); + SetLocalAngles( m_start ); + + m_OnFullyOpen.FireOutput(this, this); + return; + } + + if ( bPlaySound ) + { + PlaySound(); + } + + SetLocalAngularVelocity( ( m_direction * m_flSpeed ) * m_vecMoveAng ); + SetMoveDone( &CMomentaryRotButton::UseMoveDone ); +} + + +//----------------------------------------------------------------------------- +// Purpose: Updates the value of our position, firing any targets. +// Input : value - New position, from 0 - 1. +//----------------------------------------------------------------------------- +void CMomentaryRotButton::UpdateTarget( float value, CBaseEntity *pActivator ) +{ + if ( !m_bUpdateTarget ) + return; + + if (m_Position.Get() != value) + { + m_Position.Set(value, pActivator, this); + } +} + + +//----------------------------------------------------------------------------- +// Purpose: Handles the end of motion caused by player use. +//----------------------------------------------------------------------------- +void CMomentaryRotButton::UseMoveDone( void ) +{ + SetLocalAngularVelocity( vec3_angle ); + + // Make sure our targets stop where we stopped. + float flPos = GetPos( GetLocalAngles() ); + UpdateTarget( flPos, this ); + + // Alert that we've been unpressed + m_OnUnpressed.FireOutput( m_hActivator, this ); + + m_lastUsed = 0; + + if ( !HasSpawnFlags( SF_BUTTON_TOGGLE ) && m_returnSpeed > 0 ) + { + SetMoveDone( &CMomentaryRotButton::ReturnMoveDone ); + m_direction = -1; + + // Delay before autoreturn. + SetMoveDoneTime( 0.1f ); + } + else + { + SetThink( NULL ); + SetMoveDone( NULL ); + } +} + + +//----------------------------------------------------------------------------- +// Purpose: MoveDone function for rotating back to the start position. +//----------------------------------------------------------------------------- +void CMomentaryRotButton::ReturnMoveDone( void ) +{ + float value = GetPos( GetLocalAngles() ); + if ( value <= 0 ) + { + // + // Got back to the start, stop spinning. + // + SetLocalAngularVelocity( vec3_angle ); + SetLocalAngles( m_start ); + + UpdateTarget( 0, NULL ); + + SetMoveDoneTime( -1 ); + SetMoveDone( NULL ); + + SetNextThink( TICK_NEVER_THINK ); + SetThink( NULL ); + } + else + { + SetLocalAngularVelocity( -m_returnSpeed * m_vecMoveAng ); + SetMoveDoneTime( 0.1f ); + + SetThink( &CMomentaryRotButton::UpdateThink ); + SetNextThink( gpGlobals->curtime + 0.01f ); + } +} + + +//----------------------------------------------------------------------------- +// Purpose: Think function for updating target as we move. +//----------------------------------------------------------------------------- +void CMomentaryRotButton::UpdateThink( void ) +{ + float value = GetPos( GetLocalAngles() ); + UpdateTarget( value, NULL ); + SetNextThink( gpGlobals->curtime ); +} + + +//----------------------------------------------------------------------------- +// Purpose: Draw any debug text overlays +// Output : Current text offset from the top +//----------------------------------------------------------------------------- +int CMomentaryRotButton::DrawDebugTextOverlays(void) +{ + int text_offset = BaseClass::DrawDebugTextOverlays(); + + if (m_debugOverlays & OVERLAY_TEXT_BIT) + { + char tempstr[255]; + + Q_snprintf(tempstr,sizeof(tempstr),"QAngle: %.2f %.2f %.2f", GetLocalAngles()[0], GetLocalAngles()[1], GetLocalAngles()[2]); + EntityText(text_offset,tempstr,0); + text_offset++; + + Q_snprintf(tempstr,sizeof(tempstr),"AVelocity: %.2f %.2f %.2f", GetLocalAngularVelocity()[0], GetLocalAngularVelocity()[1], GetLocalAngularVelocity()[2]); + EntityText(text_offset,tempstr,0); + text_offset++; + + Q_snprintf(tempstr,sizeof(tempstr),"Target Pos: %3.3f",m_IdealYaw); + EntityText(text_offset,tempstr,0); + text_offset++; + + float flCurPos = GetPos(GetLocalAngles()); + Q_snprintf(tempstr,sizeof(tempstr),"Current Pos: %3.3f",flCurPos); + EntityText(text_offset,tempstr,0); + text_offset++; + + Q_snprintf(tempstr,sizeof(tempstr),"Direction: %s",(m_direction == 1) ? "Forward" : "Backward"); + EntityText(text_offset,tempstr,0); + text_offset++; + + } + return text_offset; +} + +//----------------------------------------------------------------------------- +// Purpose: Input hander that starts the spawner +//----------------------------------------------------------------------------- +void CMomentaryRotButton::InputEnable( inputdata_t &inputdata ) +{ + Enable(); +} + + +//----------------------------------------------------------------------------- +// Purpose: Input hander that stops the spawner +//----------------------------------------------------------------------------- +void CMomentaryRotButton::InputDisable( inputdata_t &inputdata ) +{ + Disable(); +} + +//----------------------------------------------------------------------------- +// Purpose: Start the spawner +//----------------------------------------------------------------------------- +void CMomentaryRotButton::Enable( void ) +{ + m_bDisabled = false; +} + + +//----------------------------------------------------------------------------- +// Purpose: Stop the spawner +//----------------------------------------------------------------------------- +void CMomentaryRotButton::Disable( void ) +{ + m_bDisabled = true; } \ No newline at end of file -- cgit v1.2.3