diff options
Diffstat (limited to 'game/client/hl2/hud_damageindicator.cpp')
| -rw-r--r-- | game/client/hl2/hud_damageindicator.cpp | 461 |
1 files changed, 461 insertions, 0 deletions
diff --git a/game/client/hl2/hud_damageindicator.cpp b/game/client/hl2/hud_damageindicator.cpp new file mode 100644 index 0000000..b6d2a9b --- /dev/null +++ b/game/client/hl2/hud_damageindicator.cpp @@ -0,0 +1,461 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#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" +#include "sourcevr/isourcevirtualreality.h" + +using namespace vgui; + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + + +//----------------------------------------------------------------------------- +// Purpose: HDU Damage indication +//----------------------------------------------------------------------------- +class CHudDamageIndicator : public CHudElement, public vgui::Panel +{ + DECLARE_CLASS_SIMPLE( CHudDamageIndicator, vgui::Panel ); + +public: + CHudDamageIndicator( const char *pElementName ); + void Init( void ); + void Reset( void ); + virtual bool ShouldDraw( void ); + + // Handler for our message + void MsgFunc_Damage( bf_read &msg ); + +private: + virtual void Paint(); + virtual void ApplySchemeSettings(vgui::IScheme *pScheme); + +private: + CPanelAnimationVarAliasType( float, m_flDmgX, "dmg_xpos", "10", "proportional_float" ); + CPanelAnimationVarAliasType( float, m_flDmgY, "dmg_ypos", "80", "proportional_float" ); + CPanelAnimationVarAliasType( float, m_flDmgWide, "dmg_wide", "30", "proportional_float" ); + CPanelAnimationVarAliasType( float, m_flDmgTall1, "dmg_tall1", "300", "proportional_float" ); + CPanelAnimationVarAliasType( float, m_flDmgTall2, "dmg_tall2", "240", "proportional_float" ); + + CPanelAnimationVar( Color, m_DmgColorLeft, "DmgColorLeft", "255 0 0 0" ); + CPanelAnimationVar( Color, m_DmgColorRight, "DmgColorRight", "255 0 0 0" ); + + CPanelAnimationVar( Color, m_DmgHighColorLeft, "DmgHighColorLeft", "255 0 0 0" ); + CPanelAnimationVar( Color, m_DmgHighColorRight, "DmgHighColorRight", "255 0 0 0" ); + + CPanelAnimationVar( Color, m_DmgFullscreenColor, "DmgFullscreenColor", "255 0 0 0" ); + + void DrawDamageIndicator(int side); + void DrawFullscreenDamageIndicator(); + void GetDamagePosition( const Vector &vecDelta, float *flRotation ); + + CMaterialReference m_WhiteAdditiveMaterial; +}; + +DECLARE_HUDELEMENT( CHudDamageIndicator ); +DECLARE_HUD_MESSAGE( CHudDamageIndicator, Damage ); + +enum +{ + DAMAGE_ANY, + DAMAGE_LOW, + DAMAGE_HIGH, +}; + +#define ANGLE_ANY 0.0f +#define DMG_ANY 0 + +struct DamageAnimation_t +{ + const char *name; + int bitsDamage; + float angleMinimum; + float angleMaximum; + int damage; +}; + +//----------------------------------------------------------------------------- +// Purpose: List of damage animations, finds first that matches criteria +//----------------------------------------------------------------------------- +static DamageAnimation_t g_DamageAnimations[] = +{ + { "HudTakeDamageDrown", DMG_DROWN, ANGLE_ANY, ANGLE_ANY, DAMAGE_ANY }, + { "HudTakeDamagePoison", DMG_POISON, ANGLE_ANY, ANGLE_ANY, DAMAGE_ANY }, + { "HudTakeDamageBurn", DMG_BURN, ANGLE_ANY, ANGLE_ANY, DAMAGE_ANY }, + { "HudTakeDamageRadiation", DMG_RADIATION, ANGLE_ANY, ANGLE_ANY, DAMAGE_ANY }, + { "HudTakeDamageRadiation", DMG_ACID, ANGLE_ANY, ANGLE_ANY, DAMAGE_ANY }, + + { "HudTakeDamageHighLeft", DMG_ANY, 45.0f, 135.0f, DAMAGE_HIGH }, + { "HudTakeDamageHighRight", DMG_ANY, 225.0f, 315.0f, DAMAGE_HIGH }, + { "HudTakeDamageHigh", DMG_ANY, ANGLE_ANY, ANGLE_ANY, DAMAGE_HIGH }, + + { "HudTakeDamageLeft", DMG_ANY, 45.0f, 135.0f, DAMAGE_ANY }, + { "HudTakeDamageRight", DMG_ANY, 225.0f, 315.0f, DAMAGE_ANY }, + { "HudTakeDamageBehind", DMG_ANY, 135.0f, 225.0f, DAMAGE_ANY }, + + // fall through to front damage + { "HudTakeDamageFront", DMG_ANY, ANGLE_ANY, ANGLE_ANY, DAMAGE_ANY }, + { NULL }, +}; + + +//----------------------------------------------------------------------------- +// Purpose: Constructor +//----------------------------------------------------------------------------- +CHudDamageIndicator::CHudDamageIndicator( const char *pElementName ) : CHudElement( pElementName ), BaseClass(NULL, "HudDamageIndicator") +{ + vgui::Panel *pParent = g_pClientMode->GetViewport(); + SetParent( pParent ); + + m_WhiteAdditiveMaterial.Init( "vgui/white_additive", TEXTURE_GROUP_VGUI ); + + SetHiddenBits( HIDEHUD_HEALTH ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CHudDamageIndicator::Reset( void ) +{ + m_DmgColorLeft[3] = 0; + m_DmgColorRight[3] = 0; + m_DmgHighColorLeft[3] = 0; + m_DmgHighColorRight[3] = 0; + m_DmgFullscreenColor[3] = 0; +} + +void CHudDamageIndicator::Init( void ) +{ + HOOK_HUD_MESSAGE( CHudDamageIndicator, Damage ); +} + +//----------------------------------------------------------------------------- +// Purpose: Save CPU cycles by letting the HUD system early cull +// costly traversal. Called per frame, return true if thinking and +// painting need to occur. +//----------------------------------------------------------------------------- +bool CHudDamageIndicator::ShouldDraw( void ) +{ + bool bNeedsDraw = m_DmgColorLeft[3] || + m_DmgColorRight[3] || + m_DmgHighColorLeft[3] || + m_DmgHighColorRight[3] || + m_DmgFullscreenColor[3]; + + return ( bNeedsDraw && CHudElement::ShouldDraw() ); +} + +//----------------------------------------------------------------------------- +// Purpose: Draws a damage quad +//----------------------------------------------------------------------------- +void CHudDamageIndicator::DrawDamageIndicator(int side) +{ + CMatRenderContextPtr pRenderContext( materials ); + IMesh *pMesh = pRenderContext->GetDynamicMesh( true, NULL, NULL, m_WhiteAdditiveMaterial ); + + CMeshBuilder meshBuilder; + meshBuilder.Begin( pMesh, MATERIAL_QUADS, 1 ); + + int insetY = (m_flDmgTall1 - m_flDmgTall2) / 2; + + int x1 = m_flDmgX; + int x2 = m_flDmgX + m_flDmgWide; + int y[4] = { (int)m_flDmgY, (int)(m_flDmgY + insetY), (int)(m_flDmgY + m_flDmgTall1 - insetY), (int)(m_flDmgY + m_flDmgTall1) }; + int alpha[4] = { 0, 1, 1, 0 }; + + // see if we're high damage + bool bHighDamage = false; + if ( m_DmgHighColorRight[3] > m_DmgColorRight[3] || m_DmgHighColorLeft[3] > m_DmgColorLeft[3] ) + { + // make more of the screen be covered by damage + x1 = GetWide() * 0.0f; + x2 = GetWide() * 0.5f; + y[0] = 0.0f; + y[1] = 0.0f; + y[2] = GetTall(); + y[3] = GetTall(); + alpha[0] = 1.0f; + alpha[1] = 0.0f; + alpha[2] = 0.0f; + alpha[3] = 1.0f; + bHighDamage = true; + } + + int r, g, b, a; + if (side == 1) + { + if ( bHighDamage ) + { + r = m_DmgHighColorRight[0], g = m_DmgHighColorRight[1], b = m_DmgHighColorRight[2], a = m_DmgHighColorRight[3]; + } + else + { + r = m_DmgColorRight[0], g = m_DmgColorRight[1], b = m_DmgColorRight[2], a = m_DmgColorRight[3]; + } + + // realign x coords + x1 = GetWide() - x1; + x2 = GetWide() - x2; + + meshBuilder.Color4ub( r, g, b, a * alpha[0]); + meshBuilder.TexCoord2f( 0,0,0 ); + meshBuilder.Position3f( x1, y[0], 0 ); + meshBuilder.AdvanceVertex(); + + meshBuilder.Color4ub( r, g, b, a * alpha[3] ); + meshBuilder.TexCoord2f( 0,0,1 ); + meshBuilder.Position3f( x1, y[3], 0 ); + meshBuilder.AdvanceVertex(); + + meshBuilder.Color4ub( r, g, b, a * alpha[2] ); + meshBuilder.TexCoord2f( 0,1,1 ); + meshBuilder.Position3f( x2, y[2], 0 ); + meshBuilder.AdvanceVertex(); + + meshBuilder.Color4ub( r, g, b, a * alpha[1] ); + meshBuilder.TexCoord2f( 0,1,0 ); + meshBuilder.Position3f( x2, y[1], 0 ); + meshBuilder.AdvanceVertex(); + } + else + { + if ( bHighDamage ) + { + r = m_DmgHighColorLeft[0], g = m_DmgHighColorLeft[1], b = m_DmgHighColorLeft[2], a = m_DmgHighColorLeft[3]; + } + else + { + r = m_DmgColorLeft[0], g = m_DmgColorLeft[1], b = m_DmgColorLeft[2], a = m_DmgColorLeft[3]; + } + + meshBuilder.Color4ub( r, g, b, a * alpha[0] ); + meshBuilder.TexCoord2f( 0,0,0 ); + meshBuilder.Position3f( x1, y[0], 0 ); + meshBuilder.AdvanceVertex(); + + meshBuilder.Color4ub( r, g, b, a * alpha[1] ); + meshBuilder.TexCoord2f( 0,1,0 ); + meshBuilder.Position3f( x2, y[1], 0 ); + meshBuilder.AdvanceVertex(); + + meshBuilder.Color4ub( r, g, b, a * alpha[2] ); + meshBuilder.TexCoord2f( 0,1,1 ); + meshBuilder.Position3f( x2, y[2], 0 ); + meshBuilder.AdvanceVertex(); + + meshBuilder.Color4ub( r, g, b, a * alpha[3] ); + meshBuilder.TexCoord2f( 0,0,1 ); + meshBuilder.Position3f( x1, y[3], 0 ); + meshBuilder.AdvanceVertex(); + } + + meshBuilder.End(); + pMesh->Draw(); +} + +//----------------------------------------------------------------------------- +// Purpose: Draws full screen damage fade +//----------------------------------------------------------------------------- +void CHudDamageIndicator::DrawFullscreenDamageIndicator() +{ + CMatRenderContextPtr pRenderContext( materials ); + IMesh *pMesh = pRenderContext->GetDynamicMesh( true, NULL, NULL, m_WhiteAdditiveMaterial ); + + CMeshBuilder meshBuilder; + meshBuilder.Begin( pMesh, MATERIAL_QUADS, 1 ); + int r = m_DmgFullscreenColor[0], g = m_DmgFullscreenColor[1], b = m_DmgFullscreenColor[2], a = m_DmgFullscreenColor[3]; + + float wide = GetWide(), tall = GetTall(); + + meshBuilder.Color4ub( r, g, b, a ); + meshBuilder.TexCoord2f( 0,0,0 ); + meshBuilder.Position3f( 0.0f, 0.0f, 0 ); + meshBuilder.AdvanceVertex(); + + meshBuilder.Color4ub( r, g, b, a ); + meshBuilder.TexCoord2f( 0,1,0 ); + meshBuilder.Position3f( wide, 0.0f, 0 ); + meshBuilder.AdvanceVertex(); + + meshBuilder.Color4ub( r, g, b, a ); + meshBuilder.TexCoord2f( 0,1,1 ); + meshBuilder.Position3f( wide, tall, 0 ); + meshBuilder.AdvanceVertex(); + + meshBuilder.Color4ub( r, g, b, a ); + meshBuilder.TexCoord2f( 0,0,1 ); + meshBuilder.Position3f( 0.0f, tall, 0 ); + meshBuilder.AdvanceVertex(); + + meshBuilder.End(); + pMesh->Draw(); +} + +//----------------------------------------------------------------------------- +// Purpose: Paints the damage display +//----------------------------------------------------------------------------- +void CHudDamageIndicator::Paint() +{ + // draw fullscreen damage indicators + DrawFullscreenDamageIndicator(); + + // draw side damage indicators + DrawDamageIndicator(0); + DrawDamageIndicator(1); +} + +//----------------------------------------------------------------------------- +// Purpose: Message handler for Damage message +//----------------------------------------------------------------------------- +void CHudDamageIndicator::MsgFunc_Damage( bf_read &msg ) +{ + int armor = msg.ReadByte(); // armor + int damageTaken = msg.ReadByte(); // health + long bitsDamage = msg.ReadLong(); // damage bits + + Vector vecFrom; + + vecFrom.x = msg.ReadFloat(); + vecFrom.y = msg.ReadFloat(); + vecFrom.z = msg.ReadFloat(); + + C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer(); + if ( !pPlayer ) + return; + + // player has just died, just run the dead damage animation + if ( pPlayer->GetHealth() <= 0 ) + { + g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( "HudPlayerDeath" ); + return; + } + + // ignore damage without direction + // this should never happen, unless it's drowning damage, + // or the player is forcibly killed, handled above + if ( vecFrom == vec3_origin && !(bitsDamage & DMG_DROWN)) + return; + + Vector vecDelta = (vecFrom - MainViewOrigin()); + VectorNormalize( vecDelta ); + + int highDamage = DAMAGE_LOW; + if ( damageTaken > 25 ) + { + highDamage = DAMAGE_HIGH; + } + + // if we have no suit, all damage is high + if ( !pPlayer->IsSuitEquipped() ) + { + highDamage = DAMAGE_HIGH; + } + + if ( damageTaken > 0 || armor > 0 ) + { + // see which quandrant the effect is in + float angle; + GetDamagePosition( vecDelta, &angle ); + + // see which effect to play + DamageAnimation_t *dmgAnim = g_DamageAnimations; + for ( ; dmgAnim->name != NULL; ++dmgAnim ) + { + if ( dmgAnim->bitsDamage && !(bitsDamage & dmgAnim->bitsDamage) ) + continue; + + if ( dmgAnim->angleMinimum && angle < dmgAnim->angleMinimum ) + continue; + + if ( dmgAnim->angleMaximum && angle > dmgAnim->angleMaximum ) + continue; + + if ( dmgAnim->damage && dmgAnim->damage != highDamage ) + continue; + + // we have a match, break + break; + } + + if ( dmgAnim->name ) + { + g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( dmgAnim->name ); + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: Convert a damage position in world units to the screen's units +//----------------------------------------------------------------------------- +void CHudDamageIndicator::GetDamagePosition( const Vector &vecDelta, float *flRotation ) +{ + float flRadius = 360.0f; + + // 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); + float xpos = flRadius * -side; + float 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)((GetWide() / 2) + (flRadius * sa)); + ypos = (int)((GetTall() / 2) - (flRadius * ca)); +} + +//----------------------------------------------------------------------------- +// Purpose: hud scheme settings +//----------------------------------------------------------------------------- +void CHudDamageIndicator::ApplySchemeSettings(vgui::IScheme *pScheme) +{ + BaseClass::ApplySchemeSettings(pScheme); + SetPaintBackgroundEnabled(false); + + int vx, vy, vw, vh; + vgui::surface()->GetFullscreenViewport( vx, vy, vw, vh ); + + SetForceStereoRenderToFrameBuffer( true ); + + if( UseVR() ) + { + m_flDmgY = 0.125f * (float)vh; + m_flDmgTall1 = 0.625f * (float)vh; + m_flDmgTall2 = 0.4f * (float)vh; + m_flDmgWide = 0.1f * (float)vw; + } + + SetSize(vw, vh); +} |