Modified source engine (2017) developed by valve and leaked in 2020. Not for commercial purporses
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

497 lines
12 KiB

#include "cbase.h"
#include "asw_broadcast_camera.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
#define SF_CAMERA_PLAYER_POSITION 1 // NOTE: Starting at player position not supported
#define SF_CAMERA_PLAYER_TARGET 2 // NOTE: Following player not supported
#define SF_CAMERA_PLAYER_TAKECONTROL 4
#define SF_CAMERA_PLAYER_INFINITE_WAIT 8
#define SF_CAMERA_PLAYER_SNAP_TO 16
#define SF_CAMERA_PLAYER_NOT_SOLID 32 // NOTE: not supported (all players in asw are non-solid anyway)
#define SF_CAMERA_PLAYER_INTERRUPT 64 // NOTE: not supported
LINK_ENTITY_TO_CLASS( asw_broadcast_camera, CASW_Broadcast_Camera );
BEGIN_DATADESC( CASW_Broadcast_Camera )
//DEFINE_FIELD( m_hPlayer, FIELD_EHANDLE ),
DEFINE_FIELD( m_hTarget, FIELD_EHANDLE ),
DEFINE_FIELD( m_pPath, FIELD_CLASSPTR ),
DEFINE_FIELD( m_sPath, FIELD_STRING ),
DEFINE_FIELD( m_flWait, FIELD_FLOAT ),
DEFINE_FIELD( m_flReturnTime, FIELD_TIME ),
DEFINE_FIELD( m_flStopTime, FIELD_TIME ),
DEFINE_FIELD( m_moveDistance, FIELD_FLOAT ),
DEFINE_FIELD( m_targetSpeed, FIELD_FLOAT ),
DEFINE_FIELD( m_initialSpeed, FIELD_FLOAT ),
DEFINE_FIELD( m_acceleration, FIELD_FLOAT ),
DEFINE_FIELD( m_deceleration, FIELD_FLOAT ),
DEFINE_FIELD( m_state, FIELD_INTEGER ),
DEFINE_FIELD( m_vecMoveDir, FIELD_VECTOR ),
DEFINE_KEYFIELD( m_iszTargetAttachment, FIELD_STRING, "targetattachment" ),
DEFINE_FIELD( m_iAttachmentIndex, FIELD_INTEGER ),
DEFINE_FIELD( m_bSnapToGoal, FIELD_BOOLEAN ),
DEFINE_FIELD( m_vecLastPos, FIELD_VECTOR),
//DEFINE_FIELD( m_nPlayerButtons, FIELD_INTEGER ),
// Inputs
DEFINE_INPUTFUNC( FIELD_VOID, "Enable", InputEnable ),
DEFINE_INPUTFUNC( FIELD_VOID, "Disable", InputDisable ),
// Function Pointers
DEFINE_FUNCTION( FollowTarget ),
DEFINE_OUTPUT( m_OnEndFollow, "OnEndFollow" ),
END_DATADESC()
void CASW_Broadcast_Camera::Spawn( void )
{
BaseClass::Spawn();
SetMoveType( MOVETYPE_NOCLIP );
SetSolid( SOLID_NONE ); // Remove model & collisions
SetRenderAlpha( 0 ); // The engine won't draw this model if this is set to 0 and blending is on
m_nRenderMode = kRenderTransTexture;
m_state = USE_OFF;
m_initialSpeed = m_flSpeed;
if ( m_acceleration == 0 )
m_acceleration = 500;
if ( m_deceleration == 0 )
m_deceleration = 500;
DispatchUpdateTransmitState();
}
int CASW_Broadcast_Camera::UpdateTransmitState()
{
// always tranmit if currently used by a monitor
if ( m_state == USE_ON )
{
return SetTransmitState( FL_EDICT_ALWAYS );
}
else
{
return SetTransmitState( FL_EDICT_DONTSEND );
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
bool CASW_Broadcast_Camera::KeyValue( const char *szKeyName, const char *szValue )
{
if (FStrEq(szKeyName, "wait"))
{
m_flWait = atof(szValue);
}
else if (FStrEq(szKeyName, "moveto"))
{
m_sPath = AllocPooledString( szValue );
}
else if (FStrEq(szKeyName, "acceleration"))
{
m_acceleration = atof( szValue );
}
else if (FStrEq(szKeyName, "deceleration"))
{
m_deceleration = atof( szValue );
}
else
return BaseClass::KeyValue( szKeyName, szValue );
return true;
}
//------------------------------------------------------------------------------
// Purpose: Input handler to turn on this trigger.
//------------------------------------------------------------------------------
void CASW_Broadcast_Camera::InputEnable( inputdata_t &inputdata )
{
//m_hPlayer = inputdata.pActivator;
Enable();
}
//------------------------------------------------------------------------------
// Purpose: Input handler to turn off this trigger.
//------------------------------------------------------------------------------
void CASW_Broadcast_Camera::InputDisable( inputdata_t &inputdata )
{
Disable();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CASW_Broadcast_Camera::Enable( void )
{
m_state = USE_ON;
//if ( !m_hPlayer || !m_hPlayer->IsPlayer() )
//{
//m_hPlayer = UTIL_GetLocalPlayer();
//}
//if ( !m_hPlayer )
//{
//DispatchUpdateTransmitState();
//return;
//}
//if ( m_hPlayer->IsPlayer() )
//{
//m_nPlayerButtons = ((CBasePlayer*)m_hPlayer.Get())->m_nButtons;
//}
//if ( HasSpawnFlags( SF_CAMERA_PLAYER_NOT_SOLID ) )
//{
//m_hPlayer->AddSolidFlags( FSOLID_NOT_SOLID );
//}
m_flReturnTime = gpGlobals->curtime + m_flWait;
m_flSpeed = m_initialSpeed;
m_targetSpeed = m_initialSpeed;
if ( HasSpawnFlags( SF_CAMERA_PLAYER_SNAP_TO ) )
{
m_bSnapToGoal = true;
}
//if ( HasSpawnFlags(SF_CAMERA_PLAYER_TARGET ) )
//{
//m_hTarget = m_hPlayer;
//}
//else
//{
m_hTarget = GetNextTarget();
//}
// If we don't have a target, ignore the attachment / etc
if ( m_hTarget )
{
m_iAttachmentIndex = 0;
if ( m_iszTargetAttachment != NULL_STRING )
{
if ( !m_hTarget->GetBaseAnimating() )
{
Warning("%s tried to target an attachment (%s) on target %s, which has no model.\n", GetClassname(), STRING(m_iszTargetAttachment), STRING(m_hTarget->GetEntityName()) );
}
else
{
m_iAttachmentIndex = m_hTarget->GetBaseAnimating()->LookupAttachment( STRING(m_iszTargetAttachment) );
if ( !m_iAttachmentIndex )
{
Warning("%s could not find attachment %s on target %s.\n", GetClassname(), STRING(m_iszTargetAttachment), STRING(m_hTarget->GetEntityName()) );
}
}
}
}
//if (HasSpawnFlags(SF_CAMERA_PLAYER_TAKECONTROL ) )
//{
//((CBasePlayer*)m_hPlayer.Get())->EnableControl(FALSE);
//}
if ( m_sPath != NULL_STRING )
{
m_pPath = gEntList.FindEntityByName( NULL, m_sPath, NULL); //, m_hPlayer );
}
else
{
m_pPath = NULL;
}
m_flStopTime = gpGlobals->curtime;
if ( m_pPath )
{
if ( m_pPath->m_flSpeed != 0 )
m_targetSpeed = m_pPath->m_flSpeed;
m_flStopTime += m_pPath->GetDelay();
m_vecMoveDir = m_pPath->GetLocalOrigin() - GetLocalOrigin();
m_moveDistance = VectorNormalize( m_vecMoveDir );
m_flStopTime = gpGlobals->curtime + m_pPath->GetDelay();
}
else
{
m_moveDistance = 0;
}
/*
if ( m_pPath )
{
if ( m_pPath->m_flSpeed != 0 )
m_targetSpeed = m_pPath->m_flSpeed;
Msg("target speed is %f\n", m_targetSpeed);
m_flStopTime += m_pPath->GetDelay();
}
*/
// copy over player information
//if (HasSpawnFlags(SF_CAMERA_PLAYER_POSITION ) )
//{
//UTIL_SetOrigin( this, m_hPlayer->EyePosition() );
//SetLocalAngles( QAngle( m_hPlayer->GetLocalAngles().x, m_hPlayer->GetLocalAngles().y, 0 ) );
//SetAbsVelocity( m_hPlayer->GetAbsVelocity() );
//}
//else
//{
SetAbsVelocity( vec3_origin );
//}
UpdateAllPlayers();
//((CBasePlayer*)m_hPlayer.Get())->SetViewEntity( this );
// Hide the player's viewmodel
//if ( ((CBasePlayer*)m_hPlayer.Get())->GetActiveWeapon() )
//{
//((CBasePlayer*)m_hPlayer.Get())->GetActiveWeapon()->AddEffects( EF_NODRAW );
//}
// Only track if we have a target
if ( m_hTarget )
{
// follow the player down
SetThink( &CASW_Broadcast_Camera::FollowTarget );
SetNextThink( gpGlobals->curtime );
}
//m_moveDistance = 0;
m_vecLastPos = GetAbsOrigin();
Move();
DispatchUpdateTransmitState();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CASW_Broadcast_Camera::Disable( void )
{
RestoreAllPlayerViews();
//if ( m_hPlayer && m_hPlayer->IsAlive() )
//{
//if ( HasSpawnFlags( SF_CAMERA_PLAYER_NOT_SOLID ) )
//{
//m_hPlayer->RemoveSolidFlags( FSOLID_NOT_SOLID );
//}
//((CBasePlayer*)m_hPlayer.Get())->SetViewEntity( m_hPlayer );
//((CBasePlayer*)m_hPlayer.Get())->EnableControl(TRUE);
// Restore the player's viewmodel
//if ( ((CBasePlayer*)m_hPlayer.Get())->GetActiveWeapon() )
//{
//((CBasePlayer*)m_hPlayer.Get())->GetActiveWeapon()->RemoveEffects( EF_NODRAW );
//}
//}
m_state = USE_OFF;
m_flReturnTime = gpGlobals->curtime;
SetThink( NULL );
m_OnEndFollow.FireOutput(this, this); // dvsents2: what is the best name for this output?
SetLocalAngularVelocity( vec3_angle );
DispatchUpdateTransmitState();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CASW_Broadcast_Camera::FollowTarget( )
{
//if (m_hPlayer == NULL)
//return;
if ( m_hTarget == NULL )
{
Disable();
return;
}
if ( !HasSpawnFlags(SF_CAMERA_PLAYER_INFINITE_WAIT) && (!m_hTarget || m_flReturnTime < gpGlobals->curtime) )
{
Disable();
return;
}
UpdateAllPlayers();
QAngle vecGoal;
if ( m_iAttachmentIndex )
{
Vector vecOrigin;
m_hTarget->GetBaseAnimating()->GetAttachment( m_iAttachmentIndex, vecOrigin );
VectorAngles( vecOrigin - GetAbsOrigin(), vecGoal );
}
else
{
if ( m_hTarget )
{
VectorAngles( m_hTarget->GetAbsOrigin() - GetAbsOrigin(), vecGoal );
}
else
{
// Use the viewcontroller's angles
vecGoal = GetAbsAngles();
}
}
// Should we just snap to the goal angles?
if ( m_bSnapToGoal )
{
SetAbsAngles( vecGoal );
m_bSnapToGoal = false;
}
else
{
// UNDONE: Can't we just use UTIL_AngleDiff here?
QAngle angles = GetLocalAngles();
if (angles.y > 360)
angles.y -= 360;
if (angles.y < 0)
angles.y += 360;
SetLocalAngles( angles );
float dx = vecGoal.x - GetLocalAngles().x;
float dy = vecGoal.y - GetLocalAngles().y;
if (dx < -180)
dx += 360;
if (dx > 180)
dx = dx - 360;
if (dy < -180)
dy += 360;
if (dy > 180)
dy = dy - 360;
QAngle vecAngVel;
vecAngVel.Init( dx * 40 * gpGlobals->frametime, dy * 40 * gpGlobals->frametime, GetLocalAngularVelocity().z );
SetLocalAngularVelocity(vecAngVel);
}
if (!HasSpawnFlags(SF_CAMERA_PLAYER_TAKECONTROL))
{
SetAbsVelocity( GetAbsVelocity() * 0.8 );
if (GetAbsVelocity().Length( ) < 10.0)
{
SetAbsVelocity( vec3_origin );
}
}
SetNextThink( gpGlobals->curtime );
Move();
}
void CASW_Broadcast_Camera::Move()
{
/*
if ( HasSpawnFlags( SF_CAMERA_PLAYER_INTERRUPT ) )
{
if ( m_hPlayer )
{
CBasePlayer *pPlayer = ToBasePlayer( m_hPlayer );
if ( pPlayer )
{
int buttonsChanged = m_nPlayerButtons ^ pPlayer->m_nButtons;
if ( buttonsChanged && pPlayer->m_nButtons )
{
Disable();
return;
}
m_nPlayerButtons = pPlayer->m_nButtons;
}
}
}
*/
// Not moving on a path, return
if (!m_pPath)
return;
// Subtract movement from the previous frame
//m_moveDistance -= m_flSpeed * gpGlobals->frametime;
m_moveDistance -= VectorNormalize(GetAbsOrigin() - m_vecLastPos);
// Have we moved enough to reach the target?
if ( m_moveDistance <= 0 )
{
variant_t emptyVariant;
m_pPath->AcceptInput( "InPass", this, this, emptyVariant, 0 );
// Time to go to the next target
m_pPath = m_pPath->GetNextTarget();
// Set up next corner
if ( !m_pPath )
{
SetAbsVelocity( vec3_origin );
}
else
{
if ( m_pPath->m_flSpeed != 0 )
m_targetSpeed = m_pPath->m_flSpeed;
m_vecMoveDir = m_pPath->GetLocalOrigin() - GetLocalOrigin();
m_moveDistance = VectorNormalize( m_vecMoveDir );
m_flStopTime = gpGlobals->curtime + m_pPath->GetDelay();
}
}
if ( m_flStopTime > gpGlobals->curtime )
m_flSpeed = UTIL_Approach( 0, m_flSpeed, m_deceleration * gpGlobals->frametime );
else
m_flSpeed = UTIL_Approach( m_targetSpeed, m_flSpeed, m_acceleration * gpGlobals->frametime );
float fraction = 2 * gpGlobals->frametime;
SetAbsVelocity( ((m_vecMoveDir * m_flSpeed) * fraction) + (GetAbsVelocity() * (1-fraction)) );
m_vecLastPos = GetAbsOrigin();
}
// makes sure all players are viewing this and frozen if needed
void CASW_Broadcast_Camera::UpdateAllPlayers()
{
for ( int i = 1; i <= MAX_PLAYERS; i++ )
{
CBasePlayer *pPlayer = UTIL_PlayerByIndex( i );
if ( pPlayer )
{
if (HasSpawnFlags(SF_CAMERA_PLAYER_TAKECONTROL ) )
pPlayer->EnableControl(false);
pPlayer->SetViewEntity( this );
}
}
}
// puts player views back to normal
void CASW_Broadcast_Camera::RestoreAllPlayerViews()
{
for ( int i = 1; i <= MAX_PLAYERS; i++ )
{
CBasePlayer *pPlayer = UTIL_PlayerByIndex( i );
if ( pPlayer )
{
pPlayer->SetViewEntity( pPlayer );
pPlayer->EnableControl(true);
}
}
}