Counter Strike : Global Offensive Source Code
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.
 
 
 
 
 
 

526 lines
15 KiB

//===== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======//
//
// Purpose: One of the two ends of a portal pair which can be picked up and placed by weapon_camera
//
//===========================================================================//
#include "cbase.h"
#include "portal_mp_gamerules.h"
#include "cvisibilitymonitor.h"
#include "cegclientwrapper.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
#define PROP_BUTTON_MODEL_NAME "models/props/switch001.mdl"
#define PROP_UNDER_BUTTON_MODEL_NAME "models/props_underground/underground_testchamber_button.mdl"
ConVar sv_portal2_button_hint_range( "sv_portal2_button_hint_range", "350.0", FCVAR_NONE );
//-----------------------------------------------------------------------------
// Context think
//-----------------------------------------------------------------------------
static const char *s_pTimerThinkContext = "TimerThinkContext";
class CPropButton : public CBaseAnimating
{
public:
DECLARE_CLASS( CPropButton, CBaseAnimating );
DECLARE_DATADESC();
CPropButton( void );
virtual void Precache( void );
virtual void Spawn( void );
virtual bool CreateVPhysics( void );
virtual void Activate( void );
virtual void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
virtual int ObjectCaps( void ) { return (BaseClass::ObjectCaps() | FCAP_IMPULSE_USE ); }
void AnimateThink( void );
void TimerThink( void );
void Lock();
void Unlock();
int DrawDebugTextOverlays();
virtual const char *GetButtonModelName();
private:
void Press( CBaseEntity *pActivator );
void InputPress( inputdata_t &input );
void InputLock( inputdata_t &inputdata );
void InputUnlock( inputdata_t &inputdata );
void InputCancelPress( inputdata_t &input );
void OnPressed( void );
void OnButtonReset( void );
EHANDLE m_hActivator;
COutputEvent m_OnPressed;
COutputEvent m_OnPressedOrange;
COutputEvent m_OnPressedBlue;
COutputEvent m_OnButtonReset;
bool m_bLocked;
float m_flDelayBeforeReset;
float m_flGoalTime; // goal time when a pressed button should unpress
bool m_bIsTimer;
bool m_bTimerCancelled;
bool m_bPreventFastReset;
protected:
virtual void LookUpAnimationSequences( void );
// animation sequences for the button
int m_UpSequence;
int m_DownSequence;
int m_IdleDownSequence;
int m_IdleUpSequence;
};
LINK_ENTITY_TO_CLASS( prop_button, CPropButton );
BEGIN_DATADESC( CPropButton )
DEFINE_THINKFUNC( AnimateThink ),
DEFINE_THINKFUNC( TimerThink ),
DEFINE_KEYFIELD( m_flDelayBeforeReset, FIELD_FLOAT, "Delay" ),
DEFINE_KEYFIELD( m_bIsTimer, FIELD_BOOLEAN, "IsTimer" ),
DEFINE_KEYFIELD( m_bPreventFastReset, FIELD_BOOLEAN, "PreventFastReset" ),
DEFINE_FIELD( m_hActivator, FIELD_EHANDLE ),
DEFINE_FIELD( m_bLocked, FIELD_BOOLEAN ),
DEFINE_FIELD( m_bTimerCancelled, FIELD_BOOLEAN ),
DEFINE_FIELD( m_flGoalTime, FIELD_TIME ),
DEFINE_FIELD( m_UpSequence, FIELD_INTEGER ),
DEFINE_FIELD( m_DownSequence, FIELD_INTEGER ),
DEFINE_FIELD( m_IdleDownSequence, FIELD_INTEGER ),
DEFINE_FIELD( m_IdleUpSequence, FIELD_INTEGER ),
DEFINE_INPUTFUNC( FIELD_VOID, "Press", InputPress ),
DEFINE_INPUTFUNC( FIELD_VOID, "Lock", InputLock ),
DEFINE_INPUTFUNC( FIELD_VOID, "Unlock", InputUnlock ),
DEFINE_INPUTFUNC( FIELD_VOID, "CancelPress", InputCancelPress ),
DEFINE_OUTPUT( m_OnPressed, "OnPressed" ),
DEFINE_OUTPUT( m_OnPressedOrange, "OnPressedOrange" ),
DEFINE_OUTPUT( m_OnPressedBlue, "OnPressedBlue" ),
DEFINE_OUTPUT( m_OnButtonReset, "OnButtonReset" ),
END_DATADESC()
//-----------------------------------------------------------------------------
// Purpose: constructor
//-----------------------------------------------------------------------------
CPropButton::CPropButton( void )
{
// set the default locked state on spawn
m_bLocked = false;
m_bTimerCancelled = false;
RemoveEffects( EF_SHADOWDEPTH_NOCACHE );
AddEffects( EF_MARKED_FOR_FAST_REFLECTION );
}
const char *CPropButton::GetButtonModelName()
{
return PROP_BUTTON_MODEL_NAME;
}
void CPropButton::LookUpAnimationSequences( void )
{
// look up animation sequences
m_UpSequence = LookupSequence( "up" );
m_DownSequence = LookupSequence( "down" );
m_IdleUpSequence = LookupSequence( "idle" );
m_IdleDownSequence = LookupSequence( "idle_down" );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CPropButton::Precache( void )
{
PrecacheModel( GetButtonModelName() );
// sounds for button
PrecacheScriptSound( "Portal.button_down" );
PrecacheScriptSound( "Portal.button_up" );
PrecacheScriptSound( "Portal.button_locked" );
PrecacheScriptSound( "Portal.room1_TickTock" );
BaseClass::Precache();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CPropButton::Spawn( void )
{
Precache();
BaseClass::Spawn();
SetMoveType( MOVETYPE_NONE );
SetSolid( SOLID_VPHYSICS );
SetModel( GetButtonModelName() );
//Buttons are unpaintable
AddFlag( FL_UNPAINTABLE );
LookUpAnimationSequences();
m_flGoalTime = 0;
CreateVPhysics();
VisibilityMonitor_AddEntity_NotVisibleThroughGlass( this, sv_portal2_button_hint_range.GetFloat() - 50.0f, NULL, NULL );
// Never let crucial game components fade out!
SetFadeDistance( -1.0f, 0.0f );
SetGlobalFadeScale( 0.0f );
// Start "up"
ResetSequence( m_IdleUpSequence );
}
bool CPropButton::CreateVPhysics( void )
{
VPhysicsInitStatic();
return true;
}
void CPropButton::Activate( void )
{
BaseClass::Activate();
SetThink( &CPropButton::AnimateThink );
SetNextThink( gpGlobals->curtime + 0.1f );
}
//-----------------------------------------------------------------------------
// Purpose: Animate and catch edge cases for us stopping / starting our animation
//-----------------------------------------------------------------------------
void CPropButton::AnimateThink( void )
{
// Update our animation
StudioFrameAdvance();
DispatchAnimEvents( this );
// this loop runs every time an animation finishes
// and figures out the next animation to play.
if ( IsSequenceFinished() )
{
int nSequence = GetSequence();
if ( nSequence == m_UpSequence )
{
ResetSequence( m_IdleUpSequence );
// fire the OnButtonReset output
OnButtonReset();
}
else if ( nSequence == m_DownSequence )
{
ResetSequence( m_IdleDownSequence );
// set the time for the button to reset
m_flGoalTime = gpGlobals->curtime + m_flDelayBeforeReset;
// fire the OnPressed output
OnPressed();
//if the button is a timer play the tick-tock sound while button is down
if ( m_bIsTimer )
{
SetContextThink( &CPropButton::TimerThink, gpGlobals->curtime + 1.0f, s_pTimerThinkContext );
if( !m_bPreventFastReset )
{
// since this is a timer button the button resets to the up position immediately after being pressed
ResetSequence( m_UpSequence );
}
}
}
else if ( nSequence == m_IdleDownSequence )
{
// reset the button if it is time
if ( gpGlobals->curtime > m_flGoalTime )
{
ResetSequence( m_UpSequence );
}
}
}
SetThink( &CPropButton::AnimateThink );
SetNextThink( gpGlobals->curtime + 0.1f );
}
void CPropButton::TimerThink( void )
{
// determine if we should play the tick-tock sound
if ( m_flGoalTime > gpGlobals->curtime )
{
EmitSound( "Portal.room1_TickTock" );
// tick again in 1 second
SetContextThink( &CPropButton::TimerThink, gpGlobals->curtime + 1.0f, s_pTimerThinkContext );
}
else
{
// stop ticking
SetContextThink( NULL, TICK_NEVER_THINK, s_pTimerThinkContext );
// skip the button reset events if the timer was cancelled
if ( m_bTimerCancelled )
{
m_bTimerCancelled = false;
}
else
{
// play the button up sound
EmitSound( "Portal.button_up" );
// fire the OnReset output
m_OnButtonReset.FireOutput( this, this );
}
}
}
//-----------------------------------------------------------------------------
// Purpose: Press the button
//-----------------------------------------------------------------------------
void CPropButton::Press( CBaseEntity *pActivator )
{
if ( m_bLocked )
{
// button is locked so play a locked sound
EmitSound( "Portal.button_locked" );
}
else
{
// animate the button being pressed
int nCurrentSequence = GetSequence();
if (nCurrentSequence == m_IdleUpSequence )
{
ResetSequence( m_DownSequence );
// play the button press sound
EmitSound( "Portal.button_down" );
}
m_hActivator = pActivator;
}
}
//-----------------------------------------------------------------------------
// Purpose: Press the button (via input)
//-----------------------------------------------------------------------------
void CPropButton::InputPress( inputdata_t &input )
{
Press( input.pActivator );
}
//-----------------------------------------------------------------------------
// Purpose: Expire the timer
//-----------------------------------------------------------------------------
void CPropButton::InputCancelPress( inputdata_t &input )
{
m_bTimerCancelled = true;
// set the goal time to the current time so the timer logic will expire
m_flGoalTime = gpGlobals->curtime;
}
//-----------------------------------------------------------------------------
// Purpose: Fire output for button being pressed
//-----------------------------------------------------------------------------
void CPropButton::OnPressed( void )
{
// fire the OnPressed output
if ( m_hActivator.Get() != NULL )
{
CBaseEntity *pOther = dynamic_cast<CBaseEntity*>(m_hActivator.Get());
if ( GameRules() && GameRules()->IsMultiplayer() && pOther && pOther->IsPlayer() )
{
if ( pOther->GetTeamNumber() == TEAM_RED )
{
m_OnPressedOrange.FireOutput( pOther, this );
}
else if ( pOther->GetTeamNumber() == TEAM_BLUE )
{
m_OnPressedBlue.FireOutput( pOther, this );
}
}
m_OnPressed.FireOutput( m_hActivator.Get(), this );
}
else
m_OnPressed.FireOutput( this, this );
}
//-----------------------------------------------------------------------------
// Purpose: Fire output when button has reset after being pressed
//-----------------------------------------------------------------------------
void CPropButton::OnButtonReset( void )
{
// skip the button reset events if the timer was cancelled
if ( m_bTimerCancelled )
{
m_bTimerCancelled = false;
}
else if( !m_bIsTimer ) // if the button is a timer then don't do this. the timer will handle this step when it expires.
{
// play the button up sound
EmitSound( "Portal.button_up" );
// fire the OnReset output
m_OnButtonReset.FireOutput( this, this );
}
else
{
STEAMWORKS_SELFCHECK();
}
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : *pActivator -
// *pCaller -
// useType -
// value -
//-----------------------------------------------------------------------------
void CPropButton::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
{
CBasePlayer *pPlayer = ToBasePlayer( pActivator );
if ( pPlayer )
{
// press the button
Press( pActivator );
}
}
//-----------------------------------------------------------------------------
// Purpose: Locks the button. If locked, the button will play the locked sound
// when the player tries to use it.
//-----------------------------------------------------------------------------
void CPropButton::Lock()
{
m_bLocked = true;
}
//-----------------------------------------------------------------------------
// Purpose: Unlocks the button, making it able to be pressed again.
//-----------------------------------------------------------------------------
void CPropButton::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 CPropButton::InputLock( inputdata_t &inputdata )
{
Lock();
}
//-----------------------------------------------------------------------------
// Purpose: Unlocks the button, making it able to be pressed again.
//-----------------------------------------------------------------------------
void CPropButton::InputUnlock( inputdata_t &inputdata )
{
Unlock();
}
//-----------------------------------------------------------------------------
// Draw debug overlays
//-----------------------------------------------------------------------------
int CPropButton::DrawDebugTextOverlays()
{
int text_offset = BaseClass::DrawDebugTextOverlays();
char tempstr[255];
Q_snprintf( tempstr, sizeof(tempstr), "%s", m_bLocked ? "Locked" : "Unlocked" );
EntityText( text_offset, tempstr, 0 );
text_offset++;
Q_snprintf( tempstr, sizeof(tempstr), "%s", m_bIsTimer ? "Is a timer" : "Is not a timer" );
EntityText( text_offset, tempstr, 0 );
text_offset++;
Q_snprintf( tempstr, sizeof(tempstr), "Delay: %f", m_flDelayBeforeReset );
EntityText( text_offset, tempstr, 0 );
text_offset++;
if ( ( m_flGoalTime - gpGlobals->curtime) > 0 )
{
Q_snprintf( tempstr, sizeof(tempstr), "Timer expires in: %.2f", ( m_flGoalTime - gpGlobals->curtime) );
EntityText( text_offset, tempstr, 0 );
text_offset++;
}
return text_offset;
}
//-----------------------------------------------------------------------------
// Underground button
//-----------------------------------------------------------------------------
class CPropUnderButton : public CPropButton
{
DECLARE_CLASS( CPropUnderButton, CPropButton );
DECLARE_DATADESC()
public:
virtual const char *GetButtonModelName();
protected:
virtual void LookUpAnimationSequences( void );
};
LINK_ENTITY_TO_CLASS( prop_under_button, CPropUnderButton );
BEGIN_DATADESC( CPropUnderButton )
END_DATADESC()
const char *CPropUnderButton::GetButtonModelName()
{
return PROP_UNDER_BUTTON_MODEL_NAME;
}
void CPropUnderButton::LookUpAnimationSequences( void )
{
// look up animation sequences
m_UpSequence = LookupSequence( "release" );
m_DownSequence = LookupSequence( "press" );
m_IdleUpSequence = LookupSequence( "release_idle" );
m_IdleDownSequence = LookupSequence( "press_idle" );
}