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
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); |
|
} |
|
} |
|
} |