hl2_src-leak-2017/src/game/client/tf2/hud_damageindicator.cpp

323 lines
11 KiB
C++

//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Hud element that indicates the direction of damage taken by the player
//
//=============================================================================//
#include "cbase.h"
#include "hud.h"
#include "text_message.h"
#include "hud_macros.h"
#include "iclientmode.h"
#include "view.h"
#include <KeyValues.h>
#include <vgui_controls/AnimationController.h>
#include <vgui/ISurface.h>
#include "VGuiMatSurface/IMatSystemSurface.h"
#include "materialsystem/imaterial.h"
#include "materialsystem/imesh.h"
#include "materialsystem/imaterialvar.h"
#include "IEffects.h"
#include "hudelement.h"
using namespace vgui;
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
class CHudDamageIndicator : public CHudElement, public vgui::Panel
{
DECLARE_CLASS_SIMPLE( CHudDamageIndicator, vgui::Panel );
public:
CHudDamageIndicator( const char *pElementName );
void Init( void );
void VidInit( void );
void Reset( void );
virtual bool ShouldDraw( void );
// Handler for our message
void MsgFunc_Damage( bf_read &msg );
private:
virtual void OnThink();
virtual void Paint();
virtual void ApplySchemeSettings(vgui::IScheme *pScheme);
// Painting
void GetDamagePosition( const Vector &vecDelta, float flRadius, int *xpos, int *ypos, float *flRotation );
void DrawDamageIndicator(int x0, int y0, int x1, int y1, float alpha, float flRotation );
private:
// Indication times
CPanelAnimationVarAliasType( float, m_flMinimumWidth, "MinimumWidth", "10", "proportional_float" );
CPanelAnimationVarAliasType( float, m_flMaximumWidth, "MaximumWidth", "100", "proportional_float" );
CPanelAnimationVarAliasType( float, m_flMinimumHeight, "MinimumHeight", "20", "proportional_float" );
CPanelAnimationVarAliasType( float, m_flMaximumHeight, "MaximumHeight", "100", "proportional_float" );
CPanelAnimationVarAliasType( float, m_flStartRadius, "StartRadius", "140", "proportional_float" );
CPanelAnimationVarAliasType( float, m_flEndRadius, "EndRadius", "120", "proportional_float" );
CPanelAnimationVar( float, m_iMaximumDamage, "MaximumDamage", "50" );
CPanelAnimationVar( float, m_flMinimumTime, "MinimumTime", "1" );
CPanelAnimationVar( float, m_flMaximumTime, "MaximumTime", "6" );
CPanelAnimationVar( float, m_flTravelTime, "TravelTime", ".1" );
CPanelAnimationVar( float, m_flFadeOutPercentage, "FadeOutPercentage", "0.7" );
CPanelAnimationVar( float, m_flNoise, "Noise", "0.1" );
// List of damages we've taken
struct damage_t
{
int iScale;
float flLifeTime;
float flStartTime;
Vector vecDelta; // Damage origin relative to the player
};
CUtlVector<damage_t> m_vecDamages;
};
DECLARE_HUDELEMENT( CHudDamageIndicator );
DECLARE_HUD_MESSAGE( CHudDamageIndicator, Damage );
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
CHudDamageIndicator::CHudDamageIndicator( const char *pElementName ) :
CHudElement( pElementName ), BaseClass(NULL, "DamageIndicator")
{
vgui::Panel *pParent = g_pClientMode->GetViewport();
SetParent( pParent );
SetHiddenBits( HIDEHUD_HEALTH );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CHudDamageIndicator::Init( void )
{
HOOK_HUD_MESSAGE( CHudDamageIndicator, Damage );
Reset();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CHudDamageIndicator::Reset( void )
{
m_vecDamages.Purge();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CHudDamageIndicator::VidInit( void )
{
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CHudDamageIndicator::OnThink()
{
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
bool CHudDamageIndicator::ShouldDraw( void )
{
if ( !CHudElement::ShouldDraw() )
return false;
// Don't draw if we don't have any damage to indicate
if ( !m_vecDamages.Count() )
return false;
return true;
}
//-----------------------------------------------------------------------------
// Purpose: Convert a damage position in world units to the screen's units
//-----------------------------------------------------------------------------
void CHudDamageIndicator::GetDamagePosition( const Vector &vecDelta, float flRadius, int *xpos, int *ypos, float *flRotation )
{
// Player Data
Vector playerPosition = MainViewOrigin();
QAngle playerAngles = MainViewAngles();
Vector forward, right, up(0,0,1);
AngleVectors (playerAngles, &forward, NULL, NULL );
forward.z = 0;
VectorNormalize(forward);
CrossProduct( up, forward, right );
float front = DotProduct(vecDelta, forward);
float side = DotProduct(vecDelta, right);
*xpos = flRadius * -side;
*ypos = flRadius * -front;
// Get the rotation (yaw)
*flRotation = atan2(*xpos,*ypos) + M_PI;
*flRotation *= 180 / M_PI;
float yawRadians = -(*flRotation) * M_PI / 180.0f;
float ca = cos( yawRadians );
float sa = sin( yawRadians );
// Rotate it around the circle
*xpos = (int)((ScreenWidth() / 2) + (flRadius * sa));
*ypos = (int)((ScreenHeight() / 2) - (flRadius * ca));
}
//-----------------------------------------------------------------------------
// Purpose: Draw a single damage indicator
//-----------------------------------------------------------------------------
void CHudDamageIndicator::DrawDamageIndicator(int x0, int y0, int x1, int y1, float alpha, float flRotation )
{
IMaterial *pMat = materials->FindMaterial( "hud/health/indicator", TEXTURE_GROUP_VGUI );
CMatRenderContextPtr pRenderContext( materials );
IMesh *pMesh = pRenderContext->GetDynamicMesh( true, NULL, NULL, pMat );
// Get the corners, since they're being rotated
int wide = x1 - x0;
int tall = y1 - y0;
Vector2D vecCorners[4];
Vector2D center( x0 + (wide * 0.5f), y0 + (tall * 0.5f) );
float yawRadians = -flRotation * M_PI / 180.0f;
Vector2D axis[2];
axis[0].x = cos(yawRadians);
axis[0].y = sin(yawRadians);
axis[1].x = -axis[0].y;
axis[1].y = axis[0].x;
Vector2DMA( center, -0.5f * wide, axis[0], vecCorners[0] );
Vector2DMA( vecCorners[0], -0.5f * tall, axis[1], vecCorners[0] );
Vector2DMA( vecCorners[0], wide, axis[0], vecCorners[1] );
Vector2DMA( vecCorners[1], tall, axis[1], vecCorners[2] );
Vector2DMA( vecCorners[0], tall, axis[1], vecCorners[3] );
// Draw the sucker
CMeshBuilder meshBuilder;
meshBuilder.Begin( pMesh, MATERIAL_QUADS, 1 );
int iAlpha = alpha * 255;
meshBuilder.Color4ub( 255,255,255, iAlpha );
meshBuilder.TexCoord2f( 0,0,0 );
meshBuilder.Position3f( vecCorners[0].x,vecCorners[0].y,0 );
meshBuilder.AdvanceVertex();
meshBuilder.Color4ub( 255,255,255, iAlpha );
meshBuilder.TexCoord2f( 0,1,0 );
meshBuilder.Position3f( vecCorners[1].x,vecCorners[1].y,0 );
meshBuilder.AdvanceVertex();
meshBuilder.Color4ub( 255,255,255, iAlpha );
meshBuilder.TexCoord2f( 0,1,1 );
meshBuilder.Position3f( vecCorners[2].x,vecCorners[2].y,0 );
meshBuilder.AdvanceVertex();
meshBuilder.Color4ub( 255,255,255, iAlpha );
meshBuilder.TexCoord2f( 0,0,1 );
meshBuilder.Position3f( vecCorners[3].x,vecCorners[3].y,0 );
meshBuilder.AdvanceVertex();
meshBuilder.End();
pMesh->Draw();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CHudDamageIndicator::Paint()
{
// Iterate backwards, because we might remove them as we go
int iSize = m_vecDamages.Count();
for (int i = iSize-1; i >= 0; i--)
{
// Scale size to the damage
int clampedDamage = clamp( m_vecDamages[i].iScale, 0, m_iMaximumDamage );
int iWidth = RemapVal(clampedDamage, 0, m_iMaximumDamage, m_flMinimumWidth, m_flMaximumWidth) * 0.5;
int iHeight = RemapVal(clampedDamage, 0, m_iMaximumDamage, m_flMinimumHeight, m_flMaximumHeight) * 0.5;
// Find the place to draw it
int xpos, ypos;
float flRotation;
float flTimeSinceStart = ( gpGlobals->curtime - m_vecDamages[i].flStartTime );
float flRadius = RemapVal( MIN( flTimeSinceStart, m_flTravelTime ), 0, m_flTravelTime, m_flStartRadius, m_flEndRadius );
GetDamagePosition( m_vecDamages[i].vecDelta, flRadius, &xpos, &ypos, &flRotation );
// Calculate life left
float flLifeLeft = ( m_vecDamages[i].flLifeTime - gpGlobals->curtime );
if ( flLifeLeft > 0 )
{
float flPercent = flTimeSinceStart / (m_vecDamages[i].flLifeTime - m_vecDamages[i].flStartTime);
float alpha;
if ( flPercent <= m_flFadeOutPercentage )
{
alpha = 1.0;
}
else
{
alpha = 1.0 - RemapVal( flPercent, m_flFadeOutPercentage, 1.0, 0.0, 1.0 );
}
DrawDamageIndicator( xpos-iWidth, ypos-iHeight, xpos+iWidth, ypos+iHeight, alpha, flRotation );
}
else
{
m_vecDamages.Remove(i);
}
}
}
//-----------------------------------------------------------------------------
// Purpose: Message handler for Damage message
//-----------------------------------------------------------------------------
void CHudDamageIndicator::MsgFunc_Damage( bf_read &msg )
{
damage_t damage;
damage.iScale = msg.ReadByte();
if ( damage.iScale > m_iMaximumDamage )
{
damage.iScale = m_iMaximumDamage;
}
Vector vecOrigin;
vecOrigin.x = msg.ReadFloat();
vecOrigin.y = msg.ReadFloat();
vecOrigin.z = msg.ReadFloat();
damage.flStartTime = gpGlobals->curtime;
damage.flLifeTime = gpGlobals->curtime + RemapVal(damage.iScale, 0, m_iMaximumDamage, m_flMinimumTime, m_flMaximumTime);
if ( vecOrigin == vec3_origin )
{
vecOrigin = MainViewOrigin();
}
damage.vecDelta = (vecOrigin - MainViewOrigin());
VectorNormalize( damage.vecDelta );
// Add some noise
damage.vecDelta[0] += random->RandomFloat( -m_flNoise, m_flNoise );
damage.vecDelta[1] += random->RandomFloat( -m_flNoise, m_flNoise );
damage.vecDelta[2] += random->RandomFloat( -m_flNoise, m_flNoise );
VectorNormalize( damage.vecDelta );
m_vecDamages.AddToTail( damage );
}
//-----------------------------------------------------------------------------
// Purpose: hud scheme settings
//-----------------------------------------------------------------------------
void CHudDamageIndicator::ApplySchemeSettings(vgui::IScheme *pScheme)
{
BaseClass::ApplySchemeSettings(pScheme);
SetPaintBackgroundEnabled(false);
// set our size
int screenWide, screenTall;
int x, y;
GetPos(x, y);
GetHudSize(screenWide, screenTall);
SetBounds(0, y, screenWide, screenTall - y);
}