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.
330 lines
11 KiB
330 lines
11 KiB
//========= 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); |
|
}
|
|
|