333 lines
9.1 KiB
C++
333 lines
9.1 KiB
C++
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
|
|
//
|
|
// Purpose: Displays HUD elements to indicate damage taken
|
|
//
|
|
//=====================================================================================//
|
|
|
|
#include "cbase.h"
|
|
#include "hud.h"
|
|
#include "hudelement.h"
|
|
#include "hud_element_helper.h"
|
|
#include "scaleformui/scaleformui.h"
|
|
#include "sfhuddamageindicator.h"
|
|
#include "vgui/ILocalize.h"
|
|
#include "text_message.h"
|
|
#include "hud_macros.h"
|
|
#include "view.h"
|
|
#include "sfhudfreezepanel.h"
|
|
#include "sfhudreticle.h"
|
|
#include "hltvcamera.h"
|
|
#include "inputsystem/iinputsystem.h"
|
|
|
|
// memdbgon must be the last include file in a .cpp file!!!
|
|
#include "tier0/memdbgon.h"
|
|
|
|
DECLARE_HUDELEMENT( SFHudDamageIndicator );
|
|
DECLARE_HUD_MESSAGE( SFHudDamageIndicator, Damage );
|
|
|
|
SFUI_BEGIN_GAME_API_DEF
|
|
SFUI_END_GAME_API_DEF( SFHudDamageIndicator, DamageIndicatorModule );
|
|
|
|
extern ConVar cl_draw_only_deathnotices;
|
|
|
|
// [jason] Globals, extracted from the vgui version of the damage indicators. Comments are my own:
|
|
|
|
static float g_FadeScale = 2.f; // scale applied to delta-seconds to control the fade of the direction dmg indicators
|
|
static float g_StartFadeThreshold = 0.4f; // scale at which the directional dmg indicator begins to auto-fade out (controlled entirely in Flash); used to be the point where it became invisible in VGui
|
|
static float g_DetectDamageTakenInterval = 1.0f; // (in seconds) - if you haven't received new damage at least this recently, all direction indicators fade out at this point
|
|
static float g_CloseDamageDistance = 50.f; // (in world units) - if damage received is closer than this to player, all directions light up
|
|
static float g_DirectionDotTolerance = 0.3f; // incoming dmg direction dot product must be > this value in order for damage to be "from" this direction
|
|
|
|
|
|
SFHudDamageIndicator::SFHudDamageIndicator( const char *value ) : SFHudFlashInterface( value ),
|
|
m_flAttackFront(0.f),
|
|
m_flAttackRear(0.f),
|
|
m_flAttackLeft(0.f),
|
|
m_flAttackRight(0.f),
|
|
m_flFadeCompleteTime(0.f),
|
|
m_lastFrameTime(0.f)
|
|
{
|
|
SetHiddenBits( HIDEHUD_HEALTH );
|
|
HOOK_HUD_MESSAGE( SFHudDamageIndicator, Damage );
|
|
}
|
|
|
|
SFHudDamageIndicator::~SFHudDamageIndicator()
|
|
{
|
|
}
|
|
|
|
void SFHudDamageIndicator::IndicateDamage( DamageDirection dmgDir, float newPercentage )
|
|
{
|
|
if ( m_bActive && m_FlashAPI )
|
|
{
|
|
WITH_SFVALUEARRAY_SLOT_LOCKED( data, 2 )
|
|
{
|
|
m_pScaleformUI->ValueArray_SetElement( data, 0, dmgDir );
|
|
m_pScaleformUI->ValueArray_SetElement( data, 1, newPercentage );
|
|
m_pScaleformUI->Value_InvokeWithoutReturn( m_FlashAPI, "showDamageDirection", data, 2 );
|
|
}
|
|
}
|
|
}
|
|
|
|
void SFHudDamageIndicator::HideAll( void )
|
|
{
|
|
if ( m_FlashAPI )
|
|
{
|
|
WITH_SLOT_LOCKED
|
|
{
|
|
m_pScaleformUI->Value_InvokeWithoutReturn( m_FlashAPI, "hideAll", NULL, 0 );
|
|
}
|
|
}
|
|
}
|
|
|
|
#define UPDATE_DIR_DAMAGE( dirValue, dirEnum ) \
|
|
if ( dirValue > 0.f ) \
|
|
{ \
|
|
dirValue = MAX( 0.f, dirValue - flFade ); \
|
|
if ( dirValue > g_StartFadeThreshold ) \
|
|
{ \
|
|
IndicateDamage( dirEnum, dirValue ); \
|
|
} \
|
|
else \
|
|
{ /* start auto-fade at this level */ \
|
|
dirValue = 0.f; \
|
|
IndicateDamage( dirEnum, -1.f ); \
|
|
} \
|
|
}
|
|
|
|
void SFHudDamageIndicator::ProcessInput( void )
|
|
{
|
|
if ( m_flFadeCompleteTime > gpGlobals->curtime )
|
|
{
|
|
// We have recent damage information, propagate it to all damage directions:
|
|
float flFade = ( gpGlobals->curtime - m_lastFrameTime ) * g_FadeScale;
|
|
|
|
UPDATE_DIR_DAMAGE( m_flAttackFront, SFDD_DamageUp );
|
|
UPDATE_DIR_DAMAGE( m_flAttackRear, SFDD_DamageDown );
|
|
UPDATE_DIR_DAMAGE( m_flAttackLeft, SFDD_DamageLeft );
|
|
UPDATE_DIR_DAMAGE( m_flAttackRight, SFDD_DamageRight );
|
|
}
|
|
else
|
|
{
|
|
// We haven't received recent damage info, so begin to fade out all dmg directions
|
|
if ( m_flAttackFront > 0.f ||
|
|
m_flAttackRear > 0.f ||
|
|
m_flAttackLeft > 0.f ||
|
|
m_flAttackRight > 0.f )
|
|
{
|
|
m_flAttackFront = 0.0f;
|
|
m_flAttackRear = 0.0f;
|
|
m_flAttackRight = 0.0f;
|
|
m_flAttackLeft = 0.0f;
|
|
|
|
// -1 causes all damage directions to fade down to zero from their current levels
|
|
IndicateDamage( SFDD_DamageTotal, -1.f );
|
|
}
|
|
}
|
|
|
|
m_lastFrameTime = gpGlobals->curtime;
|
|
}
|
|
|
|
void SFHudDamageIndicator::FlashReady( void )
|
|
{
|
|
// hide everything initially
|
|
HideAll();
|
|
}
|
|
|
|
bool SFHudDamageIndicator::PreUnloadFlash( void )
|
|
{
|
|
// $TODO: Anything to release?
|
|
|
|
return true;
|
|
}
|
|
|
|
void SFHudDamageIndicator::LevelInit( void )
|
|
{
|
|
if ( !FlashAPIIsValid() )
|
|
{
|
|
SFUI_REQUEST_ELEMENT( SF_SS_SLOT( GET_ACTIVE_SPLITSCREEN_SLOT() ), g_pScaleformUI, SFHudDamageIndicator, this, DamageIndicatorModule );
|
|
}
|
|
else
|
|
{
|
|
// When initially loaded, hide all indicators
|
|
HideAll();
|
|
}
|
|
}
|
|
|
|
void SFHudDamageIndicator::LevelShutdown( void )
|
|
{
|
|
if ( FlashAPIIsValid() )
|
|
{
|
|
RemoveFlashElement();
|
|
}
|
|
}
|
|
|
|
void SFHudDamageIndicator::Reset( void )
|
|
{
|
|
m_flAttackFront = 0.0f;
|
|
m_flAttackRear = 0.0f;
|
|
m_flAttackRight = 0.0f;
|
|
m_flAttackLeft = 0.0f;
|
|
m_flFadeCompleteTime = 0.0f;
|
|
|
|
HideAll();
|
|
}
|
|
|
|
bool SFHudDamageIndicator::ShouldDraw( void )
|
|
{
|
|
if ( IsTakingAFreezecamScreenshot() )
|
|
return false;
|
|
|
|
return cl_drawhud.GetBool() && cl_draw_only_deathnotices.GetBool() == false && CHudElement::ShouldDraw();
|
|
}
|
|
|
|
|
|
void SFHudDamageIndicator::SetActive( bool bActive )
|
|
{
|
|
if ( m_bActive && !bActive )
|
|
{
|
|
HideAll();
|
|
}
|
|
|
|
CHudElement::SetActive( bActive );
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: Message handler for Damage message
|
|
//-----------------------------------------------------------------------------
|
|
bool SFHudDamageIndicator::MsgFunc_Damage( const CCSUsrMsg_Damage &msg )
|
|
{
|
|
|
|
C_BasePlayer *pVictimPlayer = NULL;
|
|
if ( g_bEngineIsHLTV )
|
|
{
|
|
// Only show damage indicator for the player we are currently observing.
|
|
if ( HLTVCamera()->GetMode() != OBS_MODE_IN_EYE )
|
|
return true;
|
|
|
|
C_BaseEntity* pTarget = HLTVCamera()->GetPrimaryTarget();
|
|
if ( !pTarget || !pTarget->IsPlayer() || pTarget->entindex() != msg.victim_entindex() )
|
|
return true;
|
|
|
|
// This cast is safe because pTarget->IsPlayer() returned true above
|
|
pVictimPlayer = static_cast< C_BasePlayer* >( pTarget );
|
|
}
|
|
else
|
|
{
|
|
Assert( C_BasePlayer::GetLocalPlayer()->entindex() == msg.victim_entindex() );
|
|
pVictimPlayer = C_BasePlayer::GetLocalPlayer();
|
|
}
|
|
|
|
|
|
int damageTaken = msg.amount();
|
|
|
|
if ( damageTaken > 0 )
|
|
{
|
|
Vector vecFrom;
|
|
vecFrom.x = msg.inflictor_world_pos().x();
|
|
vecFrom.y = msg.inflictor_world_pos().y();
|
|
vecFrom.z = msg.inflictor_world_pos().z();
|
|
|
|
m_flFadeCompleteTime = gpGlobals->curtime + g_DetectDamageTakenInterval;
|
|
CalcDamageDirection( vecFrom, pVictimPlayer );
|
|
|
|
// If we are using a Steam Controller, do haptics on the Steam Controller
|
|
// to indicate getting hit.
|
|
if ( g_pInputSystem->IsSteamControllerActive() && steamapicontext->SteamController() )
|
|
{
|
|
static ConVarRef steam_controller_haptics( "steam_controller_haptics" );
|
|
if ( steam_controller_haptics.GetBool() )
|
|
{
|
|
ControllerHandle_t handles[MAX_STEAM_CONTROLLERS];
|
|
int nControllers = steamapicontext->SteamController()->GetConnectedControllers( handles );
|
|
|
|
for ( int i = 0; i < nControllers; ++i )
|
|
{
|
|
float flLeft = m_flAttackLeft + m_flAttackFront*0.5 + m_flAttackRear*0.5;
|
|
float flRight = m_flAttackRight + m_flAttackFront*0.5 + m_flAttackRear*0.5;
|
|
float flTotal = flLeft + flRight;
|
|
if ( flTotal > 0.0 )
|
|
{
|
|
flLeft /= flTotal;
|
|
flRight /= flTotal;
|
|
if ( flRight > 0 )
|
|
{
|
|
steamapicontext->SteamController()->TriggerHapticPulse( handles[ i ], k_ESteamControllerPad_Right, 2000*flRight );
|
|
}
|
|
|
|
if ( flLeft > 0 )
|
|
{
|
|
steamapicontext->SteamController()->TriggerHapticPulse( handles[ i ], k_ESteamControllerPad_Left, 2000*flLeft );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
// [jason] This code is duplicated from cs_hud_damageindicator.cpp:
|
|
void SFHudDamageIndicator::CalcDamageDirection( const Vector &vecFrom, C_BasePlayer *pVictimPlayer )
|
|
{
|
|
// I assume this is done to detect damage from world (falling) and not display
|
|
// an indicator for this. Old code was zeroing all indicator values here which caused
|
|
// a bug if we were currently in mid-fade for a previous damage source.
|
|
if ( vecFrom == vec3_origin )
|
|
{
|
|
return;
|
|
}
|
|
|
|
if ( !pVictimPlayer )
|
|
{
|
|
return;
|
|
}
|
|
|
|
Vector vecDelta = ( vecFrom - pVictimPlayer->GetRenderOrigin() );
|
|
|
|
if ( vecDelta.Length() <= g_CloseDamageDistance )
|
|
{
|
|
m_flAttackFront = 1.0f;
|
|
m_flAttackRear = 1.0f;
|
|
m_flAttackRight = 1.0f;
|
|
m_flAttackLeft = 1.0f;
|
|
|
|
return;
|
|
}
|
|
|
|
VectorNormalize( vecDelta );
|
|
|
|
Vector forward;
|
|
Vector right;
|
|
AngleVectors( MainViewAngles( GET_ACTIVE_SPLITSCREEN_SLOT() ), &forward, &right, NULL );
|
|
|
|
float flFront = DotProduct( vecDelta, forward );
|
|
float flSide = DotProduct( vecDelta, right );
|
|
|
|
if ( flFront > 0 )
|
|
{
|
|
if ( flFront > g_DirectionDotTolerance )
|
|
m_flAttackFront = MAX( m_flAttackFront, flFront );
|
|
}
|
|
else
|
|
{
|
|
float f = fabs( flFront );
|
|
if ( f > g_DirectionDotTolerance )
|
|
m_flAttackRear = MAX( m_flAttackRear, f );
|
|
}
|
|
|
|
if ( flSide > 0 )
|
|
{
|
|
if ( flSide > g_DirectionDotTolerance )
|
|
m_flAttackRight = MAX( m_flAttackRight, flSide );
|
|
}
|
|
else
|
|
{
|
|
float f = fabs( flSide );
|
|
if ( f > g_DirectionDotTolerance )
|
|
m_flAttackLeft = MAX( m_flAttackLeft, f );
|
|
}
|
|
}
|