//========= Copyright Valve Corporation, All rights reserved. ============// // // Purpose: // // $NoKeywords: $ // //=============================================================================// #include "cbase.h" #include "hud.h" #include "hudelement.h" #include "iclientmode.h" #include "c_basehlplayer.h" #include "view_scene.h" #include "engine/IEngineSound.h" #include "vgui_controls/AnimationController.h" #include "vgui_controls/Controls.h" #include "vgui_controls/Panel.h" #include "vgui/ISurface.h" #include "iviewrender.h" // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" ConVar hud_draw_active_reticle("hud_draw_active_reticle", "0" ); ConVar hud_draw_fixed_reticle("hud_draw_fixed_reticle", "0", FCVAR_ARCHIVE ); ConVar hud_autoaim_scale_icon( "hud_autoaim_scale_icon", "0" ); ConVar hud_autoaim_method( "hud_autoaim_method", "1" ); ConVar hud_reticle_scale("hud_reticle_scale", "1.0" ); ConVar hud_reticle_minalpha( "hud_reticle_minalpha", "125" ); ConVar hud_reticle_maxalpha( "hud_reticle_maxalpha", "255" ); ConVar hud_alpha_speed("hud_reticle_alpha_speed", "700" ); ConVar hud_magnetism("hud_magnetism", "0.3" ); enum { AUTOAIM_METHOD_RETICLE = 1, AUTOAIM_METHOD_DRIFT, }; using namespace vgui; class CHUDAutoAim : public CHudElement, public vgui::Panel { DECLARE_CLASS_SIMPLE( CHUDAutoAim, vgui::Panel ); public: CHUDAutoAim( const char *pElementName ); virtual ~CHUDAutoAim( void ); void ApplySchemeSettings( IScheme *scheme ); void Init( void ); void VidInit( void ); bool ShouldDraw( void ); virtual void OnThink(); virtual void Paint(); private: void ResetAlpha() { m_alpha = 0; } void ResetScale() { m_scale = 1.0f; } void ResetPosition() { m_vecPos.x = ScreenWidth() / 2; m_vecPos.y = ScreenHeight() / 2; m_vecPos.z = 0; } Vector m_vecPos; float m_alpha; float m_scale; float m_alphaFixed; // alpha value for the fixed element. int m_textureID_ActiveReticle; int m_textureID_FixedReticle; }; DECLARE_HUDELEMENT( CHUDAutoAim ); CHUDAutoAim::CHUDAutoAim( const char *pElementName ) : CHudElement( pElementName ), BaseClass( NULL, "HUDAutoAim" ) { vgui::Panel *pParent = g_pClientMode->GetViewport(); SetParent( pParent ); SetHiddenBits( HIDEHUD_CROSSHAIR ); m_textureID_ActiveReticle = -1; m_textureID_FixedReticle = -1; } CHUDAutoAim::~CHUDAutoAim( void ) { if ( vgui::surface() ) { if ( m_textureID_ActiveReticle != -1 ) { vgui::surface()->DestroyTextureID( m_textureID_ActiveReticle ); m_textureID_ActiveReticle = -1; } if ( m_textureID_FixedReticle != -1 ) { vgui::surface()->DestroyTextureID( m_textureID_FixedReticle ); m_textureID_FixedReticle = -1; } } } void CHUDAutoAim::ApplySchemeSettings( IScheme *scheme ) { BaseClass::ApplySchemeSettings( scheme ); SetPaintBackgroundEnabled( false ); } void CHUDAutoAim::Init( void ) { ResetPosition(); ResetAlpha(); ResetScale(); } void CHUDAutoAim::VidInit( void ) { SetAlpha( 255 ); Init(); if ( m_textureID_ActiveReticle == -1 ) { m_textureID_ActiveReticle = vgui::surface()->CreateNewTextureID(); vgui::surface()->DrawSetTextureFile( m_textureID_ActiveReticle, "vgui/hud/autoaim", true, false ); } if ( m_textureID_FixedReticle == -1 ) { m_textureID_FixedReticle = vgui::surface()->CreateNewTextureID(); vgui::surface()->DrawSetTextureFile( m_textureID_FixedReticle, "vgui/hud/xbox_reticle", true, false ); } } //----------------------------------------------------------------------------- // 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 CHUDAutoAim::ShouldDraw( void ) { #ifndef HL1_CLIENT_DLL C_BaseHLPlayer *pLocalPlayer = (C_BaseHLPlayer *)C_BasePlayer::GetLocalPlayer(); if ( pLocalPlayer ) { if( !pLocalPlayer->m_HL2Local.m_bDisplayReticle ) { return false; } } #endif return ( (hud_draw_fixed_reticle.GetBool() || hud_draw_active_reticle.GetBool()) && CHudElement::ShouldDraw() && !engine->IsDrawingLoadingImage() ); } #define AUTOAIM_ALPHA_UP_SPEED 1000 #define AUTOAIM_ALPHA_DOWN_SPEED 300 #define AUTOAIM_MAX_ALPHA 120 #define AUTOAIM_MAX_SCALE 1.0f #define AUTOAIM_MIN_SCALE 0.5f #define AUTOAIM_SCALE_SPEED 10.0f #define AUTOAIM_ONTARGET_CROSSHAIR_SPEED (ScreenWidth() / 3) // Can cross the whole screen in 3 seconds. #define AUTOAIM_OFFTARGET_CROSSHAIR_SPEED (ScreenWidth() / 4) void CHUDAutoAim::OnThink() { int wide, tall; GetSize( wide, tall ); BaseClass::OnThink(); // Get the HL2 player C_BaseHLPlayer *pLocalPlayer = (C_BaseHLPlayer *)C_BasePlayer::GetLocalPlayer(); if ( pLocalPlayer == NULL ) { // Just turn the autoaim crosshair off. ResetPosition(); ResetAlpha(); ResetScale(); m_alphaFixed = 0.0f; return; } // Get the autoaim target. CBaseEntity *pTarget = pLocalPlayer->m_HL2Local.m_hAutoAimTarget.Get(); // Fixed element stuff float flFixedAlphaGoal; if( pTarget ) { flFixedAlphaGoal = hud_reticle_maxalpha.GetFloat(); } else { flFixedAlphaGoal = hud_reticle_minalpha.GetFloat(); } if( pLocalPlayer->m_HL2Local.m_bZooming || pLocalPlayer->m_HL2Local.m_bWeaponLowered ) { flFixedAlphaGoal = 0.0f; } m_alphaFixed = Approach( flFixedAlphaGoal, m_alphaFixed, (hud_alpha_speed.GetFloat() * gpGlobals->frametime) ); switch( hud_autoaim_method.GetInt() ) { case AUTOAIM_METHOD_RETICLE: { if( pLocalPlayer->m_HL2Local.m_hAutoAimTarget.Get() && pLocalPlayer->m_HL2Local.m_bStickyAutoAim ) { if( !pLocalPlayer->IsInAVehicle() ) { Vector vecLook; pLocalPlayer->EyeVectors( &vecLook, NULL, NULL ); Vector vecMove = pLocalPlayer->GetAbsVelocity(); float flSpeed = VectorNormalize( vecMove ); float flDot = DotProduct( vecLook, vecMove ); if( flSpeed >= 100 && fabs(flDot) <= 0.707f ) { QAngle viewangles; QAngle targetangles; QAngle delta; engine->GetViewAngles( viewangles ); Vector vecDir = pLocalPlayer->m_HL2Local.m_vecAutoAimPoint - pLocalPlayer->EyePosition(); VectorNormalize(vecDir); VectorAngles( vecDir, targetangles ); float magnetism = hud_magnetism.GetFloat(); delta[0] = ApproachAngle( targetangles[0], viewangles[0], magnetism ); delta[1] = ApproachAngle( targetangles[1], viewangles[1], magnetism ); delta[2] = targetangles[2]; //viewangles[PITCH] = clamp( viewangles[ PITCH ], -cl_pitchup.GetFloat(), cl_pitchdown.GetFloat() ); engine->SetViewAngles( delta ); } } } #if 0 bool doScaling = hud_autoaim_scale_icon.GetBool(); // These are the X & Y coords of where the crosshair should be. Default to // returning to the center of the screen if there is no target. int goalx = ScreenWidth() / 2; int goaly = ScreenHeight() / 2; int goalalpha = 0; float goalscale = AUTOAIM_MIN_SCALE; float speed = AUTOAIM_OFFTARGET_CROSSHAIR_SPEED; if( pTarget ) { // Get the autoaim crosshair onto the target. Vector screen; // Center the crosshair on the entity. if( doScaling ) { // Put the crosshair over the center of the target. ScreenTransform( pTarget->WorldSpaceCenter(), screen ); } else { // Put the crosshair exactly where the player is aiming. ScreenTransform( pLocalPlayer->m_HL2Local.m_vecAutoAimPoint, screen ); } // Set Goal Position and speed. goalx += 0.5f * screen[0] * ScreenWidth() + 0.5f; goaly -= 0.5f * screen[1] * ScreenHeight() + 0.5f; speed = AUTOAIM_ONTARGET_CROSSHAIR_SPEED; goalalpha = AUTOAIM_MAX_ALPHA; if( doScaling ) { // Scale the crosshair to envelope the entity's bounds on screen. Vector vecMins, vecMaxs; Vector vecScreenMins, vecScreenMaxs; // Get mins and maxs in world space vecMins = pTarget->GetAbsOrigin() + pTarget->WorldAlignMins(); vecMaxs = pTarget->GetAbsOrigin() + pTarget->WorldAlignMaxs(); // Project them to screen ScreenTransform( vecMins, vecScreenMins ); ScreenTransform( vecMaxs, vecScreenMaxs ); vecScreenMins.y = (ScreenWidth()/2) - 0.5f * vecScreenMins.y * ScreenWidth() + 0.5f; vecScreenMaxs.y = (ScreenWidth()/2) - 0.5f * vecScreenMaxs.y * ScreenWidth() + 0.5f; float screenSize = vecScreenMins.y - vecScreenMaxs.y; // Set goal scale goalscale = screenSize / 64.0f; // 64 is the width of the crosshair art. } else { goalscale = 1.0f; } } // Now approach the goal, alpha, and scale Vector vecGoal( goalx, goaly, 0 ); Vector vecDir = vecGoal - m_vecPos; float flDistRemaining = VectorNormalize( vecDir ); m_vecPos += vecDir * min(flDistRemaining, (speed * gpGlobals->frametime) ); // Lerp and Clamp scale float scaleDelta = fabs( goalscale - m_scale ); float scaleMove = MIN( AUTOAIM_SCALE_SPEED * gpGlobals->frametime, scaleDelta ); if( m_scale < goalscale ) { m_scale += scaleMove; } else if( m_scale > goalscale ) { m_scale -= scaleMove; } if( m_scale > AUTOAIM_MAX_SCALE ) { m_scale = AUTOAIM_MAX_SCALE; } else if( m_scale < AUTOAIM_MIN_SCALE ) { m_scale = AUTOAIM_MIN_SCALE; } if( goalalpha > m_alpha ) { m_alpha += AUTOAIM_ALPHA_UP_SPEED * gpGlobals->frametime; } else if( goalalpha < m_alpha ) { m_alpha -= AUTOAIM_ALPHA_DOWN_SPEED * gpGlobals->frametime; } // Clamp alpha if( m_alpha < 0 ) { m_alpha = 0; } else if( m_alpha > AUTOAIM_MAX_ALPHA ) { m_alpha = AUTOAIM_MAX_ALPHA; } #endif } break; case AUTOAIM_METHOD_DRIFT: { if( pLocalPlayer->m_HL2Local.m_hAutoAimTarget.Get() ) { QAngle viewangles; engine->GetViewAngles( viewangles ); Vector vecDir = pLocalPlayer->m_HL2Local.m_vecAutoAimPoint - pLocalPlayer->EyePosition(); VectorNormalize(vecDir); VectorAngles( vecDir, viewangles ); //viewangles[PITCH] = clamp( viewangles[ PITCH ], -cl_pitchup.GetFloat(), cl_pitchdown.GetFloat() ); engine->SetViewAngles( viewangles ); } } break; } } void CHUDAutoAim::Paint() { if( hud_draw_active_reticle.GetBool() ) { int xCenter = m_vecPos.x; int yCenter = m_vecPos.y; int width, height; float xMod, yMod; vgui::surface()->DrawSetTexture( m_textureID_ActiveReticle ); vgui::surface()->DrawSetColor( 255, 255, 255, m_alpha ); vgui::surface()->DrawGetTextureSize( m_textureID_ActiveReticle, width, height ); float uv1 = 0.5f / width, uv2 = 1.0f - uv1; vgui::Vertex_t vert[4]; Vector2D uv11( uv1, uv1 ); Vector2D uv12( uv1, uv2 ); Vector2D uv21( uv2, uv1 ); Vector2D uv22( uv2, uv2 ); xMod = width; yMod = height; xMod *= m_scale; yMod *= m_scale; xMod /= 2; yMod /= 2; vert[0].Init( Vector2D( xCenter + xMod, yCenter + yMod ), uv21 ); vert[1].Init( Vector2D( xCenter - xMod, yCenter + yMod ), uv11 ); vert[2].Init( Vector2D( xCenter - xMod, yCenter - yMod ), uv12 ); vert[3].Init( Vector2D( xCenter + xMod, yCenter - yMod ), uv22 ); vgui::surface()->DrawTexturedPolygon( 4, vert ); } if( hud_draw_fixed_reticle.GetBool() ) { int width, height; float xMod, yMod; vgui::surface()->DrawSetTexture( m_textureID_FixedReticle ); vgui::surface()->DrawGetTextureSize( m_textureID_FixedReticle, width, height ); int xCenter = ScreenWidth() / 2; int yCenter = ScreenHeight() / 2; vgui::Vertex_t vert[4]; Vector2D uv11( 0, 0 ); Vector2D uv12( 0, 1 ); Vector2D uv21( 1, 0 ); Vector2D uv22( 1, 1 ); xMod = width; yMod = height; xMod /= 2; yMod /= 2; vert[0].Init( Vector2D( xCenter + xMod, yCenter + yMod ), uv21 ); vert[1].Init( Vector2D( xCenter - xMod, yCenter + yMod ), uv11 ); vert[2].Init( Vector2D( xCenter - xMod, yCenter - yMod ), uv12 ); vert[3].Init( Vector2D( xCenter + xMod, yCenter - yMod ), uv22 ); Color clr; clr = gHUD.m_clrNormal; int r,g,b,a; clr.GetColor( r,g,b,a ); C_BaseHLPlayer *pLocalPlayer = (C_BaseHLPlayer *)C_BasePlayer::GetLocalPlayer(); if( pLocalPlayer && pLocalPlayer->m_HL2Local.m_hAutoAimTarget.Get() ) { r = 250; g = 138; b = 4; } clr.SetColor( r,g,b,m_alphaFixed); vgui::surface()->DrawSetColor( clr ); vgui::surface()->DrawTexturedPolygon( 4, vert ); } }