//========= Copyright Valve Corporation, All rights reserved. ============// // // Purpose: // // $NoKeywords: $ //=============================================================================// #include "cbase.h" #include "tf_hud_annotationspanel.h" #include "vgui_controls/AnimationController.h" #include "iclientmode.h" #include "c_tf_player.h" #include "c_tf_playerresource.h" #include #include #include #include "c_baseobject.h" #include "fmtstr.h" #include "tf_gamerules.h" #include "tf_hud_statpanel.h" #include "view.h" #include "ivieweffects.h" #include "viewrender.h" #include "tf_gamerules.h" #include "tf_hud_training.h" // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" DECLARE_HUDELEMENT_DEPTH( CTFAnnotationsPanel, 1 ); static const float LIFE_TIME = 1.0f; //----------------------------------------------------------------------------- // Purpose: Constructor //----------------------------------------------------------------------------- CTFAnnotationsPanel::CTFAnnotationsPanel( const char *pElementName ) : EditablePanel( NULL, "AnnotationsPanel" ), CHudElement( pElementName ) { vgui::Panel *pParent = g_pClientMode->GetViewport(); SetParent( pParent ); m_bShouldBeVisible = false; SetScheme( "ClientScheme" ); } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- CTFAnnotationsPanel::~CTFAnnotationsPanel() { Reset(); } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CTFAnnotationsPanel::Reset() { RemoveAll(); } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CTFAnnotationsPanel::Init() { // listen for events ListenForGameEvent( "show_annotation" ); ListenForGameEvent( "hide_annotation" ); RemoveAll(); CHudElement::Init(); } //----------------------------------------------------------------------------- // Purpose: Applies scheme settings //----------------------------------------------------------------------------- void CTFAnnotationsPanel::ApplySchemeSettings( vgui::IScheme *pScheme ) { BaseClass::ApplySchemeSettings( pScheme ); } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CTFAnnotationsPanel::FireGameEvent( IGameEvent * event ) { const char *pEventName = event->GetName(); if ( Q_strcmp( "hide_annotation", pEventName ) == 0 ) { HideAnnotation( event->GetInt("id") ); } else if ( Q_strcmp( "show_annotation", pEventName ) == 0 ) { AddAnnotation( event ); } } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- CTFAnnotationsPanelCallout *CTFAnnotationsPanel::TestAndAddCallout( int id, Vector &origin, const char *text ) { int insertSlot = -1; // Find an available slot and also see if this call out already exists in the list. for (int i=0; iGetAnnotationID() == id) { m_pCalloutPanels[i]->SetText( text ); m_pCalloutPanels[i]->SetLocation( origin ); m_pCalloutPanels[i]->SetFollowEntity( NULL ); m_pCalloutPanels[i]->InvalidateLayout(); return m_pCalloutPanels[i]; } // if one is available, use it if ( m_pCalloutPanels[i]->IsVisible() == false ) { insertSlot = i; continue; } } CTFAnnotationsPanelCallout *pCallout = new CTFAnnotationsPanelCallout( g_pClientMode->GetViewport(), "AnnotationsPanelCallout", id, origin, text ); if (-1 == insertSlot) { m_pCalloutPanels.AddToTail( vgui::SETUP_PANEL(pCallout) ); } else { if ( m_pCalloutPanels[insertSlot] != NULL ) { m_pCalloutPanels[insertSlot]->MarkForDeletion(); } m_pCalloutPanels[insertSlot] = vgui::SETUP_PANEL(pCallout); } return pCallout; } void CTFAnnotationsPanel::UpdateAnnotations( void ) { //Find an available slot and also see if this call out already exists in the list. for ( int i = m_pCalloutPanels.Count()-1; i >= 0; i-- ) { if ( !m_pCalloutPanels[i] ) { m_pCalloutPanels.Remove(i); continue; } // Update the callout. If it says it's finished, remove it. if ( m_pCalloutPanels[i]->UpdateCallout() ) { m_pCalloutPanels[i]->MarkForDeletion(); m_pCalloutPanels.Remove(i); } } // If we have no active callouts, hide if ( !m_pCalloutPanels.Count() ) { m_bShouldBeVisible = false; } } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CTFAnnotationsPanel::AddAnnotation( IGameEvent * event ) { const char *text = event->GetString( "text" ); int id = event->GetInt("id"); float x = event->GetFloat("worldPosX"); float y = event->GetFloat("worldPosY"); float z = event->GetFloat("worldPosZ"); int iVisibilityBitfield = event->GetInt("visibilityBitfield"); float flLifetime = event->GetFloat("lifetime"); int iFollowEntIndex = event->GetInt("follow_entindex"); bool bShowDistance = event->GetBool("show_distance"); const char *pSound = event->GetString( "play_sound" ); bool bShowEffect = event->GetBool( "show_effect" ); Vector location; location.x = x; location.y = y; location.z = z; m_bShouldBeVisible = true; // Try and add the callout CTFAnnotationsPanelCallout *pCallout = TestAndAddCallout( id, location, text ); if ( pCallout ) { C_BaseEntity *pFollowEntity = iFollowEntIndex != 0 ? ClientEntityList().GetEnt( iFollowEntIndex) : NULL; pCallout->Touch(); pCallout->SetLifetime( flLifetime ); pCallout->SetVisibilityBitfield( iVisibilityBitfield ); pCallout->SetFollowEntity( pFollowEntity ); pCallout->SetShowDistance( bShowDistance ); pCallout->UpdateCallout(); if ( pCallout->IsVisible() ) { if ( pSound ) { vgui::surface()->PlaySound( pSound ); } if ( bShowEffect ) { if ( pFollowEntity && pFollowEntity->ParticleProp()) { pFollowEntity->ParticleProp()->Create( "ping_circle", PATTACH_ABSORIGIN_FOLLOW ); } else { Vector vecNormal( event->GetFloat("worldNormalX"), event->GetFloat("worldNormalY"), event->GetFloat("worldNormalZ") ); Vector vecOrigin( x, y, z ); vecOrigin += vecNormal * 20.0f; QAngle vecAngles; VectorAngles( vecNormal, vecAngles ); DispatchParticleEffect( "ping_circle", vecOrigin, vecAngles ); } } } } } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CTFAnnotationsPanel::HideAnnotation( int id ) { // Delete all our callout panels for ( int i = m_pCalloutPanels.Count()-1; i >= 0; i-- ) { if ( m_pCalloutPanels[i]->GetAnnotationID() == id ) { m_pCalloutPanels[i]->FadeAndRemove(); break; } } } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CTFAnnotationsPanel::RemoveAll() { m_bShouldBeVisible = false; // Delete all our callout panels for ( int i = m_pCalloutPanels.Count()-1; i >= 0; i-- ) { m_pCalloutPanels[i]->MarkForDeletion(); } m_pCalloutPanels.RemoveAll(); } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- bool CTFAnnotationsPanel::ShouldDraw( void ) { return m_bShouldBeVisible; } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CTFAnnotationsPanel::OnThink( void ) { BaseClass::OnThink(); if ( IsVisible() ) { UpdateAnnotations(); } } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- CTFAnnotationsPanelCallout::~CTFAnnotationsPanelCallout() { if ( m_pArrowImages ) { m_pArrowImages->deleteThis(); } } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- CTFAnnotationsPanelCallout::CTFAnnotationsPanelCallout( Panel *parent, const char *name, int id, Vector &location, const char* text ) : EditablePanel( parent, name ) { m_pAnnotationLabel = NULL; m_pDistanceLabel = NULL; m_pArrowImages = NULL; m_ID = id; m_Location = location; m_Text = text; m_DeathTime = 0.0f; m_flLerpPercentage = 1.0f; m_bWasOffscreen = false; m_bShowDistance = false; m_flAlpha[0] = m_flAlpha[1] = 0.0f; SetWorldPositionCurrentFrame( true ); } //----------------------------------------------------------------------------- // Purpose: Applies scheme settings //----------------------------------------------------------------------------- void CTFAnnotationsPanelCallout::ApplySettings( KeyValues *pInResourceData ) { BaseClass::ApplySettings( pInResourceData ); if ( !m_pArrowImages ) { KeyValues *pArrowImagesSubKey = pInResourceData->FindKey( "ArrowIcons" ); AssertMsg( pArrowImagesSubKey, "This must exist!" ); m_pArrowImages = pArrowImagesSubKey->MakeCopy(); } } //----------------------------------------------------------------------------- // Purpose: Applies scheme settings //----------------------------------------------------------------------------- void CTFAnnotationsPanelCallout::ApplySchemeSettings( vgui::IScheme *pScheme ) { BaseClass::ApplySchemeSettings( pScheme ); LoadControlSettings( "resource/UI/AnnotationsPanelCallout.res" ); m_pDistanceLabel = dynamic_cast