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.
331 lines
11 KiB
331 lines
11 KiB
![]()
4 years ago
|
//========= 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"
|
||
|
#include "clienteffectprecachesystem.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, float *xpos, float *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", "100" );
|
||
|
CPanelAnimationVar( float, m_flMinimumTime, "MinimumTime", "1" );
|
||
|
CPanelAnimationVar( float, m_flMaximumTime, "MaximumTime", "2" );
|
||
|
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;
|
||
|
|
||
|
CMaterialReference m_WhiteAdditiveMaterial;
|
||
|
};
|
||
|
|
||
|
DECLARE_HUDELEMENT( CHudDamageIndicator );
|
||
|
DECLARE_HUD_MESSAGE( CHudDamageIndicator, Damage );
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// Purpose:
|
||
|
//-----------------------------------------------------------------------------
|
||
|
CHudDamageIndicator::CHudDamageIndicator( const char *pElementName ) :
|
||
|
CHudElement( pElementName ), BaseClass(NULL, "HudDamageIndicator")
|
||
|
{
|
||
|
vgui::Panel *pParent = g_pClientMode->GetViewport();
|
||
|
SetParent( pParent );
|
||
|
|
||
|
SetHiddenBits( HIDEHUD_HEALTH );
|
||
|
|
||
|
m_WhiteAdditiveMaterial.Init( "VGUI/damageindicator", TEXTURE_GROUP_VGUI );
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// 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, float *xpos, float *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 )
|
||
|
{
|
||
|
CMatRenderContextPtr pRenderContext( materials );
|
||
|
IMesh *pMesh = pRenderContext->GetDynamicMesh( true, NULL, NULL, m_WhiteAdditiveMaterial );
|
||
|
|
||
|
// 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
|
||
|
float clampedDamage = clamp( (float) m_vecDamages[i].iScale, 0.f, 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
|
||
|
float 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.ReadShort();
|
||
|
msg.ReadLong(); // Read & ignored
|
||
|
if ( !msg.ReadOneBit() )
|
||
|
return;
|
||
|
|
||
|
if ( damage.iScale > m_iMaximumDamage )
|
||
|
{
|
||
|
damage.iScale = m_iMaximumDamage;
|
||
|
}
|
||
|
Vector vecOrigin;
|
||
|
msg.ReadBitVec3Coord( vecOrigin );
|
||
|
|
||
|
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);
|
||
|
}
|