initial
This commit is contained in:
526
game/server/portal2/prop_button.cpp
Normal file
526
game/server/portal2/prop_button.cpp
Normal file
@@ -0,0 +1,526 @@
|
||||
//===== 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" );
|
||||
}
|
||||
797
game/server/portal2/prop_floor_button.cpp
Normal file
797
game/server/portal2/prop_floor_button.cpp
Normal file
@@ -0,0 +1,797 @@
|
||||
//===== Copyright (c) 1996-2005, Valve Corporation, All rights reserved. ======//
|
||||
//
|
||||
// Purpose: button that can be pressed by a weighted cube or player standing on it
|
||||
//
|
||||
//===========================================================================//
|
||||
|
||||
#include "cbase.h"
|
||||
#include "props.h"
|
||||
#include "triggers.h"
|
||||
#include "prop_weightedcube.h"
|
||||
#include "portal_mp_gamerules.h"
|
||||
#include "prop_monster_box.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
#define PROP_FLOOR_BUTTON_DEFAULT_MODEL_NAME "models/props/portal_button.mdl"
|
||||
#define PROP_FLOOR_CUBE_BUTTON_MODEL_NAME "models/props/box_socket.mdl"
|
||||
#define PROP_FLOOR_BALL_BUTTON_MODEL_NAME "models/props/ball_button.mdl"
|
||||
#define PROP_UNDER_FLOOR_BUTTON_MODEL_NAME "models/props_underground/underground_floor_button.mdl"
|
||||
|
||||
static const char * s_pszPressingBoxHasSetteledThinkContext = "PressingBoxHasSetteledThinkContext";
|
||||
|
||||
class CPropFloorButton;
|
||||
|
||||
enum button_skins
|
||||
{
|
||||
button_off_skin,
|
||||
button_on_skin
|
||||
};
|
||||
|
||||
//
|
||||
// Trigger for floor button
|
||||
//
|
||||
|
||||
class CPortalButtonTrigger : public CBaseTrigger
|
||||
{
|
||||
public:
|
||||
DECLARE_CLASS( CPortalButtonTrigger, CBaseTrigger );
|
||||
DECLARE_DATADESC();
|
||||
|
||||
static CPortalButtonTrigger *Create( const Vector &vecOrigin, const QAngle &vecAngles, const Vector &vecMins, const Vector &vecMaxs, CPropFloorButton *pOwner );
|
||||
|
||||
virtual bool PassesTriggerFilters(CBaseEntity *pOther);
|
||||
|
||||
virtual void OnStartTouchAll( CBaseEntity *pOther );
|
||||
|
||||
virtual void EndTouch(CBaseEntity *pOther);
|
||||
virtual void OnEndTouchAll( CBaseEntity *pOther );
|
||||
virtual void StartTouch(CBaseEntity *pOther);
|
||||
virtual void Spawn( void );
|
||||
|
||||
|
||||
private:
|
||||
CPropFloorButton *m_pOwnerButton;
|
||||
};
|
||||
|
||||
LINK_ENTITY_TO_CLASS( trigger_portal_button, CPortalButtonTrigger );
|
||||
|
||||
BEGIN_DATADESC( CPortalButtonTrigger )
|
||||
|
||||
DEFINE_FIELD( m_pOwnerButton, FIELD_CLASSPTR ),
|
||||
|
||||
END_DATADESC()
|
||||
|
||||
//
|
||||
// Floor Button
|
||||
//
|
||||
|
||||
class CPropFloorButton : public CDynamicProp
|
||||
{
|
||||
public:
|
||||
DECLARE_CLASS( CPropFloorButton, CDynamicProp );
|
||||
DECLARE_DATADESC();
|
||||
DECLARE_SERVERCLASS();
|
||||
|
||||
CPropFloorButton();
|
||||
|
||||
virtual void Precache( void );
|
||||
virtual void Spawn( void );
|
||||
virtual bool CreateVPhysics( void );
|
||||
virtual void Activate( void );
|
||||
|
||||
virtual void AnimateThink( void );
|
||||
virtual void UpdateOnRemove( void );
|
||||
void PressingBoxHasSetteledThink( void );
|
||||
|
||||
virtual const char *GetButtonModelName();
|
||||
virtual bool ShouldPlayerTouch();
|
||||
virtual bool OnlyAcceptBall( void ) { return false; }
|
||||
virtual bool AcceptsBall( void ) { return true; }
|
||||
void SetSkin( int skinNum );
|
||||
|
||||
private:
|
||||
void OnPressed( CBaseEntity* pActivator );
|
||||
void OnUnPressed( CBaseEntity* pActivator );
|
||||
|
||||
COutputEvent m_OnPressed;
|
||||
COutputEvent m_OnPressedOrange;
|
||||
COutputEvent m_OnPressedBlue;
|
||||
COutputEvent m_OnUnPressed;
|
||||
|
||||
protected:
|
||||
CHandle<CPortalButtonTrigger> m_hButtonTrigger;
|
||||
|
||||
CNetworkVar( bool, m_bButtonState );
|
||||
|
||||
virtual void CreateTriggers( void );
|
||||
void TriggerStartTouch( CBaseEntity *pOther );
|
||||
void TriggerEndTouch( CBaseEntity *pOther );
|
||||
|
||||
virtual void Press( CBaseEntity *pActivator );
|
||||
virtual void UnPress( CBaseEntity *pActivator );
|
||||
|
||||
void InputPressIn( inputdata_t &inputdata );
|
||||
void InputPressOut( inputdata_t &inputdata );
|
||||
|
||||
virtual void LookUpAnimationSequences( void );
|
||||
|
||||
// animation sequences for the button
|
||||
int m_UpSequence;
|
||||
int m_DownSequence;
|
||||
|
||||
friend class CPortalButtonTrigger;
|
||||
};
|
||||
|
||||
LINK_ENTITY_TO_CLASS( prop_floor_button, CPropFloorButton );
|
||||
|
||||
BEGIN_DATADESC( CPropFloorButton )
|
||||
|
||||
DEFINE_THINKFUNC( AnimateThink ),
|
||||
DEFINE_THINKFUNC( PressingBoxHasSetteledThink ),
|
||||
|
||||
DEFINE_FIELD( m_UpSequence, FIELD_INTEGER ),
|
||||
DEFINE_FIELD( m_DownSequence, FIELD_INTEGER ),
|
||||
|
||||
DEFINE_FIELD( m_hButtonTrigger, FIELD_EHANDLE ),
|
||||
|
||||
DEFINE_INPUTFUNC( FIELD_VOID, "PressIn", InputPressIn ),
|
||||
DEFINE_INPUTFUNC( FIELD_VOID, "PressOut", InputPressOut ),
|
||||
|
||||
DEFINE_OUTPUT( m_OnPressed, "OnPressed" ),
|
||||
DEFINE_OUTPUT( m_OnPressedOrange, "OnPressedOrange" ),
|
||||
DEFINE_OUTPUT( m_OnPressedBlue, "OnPressedBlue" ),
|
||||
DEFINE_OUTPUT( m_OnUnPressed, "OnUnPressed" ),
|
||||
|
||||
END_DATADESC()
|
||||
|
||||
IMPLEMENT_SERVERCLASS_ST(CPropFloorButton, DT_PropFloorButton)
|
||||
|
||||
SendPropBool( SENDINFO( m_bButtonState ) ),
|
||||
|
||||
END_SEND_TABLE()
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: constructor
|
||||
//-----------------------------------------------------------------------------
|
||||
CPropFloorButton::CPropFloorButton():
|
||||
m_bButtonState( false ) // button is not pressed by default
|
||||
{
|
||||
RemoveEffects( EF_SHADOWDEPTH_NOCACHE );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CPropFloorButton::Precache( void )
|
||||
{
|
||||
PrecacheModel( GetButtonModelName() );
|
||||
|
||||
BaseClass::Precache();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CPropFloorButton::Spawn( void )
|
||||
{
|
||||
KeyValue( "model", GetButtonModelName() );
|
||||
|
||||
Precache();
|
||||
BaseClass::Spawn();
|
||||
|
||||
SetSolid( SOLID_VPHYSICS );
|
||||
|
||||
LookUpAnimationSequences();
|
||||
|
||||
// Start in the up state
|
||||
ResetSequence( m_UpSequence );
|
||||
|
||||
// Ensure the 'off' skin is set
|
||||
SetSkin( button_off_skin );
|
||||
|
||||
//Buttons are unpaintable
|
||||
AddFlag( FL_UNPAINTABLE );
|
||||
|
||||
CreateVPhysics();
|
||||
|
||||
CreateTriggers();
|
||||
|
||||
AddEffects( EF_MARKED_FOR_FAST_REFLECTION );
|
||||
|
||||
// Never let crucial game components fade out!
|
||||
SetFadeDistance( -1.0f, 0.0f );
|
||||
SetGlobalFadeScale( 0.0f );
|
||||
}
|
||||
|
||||
|
||||
void CPropFloorButton::LookUpAnimationSequences( void )
|
||||
{
|
||||
// look up animation sequences
|
||||
m_UpSequence = LookupSequence( "up" );
|
||||
m_DownSequence = LookupSequence( "down" );
|
||||
}
|
||||
|
||||
|
||||
bool CPropFloorButton::CreateVPhysics( void )
|
||||
{
|
||||
BaseClass::CreateVPhysics();
|
||||
return true;
|
||||
}
|
||||
|
||||
void CPropFloorButton::Activate( void )
|
||||
{
|
||||
BaseClass::Activate();
|
||||
|
||||
SetThink( &CPropFloorButton::AnimateThink );
|
||||
SetNextThink( gpGlobals->curtime + 0.1f );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Animate and catch edge cases for us stopping / starting our animation
|
||||
//-----------------------------------------------------------------------------
|
||||
void CPropFloorButton::AnimateThink( void )
|
||||
{
|
||||
// Update our animation
|
||||
StudioFrameAdvance();
|
||||
DispatchAnimEvents( this );
|
||||
m_BoneFollowerManager.UpdateBoneFollowers(this);
|
||||
|
||||
SetNextThink( gpGlobals->curtime + 0.1f );
|
||||
RANDOM_CEG_TEST_SECRET();
|
||||
|
||||
// debug overlay of trigger displays if ent_bbox is used on entity
|
||||
if ( m_debugOverlays & OVERLAY_BBOX_BIT )
|
||||
{
|
||||
if ( m_hButtonTrigger )
|
||||
{
|
||||
m_hButtonTrigger->m_debugOverlays |= OVERLAY_BBOX_BIT;
|
||||
NDebugOverlay::Cross3D( GetAbsOrigin(), 4, 0, 255, 0, true, 0.1f );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( m_hButtonTrigger )
|
||||
{
|
||||
m_hButtonTrigger->m_debugOverlays &= ~OVERLAY_BBOX_BIT;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CPropFloorButton::PressingBoxHasSetteledThink( void )
|
||||
{
|
||||
if ( gpGlobals->maxClients == 1 && (V_strcmp( gpGlobals->mapname.ToCStr(), "sp_a2_bts1" ) != 0)
|
||||
&& (V_strcmp( gpGlobals->mapname.ToCStr(), "mp_coop_catapult_1" ) != 0) )
|
||||
{
|
||||
UTIL_RecordAchievementEvent( "ACH.BOX_HOLE_IN_ONE" );
|
||||
}
|
||||
|
||||
SetContextThink( NULL, gpGlobals->curtime, s_pszPressingBoxHasSetteledThinkContext );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CPropFloorButton::UpdateOnRemove( void )
|
||||
{
|
||||
if ( m_hButtonTrigger )
|
||||
{
|
||||
UTIL_Remove( m_hButtonTrigger );
|
||||
m_hButtonTrigger = NULL;
|
||||
}
|
||||
BaseClass::UpdateOnRemove();
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: return floor button model name
|
||||
//-----------------------------------------------------------------------------
|
||||
const char *CPropFloorButton::GetButtonModelName()
|
||||
{
|
||||
if ( m_ModelName == NULL_STRING )
|
||||
return PROP_FLOOR_BUTTON_DEFAULT_MODEL_NAME;
|
||||
|
||||
return STRING( m_ModelName );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Press the button
|
||||
//-----------------------------------------------------------------------------
|
||||
CEG_NOINLINE void CPropFloorButton::Press( CBaseEntity *pActivator )
|
||||
{
|
||||
// play the down sequence
|
||||
ResetSequence( m_DownSequence );
|
||||
|
||||
// set the button state for the client
|
||||
m_bButtonState = true;
|
||||
|
||||
// Change the skin
|
||||
SetSkin( button_on_skin );
|
||||
CEG_PROTECT_MEMBER_FUNCTION( CPropFloorButton_Press );
|
||||
|
||||
// call the function that fires the OnPressed output
|
||||
OnPressed( pActivator );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: UnPress the button
|
||||
//-----------------------------------------------------------------------------
|
||||
void CPropFloorButton::UnPress( CBaseEntity *pActivator )
|
||||
{
|
||||
// play the up sequence
|
||||
ResetSequence( m_UpSequence );
|
||||
|
||||
// set the button state for the client
|
||||
m_bButtonState = false;
|
||||
|
||||
// Change the skin
|
||||
SetSkin( button_off_skin );
|
||||
|
||||
// call the function that fires the OnUnPressed output
|
||||
OnUnPressed( pActivator );
|
||||
}
|
||||
|
||||
void CPropFloorButton::InputPressIn( inputdata_t &inputdata )
|
||||
{
|
||||
Press( inputdata.pActivator );
|
||||
}
|
||||
|
||||
void CPropFloorButton::InputPressOut( inputdata_t &inputdata )
|
||||
{
|
||||
UnPress( inputdata.pActivator );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Fire output for button being pressed
|
||||
//-----------------------------------------------------------------------------
|
||||
void CPropFloorButton::OnPressed( CBaseEntity* pActivator )
|
||||
{
|
||||
if ( pActivator != NULL )
|
||||
{
|
||||
CBaseEntity *pOther = dynamic_cast<CBaseEntity*>(pActivator);
|
||||
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 );
|
||||
}
|
||||
}
|
||||
|
||||
if( FClassnameIs( pActivator, "prop_monster_box" ) )
|
||||
{
|
||||
CPropMonsterBox* pMonsterBox = static_cast<CPropMonsterBox*>( pActivator );
|
||||
pMonsterBox->BecomeBox( false );
|
||||
}
|
||||
}
|
||||
|
||||
// If this button was pressed without touching the player, fire the special output used for the 'hole in one' achievement.
|
||||
if ( UTIL_IsWeightedCube( pActivator ) )
|
||||
{
|
||||
CPropWeightedCube *pCube = (CPropWeightedCube*)pActivator;
|
||||
Assert( pCube );
|
||||
if ( pCube )
|
||||
{
|
||||
if ( pCube->WasTouchedByPlayer() == false )
|
||||
{
|
||||
// HACK: this delay is a guess at how long it takes to be sure the box has setteled...
|
||||
SetContextThink( &CPropFloorButton::PressingBoxHasSetteledThink, gpGlobals->curtime + 2.0f, s_pszPressingBoxHasSetteledThinkContext );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_OnPressed.FireOutput( pActivator, this );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Fire output when button has reset after being pressed
|
||||
//-----------------------------------------------------------------------------
|
||||
void CPropFloorButton::OnUnPressed( CBaseEntity* pActivator )
|
||||
{
|
||||
if( pActivator && FClassnameIs( pActivator, "prop_monster_box" ) )
|
||||
{
|
||||
CPropMonsterBox* pMonsterBox = static_cast<CPropMonsterBox*>( pActivator );
|
||||
pMonsterBox->BecomeMonster( false );
|
||||
}
|
||||
|
||||
|
||||
SetContextThink( NULL, gpGlobals->curtime, s_pszPressingBoxHasSetteledThinkContext );
|
||||
|
||||
// fire the OnUnPressed output
|
||||
m_OnUnPressed.FireOutput( pActivator, this );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Create triggers for button
|
||||
//-----------------------------------------------------------------------------
|
||||
void CPropFloorButton::CreateTriggers( void )
|
||||
{
|
||||
Vector vecOrigin = GetAbsOrigin();
|
||||
|
||||
// trigger size
|
||||
Vector vecMins( -20,-20,0 );
|
||||
Vector vecMaxs( 20,20,14 );
|
||||
|
||||
|
||||
// Create the button trigger
|
||||
m_hButtonTrigger = CPortalButtonTrigger::Create( vecOrigin, GetAbsAngles(), vecMins, vecMaxs, this );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CPropFloorButton::TriggerStartTouch( CBaseEntity *pOther )
|
||||
{
|
||||
Press( pOther );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CPropFloorButton::TriggerEndTouch( CBaseEntity *pOther )
|
||||
{
|
||||
UnPress( pOther );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CPropFloorButton::ShouldPlayerTouch()
|
||||
{
|
||||
// Yes, players can touch the prop floor button
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Set the model skin
|
||||
//-----------------------------------------------------------------------------
|
||||
void CPropFloorButton::SetSkin( int skinNum )
|
||||
{
|
||||
m_nSkin = skinNum;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: creates the button trigger
|
||||
//-----------------------------------------------------------------------------
|
||||
CPortalButtonTrigger *CPortalButtonTrigger::Create( const Vector &vecOrigin, const QAngle &vecAngles, const Vector &vecMins, const Vector &vecMaxs, CPropFloorButton *pOwner )
|
||||
{
|
||||
CPortalButtonTrigger *pTrigger = (CPortalButtonTrigger *) CreateEntityByName( "trigger_portal_button" );
|
||||
if ( pTrigger == NULL )
|
||||
return NULL;
|
||||
|
||||
UTIL_SetOrigin( pTrigger, vecOrigin );
|
||||
pTrigger->SetAbsAngles( vecAngles );
|
||||
UTIL_SetSize( pTrigger, vecMins, vecMaxs );
|
||||
|
||||
DispatchSpawn( pTrigger );
|
||||
|
||||
pTrigger->SetParent( (CBaseEntity *) pOwner );
|
||||
|
||||
pTrigger->m_pOwnerButton = pOwner;
|
||||
|
||||
return pTrigger;
|
||||
}
|
||||
|
||||
void CPortalButtonTrigger::StartTouch(CBaseEntity *pOther)
|
||||
{
|
||||
if( !pOther->IsMarkedForDeletion() && FClassnameIs( pOther, "prop_weighted_cube") )
|
||||
{
|
||||
if ( PassesTriggerFilters( pOther ) )
|
||||
{
|
||||
//Set the cube to activate
|
||||
CPropWeightedCube* pCube = assert_cast<CPropWeightedCube*>( pOther );
|
||||
if( pCube )
|
||||
{
|
||||
pCube->SetActivated( true );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BaseClass::StartTouch( pOther );
|
||||
}
|
||||
|
||||
void CPortalButtonTrigger::EndTouch(CBaseEntity *pOther)
|
||||
{
|
||||
if( !pOther->IsMarkedForDeletion() && FClassnameIs( pOther, "prop_weighted_cube") )
|
||||
{
|
||||
if ( PassesTriggerFilters( pOther ) )
|
||||
{
|
||||
//Set the cube to deactivate
|
||||
CPropWeightedCube* pCube = assert_cast<CPropWeightedCube*>( pOther );
|
||||
if( pCube )
|
||||
{
|
||||
pCube->SetActivated( false );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BaseClass::EndTouch( pOther );
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
// Purpose: checks filters on trigger in addition to specific filters (player, cube)
|
||||
//----------------------------------------------------------------------------------
|
||||
bool CPortalButtonTrigger::PassesTriggerFilters(CBaseEntity *pOther)
|
||||
{
|
||||
bool bPassedFilter = BaseClass::PassesTriggerFilters( pOther );
|
||||
|
||||
// did I fail the baseclass filter check?
|
||||
if ( !bPassedFilter )
|
||||
return false;
|
||||
|
||||
|
||||
// are players allowed to touch me?
|
||||
if ( m_pOwnerButton->ShouldPlayerTouch() )
|
||||
{
|
||||
// did a player touch me?
|
||||
if ( pOther->IsPlayer() )
|
||||
return true;
|
||||
}
|
||||
|
||||
// did a cube touch me?
|
||||
if ( FClassnameIs( pOther, "prop_weighted_cube") || FClassnameIs( pOther, "prop_monster_box") )
|
||||
{
|
||||
CPropWeightedCube *pCube = static_cast<CPropWeightedCube*>( pOther );
|
||||
bool bIsBall = pCube && pCube->GetCubeType() == CUBE_SPHERE;
|
||||
|
||||
if ( ( bIsBall && m_pOwnerButton->AcceptsBall() ) || //If the button accepts balls and this is a ball ( floor, under and ball buttons )
|
||||
( !bIsBall && !m_pOwnerButton->OnlyAcceptBall() ) ) //If the button doesn't only accept balls and this is not a ball ( cube buttons )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// failed filter check
|
||||
return false;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
// Purpose: called only when the trigger is touched for the first time
|
||||
//----------------------------------------------------------------------------------
|
||||
void CPortalButtonTrigger::OnStartTouchAll( CBaseEntity *pOther )
|
||||
{
|
||||
// call the button's start touch function
|
||||
if ( m_pOwnerButton )
|
||||
{
|
||||
m_pOwnerButton->TriggerStartTouch( pOther );
|
||||
}
|
||||
|
||||
BaseClass::OnStartTouchAll( pOther );
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
// Purpose: called when the last object stops touching the trigger
|
||||
//----------------------------------------------------------------------------------
|
||||
void CPortalButtonTrigger::OnEndTouchAll( CBaseEntity *pOther )
|
||||
{
|
||||
// call the button's end touch function
|
||||
if ( m_pOwnerButton )
|
||||
{
|
||||
m_pOwnerButton->TriggerEndTouch( pOther );
|
||||
}
|
||||
|
||||
BaseClass::OnEndTouchAll( pOther );
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
// Purpose: spawn the trigger
|
||||
//----------------------------------------------------------------------------------
|
||||
void CPortalButtonTrigger::Spawn( void )
|
||||
{
|
||||
// Setup our basic attributes
|
||||
SetMoveType( MOVETYPE_NONE );
|
||||
SetSolid( SOLID_OBB );
|
||||
SetSolidFlags( FSOLID_NOT_SOLID|FSOLID_TRIGGER );
|
||||
|
||||
AddSpawnFlags( SF_TRIGGER_ALLOW_CLIENTS|SF_TRIGGER_ALLOW_PHYSICS );
|
||||
|
||||
BaseClass::Spawn();
|
||||
}
|
||||
|
||||
//
|
||||
// Floor Button
|
||||
//
|
||||
|
||||
ConVar sv_slippery_cube_button( "sv_slippery_cube_button", "1", FCVAR_CHEAT );
|
||||
|
||||
class CPropFloorCubeButton : public CPropFloorButton
|
||||
{
|
||||
public:
|
||||
DECLARE_CLASS( CPropFloorCubeButton, CPropFloorButton );
|
||||
DECLARE_DATADESC();
|
||||
|
||||
CPropFloorCubeButton();
|
||||
|
||||
virtual const char *GetButtonModelName();
|
||||
virtual bool ShouldPlayerTouch();
|
||||
virtual bool OnlyAcceptBall( void ) { return false; }
|
||||
virtual bool AcceptsBall( void ) { return m_bAcceptsBall; }
|
||||
|
||||
friend class CPortalButtonTrigger;
|
||||
|
||||
protected:
|
||||
virtual void Press( CBaseEntity *pActivator );
|
||||
virtual void UnPress( CBaseEntity *pActivator );
|
||||
|
||||
private:
|
||||
int m_nStoredMaterialIndex;
|
||||
|
||||
bool m_bAcceptsBall;
|
||||
};
|
||||
|
||||
LINK_ENTITY_TO_CLASS( prop_floor_cube_button, CPropFloorCubeButton );
|
||||
|
||||
BEGIN_DATADESC( CPropFloorCubeButton )
|
||||
|
||||
DEFINE_KEYFIELD( m_bAcceptsBall, FIELD_BOOLEAN, "AcceptsBall" ),
|
||||
|
||||
END_DATADESC()
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
CPropFloorCubeButton::CPropFloorCubeButton()
|
||||
: m_bAcceptsBall( true )
|
||||
{
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: get cube button model name
|
||||
//-----------------------------------------------------------------------------
|
||||
const char *CPropFloorCubeButton::GetButtonModelName()
|
||||
{
|
||||
return PROP_FLOOR_CUBE_BUTTON_MODEL_NAME;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CPropFloorCubeButton::ShouldPlayerTouch()
|
||||
{
|
||||
// Players may not touch the cube button
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void CPropFloorCubeButton::Press( CBaseEntity *pActivator )
|
||||
{
|
||||
if ( sv_slippery_cube_button.GetBool() )
|
||||
{
|
||||
// set the object material type to be ice so it will slip into the cube button
|
||||
IPhysicsObject* pPhysObject = pActivator->VPhysicsGetObject();
|
||||
if( pPhysObject )
|
||||
{
|
||||
m_nStoredMaterialIndex = pPhysObject->GetMaterialIndex();
|
||||
|
||||
pPhysObject->SetMaterialIndex( physprops->GetSurfaceIndex( "ice" ) );
|
||||
}
|
||||
}
|
||||
|
||||
BaseClass::Press( pActivator );
|
||||
}
|
||||
|
||||
|
||||
void CPropFloorCubeButton::UnPress( CBaseEntity *pActivator )
|
||||
{
|
||||
if ( sv_slippery_cube_button.GetBool() )
|
||||
{
|
||||
IPhysicsObject* pPhysObject = pActivator->VPhysicsGetObject();
|
||||
if( pPhysObject )
|
||||
{
|
||||
pPhysObject->SetMaterialIndex( m_nStoredMaterialIndex );
|
||||
}
|
||||
}
|
||||
|
||||
BaseClass::UnPress( pActivator );
|
||||
}
|
||||
|
||||
|
||||
class CPropFloorBallButton : public CPropFloorButton
|
||||
{
|
||||
public:
|
||||
DECLARE_CLASS( CPropFloorBallButton, CPropFloorButton );
|
||||
DECLARE_DATADESC();
|
||||
|
||||
virtual const char *GetButtonModelName();
|
||||
virtual bool ShouldPlayerTouch();
|
||||
virtual bool OnlyAcceptBall( void ) { return true; }
|
||||
virtual bool AcceptsBall( void ) { return true; }
|
||||
virtual void CreateTriggers( void );
|
||||
|
||||
friend class CPortalButtonTrigger;
|
||||
|
||||
private:
|
||||
int m_nStoredMaterialIndex;
|
||||
};
|
||||
|
||||
LINK_ENTITY_TO_CLASS( prop_floor_ball_button, CPropFloorBallButton );
|
||||
|
||||
BEGIN_DATADESC( CPropFloorBallButton )
|
||||
|
||||
END_DATADESC()
|
||||
|
||||
|
||||
void CPropFloorBallButton::CreateTriggers( void )
|
||||
{
|
||||
Vector vecOrigin = GetAbsOrigin();
|
||||
|
||||
// trigger size
|
||||
Vector vecMins( -5,-5,0 );
|
||||
Vector vecMaxs( 5,5,14 );
|
||||
|
||||
// Create the button trigger
|
||||
m_hButtonTrigger = CPortalButtonTrigger::Create( vecOrigin, GetAbsAngles(), vecMins, vecMaxs, this );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: get cube button model name
|
||||
//-----------------------------------------------------------------------------
|
||||
const char *CPropFloorBallButton::GetButtonModelName()
|
||||
{
|
||||
return PROP_FLOOR_BALL_BUTTON_MODEL_NAME;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CPropFloorBallButton::ShouldPlayerTouch()
|
||||
{
|
||||
// Players may not touch the cube button
|
||||
return false;
|
||||
}
|
||||
|
||||
class CPropUnderFloorButton : public CPropFloorButton
|
||||
{
|
||||
public:
|
||||
DECLARE_CLASS( CPropUnderFloorButton, CPropFloorButton );
|
||||
DECLARE_DATADESC();
|
||||
|
||||
virtual const char *GetButtonModelName();
|
||||
|
||||
friend class CPortalButtonTrigger;
|
||||
|
||||
protected:
|
||||
|
||||
virtual void LookUpAnimationSequences( void );
|
||||
virtual void CreateTriggers( void );
|
||||
};
|
||||
|
||||
LINK_ENTITY_TO_CLASS( prop_under_floor_button, CPropUnderFloorButton );
|
||||
|
||||
BEGIN_DATADESC( CPropUnderFloorButton )
|
||||
|
||||
END_DATADESC()
|
||||
|
||||
|
||||
const char *CPropUnderFloorButton::GetButtonModelName()
|
||||
{
|
||||
return PROP_UNDER_FLOOR_BUTTON_MODEL_NAME;
|
||||
}
|
||||
|
||||
|
||||
void CPropUnderFloorButton::LookUpAnimationSequences( void )
|
||||
{
|
||||
// look up animation sequences
|
||||
m_UpSequence = LookupSequence( "release" );
|
||||
m_DownSequence = LookupSequence( "press" );
|
||||
}
|
||||
|
||||
|
||||
void CPropUnderFloorButton::CreateTriggers( void )
|
||||
{
|
||||
Vector vecOrigin = GetAbsOrigin();
|
||||
|
||||
// trigger size
|
||||
Vector vecMins( -30, -30, 0 );
|
||||
Vector vecMaxs( 30, 30, 17 );
|
||||
|
||||
|
||||
// Create the button trigger
|
||||
m_hButtonTrigger = CPortalButtonTrigger::Create( vecOrigin, GetAbsAngles(), vecMins, vecMaxs, this );
|
||||
}
|
||||
982
game/server/portal2/prop_linked_portal_door.cpp
Normal file
982
game/server/portal2/prop_linked_portal_door.cpp
Normal file
@@ -0,0 +1,982 @@
|
||||
//===== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======//
|
||||
//
|
||||
// Purpose: Door pairs that can be seamlessly linked via portals to connect disparate areas
|
||||
//
|
||||
//===========================================================================//
|
||||
|
||||
#include "cbase.h"
|
||||
#include "portal_base2d.h"
|
||||
#include "physics_bone_follower.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
//=============================================================================
|
||||
// Non-animated linked portal door
|
||||
//=============================================================================
|
||||
|
||||
class CLinkedPortalDoor : public CBaseAnimating
|
||||
{
|
||||
public:
|
||||
DECLARE_CLASS( CLinkedPortalDoor, CBaseAnimating );
|
||||
DECLARE_DATADESC();
|
||||
DECLARE_ENT_SCRIPTDESC();
|
||||
|
||||
CLinkedPortalDoor( void );
|
||||
|
||||
virtual int DrawDebugTextOverlays( void );
|
||||
|
||||
virtual void UpdateOnRemove( void );
|
||||
virtual void Spawn( void );
|
||||
virtual void Activate( void );
|
||||
virtual void NotifyPortalEvent( PortalEvent_t nEventType, CPortal_Base2D *pNotifier );
|
||||
virtual void SetTransmit( CCheckTransmitInfo *pInfo, bool bAlways );
|
||||
|
||||
const char *GetPartnername() { return STRING( m_szPartnerName ); }
|
||||
|
||||
HSCRIPT ScriptGetPartnerInstanceHandle(){ return ToHScript( m_hPartner ); }
|
||||
|
||||
void DisableLinkageThink( void );
|
||||
|
||||
virtual void Open( CBaseEntity *pActivator );
|
||||
virtual void Close( CBaseEntity *pActivator );
|
||||
|
||||
protected:
|
||||
|
||||
// These functions are called directly to avoid recursion
|
||||
virtual void OpenInternal( CBaseEntity *pActivator );
|
||||
virtual void CloseInternal( CBaseEntity *pActivator );
|
||||
|
||||
// Creation/removal of internal members
|
||||
virtual void Destroy( void );
|
||||
|
||||
void ClearLinkPartner( void );
|
||||
|
||||
virtual void OnOpen( void ) {}
|
||||
virtual void OnClose( void ) {}
|
||||
|
||||
virtual bool IsOpen();
|
||||
virtual bool IsClosed();
|
||||
|
||||
// Prevents/allows portal functionality
|
||||
void DisableLinkage( void );
|
||||
void EnableLinkage( void );
|
||||
|
||||
void SetPartner( CLinkedPortalDoor *pPartner );
|
||||
void SetPartnerByName( string_t iszentityname );
|
||||
|
||||
void InputSetPartner( inputdata_t &input );
|
||||
void InputOpen( inputdata_t &input );
|
||||
void InputClose( inputdata_t &input );
|
||||
|
||||
virtual const Vector &OffsetPosition( void ) const { return vec3_origin; }
|
||||
|
||||
string_t m_szPartnerName; // name of our linked CLinkedPortalDoor partner
|
||||
bool m_bIsLinkedToPartner; // if true, door links to partner and does not move physically
|
||||
float m_flPortalCloseDelay;
|
||||
int m_nWidth;
|
||||
int m_nHeight;
|
||||
bool m_bStartActive;
|
||||
|
||||
COutputEvent m_OnOpen;
|
||||
COutputEvent m_OnClose;
|
||||
|
||||
COutputEvent m_OnEntityTeleportFromMe;
|
||||
COutputEvent m_OnPlayerTeleportFromMe;
|
||||
COutputEvent m_OnEntityTeleportToMe;
|
||||
COutputEvent m_OnPlayerTeleportToMe;
|
||||
|
||||
CHandle<CPortal_Base2D> m_hPortal;
|
||||
CHandle<CLinkedPortalDoor> m_hPartner;
|
||||
};
|
||||
|
||||
BEGIN_DATADESC( CLinkedPortalDoor )
|
||||
|
||||
DEFINE_INPUTFUNC( FIELD_STRING, "SetPartner", InputSetPartner ),
|
||||
DEFINE_INPUTFUNC( FIELD_VOID, "Open", InputOpen ),
|
||||
DEFINE_INPUTFUNC( FIELD_VOID, "Close", InputClose ),
|
||||
|
||||
DEFINE_KEYFIELD( m_nWidth, FIELD_INTEGER, "width" ),
|
||||
DEFINE_KEYFIELD( m_nHeight, FIELD_INTEGER, "height" ),
|
||||
DEFINE_KEYFIELD( m_szPartnerName, FIELD_STRING, "partnername" ),
|
||||
DEFINE_KEYFIELD( m_bStartActive, FIELD_BOOLEAN, "startactive" ),
|
||||
|
||||
DEFINE_FIELD( m_bIsLinkedToPartner, FIELD_BOOLEAN ),
|
||||
|
||||
DEFINE_FIELD( m_hPortal, FIELD_EHANDLE ),
|
||||
DEFINE_FIELD( m_hPartner, FIELD_EHANDLE ),
|
||||
|
||||
DEFINE_THINKFUNC( DisableLinkageThink ),
|
||||
|
||||
DEFINE_OUTPUT( m_OnOpen, "OnOpen" ),
|
||||
DEFINE_OUTPUT( m_OnClose, "OnClose" ),
|
||||
|
||||
DEFINE_OUTPUT( m_OnEntityTeleportFromMe, "OnEntityTeleportFromMe" ),
|
||||
DEFINE_OUTPUT( m_OnPlayerTeleportFromMe, "OnPlayerTeleportFromMe" ),
|
||||
DEFINE_OUTPUT( m_OnEntityTeleportToMe, "OnEntityTeleportToMe" ),
|
||||
DEFINE_OUTPUT( m_OnPlayerTeleportToMe, "OnPlayerTeleportToMe" ),
|
||||
|
||||
END_DATADESC()
|
||||
|
||||
BEGIN_ENT_SCRIPTDESC( CLinkedPortalDoor, CBaseAnimating, "Door linked by portals to a partner portal door")
|
||||
DEFINE_SCRIPTFUNC( GetPartnername, "Returns the partnername of the door." )
|
||||
DEFINE_SCRIPTFUNC_NAMED( ScriptGetPartnerInstanceHandle, "GetPartnerInstance", "Get the instance handle of the door's linked partner" )
|
||||
END_SCRIPTDESC();
|
||||
|
||||
LINK_ENTITY_TO_CLASS( linked_portal_door, CLinkedPortalDoor );
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
CLinkedPortalDoor::CLinkedPortalDoor( void ) :
|
||||
m_szPartnerName( NULL_STRING ),
|
||||
m_bIsLinkedToPartner( false ),
|
||||
m_hPortal( NULL ),
|
||||
m_hPartner( NULL ),
|
||||
m_flPortalCloseDelay( 0.0f ),
|
||||
m_nWidth( 128.0f ),
|
||||
m_nHeight( 128.0f ),
|
||||
m_bStartActive( false )
|
||||
{
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Draw any debug text overlays
|
||||
// Output : Current text offset from the top
|
||||
//-----------------------------------------------------------------------------
|
||||
int CLinkedPortalDoor::DrawDebugTextOverlays( void )
|
||||
{
|
||||
int text_offset = BaseClass::DrawDebugTextOverlays();
|
||||
|
||||
if (m_debugOverlays & OVERLAY_TEXT_BIT)
|
||||
{
|
||||
char tempstr[512];
|
||||
|
||||
// print flame size
|
||||
Q_snprintf(tempstr,sizeof(tempstr),"linked partner: %s", m_szPartnerName.ToCStr() );
|
||||
EntityText(text_offset,tempstr,0);
|
||||
text_offset++;
|
||||
}
|
||||
return text_offset;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Cleanup when we're killed off
|
||||
//-----------------------------------------------------------------------------
|
||||
void CLinkedPortalDoor::UpdateOnRemove( void )
|
||||
{
|
||||
Destroy();
|
||||
BaseClass::UpdateOnRemove();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CLinkedPortalDoor::Spawn( void )
|
||||
{
|
||||
Precache();
|
||||
BaseClass::Spawn();
|
||||
|
||||
SetMoveType( MOVETYPE_NONE );
|
||||
SetSolid( SOLID_NONE );
|
||||
|
||||
AddEffects( EF_NOSHADOW );
|
||||
|
||||
m_flPortalCloseDelay = 0.0f;
|
||||
|
||||
// Reseat the portal on the wall
|
||||
Vector vForward, vUp;
|
||||
GetVectors( &vForward, NULL, &vUp );
|
||||
|
||||
// Create our portal
|
||||
m_hPortal = (CPortal_Base2D *) CreateEntityByName( "portal_base2D" );
|
||||
Assert( m_hPortal );
|
||||
if ( m_hPortal )
|
||||
{
|
||||
//
|
||||
m_hPortal->m_bIsPortal2 = false;
|
||||
m_hPortal->SetOwnerEntity( this );
|
||||
m_hPortal->SetModel( "models/portals/portal1.mdl" );
|
||||
|
||||
// Setup our bounds
|
||||
Vector mins, maxs;
|
||||
CollisionProp()->WorldSpaceAABB( &mins, &maxs );
|
||||
UTIL_SetSize( m_hPortal, mins, maxs );
|
||||
m_hPortal->Resize( m_nWidth, m_nHeight ); // Default size (get from map)
|
||||
m_hPortal->Teleport( &GetAbsOrigin(), &GetAbsAngles(), NULL );
|
||||
|
||||
// Set up the correct state for activation
|
||||
m_hPortal->SetActive( m_bStartActive );
|
||||
|
||||
// Go!
|
||||
DispatchSpawn( m_hPortal );
|
||||
|
||||
// Listen for our events
|
||||
m_hPortal->AddPortalEventListener( this );
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CLinkedPortalDoor::Activate( void )
|
||||
{
|
||||
BaseClass::Activate();
|
||||
|
||||
// Link to our initial partner (if any)
|
||||
SetPartnerByName( m_szPartnerName );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Push our transmit state down to our attached portal
|
||||
//-----------------------------------------------------------------------------
|
||||
void CLinkedPortalDoor::SetTransmit( CCheckTransmitInfo *pInfo, bool bAlways )
|
||||
{
|
||||
// Are we already marked for transmission?
|
||||
if ( pInfo->m_pTransmitEdict->Get( entindex() ) )
|
||||
return;
|
||||
|
||||
BaseClass::SetTransmit( pInfo, bAlways );
|
||||
|
||||
// Force our attached entities to go too...
|
||||
if ( m_hPortal )
|
||||
{
|
||||
m_hPortal->SetTransmit( pInfo, bAlways );
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CLinkedPortalDoor::Destroy( void )
|
||||
{
|
||||
DisableLinkage();
|
||||
|
||||
if ( m_hPortal )
|
||||
{
|
||||
m_hPortal->m_hLinkedPortal = NULL;
|
||||
}
|
||||
|
||||
m_hPartner = NULL;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Disables portal functionality.
|
||||
//-----------------------------------------------------------------------------
|
||||
void CLinkedPortalDoor::DisableLinkage( void )
|
||||
{
|
||||
if ( m_bIsLinkedToPartner == false )
|
||||
return;
|
||||
|
||||
m_bIsLinkedToPartner = false;
|
||||
|
||||
if ( m_hPortal )
|
||||
{
|
||||
m_hPortal->SetActive( false );
|
||||
m_hPortal->m_PortalSimulator.DetachFromLinked();
|
||||
}
|
||||
|
||||
if ( m_hPartner )
|
||||
{
|
||||
m_hPartner->DisableLinkage();
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CLinkedPortalDoor::ClearLinkPartner( void )
|
||||
{
|
||||
DisableLinkage();
|
||||
|
||||
if ( m_hPortal )
|
||||
{
|
||||
m_hPortal->m_hLinkedPortal = NULL;
|
||||
}
|
||||
|
||||
m_hPartner = NULL;
|
||||
m_szPartnerName = NULL_STRING;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Enables portal functionality
|
||||
//-----------------------------------------------------------------------------
|
||||
void CLinkedPortalDoor::EnableLinkage( void )
|
||||
{
|
||||
if ( m_hPartner )
|
||||
{
|
||||
Assert( ((CLinkedPortalDoor *)m_hPartner.Get())->GetEntityName() == m_szPartnerName );
|
||||
}
|
||||
else if ( m_szPartnerName != NULL_STRING )
|
||||
{
|
||||
SetPartnerByName( m_szPartnerName );
|
||||
}
|
||||
else
|
||||
{
|
||||
// Is this valid?
|
||||
Assert( 0 );
|
||||
}
|
||||
|
||||
// Already linked
|
||||
if ( m_bIsLinkedToPartner )
|
||||
return;
|
||||
|
||||
if ( m_hPartner )
|
||||
{
|
||||
// We're whatever our partner is not
|
||||
m_hPortal->m_bIsPortal2 = !m_hPartner->m_hPortal->m_bIsPortal2;
|
||||
|
||||
Vector vForward, vRight, vUp;
|
||||
GetVectors( &vForward, &vRight, &vUp );
|
||||
Vector vOffset = OffsetPosition();
|
||||
m_hPortal->NewLocation( GetAbsOrigin() + (vForward * 0.5f) + ( vForward * vOffset.x ) + ( vRight * vOffset.y ) + ( vUp * vOffset.z ), GetAbsAngles() );
|
||||
|
||||
m_bIsLinkedToPartner = true;
|
||||
|
||||
// Set up our linkage here
|
||||
m_hPortal->m_hLinkedPortal = m_hPartner->m_hPortal;
|
||||
m_hPartner->m_hPortal->m_hLinkedPortal = m_hPortal;
|
||||
m_hPortal->UpdatePortalLinkage();
|
||||
|
||||
// Force them on as well
|
||||
((CLinkedPortalDoor *)m_hPartner.Get())->EnableLinkage();
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CLinkedPortalDoor::SetPartner( CLinkedPortalDoor *pPartner )
|
||||
{
|
||||
// Don't bother if we've done this already
|
||||
if ( pPartner == ((CLinkedPortalDoor *)m_hPartner.Get()) )
|
||||
return;
|
||||
|
||||
if ( pPartner == NULL )
|
||||
{
|
||||
// This is invalid!
|
||||
Assert( pPartner != NULL );
|
||||
DisableLinkage();
|
||||
return;
|
||||
}
|
||||
else if ( m_hPartner && ((CLinkedPortalDoor *)m_hPartner.Get()) != pPartner )
|
||||
{
|
||||
// Unlink from our current partner!
|
||||
CLinkedPortalDoor *pPartner = ((CLinkedPortalDoor *)m_hPartner.Get());
|
||||
pPartner->ClearLinkPartner();// Force our partner to forget about us as well
|
||||
|
||||
ClearLinkPartner();
|
||||
}
|
||||
|
||||
// Take the new partner
|
||||
m_szPartnerName = pPartner->GetEntityName();
|
||||
m_hPartner = pPartner;
|
||||
m_hPortal->m_hLinkedPortal = pPartner->m_hPortal;
|
||||
|
||||
// This must be reciprocal!
|
||||
pPartner->SetPartner( this );
|
||||
|
||||
// If we're already open, then update our portal immediately
|
||||
if ( m_hPortal->IsActive() )
|
||||
{
|
||||
EnableLinkage();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CLinkedPortalDoor::SetPartnerByName( string_t iszentityname )
|
||||
{
|
||||
// Take the new partner name
|
||||
m_szPartnerName = iszentityname;
|
||||
|
||||
// Find the entity and link to it
|
||||
CBaseEntity* pEnt = gEntList.FindEntityByName( NULL, STRING(m_szPartnerName), this, NULL, NULL, NULL );
|
||||
if ( pEnt )
|
||||
{
|
||||
SetPartner( dynamic_cast<CLinkedPortalDoor*>(pEnt) );
|
||||
}
|
||||
else
|
||||
{
|
||||
Warning( "prop_portal_linked_door '%s' failed to link to partner named: '%s'\n", GetDebugName(), STRING(m_szPartnerName) );
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CLinkedPortalDoor::InputSetPartner( inputdata_t &input )
|
||||
{
|
||||
SetPartnerByName( input.value.StringID() );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Open the door input
|
||||
//-----------------------------------------------------------------------------
|
||||
void CLinkedPortalDoor::InputOpen( inputdata_t &input )
|
||||
{
|
||||
Open( input.pActivator );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: "Open" the door
|
||||
//-----------------------------------------------------------------------------
|
||||
void CLinkedPortalDoor::Open( CBaseEntity *pActivator )
|
||||
{
|
||||
if ( m_hPartner == NULL )
|
||||
{
|
||||
SetPartnerByName( m_szPartnerName );
|
||||
}
|
||||
|
||||
// Open ourself
|
||||
OpenInternal( pActivator );
|
||||
|
||||
// Force our partner to respond in kind
|
||||
if ( m_hPartner != NULL )
|
||||
{
|
||||
((CLinkedPortalDoor *)m_hPartner.Get())->OpenInternal( pActivator );
|
||||
}
|
||||
|
||||
EnableLinkage();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Return true if the door is open
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CLinkedPortalDoor::IsOpen()
|
||||
{
|
||||
return m_hPortal->IsActive();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Return true if the door is closed
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CLinkedPortalDoor::IsClosed()
|
||||
{
|
||||
return !(m_hPortal->IsActive());
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Internal version which is non-public
|
||||
//-----------------------------------------------------------------------------
|
||||
void CLinkedPortalDoor::OpenInternal( CBaseEntity *pActivator )
|
||||
{
|
||||
SetContextThink( NULL, TICK_NEVER_THINK, "DisableLinkageThink" );
|
||||
|
||||
// Don't fire the output if the door is already opened
|
||||
if ( IsOpen() )
|
||||
return;
|
||||
|
||||
// Fire the OnOpen output
|
||||
m_OnOpen.FireOutput( this, this );
|
||||
|
||||
OnOpen();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: "Close" the door
|
||||
//-----------------------------------------------------------------------------
|
||||
void CLinkedPortalDoor::Close( CBaseEntity *pActivator )
|
||||
{
|
||||
CloseInternal( pActivator );
|
||||
|
||||
// Get our partner to open
|
||||
if ( m_hPartner != NULL )
|
||||
{
|
||||
((CLinkedPortalDoor *)m_hPartner.Get())->CloseInternal( pActivator );
|
||||
|
||||
// Close right now unless being overridden
|
||||
if ( m_flPortalCloseDelay == 0.0f )
|
||||
{
|
||||
DisableLinkage();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Internal non-public version
|
||||
//-----------------------------------------------------------------------------
|
||||
void CLinkedPortalDoor::CloseInternal( CBaseEntity *pActivator )
|
||||
{
|
||||
// Don't fire the output if the door is already closed
|
||||
if ( IsClosed() )
|
||||
return;
|
||||
|
||||
// Fire the OnClose output
|
||||
m_OnClose.FireOutput( this, this );
|
||||
|
||||
OnClose();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Close the door input
|
||||
//-----------------------------------------------------------------------------
|
||||
void CLinkedPortalDoor::InputClose( inputdata_t &input )
|
||||
{
|
||||
Close( input.pActivator );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Close the portal down
|
||||
//-----------------------------------------------------------------------------
|
||||
void CLinkedPortalDoor::DisableLinkageThink( void )
|
||||
{
|
||||
DisableLinkage();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Handle entity teleports from / to my portal
|
||||
//-----------------------------------------------------------------------------
|
||||
void CLinkedPortalDoor::NotifyPortalEvent( PortalEvent_t nEventType, CPortal_Base2D *pNotifier )
|
||||
{
|
||||
BaseClass::NotifyPortalEvent( nEventType, pNotifier );
|
||||
|
||||
switch ( nEventType )
|
||||
{
|
||||
case PORTALEVENT_ENTITY_TELEPORTED_TO:
|
||||
m_OnEntityTeleportToMe.FireOutput( this, this );
|
||||
break;
|
||||
|
||||
case PORTALEVENT_ENTITY_TELEPORTED_FROM:
|
||||
m_OnEntityTeleportFromMe.FireOutput( this, this );
|
||||
break;
|
||||
|
||||
case PORTALEVENT_PLAYER_TELEPORTED_TO:
|
||||
m_OnPlayerTeleportToMe.FireOutput( this, this );
|
||||
break;
|
||||
|
||||
case PORTALEVENT_PLAYER_TELEPORTED_FROM:
|
||||
m_OnPlayerTeleportFromMe.FireOutput( this, this );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#define PORTAL_LINKED_DOOR_MODEL_NAME "models/props/portal_door.mdl"
|
||||
#define PORTAL_LINKED_DOOR_RESTING_SURFACE_TRACE_DIST 1.5f
|
||||
|
||||
//=============================================================================
|
||||
// Animated linked portal door
|
||||
//=============================================================================
|
||||
class CPropLinkedPortalDoor : public CLinkedPortalDoor
|
||||
{
|
||||
public:
|
||||
DECLARE_CLASS( CPropLinkedPortalDoor, CLinkedPortalDoor );
|
||||
DECLARE_SERVERCLASS();
|
||||
DECLARE_DATADESC();
|
||||
DECLARE_ENT_SCRIPTDESC();
|
||||
|
||||
CPropLinkedPortalDoor( void );
|
||||
|
||||
virtual void Precache( void );
|
||||
virtual void Spawn( void );
|
||||
virtual bool CreateVPhysics( void );
|
||||
virtual void Activate( void );
|
||||
virtual bool TestCollision( const Ray_t &ray, unsigned int mask, trace_t& trace );
|
||||
|
||||
virtual void AnimateThink( void );
|
||||
|
||||
virtual bool IsOpen( void ) { return ( GetSequence() == m_nSequenceOpenIdle || GetSequence() == m_nSequenceOpen ); }
|
||||
virtual bool IsClosed( void ) { return ( GetSequence() == m_nSequenceCloseIdle || GetSequence() == m_nSequenceClose ); }
|
||||
|
||||
protected:
|
||||
|
||||
void CreateBoneFollowers( void );
|
||||
|
||||
// Creation/removal of internal members
|
||||
virtual void Destroy( void );
|
||||
|
||||
virtual void OpenInternal( CBaseEntity *pActivator );
|
||||
virtual void CloseInternal( CBaseEntity *pActivator );
|
||||
|
||||
|
||||
void OnFullyOpened( void );
|
||||
void OnFullyClosed( void );
|
||||
|
||||
virtual void OnOpen( void );
|
||||
virtual void OnClose( void );
|
||||
|
||||
virtual void SetPartner( CLinkedPortalDoor *pPartner );
|
||||
|
||||
virtual const Vector &OffsetPosition( void ) const { static Vector vOffsetVector( 0, 0, 45 ); return vOffsetVector; }
|
||||
|
||||
COutputEvent m_OnFullyOpen;
|
||||
COutputEvent m_OnFullyClosed;
|
||||
|
||||
int m_nSequenceOpen;
|
||||
int m_nSequenceOpenIdle;
|
||||
int m_nSequenceClose;
|
||||
int m_nSequenceCloseIdle;
|
||||
|
||||
CBoneFollowerManager m_BoneFollowerManager;
|
||||
};
|
||||
|
||||
IMPLEMENT_SERVERCLASS_ST( CPropLinkedPortalDoor, DT_PropLinkedPortalDoor )
|
||||
END_SEND_TABLE()
|
||||
|
||||
BEGIN_DATADESC( CPropLinkedPortalDoor )
|
||||
|
||||
DEFINE_INPUTFUNC( FIELD_STRING, "SetPartner", InputSetPartner ),
|
||||
DEFINE_INPUTFUNC( FIELD_VOID, "Open", InputOpen ),
|
||||
DEFINE_INPUTFUNC( FIELD_VOID, "Close", InputClose ),
|
||||
|
||||
DEFINE_KEYFIELD( m_szPartnerName, FIELD_STRING, "partnername" ),
|
||||
|
||||
DEFINE_FIELD( m_bIsLinkedToPartner, FIELD_BOOLEAN ),
|
||||
DEFINE_FIELD( m_nSequenceOpen, FIELD_INTEGER ),
|
||||
DEFINE_FIELD( m_nSequenceOpenIdle, FIELD_INTEGER ),
|
||||
DEFINE_FIELD( m_nSequenceClose, FIELD_INTEGER ),
|
||||
DEFINE_FIELD( m_nSequenceCloseIdle, FIELD_INTEGER ),
|
||||
|
||||
DEFINE_FIELD( m_hPortal, FIELD_EHANDLE ),
|
||||
DEFINE_FIELD( m_hPartner, FIELD_EHANDLE ),
|
||||
|
||||
DEFINE_THINKFUNC( AnimateThink ),
|
||||
DEFINE_THINKFUNC( DisableLinkageThink ),
|
||||
|
||||
DEFINE_OUTPUT( m_OnFullyClosed, "OnFullyClosed" ),
|
||||
DEFINE_OUTPUT( m_OnFullyOpen, "OnFullyOpen" ),
|
||||
|
||||
DEFINE_OUTPUT( m_OnOpen, "OnOpen" ),
|
||||
DEFINE_OUTPUT( m_OnClose, "OnClose" ),
|
||||
|
||||
DEFINE_OUTPUT( m_OnEntityTeleportFromMe, "OnEntityTeleportFromMe" ),
|
||||
DEFINE_OUTPUT( m_OnPlayerTeleportFromMe, "OnPlayerTeleportFromMe" ),
|
||||
DEFINE_OUTPUT( m_OnEntityTeleportToMe, "OnEntityTeleportToMe" ),
|
||||
DEFINE_OUTPUT( m_OnPlayerTeleportToMe, "OnPlayerTeleportToMe" ),
|
||||
|
||||
DEFINE_EMBEDDED( m_BoneFollowerManager ),
|
||||
|
||||
END_DATADESC()
|
||||
|
||||
BEGIN_ENT_SCRIPTDESC( CPropLinkedPortalDoor, CBaseAnimating, "Door linked by portals to a partner portal door")
|
||||
DEFINE_SCRIPTFUNC( GetPartnername, "Returns the partnername of the door." )
|
||||
DEFINE_SCRIPTFUNC_NAMED( ScriptGetPartnerInstanceHandle, "GetPartnerInstance", "Get the instance handle of the door's linked partner" )
|
||||
END_SCRIPTDESC();
|
||||
|
||||
LINK_ENTITY_TO_CLASS( prop_linked_portal_door, CPropLinkedPortalDoor );
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
CPropLinkedPortalDoor::CPropLinkedPortalDoor( void ) :
|
||||
m_nSequenceOpen( -1 ),
|
||||
m_nSequenceOpenIdle( -1 ),
|
||||
m_nSequenceClose( -1 ),
|
||||
m_nSequenceCloseIdle( -1 )
|
||||
{
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CPropLinkedPortalDoor::Precache( void )
|
||||
{
|
||||
PrecacheModel( PORTAL_LINKED_DOOR_MODEL_NAME );
|
||||
|
||||
PrecacheScriptSound( "prop_portal_door.open" );
|
||||
PrecacheScriptSound( "prop_portal_door.close" );
|
||||
|
||||
BaseClass::Precache();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CPropLinkedPortalDoor::Spawn( void )
|
||||
{
|
||||
Precache();
|
||||
BaseClass::Spawn();
|
||||
|
||||
SetMoveType( MOVETYPE_NONE );
|
||||
SetSolid( SOLID_VPHYSICS );
|
||||
|
||||
AddEffects( EF_NOSHADOW );
|
||||
|
||||
m_flPortalCloseDelay = 0.5f;
|
||||
|
||||
SetModel( PORTAL_LINKED_DOOR_MODEL_NAME );
|
||||
CreateVPhysics();
|
||||
|
||||
// Cache off our sequences for quick lookup later
|
||||
m_nSequenceOpen = LookupSequence( "open" );
|
||||
m_nSequenceOpenIdle = LookupSequence( "idleopen" );
|
||||
m_nSequenceClose = LookupSequence( "close" );
|
||||
m_nSequenceCloseIdle = LookupSequence( "idleclose" );
|
||||
|
||||
// Reseat the portal on the wall
|
||||
Vector vForward, vUp;
|
||||
GetVectors( &vForward, NULL, &vUp );
|
||||
|
||||
Vector vHeightOffset = vUp * 45.0f;
|
||||
Vector vCenterTraceOrigin = GetAbsOrigin() + ( vForward * 12.0f ) + vHeightOffset; //HACKHACK: 45 up because we're using a model with a bottom oriented origin, but portals use centered origin
|
||||
trace_t tr;
|
||||
UTIL_TraceLine( vCenterTraceOrigin, vCenterTraceOrigin - ( vForward * 36.0f ), MASK_SOLID, this, COLLISION_GROUP_NONE, &tr );
|
||||
Vector vFinalPos = tr.endpos - vHeightOffset; // Take the fix-up back off
|
||||
Teleport( &vFinalPos, &GetAbsAngles(), NULL );
|
||||
|
||||
// Start closed
|
||||
ResetSequence( m_nSequenceCloseIdle );
|
||||
|
||||
// Create our portal
|
||||
if ( m_hPortal )
|
||||
{
|
||||
m_hPortal->SetModel( "models/portals/portal1.mdl" );
|
||||
|
||||
// Setup our bounds
|
||||
Vector mins, maxs;
|
||||
CollisionProp()->WorldSpaceAABB( &mins, &maxs );
|
||||
UTIL_SetSize( m_hPortal, mins, maxs );
|
||||
m_hPortal->Resize( 78, 82 ); // FIXME: Need to get these dimensions from somewhere else!
|
||||
Vector vPos = tr.endpos + (vForward * 0.5f);
|
||||
m_hPortal->Teleport( &vPos, &GetAbsAngles(), NULL );
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CPropLinkedPortalDoor::CreateVPhysics( void )
|
||||
{
|
||||
CreateBoneFollowers();
|
||||
|
||||
if ( m_BoneFollowerManager.GetNumBoneFollowers() )
|
||||
{
|
||||
if ( GetSolidFlags() & FSOLID_NOT_SOLID )
|
||||
{
|
||||
// Already non-solid? Must need bone followers for some other reason
|
||||
// like needing to attach constraints to this object
|
||||
for ( int i = 0; i < m_BoneFollowerManager.GetNumBoneFollowers(); i++ )
|
||||
{
|
||||
CBaseEntity *pFollower = m_BoneFollowerManager.GetBoneFollower(i)->hFollower;
|
||||
if ( pFollower )
|
||||
{
|
||||
pFollower->AddSolidFlags(FSOLID_NOT_SOLID);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
// If our collision is through bone followers, we want to be non-solid
|
||||
AddSolidFlags( FSOLID_NOT_SOLID );
|
||||
// add these for the client, FSOLID_NOT_SOLID should keep it out of the testCollision code
|
||||
// except in the case of TraceEntity() which the client does for impact effects
|
||||
AddSolidFlags( FSOLID_CUSTOMRAYTEST | FSOLID_CUSTOMBOXTEST );
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
VPhysicsInitStatic();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CPropLinkedPortalDoor::CreateBoneFollowers( void )
|
||||
{
|
||||
// already created bone followers? Don't do so again.
|
||||
if ( m_BoneFollowerManager.GetNumBoneFollowers() )
|
||||
return;
|
||||
|
||||
KeyValues *modelKeyValues = new KeyValues("");
|
||||
if ( modelKeyValues->LoadFromBuffer( modelinfo->GetModelName( GetModel() ), modelinfo->GetModelKeyValueText( GetModel() ) ) )
|
||||
{
|
||||
// Do we have a bone follower section?
|
||||
KeyValues *pkvBoneFollowers = modelKeyValues->FindKey("bone_followers");
|
||||
if ( pkvBoneFollowers )
|
||||
{
|
||||
// Loop through the list and create the bone followers
|
||||
KeyValues *pBone = pkvBoneFollowers->GetFirstSubKey();
|
||||
while ( pBone )
|
||||
{
|
||||
// Add it to the list
|
||||
const char *pBoneName = pBone->GetString();
|
||||
m_BoneFollowerManager.AddBoneFollower( this, pBoneName );
|
||||
|
||||
pBone = pBone->GetNextKey();
|
||||
}
|
||||
}
|
||||
|
||||
modelKeyValues->deleteThis();
|
||||
}
|
||||
|
||||
// if we got here, we don't have a bone follower section, but if we have a ragdoll
|
||||
// go ahead and create default bone followers for it
|
||||
if ( m_BoneFollowerManager.GetNumBoneFollowers() == 0 )
|
||||
{
|
||||
vcollide_t *pCollide = modelinfo->GetVCollide( GetModelIndex() );
|
||||
if ( pCollide && pCollide->solidCount > 1 )
|
||||
{
|
||||
CreateBoneFollowersFromRagdoll( this, &m_BoneFollowerManager, pCollide );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CPropLinkedPortalDoor::TestCollision( const Ray_t &ray, unsigned int mask, trace_t& trace )
|
||||
{
|
||||
if ( IsSolidFlagSet(FSOLID_NOT_SOLID) )
|
||||
{
|
||||
// if this entity is marked non-solid and custom test it must have bone followers
|
||||
if ( IsSolidFlagSet( FSOLID_CUSTOMBOXTEST ) && IsSolidFlagSet( FSOLID_CUSTOMRAYTEST ))
|
||||
{
|
||||
for ( int i = 0; i < m_BoneFollowerManager.GetNumBoneFollowers(); i++ )
|
||||
{
|
||||
CBaseEntity *pEntity = m_BoneFollowerManager.GetBoneFollower(i)->hFollower;
|
||||
if ( pEntity && pEntity->TestCollision(ray, mask, trace) )
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// PORTAL2: This is a change from shipped code, but should be benign
|
||||
return BaseClass::TestCollision( ray, mask, trace );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CPropLinkedPortalDoor::Activate( void )
|
||||
{
|
||||
BaseClass::Activate();
|
||||
|
||||
// Start our animation cycle
|
||||
SetThink( &CPropLinkedPortalDoor::AnimateThink );
|
||||
SetNextThink( gpGlobals->curtime + 0.1f );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Animate and catch edge cases for us stopping / starting our animation
|
||||
//-----------------------------------------------------------------------------
|
||||
void CPropLinkedPortalDoor::AnimateThink( void )
|
||||
{
|
||||
// Update our animation
|
||||
StudioFrameAdvance();
|
||||
DispatchAnimEvents( this );
|
||||
m_BoneFollowerManager.UpdateBoneFollowers( this );
|
||||
|
||||
if ( IsSequenceFinished() )
|
||||
{
|
||||
int nSequence = GetSequence();
|
||||
if ( nSequence == m_nSequenceOpen )
|
||||
{
|
||||
int nIdleSequence = m_nSequenceOpenIdle;
|
||||
ResetSequence( nIdleSequence );
|
||||
|
||||
OnFullyOpened();
|
||||
}
|
||||
else if ( nSequence == m_nSequenceClose )
|
||||
{
|
||||
int nIdleSequence = m_nSequenceCloseIdle;
|
||||
ResetSequence( nIdleSequence );
|
||||
|
||||
OnFullyClosed();
|
||||
}
|
||||
}
|
||||
|
||||
SetThink( &CPropLinkedPortalDoor::AnimateThink );
|
||||
SetNextThink( gpGlobals->curtime + 0.1f );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Open the door
|
||||
//-----------------------------------------------------------------------------
|
||||
void CPropLinkedPortalDoor::OpenInternal( CBaseEntity *pActivator )
|
||||
{
|
||||
BaseClass::OpenInternal( pActivator );
|
||||
|
||||
// Only set the door open sequence if the door is closed
|
||||
if ( IsClosed() )
|
||||
{
|
||||
ResetSequence( m_nSequenceOpen );
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Close the door
|
||||
//-----------------------------------------------------------------------------
|
||||
void CPropLinkedPortalDoor::CloseInternal( CBaseEntity *pActivator )
|
||||
{
|
||||
BaseClass::CloseInternal( pActivator );
|
||||
|
||||
// Only set the door closed sequence if the door is open
|
||||
if ( IsOpen() )
|
||||
{
|
||||
ResetSequence( m_nSequenceClose );
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: OnOpened output
|
||||
//-----------------------------------------------------------------------------
|
||||
void CPropLinkedPortalDoor::OnOpen( void )
|
||||
{
|
||||
// Play door open sound
|
||||
EmitSound( "prop_portal_door.open" );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: OnClosed output
|
||||
//-----------------------------------------------------------------------------
|
||||
void CPropLinkedPortalDoor::OnClose( void )
|
||||
{
|
||||
// Play door close sound
|
||||
EmitSound( "prop_portal_door.close" );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: OnFullyOpened output
|
||||
//-----------------------------------------------------------------------------
|
||||
void CPropLinkedPortalDoor::OnFullyOpened( void )
|
||||
{
|
||||
m_OnFullyOpen.FireOutput( this, this );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Close the door
|
||||
//-----------------------------------------------------------------------------
|
||||
void CPropLinkedPortalDoor::OnFullyClosed( void )
|
||||
{
|
||||
m_OnFullyClosed.FireOutput( this, this );
|
||||
SetContextThink( &CLinkedPortalDoor::DisableLinkageThink, gpGlobals->curtime + m_flPortalCloseDelay, "DisableLinkageThink" );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CPropLinkedPortalDoor::Destroy( void )
|
||||
{
|
||||
BaseClass::Destroy();
|
||||
|
||||
m_BoneFollowerManager.DestroyBoneFollowers();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CPropLinkedPortalDoor::SetPartner( CLinkedPortalDoor *pPartner )
|
||||
{
|
||||
BaseClass::SetPartner( pPartner );
|
||||
|
||||
// If we're already open, then update our portal immediately
|
||||
if ( GetSequence() == m_nSequenceOpenIdle )
|
||||
{
|
||||
if ( IsOpen() )
|
||||
{
|
||||
pPartner->Open( this );
|
||||
}
|
||||
else
|
||||
{
|
||||
pPartner->Close( this );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
457
game/server/portal2/prop_testchamber_door.cpp
Normal file
457
game/server/portal2/prop_testchamber_door.cpp
Normal file
@@ -0,0 +1,457 @@
|
||||
//===== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======//
|
||||
//
|
||||
// Purpose: Test chamber doors
|
||||
//
|
||||
//===========================================================================//
|
||||
|
||||
#include "cbase.h"
|
||||
|
||||
#include "prop_testchamber_door.h"
|
||||
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
#define TESTCHAMBER_DOOR_MODEL_NAME "models/props/portal_door_combined.mdl"
|
||||
|
||||
#define TESTCHAMBER_DOOR_AREA_PORTAL_NEVER_FADE_DISTANCE 10000.0f
|
||||
|
||||
|
||||
BEGIN_DATADESC( CPropTestChamberDoor )
|
||||
|
||||
DEFINE_FIELD( m_nSequenceOpen, FIELD_INTEGER ),
|
||||
DEFINE_FIELD( m_nSequenceOpenIdle, FIELD_INTEGER ),
|
||||
DEFINE_FIELD( m_nSequenceClose, FIELD_INTEGER ),
|
||||
DEFINE_FIELD( m_nSequenceCloseIdle, FIELD_INTEGER ),
|
||||
|
||||
DEFINE_FIELD( m_bIsOpen, FIELD_BOOLEAN ),
|
||||
DEFINE_FIELD( m_bIsAnimating, FIELD_BOOLEAN ),
|
||||
DEFINE_FIELD( m_bIsLocked, FIELD_BOOLEAN ),
|
||||
|
||||
DEFINE_FIELD( m_hAreaPortalWindow, FIELD_EHANDLE ),
|
||||
|
||||
DEFINE_KEYFIELD( m_strAreaPortalWindowName, FIELD_STRING, "AreaPortalWindow" ),
|
||||
DEFINE_KEYFIELD( m_bUseAreaPortalFade, FIELD_BOOLEAN, "UseAreaPortalFade" ),
|
||||
DEFINE_KEYFIELD( m_flAreaPortalFadeStartDistance, FIELD_FLOAT, "AreaPortalFadeStart" ),
|
||||
DEFINE_KEYFIELD( m_flAreaPortalFadeEndDistance, FIELD_FLOAT, "AreaPortalFadeEnd" ),
|
||||
|
||||
DEFINE_THINKFUNC( AnimateThink ),
|
||||
|
||||
DEFINE_INPUTFUNC( FIELD_VOID, "Open", InputOpen ),
|
||||
DEFINE_INPUTFUNC( FIELD_VOID, "Close", InputClose ),
|
||||
DEFINE_INPUTFUNC( FIELD_VOID, "Lock", InputLock ),
|
||||
DEFINE_INPUTFUNC( FIELD_VOID, "LockOpen", InputLockOpen ),
|
||||
DEFINE_INPUTFUNC( FIELD_VOID, "Unlock", InputUnlock ),
|
||||
|
||||
DEFINE_OUTPUT( m_OnOpen, "OnOpen" ),
|
||||
DEFINE_OUTPUT( m_OnClose, "OnClose" ),
|
||||
DEFINE_OUTPUT( m_OnFullyClosed, "OnFullyClosed" ),
|
||||
DEFINE_OUTPUT( m_OnFullyOpen, "OnFullyOpen" ),
|
||||
|
||||
DEFINE_EMBEDDED( m_BoneFollowerManager ),
|
||||
|
||||
END_DATADESC()
|
||||
|
||||
LINK_ENTITY_TO_CLASS( prop_testchamber_door, CPropTestChamberDoor );
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
CPropTestChamberDoor::CPropTestChamberDoor( void )
|
||||
: m_bIsOpen( false ),
|
||||
m_bIsAnimating( false ),
|
||||
m_bIsLocked( false )
|
||||
{
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CPropTestChamberDoor::Precache( void )
|
||||
{
|
||||
PrecacheModel( TESTCHAMBER_DOOR_MODEL_NAME );
|
||||
|
||||
PrecacheScriptSound( "prop_portal_door.open" );
|
||||
PrecacheScriptSound( "prop_portal_door.close" );
|
||||
|
||||
BaseClass::Precache();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CPropTestChamberDoor::Spawn( void )
|
||||
{
|
||||
Precache();
|
||||
BaseClass::Spawn();
|
||||
|
||||
SetMoveType( MOVETYPE_NONE );
|
||||
SetSolid( SOLID_VPHYSICS );
|
||||
|
||||
AddEffects( EF_NOSHADOW );
|
||||
|
||||
SetModel( TESTCHAMBER_DOOR_MODEL_NAME );
|
||||
CreateVPhysics();
|
||||
|
||||
// Cache off our sequences for quick lookup later
|
||||
m_nSequenceOpen = LookupSequence( "open" );
|
||||
m_nSequenceOpenIdle = LookupSequence( "idleopen" );
|
||||
m_nSequenceClose = LookupSequence( "close" );
|
||||
m_nSequenceCloseIdle = LookupSequence( "idleclose" );
|
||||
|
||||
// Start closed
|
||||
ResetSequence( m_nSequenceOpen );
|
||||
|
||||
SetPlaybackRate( 0.0f );
|
||||
|
||||
//If an area portal window name has been specified
|
||||
if( m_strAreaPortalWindowName != NULL_STRING )
|
||||
{
|
||||
CBaseEntity *pAreaPortalWindow = gEntList.FindEntityByName( NULL, m_strAreaPortalWindowName );
|
||||
if( pAreaPortalWindow )
|
||||
{
|
||||
m_hAreaPortalWindow = (CFuncAreaPortalWindow*) pAreaPortalWindow;
|
||||
|
||||
AreaPortalClose();
|
||||
}
|
||||
else
|
||||
{
|
||||
DevWarning( "Could not find area portal window named %s for test chamber door %s\n", m_strAreaPortalWindowName.ToCStr(), m_iClassname.ToCStr() );
|
||||
}
|
||||
}
|
||||
|
||||
AddEffects( EF_MARKED_FOR_FAST_REFLECTION );
|
||||
|
||||
// Never let crucial game components fade out!
|
||||
SetFadeDistance( -1.0f, 0.0f );
|
||||
SetGlobalFadeScale( 0.0f );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CPropTestChamberDoor::Activate( void )
|
||||
{
|
||||
BaseClass::Activate();
|
||||
|
||||
// Start our animation cycle
|
||||
SetThink( &CPropTestChamberDoor::AnimateThink );
|
||||
SetNextThink( gpGlobals->curtime + 0.1f );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Open the door input
|
||||
//-----------------------------------------------------------------------------
|
||||
void CPropTestChamberDoor::UpdateOnRemove( void )
|
||||
{
|
||||
m_BoneFollowerManager.DestroyBoneFollowers();
|
||||
|
||||
BaseClass::UpdateOnRemove();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Open the door input
|
||||
//-----------------------------------------------------------------------------
|
||||
void CPropTestChamberDoor::InputOpen( inputdata_t &input )
|
||||
{
|
||||
Open( input.pActivator );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: "Open" the door
|
||||
//-----------------------------------------------------------------------------
|
||||
void CPropTestChamberDoor::Open( CBaseEntity *pActivator )
|
||||
{
|
||||
// Don't fire the output if the door is already opened or locked
|
||||
if ( IsOpen() || m_bIsLocked )
|
||||
return;
|
||||
|
||||
//Play the open animation forwards
|
||||
SetPlaybackRate( 1.0f );
|
||||
|
||||
m_bIsOpen = true;
|
||||
m_bIsAnimating = true;
|
||||
|
||||
OnOpen();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Return true if the door is open
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CPropTestChamberDoor::IsOpen()
|
||||
{
|
||||
return ( m_bIsOpen );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Return true if the door is closed
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CPropTestChamberDoor::IsClosed()
|
||||
{
|
||||
return ( !m_bIsOpen );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: "Close" the door
|
||||
//-----------------------------------------------------------------------------
|
||||
void CPropTestChamberDoor::Close( CBaseEntity *pActivator )
|
||||
{
|
||||
// Don't fire the output if the door is already closed or locked
|
||||
if ( IsClosed() || m_bIsLocked )
|
||||
return;
|
||||
|
||||
//Play the open animation backwards
|
||||
SetPlaybackRate( -1.0f );
|
||||
|
||||
m_bIsOpen = false;
|
||||
m_bIsAnimating = true;
|
||||
|
||||
OnClose();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Close the door input
|
||||
//-----------------------------------------------------------------------------
|
||||
void CPropTestChamberDoor::InputClose( inputdata_t &input )
|
||||
{
|
||||
Close( input.pActivator );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Locks the door so open and close input don't have any affect until unlocked
|
||||
//-----------------------------------------------------------------------------
|
||||
void CPropTestChamberDoor::InputLock( inputdata_t &input )
|
||||
{
|
||||
m_bIsLocked = true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: If closed, opens the door and then locks it so open and close inputs have no effect
|
||||
//-----------------------------------------------------------------------------
|
||||
void CPropTestChamberDoor::InputLockOpen( inputdata_t &input )
|
||||
{
|
||||
Open( input.pActivator );
|
||||
|
||||
m_bIsLocked = true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Unlocks the door so open and close input work again
|
||||
//-----------------------------------------------------------------------------
|
||||
void CPropTestChamberDoor::InputUnlock( inputdata_t &input )
|
||||
{
|
||||
m_bIsLocked = false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CPropTestChamberDoor::CreateVPhysics( void )
|
||||
{
|
||||
CreateBoneFollowers();
|
||||
|
||||
if ( m_BoneFollowerManager.GetNumBoneFollowers() )
|
||||
{
|
||||
if ( GetSolidFlags() & FSOLID_NOT_SOLID )
|
||||
{
|
||||
// Already non-solid? Must need bone followers for some other reason
|
||||
// like needing to attach constraints to this object
|
||||
for ( int i = 0; i < m_BoneFollowerManager.GetNumBoneFollowers(); i++ )
|
||||
{
|
||||
CBaseEntity *pFollower = m_BoneFollowerManager.GetBoneFollower(i)->hFollower;
|
||||
if ( pFollower )
|
||||
{
|
||||
pFollower->AddSolidFlags(FSOLID_NOT_SOLID);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
// If our collision is through bone followers, we want to be non-solid
|
||||
AddSolidFlags( FSOLID_NOT_SOLID );
|
||||
// add these for the client, FSOLID_NOT_SOLID should keep it out of the testCollision code
|
||||
// except in the case of TraceEntity() which the client does for impact effects
|
||||
AddSolidFlags( FSOLID_CUSTOMRAYTEST | FSOLID_CUSTOMBOXTEST );
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
VPhysicsInitStatic();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CPropTestChamberDoor::CreateBoneFollowers( void )
|
||||
{
|
||||
// already created bone followers? Don't do so again.
|
||||
if ( m_BoneFollowerManager.GetNumBoneFollowers() )
|
||||
return;
|
||||
|
||||
KeyValues *modelKeyValues = new KeyValues("");
|
||||
if ( modelKeyValues->LoadFromBuffer( modelinfo->GetModelName( GetModel() ), modelinfo->GetModelKeyValueText( GetModel() ) ) )
|
||||
{
|
||||
// Do we have a bone follower section?
|
||||
KeyValues *pkvBoneFollowers = modelKeyValues->FindKey("bone_followers");
|
||||
if ( pkvBoneFollowers )
|
||||
{
|
||||
// Loop through the list and create the bone followers
|
||||
KeyValues *pBone = pkvBoneFollowers->GetFirstSubKey();
|
||||
while ( pBone )
|
||||
{
|
||||
// Add it to the list
|
||||
const char *pBoneName = pBone->GetString();
|
||||
m_BoneFollowerManager.AddBoneFollower( this, pBoneName );
|
||||
|
||||
pBone = pBone->GetNextKey();
|
||||
}
|
||||
}
|
||||
|
||||
modelKeyValues->deleteThis();
|
||||
}
|
||||
|
||||
// if we got here, we don't have a bone follower section, but if we have a ragdoll
|
||||
// go ahead and create default bone followers for it
|
||||
if ( m_BoneFollowerManager.GetNumBoneFollowers() == 0 )
|
||||
{
|
||||
vcollide_t *pCollide = modelinfo->GetVCollide( GetModelIndex() );
|
||||
if ( pCollide && pCollide->solidCount > 1 )
|
||||
{
|
||||
CreateBoneFollowersFromRagdoll( this, &m_BoneFollowerManager, pCollide );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CPropTestChamberDoor::TestCollision( const Ray_t &ray, unsigned int mask, trace_t& trace )
|
||||
{
|
||||
if ( IsSolidFlagSet(FSOLID_NOT_SOLID) )
|
||||
{
|
||||
// if this entity is marked non-solid and custom test it must have bone followers
|
||||
if ( IsSolidFlagSet( FSOLID_CUSTOMBOXTEST ) && IsSolidFlagSet( FSOLID_CUSTOMRAYTEST ))
|
||||
{
|
||||
for ( int i = 0; i < m_BoneFollowerManager.GetNumBoneFollowers(); i++ )
|
||||
{
|
||||
CBaseEntity *pEntity = m_BoneFollowerManager.GetBoneFollower(i)->hFollower;
|
||||
if ( pEntity && pEntity->TestCollision(ray, mask, trace) )
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// PORTAL2: This is a change from shipped code, but should be benign
|
||||
return BaseClass::TestCollision( ray, mask, trace );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Animate and catch edge cases for us stopping / starting our animation
|
||||
//-----------------------------------------------------------------------------
|
||||
void CPropTestChamberDoor::AnimateThink( void )
|
||||
{
|
||||
// Update our animation
|
||||
StudioFrameAdvance();
|
||||
DispatchAnimEvents( this );
|
||||
m_BoneFollowerManager.UpdateBoneFollowers( this );
|
||||
|
||||
if( m_bIsAnimating )
|
||||
{
|
||||
if ( IsSequenceFinished() )
|
||||
{
|
||||
if( m_bIsOpen )
|
||||
{
|
||||
OnFullyOpened();
|
||||
}
|
||||
else
|
||||
{
|
||||
OnFullyClosed();
|
||||
}
|
||||
|
||||
m_bIsAnimating = false;
|
||||
}
|
||||
}
|
||||
|
||||
SetThink( &CPropTestChamberDoor::AnimateThink );
|
||||
SetNextThink( gpGlobals->curtime + 0.1f );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: OnOpened output
|
||||
//-----------------------------------------------------------------------------
|
||||
void CPropTestChamberDoor::OnOpen( void )
|
||||
{
|
||||
// Fire the OnOpen output
|
||||
m_OnOpen.FireOutput( this, this );
|
||||
|
||||
// Play door open sound
|
||||
EmitSound( "prop_portal_door.open" );
|
||||
|
||||
AreaPortalOpen();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: OnClosed output
|
||||
//-----------------------------------------------------------------------------
|
||||
void CPropTestChamberDoor::OnClose( void )
|
||||
{
|
||||
// Fire the OnClose output
|
||||
m_OnClose.FireOutput( this, this );
|
||||
|
||||
// Play door close sound
|
||||
EmitSound( "prop_portal_door.close" );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: OnFullyOpened output
|
||||
//-----------------------------------------------------------------------------
|
||||
void CPropTestChamberDoor::OnFullyOpened( void )
|
||||
{
|
||||
m_OnFullyOpen.FireOutput( this, this );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Close the door
|
||||
//-----------------------------------------------------------------------------
|
||||
void CPropTestChamberDoor::OnFullyClosed( void )
|
||||
{
|
||||
m_OnFullyClosed.FireOutput( this, this );
|
||||
|
||||
AreaPortalClose();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Open the area portal window associated with this door
|
||||
//-----------------------------------------------------------------------------
|
||||
void CPropTestChamberDoor::AreaPortalOpen( void )
|
||||
{
|
||||
if( m_hAreaPortalWindow)
|
||||
{
|
||||
float flFadeStart = TESTCHAMBER_DOOR_AREA_PORTAL_NEVER_FADE_DISTANCE;
|
||||
float flFadeEnd = TESTCHAMBER_DOOR_AREA_PORTAL_NEVER_FADE_DISTANCE;
|
||||
|
||||
if( m_bUseAreaPortalFade )
|
||||
{
|
||||
flFadeStart = m_flAreaPortalFadeStartDistance;
|
||||
flFadeEnd = m_flAreaPortalFadeEndDistance;
|
||||
}
|
||||
|
||||
m_hAreaPortalWindow->m_flFadeStartDist = flFadeStart;
|
||||
m_hAreaPortalWindow->m_flFadeDist = flFadeEnd;
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Close the area portal window associated with this door
|
||||
//-----------------------------------------------------------------------------
|
||||
void CPropTestChamberDoor::AreaPortalClose( void )
|
||||
{
|
||||
if( m_hAreaPortalWindow)
|
||||
{
|
||||
m_hAreaPortalWindow->m_flFadeStartDist = 0;
|
||||
m_hAreaPortalWindow->m_flFadeDist = 0;
|
||||
}
|
||||
}
|
||||
93
game/server/portal2/prop_testchamber_door.h
Normal file
93
game/server/portal2/prop_testchamber_door.h
Normal file
@@ -0,0 +1,93 @@
|
||||
//===== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//===========================================================================//
|
||||
|
||||
#ifndef PROP_TESTCHAMBER_DOOR_H
|
||||
#define PROP_TESTCHAMBER_DOOR_H
|
||||
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include "func_areaportalwindow.h"
|
||||
#include "physics_bone_follower.h"
|
||||
|
||||
//=============================================================================
|
||||
// Non-animated linked portal door
|
||||
//=============================================================================
|
||||
|
||||
class CPropTestChamberDoor : public CBaseAnimating
|
||||
{
|
||||
public:
|
||||
DECLARE_CLASS( CPropTestChamberDoor, CBaseAnimating );
|
||||
DECLARE_DATADESC();
|
||||
|
||||
CPropTestChamberDoor( void );
|
||||
|
||||
virtual void Precache( void );
|
||||
virtual void Spawn( void );
|
||||
virtual void Activate( void );
|
||||
virtual bool CreateVPhysics( void );
|
||||
|
||||
virtual void UpdateOnRemove( void );
|
||||
|
||||
virtual void Open( CBaseEntity *pActivator );
|
||||
virtual void Close( CBaseEntity *pActivator );
|
||||
|
||||
virtual bool TestCollision( const Ray_t &ray, unsigned int mask, trace_t& trace );
|
||||
virtual void AnimateThink( void );
|
||||
|
||||
virtual bool IsOpen();
|
||||
virtual bool IsClosed();
|
||||
bool IsAnimating() const { return m_bIsAnimating; }
|
||||
|
||||
protected:
|
||||
|
||||
void Destroy( void );
|
||||
|
||||
void CreateBoneFollowers( void );
|
||||
|
||||
void OnFullyOpened( void );
|
||||
void OnFullyClosed( void );
|
||||
|
||||
virtual void OnOpen( void );
|
||||
virtual void OnClose( void );
|
||||
|
||||
void InputOpen( inputdata_t &input );
|
||||
void InputClose( inputdata_t &input );
|
||||
void InputLock( inputdata_t &input );
|
||||
void InputLockOpen( inputdata_t &input );
|
||||
void InputUnlock( inputdata_t &input );
|
||||
|
||||
COutputEvent m_OnOpen;
|
||||
COutputEvent m_OnClose;
|
||||
COutputEvent m_OnFullyOpen;
|
||||
COutputEvent m_OnFullyClosed;
|
||||
|
||||
int m_nSequenceOpen;
|
||||
int m_nSequenceOpenIdle;
|
||||
int m_nSequenceClose;
|
||||
int m_nSequenceCloseIdle;
|
||||
|
||||
bool m_bIsOpen;
|
||||
bool m_bIsAnimating;
|
||||
bool m_bIsLocked;
|
||||
|
||||
CBoneFollowerManager m_BoneFollowerManager;
|
||||
|
||||
//Area portal window
|
||||
void AreaPortalOpen( void );
|
||||
void AreaPortalClose( void );
|
||||
|
||||
string_t m_strAreaPortalWindowName;
|
||||
CHandle<CFuncAreaPortalWindow> m_hAreaPortalWindow;
|
||||
bool m_bUseAreaPortalFade;
|
||||
float m_flAreaPortalFadeStartDistance;
|
||||
float m_flAreaPortalFadeEndDistance;
|
||||
};
|
||||
|
||||
|
||||
#endif // PROP_TESTCHAMBER_DOOR_H
|
||||
1581
game/server/portal2/prop_weightedcube.cpp
Normal file
1581
game/server/portal2/prop_weightedcube.cpp
Normal file
File diff suppressed because it is too large
Load Diff
219
game/server/portal2/prop_weightedcube.h
Normal file
219
game/server/portal2/prop_weightedcube.h
Normal file
@@ -0,0 +1,219 @@
|
||||
//========= Copyright © 1996-2009, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: First-class cube entity so we can query by type and generally make inferences
|
||||
// that are harder to do without an entity of that type.
|
||||
//
|
||||
//=====================================================================================//
|
||||
|
||||
#include "cbase.h"
|
||||
#include "props.h"
|
||||
#include "ai_utils.h"
|
||||
#include "physics_saverestore.h"
|
||||
#include "phys_controller.h"
|
||||
#include "portal_base2d.h"
|
||||
#include "datacache/imdlcache.h"
|
||||
#include "func_portal_detector.h"
|
||||
|
||||
#include "player_pickup_paint_power_user.h"
|
||||
|
||||
DECLARE_AUTO_LIST( IPropWeightedCubeAutoList );
|
||||
|
||||
enum WeightedCubeType_e
|
||||
{
|
||||
CUBE_STANDARD,
|
||||
CUBE_COMPANION,
|
||||
CUBE_REFLECTIVE,
|
||||
CUBE_SPHERE,
|
||||
CUBE_ANTIQUE,
|
||||
CUBE_SCHRODINGER,
|
||||
};
|
||||
|
||||
//
|
||||
// Tip controller
|
||||
//
|
||||
|
||||
class CCubeRotationController : public CPointEntity, public IMotionEvent
|
||||
{
|
||||
DECLARE_CLASS( CCubeRotationController, CPointEntity );
|
||||
DECLARE_DATADESC();
|
||||
|
||||
public:
|
||||
|
||||
~CCubeRotationController( void );
|
||||
void Spawn( void );
|
||||
void Activate( void );
|
||||
void Enable( bool state = true );
|
||||
void Suspend( float time );
|
||||
float SuspendedTill( void );
|
||||
void SetAlignmentVector( const Vector &vecAlign );
|
||||
Vector GetAlignmentVector( void ) { return m_worldGoalAxis; }
|
||||
|
||||
void SuspendAfter( float flTime );
|
||||
|
||||
bool Enabled( void );
|
||||
|
||||
static CCubeRotationController *CreateRotationController( CBaseEntity *pOwner );
|
||||
|
||||
// IMotionEvent
|
||||
virtual simresult_e Simulate( IPhysicsMotionController *pController, IPhysicsObject *pObject, float deltaTime, Vector &linear, AngularImpulse &angular );
|
||||
|
||||
private:
|
||||
bool m_bEnabled;
|
||||
float m_flSuspendTime;
|
||||
Vector m_worldGoalAxis;
|
||||
Vector m_localTestAxis;
|
||||
IPhysicsMotionController *m_pController;
|
||||
float m_angularLimit;
|
||||
CBaseEntity *m_pParent;
|
||||
};
|
||||
|
||||
class CPropWeightedCube : public PlayerPickupPaintPowerUser< CPhysicsProp >, public IPropWeightedCubeAutoList
|
||||
{
|
||||
public:
|
||||
DECLARE_CLASS( CPropWeightedCube, PlayerPickupPaintPowerUser< CPhysicsProp > );
|
||||
DECLARE_SERVERCLASS();
|
||||
IMPLEMENT_AUTO_LIST_GET();
|
||||
|
||||
CPropWeightedCube();
|
||||
|
||||
virtual void Spawn( void );
|
||||
virtual void Activate( void );
|
||||
virtual void Precache( void );
|
||||
virtual int ObjectCaps( void );
|
||||
|
||||
virtual void OnFizzled( void )
|
||||
{
|
||||
// Handle the special Summer Sale achievement case
|
||||
// If a cube ever fizzles on the "red racer" map, the achievement is lost
|
||||
if ( V_stricmp( STRING(gpGlobals->mapname), "mp_coop_paint_red_racer" ) == 0 )
|
||||
{
|
||||
CBaseEntity *pEntity = gEntList.FindEntityByName( NULL, "@glados" );
|
||||
if ( pEntity )
|
||||
{
|
||||
pEntity->RunScript( "CoopCubeFizzle()", "OnFizzled" );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
m_OnFizzled.FireOutput( this, this );
|
||||
}
|
||||
|
||||
virtual bool HasPreferredCarryAnglesForPlayer( CBasePlayer *pPlayer );
|
||||
virtual QAngle PreferredCarryAngles( void );
|
||||
virtual void OnPhysGunPickup( CBasePlayer *pPhysGunUser, PhysGunPickup_t reason );
|
||||
virtual void OnPhysGunDrop( CBasePlayer *pPhysGunUser, PhysGunDrop_t reason );
|
||||
virtual void UpdateOnRemove( void );
|
||||
virtual void NotifySystemEvent(CBaseEntity *pNotify, notify_system_event_t eventType, const notify_system_event_params_t ¶ms );
|
||||
|
||||
virtual void StartTouch( CBaseEntity *pOther );
|
||||
virtual void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
|
||||
|
||||
void SetSkin( int skinNum );
|
||||
|
||||
void SetActivated( bool bActivate );
|
||||
|
||||
// instead of getting which model it uses, we can just ask this
|
||||
WeightedCubeType_e GetCubeType( void ) { return m_nCubeType; }
|
||||
|
||||
#ifndef CLIENT_DLL
|
||||
CPropWeightedCube* GetSchrodingerTwin( void );
|
||||
#endif
|
||||
|
||||
void SetLaser( CBaseEntity *pLaser );
|
||||
CBaseEntity* GetLaser()
|
||||
{
|
||||
return m_hLaser.Get();
|
||||
}
|
||||
bool HasLaser( void )
|
||||
{
|
||||
return m_hLaser.Get() != NULL;
|
||||
}
|
||||
|
||||
virtual int UpdateTransmitState();
|
||||
|
||||
virtual void Paint( PaintPowerType paintType, const Vector &worldContactPt );
|
||||
|
||||
void UpdateSchrodingerSound( void );
|
||||
|
||||
void SchrodingerThink( void );
|
||||
void DisabledThink( void );
|
||||
bool IsMovementDisabled() const { return m_bMovementDisabled; }
|
||||
bool ShouldEnterDisabledState( void );
|
||||
void EnterDisabledState( void );
|
||||
void ExitDisabledState( void );
|
||||
|
||||
void OnEnteredTractorBeam( void );
|
||||
void OnExitedTractorBeam( void );
|
||||
void TractorBeamThink( void );
|
||||
void ExitTractorBeamThink( void );
|
||||
|
||||
bool WasTouchedByPlayer() { return m_bTouchedByPlayer; }
|
||||
|
||||
#ifndef CLIENT_DLL
|
||||
#define CREATE_CUBE_AT_POSITION false
|
||||
static void CreatePortalWeightedCube( WeightedCubeType_e objectType, bool bAtCursorPosition = true, const Vector &position = vec3_origin );
|
||||
#endif
|
||||
|
||||
private:
|
||||
|
||||
void ConvertOldSkins( void );
|
||||
void SetCubeType( void );
|
||||
void SetPaintedMaterial( PaintPowerType paintType );
|
||||
void SetCubeSkin( void );
|
||||
|
||||
void InputDissolve( inputdata_t &in );
|
||||
void InputSilentDissolve( inputdata_t &in );
|
||||
void InputPreDissolveJoke( inputdata_t &in );
|
||||
QAngle CalculatePreferredAngles( CBasePlayer *pPlayer );
|
||||
void UpdatePreferredAngles( CBasePlayer *pPlayer );
|
||||
|
||||
COutputEvent m_OnFizzled;
|
||||
COutputEvent m_OnBluePickUp;
|
||||
COutputEvent m_OnOrangePickUp;
|
||||
COutputEvent m_OnPainted;
|
||||
QAngle m_vecCarryAngles;
|
||||
CHandle<CCubeRotationController> m_pController;
|
||||
EHANDLE m_hLaser;
|
||||
|
||||
int m_nBouncyMaterialIndex;
|
||||
|
||||
void InputDisablePortalFunnel( inputdata_t &in );
|
||||
void InputEnablePortalFunnel( inputdata_t &in );
|
||||
|
||||
void InputExitDisabledState( inputdata_t &in );
|
||||
|
||||
void InputSetPaint( inputdata_t &in );
|
||||
|
||||
void InputDisablePickup( inputdata_t &in );
|
||||
void InputEnablePickup( inputdata_t &in );
|
||||
|
||||
DECLARE_DATADESC();
|
||||
|
||||
CSoundPatch *m_pSchrodingerSound;
|
||||
|
||||
WeightedCubeType_e m_nCubeType;
|
||||
bool m_bRusted;
|
||||
bool m_bActivated;
|
||||
bool m_bNewSkins;
|
||||
|
||||
PaintPowerType m_nCurrentPaintedType;
|
||||
|
||||
float m_flDisabledNudgeStartTime;
|
||||
bool m_bMovementDisabled;
|
||||
bool m_bTouchedByPlayer;
|
||||
bool m_bPickupDisabled;
|
||||
|
||||
#ifndef CLIENT_DLL
|
||||
// Schrodinger's Balls
|
||||
CHandle< CPropWeightedCube > m_hSchrodingerTwin;
|
||||
static CHandle< CPropWeightedCube > m_hSchrodingerDangling;
|
||||
#endif
|
||||
};
|
||||
|
||||
bool UTIL_IsReflectiveCube( CBaseEntity *pEntity );
|
||||
bool UTIL_IsWeightedCube( CBaseEntity *pEntity );
|
||||
|
||||
#ifndef CLIENT_DLL
|
||||
bool UTIL_IsSchrodinger( CBaseEntity *pEntity );
|
||||
CPropWeightedCube* UTIL_GetSchrodingerTwin( CBaseEntity *pEntity );
|
||||
#endif
|
||||
Reference in New Issue
Block a user