diff options
Diffstat (limited to 'game/client/dod')
112 files changed, 25064 insertions, 0 deletions
diff --git a/game/client/dod/VGUI/backgroundpanel.cpp b/game/client/dod/VGUI/backgroundpanel.cpp new file mode 100644 index 0000000..9783c21 --- /dev/null +++ b/game/client/dod/VGUI/backgroundpanel.cpp @@ -0,0 +1,677 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#include "cbase.h" +#include "backgroundpanel.h" + +#include <vgui/IVGui.h> +#include <vgui/IScheme.h> +#include <vgui/ISurface.h> +#include <vgui_controls/Label.h> +#include <vgui/ILocalize.h> +#include "vgui_controls/BuildGroup.h" +#include "vgui_controls/BitmapImagePanel.h" + +using namespace vgui; + +#define DEBUG_WINDOW_RESIZING 0 +#define DEBUG_WINDOW_REPOSITIONING 0 + +//----------------------------------------------------------------------------- +const int NumSegments = 7; +static int coord[NumSegments+1] = { + 0, + 1, + 2, + 3, + 4, + 6, + 9, + 10 +}; + +//----------------------------------------------------------------------------- +void DrawRoundedBackground( Color bgColor, int wide, int tall ) +{ + int x1, x2, y1, y2; + surface()->DrawSetColor(bgColor); + surface()->DrawSetTextColor(bgColor); + + int i; + + // top-left corner -------------------------------------------------------- + int xDir = 1; + int yDir = -1; + int xIndex = 0; + int yIndex = NumSegments - 1; + int xMult = 1; + int yMult = 1; + int x = 0; + int y = 0; + for ( i=0; i<NumSegments; ++i ) + { + x1 = MIN( x + coord[xIndex]*xMult, x + coord[xIndex+1]*xMult ); + x2 = MAX( x + coord[xIndex]*xMult, x + coord[xIndex+1]*xMult ); + y1 = MAX( y + coord[yIndex]*yMult, y + coord[yIndex+1]*yMult ); + y2 = y + coord[NumSegments]; + surface()->DrawFilledRect( x1, y1, x2, y2 ); + + xIndex += xDir; + yIndex += yDir; + } + + // top-right corner ------------------------------------------------------- + xDir = 1; + yDir = -1; + xIndex = 0; + yIndex = NumSegments - 1; + x = wide; + y = 0; + xMult = -1; + yMult = 1; + for ( i=0; i<NumSegments; ++i ) + { + x1 = MIN( x + coord[xIndex]*xMult, x + coord[xIndex+1]*xMult ); + x2 = MAX( x + coord[xIndex]*xMult, x + coord[xIndex+1]*xMult ); + y1 = MAX( y + coord[yIndex]*yMult, y + coord[yIndex+1]*yMult ); + y2 = y + coord[NumSegments]; + surface()->DrawFilledRect( x1, y1, x2, y2 ); + xIndex += xDir; + yIndex += yDir; + } + + // bottom-right corner ---------------------------------------------------- + xDir = 1; + yDir = -1; + xIndex = 0; + yIndex = NumSegments - 1; + x = wide; + y = tall; + xMult = -1; + yMult = -1; + for ( i=0; i<NumSegments; ++i ) + { + x1 = MIN( x + coord[xIndex]*xMult, x + coord[xIndex+1]*xMult ); + x2 = MAX( x + coord[xIndex]*xMult, x + coord[xIndex+1]*xMult ); + y1 = y - coord[NumSegments]; + y2 = MIN( y + coord[yIndex]*yMult, y + coord[yIndex+1]*yMult ); + surface()->DrawFilledRect( x1, y1, x2, y2 ); + xIndex += xDir; + yIndex += yDir; + } + + // bottom-left corner ----------------------------------------------------- + xDir = 1; + yDir = -1; + xIndex = 0; + yIndex = NumSegments - 1; + x = 0; + y = tall; + xMult = 1; + yMult = -1; + for ( i=0; i<NumSegments; ++i ) + { + x1 = MIN( x + coord[xIndex]*xMult, x + coord[xIndex+1]*xMult ); + x2 = MAX( x + coord[xIndex]*xMult, x + coord[xIndex+1]*xMult ); + y1 = y - coord[NumSegments]; + y2 = MIN( y + coord[yIndex]*yMult, y + coord[yIndex+1]*yMult ); + surface()->DrawFilledRect( x1, y1, x2, y2 ); + xIndex += xDir; + yIndex += yDir; + } + + // paint between top left and bottom left --------------------------------- + x1 = 0; + x2 = coord[NumSegments]; + y1 = coord[NumSegments]; + y2 = tall - coord[NumSegments]; + surface()->DrawFilledRect( x1, y1, x2, y2 ); + + // paint between left and right ------------------------------------------- + x1 = coord[NumSegments]; + x2 = wide - coord[NumSegments]; + y1 = 0; + y2 = tall; + surface()->DrawFilledRect( x1, y1, x2, y2 ); + + // paint between top right and bottom right ------------------------------- + x1 = wide - coord[NumSegments]; + x2 = wide; + y1 = coord[NumSegments]; + y2 = tall - coord[NumSegments]; + surface()->DrawFilledRect( x1, y1, x2, y2 ); +} + +//----------------------------------------------------------------------------- +void DrawRoundedBorder( Color borderColor, int wide, int tall ) +{ + int x1, x2, y1, y2; + surface()->DrawSetColor(borderColor); + surface()->DrawSetTextColor(borderColor); + + int i; + + // top-left corner -------------------------------------------------------- + int xDir = 1; + int yDir = -1; + int xIndex = 0; + int yIndex = NumSegments - 1; + int xMult = 1; + int yMult = 1; + int x = 0; + int y = 0; + for ( i=0; i<NumSegments; ++i ) + { + x1 = MIN( x + coord[xIndex]*xMult, x + coord[xIndex+1]*xMult ); + x2 = MAX( x + coord[xIndex]*xMult, x + coord[xIndex+1]*xMult ); + y1 = MIN( y + coord[yIndex]*yMult, y + coord[yIndex+1]*yMult ); + y2 = MAX( y + coord[yIndex]*yMult, y + coord[yIndex+1]*yMult ); + surface()->DrawFilledRect( x1, y1, x2, y2 ); + + xIndex += xDir; + yIndex += yDir; + } + + // top-right corner ------------------------------------------------------- + xDir = 1; + yDir = -1; + xIndex = 0; + yIndex = NumSegments - 1; + x = wide; + y = 0; + xMult = -1; + yMult = 1; + for ( i=0; i<NumSegments; ++i ) + { + x1 = MIN( x + coord[xIndex]*xMult, x + coord[xIndex+1]*xMult ); + x2 = MAX( x + coord[xIndex]*xMult, x + coord[xIndex+1]*xMult ); + y1 = MIN( y + coord[yIndex]*yMult, y + coord[yIndex+1]*yMult ); + y2 = MAX( y + coord[yIndex]*yMult, y + coord[yIndex+1]*yMult ); + surface()->DrawFilledRect( x1, y1, x2, y2 ); + xIndex += xDir; + yIndex += yDir; + } + + // bottom-right corner ---------------------------------------------------- + xDir = 1; + yDir = -1; + xIndex = 0; + yIndex = NumSegments - 1; + x = wide; + y = tall; + xMult = -1; + yMult = -1; + for ( i=0; i<NumSegments; ++i ) + { + x1 = MIN( x + coord[xIndex]*xMult, x + coord[xIndex+1]*xMult ); + x2 = MAX( x + coord[xIndex]*xMult, x + coord[xIndex+1]*xMult ); + y1 = MIN( y + coord[yIndex]*yMult, y + coord[yIndex+1]*yMult ); + y2 = MAX( y + coord[yIndex]*yMult, y + coord[yIndex+1]*yMult ); + surface()->DrawFilledRect( x1, y1, x2, y2 ); + xIndex += xDir; + yIndex += yDir; + } + + // bottom-left corner ----------------------------------------------------- + xDir = 1; + yDir = -1; + xIndex = 0; + yIndex = NumSegments - 1; + x = 0; + y = tall; + xMult = 1; + yMult = -1; + for ( i=0; i<NumSegments; ++i ) + { + x1 = MIN( x + coord[xIndex]*xMult, x + coord[xIndex+1]*xMult ); + x2 = MAX( x + coord[xIndex]*xMult, x + coord[xIndex+1]*xMult ); + y1 = MIN( y + coord[yIndex]*yMult, y + coord[yIndex+1]*yMult ); + y2 = MAX( y + coord[yIndex]*yMult, y + coord[yIndex+1]*yMult ); + surface()->DrawFilledRect( x1, y1, x2, y2 ); + xIndex += xDir; + yIndex += yDir; + } + + // top -------------------------------------------------------------------- + x1 = coord[NumSegments]; + x2 = wide - coord[NumSegments]; + y1 = 0; + y2 = 1; + surface()->DrawFilledRect( x1, y1, x2, y2 ); + + // bottom ----------------------------------------------------------------- + x1 = coord[NumSegments]; + x2 = wide - coord[NumSegments]; + y1 = tall - 1; + y2 = tall; + surface()->DrawFilledRect( x1, y1, x2, y2 ); + + // left ------------------------------------------------------------------- + x1 = 0; + x2 = 1; + y1 = coord[NumSegments]; + y2 = tall - coord[NumSegments]; + surface()->DrawFilledRect( x1, y1, x2, y2 ); + + // right ------------------------------------------------------------------ + x1 = wide - 1; + x2 = wide; + y1 = coord[NumSegments]; + y2 = tall - coord[NumSegments]; + surface()->DrawFilledRect( x1, y1, x2, y2 ); +} + +//----------------------------------------------------------------------------- +class CaptionLabel : public Label +{ +public: + CaptionLabel(Panel *parent, const char *panelName, const char *text) : Label(parent, panelName, text) + { + } + + virtual void ApplySchemeSettings( vgui::IScheme *pScheme ) + { + Label::ApplySchemeSettings( pScheme ); + SetFont( pScheme->GetFont( "MenuTitle", IsProportional() ) ); + } +}; + +//----------------------------------------------------------------------------- +// Purpose: transform a normalized value into one that is scaled based the minimum +// of the horizontal and vertical ratios +//----------------------------------------------------------------------------- +static int GetAlternateProportionalValueFromNormal(int normalizedValue) +{ + int wide, tall; + GetHudSize( wide, tall ); + int proH, proW; + surface()->GetProportionalBase( proW, proH ); + double scaleH = (double)tall / (double)proH; + double scaleW = (double)wide / (double)proW; + double scale = (scaleW < scaleH) ? scaleW : scaleH; + + return (int)( normalizedValue * scale ); +} + +//----------------------------------------------------------------------------- +// Purpose: transform a standard scaled value into one that is scaled based the minimum +// of the horizontal and vertical ratios +//----------------------------------------------------------------------------- +int GetAlternateProportionalValueFromScaled(vgui::HScheme hScheme, int scaledValue) +{ + return GetAlternateProportionalValueFromNormal( scheme()->GetProportionalNormalizedValueEx( hScheme, scaledValue ) ); +} + +//----------------------------------------------------------------------------- +// Purpose: moves and resizes a single control +//----------------------------------------------------------------------------- +static void RepositionControl( Panel *pPanel ) +{ + int x, y, w, h; + pPanel->GetBounds(x, y, w, h); + +#if DEBUG_WINDOW_RESIZING + int x1, y1, w1, h1; + pPanel->GetBounds(x1, y1, w1, h1); + int x2, y2, w2, h2; + x2 = scheme()->GetProportionalNormalizedValueEx( pPanel->GetScheme(),x1 ); + y2 = scheme()->GetProportionalNormalizedValueEx( pPanel->GetScheme(),y1 ); + w2 = scheme()->GetProportionalNormalizedValueEx( pPanel->GetScheme(),w1 ); + h2 = scheme()->GetProportionalNormalizedValueEx( pPanel->GetScheme(),h1 ); +#endif + + x = GetAlternateProportionalValueFromScaled(pPanel->GetScheme(),x); + y = GetAlternateProportionalValueFromScaled(pPanel->GetScheme(),y); + w = GetAlternateProportionalValueFromScaled(pPanel->GetScheme(),w); + h = GetAlternateProportionalValueFromScaled(pPanel->GetScheme(),h); + + pPanel->SetBounds(x, y, w, h); + +#if DEBUG_WINDOW_RESIZING + DevMsg( "Resizing '%s' from (%d,%d) %dx%d to (%d,%d) %dx%d -- initially was (%d,%d) %dx%d\n", + pPanel->GetName(), x1, y1, w1, h1, x, y, w, h, x2, y2, w2, h2 ); +#endif +} + +//----------------------------------------------------------------------------- +// Purpose: Sets colors etc for background image panels +//----------------------------------------------------------------------------- +void ApplyBackgroundSchemeSettings( EditablePanel *pWindow, vgui::IScheme *pScheme ) +{ + Color bgColor = Color( 255, 255, 255, pScheme->GetColor( "BgColor", Color( 0, 0, 0, 0 ) )[3] ); + Color fgColor = pScheme->GetColor( "FgColor", Color( 0, 0, 0, 0 ) ); + + if ( !pWindow ) + return; + + CBitmapImagePanel *pBitmapPanel; + + // corners -------------------------------------------- + pBitmapPanel = dynamic_cast< CBitmapImagePanel * >(pWindow->FindChildByName( "TopLeftPanel" )); + if ( pBitmapPanel ) + { + pBitmapPanel->setImageColor( bgColor ); + } + pBitmapPanel = dynamic_cast< CBitmapImagePanel * >(pWindow->FindChildByName( "TopRightPanel" )); + if ( pBitmapPanel ) + { + pBitmapPanel->setImageColor( bgColor ); + } + pBitmapPanel = dynamic_cast< CBitmapImagePanel * >(pWindow->FindChildByName( "BottomLeftPanel" )); + if ( pBitmapPanel ) + { + pBitmapPanel->setImageColor( bgColor ); + } + pBitmapPanel = dynamic_cast< CBitmapImagePanel * >(pWindow->FindChildByName( "BottomRightPanel" )); + if ( pBitmapPanel ) + { + pBitmapPanel->setImageColor( bgColor ); + } + + // background ----------------------------------------- + pBitmapPanel = dynamic_cast< CBitmapImagePanel * >(pWindow->FindChildByName( "TopSolid" )); + if ( pBitmapPanel ) + { + pBitmapPanel->setImageColor( bgColor ); + } + pBitmapPanel = dynamic_cast< CBitmapImagePanel * >(pWindow->FindChildByName( "UpperMiddleSolid" )); + if ( pBitmapPanel ) + { + pBitmapPanel->setImageColor( bgColor ); + } + pBitmapPanel = dynamic_cast< CBitmapImagePanel * >(pWindow->FindChildByName( "LowerMiddleSolid" )); + if ( pBitmapPanel ) + { + pBitmapPanel->setImageColor( bgColor ); + } + pBitmapPanel = dynamic_cast< CBitmapImagePanel * >(pWindow->FindChildByName( "BottomSolid" )); + if ( pBitmapPanel ) + { + pBitmapPanel->setImageColor( bgColor ); + } + + // Logo ----------------------------------------------- +/* pBitmapPanel = dynamic_cast< CBitmapImagePanel * >(pWindow->FindChildByName( "ExclamationPanel" )); + if ( pBitmapPanel ) + { + pBitmapPanel->setImageColor( fgColor ); + } +*/ +} + +//----------------------------------------------------------------------------- +// Purpose: Re-aligns background image panels so they are touching. +//----------------------------------------------------------------------------- +static void FixupBackgroundPanels( EditablePanel *pWindow, int offsetX, int offsetY ) +{ + if ( !pWindow ) + return; + + int screenWide, screenTall; + pWindow->GetSize( screenWide, screenTall ); + + int inset = GetAlternateProportionalValueFromNormal( 20 ); + int cornerSize = GetAlternateProportionalValueFromNormal( 10 ); + + int titleHeight = GetAlternateProportionalValueFromNormal( 42 ); + int mainHeight = GetAlternateProportionalValueFromNormal( 376 ); + + int logoSize = titleHeight; + + int captionInset = GetAlternateProportionalValueFromNormal( 76 ); + + Panel *pPanel; + + // corners -------------------------------------------- + pPanel = pWindow->FindChildByName( "TopLeftPanel" ); + if ( pPanel ) + { + pPanel->SetZPos( -20 ); + pPanel->SetBounds( offsetX + inset, offsetY + inset, cornerSize, cornerSize ); + } + + pPanel = pWindow->FindChildByName( "TopRightPanel" ); + if ( pPanel ) + { + pPanel->SetZPos( -20 ); + pPanel->SetBounds( screenWide - offsetX - inset - cornerSize, offsetY + inset, cornerSize, cornerSize ); + } + + pPanel = pWindow->FindChildByName( "BottomLeftPanel" ); + if ( pPanel ) + { + pPanel->SetZPos( -20 ); + pPanel->SetBounds( offsetX + inset, screenTall - offsetY - inset - cornerSize, cornerSize, cornerSize ); + } + + pPanel = pWindow->FindChildByName( "BottomRightPanel" ); + if ( pPanel ) + { + pPanel->SetZPos( -20 ); + pPanel->SetBounds( screenWide - offsetX - inset - cornerSize, screenTall - offsetY - inset - cornerSize, cornerSize, cornerSize ); + } + + // background ----------------------------------------- + pPanel = pWindow->FindChildByName( "TopSolid" ); + if ( pPanel ) + { + pPanel->SetZPos( -20 ); + pPanel->SetBounds( offsetX + inset + cornerSize, offsetY + inset, screenWide - 2*offsetX - 2*inset - 2*cornerSize, cornerSize ); + } + + pPanel = pWindow->FindChildByName( "UpperMiddleSolid" ); + if ( pPanel ) + { + pPanel->SetZPos( -20 ); + pPanel->SetBounds( offsetX + inset, offsetY + inset + cornerSize, screenWide - 2*offsetX - 2*inset, titleHeight ); + } + + pPanel = pWindow->FindChildByName( "LowerMiddleSolid" ); + if ( pPanel ) + { + pPanel->SetZPos( -20 ); + pPanel->SetBounds( offsetX + inset + cornerSize, screenTall - offsetY - inset - cornerSize, screenWide - 2*offsetX - 2*inset - 2*cornerSize, cornerSize ); + } + + pPanel = pWindow->FindChildByName( "BottomSolid" ); + if ( pPanel ) + { + pPanel->SetZPos( -20 ); + pPanel->SetBounds( offsetX + inset, screenTall - offsetY - inset - cornerSize - mainHeight, screenWide - 2*offsetX - 2*inset, mainHeight ); + } + + // transparent border --------------------------------- + pPanel = pWindow->FindChildByName( "TopClear" ); + if ( pPanel ) + { + pPanel->SetZPos( -20 ); + pPanel->SetBounds( 0, 0, screenWide, offsetY + inset ); + } + + pPanel = pWindow->FindChildByName( "BottomClear" ); + if ( pPanel ) + { + pPanel->SetZPos( -20 ); + pPanel->SetBounds( 0, screenTall - offsetY - inset, screenWide, offsetY + inset ); + } + + pPanel = pWindow->FindChildByName( "LeftClear" ); + if ( pPanel ) + { + pPanel->SetZPos( -20 ); + pPanel->SetBounds( 0, offsetY + inset, offsetX + inset, screenTall - 2*offsetY - 2*inset ); + } + + pPanel = pWindow->FindChildByName( "RightClear" ); + if ( pPanel ) + { + pPanel->SetZPos( -20 ); + pPanel->SetBounds( screenWide - offsetX - inset, offsetY + inset, offsetX + inset, screenTall - 2*offsetY - 2*inset ); + } + + // Logo ----------------------------------------------- +/* int logoInset = (cornerSize + titleHeight - logoSize)/2; + pPanel = pWindow->FindChildByName( "ExclamationPanel" ); + if ( pPanel ) + { + pPanel->SetZPos( -19 ); // higher than the background + pPanel->SetBounds( offsetX + inset + logoInset, offsetY + inset + logoInset, logoSize, logoSize ); + } +*/ + // Title caption -------------------------------------- + pPanel = dynamic_cast< Label * >(pWindow->FindChildByName( "CaptionLabel" )); + if ( pPanel ) + { + pPanel->SetZPos( -19 ); // higher than the background + pPanel->SetBounds( offsetX + captionInset/*inset + 2*logoInset + logoSize*/, offsetY + inset /*+ logoInset*/, screenWide, logoSize ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: Creates background image panels +//----------------------------------------------------------------------------- +void CreateBackground( EditablePanel *pWindow ) +{ + // corners -------------------------------------------- + new CBitmapImagePanel( pWindow, "TopLeftPanel", "gfx/vgui/round_corner_nw" ); + new CBitmapImagePanel( pWindow, "TopRightPanel", "gfx/vgui/round_corner_ne" ); + new CBitmapImagePanel( pWindow, "BottomLeftPanel", "gfx/vgui/round_corner_sw" ); + new CBitmapImagePanel( pWindow, "BottomRightPanel", "gfx/vgui/round_corner_se" ); + + // background ----------------------------------------- + new CBitmapImagePanel( pWindow, "TopSolid", "gfx/vgui/solid_background" ); + new CBitmapImagePanel( pWindow, "UpperMiddleSolid", "gfx/vgui/solid_background" ); + new CBitmapImagePanel( pWindow, "LowerMiddleSolid", "gfx/vgui/solid_background" ); + new CBitmapImagePanel( pWindow, "BottomSolid", "gfx/vgui/solid_background" ); + + // transparent border --------------------------------- + new CBitmapImagePanel( pWindow, "TopClear", "gfx/vgui/trans_background" ); + new CBitmapImagePanel( pWindow, "BottomClear", "gfx/vgui/trans_background" ); + new CBitmapImagePanel( pWindow, "LeftClear", "gfx/vgui/trans_background" ); + new CBitmapImagePanel( pWindow, "RightClear", "gfx/vgui/trans_background" ); + + // Logo ----------------------------------------------- +// new CBitmapImagePanel( pWindow, "ExclamationPanel", "gfx/vgui/TF_logo" ); + + // Title caption -------------------------------------- + Panel *pPanel = dynamic_cast< Label * >(pWindow->FindChildByName( "CaptionLabel" )); + if ( !pPanel ) + new CaptionLabel( pWindow, "CaptionLabel", "" ); +} + +void ResizeWindowControls( EditablePanel *pWindow, int tall, int wide, int offsetX, int offsetY ) +{ + if (!pWindow || !pWindow->GetBuildGroup() || !pWindow->GetBuildGroup()->GetPanelList()) + return; + + CUtlVector<PHandle> *panelList = pWindow->GetBuildGroup()->GetPanelList(); + CUtlVector<Panel *> resizedPanels; + CUtlVector<Panel *> movedPanels; + + // Resize to account for 1.25 aspect ratio (1280x1024) screens + { + for ( int i = 0; i < panelList->Size(); ++i ) + { + PHandle handle = (*panelList)[i]; + + Panel *panel = handle.Get(); + + bool found = false; + for ( int j = 0; j < resizedPanels.Size(); ++j ) + { + if (panel == resizedPanels[j]) + found = true; + } + + if (!panel || found) + { + continue; + } + + resizedPanels.AddToTail( panel ); // don't move a panel more than once + + if ( panel != pWindow ) + { + RepositionControl( panel ); + } + } + } + + // and now re-center them. Woohoo! + for ( int i = 0; i < panelList->Size(); ++i ) + { + PHandle handle = (*panelList)[i]; + + Panel *panel = handle.Get(); + + bool found = false; + for ( int j = 0; j < movedPanels.Size(); ++j ) + { + if (panel == movedPanels[j]) + found = true; + } + + if (!panel || found) + { + continue; + } + + movedPanels.AddToTail( panel ); // don't move a panel more than once + + if ( panel != pWindow ) + { + int x, y; + + panel->GetPos( x, y ); + panel->SetPos( x + offsetX, y + offsetY ); + +#if DEBUG_WINDOW_REPOSITIONING + DevMsg( "Repositioning '%s' from (%d,%d) to (%d,%d) -- a distance of (%d,%d)\n", + panel->GetName(), x, y, x + offsetX, y + offsetY, offsetX, offsetY ); +#endif + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: Resizes windows to fit completely on-screen (for 1280x1024), and +// centers them on the screen. Sub-controls are also resized and moved. +//----------------------------------------------------------------------------- +void LayoutBackgroundPanel( EditablePanel *pWindow ) +{ + if ( !pWindow ) + return; + + int screenW, screenH; + GetHudSize( screenW, screenH ); + + int wide, tall; + pWindow->GetSize( wide, tall ); + + int offsetX = 0; + int offsetY = 0; + + // Slide everything over to the center + pWindow->SetBounds( 0, 0, screenW, screenH ); + + if ( wide != screenW || tall != screenH ) + { + wide = GetAlternateProportionalValueFromScaled(pWindow->GetScheme(), wide); + tall = GetAlternateProportionalValueFromScaled(pWindow->GetScheme(), tall); + + offsetX = (screenW - wide)/2; + offsetY = (screenH - tall)/2; + + ResizeWindowControls( pWindow, tall, wide, offsetX, offsetY ); + } + + // now that the panels are moved/resized, look for some bg panels, and re-align them + FixupBackgroundPanels( pWindow, offsetX, offsetY ); +} + +//----------------------------------------------------------------------------- + diff --git a/game/client/dod/VGUI/backgroundpanel.h b/game/client/dod/VGUI/backgroundpanel.h new file mode 100644 index 0000000..7006aeb --- /dev/null +++ b/game/client/dod/VGUI/backgroundpanel.h @@ -0,0 +1,53 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef DODBACKGROUND_H +#define DODBACKGROUND_H + +#include <vgui_controls/Frame.h> +#include <vgui_controls/EditablePanel.h> + +//----------------------------------------------------------------------------- +// Purpose: Creates background image panels +//----------------------------------------------------------------------------- +void CreateBackground( vgui::EditablePanel *pWindow ); + +//----------------------------------------------------------------------------- +// Purpose: Resizes windows to fit completely on-screen (for 1280x1024), and +// centers them on the screen. Sub-controls are also resized and moved. +//----------------------------------------------------------------------------- +void LayoutBackgroundPanel( vgui::EditablePanel *pWindow ); + +//----------------------------------------------------------------------------- +// Purpose: Sets colors etc for background image panels +//----------------------------------------------------------------------------- +void ApplyBackgroundSchemeSettings( vgui::EditablePanel *pWindow, vgui::IScheme *pScheme ); + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void ResizeWindowControls( vgui::EditablePanel *pWindow, int tall, int wide, int offsetX, int offsetY ); + +//----------------------------------------------------------------------------- +// Purpose: transform a standard scaled value into one that is scaled based the minimum +// of the horizontal and vertical ratios +//----------------------------------------------------------------------------- +int GetAlternateProportionalValueFromScaled( vgui::HScheme hScheme, int scaledValue ); + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void DrawRoundedBackground( Color bgColor, int wide, int tall ); + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void DrawRoundedBorder( Color borderColor, int wide, int tall ); + +//----------------------------------------------------------------------------- + +#endif // DODBACKGROUND_H diff --git a/game/client/dod/VGUI/dodbutton.cpp b/game/client/dod/VGUI/dodbutton.cpp new file mode 100644 index 0000000..11e0ade --- /dev/null +++ b/game/client/dod/VGUI/dodbutton.cpp @@ -0,0 +1,99 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#include "cbase.h" +#include "dodbutton.h" + +#include <vgui/ISurface.h> +#include <vgui_controls/EditablePanel.h> + +// memdbgon must be the last include file in a .cpp file!!! +#include <tier0/memdbgon.h> + +using namespace vgui; + +//=============================================== +// CDODButtonShape - drawing class for dod button shape +//=============================================== +void CDODButtonShape::DrawShapedBorder( int x, int y, int wide, int tall, Color fgcolor ) +{ + int halfheight = tall / 3; + + surface()->DrawSetColor(fgcolor); + + // top + surface()->DrawLine( 0, 1, wide-1, 1 ); + + // left + surface()->DrawLine( 1, 1, 1, tall-1 ); + + // bottom + surface()->DrawLine( 0, tall-1, wide-halfheight, tall-1 ); + + // right + surface()->DrawLine( wide-1, 0, wide-1, tall-halfheight ); + + // diagonal + surface()->DrawLine( wide-1, tall-halfheight-1, wide-halfheight-1, tall-1 ); +} + +void CDODButtonShape::DrawShapedBackground( int x, int y, int wide, int tall, Color bgcolor ) +{ + int halfheight = tall / 3; + + if ( m_iWhiteTexture < 0 ) + { + m_iWhiteTexture = vgui::surface()->CreateNewTextureID(); + vgui::surface()->DrawSetTextureFile( m_iWhiteTexture, "vgui/white" , true, false); + } + + surface()->DrawSetColor(bgcolor); + surface()->DrawSetTexture( m_iWhiteTexture ); + + Vertex_t verts[5]; + + verts[0].Init( Vector2D( 0, 0 ) ); + verts[1].Init( Vector2D( wide-1, 0 ) ); + verts[2].Init( Vector2D( wide-1, tall-halfheight ) ); + verts[3].Init( Vector2D( wide-halfheight, tall-1 ) ); + verts[4].Init( Vector2D( 0, tall-1 ) ); + + surface()->DrawTexturedPolygon(5, verts); + + surface()->DrawSetTexture(0); +} + +//=============================================== +// CDODButton - shaped button +//=============================================== +void CDODButton::PaintBackground() +{ + int wide, tall; + GetSize(wide,tall); + DrawShapedBackground( 0, 0, wide, tall, GetBgColor() ); +} + +void CDODButton::PaintBorder() +{ + int wide, tall; + GetSize(wide,tall); + DrawShapedBorder( 0, 0, wide, tall, GetFgColor() ); +} + +//=============================================== +// CDODProgressBar - used for weapon stat bars +//=============================================== +void CDODProgressBar::ApplySchemeSettings(IScheme *pScheme) +{ + BaseClass::ApplySchemeSettings(pScheme); + + SetFgColor( GetSchemeColor("ClassMenuLight", pScheme ) ); + SetBgColor( GetSchemeColor("ClassMenuDark", pScheme ) ); + SetBarInset(0); + SetSegmentInfo( 0, 1 ); + SetBorder(NULL); +}
\ No newline at end of file diff --git a/game/client/dod/VGUI/dodbutton.h b/game/client/dod/VGUI/dodbutton.h new file mode 100644 index 0000000..dd1870b --- /dev/null +++ b/game/client/dod/VGUI/dodbutton.h @@ -0,0 +1,88 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef DOD_BUTTON_H +#define DOD_BUTTON_H + +#include "mouseoverpanelbutton.h" +#include "KeyValues.h" +#include <vgui/IScheme.h> +#include <vgui_controls/ProgressBar.h> +#include <vgui_controls/EditablePanel.h> + +// a button with the bottom right corner cut out + +/* + +|``````````````| +| PRESS ME! | +|_____________/ + +*/ + +class CDODButtonShape +{ +public: + CDODButtonShape() + { + m_iWhiteTexture = -1; + } + + void DrawShapedBorder( int x, int y, int wide, int tall, Color fgcolor ); + void DrawShapedBackground( int x, int y, int wide, int tall, Color bgcolor ); + +protected: + int m_iWhiteTexture; +}; + +class CDODButton : public vgui::Button, public CDODButtonShape +{ +private: + DECLARE_CLASS_SIMPLE( CDODButton, vgui::Button ); + +public: + CDODButton(vgui::Panel *parent ) : + vgui::Button( parent, "DODButton", "" ) + { + } + +protected: + virtual void PaintBackground(); + virtual void PaintBorder(); +}; + +class CDODClassInfoPanel : public vgui::EditablePanel +{ +private: + DECLARE_CLASS_SIMPLE( CDODClassInfoPanel, vgui::EditablePanel ); + +public: + CDODClassInfoPanel( vgui::Panel *parent, const char *panelName ) : vgui::EditablePanel( parent, panelName ) + { + } + + virtual void ApplySchemeSettings( vgui::IScheme *pScheme ); + virtual vgui::Panel *CreateControlByName( const char *controlName ); +}; + + +// Solid coloured progress bar with no border +class CDODProgressBar : public vgui::ProgressBar +{ +private: + DECLARE_CLASS_SIMPLE( CDODProgressBar, vgui::ProgressBar ); + +public: + CDODProgressBar(vgui::Panel *parent) : vgui::ProgressBar( parent, "statBar" ) + { + } + +protected: + virtual void ApplySchemeSettings(vgui::IScheme *pScheme); +}; + +#endif //DOD_BUTTON_H
\ No newline at end of file diff --git a/game/client/dod/VGUI/dodclassmenu.cpp b/game/client/dod/VGUI/dodclassmenu.cpp new file mode 100644 index 0000000..a32d1af --- /dev/null +++ b/game/client/dod/VGUI/dodclassmenu.cpp @@ -0,0 +1,353 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#include "cbase.h" +#include "dodclassmenu.h" + +#include <KeyValues.h> +#include <filesystem.h> +#include <vgui_controls/Button.h> +#include <vgui_controls/RichText.h> +#include <vgui/IVGui.h> + +#include "hud.h" // for gEngfuncs +#include "c_dod_player.h" +#include "c_dod_team.h" + +#include "imagemouseoverbutton.h" + +#include "dodmouseoverpanelbutton.h" +#include "dodrandombutton.h" +#include "IconPanel.h" + +#include "IGameUIFuncs.h" // for key bindings + +extern IGameUIFuncs *gameuifuncs; // for key binding details + +using namespace vgui; + +extern ConVar hud_classautokill; +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +Panel *CDODClassInfoPanel::CreateControlByName( const char *controlName ) +{ + if( !Q_stricmp( "ProgressBar", controlName ) ) + { + return new CDODProgressBar(this); + } + else if ( !Q_stricmp( "CIconPanel", controlName ) ) + { + return new CIconPanel(this, "icon_panel"); + } + else + { + return BaseClass::CreateControlByName( controlName ); + } +} + +void CDODClassInfoPanel::ApplySchemeSettings( IScheme *pScheme ) +{ + RichText *pClassInfo = dynamic_cast<RichText*>(FindChildByName("classInfo")); + + if ( pClassInfo ) + { + pClassInfo->SetBorder(pScheme->GetBorder("NoBorder")); + pClassInfo->SetBgColor(pScheme->GetColor("Blank", Color(0,0,0,0))); + } + + BaseClass::ApplySchemeSettings( pScheme ); +} + +CDODClassMenu::CDODClassMenu(IViewPort *pViewPort) : CClassMenu(pViewPort) +{ + m_mouseoverButtons.RemoveAll(); + m_iClassMenuKey = BUTTON_CODE_INVALID; + m_pInitialButton = NULL; + + m_pBackground = SETUP_PANEL( new CDODMenuBackground( this ) ); + + m_pClassInfoPanel = new CDODClassInfoPanel( this, "ClassInfoPanel" ); + + vgui::ivgui()->AddTickSignal( GetVPanel() ); + + m_iActivePlayerClass = -1; + m_iLastPlayerClassCount = -1; + + m_pClassNumLabel[0] = new Label( this, "class_1_num", "" ); + m_pClassNumLabel[1] = new Label( this, "class_2_num", "" ); + m_pClassNumLabel[2] = new Label( this, "class_3_num", "" ); + m_pClassNumLabel[3] = new Label( this, "class_4_num", "" ); + m_pClassNumLabel[4] = new Label( this, "class_5_num", "" ); + m_pClassNumLabel[5] = new Label( this, "class_6_num", "" ); + + m_pClassFullLabel[0] = new Label( this, "class_1_full", "" ); + m_pClassFullLabel[1] = new Label( this, "class_2_full", "" ); + m_pClassFullLabel[2] = new Label( this, "class_3_full", "" ); + m_pClassFullLabel[3] = new Label( this, "class_4_full", "" ); + m_pClassFullLabel[4] = new Label( this, "class_5_full", "" ); + m_pClassFullLabel[5] = new Label( this, "class_6_full", "" ); + + m_pSuicideOption = new CheckButton( this, "suicide_option", "Sky is blue?" ); +} + +void CDODClassMenu::ShowPanel( bool bShow ) +{ + if ( bShow ) + { + engine->CheckPoint( "ClassMenu" ); + + m_iClassMenuKey = gameuifuncs->GetButtonCodeForBind( "changeclass" ); + + m_pSuicideOption->SetSelected( hud_classautokill.GetBool() ); + } + + for( int i = 0; i< GetChildCount(); i++ ) + { + CImageMouseOverButton<CDODClassInfoPanel> *button = + dynamic_cast<CImageMouseOverButton<CDODClassInfoPanel> *>(GetChild(i)); + + if ( button ) + { + if( button == m_pInitialButton && bShow == true ) + button->ShowPage(); + else + button->HidePage(); + } + } + + CDODRandomButton<CDODClassInfoPanel> *pRandom = + dynamic_cast<CDODRandomButton<CDODClassInfoPanel> *>( FindChildByName("random") ); + + if ( pRandom ) + pRandom->HidePage(); + + // recalc position of checkbox, since it doesn't do right alignment + m_pSuicideOption->SizeToContents(); + + int x, y, wide, tall; + m_pSuicideOption->GetBounds( x, y, wide, tall ); + + int parentW, parentH; + GetSize( parentW, parentH ); + + x = parentW / 2; // - wide; + m_pSuicideOption->SetPos( x, y ); + + BaseClass::ShowPanel( bShow ); +} + +void CDODClassMenu::OnKeyCodePressed( KeyCode code ) +{ +#ifdef REFRESH_CLASSMENU_TOOL + + if ( code == KEY_PAD_MULTIPLY ) + { + OnRefreshClassMenu(); + } +#endif + + if ( m_iClassMenuKey != BUTTON_CODE_INVALID && m_iClassMenuKey == code ) + { + ShowPanel( false ); + } + else + { + BaseClass::OnKeyCodePressed( code ); + } +} + +void CDODClassMenu::Update() +{ + C_DODPlayer *pPlayer = C_DODPlayer::GetLocalDODPlayer(); + + if ( pPlayer && pPlayer->m_Shared.DesiredPlayerClass() == PLAYERCLASS_UNDEFINED ) + { + SetVisibleButton( "CancelButton", false ); + } + else + { + SetVisibleButton( "CancelButton", true ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +Panel *CDODClassMenu::CreateControlByName( const char *controlName ) +{ + if ( !Q_stricmp( "DODMouseOverPanelButton", controlName ) ) + { + return new CDODMouseOverButton<CDODClassInfoPanel>( this, NULL, m_pClassInfoPanel ); + } + else if( !Q_stricmp( "DODButton", controlName ) ) + { + return new CDODButton(this); + } + else if( !Q_stricmp( "DODRandomButton", controlName ) ) + { + return new CDODRandomButton<CDODClassInfoPanel>(this, NULL, m_pClassInfoPanel ); + } + else if ( !Q_stricmp( "ImageButton", controlName ) ) + { + CImageMouseOverButton<CDODClassInfoPanel> *newButton = new CImageMouseOverButton<CDODClassInfoPanel>( this, NULL, m_pClassInfoPanel ); + + if( !m_pInitialButton ) + { + m_pInitialButton = newButton; + } + + return newButton; + } + else if ( !Q_stricmp( "CIconPanel", controlName ) ) + { + return new CIconPanel(this, "icon_panel"); + } + else + { + return BaseClass::CreateControlByName( controlName ); + } +} + +//----------------------------------------------------------------------------- +// Catch the mouseover event and set the active class +//----------------------------------------------------------------------------- +void CDODClassMenu::OnShowPage( const char *pagename ) +{ + // change which class we are counting based on class name + + // turn the button name into a classname + + char buf[64]; + + Q_snprintf( buf, sizeof(buf), "cls_%s", pagename ); + + C_DODTeam *pTeam = dynamic_cast<C_DODTeam *>( GetGlobalTeam(GetTeamNumber()) ); + + if( !pTeam ) + return; + + // Pull the index of this class via IsClassOnTeam + if ( !pTeam->IsClassOnTeam( buf, m_iActivePlayerClass ) ) + { + Assert( !"bad class name on class button" ); + } + + UpdateNumClassLabel(); +} + +//----------------------------------------------------------------------------- +// Draw nothing +//----------------------------------------------------------------------------- +void CDODClassMenu::PaintBackground( void ) +{ +} + +//----------------------------------------------------------------------------- +// Do things that should be done often, eg number of players in the +// selected class +//----------------------------------------------------------------------------- +void CDODClassMenu::OnTick( void ) +{ + //When a player changes teams, their class and team values don't get here + //necessarily before the command to update the class menu. This leads to the cancel button + //being visible and people cancelling before they have a class. check for class == DOD_CLASS_NONE and if so + //hide the cancel button + + if ( !IsVisible() ) + return; + + C_DODPlayer *pPlayer = C_DODPlayer::GetLocalDODPlayer(); + + if( pPlayer && pPlayer->m_Shared.PlayerClass() == PLAYERCLASS_UNDEFINED ) + { + SetVisibleButton("CancelButton", false); + } + + UpdateNumClassLabel(); + + BaseClass::OnTick(); +} + +void CDODClassMenu::UpdateNumClassLabel( void ) +{ + int iClassCount[NUM_CLASSES]; + // Initialize to zero. Was previously used uninitialized. + int iClassLimit[NUM_CLASSES] = {}; + + // count how many of this class there are + C_DODTeam *pTeam = dynamic_cast<C_DODTeam *>( GetGlobalTeam(GetTeamNumber()) ); + + if ( !pTeam ) + return; + + char buf[16]; + + for( int i=0;i<NUM_CLASSES;i++ ) + { + iClassCount[i] = pTeam->CountPlayersOfThisClass( i ); + + if ( !m_pClassNumLabel[i] || !m_pClassFullLabel[i] ) + continue; + + if ( pTeam->IsClassOnTeam( i ) ) + { + // FIXME - store pointers to these cvars + const CDODPlayerClassInfo &pClassInfo = pTeam->GetPlayerClassInfo( i ); + ConVar *pLimitCvar = ( ConVar * )cvar->FindVar( pClassInfo.m_szLimitCvar ); + + if ( pLimitCvar ) + iClassLimit[i] = MIN( 32, pLimitCvar->GetInt() ); + } + + if ( iClassLimit[i] < 0 || iClassCount[i] < iClassLimit[i] ) + m_pClassFullLabel[i]->SetVisible( false ); + else + m_pClassFullLabel[i]->SetVisible( true ); + + if ( iClassLimit[i] > -1 ) + { + // draw "3 / 4" + Q_snprintf( buf, sizeof(buf), "%d / %d", iClassCount[i], iClassLimit[i] ); + } + else + { + // just "3" + Q_snprintf( buf, sizeof(buf), "x %d", iClassCount[i] ); + } + + m_pClassNumLabel[i]->SetText( buf ); + } +} + +void CDODClassMenu::SetVisible( bool state ) +{ + BaseClass::SetVisible( state ); +} + +void CDODClassMenu::OnSuicideOptionChanged( vgui::Panel *Panel ) +{ + hud_classautokill.SetValue( m_pSuicideOption->IsSelected() ); +} + +#ifdef REFRESH_CLASSMENU_TOOL + + void CDODClassMenu::OnRefreshClassMenu( void ) + { + for( int i = 0; i< GetChildCount(); i++ ) + { + CImageMouseOverButton<CDODClassInfoPanel> *button = + dynamic_cast<CImageMouseOverButton<CDODClassInfoPanel> *>(GetChild(i)); + + if ( button ) + { + button->RefreshClassPage(); + } + } + } + +#endif diff --git a/game/client/dod/VGUI/dodclassmenu.h b/game/client/dod/VGUI/dodclassmenu.h new file mode 100644 index 0000000..ba25347 --- /dev/null +++ b/game/client/dod/VGUI/dodclassmenu.h @@ -0,0 +1,129 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef DODCLASSMENU_H +#define DODCLASSMENU_H +#ifdef _WIN32 +#pragma once +#endif + +#include <classmenu.h> +#include <vgui_controls/EditablePanel.h> +#include <filesystem.h> +#include <dod_shareddefs.h> +#include "cbase.h" +#include "dod_gamerules.h" +#include "dodmenubackground.h" +#include "dodbutton.h" +#include "imagemouseoverbutton.h" +#include "IconPanel.h" +#include <vgui_controls/CheckButton.h> + +using namespace vgui; + +#define NUM_CLASSES 6 + +class CDODClassMenu : public CClassMenu +{ +private: + DECLARE_CLASS_SIMPLE( CDODClassMenu, CClassMenu ); + +public: + CDODClassMenu(IViewPort *pViewPort); + + virtual void Update( void ); + virtual Panel *CreateControlByName( const char *controlName ); + virtual void OnTick( void ); + virtual void PaintBackground( void ); + virtual void OnKeyCodePressed(KeyCode code); + virtual void SetVisible( bool state ); + + MESSAGE_FUNC_CHARPTR( OnShowPage, "ShowPage", page ); + + virtual void ShowPanel(bool bShow); + + void UpdateNumClassLabel( void ); + + virtual int GetTeamNumber( void ) = 0; + +#ifdef REFRESH_CLASSMENU_TOOL + MESSAGE_FUNC( OnRefreshClassMenu, "refresh_classes" ); +#endif + + MESSAGE_FUNC_PTR( OnSuicideOptionChanged, "CheckButtonChecked", panel ); + +private: + CDODClassInfoPanel *m_pClassInfoPanel; + CDODMenuBackground *m_pBackground; + CheckButton *m_pSuicideOption; + + CImageMouseOverButton<CDODClassInfoPanel> *m_pInitialButton; + int m_iActivePlayerClass; + int m_iLastPlayerClassCount; + int m_iLastClassLimit; + + ButtonCode_t m_iClassMenuKey; + + vgui::Label *m_pClassNumLabel[NUM_CLASSES]; + vgui::Label *m_pClassFullLabel[NUM_CLASSES]; +}; + +//----------------------------------------------------------------------------- +// Purpose: Draws the U.S. class menu +//----------------------------------------------------------------------------- + +class CDODClassMenu_Allies : public CDODClassMenu +{ +private: + DECLARE_CLASS_SIMPLE( CDODClassMenu_Allies, CDODClassMenu ); + +public: + CDODClassMenu_Allies(IViewPort *pViewPort) : BaseClass(pViewPort) + { + LoadControlSettings( "Resource/UI/ClassMenu_Allies.res" ); + } + + virtual const char *GetName( void ) + { + return PANEL_CLASS_ALLIES; + } + + virtual int GetTeamNumber( void ) + { + return TEAM_ALLIES; + } + +}; + + +//----------------------------------------------------------------------------- +// Purpose: Draws the Wermacht class menu +//----------------------------------------------------------------------------- + +class CDODClassMenu_Axis : public CDODClassMenu +{ +private: + DECLARE_CLASS_SIMPLE( CDODClassMenu_Axis, CDODClassMenu ); + +public: + CDODClassMenu_Axis(IViewPort *pViewPort) : BaseClass(pViewPort) + { + LoadControlSettings( "Resource/UI/ClassMenu_Axis.res" ); + } + + virtual const char *GetName( void ) + { + return PANEL_CLASS_AXIS; + } + + virtual int GetTeamNumber( void ) + { + return TEAM_AXIS; + } +}; + +#endif // DODCLASSMENU_H diff --git a/game/client/dod/VGUI/dodclientscoreboard.cpp b/game/client/dod/VGUI/dodclientscoreboard.cpp new file mode 100644 index 0000000..d26351d --- /dev/null +++ b/game/client/dod/VGUI/dodclientscoreboard.cpp @@ -0,0 +1,621 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#include "cbase.h" +#include "hud.h" +#include "dodclientscoreboard.h" +#include "c_team.h" +#include "c_dod_team.h" +#include "c_dod_playerresource.h" +#include "c_dod_player.h" +#include "dod_gamerules.h" +#include "backgroundpanel.h" + +#include <KeyValues.h> + +#include <vgui/IScheme.h> +#include <vgui/ILocalize.h> +#include <vgui/ISurface.h> +#include <vgui/IVGui.h> +#include <vgui_controls/SectionedListPanel.h> +#include <vgui_controls/ImageList.h> + +#include "voice_status.h" + +using namespace vgui; + +//----------------------------------------------------------------------------- +// Purpose: Constructor +//----------------------------------------------------------------------------- +CDODClientScoreBoardDialog::CDODClientScoreBoardDialog( IViewPort *pViewPort ):CClientScoreBoardDialog( pViewPort ) +{ + m_pPlayerListAllies = new SectionedListPanel( this, "PlayerListAllies" ); + m_pPlayerListAxis = new SectionedListPanel( this, "PlayerListAxis" ); + + m_iImageDead = 0; + m_iImageDominated = 0; + m_iImageNemesis = 0; + + m_pAllies_PlayerCount = new Label( this, "Allies_PlayerCount", "" ); + m_pAllies_Score = new Label( this, "Allies_Score", "" ); + m_pAllies_Kills = new Label( this, "Allies_Kills", "" ); + m_pAllies_Deaths = new Label( this, "Allies_Deaths", "" ); + m_pAllies_Ping = new Label( this, "Allies_Ping", "" ); + + m_pAxis_PlayerCount = new Label( this, "Axis_PlayerCount", "" ); + m_pAxis_Score = new Label( this, "Axis_Score", "" ); + m_pAxis_Kills = new Label( this, "Axis_Kills", "" ); + m_pAxis_Deaths = new Label( this, "Axis_Deaths", "" ); + m_pAxis_Ping = new Label( this, "Axis_Ping", "" ); + + ListenForGameEvent( "server_spawn" ); + SetDialogVariable( "server", "" ); + SetVisible( false ); +} + +//----------------------------------------------------------------------------- +// Purpose: Destructor +//----------------------------------------------------------------------------- +CDODClientScoreBoardDialog::~CDODClientScoreBoardDialog() +{ +} + +//----------------------------------------------------------------------------- +// Purpose: Paint background for rounded corners +//----------------------------------------------------------------------------- +void CDODClientScoreBoardDialog::PaintBackground() +{ + int wide, tall; + GetSize( wide, tall ); + + DrawRoundedBackground( m_bgColor, wide, tall ); +} + +//----------------------------------------------------------------------------- +// Purpose: Paint border for rounded corners +//----------------------------------------------------------------------------- +void CDODClientScoreBoardDialog::PaintBorder() +{ + int wide, tall; + GetSize( wide, tall ); + + DrawRoundedBorder( m_borderColor, wide, tall ); +} + +//----------------------------------------------------------------------------- +// Purpose: Apply scheme settings +//----------------------------------------------------------------------------- +void CDODClientScoreBoardDialog::ApplySchemeSettings( vgui::IScheme *pScheme ) +{ + BaseClass::ApplySchemeSettings( pScheme ); + + LoadControlSettings( "Resource/UI/scoreboard.res" ); + + m_bgColor = GetSchemeColor( "SectionedListPanel.BgColor", GetBgColor(), pScheme ); + m_borderColor = pScheme->GetColor( "Yellow", Color( 251, 206, 60, 255 ) ); + + SetBgColor( Color( 0, 0, 0, 0 ) ); + SetBorder( pScheme->GetBorder( "BaseBorder" ) ); + + if ( m_pImageList ) + { + m_iImageDead = m_pImageList->AddImage( scheme()->GetImage( "../hud/leaderboard_dead", true ) ); + m_iImageDominated = m_pImageList->AddImage( scheme()->GetImage( "../hud/leaderboard_dominated", true ) ); + m_iImageNemesis = m_pImageList->AddImage( scheme()->GetImage( "../hud/leaderboard_nemesis", true ) ); + + // resize the images to our resolution + for (int i = 1; i < m_pImageList->GetImageCount(); i++ ) + { + int wide = 13, tall = 13; + m_pImageList->GetImage(i)->SetSize(scheme()->GetProportionalScaledValueEx( GetScheme(), wide ), scheme()->GetProportionalScaledValueEx( GetScheme(),tall ) ); + } + } + + if ( m_pPlayerListAllies ) + { + m_pPlayerListAllies->SetImageList( m_pImageList, false ); + m_pPlayerListAllies->SetBgColor( Color( 0, 0, 0, 0 ) ); + m_pPlayerListAllies->SetBorder( NULL ); + m_pPlayerListAllies->SetVisible( true ); + } + + if ( m_pPlayerListAxis ) + { + m_pPlayerListAxis->SetImageList( m_pImageList, false ); + m_pPlayerListAxis->SetBgColor( Color( 0, 0, 0, 0 ) ); + m_pPlayerListAxis->SetBorder( NULL ); + m_pPlayerListAxis->SetVisible( true ); + } + + // turn off the default player list since we have our own + if ( m_pPlayerList ) + { + m_pPlayerList->SetVisible( false ); + } + + if ( m_pAllies_PlayerCount && m_pAllies_Score && m_pAllies_Kills && m_pAllies_Deaths && m_pAllies_Ping ) + { + m_pAllies_PlayerCount->SetFgColor( COLOR_DOD_GREEN ); + m_pAllies_Score->SetFgColor( COLOR_DOD_GREEN ); + m_pAllies_Kills->SetFgColor( COLOR_DOD_GREEN ); + m_pAllies_Deaths->SetFgColor( COLOR_DOD_GREEN ); + m_pAllies_Ping->SetFgColor( COLOR_DOD_GREEN ); + } + + if ( m_pAxis_PlayerCount && m_pAxis_Score && m_pAxis_Kills && m_pAxis_Deaths && m_pAxis_Ping ) + { + m_pAxis_PlayerCount->SetFgColor( COLOR_DOD_RED ); + m_pAxis_Score->SetFgColor( COLOR_DOD_RED ); + m_pAxis_Kills->SetFgColor( COLOR_DOD_RED ); + m_pAxis_Deaths->SetFgColor( COLOR_DOD_RED ); + m_pAxis_Ping->SetFgColor( COLOR_DOD_RED ); + } + + SetVisible( false ); + Reset(); +} + +//----------------------------------------------------------------------------- +// Purpose: Resets the scoreboard panel +//----------------------------------------------------------------------------- +void CDODClientScoreBoardDialog::Reset() +{ + InitPlayerList( m_pPlayerListAllies, TEAM_ALLIES ); + InitPlayerList( m_pPlayerListAxis, TEAM_AXIS ); +} + +//----------------------------------------------------------------------------- +// Purpose: Sorts players +//----------------------------------------------------------------------------- +bool CDODClientScoreBoardDialog::DODPlayerSortFunc( vgui::SectionedListPanel *list, int itemID1, int itemID2 ) +{ + KeyValues *it1 = list->GetItemData( itemID1 ); + KeyValues *it2 = list->GetItemData( itemID2 ); + Assert( it1 && it2 ); + + // first compare score + int v1 = it1->GetInt( "score" ); + int v2 = it2->GetInt( "score" ); + if ( v1 > v2 ) + return true; + else if ( v1 < v2 ) + return false; + + // then compare frags + v1 = it1->GetInt( "frags" ); + v2 = it2->GetInt( "frags" ); + if ( v1 > v2 ) + return true; + else if ( v1 < v2 ) + return false; + + // next compare deaths + v1 = it1->GetInt( "deaths" ); + v2 = it2->GetInt( "deaths" ); + if ( v1 > v2 ) + return false; + else if ( v1 < v2 ) + return true; + + // if score and deaths are the same, use player index to get deterministic sort + int iPlayerIndex1 = it1->GetInt( "playerIndex" ); + int iPlayerIndex2 = it2->GetInt( "playerIndex" ); + return ( iPlayerIndex1 > iPlayerIndex2 ); +} + +//----------------------------------------------------------------------------- +// Purpose: Inits the player list in a list panel +//----------------------------------------------------------------------------- +void CDODClientScoreBoardDialog::InitPlayerList( SectionedListPanel *pPlayerList, int teamNumber ) +{ + pPlayerList->SetVerticalScrollbar( false ); + pPlayerList->RemoveAll(); + pPlayerList->RemoveAllSections(); + pPlayerList->AddSection( 0, "Players", DODPlayerSortFunc ); + pPlayerList->SetSectionAlwaysVisible( 0, true ); + pPlayerList->SetSectionFgColor( 0, Color( 255, 255, 255, 255 ) ); + pPlayerList->SetBgColor( Color( 0, 0, 0, 0 ) ); + pPlayerList->SetBorder( NULL ); + + // set the section to have the team color + if ( teamNumber && GameResources() ) + { + pPlayerList->SetSectionFgColor( 0, GameResources()->GetTeamColor( teamNumber ) ); + } + + // Avatars are always displayed at 32x32 regardless of resolution + pPlayerList->AddColumnToSection( 0, "avatar", "", SectionedListPanel::COLUMN_IMAGE | SectionedListPanel::COLUMN_CENTER, m_iProportionalAvatarWidth ); + pPlayerList->AddColumnToSection( 0, "name", "", 0, m_iNameWidth ); + pPlayerList->AddColumnToSection( 0, "status", "", SectionedListPanel::COLUMN_IMAGE | SectionedListPanel::COLUMN_CENTER, m_iStatusWidth ); + pPlayerList->AddColumnToSection( 0, "class", "", 0, m_iClassWidth ); + pPlayerList->AddColumnToSection( 0, "score", "", SectionedListPanel::COLUMN_RIGHT, m_iScoreWidth ); + pPlayerList->AddColumnToSection( 0, "frags", "", SectionedListPanel::COLUMN_RIGHT, m_iFragsWidth ); + pPlayerList->AddColumnToSection( 0, "deaths", "", SectionedListPanel::COLUMN_RIGHT, m_iDeathWidth ); + pPlayerList->AddColumnToSection( 0, "ping", "", SectionedListPanel::COLUMN_RIGHT, m_iPingWidth ); +} + +//----------------------------------------------------------------------------- +// Purpose: Updates the dialog +//----------------------------------------------------------------------------- +void CDODClientScoreBoardDialog::Update() +{ + UpdateTeamInfo(); + UpdatePlayerList(); + UpdateSpectatorList(); + MoveToCenterOfScreen(); + + // update every second + m_fNextUpdateTime = gpGlobals->curtime + 1.0f; +} + +//----------------------------------------------------------------------------- +// Purpose: Updates information about teams +//----------------------------------------------------------------------------- +void CDODClientScoreBoardDialog::UpdateTeamInfo() +{ + // update the team sections in the scoreboard + for ( int teamIndex = TEAM_ALLIES; teamIndex <= TEAM_AXIS; teamIndex++ ) + { + wchar_t *teamName = NULL;; + C_DODTeam *team = dynamic_cast<C_DODTeam *>( GetGlobalTeam(teamIndex) ); + if ( team ) + { + // choose dialog variables to set depending on team + const char *pDialogVarTeamScore = NULL; + const char *pDialogVarTeamPlayerCount = NULL; + const char *pDialogVarTeamPing = NULL; + const char *pDialogVarTeamDeaths = NULL; + const char *pDialogVarTeamFrags = NULL; + switch ( teamIndex ) + { + case TEAM_ALLIES: + teamName = g_pVGuiLocalize->Find( "#Teamname_Allies" ); + pDialogVarTeamScore = "allies_teamscore"; + pDialogVarTeamPlayerCount = "allies_teamplayercount"; + pDialogVarTeamPing = "allies_teamping"; + pDialogVarTeamDeaths = "allies_teamdeaths"; + pDialogVarTeamFrags = "allies_teamfrags"; + break; + case TEAM_AXIS: + teamName = g_pVGuiLocalize->Find( "#Teamname_Axis" ); + pDialogVarTeamScore = "axis_teamscore"; + pDialogVarTeamPlayerCount = "axis_teamplayercount"; + pDialogVarTeamPing = "axis_teamping"; + pDialogVarTeamDeaths = "axis_teamdeaths"; + pDialogVarTeamFrags = "axis_teamfrags"; + break; + default: + Assert( false ); + break; + } + + // update team name + wchar_t name[64]; + wchar_t string1[1024]; + wchar_t wNumPlayers[6]; + _snwprintf( wNumPlayers, ARRAYSIZE( wNumPlayers ), L"%i", team->Get_Number_Players() ); + if ( !teamName && team ) + { + g_pVGuiLocalize->ConvertANSIToUnicode( team->Get_Name(), name, sizeof( name ) ); + teamName = name; + } + if ( team->Get_Number_Players() == 1 ) + { + g_pVGuiLocalize->ConstructString( string1, sizeof(string1), g_pVGuiLocalize->Find( "#scoreboard_Player" ), 2, teamName, wNumPlayers ); + } + else + { + g_pVGuiLocalize->ConstructString( string1, sizeof(string1), g_pVGuiLocalize->Find( "#scoreboard_Players" ), 2, teamName, wNumPlayers ); + } + + // set # of players for team in dialog + SetDialogVariable( pDialogVarTeamPlayerCount, string1 ); + + // Rounds won ( + tick ) + wchar_t wTeamScore[128]; + wchar_t wRoundsWon[8]; + wchar_t wTickScore[8]; + _snwprintf( wRoundsWon, ARRAYSIZE( wRoundsWon ), L"%i", team->GetRoundsWon() ); + _snwprintf( wTickScore, ARRAYSIZE( wTickScore ), L"%i", team->Get_Score() ); + g_pVGuiLocalize->ConstructString( wTeamScore, sizeof(wTeamScore), g_pVGuiLocalize->Find( "#scoreboard_teamscore" ), 2, wRoundsWon, wTickScore ); + + // set team score in dialog + SetDialogVariable( pDialogVarTeamScore, wTeamScore ); + + int kills = 0; + int deaths = 0; + int pingsum = 0; + int numcounted = 0; + int ping; + + for( int playerIndex = 1 ; playerIndex <= MAX_PLAYERS; playerIndex++ ) + { + if( g_PR->IsConnected( playerIndex ) && g_PR->GetTeam( playerIndex ) == teamIndex ) + { + ping = g_PR->GetPing( playerIndex ); + kills += g_PR->GetPlayerScore( playerIndex ); + deaths += g_PR->GetDeaths( playerIndex ); + + if ( ping >= 1 ) + { + pingsum += ping; + numcounted++; + } + } + } + + if ( numcounted > 0 ) + { + int ping = (int)( (float)pingsum / (float)numcounted ); + SetDialogVariable( pDialogVarTeamPing, ping ); + } + else + { + SetDialogVariable( pDialogVarTeamPing, "" ); + } + + SetDialogVariable( pDialogVarTeamFrags, kills ); + SetDialogVariable( pDialogVarTeamDeaths, deaths ); + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: Updates the player list +//----------------------------------------------------------------------------- +void CDODClientScoreBoardDialog::UpdatePlayerList() +{ + m_pPlayerListAllies->RemoveAll(); + m_pPlayerListAxis->RemoveAll(); + + C_DOD_PlayerResource *dod_PR = dynamic_cast<C_DOD_PlayerResource *>( g_PR ); + if ( !dod_PR ) + return; + + C_DODPlayer *pLocalPlayer = C_DODPlayer::GetLocalDODPlayer(); + if ( !pLocalPlayer ) + return; + + int iLocalPlayerIndex = GetLocalPlayerIndex(); + + for( int playerIndex = 1 ; playerIndex <= MAX_PLAYERS; playerIndex++ ) + { + if( g_PR->IsConnected( playerIndex ) ) + { + SectionedListPanel *pPlayerList = NULL; + switch ( g_PR->GetTeam( playerIndex ) ) + { + case TEAM_ALLIES: + pPlayerList = m_pPlayerListAllies; + break; + case TEAM_AXIS: + pPlayerList = m_pPlayerListAxis; + break; + } + + if ( pPlayerList == NULL ) + { + continue; + } + + KeyValues *pKeyValues = new KeyValues( "data" ); + GetPlayerScoreInfo( playerIndex, pKeyValues ); + + if ( pLocalPlayer->m_Shared.IsPlayerDominatingMe( playerIndex ) ) + { + // if local player is dominated by this player, show a nemesis icon + pKeyValues->SetString( "class", "#Scoreboard_Nemesis" ); + pKeyValues->SetInt( "status", m_iImageNemesis ); + } + else if ( pLocalPlayer->m_Shared.IsPlayerDominated( playerIndex) ) + { + // if this player is dominated by the local player, show the domination icon + pKeyValues->SetString( "class", "#Scoreboard_Dominated" ); + pKeyValues->SetInt( "status", m_iImageDominated ); + } + + int itemID = pPlayerList->AddItem( 0, pKeyValues ); + Color clr = g_PR->GetTeamColor( g_PR->GetTeam( playerIndex ) ); + pPlayerList->SetItemFgColor( itemID, clr ); + + if ( playerIndex == iLocalPlayerIndex ) + { + pPlayerList->SetSelectedItem( itemID ); + } + + pKeyValues->deleteThis(); + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: Updates the spectator list +//----------------------------------------------------------------------------- +void CDODClientScoreBoardDialog::UpdateSpectatorList() +{ + char szSpectatorList[512] = "" ; + int nSpectators = 0; + for( int playerIndex = 1 ; playerIndex <= MAX_PLAYERS; playerIndex++ ) + { + if ( ShouldShowAsSpectator( playerIndex ) ) + { + if ( nSpectators > 0 ) + { + Q_strncat( szSpectatorList, ", ", ARRAYSIZE( szSpectatorList ) ); + } + + Q_strncat( szSpectatorList, g_PR->GetPlayerName( playerIndex ), ARRAYSIZE( szSpectatorList ) ); + nSpectators++; + } + } + + wchar_t wzSpectators[512] = L""; + if ( nSpectators > 0 ) + { + const char *pchFormat = ( 1 == nSpectators ? "#ScoreBoard_Spectator" : "#ScoreBoard_Spectators" ); + + wchar_t wzSpectatorCount[16]; + wchar_t wzSpectatorList[1024]; + _snwprintf( wzSpectatorCount, ARRAYSIZE( wzSpectatorCount ), L"%i", nSpectators ); + g_pVGuiLocalize->ConvertANSIToUnicode( szSpectatorList, wzSpectatorList, sizeof( wzSpectatorList ) ); + g_pVGuiLocalize->ConstructString( wzSpectators, sizeof(wzSpectators), g_pVGuiLocalize->Find( pchFormat), 2, wzSpectatorCount, wzSpectatorList ); + } + + SetDialogVariable( "spectators", wzSpectators ); +} + +//----------------------------------------------------------------------------- +// Purpose: Returns whether the specified player index is a spectator +//----------------------------------------------------------------------------- +bool CDODClientScoreBoardDialog::ShouldShowAsSpectator( int iPlayerIndex ) +{ + C_DOD_PlayerResource *dod_PR = dynamic_cast<C_DOD_PlayerResource *>( g_PR ); + if ( !dod_PR ) + return false; + + // see if player is connected + if ( dod_PR->IsConnected( iPlayerIndex ) ) + { + // either spectator or unassigned team should show in spectator list + int iTeam = dod_PR->GetTeam( iPlayerIndex ); + if ( TEAM_SPECTATOR == iTeam || TEAM_UNASSIGNED == iTeam ) + return true; + } + return false; +} + +//----------------------------------------------------------------------------- +// Purpose: Event handler +//----------------------------------------------------------------------------- +void CDODClientScoreBoardDialog::FireGameEvent( IGameEvent *event ) +{ + const char *type = event->GetName(); + + if ( 0 == Q_strcmp( type, "server_spawn" ) ) + { + // set server name in scoreboard + const char *hostname = event->GetString( "hostname" ); + wchar_t wzHostName[256]; + wchar_t wzServerLabel[256]; + g_pVGuiLocalize->ConvertANSIToUnicode( hostname, wzHostName, sizeof( wzHostName ) ); + g_pVGuiLocalize->ConstructString( wzServerLabel, sizeof(wzServerLabel), g_pVGuiLocalize->Find( "#Scoreboard_Server" ), 1, wzHostName ); + SetDialogVariable( "server", wzServerLabel ); + } + + if( IsVisible() ) + { + Update(); + } +} + +//----------------------------------------------------------------------------- +// Purpose: Adds a new row to the scoreboard, from the playerinfo structure +//----------------------------------------------------------------------------- +bool CDODClientScoreBoardDialog::GetPlayerScoreInfo( int playerIndex, KeyValues *kv ) +{ + C_DOD_PlayerResource *dod_PR = dynamic_cast<C_DOD_PlayerResource *>( g_PR ); + if ( !dod_PR ) + return true; + + // Clean up the player name + const char *oldName = g_PR->GetPlayerName( playerIndex ); + int bufsize = strlen( oldName ) * 2 + 1; + char *newName = (char *)_alloca( bufsize ); + UTIL_MakeSafeName( oldName, newName, bufsize ); + kv->SetString( "name", newName ); + + kv->SetInt( "playerIndex", playerIndex ); + kv->SetInt( "score", dod_PR->GetScore( playerIndex ) ); + kv->SetInt( "frags", g_PR->GetPlayerScore( playerIndex ) ); + kv->SetInt( "deaths", g_PR->GetDeaths( playerIndex ) ); + kv->SetString( "class", "" ); + + UpdatePlayerAvatar( playerIndex, kv ); + + if ( g_PR->GetPing( playerIndex ) < 1 ) + { + if ( g_PR->IsFakePlayer( playerIndex ) ) + { + kv->SetString( "ping", "BOT" ); + } + else + { + kv->SetString( "ping", "" ); + } + } + else + { + kv->SetInt( "ping", g_PR->GetPing( playerIndex ) ); + } + + C_DODPlayer *pLocalPlayer = C_DODPlayer::GetLocalDODPlayer(); + if ( !pLocalPlayer ) + return true; + + int team = g_PR->GetTeam( playerIndex ); + int localteam = pLocalPlayer->GetTeamNumber(); + + // If we are on a team that shows class/status, and the local player is allowed to see this information + if( ( localteam == TEAM_SPECTATOR || localteam == TEAM_UNASSIGNED || team == localteam ) ) + { + // class name + if( g_PR->IsConnected( playerIndex ) ) + { + C_DODTeam *pTeam = dynamic_cast<C_DODTeam *>( GetGlobalTeam( team ) ); + + Assert( pTeam ); + + int cls = dod_PR->GetPlayerClass( playerIndex ); + + char szClassName[64]; + szClassName[0] = '\0'; + + if( cls != PLAYERCLASS_UNDEFINED ) + { + const CDODPlayerClassInfo &info = pTeam->GetPlayerClassInfo( cls ); + + g_pVGuiLocalize->ConvertUnicodeToANSI( g_pVGuiLocalize->Find( info.m_szPrintName ), szClassName, sizeof(szClassName) ); + } + + kv->SetString( "class", szClassName ); + } + else + { + Assert(0); + } + + // status + // display whether player is alive or dead (all players see this for all other players on both teams) + kv->SetInt( "status", g_PR->IsAlive( playerIndex ) ? 0 : m_iImageDead ); + } + + if ( g_PR->IsHLTV( playerIndex ) ) + { + // show #spectators in class field, it's transmitted as player's score + char numspecs[32]; + Q_snprintf( numspecs, sizeof( numspecs ), "%i Spectators", m_HLTVSpectators ); + kv->SetString( "class", numspecs ); + } + + return true; +} + +void CDODClientScoreBoardDialog::ShowPanel( bool bShow ) +{ + BaseClass::ShowPanel( bShow ); + + int iRenderGroup = gHUD.LookupRenderGroupIndexByName( "global" ); + + if ( bShow ) + { + gHUD.LockRenderGroup( iRenderGroup ); + } + else + { + gHUD.UnlockRenderGroup( iRenderGroup ); + } +}
\ No newline at end of file diff --git a/game/client/dod/VGUI/dodclientscoreboard.h b/game/client/dod/VGUI/dodclientscoreboard.h new file mode 100644 index 0000000..e70c6ec --- /dev/null +++ b/game/client/dod/VGUI/dodclientscoreboard.h @@ -0,0 +1,79 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef DODCLIENTSCOREBOARDDIALOG_H +#define DODCLIENTSCOREBOARDDIALOG_H +#ifdef _WIN32 +#pragma once +#endif + +#include <clientscoreboarddialog.h> +#include "dod_shareddefs.h" + +//----------------------------------------------------------------------------- +// Purpose: Game ScoreBoard +//----------------------------------------------------------------------------- +class CDODClientScoreBoardDialog : public CClientScoreBoardDialog +{ +private: + DECLARE_CLASS_SIMPLE( CDODClientScoreBoardDialog, CClientScoreBoardDialog ); + +public: + CDODClientScoreBoardDialog( IViewPort *pViewPort ); + ~CDODClientScoreBoardDialog(); + + virtual void Reset(); + virtual void Update(); + + virtual void PaintBackground(); + virtual void PaintBorder(); + virtual void ApplySchemeSettings( vgui::IScheme *pScheme ); + + virtual void ShowPanel( bool bShow ); + +private: + void InitPlayerList( vgui::SectionedListPanel *pPlayerList, int teamNumber ); + void UpdateTeamInfo(); + void UpdatePlayerList(); + void UpdateSpectatorList(); + bool GetPlayerScoreInfo( int playerIndex, KeyValues *outPlayerInfo ); + + bool ShouldShowAsSpectator( int iPlayerIndex ); + void FireGameEvent( IGameEvent *event ); + + static bool DODPlayerSortFunc( vgui::SectionedListPanel *list, int itemID1, int itemID2 ); + + Color m_bgColor; + Color m_borderColor; + + int m_iImageDead; + int m_iImageDominated; + int m_iImageNemesis; + + // player lists + vgui::SectionedListPanel *m_pPlayerListAllies; + vgui::SectionedListPanel *m_pPlayerListAxis; + + CPanelAnimationVarAliasType( int, m_iStatusWidth, "status_width", "35", "proportional_int" ); + CPanelAnimationVarAliasType( int, m_iFragsWidth, "frags_width", "30", "proportional_int" ); + CPanelAnimationVarAliasType( int, m_iProportionalAvatarWidth, "avatar_width_prop", "34", "proportional_int" ); + + vgui::Label *m_pAllies_PlayerCount; + vgui::Label *m_pAllies_Score; + vgui::Label *m_pAllies_Kills; + vgui::Label *m_pAllies_Deaths; + vgui::Label *m_pAllies_Ping; + + vgui::Label *m_pAxis_PlayerCount; + vgui::Label *m_pAxis_Score; + vgui::Label *m_pAxis_Kills; + vgui::Label *m_pAxis_Deaths; + vgui::Label *m_pAxis_Ping; +}; + + +#endif // DODCLIENTSCOREBOARDDIALOG_H diff --git a/game/client/dod/VGUI/dodcornercutpanel.cpp b/game/client/dod/VGUI/dodcornercutpanel.cpp new file mode 100644 index 0000000..bc8dc68 --- /dev/null +++ b/game/client/dod/VGUI/dodcornercutpanel.cpp @@ -0,0 +1,245 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#include "cbase.h" +#include <vgui_controls/EditablePanel.h> +#include <vgui_controls/ImagePanel.h> +#include <vgui/ISurface.h> +#include <KeyValues.h> +#include "dodcornercutpanel.h" + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +CDoDCutEditablePanel::CDoDCutEditablePanel( vgui::Panel *parent, const char *name ) : vgui::EditablePanel( parent, name ) +{ + m_nCornerToCut = DOD_CORNERCUT_PANEL_BOTTOMRIGHT; + m_nCornerCutSize = 1; + + memset( m_szBackgroundTexture, 0, sizeof( m_szBackgroundTexture ) ); + memset( m_szBackgroudColor, 0, sizeof( m_szBackgroudColor ) ); + memset( m_szBorderColor, 0, sizeof( m_szBorderColor ) ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CDoDCutEditablePanel::SetBorder( vgui::IBorder *border ) +{ + BaseClass::SetBorder( border ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CDoDCutEditablePanel::ApplySettings( KeyValues *inResourceData ) +{ + BaseClass::ApplySettings( inResourceData ); + + // check to see if we have a new name assigned + Q_strncpy( m_szBackgroundTexture, inResourceData->GetString( "BackgroundTexture", "vgui/white" ), sizeof( m_szBackgroundTexture ) ); + Q_strncpy( m_szBackgroudColor, inResourceData->GetString( "BackgroundColor", "HudPanelForeground" ), sizeof( m_szBackgroudColor ) ); + Q_strncpy( m_szBorderColor, inResourceData->GetString( "BackgroundBorder", "HudPanelBorder" ), sizeof( m_szBorderColor ) ); + + m_iBackgroundTexture = vgui::surface()->DrawGetTextureId( m_szBackgroundTexture ); + if ( m_iBackgroundTexture == -1 ) + { + m_iBackgroundTexture = vgui::surface()->CreateNewTextureID(); + } + + vgui::surface()->DrawSetTextureFile( m_iBackgroundTexture, m_szBackgroundTexture, true, true ); + + m_nCornerCutSize = inResourceData->GetInt( "CornerCutSize", 1 ); + + // scale the cut size to our screen co-ords + if ( IsProportional() ) + { + m_nCornerCutSize = vgui::scheme()->GetProportionalScaledValueEx( GetScheme(), m_nCornerCutSize ); + } + + const char *pszCorner = inResourceData->GetString( "CornerToCut", "" ); + if ( pszCorner ) + { + if ( !Q_strcmp( pszCorner, "bottom_right" ) ) + { + m_nCornerToCut = DOD_CORNERCUT_PANEL_BOTTOMRIGHT; + } + else if ( !Q_strcmp( pszCorner, "bottom_left" ) ) + { + m_nCornerToCut = DOD_CORNERCUT_PANEL_BOTTOMLEFT; + } + else if ( !Q_strcmp( pszCorner, "top_right" ) ) + { + m_nCornerToCut = DOD_CORNERCUT_PANEL_TOPRIGHT; + + } + else if ( !Q_strcmp( pszCorner, "top_left" ) ) + { + m_nCornerToCut = DOD_CORNERCUT_PANEL_TOPLEFT; + } + } + + InvalidateLayout( false, true ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CDoDCutEditablePanel::GetSettings( KeyValues *outResourceData ) +{ + BaseClass::GetSettings( outResourceData ); + + outResourceData->SetString( "BackgroundTexture", m_szBackgroundTexture); + outResourceData->SetString( "BackgroundColor", m_szBackgroudColor); + outResourceData->SetString( "BackgroundBorder", m_szBorderColor); + outResourceData->SetFloat( "CornerCutSize", m_nCornerCutSize ); + + const char *pszCorner = NULL; + switch( m_nCornerToCut ) + { + case DOD_CORNERCUT_PANEL_TOPLEFT: + pszCorner = "top_left"; + break; + case DOD_CORNERCUT_PANEL_TOPRIGHT: + pszCorner = "top_right"; + break; + case DOD_CORNERCUT_PANEL_BOTTOMLEFT: + pszCorner = "bottom_left"; + break; + case DOD_CORNERCUT_PANEL_BOTTOMRIGHT: + default: + pszCorner = "bottom_right"; + break; + } + outResourceData->SetString( "CornerToCut", pszCorner ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CDoDCutEditablePanel::ApplySchemeSettings( vgui::IScheme *pScheme ) +{ + BaseClass::ApplySchemeSettings( pScheme ); + + SetBorder( NULL ); + + m_clrBackground = pScheme->GetColor( m_szBackgroudColor, GetFgColor() ); + m_clrBorder = pScheme->GetColor( m_szBorderColor, GetBgColor() ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CDoDCutEditablePanel::PaintBackground() +{ + vgui::Vertex_t lineverts[5]; + vgui::Vertex_t verts[5]; + + int nwide, ntall; + GetSize( nwide, ntall ); + + int wide = nwide - 1; // -1 because we can't draw all the way out to the width of our panel (it gets clipped), we can only draw to width - 1 + int tall = ntall - 1; // (same as above) + + switch ( m_nCornerToCut ) + { + case DOD_CORNERCUT_PANEL_TOPLEFT: + verts[0].Init( Vector2D( m_nCornerCutSize, 0 ) ); + verts[1].Init( Vector2D( wide, 0 ) ); + verts[2].Init( Vector2D( wide, tall ) ); + verts[3].Init( Vector2D( 0, tall ) ); + verts[4].Init( Vector2D( 0, m_nCornerCutSize ) ); + + lineverts[0].Init( Vector2D( m_nCornerCutSize-1, 0 ) ); + lineverts[1].Init( Vector2D( wide, 0 ) ); + lineverts[2].Init( Vector2D( wide, tall ) ); + lineverts[3].Init( Vector2D( 0, tall ) ); + lineverts[4].Init( Vector2D( 0, m_nCornerCutSize-1 ) ); + + break; + + case DOD_CORNERCUT_PANEL_TOPRIGHT: + verts[0].Init( Vector2D( 0, 0 ) ); + verts[1].Init( Vector2D( wide - m_nCornerCutSize, 0 ) ); + verts[2].Init( Vector2D( wide, m_nCornerCutSize ) ); + verts[3].Init( Vector2D( wide, tall ) ); + verts[4].Init( Vector2D( 0, tall ) ); + + lineverts[0].Init( Vector2D( 0, 0 ) ); + lineverts[1].Init( Vector2D( wide - m_nCornerCutSize, 0 ) ); + lineverts[2].Init( Vector2D( wide, m_nCornerCutSize ) ); + lineverts[3].Init( Vector2D( wide, tall ) ); + lineverts[4].Init( Vector2D( 0, tall ) ); + + break; + + case DOD_CORNERCUT_PANEL_BOTTOMLEFT: + verts[0].Init( Vector2D( 0, 0 ) ); + verts[1].Init( Vector2D( wide, 0 ) ); + verts[2].Init( Vector2D( wide, tall ) ); + verts[3].Init( Vector2D( m_nCornerCutSize, tall ) ); + verts[4].Init( Vector2D( 0, tall - m_nCornerCutSize ) ); + + lineverts[0].Init( Vector2D( 0, 0 ) ); + lineverts[1].Init( Vector2D( wide, 0 ) ); + lineverts[2].Init( Vector2D( wide, tall ) ); + lineverts[3].Init( Vector2D( m_nCornerCutSize, tall ) ); + lineverts[4].Init( Vector2D( 0, tall - m_nCornerCutSize ) ); + + break; + + case DOD_CORNERCUT_PANEL_BOTTOMRIGHT: + default: + verts[0].Init( Vector2D( 0, 0 ) ); + verts[1].Init( Vector2D( wide, 0 ) ); + verts[2].Init( Vector2D( wide, tall - m_nCornerCutSize + 1 ) ); + verts[3].Init( Vector2D( wide - m_nCornerCutSize + 1, tall ) ); + verts[4].Init( Vector2D( 0, tall ) ); + + lineverts[0].Init( Vector2D( 0, 0 ) ); + lineverts[1].Init( Vector2D( wide, 0 ) ); + lineverts[2].Init( Vector2D( wide, tall - m_nCornerCutSize ) ); + lineverts[3].Init( Vector2D( wide - m_nCornerCutSize, tall ) ); + lineverts[4].Init( Vector2D( 0, tall ) ); + + break; + } + + vgui::surface()->DrawSetTexture( m_iBackgroundTexture ); + vgui::surface()->DrawSetColor( m_clrBackground ); + vgui::surface()->DrawTexturedPolygon( 5, verts ); + + vgui::surface()->DrawSetColor( m_clrBorder ); + vgui::surface()->DrawTexturedPolyLine( lineverts, 5 ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CDoDCutEditablePanel::SetBackGroundColor( const char *pszNewColor ) +{ + if ( !pszNewColor ) + { + return; + } + + Q_strncpy( m_szBackgroudColor, pszNewColor, sizeof( m_szBackgroudColor ) ); + InvalidateLayout( false, true ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CDoDCutEditablePanel::SetBorderColor( const char *pszNewColor ) +{ + if ( !pszNewColor ) + { + return; + } + + Q_strncpy( m_szBorderColor, pszNewColor, sizeof( m_szBorderColor ) ); + InvalidateLayout( false, true ); +}
\ No newline at end of file diff --git a/game/client/dod/VGUI/dodcornercutpanel.h b/game/client/dod/VGUI/dodcornercutpanel.h new file mode 100644 index 0000000..8ac15a6 --- /dev/null +++ b/game/client/dod/VGUI/dodcornercutpanel.h @@ -0,0 +1,66 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef DOD_CORNERCUTPANEL_H +#define DOD_CORNERCUTPANEL_H +#ifdef _WIN32 +#pragma once +#endif + +#include "cbase.h" +#include <vgui_controls/EditablePanel.h> +#include <vgui/ISurface.h> + +#include "dod_shareddefs.h" + + +//----------------------------------------------------------------------------- +// Purpose: Draws the corner-cut background panels +//----------------------------------------------------------------------------- +class CDoDCutEditablePanel : public vgui::EditablePanel +{ +public: + DECLARE_CLASS_SIMPLE( CDoDCutEditablePanel, vgui::EditablePanel ); + + CDoDCutEditablePanel( vgui::Panel *parent, const char *name ); + + virtual void PaintBackground(); + + virtual void SetBorder( vgui::IBorder *border ); + + virtual void ApplySchemeSettings( vgui::IScheme *pScheme ); + + virtual void SetVisible( bool state ) + { + BaseClass::SetVisible( state ); + } + + virtual void ApplySettings( KeyValues *inResourceData ); + virtual void GetSettings( KeyValues *outResourceData ); + + virtual void SetCornerToCut( int nCorner ){ m_nCornerToCut = nCorner; } + virtual void SetCornerCutSize( int nCutSize ){ m_nCornerCutSize = nCutSize; } + virtual void SetBackGroundColor( const char *pszNewColor ); + virtual void SetBorderColor( const char *pszNewColor ); + +private: + + int m_iBackgroundTexture; + + int m_nCornerToCut; + int m_nCornerCutSize; + + char m_szBackgroundTexture[128]; + char m_szBackgroudColor[128]; + char m_szBorderColor[128]; + + Color m_clrBackground; + Color m_clrBorder; +}; + +#endif // DOD_CORNERCUTPANEL_H + diff --git a/game/client/dod/VGUI/dodmenubackground.cpp b/game/client/dod/VGUI/dodmenubackground.cpp new file mode 100644 index 0000000..4851f2e --- /dev/null +++ b/game/client/dod/VGUI/dodmenubackground.cpp @@ -0,0 +1,89 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#include "cbase.h" +#include <vgui/ISurface.h> +#include "dodmenubackground.h" + +using namespace vgui; + +//----------------------------------------------------------------------------- +// Purpose: Constructor +//----------------------------------------------------------------------------- +CDODMenuBackground::CDODMenuBackground(Panel *parent) : EditablePanel(parent, "MenuBackground") +{ + SetProportional(true); + SetVisible(true); + + SetZPos( -1 ); + + LoadControlSettings("Resource/UI/MenuBackground.res"); +} + +void CDODMenuBackground::Init( void ) +{ + m_iBackgroundTexture = vgui::surface()->CreateNewTextureID(); + vgui::surface()->DrawSetTextureFile( m_iBackgroundTexture, "vgui/white", true, false); +} + +void CDODMenuBackground::ApplySchemeSettings( IScheme *pScheme ) +{ + int top[8]; + int main[8]; + int box[8]; + int i; + for( i=0;i<8;i++ ) + { + top[i] = vgui::scheme()->GetProportionalScaledValueEx( GetScheme(),iTopDims[i]); + main[i] = vgui::scheme()->GetProportionalScaledValueEx( GetScheme(),iMainDims[i]); + box[i] = vgui::scheme()->GetProportionalScaledValueEx( GetScheme(),iBoxDims[i]); + + if ( i < 6 ) + m_LineDims[i] = vgui::scheme()->GetProportionalScaledValueEx( GetScheme(),iLineDims[i]); + } + + m_BackgroundTopVerts[0].Init( Vector2D( top[0], top[1] ) ); + m_BackgroundTopVerts[1].Init( Vector2D( top[2], top[3] ) ); + m_BackgroundTopVerts[2].Init( Vector2D( top[4], top[5] ) ); + m_BackgroundTopVerts[3].Init( Vector2D( top[6], top[7] ) ); + + m_BackgroundMainVerts[0].Init( Vector2D( main[0], main[1] ) ); + m_BackgroundMainVerts[1].Init( Vector2D( main[2], main[3] ) ); + m_BackgroundMainVerts[2].Init( Vector2D( main[4], main[5] ) ); + m_BackgroundMainVerts[3].Init( Vector2D( main[6], main[7] ) ); + + m_BoxVerts[0].Init( Vector2D( box[0], box[1] ) ); + m_BoxVerts[1].Init( Vector2D( box[2], box[3] ) ); + m_BoxVerts[2].Init( Vector2D( box[4], box[5] ) ); + m_BoxVerts[3].Init( Vector2D( box[6], box[7] ) ); + + BaseClass::ApplySchemeSettings(pScheme); +} + +//----------------------------------------------------------------------------- +// Purpose: paint the dod style background +//----------------------------------------------------------------------------- +void CDODMenuBackground::Paint(void) +{ + vgui::surface()->DrawSetColor(128,110,53,235); + vgui::surface()->DrawSetTexture( m_iBackgroundTexture ); + + //top background + vgui::surface()->DrawTexturedPolygon( 4, m_BackgroundTopVerts ); + + //main background + vgui::surface()->DrawTexturedPolygon( 4, m_BackgroundMainVerts ); + + // top white line + vgui::surface()->DrawSetColor(255,255,255,196); + vgui::surface()->DrawLine( m_LineDims[0], m_LineDims[1], m_LineDims[2], m_LineDims[3] ); + vgui::surface()->DrawLine( m_LineDims[2], m_LineDims[3], m_LineDims[4], m_LineDims[5] ); + + // top white box + vgui::surface()->DrawTexturedPolygon( 4, m_BoxVerts ); +} + diff --git a/game/client/dod/VGUI/dodmenubackground.h b/game/client/dod/VGUI/dodmenubackground.h new file mode 100644 index 0000000..a79b145 --- /dev/null +++ b/game/client/dod/VGUI/dodmenubackground.h @@ -0,0 +1,74 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef DODMENUBACKGROUND_H +#define DODMENUBACKGROUND_H +#ifdef _WIN32 +#pragma once +#endif + +#include <vgui_controls/EditablePanel.h> +#include <vgui/ISurface.h> +#include "vgui_controls/BitmapImagePanel.h" + +using namespace vgui; + +static int iTopDims[8] = +{ + 41, 30, + 562, 30, + 599, 67, + 41, 67 +}; + +static int iMainDims[8] = +{ + 41, 67, + 599, 67, + 599, 465, + 41, 465 +}; + +static int iBoxDims[8] = +{ + 69, 83, + 86, 83, + 86, 89, + 69, 89 +}; + +static int iLineDims[6] = +{ + 69, 89, + 558, 89, + 568, 99 +}; + +class CDODMenuBackground : public vgui::EditablePanel +{ +private: + DECLARE_CLASS_SIMPLE( CDODMenuBackground, vgui::EditablePanel ); + +public: + CDODMenuBackground( Panel *parent); + + void Init(); + void ApplySchemeSettings( IScheme *pScheme ); + + virtual void Paint( void ); + +private: + vgui::Vertex_t m_BackgroundTopVerts[4]; + vgui::Vertex_t m_BackgroundMainVerts[4]; + vgui::Vertex_t m_BoxVerts[4]; + + int m_LineDims[6]; + + int m_iBackgroundTexture; +}; + +#endif //DODMENUBACKGROUND_H
\ No newline at end of file diff --git a/game/client/dod/VGUI/dodmouseoverpanelbutton.h b/game/client/dod/VGUI/dodmouseoverpanelbutton.h new file mode 100644 index 0000000..4521823 --- /dev/null +++ b/game/client/dod/VGUI/dodmouseoverpanelbutton.h @@ -0,0 +1,72 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef DOD_MOUSE_OVER_BUTTON_H +#define DOD_MOUSE_OVER_BUTTON_H + +#include "dodbutton.h" +#include "mouseoverpanelbutton.h" + +template <class T> +class CDODMouseOverButton : public MouseOverButton<T>, public CDODButtonShape +{ +private: + //DECLARE_CLASS_SIMPLE( CDODMouseOverButton, MouseOverButton ); + +public: + CDODMouseOverButton(vgui::Panel *parent, const char *panelName, T *templatePanel ) : + MouseOverButton<T>( parent, panelName, templatePanel ) + { + } + +protected: + virtual void PaintBackground(); + virtual void PaintBorder(); + +public: + virtual void ShowPage( void ); + virtual void HidePage( void ); +}; + +//=============================================== +// CDODMouseOverButton - shaped mouseover button +//=============================================== +template <class T> +void CDODMouseOverButton<T>::PaintBackground() +{ + int wide, tall; + this->GetSize(wide,tall); + DrawShapedBackground( 0, 0, wide, tall, this->GetBgColor() ); +} + +template <class T> +void CDODMouseOverButton<T>::PaintBorder() +{ + int wide, tall; + this->GetSize(wide,tall); + DrawShapedBorder( 0, 0, wide, tall, this->GetFgColor() ); +} + +template <class T> +void CDODMouseOverButton<T>::ShowPage( void ) +{ + MouseOverButton<T>::ShowPage(); + + // send message to parent that we triggered something + this->PostActionSignal( new KeyValues("ShowPage", "page", this->GetName() ) ); +} + +template <class T> +void CDODMouseOverButton<T>::HidePage( void ) +{ + MouseOverButton<T>::HidePage(); + + // send message to parent that we triggered something + this->PostActionSignal( new KeyValues("ShowPage", "page", this->GetName() ) ); +} + +#endif // DOD_MOUSE_OVER_BUTTON_H
\ No newline at end of file diff --git a/game/client/dod/VGUI/dodoverview.cpp b/game/client/dod/VGUI/dodoverview.cpp new file mode 100644 index 0000000..9d9da3b --- /dev/null +++ b/game/client/dod/VGUI/dodoverview.cpp @@ -0,0 +1,977 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#include "cbase.h" +#include <vgui/ISurface.h> +#include <vgui/ILocalize.h> +#include "dod_shareddefs.h" +#include "dodoverview.h" +#include "c_playerresource.h" +#include "c_dod_objective_resource.h" +#include "usermessages.h" +#include "coordsize.h" +#include "clientmode.h" +#include <vgui_controls/AnimationController.h> +#include "voice_status.h" +#include "spectatorgui.h" +#include "dod_hud_freezepanel.h" + +using namespace vgui; + +void __MsgFunc_UpdateRadar(bf_read &msg) +{ + if ( !g_pMapOverview ) + return; + + int iPlayerEntity = msg.ReadByte(); + + while ( iPlayerEntity > 0 ) + { + int x = msg.ReadSBitLong( COORD_INTEGER_BITS-1 ) * 4; + int y = msg.ReadSBitLong( COORD_INTEGER_BITS-1 ) * 4; + int a = msg.ReadSBitLong( 9 ); + + Vector origin( x, y, 0 ); + QAngle angles( 0, a, 0 ); + + g_pMapOverview->SetPlayerPositions( iPlayerEntity-1, origin, angles ); + + iPlayerEntity = msg.ReadByte(); // read index for next player + } +} + +extern ConVar _overview_mode; +ConVar _cl_minimapzoom( "_cl_minimapzoom", "1", FCVAR_ARCHIVE ); +ConVar _overview_mode( "_overview_mode", "1", FCVAR_ARCHIVE, "Overview mode - 0=off, 1=inset, 2=full\n", true, 0, true, 2 ); + + +CDODMapOverview *GetDODOverview( void ) +{ + return dynamic_cast<CDODMapOverview *>(g_pMapOverview); +} + +// overview_togglezoom rotates through 3 levels of zoom for the small map +//----------------------------------------------------------------------- +void ToggleZoom( void ) +{ + if ( !GetDODOverview() ) + return; + + GetDODOverview()->ToggleZoom(); +} +static ConCommand overview_togglezoom( "overview_togglezoom", ToggleZoom ); + +// overview_largemap toggles showing the large map +//------------------------------------------------ +void ShowLargeMap( void ) +{ + if ( !GetDODOverview() ) + return; + + GetDODOverview()->ShowLargeMap(); +} +static ConCommand overview_showlargemap( "+overview_largemap", ShowLargeMap ); + +void HideLargeMap( void ) +{ + if ( !GetDODOverview() ) + return; + + GetDODOverview()->HideLargeMap(); +} +static ConCommand overview_hidelargemap( "-overview_largemap", HideLargeMap ); + +//-------------------------------- +// map border ? +// icon minimum zoom +// flag swipes +// grenades +// chatting icon +// voice com icon +//--------------------------------- + +DECLARE_HUDELEMENT( CDODMapOverview ); + +ConVar dod_overview_voice_icon_size( "dod_overview_voice_icon_size", "64", FCVAR_ARCHIVE ); + +CDODMapOverview::CDODMapOverview( const char *pElementName ) : BaseClass( pElementName ) +{ + InitTeamColorsAndIcons(); + m_flIconSize = 96.0f; + m_iLastMode = MAP_MODE_OFF; + usermessages->HookMessage( "UpdateRadar", __MsgFunc_UpdateRadar ); +} + +void CDODMapOverview::Update() +{ + UpdateCapturePoints(); + + BaseClass::Update(); +} + +void CDODMapOverview::VidInit( void ) +{ + m_pC4Icon = gHUD.GetIcon( "icon_c4" ); + m_pExplodedIcon = gHUD.GetIcon( "icon_c4_exploded" ); + m_pC4PlantedBG = gHUD.GetIcon( "icon_c4_planted_bg" ); + m_pIconDefended = gHUD.GetIcon( "icon_defended" ); + + BaseClass::VidInit(); +} + +void CDODMapOverview::UpdateCapturePoints() +{ + if ( !g_pObjectiveResource ) + return; + + Color colorGreen(0,255,0,255); + + if ( !g_pObjectiveResource ) + return; + + for( int i=0;i<g_pObjectiveResource->GetNumControlPoints();i++ ) + { + // check if CP is visible at all + if( !g_pObjectiveResource->IsCPVisible(i) ) + { + if ( m_CapturePoints[i] != 0 ) + { + // remove capture point from map + RemoveObject( m_CapturePoints[i] ); + m_CapturePoints[i] = 0; + } + + continue; + } + + // ok, show CP + int iOwningTeam = g_pObjectiveResource->GetOwningTeam(i); + int iCappingTeam = g_pObjectiveResource->GetCappingTeam(i); + + int iOwningIcon = g_pObjectiveResource->GetIconForTeam( i, iOwningTeam ); + if ( iOwningIcon <= 0 ) + continue; // baah + + const char *textureName = GetMaterialNameFromIndex( iOwningIcon ); + + int objID = m_CapturePoints[i]; + + if ( objID == 0 ) + { + // add object if not already there + objID = m_CapturePoints[i] = AddObject( textureName, 0, -1 ); + + // objective positions never change (so far) + SetObjectPosition( objID, g_pObjectiveResource->GetCPPosition(i), vec3_angle ); + + AddObjectFlags( objID, MAP_OBJECT_ALIGN_TO_MAP ); + } + + SetObjectIcon( objID, textureName, 128.0 ); + + + int iBombs = g_pObjectiveResource->GetBombsRemaining( i ); + if ( iBombs > 0 ) + { + char text[8]; + Q_snprintf( text, sizeof(text), "%d", iBombs ); + SetObjectText( objID, text, colorGreen ); + } + //Draw the number of cappers below the icon + else if ( iCappingTeam != TEAM_UNASSIGNED ) + { + int numPlayers = g_pObjectiveResource->GetNumPlayersInArea( i, iCappingTeam ); + int requiredPlayers = g_pObjectiveResource->GetRequiredCappers( i, iCappingTeam ); + + if( requiredPlayers > 1 ) + { + char text[8]; + Q_snprintf( text, sizeof(text), "%d/%d", numPlayers, requiredPlayers ); + SetObjectText( objID, text, colorGreen ); + } + else + { + SetObjectText( objID, NULL, colorGreen ); + } + } + else + { + SetObjectText( objID, NULL, colorGreen ); + } + + float flBombTime = g_pObjectiveResource->GetBombTimeForPoint( i ); + + //Draw cap percentage + if( iCappingTeam != TEAM_UNASSIGNED ) + { + SetObjectStatus( objID, g_pObjectiveResource->GetCPCapPercentage(i), colorGreen ); + } + else if ( flBombTime > 0 ) + { + float flPercentRemaining = ( flBombTime / DOD_BOMB_TIMER_LENGTH ); + + SetObjectStatus( objID, flPercentRemaining, colorGreen ); + } + else + { + SetObjectStatus( objID, -1, colorGreen ); // turn it off + } + + } +} + +void CDODMapOverview::InitTeamColorsAndIcons() +{ + BaseClass::InitTeamColorsAndIcons(); + + m_TeamColors[TEAM_ALLIES] = COLOR_DOD_GREEN; + m_TeamIcons[TEAM_ALLIES] = AddIconTexture( "sprites/minimap_icons/aplayer" ); + m_CameraIcons[TEAM_ALLIES] = AddIconTexture( "sprites/minimap_icons/allies_camera" ); + + + m_TeamColors[TEAM_AXIS] = COLOR_DOD_RED; + m_TeamIcons[TEAM_AXIS] = AddIconTexture( "sprites/minimap_icons/gplayer" ); + m_CameraIcons[TEAM_AXIS] = AddIconTexture( "sprites/minimap_icons/axis_camera" ); + + Q_memset( m_flPlayerChatTime, 0, sizeof(m_flPlayerChatTime ) ); + m_iVoiceIcon = AddIconTexture( "voice/icntlk_pl" ); + m_iChatIcon = AddIconTexture( "sprites/minimap_icons/voiceIcon" ); + + Q_memset( m_CapturePoints, 0, sizeof(m_CapturePoints) ); +} + +void CDODMapOverview::DrawCamera() +{ + C_BasePlayer *localPlayer = C_BasePlayer::GetLocalPlayer(); + + if ( !localPlayer ) + return; + + int iTexture = m_CameraIcons[localPlayer->GetTeamNumber()]; + + if ( localPlayer->IsObserver() || iTexture <= 0 ) + { + BaseClass::DrawCamera(); + } + else + { + MapObject_t obj; + memset( &obj, 0, sizeof(MapObject_t) ); + + obj.icon = iTexture; + obj.position = localPlayer->GetAbsOrigin(); + obj.size = m_flIconSize * 1.5; + obj.angle = localPlayer->EyeAngles(); + obj.status = -1; + + DrawIcon( &obj ); + + DrawVoiceIconForPlayer( localPlayer->entindex() - 1 ); + } +} + +void CDODMapOverview::FireGameEvent( IGameEvent *event ) +{ + const char * type = event->GetName(); + + if ( Q_strcmp(type, "player_death") == 0 ) + { + MapPlayer_t *player = GetPlayerByUserID( event->GetInt("userid") ); + + if ( player && CanPlayerBeSeen( player ) ) + { + // create skull icon for 3 seconds + int handle = AddObject( "sprites/minimap_icons/death", 0, 3 ); + SetObjectText( handle, player->name, player->color ); + SetObjectPosition( handle, player->position, player->angle ); + } + } + else if ( Q_strcmp(type, "game_newmap") == 0 ) + { + SetMode( _overview_mode.GetInt() ); + } + + BaseClass::FireGameEvent( event ); +} + +// rules that define if you can see a player on the overview or not +bool CDODMapOverview::CanPlayerBeSeen(MapPlayer_t *player) +{ + C_BasePlayer *localPlayer = C_BasePlayer::GetLocalPlayer(); + + if ( !localPlayer || !player ) + return false; + + // don't draw ourselves + if ( localPlayer->entindex() == (player->index+1) ) + return false; + + // if local player is on spectator team, he can see everyone + if ( localPlayer->GetTeamNumber() <= TEAM_SPECTATOR ) + return true; + + // we never track unassigned or real spectators + if ( player->team <= TEAM_SPECTATOR ) + return false; + + // ingame and as dead player we can only see our own teammates + return (localPlayer->GetTeamNumber() == player->team ); +} + +void CDODMapOverview::ShowLargeMap( void ) +{ + // remember old mode + m_iLastMode = GetMode(); + + // if we hit the toggle while full, set to disappear when we release + if ( m_iLastMode == MAP_MODE_FULL ) + m_iLastMode = MAP_MODE_OFF; + + SetMode( MAP_MODE_FULL ); +} + +void CDODMapOverview::HideLargeMap( void ) +{ + SetMode( m_iLastMode ); +} + +void CDODMapOverview::ToggleZoom( void ) +{ + if ( GetMode() != MAP_MODE_INSET ) + return; + + int iZoomLevel = ( _cl_minimapzoom.GetInt() + 1 ) % DOD_MAP_ZOOM_LEVELS; + + _cl_minimapzoom.SetValue( iZoomLevel ); + + switch( _cl_minimapzoom.GetInt() ) + { + case 0: + g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( "MapZoomLevel1" ); + break; + case 1: + default: + g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( "MapZoomLevel2" ); + break; + } +} + +void CDODMapOverview::SetMode(int mode) +{ + m_flChangeSpeed = 0; // change size instantly + + if ( mode == MAP_MODE_OFF ) + { + ShowPanel( false ); + + g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( "MapOff" ); + } + else if ( mode == MAP_MODE_INSET ) + { + switch( _cl_minimapzoom.GetInt() ) + { + case 0: + g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( "MapZoomLevel1" ); + break; + case 1: + g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( "MapZoomLevel2" ); + break; + case 2: + default: + g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( "MapZoomLevel3" ); + break; + } + + C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer(); + + if ( pPlayer ) + SetFollowEntity( pPlayer->entindex() ); + + ShowPanel( true ); + + if ( m_nMode == MAP_MODE_FULL ) + g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( "MapScaleToSmall" ); + else + g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( "SnapToSmall" ); + } + else if ( mode == MAP_MODE_FULL ) + { + SetFollowEntity( 0 ); + + ShowPanel( true ); + + if ( m_nMode == MAP_MODE_INSET ) + g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( "ZoomToLarge" ); + else + g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( "SnapToLarge" ); + } + + // finally set mode + m_nMode = mode; + + // save in a cvar for archive + _overview_mode.SetValue( m_nMode ); + + UpdateSizeAndPosition(); +} + +void CDODMapOverview::UpdateSizeAndPosition() +{ + // move back up if the spectator menu is not visible + if ( !g_pSpectatorGUI || ( !g_pSpectatorGUI->IsVisible() && GetMode() == MAP_MODE_INSET ) ) + { + int x,y,w,h; + + GetBounds( x,y,w,h ); + + y = YRES(5); // hax, align to top of the screen + + SetBounds( x,y,w,h ); + } + + BaseClass::UpdateSizeAndPosition(); +} + +void CDODMapOverview::AddGrenade( C_DODBaseGrenade *pGrenade ) +{ + C_BasePlayer *localPlayer = C_BasePlayer::GetLocalPlayer(); + + if ( !localPlayer ) + return; + + int localTeam = localPlayer->GetTeamNumber(); + + // Spectators can see all grenades + // players can only see them if they are on the same team + if ( localTeam == TEAM_SPECTATOR || ( localTeam == pGrenade->GetTeamNumber() ) ) + { + AddObject( pGrenade->GetOverviewSpriteName(), pGrenade->entindex(), -1 ); + } +} + +void CDODMapOverview::RemoveGrenade( C_DODBaseGrenade *pGrenade ) +{ + RemoveObjectByIndex( pGrenade->entindex() ); +} + +ConVar cl_voicetest( "cl_voicetest", "0", FCVAR_CHEAT ); +ConVar cl_overview_chat_time( "cl_overview_chat_time", "2.0", FCVAR_ARCHIVE ); + +void CDODMapOverview::PlayerChat( int index ) +{ + m_flPlayerChatTime[index-1] = gpGlobals->curtime + cl_overview_chat_time.GetFloat(); +} + +void CDODMapOverview::DrawMapPlayers() +{ + BaseClass::DrawMapPlayers(); + + C_BasePlayer *localPlayer = C_BasePlayer::GetLocalPlayer(); + + Assert( localPlayer ); + + int iLocalPlayer = localPlayer->entindex() - 1; + + for (int i=0; i<MAX_PLAYERS; i++) + { + if ( i == iLocalPlayer ) + continue; + + MapPlayer_t *player = &m_Players[i]; + + if ( !CanPlayerBeSeen( player ) ) + continue; + + if ( player->health <= 0 ) // don't draw dead players / spectators + continue; + + DrawVoiceIconForPlayer( i ); + } +} + +void CDODMapOverview::DrawVoiceIconForPlayer( int playerIndex ) +{ + Assert( playerIndex >= 0 && playerIndex < MAX_PLAYERS ); + + MapPlayer_t *player = &m_Players[playerIndex]; + + // if they just sent a chat msg, or are using voice, or did a hand signal or voice command + // draw a chat icon + + if ( cl_voicetest.GetInt() || GetClientVoiceMgr()->IsPlayerSpeaking( player->index+1 ) ) + { + MapObject_t obj; + memset( &obj, 0, sizeof(MapObject_t) ); + + obj.icon = m_iVoiceIcon; + obj.position = player->position; + obj.size = dod_overview_voice_icon_size.GetFloat(); + obj.status = -1; + + DrawIcon( &obj ); + } + else if ( m_flPlayerChatTime[player->index] > gpGlobals->curtime ) + { + MapObject_t obj; + memset( &obj, 0, sizeof(MapObject_t) ); + + obj.icon = m_iChatIcon; + obj.position = player->position; + obj.size = dod_overview_voice_icon_size.GetFloat(); + obj.status = -1; + + DrawIcon( &obj ); + } +} + +bool CDODMapOverview::DrawIcon( MapObject_t *obj ) +{ + for ( int i=0;i<MAX_CONTROL_POINTS;i++ ) + { + if ( obj->objectID == m_CapturePoints[i] && obj->objectID != 0 ) + { + return DrawCapturePoint( i, obj ); + } + } + + return BaseClass::DrawIcon( obj ); +} + +void CDODMapOverview::DrawQuad( Vector pos, int scale, float angle, int textureID, int alpha ) +{ + Vector offset; + offset.z = 0; + + offset.x = -scale; offset.y = scale; + VectorYawRotate( offset, angle, offset ); + Vector2D pos1 = WorldToMap( pos + offset ); + + offset.x = scale; offset.y = scale; + VectorYawRotate( offset, angle, offset ); + Vector2D pos2 = WorldToMap( pos + offset ); + + offset.x = scale; offset.y = -scale; + VectorYawRotate( offset, angle, offset ); + Vector2D pos3 = WorldToMap( pos + offset ); + + offset.x = -scale; offset.y = -scale; + VectorYawRotate( offset, angle, offset ); + Vector2D pos4 = WorldToMap( pos + offset ); + + Vertex_t points[4] = + { + Vertex_t( MapToPanel ( pos1 ), Vector2D(0,0) ), + Vertex_t( MapToPanel ( pos2 ), Vector2D(1,0) ), + Vertex_t( MapToPanel ( pos3 ), Vector2D(1,1) ), + Vertex_t( MapToPanel ( pos4 ), Vector2D(0,1) ) + }; + + surface()->DrawSetColor( 255, 255, 255, alpha ); + surface()->DrawSetTexture( textureID ); + surface()->DrawTexturedPolygon( 4, points ); +} + +bool CDODMapOverview::DrawCapturePoint( int iCP, MapObject_t *obj ) +{ + int textureID = obj->icon; + Vector pos = obj->position; + float scale = obj->size; + float angle = 0; + + Vector2D pospanel = WorldToMap( pos ); + pospanel = MapToPanel( pospanel ); + + if ( !IsInPanel( pospanel ) ) + return false; // player is not within overview panel + + int iBombsRequired = g_pObjectiveResource->GetBombsRequired( iCP ); + + if ( iBombsRequired ) + { + if ( g_pObjectiveResource->IsBombSetAtPoint( iCP ) ) + { + // draw swipe over blank icon + + // 'white' icon + int iBlankIcon = g_pObjectiveResource->GetCPTimerCapIcon( iCP ); + const char *textureName = GetMaterialNameFromIndex( iBlankIcon ); + DrawQuad( pos, scale, 0, AddIconTexture( textureName ), 255 ); + + // the circular swipe + float flBombTime = g_pObjectiveResource->GetBombTimeForPoint( iCP ); + float flPercentRemaining = ( flBombTime / DOD_BOMB_TIMER_LENGTH ); + + DrawBombTimerSwipeIcon( pos, scale, textureID, flPercentRemaining ); + } + else + { + DrawQuad( pos, scale, 0, textureID, 255 ); + } + } + else + { + // draw capture swipe + DrawQuad( pos, scale, 0, textureID, 255 ); + + int iCappingTeam = g_pObjectiveResource->GetCappingTeam( iCP ); + + if ( iCappingTeam != TEAM_UNASSIGNED ) + { + int iCapperIcon = g_pObjectiveResource->GetCPCappingIcon( iCP ); + const char *textureName = GetMaterialNameFromIndex( iCapperIcon ); + + float flCapPercent = g_pObjectiveResource->GetCPCapPercentage(iCP); + bool bSwipeLeft = ( iCappingTeam == TEAM_AXIS ) ? true : false; + + DrawHorizontalSwipe( pos, scale, AddIconTexture( textureName ), flCapPercent, bSwipeLeft ); + } + + // fixup for noone is capping, but someone is in the area + int iNumAllies = g_pObjectiveResource->GetNumPlayersInArea( iCP, TEAM_ALLIES ); + int iNumAxis = g_pObjectiveResource->GetNumPlayersInArea( iCP, TEAM_AXIS ); + + int iOwningTeam = g_pObjectiveResource->GetOwningTeam( iCP ); + if ( iCappingTeam == TEAM_UNASSIGNED ) + { + if ( iNumAllies > 0 && iNumAxis == 0 && iOwningTeam != TEAM_ALLIES ) + { + iCappingTeam = TEAM_ALLIES; + } + else if ( iNumAxis > 0 && iNumAllies == 0 && iOwningTeam != TEAM_AXIS ) + { + iCappingTeam = TEAM_AXIS; + } + } + + if ( iCappingTeam != TEAM_UNASSIGNED ) + { + // Draw the number of cappers below the icon + int numPlayers = g_pObjectiveResource->GetNumPlayersInArea( iCP, iCappingTeam ); + int requiredPlayers = g_pObjectiveResource->GetRequiredCappers( iCP, iCappingTeam ); + + if ( requiredPlayers > 1 ) + { + numPlayers = MIN( numPlayers, requiredPlayers ); + + wchar_t wText[6]; + _snwprintf( wText, sizeof(wText)/sizeof(wchar_t), L"%d/%d", numPlayers, requiredPlayers ); + + int wide, tall; + surface()->GetTextSize( m_hIconFont, wText, wide, tall ); + + int x = pospanel.x-(wide/2); + int y = pospanel.y; + + // match the offset that MapOverview uses + y += GetPixelOffset( scale ) + 4; + + // draw black shadow text + surface()->DrawSetTextColor( 0, 0, 0, 255 ); + surface()->DrawSetTextPos( x+1, y ); + surface()->DrawPrintText( wText, wcslen(wText) ); + + // draw name in color + surface()->DrawSetTextColor( g_PR->GetTeamColor( iCappingTeam ) ); + surface()->DrawSetTextPos( x, y ); + surface()->DrawPrintText( wText, wcslen(wText) ); + } + } + } + + // draw bombs underneath if necessary + if ( iBombsRequired > 0 ) + { + int iBombsRemaining = g_pObjectiveResource->GetBombsRemaining( iCP ); + bool bBombPlanted = g_pObjectiveResource->IsBombSetAtPoint( iCP ); + + // draw bomb state underneath + float flBombIconScale = scale * 0.5; + + + switch( iBombsRequired ) + { + case 1: + { + Vector bombPos = pos; + bombPos.y -= scale * 1.5; + + switch( iBombsRemaining ) + { + case 0: + DrawQuad( bombPos, flBombIconScale, angle, m_pExplodedIcon->textureId, 255 ); + break; + case 1: + if ( bBombPlanted ) + { + // draw the background behind 1 + int alpha = (float)( abs( sin(2*gpGlobals->curtime) ) * 205.0 + 50.0 ); + DrawQuad( bombPos, flBombIconScale*2, angle, m_pC4PlantedBG->textureId, alpha ); + } + DrawQuad( bombPos, flBombIconScale, angle, m_pC4Icon->textureId, 255 ); + break; + } + } + break; + case 2: + { + Vector bombPos1, bombPos2; + bombPos1 = bombPos2 = pos; + bombPos1.y = bombPos2.y = pos.y - scale * 1.5; + + bombPos1.x = pos.x - scale * 0.5; + bombPos2.x = pos.x + scale * 0.5; + + switch( iBombsRemaining ) + { + case 0: + DrawQuad( bombPos1, flBombIconScale, angle, m_pExplodedIcon->textureId, 255 ); + DrawQuad( bombPos2, flBombIconScale, angle, m_pExplodedIcon->textureId, 255 ); + break; + case 1: + if ( bBombPlanted ) + { + // draw the background behind 1 + int alpha = (float)( abs( sin(2*gpGlobals->curtime) ) * 205.0 + 50.0 ); + DrawQuad( bombPos1, flBombIconScale*2, angle, m_pC4PlantedBG->textureId, alpha ); + } + DrawQuad( bombPos1, flBombIconScale, angle, m_pC4Icon->textureId, 255 ); + DrawQuad( bombPos2, flBombIconScale, angle, m_pExplodedIcon->textureId, 255 ); + break; + case 2: + if ( bBombPlanted ) + { + // draw the background behind 2 + int alpha = (float)( abs( sin(2*gpGlobals->curtime) ) * 205.0 + 50.0 ); + DrawQuad( bombPos2, flBombIconScale*2, angle, m_pC4PlantedBG->textureId, alpha ); + } + DrawQuad( bombPos1, flBombIconScale, angle, m_pC4Icon->textureId, 255 ); + DrawQuad( bombPos2, flBombIconScale, angle, m_pC4Icon->textureId, 255 ); + break; + } + } + break; + } + + // draw shield over top + if ( g_pObjectiveResource->IsBombBeingDefused( iCP ) ) + { + DrawQuad( pos, scale * 0.75, angle, m_pIconDefended->textureId, 255 ); + } + } + + return true; +} + +void CDODMapOverview::DrawBombTimerSwipeIcon( Vector pos, int scale, int textureID, float flPercentRemaining ) +{ + const float flCompleteCircle = ( 2.0f * M_PI ); + const float fl90degrees = flCompleteCircle * 0.25f; + const float fl45degrees = fl90degrees * 0.5f; + + float flEndAngle = flCompleteCircle * flPercentRemaining; // clockwise + + typedef struct + { + Vector2D vecTrailing; + Vector2D vecLeading; + } icon_quadrant_t; + + /* + Quadrants are numbered 0 - 7 counter-clockwise + _________________ + | 0 | 7 | + | | | + | 1 | 6 | + ----------------- + | 2 | 5 | + | | | + | 3 | 4 | + ----------------- + */ + + // Encode the leading and trailing edge of each quadrant + // in the range 0.0 -> 1.0 + + icon_quadrant_t quadrants[8]; + quadrants[0].vecTrailing.Init( 0.5, 0.0 ); + quadrants[0].vecLeading.Init( 0.0, 0.0 ); + + quadrants[1].vecTrailing.Init( 0.0, 0.0 ); + quadrants[1].vecLeading.Init( 0.0, 0.5 ); + + quadrants[2].vecTrailing.Init( 0.0, 0.5 ); + quadrants[2].vecLeading.Init( 0.0, 1.0 ); + + quadrants[3].vecTrailing.Init( 0.0, 1.0 ); + quadrants[3].vecLeading.Init( 0.5, 1.0 ); + + quadrants[4].vecTrailing.Init( 0.5, 1.0 ); + quadrants[4].vecLeading.Init( 1.0, 1.0 ); + + quadrants[5].vecTrailing.Init( 1.0, 1.0 ); + quadrants[5].vecLeading.Init( 1.0, 0.5 ); + + quadrants[6].vecTrailing.Init( 1.0, 0.5 ); + quadrants[6].vecLeading.Init( 1.0, 0.0 ); + + quadrants[7].vecTrailing.Init( 1.0, 0.0 ); + quadrants[7].vecLeading.Init( 0.5, 0.0 ); + + surface()->DrawSetColor( 255, 255, 255, 255 ); + surface()->DrawSetTexture( textureID ); + + Vector2D uvMid( 0.5, 0.5 ); + Vector2D newPos( pos.x - scale, pos.y + scale ); + + int j; + for ( j=0;j<=7;j++ ) + { + float flMinAngle = j * fl45degrees; + + float flAngle = clamp( flEndAngle - flMinAngle, 0, fl45degrees ); + + if ( flAngle <= 0 ) + { + // past our quadrant, draw nothing + continue; + } + else + { + // draw our segment + vgui::Vertex_t vert[3]; + + // vert 0 is mid ( 0.5, 0.5 ) + + Vector2D pos0 = WorldToMap( pos ); + vert[0].Init( MapToPanel( pos0 ), uvMid ); + + int xdir = 0, ydir = 0; + + switch( j ) + { + case 0: + case 7: + //right + xdir = 1; + ydir = 0; + break; + + case 1: + case 2: + //up + xdir = 0; + ydir = -1; + break; + + case 3: + case 4: + //left + xdir = -1; + ydir = 0; + break; + + case 5: + case 6: + //down + xdir = 0; + ydir = 1; + break; + } + + Vector vec1; + Vector2D uv1; + + // vert 1 is the variable vert based on leading edge + vec1.x = newPos.x + quadrants[j].vecTrailing.x * scale*2 - xdir * tan(flAngle) * scale; + vec1.y = newPos.y - quadrants[j].vecTrailing.y * scale*2 + ydir * tan(flAngle) * scale; + + uv1.x = quadrants[j].vecTrailing.x - xdir * abs( quadrants[j].vecLeading.x - quadrants[j].vecTrailing.x ) * tan(flAngle); + uv1.y = quadrants[j].vecTrailing.y - ydir * abs( quadrants[j].vecLeading.y - quadrants[j].vecTrailing.y ) * tan(flAngle); + + Vector2D pos1 = WorldToMap( vec1 ); + vert[1].Init( MapToPanel( pos1 ), uv1 ); + + // vert 2 is our trailing edge + Vector vec2; + + vec2.x = newPos.x + quadrants[j].vecTrailing.x * scale*2; + vec2.y = newPos.y - quadrants[j].vecTrailing.y * scale*2; + + Vector2D pos2 = WorldToMap( vec2 ); + vert[2].Init( MapToPanel( pos2 ), quadrants[j].vecTrailing ); + + surface()->DrawTexturedPolygon( 3, vert ); + } + } +} + +void CDODMapOverview::DrawHorizontalSwipe( Vector pos, int scale, int textureID, float flCapPercentage, bool bSwipeLeft ) +{ + float flIconSize = scale * 2; + float width = ( flIconSize * flCapPercentage ); + + float uv1 = 0.0f; + float uv2 = 1.0f; + + Vector2D uv11( uv1, uv2 ); + Vector2D uv21( flCapPercentage, uv2 ); + Vector2D uv22( flCapPercentage, uv1 ); + Vector2D uv12( uv1, uv1 ); + + // reversing the direction of the swipe effect + if ( bSwipeLeft ) + { + uv11.x = uv2 - flCapPercentage; + uv21.x = uv2; + uv22.x = uv2; + uv12.x = uv2 - flCapPercentage; + } + + float flXPos = pos.x - scale; + float flYPos = pos.y - scale; + + Vector upperLeft( flXPos, flYPos, 0 ); + Vector upperRight( flXPos + width, flYPos, 0 ); + Vector lowerRight( flXPos + width, flYPos + flIconSize, 0 ); + Vector lowerLeft ( flXPos, flYPos + flIconSize, 0 ); + + /// reversing the direction of the swipe effect + if ( bSwipeLeft ) + { + upperLeft.x = flXPos + flIconSize - width; + upperRight.x = flXPos + flIconSize; + lowerRight.x = flXPos + flIconSize; + lowerLeft.x = flXPos + flIconSize - width; + } + + vgui::Vertex_t vert[4]; + + Vector2D pos0 = WorldToMap( upperLeft ); + vert[0].Init( MapToPanel( pos0 ), uv11 ); + + Vector2D pos3 = WorldToMap( lowerLeft ); + vert[1].Init( MapToPanel( pos3 ), uv12 ); + + Vector2D pos2 = WorldToMap( lowerRight ); + vert[2].Init( MapToPanel( pos2 ), uv22 ); + + Vector2D pos1 = WorldToMap( upperRight ); + vert[3].Init( MapToPanel( pos1 ), uv21 ); + + surface()->DrawSetColor( 255, 255, 255, 255 ); + surface()->DrawSetTexture( textureID ); + surface()->DrawTexturedPolygon( 4, vert ); +} + + +bool CDODMapOverview::IsVisible( void ) +{ + if ( IsTakingAFreezecamScreenshot() ) + return false; + + return BaseClass::IsVisible(); +}
\ No newline at end of file diff --git a/game/client/dod/VGUI/dodoverview.h b/game/client/dod/VGUI/dodoverview.h new file mode 100644 index 0000000..879d7b2 --- /dev/null +++ b/game/client/dod/VGUI/dodoverview.h @@ -0,0 +1,81 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef DODOVERVIEW_H +#define DODOVERVIEW_H + +#include <mapoverview.h> +#include "dod_shareddefs.h" +#include "c_dod_basegrenade.h" + +class CDODMapOverview : public CMapOverview +{ + DECLARE_CLASS_SIMPLE( CDODMapOverview, CMapOverview ); + + CDODMapOverview( const char *pElementName ); + + int m_CameraIcons[MAX_TEAMS]; + int m_CapturePoints[MAX_CONTROL_POINTS]; + + void ShowLargeMap( void ); + void HideLargeMap( void ); + void ToggleZoom( void ); + + void AddGrenade( C_DODBaseGrenade *pGrenade ); + void RemoveGrenade( C_DODBaseGrenade *pGrenade ); + + void PlayerChat( int index ); + + void DrawQuad( Vector pos, int scale, float angle, int textureID, int alpha ); + void DrawBombTimerSwipeIcon( Vector pos, int scale, int textureID, float flPercentRemaining ); + void DrawHorizontalSwipe( Vector pos, int scale, int textureID, float flCapPercentage, bool bSwipeLeft ); + bool DrawCapturePoint( int iCP, MapObject_t *obj ); + + virtual void VidInit( void ); + + virtual bool IsVisible( void ); + +protected: + virtual void SetMode(int mode); + virtual void InitTeamColorsAndIcons(); + virtual void FireGameEvent( IGameEvent *event ); + virtual void DrawCamera(); + virtual void DrawMapPlayers(); + virtual void Update(); + virtual void UpdateSizeAndPosition(); + + // rules that define if you can see a player on the overview or not + virtual bool CanPlayerBeSeen(MapPlayer_t *player); + + void DrawVoiceIconForPlayer( int playerIndex ); + + virtual bool DrawIcon( MapObject_t *obj ); + +protected: + void UpdateCapturePoints(); + +private: + int m_iLastMode; + + CUtlVector<MapObject_t> m_Grenades; + + int m_iVoiceIcon; + int m_iChatIcon; + + float m_flPlayerChatTime[MAX_PLAYERS]; + + CHudTexture *m_pC4Icon; + CHudTexture *m_pExplodedIcon; + CHudTexture *m_pC4PlantedBG; + CHudTexture *m_pIconDefended; + +#define DOD_MAP_ZOOM_LEVELS 2 +}; + +extern CDODMapOverview *GetDODOverview( void ); + +#endif // DODOVERVIEW_H diff --git a/game/client/dod/VGUI/dodrandombutton.h b/game/client/dod/VGUI/dodrandombutton.h new file mode 100644 index 0000000..a846972 --- /dev/null +++ b/game/client/dod/VGUI/dodrandombutton.h @@ -0,0 +1,93 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef DOD_RANDOM_BUTTON_H +#define DOD_RANDOM_BUTTON_H + +#include "dodmouseoverpanelbutton.h" + +// CDODRandomButton - has the lower left corner cut out +// and does mouseover + +/* + +|''''''''''''''''| +| 9. Random | + \_______________| + */ + +template <class T> +class CDODRandomButton : public CDODMouseOverButton<T> +{ +private: + //DECLARE_CLASS_SIMPLE( CDODRandomButton, CDODMouseOverButton ); + +public: + CDODRandomButton(vgui::Panel *parent, const char *panelName, T *templatePanel ) : + CDODMouseOverButton<T>( parent, panelName, templatePanel ) + { + } + +protected: + virtual void PaintBackground(); + virtual void PaintBorder(); +}; + +//=============================================== +// CDODRandomButton - differently shaped button +//=============================================== +template <class T> +void CDODRandomButton<T>::PaintBackground() +{ + int wide, tall; + this->GetSize(wide,tall); + + int inset = tall; + + if ( CDODRandomButton<T>::m_iWhiteTexture < 0 ) + { + CDODRandomButton<T>::m_iWhiteTexture = vgui::surface()->CreateNewTextureID(); + vgui::surface()->DrawSetTextureFile( CDODRandomButton<T>::m_iWhiteTexture, "vgui/white" , true, false); + } + + surface()->DrawSetColor(this->GetBgColor()); + surface()->DrawSetTexture( CDODRandomButton<T>::m_iWhiteTexture ); + + Vertex_t verts[4]; + + verts[0].Init( Vector2D( 0, 0 ) ); + verts[1].Init( Vector2D( wide-1, 0 ) ); + verts[2].Init( Vector2D( wide-1, tall-1 ) ); + verts[3].Init( Vector2D( inset, tall-1 ) ); + + surface()->DrawTexturedPolygon(4, verts); +} + +template <class T> +void CDODRandomButton<T>::PaintBorder() +{ + int wide, tall; + this->GetSize(wide,tall); + + int inset = tall; + + surface()->DrawSetColor(this->GetFgColor()); + + // top + surface()->DrawLine( 0, 1, wide-1, 1 ); + + // left + surface()->DrawLine( 1, 1, inset-1, tall-1 ); + + // bottom + surface()->DrawLine( inset-1, tall-1, wide-1, tall-1 ); + + // right + surface()->DrawLine( wide-1, 0, wide-1, tall-1 ); +} + +#endif //DOD_RANDOM_BUTTON_H
\ No newline at end of file diff --git a/game/client/dod/VGUI/dodspectatorgui.cpp b/game/client/dod/VGUI/dodspectatorgui.cpp new file mode 100644 index 0000000..c4e1dd5 --- /dev/null +++ b/game/client/dod/VGUI/dodspectatorgui.cpp @@ -0,0 +1,194 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#include "cbase.h" +#include "dodspectatorgui.h" +#include "hud.h" +#include "dod_shareddefs.h" + +#include <vgui/ILocalize.h> +#include <vgui/ISurface.h> +#include <imapoverview.h> +#include "dod_gamerules.h" +#include "c_team.h" +#include "c_dod_team.h" +#include "c_dod_player.h" +#include "c_dod_playerresource.h" + +using namespace vgui; + +//----------------------------------------------------------------------------- +// Purpose: Constructor +//----------------------------------------------------------------------------- +CDODSpectatorGUI::CDODSpectatorGUI(IViewPort *pViewPort) : CSpectatorGUI(pViewPort) +{ +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +bool CDODSpectatorGUI::NeedsUpdate( void ) +{ + if ( !C_BasePlayer::GetLocalPlayer() ) + return false; + + if( IsVisible() ) + return true; + + //if ( DODGameRules()->IsGameUnderTimeLimit() && m_nLastTime != DODGameRules()->GetTimeLeft() ) + // return true; + + if ( m_nLastSpecMode != C_BasePlayer::GetLocalPlayer()->GetObserverMode() ) + return true; + + if ( m_nLastSpecTarget != C_BasePlayer::GetLocalPlayer()->GetObserverTarget() ) + return true; + + return BaseClass::NeedsUpdate(); +} + +Color CDODSpectatorGUI::GetClientColor(int index) +{ + C_BasePlayer *player = ToBasePlayer( ClientEntityList().GetEnt( index) ); + + int team = player->GetTeamNumber(); + + Assert( team == TEAM_ALLIES || team == TEAM_AXIS || team == TEAM_SPECTATOR ); + + if ( GameResources() ) + return GameResources()->GetTeamColor( team ); + else + return Color( 255, 255, 255, 255 ); +} + +void CDODSpectatorGUI::Update() +{ + BaseClass::Update(); + + C_BasePlayer *pLocalPlayer = C_BasePlayer::GetLocalPlayer(); + + if( pLocalPlayer ) + { + m_nLastSpecMode = pLocalPlayer->GetObserverMode(); + m_nLastSpecTarget = pLocalPlayer->GetObserverTarget(); + } + + UpdateTimer(); + + UpdateScores(); +} + +void CDODSpectatorGUI::UpdateTimer( void ) +{ + C_DODPlayer *pPlayer = C_DODPlayer::GetLocalDODPlayer(); + + if( !pPlayer || pPlayer->IsHLTV() ) + { + wchar_t wText[ 63 ]; + + int timer; + timer = (int)( DODGameRules()->GetTimeLeft() ); + if ( timer < 0 ) + timer = 0; + + _snwprintf ( wText, sizeof(wText)/sizeof(wchar_t), L"%d:%02d", (timer / 60), (timer % 60) ); + wText[62] = 0; + + SetDialogVariable( "timer", wText ); + SetDialogVariable( "reinforcements", wText ); + } + else if( pPlayer->GetTeamNumber() == TEAM_SPECTATOR ) + { + SetDialogVariable( "timer", L"" ); + SetDialogVariable( "reinforcements", L"" ); + } + else + { + SetDialogVariable( "timer", L"" ); + + // we need to know how much longer we are going to be in death cam + // once we know that, we can ask dodgamerules if we are going to make the next + // wave. If we aren't, gamerules can tell us the new time based on the reserve wave + float flSpawnEligibleTime; + + if ( pPlayer->GetObserverMode() == OBS_MODE_DEATHCAM ) + { + flSpawnEligibleTime = pPlayer->GetDeathTime() + DEATH_CAM_TIME; + } + else + flSpawnEligibleTime = 0; + + //will never return negative seconds + int timer = DODGameRules()->GetReinforcementTimerSeconds( pPlayer->GetTeamNumber(), flSpawnEligibleTime ); + + if( timer < 0 || ( pPlayer->GetObserverMode() == OBS_MODE_DEATHCAM ) ) + { + SetDialogVariable( "reinforcements", L"" ); + } + else + { + char szMins[4], szSecs[4]; + + int mins = timer / 60; + int secs = timer % 60; + + Q_snprintf( szMins, sizeof(szMins), "%d", mins ); + Q_snprintf( szSecs, sizeof(szSecs), "%d", secs ); + + wchar_t wMins[4], wSecs[4]; + g_pVGuiLocalize->ConvertANSIToUnicode(szMins, wMins, sizeof(wMins)); + g_pVGuiLocalize->ConvertANSIToUnicode(szSecs, wSecs, sizeof(wSecs)); + + wchar_t wLabel[128]; + + if ( mins == 1 ) //"1 minute" + { + g_pVGuiLocalize->ConstructString( wLabel, sizeof( wLabel ), g_pVGuiLocalize->Find("#Dod_Reinforcements_in_min" ), 2, wMins, wSecs ); + } + else if ( mins > 0 ) //"2 minutes" + { + g_pVGuiLocalize->ConstructString( wLabel, sizeof( wLabel ), g_pVGuiLocalize->Find("#Dod_Reinforcements_in_mins" ), 2, wMins, wSecs ); + } + else if ( secs == 1 ) //"1 second" + { + g_pVGuiLocalize->ConstructString( wLabel, sizeof( wLabel ), g_pVGuiLocalize->Find("#Dod_Reinforcements_in_sec" ), 1, wSecs ); + } + else if ( secs == 0 ) //"Prepare to Respawn" + { + g_pVGuiLocalize->ConstructString( wLabel, sizeof( wLabel ), g_pVGuiLocalize->Find("#Dod_Reinforcements_prepare_to_respawn" ), 0 ); + } + else //"2 seconds" + { + g_pVGuiLocalize->ConstructString( wLabel, sizeof( wLabel ), g_pVGuiLocalize->Find("#Dod_Reinforcements_in_secs" ), 1, wSecs ); + } + + SetDialogVariable( "reinforcements", wLabel ); + } + } +} + +void CDODSpectatorGUI::UpdateScores( void ) +{ + C_DODTeam *pAlliesTeam = static_cast<C_DODTeam *>( GetGlobalTeam(TEAM_ALLIES) ); + if ( pAlliesTeam ) + { + SetDialogVariable( "alliesscore", pAlliesTeam->GetRoundsWon() ); + } + + C_DODTeam *pAxisTeam = static_cast<C_DODTeam *>( GetGlobalTeam(TEAM_AXIS) ); + if ( pAxisTeam ) + { + SetDialogVariable( "axisscore", pAxisTeam->GetRoundsWon() ); + } +} + +bool CDODSpectatorGUI::ShouldShowPlayerLabel( int specmode ) +{ + return ( (specmode == OBS_MODE_IN_EYE) || + (specmode == OBS_MODE_CHASE) || + (specmode == OBS_MODE_DEATHCAM) ); +}
\ No newline at end of file diff --git a/game/client/dod/VGUI/dodspectatorgui.h b/game/client/dod/VGUI/dodspectatorgui.h new file mode 100644 index 0000000..11b15b4 --- /dev/null +++ b/game/client/dod/VGUI/dodspectatorgui.h @@ -0,0 +1,46 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef DODSPECTATORGUI_H +#define DODSPECTATORGUI_H +#ifdef _WIN32 +#pragma once +#endif + +#include <spectatorgui.h> + + +//----------------------------------------------------------------------------- +// Purpose: Cstrike Spectator UI +//----------------------------------------------------------------------------- +class CDODSpectatorGUI : public CSpectatorGUI +{ +private: + DECLARE_CLASS_SIMPLE( CDODSpectatorGUI, CSpectatorGUI ); + +public: + CDODSpectatorGUI( IViewPort *pViewPort ); + + virtual void Update( void ); + virtual bool NeedsUpdate( void ); + virtual Color GetClientColor(int index); + + virtual bool ShouldShowPlayerLabel( int specmode ); + + //virtual bool HasInputElements( void ) { return true; } + +protected: + + void UpdateTimer(); + void UpdateScores(); + + int m_nLastTime; + int m_nLastSpecMode; + CBaseEntity *m_nLastSpecTarget; +}; + +#endif // DODSPECTATORGUI_H diff --git a/game/client/dod/VGUI/dodteammenu.cpp b/game/client/dod/VGUI/dodteammenu.cpp new file mode 100644 index 0000000..e5d4c58 --- /dev/null +++ b/game/client/dod/VGUI/dodteammenu.cpp @@ -0,0 +1,285 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#include "cbase.h" +#include "dodteammenu.h" +#include <convar.h> +#include "hud.h" // for gEngfuncs +#include "c_dod_player.h" +#include "dod_gamerules.h" +#include <vgui/ILocalize.h> +#include <vgui/IVGui.h> +#include <vgui_controls/RichText.h> +#include "c_dod_team.h" +#include "IGameUIFuncs.h" // for key bindings + +extern IGameUIFuncs *gameuifuncs; // for key binding details + +using namespace vgui; + +//----------------------------------------------------------------------------- +// Purpose: Constructor +//----------------------------------------------------------------------------- +CDODTeamMenu::CDODTeamMenu(IViewPort *pViewPort) : CTeamMenu(pViewPort) +{ + m_pBackground = SETUP_PANEL( new CDODMenuBackground( this ) ); + + m_pPanel = new EditablePanel( this, "TeamImagePanel" );// team image panel + + m_pFirstButton = NULL; + + LoadControlSettings("Resource/UI/TeamMenu.res"); // reload this to catch DODButtons + + vgui::ivgui()->AddTickSignal( GetVPanel() ); + + m_iActiveTeam = TEAM_UNASSIGNED; + m_iLastPlayerCount = -1; +} + +//----------------------------------------------------------------------------- +// Purpose: Destructor +//----------------------------------------------------------------------------- +CDODTeamMenu::~CDODTeamMenu() +{ +} + +void CDODTeamMenu::ShowPanel(bool bShow) +{ + if ( bShow ) + { + engine->CheckPoint( "TeamMenu" ); //MATTTODO what is this? + + m_iTeamMenuKey = gameuifuncs->GetButtonCodeForBind( "changeteam" ); + } + + BaseClass::ShowPanel( bShow ); +} + +//----------------------------------------------------------------------------- +// Purpose: Make the first buttons page get displayed when the menu becomes visible +//----------------------------------------------------------------------------- +void CDODTeamMenu::SetVisible( bool state ) +{ + BaseClass::SetVisible( state ); + + for( int i = 0; i< GetChildCount(); i++ ) // get all the buy buttons to performlayout + { + CDODMouseOverButton<EditablePanel> *button = dynamic_cast<CDODMouseOverButton<EditablePanel> *>(GetChild(i)); + if ( button ) + { + if( button == m_pFirstButton && state == true ) + button->ShowPage(); + else + button->HidePage(); + + button->InvalidateLayout(); + } + } + + if ( state ) + { + Panel *pAutoButton = FindChildByName( "autobutton" ); + if ( pAutoButton ) + { + pAutoButton->RequestFocus(); + } + } +} + +void CDODTeamMenu::OnTick( void ) +{ + C_DODTeam *pAllies = dynamic_cast<C_DODTeam *>( GetGlobalTeam(TEAM_ALLIES) ); + C_DODTeam *pAxis = dynamic_cast<C_DODTeam *>( GetGlobalTeam(TEAM_AXIS) ); + + if ( !pAllies || !pAxis ) + return; + + static int iLastAlliesCount = -1; + static int iLastAxisCount = -1; + + int iNumAllies = pAllies->Get_Number_Players(); + int iNumAxis = pAxis->Get_Number_Players(); + + if ( iNumAllies != iLastAlliesCount ) + { + iLastAlliesCount = iNumAllies; + + wchar_t wbuf[128]; + + if ( iNumAllies == 1 ) + { + g_pVGuiLocalize->ConstructString( wbuf, sizeof(wbuf), g_pVGuiLocalize->Find("#teammenu_numAllies_1"), 0 ); + } + else + { + wchar_t wnum[6]; + _snwprintf( wnum, ARRAYSIZE(wnum), L"%d", iNumAllies ); + g_pVGuiLocalize->ConstructString( wbuf, sizeof(wbuf), g_pVGuiLocalize->Find("#teammenu_numAllies"), 1, wnum ); + } + + Label *pLabel = dynamic_cast<Label *>( FindChildByName("num_allies") ); + + if ( pLabel ) + pLabel->SetText( wbuf ); + } + + if ( iNumAxis != iLastAxisCount ) + { + iLastAxisCount = iNumAxis; + + wchar_t wbuf[128]; + + if ( iNumAxis == 1 ) + { + g_pVGuiLocalize->ConstructString( wbuf, sizeof(wbuf), g_pVGuiLocalize->Find("#teammenu_numAxis_1"), 0 ); + } + else + { + wchar_t wnum[6]; + _snwprintf( wnum, ARRAYSIZE(wnum), L"%d", iNumAxis ); + g_pVGuiLocalize->ConstructString( wbuf, sizeof(wbuf), g_pVGuiLocalize->Find("#teammenu_numAxis"), 1, wnum ); + } + + Label *pLabel = dynamic_cast<Label *>( FindChildByName("num_axis") ); + + if ( pLabel ) + pLabel->SetText( wbuf ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: called to update the menu with new information +//----------------------------------------------------------------------------- +void CDODTeamMenu::Update( void ) +{ + BaseClass::Update(); + + C_DODPlayer *pPlayer = C_DODPlayer::GetLocalDODPlayer(); + + Assert( pPlayer ); + + const ConVar *allowspecs = cvar->FindVar( "mp_allowspectators" ); + + if ( allowspecs && allowspecs->GetBool() ) + { + if ( !pPlayer || !DODGameRules() ) + return; + + SetVisibleButton("specbutton", true); + } + else + { + SetVisibleButton("specbutton", false ); + } + + if( pPlayer->GetTeamNumber() == TEAM_UNASSIGNED ) // we aren't on a team yet + { + SetVisibleButton("CancelButton", false); + } + else + { + SetVisibleButton("CancelButton", true); + } +} + +//----------------------------------------------------------------------------- +// Purpose: When a team button is pressed it triggers this function to +// cause the player to join a team +//----------------------------------------------------------------------------- +void CDODTeamMenu::OnCommand( const char *command ) +{ + if ( !FStrEq( command, "vguicancel" ) ) + { + engine->ClientCmd( command ); + } + + BaseClass::OnCommand( command ); + + gViewPortInterface->ShowBackGround( false ); + OnClose(); +} + +//----------------------------------------------------------------------------- +// Purpose: Sets the visibility of a button by name +//----------------------------------------------------------------------------- +void CDODTeamMenu::SetVisibleButton(const char *textEntryName, bool state) +{ + Button *entry = dynamic_cast<Button *>(FindChildByName(textEntryName)); + if (entry) + { + entry->SetVisible(state); + } +} + +void CDODTeamMenu::ApplySchemeSettings( IScheme *pScheme ) +{ + + BaseClass::ApplySchemeSettings(pScheme); +} + +//----------------------------------------------------------------------------- +// Draw nothing +//----------------------------------------------------------------------------- +void CDODTeamMenu::PaintBackground( void ) +{ +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +Panel *CDODTeamMenu::CreateControlByName( const char *controlName ) +{ + if( !Q_stricmp( "DODMouseOverPanelButton", controlName ) ) + { + CDODMouseOverButton<EditablePanel> *newButton = new CDODMouseOverButton<EditablePanel>( this, NULL, m_pPanel ); + + if( !m_pFirstButton ) + { + m_pFirstButton = newButton; + } + return newButton; + } + else if( !Q_stricmp( "DODButton", controlName ) ) + { + return new CDODButton(this); + } + else if ( !Q_stricmp( "CIconPanel", controlName ) ) + { + return new CIconPanel(this, "icon_panel"); + } + else + { + return BaseClass::CreateControlByName( controlName ); + } +} + +void CDODTeamMenu::OnShowPage( char const *pagename ) +{ + if ( !pagename || !pagename[ 0 ] ) + return; + + if ( !Q_stricmp( pagename, "allies") ) + { + m_iActiveTeam = TEAM_ALLIES; + } + else if ( !Q_stricmp( pagename, "axis" ) ) + { + m_iActiveTeam = TEAM_AXIS; + } +} + +void CDODTeamMenu::OnKeyCodePressed(KeyCode code) +{ + if ( m_iTeamMenuKey != BUTTON_CODE_INVALID && m_iTeamMenuKey == code ) + { + ShowPanel( false ); + } + else + { + BaseClass::OnKeyCodePressed( code ); + } +} diff --git a/game/client/dod/VGUI/dodteammenu.h b/game/client/dod/VGUI/dodteammenu.h new file mode 100644 index 0000000..6df7bc1 --- /dev/null +++ b/game/client/dod/VGUI/dodteammenu.h @@ -0,0 +1,67 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef DODTEAMMENU_H +#define DODTEAMMENU_H +#ifdef _WIN32 +#pragma once +#endif + +#include "teammenu.h" +#include "dodmenubackground.h" +#include "dodbutton.h" +#include "dodmouseoverpanelbutton.h" +#include "IconPanel.h" + +//----------------------------------------------------------------------------- +// Purpose: Displays the team menu +//----------------------------------------------------------------------------- +class CDODTeamMenu : public CTeamMenu +{ +private: + DECLARE_CLASS_SIMPLE( CDODTeamMenu, CTeamMenu ); + +public: + CDODTeamMenu(IViewPort *pViewPort); + ~CDODTeamMenu(); + + virtual void Update(); + virtual void OnTick(); + void ShowPanel( bool bShow ); + virtual void SetVisible( bool state ); + + virtual void PaintBackground(); + virtual Panel *CreateControlByName( const char *controlName ); + + virtual void ApplySchemeSettings( IScheme *pScheme ); + + virtual void OnKeyCodePressed(KeyCode code); + +private: + enum { NUM_TEAMS = 3 }; + + MESSAGE_FUNC_CHARPTR( OnShowPage, "ShowPage", page ); + + // VGUI2 override + void OnCommand( const char *command); + // helper functions + void SetVisibleButton(const char *textEntryName, bool state); + + CDODMenuBackground *m_pBackground; + + vgui::EditablePanel *m_pPanel; + + CDODMouseOverButton<vgui::EditablePanel> *m_pFirstButton; + + int m_iLastPlayerCount; + + int m_iActiveTeam; + + ButtonCode_t m_iTeamMenuKey; +}; + +#endif // DODTEAMMENU_H diff --git a/game/client/dod/VGUI/dodtextwindow.cpp b/game/client/dod/VGUI/dodtextwindow.cpp new file mode 100644 index 0000000..9e0309f --- /dev/null +++ b/game/client/dod/VGUI/dodtextwindow.cpp @@ -0,0 +1,162 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#include "cbase.h" +#include "dodtextwindow.h" +#include <cdll_client_int.h> + +#include <vgui/IScheme.h> +#include <vgui/ILocalize.h> +#include <vgui/ISurface.h> +#include <filesystem.h> +#include <KeyValues.h> +#include <convar.h> +#include <vgui_controls/ImageList.h> + +#include <vgui_controls/TextEntry.h> +#include <vgui_controls/Button.h> +#include <vgui_controls/BuildGroup.h> + +#include "dodbutton.h" + +#include "IGameUIFuncs.h" // for key bindings +#include <igameresources.h> +extern IGameUIFuncs *gameuifuncs; // for key binding details + +#include <game/client/iviewport.h> + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +using namespace vgui; + +//----------------------------------------------------------------------------- +// Purpose: Constructor +//----------------------------------------------------------------------------- +CDODTextWindow::CDODTextWindow(IViewPort *pViewPort) : CTextWindow( pViewPort ) +{ + SetProportional( true ); + + m_iScoreBoardKey = BUTTON_CODE_INVALID; + + m_pBackground = SETUP_PANEL( new CDODMenuBackground( this ) ); + + // Do this again ( base class already does it ) + // If we don't, custom controls that we catch in our CreateControlByName + // will not go to the CDODTextWindow version as we haven't instantiated + // ourselves as a CDODTextWindow yet. + LoadControlSettings("Resource/UI/TextWindow.res"); +} + +//----------------------------------------------------------------------------- +// Purpose: Destructor +//----------------------------------------------------------------------------- +CDODTextWindow::~CDODTextWindow() +{ +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CDODTextWindow::Update() +{ + BaseClass::Update(); + + Panel *ok = FindChildByName("okbutton"); + if (ok) + { + ok->RequestFocus(); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CDODTextWindow::SetVisible(bool state) +{ + BaseClass::SetVisible(state); + + if ( state ) + { + Panel *ok = FindChildByName("okbutton"); + if (ok) + { + ok->RequestFocus(); + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: shows the text window +//----------------------------------------------------------------------------- +void CDODTextWindow::ShowPanel(bool bShow) +{ + if ( bShow ) + { + // get key binding if shown + if ( m_iScoreBoardKey == BUTTON_CODE_INVALID ) // you need to lookup the jump key AFTER the engine has loaded + { + m_iScoreBoardKey = gameuifuncs->GetButtonCodeForBind( "showscores" ); + } + } + + BaseClass::ShowPanel( bShow ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CDODTextWindow::OnKeyCodePressed(KeyCode code) +{ + if ( m_iScoreBoardKey != BUTTON_CODE_INVALID && m_iScoreBoardKey == code ) + { + gViewPortInterface->ShowPanel( PANEL_SCOREBOARD, true ); + gViewPortInterface->PostMessageToPanel( PANEL_SCOREBOARD, new KeyValues( "PollHideCode", "code", code ) ); + } + else + { + BaseClass::OnKeyCodePressed( code ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: The background is painted elsewhere, so we should do nothing +//----------------------------------------------------------------------------- +void CDODTextWindow::PaintBackground() +{ +} + +//----------------------------------------------------------------------------- +// Purpose: Scale / center the window +//----------------------------------------------------------------------------- +void CDODTextWindow::PerformLayout() +{ + BaseClass::PerformLayout(); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CDODTextWindow::ApplySchemeSettings( vgui::IScheme *pScheme ) +{ + BaseClass::ApplySchemeSettings( pScheme ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +Panel *CDODTextWindow::CreateControlByName( const char *controlName ) +{ + if( !Q_stricmp( "DODButton", controlName ) ) + { + return new CDODButton(this); + } + else + { + return BaseClass::CreateControlByName( controlName ); + } +}
\ No newline at end of file diff --git a/game/client/dod/VGUI/dodtextwindow.h b/game/client/dod/VGUI/dodtextwindow.h new file mode 100644 index 0000000..ce067db --- /dev/null +++ b/game/client/dod/VGUI/dodtextwindow.h @@ -0,0 +1,52 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef DODTEXTWINDOW_H +#define DODTEXTWINDOW_H +#ifdef _WIN32 +#pragma once +#endif + +#include "vguitextwindow.h" +#include "dodmenubackground.h" + +#include <vgui_controls/Panel.h> + +using namespace vgui; + +//----------------------------------------------------------------------------- +// Purpose: displays the MOTD +//----------------------------------------------------------------------------- + +class CDODTextWindow : public CTextWindow +{ +private: + DECLARE_CLASS_SIMPLE( CDODTextWindow, CTextWindow ); + +public: + CDODTextWindow(IViewPort *pViewPort); + virtual ~CDODTextWindow(); + + virtual void Update(); + virtual void SetVisible(bool state); + virtual void ShowPanel( bool bShow ); + virtual void OnKeyCodePressed(vgui::KeyCode code); + virtual Panel *CreateControlByName( const char *controlName ); + +protected: + ButtonCode_t m_iScoreBoardKey; + +public: + virtual void PaintBackground(); + virtual void PerformLayout(); + virtual void ApplySchemeSettings( vgui::IScheme *pScheme ); + + CDODMenuBackground *m_pBackground; +}; + + +#endif // DODTEXTWINDOW_H diff --git a/game/client/dod/VGUI/dodviewport.cpp b/game/client/dod/VGUI/dodviewport.cpp new file mode 100644 index 0000000..4ce0a74 --- /dev/null +++ b/game/client/dod/VGUI/dodviewport.cpp @@ -0,0 +1,195 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Client DLL VGUI2 Viewport +// +// $Workfile: $ +// $Date: $ +// +//----------------------------------------------------------------------------- +// $Log: $ +// +// $NoKeywords: $ +//=============================================================================// + +#include "cbase.h" + +#pragma warning( disable : 4800 ) // disable forcing int to bool performance warning + +// VGUI panel includes +#include <vgui_controls/Panel.h> +#include <vgui/ISurface.h> +#include <KeyValues.h> +#include <vgui/Cursor.h> +#include <vgui/IScheme.h> +#include <vgui/IVGui.h> +#include <vgui/ILocalize.h> +#include <vgui/VGUI.h> + +// client dll/engine defines +#include "hud.h" +#include <voice_status.h> + +#include "dodteammenu.h" +#include "dodclassmenu.h" +#include "dodclientscoreboard.h" +#include "dodspectatorgui.h" +#include "dodtextwindow.h" +#include "dodmenubackground.h" +#include "dodoverview.h" + +#include "IGameUIFuncs.h" + +// viewport definitions +#include <baseviewport.h> +#include "dodviewport.h" +#include "vguicenterprint.h" +#include "text_message.h" +#include "c_dod_player.h" + + +CON_COMMAND_F( changeteam, "Choose a new team", FCVAR_SERVER_CAN_EXECUTE|FCVAR_CLIENTCMD_CAN_EXECUTE ) +{ + C_DODPlayer *pPlayer = C_DODPlayer::GetLocalDODPlayer(); + + if ( pPlayer && pPlayer->CanShowTeamMenu() ) + { + gViewPortInterface->ShowPanel( PANEL_TEAM, true ); + } +} + +CON_COMMAND_F( changeclass, "Choose a new class", FCVAR_SERVER_CAN_EXECUTE|FCVAR_CLIENTCMD_CAN_EXECUTE ) +{ + C_DODPlayer *pPlayer = C_DODPlayer::GetLocalDODPlayer(); + + if ( pPlayer && pPlayer->CanShowClassMenu()) + { + switch( pPlayer->GetTeamNumber() ) + { + case TEAM_ALLIES: + gViewPortInterface->ShowPanel( PANEL_CLASS_ALLIES, true ); + break; + case TEAM_AXIS: + gViewPortInterface->ShowPanel( PANEL_CLASS_AXIS, true ); + break; + default: + break; + } + } +} + +CON_COMMAND_F( spec_menu, "Activates spectator menu", FCVAR_SERVER_CAN_EXECUTE|FCVAR_CLIENTCMD_CAN_EXECUTE) +{ + bool bShowIt = true; + + if ( args.ArgC() == 2 ) + { + bShowIt = atoi( args[ 1 ] ) == 1; + } + + if ( gViewPortInterface ) + { + gViewPortInterface->ShowPanel( PANEL_SPECMENU, bShowIt ); + } +} + +CON_COMMAND_F( togglescores, "Toggles score panel", FCVAR_SERVER_CAN_EXECUTE|FCVAR_CLIENTCMD_CAN_EXECUTE) +{ + if ( !gViewPortInterface ) + return; + + IViewPortPanel *scoreboard = gViewPortInterface->FindPanelByName( PANEL_SCOREBOARD ); + + if ( !scoreboard ) + return; + + if ( scoreboard->IsVisible() ) + { + gViewPortInterface->ShowPanel( scoreboard, false ); + GetClientVoiceMgr()->StopSquelchMode(); + } + else + { + gViewPortInterface->ShowPanel( scoreboard, true ); + } +} + + +void DODViewport::ApplySchemeSettings( vgui::IScheme *pScheme ) +{ + BaseClass::ApplySchemeSettings( pScheme ); + + gHUD.InitColors( pScheme ); + + SetPaintBackgroundEnabled( false ); +} + + +IViewPortPanel* DODViewport::CreatePanelByName(const char *szPanelName) +{ + IViewPortPanel* newpanel = NULL; + + // overwrite MOD specific panel creation + if ( Q_strcmp(PANEL_TEAM, szPanelName) == 0 ) + { + newpanel = new CDODTeamMenu( this ); + } + else if ( Q_strcmp(PANEL_CLASS_ALLIES, szPanelName) == 0 ) + { + newpanel = new CDODClassMenu_Allies( this ); + } + else if ( Q_strcmp(PANEL_CLASS_AXIS, szPanelName) == 0 ) + { + newpanel = new CDODClassMenu_Axis( this ); + } + else if ( Q_strcmp(PANEL_SCOREBOARD, szPanelName) == 0) + { + newpanel = new CDODClientScoreBoardDialog( this ); + } + else if ( Q_strcmp(PANEL_SPECGUI, szPanelName) == 0 ) + { + newpanel = new CDODSpectatorGUI( this ); + } + else if ( Q_strcmp(PANEL_INFO, szPanelName) == 0 ) + { + newpanel = new CDODTextWindow( this ); + } + else + { + // create a generic base panel, don't add twice + newpanel = BaseClass::CreatePanelByName( szPanelName ); + } + + return newpanel; +} + +void DODViewport::CreateDefaultPanels( void ) +{ + AddNewPanel( CreatePanelByName( PANEL_TEAM ), "PANEL_TEAM" ); + AddNewPanel( CreatePanelByName( PANEL_CLASS_ALLIES ), "PANEL_CLASS_ALLIES" ); + AddNewPanel( CreatePanelByName( PANEL_CLASS_AXIS ), "PANEL_CLASS_AXIS" ); + + BaseClass::CreateDefaultPanels(); +} + +int DODViewport::GetDeathMessageStartHeight( void ) +{ + int y = YRES(5); + + if ( g_pSpectatorGUI && g_pSpectatorGUI->IsVisible() ) + { + y = g_pSpectatorGUI->GetTopBarHeight() + YRES(5); + } + + if ( g_pMapOverview && g_pMapOverview->IsVisible() ) + { + if ( g_pMapOverview->GetMode() == CMapOverview::MAP_MODE_INSET ) + { + int map_x, map_y, map_w, map_h; + g_pMapOverview->GetBounds( map_x, map_y, map_w, map_h ); + + y = map_y + map_h + YRES(5); + } + } + + return y; +} diff --git a/game/client/dod/VGUI/dodviewport.h b/game/client/dod/VGUI/dodviewport.h new file mode 100644 index 0000000..cf241ae --- /dev/null +++ b/game/client/dod/VGUI/dodviewport.h @@ -0,0 +1,49 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef DODVIEWPORT_H +#define DODVIEWPORT_H + +#include "baseviewport.h" + +using namespace vgui; + +namespace vgui +{ + class Panel; +} + +class CDODTeamMenu; +class CDODClassMenu_Allies; +class CDODClassMenu_Axis; +class CDODSpectatorGUI; +class CDODClientScoreBoardDialog; +class CDODMenuBackground; + + +//============================================================================== +class DODViewport : public CBaseViewport +{ + +private: + DECLARE_CLASS_SIMPLE( DODViewport, CBaseViewport ); + +public: + + IViewPortPanel* CreatePanelByName(const char *szPanelName); + void CreateDefaultPanels( void ); + + virtual void ApplySchemeSettings( vgui::IScheme *pScheme ); + + int GetDeathMessageStartHeight( void ); + + // Never show the background + virtual void ShowBackGround(bool bShow) { NULL; } +}; + + +#endif // DODVIEWPORT_H diff --git a/game/client/dod/VGUI/idodviewportmsgs.h b/game/client/dod/VGUI/idodviewportmsgs.h new file mode 100644 index 0000000..ae25fba --- /dev/null +++ b/game/client/dod/VGUI/idodviewportmsgs.h @@ -0,0 +1,25 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: interface class between viewport msg funcs and "c" based client dll +// +// $NoKeywords: $ +//=============================================================================// +#if !defined( IDODVIEWPORTMSGS_H ) +#define IDODVIEWPORTMSGS_H +#ifdef _WIN32 +#pragma once +#endif + +//#include "vgui/IViewPortMsgs.h" + +class IDODViewPortMsgs /*: public IViewPortMsgs*/ +{ +public: + virtual int MsgFunc_ScoreInfo( const char *pszName, int iSize, void *pbuf ) = 0; + +}; + + +extern IDODViewPortMsgs *gDODViewPortMsgs; + +#endif // IDODVIEWPORTMSGS_H
\ No newline at end of file diff --git a/game/client/dod/VGUI/vgui_rootpanel_dod.cpp b/game/client/dod/VGUI/vgui_rootpanel_dod.cpp new file mode 100644 index 0000000..eab820a --- /dev/null +++ b/game/client/dod/VGUI/vgui_rootpanel_dod.cpp @@ -0,0 +1,106 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// +#include "cbase.h" +#include "vgui_int.h" +#include "ienginevgui.h" +#include "vgui_rootpanel_dod.h" +#include "vgui/IVGui.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +C_DODRootPanel *g_pRootPanel = NULL; + + +//----------------------------------------------------------------------------- +// Global functions. +//----------------------------------------------------------------------------- +void VGUI_CreateClientDLLRootPanel( void ) +{ + g_pRootPanel = new C_DODRootPanel( enginevgui->GetPanel( PANEL_CLIENTDLL ) ); +} + +void VGUI_DestroyClientDLLRootPanel( void ) +{ + delete g_pRootPanel; + g_pRootPanel = NULL; +} + +vgui::VPANEL VGui_GetClientDLLRootPanel( void ) +{ + return g_pRootPanel->GetVPanel(); +} + + +//----------------------------------------------------------------------------- +// C_DODRootPanel implementation. +//----------------------------------------------------------------------------- +C_DODRootPanel::C_DODRootPanel( vgui::VPANEL parent ) + : BaseClass( NULL, "DOD Root Panel" ) +{ + SetParent( parent ); + SetPaintEnabled( false ); + SetPaintBorderEnabled( false ); + SetPaintBackgroundEnabled( false ); + + // This panel does post child painting + SetPostChildPaintEnabled( true ); + + // Make it screen sized + SetBounds( 0, 0, ScreenWidth(), ScreenHeight() ); + + // Ask for OnTick messages + vgui::ivgui()->AddTickSignal( GetVPanel() ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +C_DODRootPanel::~C_DODRootPanel( void ) +{ +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_DODRootPanel::PostChildPaint() +{ + BaseClass::PostChildPaint(); + + // Draw all panel effects + RenderPanelEffects(); +} + +//----------------------------------------------------------------------------- +// Purpose: For each panel effect, check if it wants to draw and draw it on +// this panel/surface if so +//----------------------------------------------------------------------------- +void C_DODRootPanel::RenderPanelEffects( void ) +{ +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_DODRootPanel::OnTick( void ) +{ +} + +//----------------------------------------------------------------------------- +// Purpose: Reset effects on level load/shutdown +//----------------------------------------------------------------------------- +void C_DODRootPanel::LevelInit( void ) +{ +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_DODRootPanel::LevelShutdown( void ) +{ +} + diff --git a/game/client/dod/VGUI/vgui_rootpanel_dod.h b/game/client/dod/VGUI/vgui_rootpanel_dod.h new file mode 100644 index 0000000..6390b8c --- /dev/null +++ b/game/client/dod/VGUI/vgui_rootpanel_dod.h @@ -0,0 +1,56 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef VGUI_ROOTPANEL_DOD_H +#define VGUI_ROOTPANEL_DOD_H +#ifdef _WIN32 +#pragma once +#endif + + +#include <vgui_controls/Panel.h> +#include <vgui_controls/EditablePanel.h> +#include "utlvector.h" + + +class CPanelEffect; + + +// Serial under of effect, for safe lookup +typedef unsigned int EFFECT_HANDLE; + +//----------------------------------------------------------------------------- +// Purpose: Sits between engine and client .dll panels +// Responsible for drawing screen overlays +//----------------------------------------------------------------------------- +class C_DODRootPanel : public vgui::Panel +{ + typedef vgui::Panel BaseClass; +public: + C_DODRootPanel( vgui::VPANEL parent ); + virtual ~C_DODRootPanel( void ); + + // Draw Panel effects here + virtual void PostChildPaint(); + + // Clear list of Panel Effects + virtual void LevelInit( void ); + virtual void LevelShutdown( void ); + + // Run effects and let them decide whether to remove themselves + void OnTick( void ); + +private: + + // Render all panel effects + void RenderPanelEffects( void ); + + // List of current panel effects + CUtlVector< CPanelEffect *> m_Effects; +}; + + +#endif // VGUI_ROOTPANEL_DOD_H diff --git a/game/client/dod/c_dod_basegrenade.cpp b/game/client/dod/c_dod_basegrenade.cpp new file mode 100644 index 0000000..c2f6212 --- /dev/null +++ b/game/client/dod/c_dod_basegrenade.cpp @@ -0,0 +1,107 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#include "cbase.h" +#include "c_dod_basegrenade.h" + + +#include "c_dod_player.h" +#include "dodoverview.h" + +IMPLEMENT_NETWORKCLASS_ALIASED( DODBaseGrenade, DT_DODBaseGrenade ) + +BEGIN_NETWORK_TABLE(C_DODBaseGrenade, DT_DODBaseGrenade ) + RecvPropVector( RECVINFO( m_vInitialVelocity ) ) +END_NETWORK_TABLE() + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +C_DODBaseGrenade::~C_DODBaseGrenade() +{ + GetDODOverview()->RemoveGrenade( this ); + ParticleProp()->StopEmission(); +} + +void C_DODBaseGrenade::PostDataUpdate( DataUpdateType_t type ) +{ + BaseClass::PostDataUpdate( type ); + + if ( type == DATA_UPDATE_CREATED ) + { + // Now stick our initial velocity into the interpolation history + CInterpolatedVar< Vector > &interpolator = GetOriginInterpolator(); + + interpolator.ClearHistory(); + float changeTime = GetLastChangeTime( LATCH_SIMULATION_VAR ); + + // Add a sample 1 second back. + Vector vCurOrigin = GetLocalOrigin() - m_vInitialVelocity; + interpolator.AddToHead( changeTime - 1.0, &vCurOrigin, false ); + + // Add the current sample. + vCurOrigin = GetLocalOrigin(); + interpolator.AddToHead( changeTime, &vCurOrigin, false ); + + // BUG ? this may call multiple times + GetDODOverview()->AddGrenade( this ); + + const char *pszParticleTrail = GetParticleTrailName(); + if ( pszParticleTrail ) + { + ParticleProp()->Create( pszParticleTrail, PATTACH_ABSORIGIN_FOLLOW ); + } + } +} + +int C_DODBaseGrenade::DrawModel( int flags ) +{ + if( m_flSpawnTime + 0.15 > gpGlobals->curtime ) + return 0; + + C_DODPlayer *pPlayer = C_DODPlayer::GetLocalDODPlayer(); + + if ( pPlayer && GetAbsVelocity().Length() < 30 ) + { + pPlayer->CheckGrenadeHint( GetAbsOrigin() ); + } + + return BaseClass::DrawModel( flags ); +} + +void C_DODBaseGrenade::Spawn() +{ + m_flSpawnTime = gpGlobals->curtime; + BaseClass::Spawn(); +} + +const char *C_DODBaseGrenade::GetOverviewSpriteName( void ) +{ + const char *pszSprite = ""; + + switch( GetTeamNumber() ) + { + case TEAM_ALLIES: + pszSprite = "sprites/minimap_icons/grenade_hltv"; + break; + case TEAM_AXIS: + pszSprite = "sprites/minimap_icons/stick_hltv"; + break; + default: + break; + } + + return pszSprite; +} + +IMPLEMENT_NETWORKCLASS_ALIASED( DODRifleGrenadeUS, DT_DODRifleGrenadeUS ) + +BEGIN_NETWORK_TABLE(C_DODRifleGrenadeUS, DT_DODRifleGrenadeUS ) +END_NETWORK_TABLE() + + +IMPLEMENT_CLIENTCLASS_DT(C_DODRifleGrenadeGER, DT_DODRifleGrenadeGER, CDODRifleGrenadeGER) +END_RECV_TABLE()
\ No newline at end of file diff --git a/game/client/dod/c_dod_basegrenade.h b/game/client/dod/c_dod_basegrenade.h new file mode 100644 index 0000000..bbd46aa --- /dev/null +++ b/game/client/dod/c_dod_basegrenade.h @@ -0,0 +1,72 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#ifndef C_DOD_BASEGRENADE_H +#define C_DOD_BASEGRENADE_H +#ifdef _WIN32 +#pragma once +#endif + +#include "basegrenade_shared.h" + +class C_DODBaseGrenade : public CBaseGrenade +{ +public: + DECLARE_CLASS( C_DODBaseGrenade, CBaseGrenade ); + DECLARE_NETWORKCLASS(); + + virtual void Spawn(); + +public: + C_DODBaseGrenade() {} + C_DODBaseGrenade( const C_DODBaseGrenade& ) {} + virtual ~C_DODBaseGrenade(); + + virtual int DrawModel( int flags ); + virtual void PostDataUpdate( DataUpdateType_t type ); + + virtual const char *GetOverviewSpriteName( void ); + + virtual const char *GetParticleTrailName( void ) { return "grenadetrail"; } + + float m_flSpawnTime; + + // This gets sent to the client and placed in the client's interpolation history + // so the projectile starts out moving right off the bat. + CNetworkVector( m_vInitialVelocity ); + +}; + + +class C_DODRifleGrenadeUS : public C_DODBaseGrenade +{ +public: + DECLARE_CLASS( C_DODRifleGrenadeUS, C_DODBaseGrenade ); + DECLARE_NETWORKCLASS(); + + virtual const char *GetOverviewSpriteName( void ) + { + return "sprites/minimap_icons/minimap_riflegren_us"; + } + + virtual const char *GetParticleTrailName( void ) { return "riflegrenadetrail"; } +}; + +class C_DODRifleGrenadeGER : public C_DODBaseGrenade +{ +public: + DECLARE_CLASS( C_DODRifleGrenadeGER, C_DODBaseGrenade ); + DECLARE_CLIENTCLASS(); + + virtual const char *GetOverviewSpriteName( void ) + { + return "sprites/minimap_icons/minimap_riflegren_ger"; + } + + virtual const char *GetParticleTrailName( void ) { return "riflegrenadetrail"; } +}; + +#endif // C_DOD_BASEGRENADE_H diff --git a/game/client/dod/c_dod_baserocket.cpp b/game/client/dod/c_dod_baserocket.cpp new file mode 100644 index 0000000..b20de9b --- /dev/null +++ b/game/client/dod/c_dod_baserocket.cpp @@ -0,0 +1,110 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#include "cbase.h" +#include "c_baseanimating.h" + + +class C_DODBaseRocket : public C_BaseAnimating +{ +public: + DECLARE_CLASS( C_DODBaseRocket, C_BaseAnimating ); + DECLARE_CLIENTCLASS(); + + C_DODBaseRocket(); + virtual ~C_DODBaseRocket(); + + virtual void Spawn(); + virtual int DrawModel( int flags ); + virtual void PostDataUpdate( DataUpdateType_t type ); + +private: + CNetworkVector( m_vInitialVelocity ); + float m_flSpawnTime; +}; + + +IMPLEMENT_CLIENTCLASS_DT(C_DODBaseRocket, DT_DODBaseRocket, CDODBaseRocket) + RecvPropVector( RECVINFO( m_vInitialVelocity ) ) +END_RECV_TABLE() + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +C_DODBaseRocket::C_DODBaseRocket() +{ +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +C_DODBaseRocket::~C_DODBaseRocket() +{ + ParticleProp()->StopEmission(); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_DODBaseRocket::Spawn() +{ + m_flSpawnTime = gpGlobals->curtime; + BaseClass::Spawn(); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_DODBaseRocket::PostDataUpdate( DataUpdateType_t type ) +{ + BaseClass::PostDataUpdate( type ); + + if ( type == DATA_UPDATE_CREATED ) + { + // Now stick our initial velocity into the interpolation history + CInterpolatedVar< Vector > &interpolator = GetOriginInterpolator(); + + interpolator.ClearHistory(); + float changeTime = GetLastChangeTime( LATCH_SIMULATION_VAR ); + + // Add a sample 1 second back. + Vector vCurOrigin = GetLocalOrigin() - m_vInitialVelocity; + interpolator.AddToHead( changeTime - 1.0, &vCurOrigin, false ); + + // Add the current sample. + vCurOrigin = GetLocalOrigin(); + interpolator.AddToHead( changeTime, &vCurOrigin, false ); + + // do the same for angles + CInterpolatedVar< QAngle > &rotInterpolator = GetRotationInterpolator(); + + rotInterpolator.ClearHistory(); + + // Add a rotation sample 1 second back + QAngle vCurAngles = GetLocalAngles(); + rotInterpolator.AddToHead( changeTime - 1.0, &vCurAngles, false ); + + // Add the current rotation + rotInterpolator.AddToHead( changeTime - 1.0, &vCurAngles, false ); + + int iAttachment = 1; //LookupAttachment( "smoke" ); // don't do bone access at this time, we know it's 1. + ParticleProp()->Create( "rockettrail", PATTACH_POINT_FOLLOW, iAttachment ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +int C_DODBaseRocket::DrawModel( int flags ) +{ + // During the first half-second of our life, don't draw ourselves + if ( gpGlobals->curtime - m_flSpawnTime < 0.2 ) + { + return 0; + } + + return BaseClass::DrawModel( flags ); +}
\ No newline at end of file diff --git a/game/client/dod/c_dod_bombdispenser.cpp b/game/client/dod/c_dod_bombdispenser.cpp new file mode 100644 index 0000000..61b8b2c --- /dev/null +++ b/game/client/dod/c_dod_bombdispenser.cpp @@ -0,0 +1,43 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#include "cbase.h" +#include "c_dod_player.h" +#include "dodoverview.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +class C_DODBombDispenserMapIcon : public C_BaseEntity +{ + DECLARE_CLASS( C_DODBombDispenserMapIcon, C_BaseEntity ); + + DECLARE_NETWORKCLASS(); + +public: + virtual ~C_DODBombDispenserMapIcon(); + virtual void OnDataChanged( DataUpdateType_t type ); +}; + +IMPLEMENT_NETWORKCLASS_ALIASED( DODBombDispenserMapIcon, DT_DODBombDispenserMapIcon ) + +BEGIN_NETWORK_TABLE(C_DODBombDispenserMapIcon, DT_DODBombDispenserMapIcon ) +END_NETWORK_TABLE() + +C_DODBombDispenserMapIcon::~C_DODBombDispenserMapIcon( void ) +{ + GetDODOverview()->RemoveObjectByIndex( entindex() ); +} + +void C_DODBombDispenserMapIcon::OnDataChanged( DataUpdateType_t type ) +{ + BaseClass::OnDataChanged( type ); + + if ( type == DATA_UPDATE_CREATED ) + { + GetDODOverview()->AddObject( "sprites/obj_icons/icon_bomb_dispenser", entindex(), -1 ); + } +}
\ No newline at end of file diff --git a/game/client/dod/c_dod_bombtarget.cpp b/game/client/dod/c_dod_bombtarget.cpp new file mode 100644 index 0000000..c14ed1d --- /dev/null +++ b/game/client/dod/c_dod_bombtarget.cpp @@ -0,0 +1,115 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#include "cbase.h" +#include "c_dod_bombtarget.h" +#include "dod_shareddefs.h" +#include "c_dod_player.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +IMPLEMENT_NETWORKCLASS_ALIASED( DODBombTarget, DT_DODBombTarget ) + +BEGIN_NETWORK_TABLE(C_DODBombTarget, DT_DODBombTarget ) + RecvPropInt( RECVINFO(m_iState) ), + RecvPropInt( RECVINFO(m_iBombingTeam) ), + + RecvPropInt( RECVINFO(m_iTargetModel) ), + RecvPropInt( RECVINFO(m_iUnavailableModel) ), +END_NETWORK_TABLE() + +void C_DODBombTarget::NotifyShouldTransmit( ShouldTransmitState_t state ) +{ + BaseClass::NotifyShouldTransmit( state ); + + // Turn off + if ( state == SHOULDTRANSMIT_END ) + { + SetNextClientThink( CLIENT_THINK_NEVER ); + } + + // Turn on + if ( state == SHOULDTRANSMIT_START ) + { + SetNextClientThink( CLIENT_THINK_ALWAYS ); + } +} + +void C_DODBombTarget::ClientThink( void ) +{ + // if we are near the player, maybe give them a hint! + + C_DODPlayer *pPlayer = C_DODPlayer::GetLocalDODPlayer(); + + if ( pPlayer && pPlayer->IsAlive() ) + { + Vector vecDist = GetAbsOrigin() - pPlayer->GetAbsOrigin(); + + if ( vecDist.Length() < 200 ) + { + int iOppositeTeam = ( m_iBombingTeam == TEAM_ALLIES ) ? TEAM_AXIS : TEAM_ALLIES; + if ( pPlayer->GetTeamNumber() == m_iBombingTeam && m_iState == BOMB_TARGET_ACTIVE ) + { + pPlayer->CheckBombTargetPlantHint(); + } + else if ( pPlayer->GetTeamNumber() == iOppositeTeam && m_iState == BOMB_TARGET_ARMED ) + { + pPlayer->CheckBombTargetDefuseHint(); + } + } + } + + SetNextClientThink( gpGlobals->curtime + 0.5 ); +} + +int C_DODBombTarget::DrawModel( int flags ) +{ + if ( m_iState == BOMB_TARGET_ACTIVE ) + { + C_DODPlayer *pPlayer = C_DODPlayer::GetLocalDODPlayer(); + + int iOppositeTeam = ( m_iBombingTeam == TEAM_ALLIES ) ? TEAM_AXIS : TEAM_ALLIES; + +#ifdef _DEBUG + if ( m_iBombingTeam == TEAM_UNASSIGNED ) + iOppositeTeam = TEAM_UNASSIGNED; +#endif + + if ( pPlayer && pPlayer->GetTeamNumber() == iOppositeTeam ) + { + // draw a different model for the non-planting team + + if ( GetModelIndex() != m_iUnavailableModel ) + { + SetModelIndex( m_iUnavailableModel ); + } + } + else + { + if ( GetModelIndex() != m_iTargetModel ) + { + SetModelIndex( m_iTargetModel ); + } + } + } + + return BaseClass::DrawModel( flags ); +} + +// a player of the passed team is looking at us, see if we should +// play the hint telling them how to defuse +bool C_DODBombTarget::ShouldPlayDefuseHint( int team ) +{ + return ( m_iState == BOMB_TARGET_ARMED && team != m_iBombingTeam ); +} + +// a player of the passed team is looking at us, see if we should +// play the hint telling them how to plant a bomb here +bool C_DODBombTarget::ShouldPlayPlantHint( int team ) +{ + return ( m_iState == BOMB_TARGET_ACTIVE && team == m_iBombingTeam ); +} diff --git a/game/client/dod/c_dod_bombtarget.h b/game/client/dod/c_dod_bombtarget.h new file mode 100644 index 0000000..79373eb --- /dev/null +++ b/game/client/dod/c_dod_bombtarget.h @@ -0,0 +1,38 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#ifndef C_DOD_BOMBTARGET_H +#define C_DOD_BOMBTARGET_H +#ifdef _WIN32 +#pragma once +#endif + +#include "c_baseanimating.h" + +class C_DODBombTarget : public C_BaseAnimating +{ + DECLARE_CLASS( C_DODBombTarget, C_BaseAnimating ); + + DECLARE_NETWORKCLASS(); + +public: + virtual int DrawModel( int flags ); + virtual void NotifyShouldTransmit( ShouldTransmitState_t state ); + virtual void ClientThink( void ); + + // play the hint telling them how to defuse + bool ShouldPlayDefuseHint( int team ); + bool ShouldPlayPlantHint( int team ); + +private: + CNetworkVar( int, m_iState ); + CNetworkVar( int, m_iBombingTeam ); + + CNetworkVar( int, m_iTargetModel ); + CNetworkVar( int, m_iUnavailableModel ); +}; + +#endif //C_DOD_BOMBTARGET_H
\ No newline at end of file diff --git a/game/client/dod/c_dod_objective_resource.cpp b/game/client/dod/c_dod_objective_resource.cpp new file mode 100644 index 0000000..097afc5 --- /dev/null +++ b/game/client/dod/c_dod_objective_resource.cpp @@ -0,0 +1,177 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Entity that propagates objective data +// +// $NoKeywords: $ +//=============================================================================// +#include "cbase.h" +#include "c_dod_objective_resource.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +// owner recv proxy +void RecvProxy_Owner( const CRecvProxyData *pData, void *pStruct, void *pOut ) +{ + // hacks? Not sure how else to get the index of the integer that is + // being transmitted. + int index = pData->m_pRecvProp->GetOffset() / sizeof(int); + + g_pObjectiveResource->SetOwningTeam( index, pData->m_Value.m_Int ); +} + +// capper recv proxy +void RecvProxy_CappingTeam( const CRecvProxyData *pData, void *pStruct, void *pOut ) +{ + int index = pData->m_pRecvProp->GetOffset() / sizeof(int); + + g_pObjectiveResource->SetCappingTeam( index, pData->m_Value.m_Int ); +} + +void RecvProxy_BombPlanted( const CRecvProxyData *pData, void *pStruct, void *pOut ) +{ + int index = pData->m_pRecvProp->GetOffset() / sizeof(bool); + + g_pObjectiveResource->SetBombPlanted( index, pData->m_Value.m_Int ); +} + +IMPLEMENT_CLIENTCLASS_DT_NOBASE(C_DODObjectiveResource, DT_DODObjectiveResource, CDODObjectiveResource) + + RecvPropInt( RECVINFO(m_iNumControlPoints) ), + + // data variables + RecvPropArray( RecvPropVector(RECVINFO(m_vCPPositions[0])), m_vCPPositions), + RecvPropArray3( RECVINFO_ARRAY(m_bCPIsVisible), RecvPropInt( RECVINFO(m_bCPIsVisible[0]) ) ), + RecvPropArray3( RECVINFO_ARRAY(m_iAlliesIcons), RecvPropInt( RECVINFO(m_iAlliesIcons[0]) ) ), + RecvPropArray3( RECVINFO_ARRAY(m_iAxisIcons), RecvPropInt( RECVINFO(m_iAxisIcons[0]) ) ), + RecvPropArray3( RECVINFO_ARRAY(m_iNeutralIcons), RecvPropInt( RECVINFO(m_iNeutralIcons[0]) ) ), + RecvPropArray3( RECVINFO_ARRAY(m_iTimerCapIcons), RecvPropInt( RECVINFO(m_iTimerCapIcons[0]) ) ), + RecvPropArray3( RECVINFO_ARRAY(m_iBombedIcons), RecvPropInt( RECVINFO(m_iBombedIcons[0]) ) ), + RecvPropArray3( RECVINFO_ARRAY(m_iAlliesReqCappers),RecvPropInt( RECVINFO(m_iAlliesReqCappers[0]) ) ), + RecvPropArray3( RECVINFO_ARRAY(m_iAxisReqCappers), RecvPropInt( RECVINFO(m_iAxisReqCappers[0]) ) ), + RecvPropArray3( RECVINFO_ARRAY(m_flAlliesCapTime), RecvPropTime( RECVINFO(m_flAlliesCapTime[0]) ) ), + RecvPropArray3( RECVINFO_ARRAY(m_flAxisCapTime), RecvPropTime( RECVINFO(m_flAxisCapTime[0]) ) ), + RecvPropArray3( RECVINFO_ARRAY(m_bBombPlanted), RecvPropInt( RECVINFO(m_bBombPlanted[0]), 0, RecvProxy_BombPlanted ) ), + RecvPropArray3( RECVINFO_ARRAY(m_iBombsRequired), RecvPropInt( RECVINFO(m_iBombsRequired[0]) ) ), + RecvPropArray3( RECVINFO_ARRAY(m_iBombsRemaining), RecvPropInt( RECVINFO(m_iBombsRemaining[0]) ) ), + RecvPropArray3( RECVINFO_ARRAY(m_bBombBeingDefused),RecvPropInt( RECVINFO(m_bBombBeingDefused[0]) ) ), + + // state variables + RecvPropArray3( RECVINFO_ARRAY(m_iNumAllies), RecvPropInt( RECVINFO(m_iNumAllies[0]) ) ), + RecvPropArray3( RECVINFO_ARRAY(m_iNumAxis), RecvPropInt( RECVINFO(m_iNumAxis[0]) ) ), + RecvPropArray3( RECVINFO_ARRAY(m_iCappingTeam), RecvPropInt( RECVINFO(m_iCappingTeam[0]), 0, RecvProxy_CappingTeam ) ), + RecvPropArray3( RECVINFO_ARRAY(m_iOwner), RecvPropInt( RECVINFO(m_iOwner[0]), 0, RecvProxy_Owner ) ), + +END_RECV_TABLE() + +C_DODObjectiveResource *g_pObjectiveResource; + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +C_DODObjectiveResource::C_DODObjectiveResource() +{ + m_iNumControlPoints = 0; + + for ( int i=0; i < MAX_CONTROL_POINTS; i++ ) + { + m_flCapStartTimes[i] = 0; + m_flCapEndTimes[i] = 0; + m_iAlliesIcons[i] = 0; + m_iAxisIcons[i] = 0; + m_iNeutralIcons[i] = 0; + m_iTimerCapIcons[i] = 0; + m_iBombedIcons[i] = 0; + m_iNumAllies[i] = 0; + m_iNumAxis[i] = 0; + } + + g_pObjectiveResource = this; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +C_DODObjectiveResource::~C_DODObjectiveResource() +{ + g_pObjectiveResource = NULL; +} + +float C_DODObjectiveResource::GetCPCapPercentage( int index ) +{ + Assert( 0 <= index && index <= m_iNumControlPoints ); + + float flCapLength = m_flCapEndTimes[index] - m_flCapStartTimes[index]; + + if( flCapLength <= 0 ) + return 0.0f; + + float flElapsedTime = gpGlobals->curtime - m_flCapStartTimes[index]; + + if( flElapsedTime > flCapLength ) + return 1.0f; + + return ( flElapsedTime / flCapLength ); +} + +void C_DODObjectiveResource::SetOwningTeam( int index, int team ) +{ + int cappingTeam = GetCappingTeam(index); + + if ( team == cappingTeam ) + { + // successful cap, reset things + m_iCappingTeam[index] = TEAM_UNASSIGNED; + m_flCapStartTimes[index] = 0.0f; + m_flCapEndTimes[index] = 0.0f; + } + + m_iOwner[index] = team; +} + +void C_DODObjectiveResource::SetCappingTeam( int index, int team ) +{ + if ( team != GetOwningTeam( index ) && ( team == TEAM_ALLIES || team == TEAM_AXIS ) ) + { + int caplength = 0; + + switch ( team ) + { + case TEAM_ALLIES: + caplength = m_flAlliesCapTime[index]; + break; + case TEAM_AXIS: + caplength = m_flAxisCapTime[index]; + break; + } + + // start the cap + m_flCapStartTimes[index] = gpGlobals->curtime; + m_flCapEndTimes[index] = gpGlobals->curtime + caplength; + } + else + { + m_flCapStartTimes[index] = 0.0; + m_flCapEndTimes[index] = 0.0; + } + + m_iCappingTeam[index] = team; +} + +void C_DODObjectiveResource::SetBombPlanted( int index, int iBombPlanted ) +{ + // Assert( index < m_iNumControlPoints ); + + m_bBombPlanted[index] = ( iBombPlanted > 0 ); + + if ( m_bBombPlanted[index] ) + { + // start the countdown, make timer visible + m_flBombEndTimes[index] = gpGlobals->curtime + DOD_BOMB_TIMER_LENGTH; + } + else + { + // hide timer, reset countdown + m_flBombEndTimes[index] = 0; + } +}
\ No newline at end of file diff --git a/game/client/dod/c_dod_objective_resource.h b/game/client/dod/c_dod_objective_resource.h new file mode 100644 index 0000000..a8ab994 --- /dev/null +++ b/game/client/dod/c_dod_objective_resource.h @@ -0,0 +1,239 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Entity that propagates general data needed by clients for every player. +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef C_DOD_OBJECTIVE_RESOURCE_H +#define C_DOD_OBJECTIVE_RESOURCE_H +#ifdef _WIN32 +#pragma once +#endif + +#include "dod_shareddefs.h" +#include "const.h" +#include "c_baseentity.h" +#include <igameresources.h> + + +class C_DODObjectiveResource : public C_BaseEntity +{ + DECLARE_CLASS( C_DODObjectiveResource, C_BaseEntity ); +public: + DECLARE_CLIENTCLASS(); + + C_DODObjectiveResource(); + virtual ~C_DODObjectiveResource(); + +public: + + float GetCPCapPercentage( int index ); + int GetNumControlPoints( void ) { return m_iNumControlPoints; } + + void SetOwningTeam( int index, int team ); + void SetCappingTeam( int index, int team ); + + // Is the point visible in the objective display + bool IsCPVisible( int index ) + { + Assert( index < m_iNumControlPoints ); + + return m_bCPIsVisible[index]; + } + + // Get the world location of this control point + Vector& GetCPPosition( int index ) + { + Assert( index < m_iNumControlPoints ); + return m_vCPPositions[index]; + } + + int GetOwningTeam( int index ) + { + if ( index >= m_iNumControlPoints ) + return TEAM_UNASSIGNED; + + return m_iOwner[index]; + } + + int GetCappingTeam( int index ) + { + if ( index >= m_iNumControlPoints ) + return TEAM_UNASSIGNED; + + return m_iCappingTeam[index]; + } + + // Icons + int GetCPCurrentOwnerIcon( int index ) + { + Assert( index < m_iNumControlPoints ); + + int iOwner = GetOwningTeam(index); + + return GetIconForTeam( index, iOwner ); + } + + int GetCPCappingIcon( int index ) + { + Assert( index < m_iNumControlPoints ); + + int iCapper = GetCappingTeam(index); + + Assert( iCapper != TEAM_UNASSIGNED ); + + return GetIconForTeam( index, iCapper );; + } + + int GetCPTimerCapIcon( int index ) + { + Assert( index < m_iNumControlPoints ); + + return m_iTimerCapIcons[index]; + } + + int GetCPBombedIcon( int index ) + { + Assert( index < m_iNumControlPoints ); + + return m_iBombedIcons[index]; + } + + int GetIconForTeam( int index, int team ) + { + int icon = 0; + + switch ( team ) + { + case TEAM_ALLIES: + icon = m_iAlliesIcons[index]; + break; + case TEAM_AXIS: + icon = m_iAxisIcons[index]; + break; + case TEAM_UNASSIGNED: + icon = m_iNeutralIcons[index]; + break; + default: + Assert(0); + break; + } + + return icon; + } + + // Number of players in the area + int GetNumPlayersInArea( int index, int team ) + { + Assert( index < m_iNumControlPoints ); + + int num = 0; + + switch ( team ) + { + case TEAM_ALLIES: + num = m_iNumAllies[index]; + break; + case TEAM_AXIS: + num = m_iNumAxis[index]; + break; + default: + Assert(0); + break; + } + + return num; + } + + // get the required cappers for the passed team + int GetRequiredCappers( int index, int team ) + { + Assert( index < m_iNumControlPoints ); + + int num = 0; + + switch ( team ) + { + case TEAM_ALLIES: + num = m_iAlliesReqCappers[index]; + break; + case TEAM_AXIS: + num = m_iAxisReqCappers[index]; + break; + default: + Assert(0); + break; + } + + return num; + } + + void SetBombPlanted( int index, int iBombPlanted ); + + void SetBombBeingDefused( int index, bool bBombBeingDefused ) + { + m_bBombBeingDefused[index] = bBombBeingDefused; + } + + bool IsBombSetAtPoint( int index ) + { + return m_bBombPlanted[index]; + } + + bool IsBombBeingDefused( int index ) + { + return m_bBombBeingDefused[index]; + } + + float GetBombTimeForPoint( int index ) + { + return MAX( 0, m_flBombEndTimes[index] - gpGlobals->curtime ); + } + + int GetBombsRequired( int index ) + { + return m_iBombsRequired[index]; + } + + int GetBombsRemaining( int index ) + { + return m_iBombsRemaining[index]; + } + +protected: + + int m_iNumControlPoints; + + // data variables + Vector m_vCPPositions[MAX_CONTROL_POINTS]; + bool m_bCPIsVisible[MAX_CONTROL_POINTS]; + int m_iAlliesIcons[MAX_CONTROL_POINTS]; + int m_iAxisIcons[MAX_CONTROL_POINTS]; + int m_iNeutralIcons[MAX_CONTROL_POINTS]; + int m_iTimerCapIcons[MAX_CONTROL_POINTS]; + int m_iBombedIcons[MAX_CONTROL_POINTS]; + int m_iAlliesReqCappers[MAX_CONTROL_POINTS]; + int m_iAxisReqCappers[MAX_CONTROL_POINTS]; + float m_flAlliesCapTime[MAX_CONTROL_POINTS]; + float m_flAxisCapTime[MAX_CONTROL_POINTS]; + bool m_bBombPlanted[MAX_CONTROL_POINTS]; + int m_iBombsRequired[MAX_CONTROL_POINTS]; + int m_iBombsRemaining[MAX_CONTROL_POINTS]; + bool m_bBombBeingDefused[MAX_CONTROL_POINTS]; + + // state variables + int m_iNumAllies[MAX_CONTROL_POINTS]; + int m_iNumAxis[MAX_CONTROL_POINTS]; + int m_iCappingTeam[MAX_CONTROL_POINTS]; + int m_iOwner[MAX_CONTROL_POINTS]; + + // client calculated state + float m_flCapStartTimes[MAX_CONTROL_POINTS]; + float m_flCapEndTimes[MAX_CONTROL_POINTS]; + float m_flBombEndTimes[MAX_CONTROL_POINTS]; +}; + +extern C_DODObjectiveResource *g_pObjectiveResource; + +#endif // C_DOD_OBJECTIVE_RESOURCE_H diff --git a/game/client/dod/c_dod_player.cpp b/game/client/dod/c_dod_player.cpp new file mode 100644 index 0000000..c28e5aa --- /dev/null +++ b/game/client/dod/c_dod_player.cpp @@ -0,0 +1,2780 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//===========================================================================// + +#include "cbase.h" +#include "c_dod_player.h" +#include "c_user_message_register.h" +#include "view.h" +#include "iclientvehicle.h" +#include "ivieweffects.h" +#include "input.h" +#include "IEffects.h" +#include "fx.h" +#include "c_basetempentity.h" +#include "hud_macros.h" +#include "engine/ivdebugoverlay.h" +#include "smoke_fog_overlay.h" +#include "bone_setup.h" +#include "in_buttons.h" +#include "r_efx.h" +#include "dlight.h" +#include "shake.h" +#include "cl_animevent.h" +#include "fx_dod_blood.h" +#include "effect_dispatch_data.h" //for water ripple / splash effect +#include "c_te_effect_dispatch.h" //ditto +#include "dod_gamerules.h" +#include <igameevents.h> +#include "physpropclientside.h" +#include "obstacle_pushaway.h" +#include "prediction.h" +#include "viewangleanim.h" +#include "soundenvelope.h" +#include "weapon_dodbipodgun.h" +#include "c_dod_basegrenade.h" +#include "dod_weapon_parse.h" +#include "view_scene.h" +#include "dod_headiconmanager.h" +#include "c_world.h" +#include "c_dod_bombtarget.h" +#include "toolframework/itoolframework.h" +#include "toolframework_client.h" +#include "c_team.h" +#include "collisionutils.h" +#include "weapon_dodsniper.h" +// NVNT - haptics system for spectating and grenades +#include "haptics/haptic_utils.h" +// NVNT - for grenade effects +#include "weapon_dodbasegrenade.h" +// NVNT - for planting bomb effect +#include "weapon_dodbasebomb.h" + +#if defined( CDODPlayer ) + #undef CDODPlayer +#endif + +#include "iviewrender_beams.h" // flashlight beam + +#include "materialsystem/imesh.h" //for materials->FindMaterial +#include "iviewrender.h" //for view-> +ConVar cl_ragdoll_physics_enable( "cl_ragdoll_physics_enable", "1", 0, "Enable/disable ragdoll physics." ); + +ConVar cl_autoreload( "cl_autoreload", "1", FCVAR_USERINFO | FCVAR_ARCHIVE, "Set to 1 to auto reload your weapon when it is empty" ); +ConVar cl_autorezoom( "cl_autorezoom", "1", FCVAR_USERINFO | FCVAR_ARCHIVE, "When set to 1, sniper rifles and bazooka weapons will automatically raise after each shot" ); + +#include "tier0/memdbgon.h" + +//====================================================== +// +// Cold Breath Emitter - for DOD players. +// +class ColdBreathEmitter : public CSimpleEmitter +{ +public: + + ColdBreathEmitter( const char *pDebugName ) : CSimpleEmitter( pDebugName ) {} + + static ColdBreathEmitter *Create( const char *pDebugName ) + { + return new ColdBreathEmitter( pDebugName ); + } + + void UpdateVelocity( SimpleParticle *pParticle, float timeDelta ) + { + // Float up when lifetime is half gone. + pParticle->m_vecVelocity[2] -= ( 8.0f * timeDelta ); + + + // FIXME: optimize this.... + pParticle->m_vecVelocity *= ExponentialDecay( 0.9, 0.03, timeDelta ); + } + + virtual float UpdateRoll( SimpleParticle *pParticle, float timeDelta ) + { + pParticle->m_flRoll += pParticle->m_flRollDelta * timeDelta; + + pParticle->m_flRollDelta += pParticle->m_flRollDelta * ( timeDelta * -2.0f ); + + //Cap the minimum roll + if ( fabs( pParticle->m_flRollDelta ) < 0.5f ) + { + pParticle->m_flRollDelta = ( pParticle->m_flRollDelta > 0.0f ) ? 0.5f : -0.5f; + } + + return pParticle->m_flRoll; + } + +private: + + ColdBreathEmitter( const ColdBreathEmitter & ); +}; + + +void RecvProxy_StunTime( const CRecvProxyData *pData, void *pStruct, void *pOut ) +{ + C_DODPlayer *pPlayerData = (C_DODPlayer *) pStruct; + + if( pPlayerData != C_BasePlayer::GetLocalPlayer() ) + return; + + if ( (pPlayerData->m_flStunDuration != pData->m_Value.m_Float) && pData->m_Value.m_Float > 0 ) + { + pPlayerData->m_flStunAlpha = 1; + } + + pPlayerData->m_flStunDuration = pData->m_Value.m_Float; + pPlayerData->m_flStunEffectTime = gpGlobals->curtime + pPlayerData->m_flStunDuration; +} + +// -------------------------------------------------------------------------------- // +// Player animation event. Sent to the client when a player fires, jumps, reloads, etc.. +// -------------------------------------------------------------------------------- // + +class C_TEPlayerAnimEvent : public C_BaseTempEntity +{ +public: + DECLARE_CLASS( C_TEPlayerAnimEvent, C_BaseTempEntity ); + DECLARE_CLIENTCLASS(); + + virtual void PostDataUpdate( DataUpdateType_t updateType ) + { + // Create the effect. + C_DODPlayer *pPlayer = dynamic_cast< C_DODPlayer* >( m_hPlayer.Get() ); + if ( pPlayer && !pPlayer->IsDormant() ) + { + pPlayer->DoAnimationEvent( (PlayerAnimEvent_t)m_iEvent.Get(), m_nData ); + } + } + +public: + CNetworkHandle( CBasePlayer, m_hPlayer ); + CNetworkVar( int, m_iEvent ); + CNetworkVar( int, m_nData ); +}; + +IMPLEMENT_CLIENTCLASS_EVENT( C_TEPlayerAnimEvent, DT_TEPlayerAnimEvent, CTEPlayerAnimEvent ); + + +BEGIN_RECV_TABLE_NOBASE( C_TEPlayerAnimEvent, DT_TEPlayerAnimEvent ) + RecvPropEHandle( RECVINFO( m_hPlayer ) ), + RecvPropInt( RECVINFO( m_iEvent ) ), + RecvPropInt( RECVINFO( m_nData ) ) +END_RECV_TABLE() + +void RecvProxy_CapAreaIndex( const CRecvProxyData *pData, void *pStruct, void *pOut ) +{ + CDODPlayerShared *pShared = ( CDODPlayerShared *)pStruct; + + int iCapAreaIndex = pData->m_Value.m_Int; + + if ( iCapAreaIndex != pShared->GetCPIndex() ) + { + pShared->SetCPIndex( iCapAreaIndex ); + } +} + +// ------------------------------------------------------------------------------------------ // +// Data tables. +// ------------------------------------------------------------------------------------------ // + +// CDODPlayerShared Data Tables +//============================= + +// specific to the local player ( ideally should not be in CDODPlayerShared! ) +BEGIN_RECV_TABLE_NOBASE( CDODPlayerShared, DT_DODSharedLocalPlayerExclusive ) + RecvPropInt( RECVINFO( m_iPlayerClass ) ), + RecvPropInt( RECVINFO( m_iDesiredPlayerClass ) ), + RecvPropFloat( RECVINFO( m_flDeployedYawLimitLeft ) ), + RecvPropFloat( RECVINFO( m_flDeployedYawLimitRight ) ), + RecvPropInt( RECVINFO( m_iCPIndex ), 0, RecvProxy_CapAreaIndex ), + RecvPropArray3( RECVINFO_ARRAY( m_bPlayerDominated ), RecvPropBool( RECVINFO( m_bPlayerDominated[0] ) ) ), + RecvPropArray3( RECVINFO_ARRAY( m_bPlayerDominatingMe ), RecvPropBool( RECVINFO( m_bPlayerDominatingMe[0] ) ) ), +END_RECV_TABLE() + +// main table +BEGIN_RECV_TABLE_NOBASE( CDODPlayerShared, DT_DODPlayerShared ) + RecvPropFloat( RECVINFO( m_flStamina ) ), + RecvPropTime( RECVINFO( m_flSlowedUntilTime ) ), + RecvPropBool( RECVINFO( m_bProne ) ), + RecvPropBool( RECVINFO( m_bIsSprinting ) ), + RecvPropTime( RECVINFO( m_flGoProneTime ) ), + RecvPropTime( RECVINFO( m_flUnProneTime ) ), + RecvPropTime( RECVINFO( m_flDeployChangeTime ) ), + RecvPropFloat( RECVINFO( m_flDeployedHeight ) ), + RecvPropBool( RECVINFO( m_bPlanting ) ), + RecvPropBool( RECVINFO( m_bDefusing ) ), + RecvPropDataTable( "dodsharedlocaldata", 0, 0, &REFERENCE_RECV_TABLE(DT_DODSharedLocalPlayerExclusive) ), +END_RECV_TABLE() + + +// C_DODPlayer Data Tables +//========================= + +// specific to the local player +BEGIN_RECV_TABLE_NOBASE( C_DODPlayer, DT_DODLocalPlayerExclusive ) + RecvPropVector( RECVINFO_NAME( m_vecNetworkOrigin, m_vecOrigin ) ), + RecvPropFloat( RECVINFO( m_flStunDuration ), 0, RecvProxy_StunTime ), + RecvPropFloat( RECVINFO( m_flStunMaxAlpha)), + RecvPropInt( RECVINFO( m_iProgressBarDuration ) ), + RecvPropFloat( RECVINFO( m_flProgressBarStartTime ) ), +END_RECV_TABLE() + +// all players except the local player +BEGIN_RECV_TABLE_NOBASE( C_DODPlayer, DT_DODNonLocalPlayerExclusive ) + RecvPropVector( RECVINFO_NAME( m_vecNetworkOrigin, m_vecOrigin ) ), +END_RECV_TABLE() + +// main table +IMPLEMENT_CLIENTCLASS_DT( C_DODPlayer, DT_DODPlayer, CDODPlayer ) + RecvPropDataTable( RECVINFO_DT( m_Shared ), 0, &REFERENCE_RECV_TABLE( DT_DODPlayerShared ) ), + + RecvPropDataTable( "dodlocaldata", 0, 0, &REFERENCE_RECV_TABLE(DT_DODLocalPlayerExclusive) ), + RecvPropDataTable( "dodnonlocaldata", 0, 0, &REFERENCE_RECV_TABLE(DT_DODNonLocalPlayerExclusive) ), + + RecvPropFloat( RECVINFO( m_angEyeAngles[0] ) ), + RecvPropFloat( RECVINFO( m_angEyeAngles[1] ) ), + RecvPropEHandle( RECVINFO( m_hRagdoll ) ), + RecvPropBool( RECVINFO( m_bSpawnInterpCounter ) ), + RecvPropInt( RECVINFO( m_iAchievementAwardsMask ) ), + +END_RECV_TABLE() + + +// ------------------------------------------------------------------------------------------ // +// Prediction tables. +// ------------------------------------------------------------------------------------------ // +BEGIN_PREDICTION_DATA_NO_BASE( CDODPlayerShared ) + DEFINE_PRED_FIELD( m_bProne, FIELD_BOOLEAN, FTYPEDESC_INSENDTABLE ), + DEFINE_PRED_FIELD( m_flStamina, FIELD_FLOAT, FTYPEDESC_INSENDTABLE ), + DEFINE_PRED_FIELD( m_bIsSprinting, FIELD_BOOLEAN, FTYPEDESC_INSENDTABLE ), + DEFINE_PRED_FIELD( m_flGoProneTime, FIELD_FLOAT, FTYPEDESC_INSENDTABLE ), + DEFINE_PRED_FIELD( m_flUnProneTime, FIELD_FLOAT, FTYPEDESC_INSENDTABLE ), + DEFINE_PRED_FIELD( m_flDeployChangeTime, FIELD_FLOAT, FTYPEDESC_INSENDTABLE ), + DEFINE_PRED_FIELD( m_flDeployedHeight, FIELD_FLOAT, FTYPEDESC_INSENDTABLE ) +END_PREDICTION_DATA() + +BEGIN_PREDICTION_DATA( C_DODPlayer ) + DEFINE_PRED_TYPEDESCRIPTION( m_Shared, CDODPlayerShared ), + DEFINE_PRED_FIELD( m_flCycle, FIELD_FLOAT, FTYPEDESC_OVERRIDE | FTYPEDESC_PRIVATE | FTYPEDESC_NOERRORCHECK ), + DEFINE_PRED_FIELD( m_nSequence, FIELD_INTEGER, FTYPEDESC_OVERRIDE | FTYPEDESC_PRIVATE | FTYPEDESC_NOERRORCHECK ), +END_PREDICTION_DATA() + + +// ----------------------------------------------------------------------------- // +// Client ragdoll entity. +// ----------------------------------------------------------------------------- // + +ConVar cl_low_violence( "cl_low_violence", "0" ); +ConVar cl_ragdoll_fade_time( "cl_ragdoll_fade_time", "15", FCVAR_CLIENTDLL ); +ConVar cl_ragdoll_pronecheck_distance( "cl_ragdoll_pronecheck_distance", "64", FCVAR_GAMEDLL ); + +class C_DODRagdoll : public C_BaseAnimatingOverlay +{ +public: + DECLARE_CLASS( C_DODRagdoll, C_BaseAnimatingOverlay ); + DECLARE_CLIENTCLASS(); + + C_DODRagdoll(); + ~C_DODRagdoll(); + + virtual void OnDataChanged( DataUpdateType_t type ); + + int GetPlayerEntIndex() const; + IRagdoll* GetIRagdoll() const; + + void ImpactTrace( trace_t *pTrace, int iDamageType, const char *pCustomImpactName ); + + void ClientThink( void ); + void StartFadeOut( float fDelay ); + + bool IsRagdollVisible(); +private: + + C_DODRagdoll( const C_DODRagdoll & ) {} + + void Interp_Copy( C_BaseAnimatingOverlay *pSourceEntity ); + + void CreateLowViolenceRagdoll(); + void CreateDODRagdoll(); + +private: + + EHANDLE m_hPlayer; + CNetworkVector( m_vecRagdollVelocity ); + CNetworkVector( m_vecRagdollOrigin ); + float m_fDeathTime; + bool m_bFadingOut; +}; + + +IMPLEMENT_CLIENTCLASS_DT_NOBASE( C_DODRagdoll, DT_DODRagdoll, CDODRagdoll ) + RecvPropVector( RECVINFO(m_vecRagdollOrigin) ), + RecvPropEHandle( RECVINFO( m_hPlayer ) ), + RecvPropInt( RECVINFO( m_nModelIndex ) ), + RecvPropInt( RECVINFO(m_nForceBone) ), + RecvPropVector( RECVINFO(m_vecForce) ), + RecvPropVector( RECVINFO( m_vecRagdollVelocity ) ) +END_RECV_TABLE() + + +C_DODRagdoll::C_DODRagdoll() +{ + m_fDeathTime = -1; + m_bFadingOut = false; +} + +C_DODRagdoll::~C_DODRagdoll() +{ + PhysCleanupFrictionSounds( this ); +} + +void C_DODRagdoll::Interp_Copy( C_BaseAnimatingOverlay *pSourceEntity ) +{ + if ( !pSourceEntity ) + return; + + VarMapping_t *pSrc = pSourceEntity->GetVarMapping(); + VarMapping_t *pDest = GetVarMapping(); + + // Find all the VarMapEntry_t's that represent the same variable. + for ( int i = 0; i < pDest->m_Entries.Count(); i++ ) + { + VarMapEntry_t *pDestEntry = &pDest->m_Entries[i]; + for ( int j=0; j < pSrc->m_Entries.Count(); j++ ) + { + VarMapEntry_t *pSrcEntry = &pSrc->m_Entries[j]; + if ( !Q_strcmp( pSrcEntry->watcher->GetDebugName(), + pDestEntry->watcher->GetDebugName() ) ) + { + pDestEntry->watcher->Copy( pSrcEntry->watcher ); + break; + } + } + } +} + +void C_DODRagdoll::ImpactTrace( trace_t *pTrace, int iDamageType, const char *pCustomImpactName ) +{ + IPhysicsObject *pPhysicsObject = VPhysicsGetObject(); + + if( !pPhysicsObject ) + return; + + Vector dir = pTrace->endpos - pTrace->startpos; + + if ( iDamageType == DMG_BLAST ) + { + dir *= 4000; // adjust impact strength + + // apply force at object mass center + pPhysicsObject->ApplyForceCenter( dir ); + } + else + { + Vector hitpos; + + VectorMA( pTrace->startpos, pTrace->fraction, dir, hitpos ); + VectorNormalize( dir ); + + dir *= 4000; // adjust impact strength + + // apply force where we hit it + pPhysicsObject->ApplyForceOffset( dir, hitpos ); + + // Blood spray! + FX_DOD_BloodSpray( hitpos, dir, 10 ); + } + + m_pRagdoll->ResetRagdollSleepAfterTime(); +} + + +void C_DODRagdoll::CreateLowViolenceRagdoll() +{ + // Just play a death animation. + // Find a death anim to play. + int iMinDeathAnim = 9999, iMaxDeathAnim = -9999; + for ( int iAnim=1; iAnim < 100; iAnim++ ) + { + char str[512]; + Q_snprintf( str, sizeof( str ), "death%d", iAnim ); + if ( LookupSequence( str ) == -1 ) + break; + + iMinDeathAnim = MIN( iMinDeathAnim, iAnim ); + iMaxDeathAnim = MAX( iMaxDeathAnim, iAnim ); + } + + if ( iMinDeathAnim == 9999 ) + { + CreateDODRagdoll(); + } + else + { + int iDeathAnim = RandomInt( iMinDeathAnim, iMaxDeathAnim ); + char str[512]; + Q_snprintf( str, sizeof( str ), "death%d", iDeathAnim ); + + SetSequence( LookupSequence( str ) ); + ForceClientSideAnimationOn(); + + SetNetworkOrigin( m_vecRagdollOrigin ); + SetAbsOrigin( m_vecRagdollOrigin ); + SetAbsVelocity( m_vecRagdollVelocity ); + + C_DODPlayer *pPlayer = dynamic_cast< C_DODPlayer* >( m_hPlayer.Get() ); + if ( pPlayer && !pPlayer->IsDormant() ) + { + // move my current model instance to the ragdoll's so decals are preserved. + pPlayer->SnatchModelInstance( this ); + + SetAbsAngles( pPlayer->GetRenderAngles() ); + SetNetworkAngles( pPlayer->GetRenderAngles() ); + } + + Interp_Reset( GetVarMapping() ); + } +} + +void C_DODRagdoll::CreateDODRagdoll() +{ + // First, initialize all our data. If we have the player's entity on our client, + // then we can make ourselves start out exactly where the player is. + C_DODPlayer *pPlayer = dynamic_cast< C_DODPlayer* >( m_hPlayer.Get() ); + +#ifdef _DEBUG + DevMsg( 2, "CreateDODRagdoll %d %d\n", gpGlobals->framecount, pPlayer ? pPlayer->entindex() : 0 ); +#endif + + if ( pPlayer && !pPlayer->IsDormant() ) + { + // move my current model instance to the ragdoll's so decals are preserved. + pPlayer->SnatchModelInstance( this ); + + VarMapping_t *varMap = GetVarMapping(); + + // Copy all the interpolated vars from the player entity. + // The entity uses the interpolated history to get bone velocity. + if ( !pPlayer->IsLocalPlayer() && pPlayer->dod_IsInterpolationEnabled() ) + { + Interp_Copy( pPlayer ); + + SetAbsAngles( pPlayer->GetRenderAngles() ); + GetRotationInterpolator().Reset(); + + m_flAnimTime = pPlayer->m_flAnimTime; + SetSequence( pPlayer->GetSequence() ); + m_flPlaybackRate = pPlayer->GetPlaybackRate(); + } + else + { + // This is the local player, so set them in a default + // pose and slam their velocity, angles and origin + SetAbsOrigin( m_vecRagdollOrigin ); + + SetAbsAngles( pPlayer->GetRenderAngles() ); + + SetAbsVelocity( m_vecRagdollVelocity ); + + int iSeq = LookupSequence( "RagdollSpawn" ); // hax, find a neutral standing pose + if ( iSeq == -1 ) + { + Assert( false ); // missing look_idle? + iSeq = 0; + } + + SetSequence( iSeq ); // look_idle, basic pose + SetCycle( 0.0 ); + + Interp_Reset( varMap ); + } + + m_nBody = pPlayer->GetBody(); + } + else + { + // overwrite network origin so later interpolation will + // use this position + SetNetworkOrigin( m_vecRagdollOrigin ); + + SetAbsOrigin( m_vecRagdollOrigin ); + SetAbsVelocity( m_vecRagdollVelocity ); + + Interp_Reset( GetVarMapping() ); + + } + + SetModelIndex( m_nModelIndex ); + + // Turn it into a ragdoll. + if ( cl_ragdoll_physics_enable.GetInt() ) + { + // Make us a ragdoll.. + m_nRenderFX = kRenderFxRagdoll; + + matrix3x4_t boneDelta0[MAXSTUDIOBONES]; + matrix3x4_t boneDelta1[MAXSTUDIOBONES]; + matrix3x4_t currentBones[MAXSTUDIOBONES]; + const float boneDt = 0.05f; + + if ( pPlayer && pPlayer == C_BasePlayer::GetLocalPlayer() ) + { + pPlayer->GetRagdollInitBoneArrays( boneDelta0, boneDelta1, currentBones, boneDt ); + } + else + { + GetRagdollInitBoneArrays( boneDelta0, boneDelta1, currentBones, boneDt ); + } + + InitAsClientRagdoll( boneDelta0, boneDelta1, currentBones, boneDt ); + } + else + { + ClientLeafSystem()->SetRenderGroup( GetRenderHandle(), RENDER_GROUP_TRANSLUCENT_ENTITY ); + } + + // Fade out the ragdoll in a while + StartFadeOut( cl_ragdoll_fade_time.GetFloat() ); + SetNextClientThink( gpGlobals->curtime + 5.0f ); +} + +void C_DODRagdoll::OnDataChanged( DataUpdateType_t type ) +{ + BaseClass::OnDataChanged( type ); + + if ( type == DATA_UPDATE_CREATED ) + { + if ( cl_low_violence.GetInt() ) + { + CreateLowViolenceRagdoll(); + } + else + { + CreateDODRagdoll(); + } + } + else + { + if ( !cl_ragdoll_physics_enable.GetInt() ) + { + // Don't let it set us back to a ragdoll with data from the server. + m_nRenderFX = kRenderFxNone; + } + } +} + +IRagdoll* C_DODRagdoll::GetIRagdoll() const +{ + return m_pRagdoll; +} + +bool C_DODRagdoll::IsRagdollVisible() +{ + Vector vMins = Vector(-1,-1,-1); //WorldAlignMins(); + Vector vMaxs = Vector(1,1,1); //WorldAlignMaxs(); + + Vector origin = GetAbsOrigin(); + + if( !engine->IsBoxInViewCluster( vMins + origin, vMaxs + origin) ) + { + return false; + } + else if( engine->CullBox( vMins + origin, vMaxs + origin ) ) + { + return false; + } + + return true; +} + +void C_DODRagdoll::ClientThink( void ) +{ + SetNextClientThink( CLIENT_THINK_ALWAYS ); + + if ( m_bFadingOut == true ) + { + int iAlpha = GetRenderColor().a; + int iFadeSpeed = 600.0f; + + iAlpha = MAX( iAlpha - ( iFadeSpeed * gpGlobals->frametime ), 0 ); + + SetRenderMode( kRenderTransAlpha ); + SetRenderColorA( iAlpha ); + + if ( iAlpha == 0 ) + { + //Release(); + AddEffects( EF_NODRAW ); + } + + return; + } + + for( int iClient = 1; iClient <= gpGlobals->maxClients; ++iClient ) + { + C_DODPlayer *pEnt = static_cast< C_DODPlayer *> ( UTIL_PlayerByIndex( iClient ) ); + + if(!pEnt || !pEnt->IsPlayer()) + continue; + + if ( m_hPlayer == NULL ) + continue; + + if ( pEnt->entindex() == m_hPlayer->entindex() ) + continue; + + if ( pEnt->GetHealth() <= 0 ) + continue; + + if ( pEnt->m_Shared.IsProne() == false ) + continue; + + Vector vTargetOrigin = pEnt->GetAbsOrigin(); + Vector vMyOrigin = GetAbsOrigin(); + + Vector vDir = vTargetOrigin - vMyOrigin; + + if ( vDir.Length() > cl_ragdoll_pronecheck_distance.GetInt() ) + continue; + + SetNextClientThink( CLIENT_THINK_ALWAYS ); + m_bFadingOut = true; + return; + } + + // if the player is looking at us, delay the fade + if ( IsRagdollVisible() ) + { + StartFadeOut( 5.0 ); + return; + } + + if ( m_fDeathTime > gpGlobals->curtime ) + return; + + //Release(); // Die + AddEffects( EF_NODRAW ); +} + +void C_DODRagdoll::StartFadeOut( float fDelay ) +{ + m_fDeathTime = gpGlobals->curtime + fDelay; + SetNextClientThink( CLIENT_THINK_ALWAYS ); +} + +// ------------------------------------------------------------------------------------------ // +// C_DODPlayer implementation. +// ------------------------------------------------------------------------------------------ // +C_DODPlayer::C_DODPlayer() : + m_iv_angEyeAngles( "C_DODPlayer::m_iv_angEyeAngles" ) +{ + m_PlayerAnimState = CreatePlayerAnimState( this ); + + m_Shared.Init( this ); + + m_flPitchRecoilAccumulator = 0.0; + m_flYawRecoilAccumulator = 0.0; + m_flRecoilTimeRemaining = 0.0; + + m_iProgressBarDuration = 0; + m_flProgressBarStartTime = 0.0f; + + AddVar( &m_angEyeAngles, &m_iv_angEyeAngles, LATCH_SIMULATION_VAR ); + + m_flProneViewOffset = 0.0; + m_bProneSwayingRight = true; + m_iIDEntIndex = 0; + + m_Hints.Init( this, NUM_HINTS, g_pszHintMessages ); + + m_pFlashlightBeam = NULL; + + m_fNextThinkPushAway = 0.0f; + + // Cold breath. + m_bColdBreathOn = false; + m_flColdBreathTimeStart = 0.0f; + m_flColdBreathTimeEnd = 0.0f; + m_hColdBreathEmitter = NULL; + m_hColdBreathMaterial = INVALID_MATERIAL_HANDLE; + + m_flHideHeadIconUntilTime = 0.0f; + + m_iAchievementAwardsMask = 0; + m_pHeadIconMaterial = NULL; +} + + +C_DODPlayer::~C_DODPlayer() +{ + m_PlayerAnimState->Release(); + + ReleaseFlashlight(); + + // Kill the stamina sound! + if ( m_pStaminaSound ) + { + CSoundEnvelopeController::GetController().SoundDestroy( m_pStaminaSound ); + m_pStaminaSound = NULL; + } + + // Cold breath. + DestroyColdBreathEmitter(); +} + + +C_DODPlayer* C_DODPlayer::GetLocalDODPlayer() +{ + return ToDODPlayer( C_BasePlayer::GetLocalPlayer() ); +} + +IRagdoll* C_DODPlayer::GetRepresentativeRagdoll() const +{ + if ( m_hRagdoll.Get() ) + { + C_DODRagdoll *pRagdoll = (C_DODRagdoll*)m_hRagdoll.Get(); + + return pRagdoll->GetIRagdoll(); + } + else + { + return NULL; + } +} + +const QAngle& C_DODPlayer::GetRenderAngles() +{ + if ( IsRagdoll() ) + { + return vec3_angle; + } + else + { + return m_PlayerAnimState->GetRenderAngles(); + } +} + + +void C_DODPlayer::UpdateClientSideAnimation() +{ + // Update the animation data. It does the local check here so this works when using + // a third-person camera (and we don't have valid player angles). + if ( this == C_DODPlayer::GetLocalDODPlayer() ) + m_PlayerAnimState->Update( EyeAngles()[YAW], m_angEyeAngles[PITCH] ); + else + m_PlayerAnimState->Update( m_angEyeAngles[YAW], m_angEyeAngles[PITCH] ); + + BaseClass::UpdateClientSideAnimation(); +} + +ConVar dod_playachievementsound( "dod_playachievementsound", "1", FCVAR_ARCHIVE ); + +void C_DODPlayer::OnAchievementAchieved( int iAchievement ) +{ + // don't draw the head icon for a length of time after showing the particle effect + m_flHideHeadIconUntilTime = gpGlobals->curtime + 2.5; + + if ( dod_playachievementsound.GetBool() ) + { + EmitSound( "Achievement.Earned" ); + } + + BaseClass::OnAchievementAchieved( iAchievement ); +} + +int C_DODPlayer::DrawModel( int flags ) +{ + int nRetval = BaseClass::DrawModel( flags ); + if ( nRetval != 0 ) + { + // register to draw the head icon, unless we're hiding it due to the "achieved" particle effect + if ( gpGlobals->curtime > m_flHideHeadIconUntilTime ) + { + HeadIconManager()->PlayerDrawn( this ); + } + } + return nRetval; +} + +void C_DODPlayer::DoAnimationEvent( PlayerAnimEvent_t event, int nData ) +{ + m_PlayerAnimState->DoAnimationEvent( event, nData ); +} + +DODPlayerState C_DODPlayer::State_Get() const +{ + return m_iPlayerState; +} + +bool C_DODPlayer::CanShowClassMenu( void ) +{ + return ( GetTeamNumber() == TEAM_ALLIES || GetTeamNumber() == TEAM_AXIS ); +} + +void C_DODPlayer::DoRecoil( int iWpnID, float flWpnRecoil ) +{ + float flPitchRecoil = flWpnRecoil; + float flYawRecoil = flPitchRecoil / 4; + + if( iWpnID == WEAPON_BAR ) + flYawRecoil = MIN( flYawRecoil, 1.3 ); + + if ( m_Shared.IsInMGDeploy() ) + { + flPitchRecoil = 0.0; + flYawRecoil = 0.0; + } + else if ( m_Shared.IsProne() && + iWpnID != WEAPON_30CAL && + iWpnID != WEAPON_MG42 ) //minor hackage + { + flPitchRecoil = flPitchRecoil / 4; + flYawRecoil = flYawRecoil / 4; + } + else if ( m_Shared.IsDucking() ) + { + flPitchRecoil = flPitchRecoil / 2; + flYawRecoil = flYawRecoil / 2; + } + + SetRecoilAmount( flPitchRecoil, flYawRecoil ); +} + +//Set the amount of pitch and yaw recoil we want to do over the next RECOIL_DURATION seconds +void C_DODPlayer::SetRecoilAmount( float flPitchRecoil, float flYawRecoil ) +{ + //Slam the values, abandon previous recoils + m_flPitchRecoilAccumulator = flPitchRecoil; + + flYawRecoil = flYawRecoil * random->RandomFloat( 0.8, 1.1 ); + + if( random->RandomInt( 0,1 ) <= 0 ) + m_flYawRecoilAccumulator = flYawRecoil; + else + m_flYawRecoilAccumulator = -flYawRecoil; + + m_flRecoilTimeRemaining = RECOIL_DURATION; +} + +//Get the amount of recoil we should do this frame +void C_DODPlayer::GetRecoilToAddThisFrame( float &flPitchRecoil, float &flYawRecoil ) +{ + if( m_flRecoilTimeRemaining <= 0 ) + { + flPitchRecoil = 0.0; + flYawRecoil = 0.0; + return; + } + + float flRemaining = MIN( m_flRecoilTimeRemaining, gpGlobals->frametime ); + + float flRecoilProportion = ( flRemaining / RECOIL_DURATION ); + + flPitchRecoil = m_flPitchRecoilAccumulator * flRecoilProportion; + flYawRecoil = m_flYawRecoilAccumulator * flRecoilProportion; + + m_flRecoilTimeRemaining -= gpGlobals->frametime; +} + +//----------------------------------------------------------------------------- +// Purpose: Input handling +//----------------------------------------------------------------------------- +bool C_DODPlayer::CreateMove( float flInputSampleTime, CUserCmd *pCmd ) +{ + // Lock view if deployed + if( m_Shared.IsInMGDeploy() ) + { + m_Shared.ClampDeployedAngles( &pCmd->viewangles ); + } + + //if we're prone and moving, do some sway + if( m_Shared.IsProne() && IsAlive() ) + { + float flSpeed = GetAbsVelocity().Length(); + + float flSwayAmount = PRONE_SWAY_AMOUNT * gpGlobals->frametime; + + if( flSpeed > 10 ) + { + if (m_flProneViewOffset >= PRONE_MAX_SWAY) + { + m_bProneSwayingRight = false; + } + else if (m_flProneViewOffset <= -PRONE_MAX_SWAY) + { + m_bProneSwayingRight = true; + } + + if (m_bProneSwayingRight) + { + pCmd->viewangles[YAW] += flSwayAmount; + m_flProneViewOffset += flSwayAmount; + } + else + { + pCmd->viewangles[YAW] -= flSwayAmount; + m_flProneViewOffset -= flSwayAmount; + } + } + else + { + // Return to 0 prone sway offset gradually + + //Quick Checks to make sure it isn't bigger or smaller than our sway amount + if ( (m_flProneViewOffset < 0.0 && m_flProneViewOffset > -flSwayAmount) || + (m_flProneViewOffset > 0.0 && m_flProneViewOffset < flSwayAmount) ) + { + m_flProneViewOffset = 0.0; + } + + if (m_flProneViewOffset > 0.0) + { + pCmd->viewangles[YAW] -= flSwayAmount; + m_flProneViewOffset -= flSwayAmount; + } + else if (m_flProneViewOffset < 0.0) + { + pCmd->viewangles[YAW] += flSwayAmount; + m_flProneViewOffset += flSwayAmount; + } + } + } + + bool bResult = BaseClass::CreateMove( flInputSampleTime, pCmd ); + + AvoidPlayers( pCmd ); + + return bResult; +} + +// How fast to avoid collisions with center of other object, in units per second +#define AVOID_SPEED 1000.0f +ConVar cl_avoidspeed( "cl_avoidspeed", "1000.0f", FCVAR_CLIENTDLL ); +extern ConVar cl_forwardspeed; +extern ConVar cl_backspeed; +extern ConVar cl_sidespeed; + +bool C_DODPlayer::ShouldDraw( void ) +{ + if( IsDormant() ) + return false; + + // If we're dead, our ragdoll will be drawn for us instead. + if ( !IsAlive() ) + return false; + + if( GetTeamNumber() == TEAM_SPECTATOR ) + return false; + + if( IsLocalPlayer() ) + { + if ( IsRagdoll() ) + return true; + } + + return BaseClass::ShouldDraw(); +} + +//----------------------------------------------------------------------------- +// Deal with visibility +//----------------------------------------------------------------------------- +void C_DODPlayer::GetToolRecordingState( KeyValues *msg ) +{ +#ifndef _XBOX + BaseClass::GetToolRecordingState( msg ); + BaseEntityRecordingState_t *pBaseEntityState = (BaseEntityRecordingState_t*)msg->GetPtr( "baseentity" ); + if ( IsLocalPlayer() ) + { + pBaseEntityState->m_bVisible = !IsDormant() && IsAlive() && ( GetTeamNumber() != TEAM_SPECTATOR ) && + ( GetRenderMode() != kRenderNone ) && (GetObserverMode() != OBS_MODE_DEATHCAM) && !IsEffectActive(EF_NODRAW); + } +#endif +} + + +CWeaponDODBase* C_DODPlayer::GetActiveDODWeapon() const +{ + C_BaseCombatWeapon *pWpn = GetActiveWeapon(); + + if ( !pWpn ) + return NULL; + + return dynamic_cast< CWeaponDODBase* >( pWpn ); +} + +C_BaseAnimating * C_DODPlayer::BecomeRagdollOnClient() +{ + return NULL; +} + +void C_DODPlayer::FireEvent( const Vector& origin, const QAngle& angles, int event, const char *options ) +{ + if( event == 7002 ) + { + if( this == C_BasePlayer::GetLocalPlayer() ) + return; + + CWeaponDODBase *pWeapon = GetActiveDODWeapon(); + + if ( !pWeapon ) + return; + + int iAttachment = 2; + Vector vecOrigin; + QAngle angAngles; + + if( pWeapon->GetAttachment( iAttachment, vecOrigin, angAngles ) ) + { + int shellType = atoi(options); + + CEffectData data; + data.m_nHitBox = shellType; + data.m_vOrigin = vecOrigin; + data.m_vAngles = angAngles; + DispatchEffect( "DOD_EjectBrass", data ); + } + } + else + BaseClass::FireEvent( origin, angles, event, options ); + + /* + // MATTTODO: water footstep effects + if( event == 7001 ) + { + bool bInWater = ( enginetrace->GetPointContents(origin) & CONTENTS_WATER ); + + if( bInWater ) + { + //run splash + CEffectData data; + + //trace up from foot position to the water surface + trace_t tr; + Vector vecTrace(0,0,1024); + UTIL_TraceLine( origin, origin + vecTrace, MASK_WATER, NULL, COLLISION_GROUP_NONE, &tr ); + if ( tr.fractionleftsolid ) + { + data.m_vOrigin = origin + (vecTrace * tr.fractionleftsolid); + } + else + { + data.m_vOrigin = origin; + } + + data.m_vNormal = Vector( 0,0,1 ); + data.m_flScale = random->RandomFloat( 4.0f, 5.0f ); + DispatchEffect( "watersplash", data ); + } + } + else if( event == 7002 ) + { + bool bInWater = ( enginetrace->GetPointContents(origin) & CONTENTS_WATER ); + + if( bInWater ) + { + //walk ripple + CEffectData data; + + //trace up from foot position to the water surface + trace_t tr; + Vector vecTrace(0,0,1024); + UTIL_TraceLine( origin, origin + vecTrace, MASK_WATER, NULL, COLLISION_GROUP_NONE, &tr ); + if ( tr.fractionleftsolid ) + { + data.m_vOrigin = origin + (vecTrace * tr.fractionleftsolid); + } + else + { + data.m_vOrigin = origin; + } + + data.m_vNormal = Vector( 0,0,1 ); + data.m_flScale = random->RandomFloat( 4.0f, 7.0f ); + DispatchEffect( "waterripple", data ); + } + } + */ +} +// NVNT gate for spectating. +static bool inSpectating_Haptics = false; +// NVNT check grenade things ( -- this is here to avoid modificaions to the grenade class -- ) +static bool s_holdingGrenade = false; +static bool s_grenadePinPulled = false; +static bool s_grenadeArmed = false; +static bool s_bombPlanting = false; +void C_DODPlayer::ClientThink() +{ + BaseClass::ClientThink(); + + if ( gpGlobals->curtime >= m_fNextThinkPushAway ) + { + PerformObstaclePushaway( this ); + m_fNextThinkPushAway = gpGlobals->curtime + PUSHAWAY_THINK_INTERVAL; + } + + if ( IsLocalPlayer() ) + { + UpdateIDTarget(); + + StaminaSoundThink(); + + // Recoil + QAngle viewangles; + engine->GetViewAngles( viewangles ); + + float flYawRecoil; + float flPitchRecoil; + GetRecoilToAddThisFrame( flPitchRecoil, flYawRecoil ); + + // Recoil + if( flPitchRecoil > 0 ) + { + //add the recoil pitch + viewangles[PITCH] -= flPitchRecoil; + viewangles[YAW] += flYawRecoil; + } + + // Sniper sway + if( m_Shared.IsSniperZoomed() && GetFOV() <= 20 ) + { + //multiply by frametime to balance for framerate changes + float x = gpGlobals->frametime * cos( gpGlobals->curtime ); + float y = gpGlobals->frametime * 2 * cos( 2 * gpGlobals->curtime ); + + float scale; + + if( m_Shared.IsDucking() ) //duck + scale = ZOOM_SWAY_DUCKING; + else if( m_Shared.IsProne() ) + scale = ZOOM_SWAY_PRONE; + else //standing + scale = ZOOM_SWAY_STANDING; + + if( GetAbsVelocity().Length() > 10 ) + scale += ZOOM_SWAY_MOVING_PENALTY; + + viewangles[PITCH] += y * scale; + viewangles[YAW] += x * scale; + } + + engine->SetViewAngles( viewangles ); + // NVNT check spectator nav. + if( ( ( GetTeamNumber() == TEAM_SPECTATOR ) || ( !this->IsAlive() ) ) ) { + if(!inSpectating_Haptics) + { + if ( haptics ) + haptics->SetNavigationClass("spectate"); + inSpectating_Haptics = true; + } + }else{ + if(inSpectating_Haptics) { + if ( haptics ) + haptics->SetNavigationClass("on_foot"); + inSpectating_Haptics = false; + } + } + + // NVNT check grenade things ( -- this is here to avoid modificaions to the grenade class -- ) + C_WeaponDODBaseGrenade *heldGrenade = dynamic_cast<C_WeaponDODBaseGrenade*>(GetActiveDODWeapon()); + if(heldGrenade) + { + if(!s_holdingGrenade) + { + s_holdingGrenade = true; + } + bool pinPulled = heldGrenade->m_bPinPulled; + if(pinPulled != s_grenadePinPulled) { + if(pinPulled) + { + if ( haptics ) + haptics->ProcessHapticEvent(3, "Weapons", heldGrenade->GetClassname(), "PinPulled"); + }else { + if ( haptics ) + haptics->ProcessHapticEvent(3, "Weapons", heldGrenade->GetClassname(), "PinReplaced"); + } + s_grenadePinPulled = pinPulled; + } + bool grenadeArmed = heldGrenade->m_bArmed; + if(grenadeArmed != s_grenadeArmed) { + if(grenadeArmed) + { + if ( haptics ) + haptics->ProcessHapticEvent(3, "Weapons", heldGrenade->GetClassname(), "Armed"); + }else { + if ( haptics ) + haptics->ProcessHapticEvent(3, "Weapons", heldGrenade->GetClassname(), "Unarmed"); + } + s_grenadeArmed = grenadeArmed; + } + }else{ + if( s_holdingGrenade ) + { + if(s_grenadeArmed && s_grenadePinPulled) { + if ( haptics ) + haptics->ProcessHapticEvent(3, "Weapons", "Grenades", "Thrown"); + } + s_holdingGrenade = false; + s_grenadeArmed = false; + s_grenadePinPulled = false; + } + C_DODBaseBombWeapon *heldBomb = dynamic_cast<C_DODBaseBombWeapon*>(GetActiveDODWeapon()); + + if(heldBomb) { + bool isPlanting = heldBomb->IsPlanting(); + if(isPlanting!=s_bombPlanting) { + if(isPlanting) { + if(!s_bombPlanting) { + s_bombPlanting = true; + if ( haptics ) + haptics->ProcessHapticEvent(3, "Weapons", heldBomb->GetClassname(), "Plant"); + } + }else{ + if(s_bombPlanting) { + if ( haptics ) + haptics->ProcessHapticEvent(3, "Weapons", heldBomb->GetClassname(), "StopPlant"); + } + } + } + }else if(s_bombPlanting) { + s_bombPlanting = false; + if ( haptics ) + haptics->ProcessHapticEvent(3, "Weapons", "Bomb", "Complete"); + } + } + + } + else + { + // Cold breath. + UpdateColdBreath(); + } +} + +// Start or stop the stamina breathing sound if necessary +void C_DODPlayer::StaminaSoundThink( void ) +{ + if ( m_bPlayingLowStaminaSound ) + { + if ( !IsAlive() || m_Shared.GetStamina() >= LOW_STAMINA_THRESHOLD ) + { + // stop the sprint sound + CSoundEnvelopeController &controller = CSoundEnvelopeController::GetController(); + controller.SoundFadeOut( m_pStaminaSound, 1.0, true ); + + // SoundFadeOut will destroy this sound, so we will have to create another one + // if we go below the threshold again soon + m_pStaminaSound = NULL; + + m_bPlayingLowStaminaSound = false; + } + } + else + { + if ( IsAlive() && m_Shared.GetStamina() < LOW_STAMINA_THRESHOLD ) + { + // we are alive and have low stamina + CLocalPlayerFilter filter; + + CSoundEnvelopeController &controller = CSoundEnvelopeController::GetController(); + + if ( !m_pStaminaSound ) + m_pStaminaSound = controller.SoundCreate( filter, entindex(), "Player.Sprint" ); + + controller.Play( m_pStaminaSound, 0.0, 100 ); + controller.SoundChangeVolume( m_pStaminaSound, 1.0, 2.0 ); + + m_bPlayingLowStaminaSound = true; + } + } +} + +void C_DODPlayer::OnDataChanged( DataUpdateType_t type ) +{ + BaseClass::OnDataChanged( type ); + + if ( type == DATA_UPDATE_CREATED ) + { + SetNextClientThink( CLIENT_THINK_ALWAYS ); + } + + UpdateVisibility(); +} + +void C_DODPlayer::PostDataUpdate( DataUpdateType_t updateType ) +{ + // C_BaseEntity assumes we're networking the entity's angles, so pretend that it + // networked the same value we already have. + SetNetworkAngles( GetLocalAngles() ); + + BaseClass::PostDataUpdate( updateType ); + + if( m_bSpawnInterpCounter != m_bSpawnInterpCounterCache ) + { + if ( IsLocalPlayer() ) + { + LocalPlayerRespawn(); + } + + m_bSpawnInterpCounterCache = m_bSpawnInterpCounter.m_Value; + } +} + +// Called every time the player respawns +void C_DODPlayer::LocalPlayerRespawn( void ) +{ + MoveToLastReceivedPosition( true ); + ResetLatched(); + + ResetToneMapping(1.0); + + m_Shared.m_bForceProneChange = true; + + m_flLastRespawnTime = gpGlobals->curtime; +} + +class C_FadingPhysPropClientside : public C_PhysPropClientside +{ +public: + DECLARE_CLASS( C_FadingPhysPropClientside, C_PhysPropClientside ); + + // if we wake, extend fade time + + virtual void ImpactTrace( trace_t *pTrace, int iDamageType, const char *pCustomImpactName ) + { + // If we haven't started fading + if( GetRenderColor().a >= 255 ) + { + // delay the fade + StartFadeOut( 10.0 ); + + // register the impact + BaseClass::ImpactTrace( pTrace, iDamageType, pCustomImpactName ); + } + } +}; + +void C_DODPlayer::PopHelmet( Vector vecDir, Vector vecForceOrigin, int iModel ) +{ + if ( IsDormant() ) + return; // We can't see them anyway, just bail + + C_FadingPhysPropClientside *pEntity = new C_FadingPhysPropClientside(); + + if ( !pEntity ) + return; + + const model_t *model = modelinfo->GetModel( iModel ); + + if ( !model ) + { + DevMsg("CTempEnts::PhysicsProp: model index %i not found\n", iModel ); + return; + } + + Vector vecHead; + QAngle angHeadAngles; + + { + C_BaseAnimating::AutoAllowBoneAccess boneaccess( true, false ); + int iAttachment = LookupAttachment( "head" ); + GetAttachment( iAttachment, vecHead, angHeadAngles ); //attachment 1 is the head attachment + } + + pEntity->SetModelName( modelinfo->GetModelName(model) ); + pEntity->SetAbsOrigin( vecHead ); + pEntity->SetAbsAngles( angHeadAngles ); + pEntity->SetPhysicsMode( PHYSICS_MULTIPLAYER_CLIENTSIDE ); + + if ( !pEntity->Initialize() ) + { + pEntity->Release(); + return; + } + + IPhysicsObject *pPhysicsObject = pEntity->VPhysicsGetObject(); + + if( pPhysicsObject ) + { +#ifdef DEBUG + if( vecForceOrigin == vec3_origin ) + { + vecForceOrigin = GetAbsOrigin(); + } +#endif + + Vector vecForce = vecDir; + Vector vecOffset = vecForceOrigin - pEntity->GetAbsOrigin(); + pPhysicsObject->ApplyForceOffset( vecForce, vecOffset ); + } + else + { + // failed to create a physics object + pEntity->Release(); + return; + } + + pEntity->StartFadeOut( 10.0 ); +} + +void C_DODPlayer::ReceiveMessage( int classID, bf_read &msg ) +{ + if ( classID != GetClientClass()->m_ClassID ) + { + // message is for subclass + BaseClass::ReceiveMessage( classID, msg ); + return; + } + + int messageType = msg.ReadByte(); + switch( messageType ) + { + case DOD_PLAYER_POP_HELMET: + { + Vector vecDir, vecForceOffset; + msg.ReadBitVec3Coord( vecDir ); + msg.ReadBitVec3Coord( vecForceOffset ); + + int model = msg.ReadShort(); + + PopHelmet( vecDir, vecForceOffset, model ); + } + break; + case DOD_PLAYER_REMOVE_DECALS: + { + RemoveAllDecals(); + } + break; + default: + break; + } +} + +//----------------------------------------------------------------------------- +// Purpose: Update this client's target entity +//----------------------------------------------------------------------------- +void C_DODPlayer::UpdateIDTarget() +{ + Assert( IsLocalPlayer() ); + + // Clear old target and find a new one + m_iIDEntIndex = 0; + + // don't show IDs in chase spec mode + if ( GetObserverMode() == OBS_MODE_CHASE || + GetObserverMode() == OBS_MODE_DEATHCAM ) + return; + + trace_t tr; + Vector vecStart, vecEnd; + VectorMA( MainViewOrigin(), 1500, MainViewForward(), vecEnd ); + VectorMA( MainViewOrigin(), 10, MainViewForward(), vecStart ); + UTIL_TraceLine( vecStart, vecEnd, MASK_SOLID, this, COLLISION_GROUP_NONE, &tr ); + + C_BaseEntity *pEntity = NULL; + if ( !tr.startsolid && tr.DidHitNonWorldEntity() ) + { + pEntity = tr.m_pEnt; + + if ( pEntity && (pEntity != this) ) + { + m_iIDEntIndex = pEntity->entindex(); + } + } + + // if we haven't done the weapon hint, and this entity is a weapon, + // show the weapon hint + if ( m_Hints.HasPlayedHint( HINT_PICK_UP_WEAPON ) == false && pEntity ) + { + Vector vecDist = vecStart - tr.endpos; + + // if m_iIDEntIndex is a CWeaponDODBase, show pick up hint + CWeaponDODBase *pWpn = dynamic_cast<CWeaponDODBase *>( pEntity ); + if ( pWpn && vecDist.Length() < 100 ) + { + HintMessage( HINT_PICK_UP_WEAPON ); + } + } +} + +bool C_DODPlayer::ShouldAutoReload( void ) +{ + return cl_autoreload.GetBool(); +} + +bool C_DODPlayer::ShouldAutoRezoom( void ) +{ + return cl_autorezoom.GetBool(); +} + +void C_DODPlayer::CheckGrenadeHint( Vector vecGrenadeOrigin ) +{ + if ( m_Hints.HasPlayedHint( HINT_PICK_UP_GRENADE ) == false ) + { + // if its within 500 units + float flDist = ( vecGrenadeOrigin - GetAbsOrigin() ).Length2D(); + + if ( flDist < 500 ) + { + m_Hints.HintMessage( HINT_PICK_UP_GRENADE ); + } + } +} + +void C_DODPlayer::CheckBombTargetPlantHint( void ) +{ + if ( m_Hints.HasPlayedHint( HINT_BOMB_TARGET ) == false ) + { + m_Hints.HintMessage( HINT_BOMB_TARGET ); + } +} + +void C_DODPlayer::CheckBombTargetDefuseHint( void ) +{ + if ( m_Hints.HasPlayedHint( HINT_DEFUSE_BOMB ) == false ) + { + m_Hints.HintMessage( HINT_DEFUSE_BOMB ); + } +} + +void C_DODPlayer::LowerWeapon( void ) +{ + m_bWeaponLowered = true; +} + +void C_DODPlayer::RaiseWeapon( void ) +{ + m_bWeaponLowered = false; +} + +bool C_DODPlayer::IsWeaponLowered( void ) +{ + if ( GetMoveType() == MOVETYPE_LADDER ) + return true; + + CWeaponDODBase *pWeapon = GetActiveDODWeapon(); + + if ( !pWeapon ) + return false; + + // Lower when underwater ( except if its melee ) + if ( GetWaterLevel() > 2 && pWeapon->GetDODWpnData().m_WeaponType != WPN_TYPE_MELEE ) + return true; + + if ( m_Shared.IsProne() && GetAbsVelocity().LengthSqr() > 1 ) + return true; + + if ( m_Shared.IsGoingProne() || m_Shared.IsGettingUpFromProne() ) + return true; + + if ( m_Shared.IsJumping() ) + return true; + + if ( m_Shared.IsDefusing() ) + return true; + + // Lower losing team's weapons in bonus round + int state = DODGameRules()->State_Get(); + + if ( state == STATE_ALLIES_WIN && GetTeamNumber() == TEAM_AXIS ) + return true; + + if ( state == STATE_AXIS_WIN && GetTeamNumber() == TEAM_ALLIES ) + return true; + + if ( m_Shared.IsBazookaDeployed() ) + return false; + + Vector vel = GetAbsVelocity(); + if ( vel.Length2D() < 50 ) + return false; + + if ( m_nButtons & IN_SPEED && ( m_nButtons & IN_FORWARD ) && + m_Shared.GetStamina() >= 5 && + !m_Shared.IsDucking() ) + return true; + + return m_bWeaponLowered; +} + +// Shadows + +ConVar cl_blobbyshadows( "cl_blobbyshadows", "0", FCVAR_CLIENTDLL ); +ShadowType_t C_DODPlayer::ShadowCastType( void ) +{ + if ( !IsVisible() ) + return SHADOWS_NONE; + + C_DODPlayer *pLocalPlayer = C_DODPlayer::GetLocalDODPlayer(); + + // if we're first person spectating this player + if ( pLocalPlayer && + pLocalPlayer->GetObserverTarget() == this && + pLocalPlayer->GetObserverMode() == OBS_MODE_IN_EYE ) + { + return SHADOWS_NONE; + } + + if( cl_blobbyshadows.GetBool() ) + return SHADOWS_SIMPLE; + + return SHADOWS_RENDER_TO_TEXTURE_DYNAMIC; +} + +float g_flFattenAmt = 4; +void C_DODPlayer::GetShadowRenderBounds( Vector &mins, Vector &maxs, ShadowType_t shadowType ) +{ + if ( shadowType == SHADOWS_SIMPLE ) + { + // Don't let the render bounds change when we're using blobby shadows, or else the shadow + // will pop and stretch. + mins = CollisionProp()->OBBMins(); + maxs = CollisionProp()->OBBMaxs(); + } + else + { + GetRenderBounds( mins, maxs ); + + // We do this because the normal bbox calculations don't take pose params into account, and + // the rotation of the guy's upper torso can place his gun a ways out of his bbox, and + // the shadow will get cut off as he rotates. + // + // Thus, we give it some padding here. + mins -= Vector( g_flFattenAmt, g_flFattenAmt, 0 ); + maxs += Vector( g_flFattenAmt, g_flFattenAmt, 0 ); + } +} + + +void C_DODPlayer::GetRenderBounds( Vector& theMins, Vector& theMaxs ) +{ + // TODO POSTSHIP - this hack/fix goes hand-in-hand with a fix in CalcSequenceBoundingBoxes in utils/studiomdl/simplify.cpp. + // When we enable the fix in CalcSequenceBoundingBoxes, we can get rid of this. + // + // What we're doing right here is making sure it only uses the bbox for our lower-body sequences since, + // with the current animations and the bug in CalcSequenceBoundingBoxes, are WAY bigger than they need to be. + C_BaseAnimating::GetRenderBounds( theMins, theMaxs ); +} + + +bool C_DODPlayer::GetShadowCastDirection( Vector *pDirection, ShadowType_t shadowType ) const +{ + if ( shadowType == SHADOWS_SIMPLE ) + { + // Blobby shadows should sit directly underneath us. + pDirection->Init( 0, 0, -1 ); + return true; + } + else + { + return BaseClass::GetShadowCastDirection( pDirection, shadowType ); + } +} + +ConVar cl_muzzleflash_dlight_3rd( "cl_muzzleflash_dlight_3rd", "1" ); + +void C_DODPlayer::ProcessMuzzleFlashEvent() +{ + CBasePlayer *pLocalPlayer = C_BasePlayer::GetLocalPlayer(); + + bool bInToolRecordingMode = ToolsEnabled() && clienttools->IsInRecordingMode(); + + // Reenable when the weapons have muzzle flash attachments in the right spot. + if ( this == pLocalPlayer && !bInToolRecordingMode ) + return; // don't show own world muzzle flashs in for localplayer + + if ( pLocalPlayer && pLocalPlayer->GetObserverMode() == OBS_MODE_IN_EYE ) + { + // also don't show in 1st person spec mode + if ( pLocalPlayer->GetObserverTarget() == this ) + return; + } + + CWeaponDODBase *pWeapon = GetActiveDODWeapon(); + if ( !pWeapon ) + return; + + int nModelIndex = pWeapon->GetModelIndex(); + int nWorldModelIndex = pWeapon->GetWorldModelIndex(); + if ( bInToolRecordingMode && nModelIndex != nWorldModelIndex ) + { + pWeapon->SetModelIndex( nWorldModelIndex ); + } + + Vector vecOrigin; + QAngle angAngles; + + //MATTTODO - use string names of the weapon + const static int iMuzzleFlashAttachment = 1; + const static int iEjectBrassAttachment = 2; + + // If we have an attachment, then stick a light on it. + if ( cl_muzzleflash_dlight_3rd.GetBool() && pWeapon->GetAttachment( iMuzzleFlashAttachment, vecOrigin, angAngles ) ) + { + // Muzzleflash light + dlight_t *el = effects->CL_AllocDlight( LIGHT_INDEX_MUZZLEFLASH ); + el->origin = vecOrigin; + el->radius = 70; + + if ( pWeapon->GetDODWpnData().m_WeaponType == WPN_TYPE_SNIPER ) + el->radius = 150; + + el->decay = el->radius / 0.05f; + el->die = gpGlobals->curtime + 0.05f; + el->color.r = 255; + el->color.g = 192; + el->color.b = 64; + el->color.exponent = 5; + + if ( bInToolRecordingMode ) + { + Color clr( el->color.r, el->color.g, el->color.b ); + + KeyValues *msg = new KeyValues( "TempEntity" ); + + msg->SetInt( "te", TE_DYNAMIC_LIGHT ); + msg->SetString( "name", "TE_DynamicLight" ); + msg->SetFloat( "time", gpGlobals->curtime ); + msg->SetFloat( "duration", el->die ); + msg->SetFloat( "originx", el->origin.x ); + msg->SetFloat( "originy", el->origin.y ); + msg->SetFloat( "originz", el->origin.z ); + msg->SetFloat( "radius", el->radius ); + msg->SetFloat( "decay", el->decay ); + msg->SetColor( "color", clr ); + msg->SetInt( "exponent", el->color.exponent ); + msg->SetInt( "lightindex", LIGHT_INDEX_MUZZLEFLASH ); + + ToolFramework_PostToolMessage( HTOOLHANDLE_INVALID, msg ); + msg->deleteThis(); + } + } + + const char *pszMuzzleFlashEffect = NULL; + + switch( pWeapon->GetDODWpnData().m_iMuzzleFlashType ) + { + case DOD_MUZZLEFLASH_PISTOL: + pszMuzzleFlashEffect = "muzzle_pistols"; + break; + case DOD_MUZZLEFLASH_AUTO: + pszMuzzleFlashEffect = "muzzle_fullyautomatic"; + break; + case DOD_MUZZLEFLASH_RIFLE: + pszMuzzleFlashEffect = "muzzle_rifles"; + break; + case DOD_MUZZLEFLASH_ROCKET: + pszMuzzleFlashEffect = "muzzle_rockets"; + break; + case DOD_MUZZLEFLASH_MG42: + pszMuzzleFlashEffect = "muzzle_mg42"; + break; + default: + break; + } + + if ( pszMuzzleFlashEffect ) + { + DispatchParticleEffect( pszMuzzleFlashEffect, PATTACH_POINT_FOLLOW, pWeapon, 1 ); + } + + if( pWeapon->ShouldAutoEjectBrass() ) + { + // shell eject + if( pWeapon->GetAttachment( iEjectBrassAttachment, vecOrigin, angAngles ) ) + { + int shellType = pWeapon->GetEjectBrassShellType(); + + CEffectData data; + data.m_nHitBox = shellType; + data.m_vOrigin = vecOrigin; + data.m_vAngles = angAngles; + DispatchEffect( "DOD_EjectBrass", data ); + } + } + + if ( bInToolRecordingMode && nModelIndex != nWorldModelIndex ) + { + pWeapon->SetModelIndex( nModelIndex ); + } +} + +void C_DODPlayer::NotifyShouldTransmit( ShouldTransmitState_t state ) +{ + // Remove all effects if we go out of the PVS. + if ( state == SHOULDTRANSMIT_END ) + { + if( m_pFlashlightBeam != NULL ) + { + ReleaseFlashlight(); + } + } + + BaseClass::NotifyShouldTransmit( state ); +} + +void C_DODPlayer::Simulate( void ) +{ + if( this != C_BasePlayer::GetLocalPlayer() ) + { + if ( IsEffectActive( EF_DIMLIGHT ) ) + { + QAngle eyeAngles = m_angEyeAngles; + Vector vForward; + AngleVectors( eyeAngles, &vForward ); + + int iAttachment = LookupAttachment( "anim_attachment_RH" ); + + Vector vecOrigin; + QAngle dummy; + GetAttachment( iAttachment, vecOrigin, dummy ); + + trace_t tr; + UTIL_TraceLine( vecOrigin, vecOrigin + (vForward * 200), MASK_SHOT, this, COLLISION_GROUP_NONE, &tr ); + + if( !m_pFlashlightBeam ) + { + BeamInfo_t beamInfo; + beamInfo.m_nType = TE_BEAMPOINTS; + beamInfo.m_vecStart = tr.startpos; + beamInfo.m_vecEnd = tr.endpos; + beamInfo.m_pszModelName = "sprites/glow01.vmt"; + beamInfo.m_pszHaloName = "sprites/glow01.vmt"; + beamInfo.m_flHaloScale = 3.0; + beamInfo.m_flWidth = 8.0f; + beamInfo.m_flEndWidth = 35.0f; + beamInfo.m_flFadeLength = 300.0f; + beamInfo.m_flAmplitude = 0; + beamInfo.m_flBrightness = 60.0; + beamInfo.m_flSpeed = 0.0f; + beamInfo.m_nStartFrame = 0.0; + beamInfo.m_flFrameRate = 0.0; + beamInfo.m_flRed = 255.0; + beamInfo.m_flGreen = 255.0; + beamInfo.m_flBlue = 255.0; + beamInfo.m_nSegments = 8; + beamInfo.m_bRenderable = true; + beamInfo.m_flLife = 0.5; + beamInfo.m_nFlags = FBEAM_FOREVER | FBEAM_ONLYNOISEONCE | FBEAM_NOTILE | FBEAM_HALOBEAM; + + m_pFlashlightBeam = beams->CreateBeamPoints( beamInfo ); + } + + if( m_pFlashlightBeam ) + { + BeamInfo_t beamInfo; + beamInfo.m_vecStart = tr.startpos; + beamInfo.m_vecEnd = tr.endpos; + beamInfo.m_flRed = 255.0; + beamInfo.m_flGreen = 255.0; + beamInfo.m_flBlue = 255.0; + + beams->UpdateBeamInfo( m_pFlashlightBeam, beamInfo ); + + dlight_t *el = effects->CL_AllocDlight( 0 ); + el->origin = tr.endpos; + el->radius = 50; + el->color.r = 200; + el->color.g = 200; + el->color.b = 200; + el->die = gpGlobals->curtime + 0.1; + } + } + else if ( m_pFlashlightBeam ) + { + ReleaseFlashlight(); + } + } + + BaseClass::Simulate(); +} + +void C_DODPlayer::ReleaseFlashlight( void ) +{ + if( m_pFlashlightBeam ) + { + m_pFlashlightBeam->flags = 0; + m_pFlashlightBeam->die = gpGlobals->curtime - 1; + + m_pFlashlightBeam = NULL; + } +} + +bool C_DODPlayer::SetFOV( CBaseEntity *pRequester, int FOV, float zoomRate /* = 0.0f */ ) +{ + /* + if( FOV < 30 ) + { + // fade in + ScreenFade_t sf; + memset( &sf, 0, sizeof( sf ) ); + sf.a = 255; + sf.r = 0; + sf.g = 0; + sf.b = 0; + sf.duration = (unsigned short)((float)(1<<SCREENFADE_FRACBITS) * 2.5f ); + sf.fadeFlags = FFADE_IN; + vieweffects->Fade( sf ); + } + else + { + //cancel the fade if its active + ScreenFade_t sf; + memset( &sf, 0, sizeof( sf ) ); + sf.fadeFlags = FFADE_IN | FFADE_PURGE; + vieweffects->Fade( sf ); + } + */ + + return true; +} + +void C_DODPlayer::CalcObserverView( Vector& eyeOrigin, QAngle& eyeAngles, float& fov ) +{ + if( GetObserverMode() == OBS_MODE_DEATHCAM ) + { + CalcDODDeathCamView( eyeOrigin, eyeAngles, fov ); + } + else + BaseClass::CalcObserverView( eyeOrigin, eyeAngles, fov ); +} + +static Vector WALL_MIN(-WALL_OFFSET,-WALL_OFFSET,-WALL_OFFSET); +static Vector WALL_MAX(WALL_OFFSET,WALL_OFFSET,WALL_OFFSET); + +void C_DODPlayer::CalcDODDeathCamView(Vector& eyeOrigin, QAngle& eyeAngles, float& fov) +{ + CBaseEntity * killer = GetObserverTarget(); + + //float interpolation = ( gpGlobals->curtime - m_flDeathTime ) / DEATH_ANIMATION_TIME; + + // Interpolate very quickly to the killer and follow + float interpolation = ( gpGlobals->curtime - m_flDeathTime ) / 0.2f; + interpolation = clamp( interpolation, 0.0f, 1.0f ); + + m_flObserverChaseDistance += gpGlobals->frametime*48.0f; + m_flObserverChaseDistance = clamp( m_flObserverChaseDistance, CHASE_CAM_DISTANCE_MIN, CHASE_CAM_DISTANCE_MAX ); + + QAngle aForward = eyeAngles = EyeAngles(); + Vector origin = EyePosition(); + + IRagdoll *pRagdoll = GetRepresentativeRagdoll(); + if ( pRagdoll ) + { + origin = pRagdoll->GetRagdollOrigin(); + origin.z += VEC_DEAD_VIEWHEIGHT_SCALED( this ).z; // look over ragdoll, not through + } + + if ( killer && (killer != this) ) + { + Vector vecKiller = killer->GetAbsOrigin(); + + C_DODPlayer *player = ToDODPlayer( killer ); + if ( player && player->IsAlive() ) + { + if ( player->m_Shared.IsProne() ) + { + VectorAdd( vecKiller, VEC_PRONE_VIEW_SCALED( this ), vecKiller ); + } + else if( player->GetFlags() & FL_DUCKING ) + { + VectorAdd( vecKiller, VEC_DUCK_VIEW_SCALED( this ), vecKiller ); + } + else + { + VectorAdd( vecKiller, VEC_VIEW_SCALED( this ), vecKiller ); + } + } + + Vector vecToKiller = vecKiller - origin; + QAngle aKiller; + VectorAngles( vecToKiller, aKiller ); + InterpolateAngles( aForward, aKiller, eyeAngles, interpolation ); + } + + Vector vForward; AngleVectors( eyeAngles, &vForward ); + + VectorNormalize( vForward ); + + VectorMA( origin, -m_flObserverChaseDistance, vForward, eyeOrigin ); + + trace_t trace; // clip against world + C_BaseEntity::PushEnableAbsRecomputations( false ); // HACK don't recompute positions while doing RayTrace + UTIL_TraceHull( origin, eyeOrigin, WALL_MIN, WALL_MAX, MASK_SOLID, this, COLLISION_GROUP_NONE, &trace ); + C_BaseEntity::PopEnableAbsRecomputations(); + + if (trace.fraction < 1.0) + { + eyeOrigin = trace.endpos; + m_flObserverChaseDistance = VectorLength(origin - eyeOrigin); + } + + fov = GetFOV(); +} + +void C_DODPlayer::CalcChaseCamView(Vector& eyeOrigin, QAngle& eyeAngles, float& fov) +{ + C_BaseEntity *target = GetObserverTarget(); + + if ( !target ) + { + // just copy a save in-map position + VectorCopy( EyePosition(), eyeOrigin ); + VectorCopy( EyeAngles(), eyeAngles ); + return; + }; + + Vector forward, viewpoint; + + // GetRenderOrigin() returns ragdoll pos if player is ragdolled + Vector origin = target->GetRenderOrigin(); + + C_DODPlayer *player = ToDODPlayer( target ); + + if ( player && player->IsAlive() ) + { + if ( player->m_Shared.IsProne() ) + { + VectorAdd( origin, VEC_PRONE_VIEW_SCALED( this ), origin ); + } + else if( player->GetFlags() & FL_DUCKING ) + { + VectorAdd( origin, VEC_DUCK_VIEW_SCALED( this ), origin ); + } + else + { + VectorAdd( origin, VEC_VIEW_SCALED( this ), origin ); + } + } + else + { + // assume it's the players ragdoll + VectorAdd( origin, VEC_DEAD_VIEWHEIGHT_SCALED( this ), origin ); + } + + QAngle viewangles; + + if ( IsLocalPlayer() ) + { + engine->GetViewAngles( viewangles ); + } + else + { + viewangles = EyeAngles(); + } + + m_flObserverChaseDistance += gpGlobals->frametime*48.0f; + m_flObserverChaseDistance = clamp( m_flObserverChaseDistance, CHASE_CAM_DISTANCE_MIN, CHASE_CAM_DISTANCE_MAX ); + + AngleVectors( viewangles, &forward ); + + VectorNormalize( forward ); + + VectorMA(origin, -m_flObserverChaseDistance, forward, viewpoint ); + + trace_t trace; + C_BaseEntity::PushEnableAbsRecomputations( false ); // HACK don't recompute positions while doing RayTrace + UTIL_TraceHull( origin, viewpoint, WALL_MIN, WALL_MAX, MASK_SOLID, target, COLLISION_GROUP_NONE, &trace ); + C_BaseEntity::PopEnableAbsRecomputations(); + + if (trace.fraction < 1.0) + { + viewpoint = trace.endpos; + m_flObserverChaseDistance = VectorLength(origin - eyeOrigin); + } + + VectorCopy( viewangles, eyeAngles ); + VectorCopy( viewpoint, eyeOrigin ); + + fov = GetFOV(); +} + +extern ConVar spec_freeze_traveltime; +extern ConVar spec_freeze_time; +extern ConVar cl_dod_freezecam; + +//----------------------------------------------------------------------------- +// Purpose: Calculate the view for the player while he's in freeze frame observer mode +//----------------------------------------------------------------------------- +void C_DODPlayer::CalcFreezeCamView( Vector& eyeOrigin, QAngle& eyeAngles, float& fov ) +{ + C_BaseEntity *pTarget = GetObserverTarget(); + if ( !pTarget || !cl_dod_freezecam.GetBool() ) + { + CalcDeathCamView( eyeOrigin, eyeAngles, fov ); + return; + } + + // Zoom towards our target + float flCurTime = (gpGlobals->curtime - m_flFreezeFrameStartTime); + float flBlendPerc = clamp( flCurTime / spec_freeze_traveltime.GetFloat(), 0, 1 ); + flBlendPerc = SimpleSpline( flBlendPerc ); + + // Find the position we would like to be lookin at + Vector vecCamDesired = pTarget->GetObserverCamOrigin(); // Returns ragdoll origin if they're ragdolled + VectorAdd( vecCamDesired, GetChaseCamViewOffset( pTarget ), vecCamDesired ); + Vector vecCamTarget = vecCamDesired; + if ( !pTarget->IsAlive() ) + { + vecCamTarget.z += pTarget->GetBaseAnimating() ? VEC_DEAD_VIEWHEIGHT_SCALED( pTarget->GetBaseAnimating() ).z : VEC_DEAD_VIEWHEIGHT.z; // look over ragdoll, not through + } + + // Figure out a view position in front of the target + Vector vecEyeOnPlane = eyeOrigin; + vecEyeOnPlane.z = vecCamTarget.z; + Vector vecTargetPos = vecCamTarget; + Vector vecToTarget = vecTargetPos - vecEyeOnPlane; + VectorNormalize( vecToTarget ); + + // Stop a few units away from the target, and shift up to be at the same height + vecTargetPos = vecCamTarget - (vecToTarget * m_flFreezeFrameDistance); + float flEyePosZ = pTarget->EyePosition().z; + vecTargetPos.z = flEyePosZ + m_flFreezeZOffset; + + // Now trace out from the target, so that we're put in front of any walls + trace_t trace; + C_BaseEntity::PushEnableAbsRecomputations( false ); // HACK don't recompute positions while doing RayTrace + UTIL_TraceLine( vecCamTarget, vecTargetPos, MASK_SOLID, pTarget, COLLISION_GROUP_NONE, &trace ); + C_BaseEntity::PopEnableAbsRecomputations(); + if (trace.fraction < 1.0 ) + { + // The camera's going to be really close to the target. So we don't end up + // looking at someone's chest, aim close freezecams at the target's eyes. + vecTargetPos = trace.endpos; + vecCamTarget = vecCamDesired; + + // To stop all close in views looking up at character's chins, move the view up. + vecTargetPos.z += fabs(vecCamTarget.z - vecTargetPos.z) * 0.85; + C_BaseEntity::PushEnableAbsRecomputations( false ); // HACK don't recompute positions while doing RayTrace + UTIL_TraceLine( vecCamTarget, vecTargetPos, MASK_SOLID, pTarget, COLLISION_GROUP_NONE, &trace ); + C_BaseEntity::PopEnableAbsRecomputations(); + vecTargetPos = trace.endpos; + } + + // Look directly at the target + vecToTarget = vecCamTarget - vecTargetPos; + VectorNormalize( vecToTarget ); + VectorAngles( vecToTarget, eyeAngles ); + + VectorLerp( m_vecFreezeFrameStart, vecTargetPos, flBlendPerc, eyeOrigin ); + + if ( flCurTime >= spec_freeze_traveltime.GetFloat() && !m_bSentFreezeFrame ) + { + IGameEvent *pEvent = gameeventmanager->CreateEvent( "freezecam_started" ); + if ( pEvent ) + { + gameeventmanager->FireEventClientSide( pEvent ); + } + + m_bSentFreezeFrame = true; + view->FreezeFrame( spec_freeze_time.GetFloat() ); + } +} + +const Vector& C_DODPlayer::GetRenderOrigin( void ) +{ + if ( !IsAlive() && m_hRagdoll.Get() ) + return m_hRagdoll.Get()->GetRenderOrigin(); + + return BaseClass::GetRenderOrigin(); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +Vector C_DODPlayer::GetChaseCamViewOffset( CBaseEntity *target ) +{ + C_DODPlayer *pPlayer = ToDODPlayer( target ); + + if ( pPlayer && pPlayer->IsAlive() ) + { + if ( pPlayer->m_Shared.IsProne() ) + { + return VEC_PRONE_VIEW; + } + } + + return BaseClass::GetChaseCamViewOffset( target ); +} + +const QAngle& C_DODPlayer::EyeAngles() +{ + if ( IsLocalPlayer() && g_nKillCamMode == OBS_MODE_NONE ) + { + return BaseClass::EyeAngles(); + } + else + { + return m_angEyeAngles; + } +} + +// Cold breath defines. +#define COLDBREATH_EMIT_MIN 2.0f +#define COLDBREATH_EMIT_MAX 3.0f +#define COLDBREATH_EMIT_SCALE 0.35f +#define COLDBREATH_PARTICLE_LIFE_MIN 0.25f +#define COLDBREATH_PARTICLE_LIFE_MAX 1.0f +#define COLDBREATH_PARTICLE_LIFE_SCALE 0.75 +#define COLDBREATH_PARTICLE_SIZE_MIN 1.0f +#define COLDBREATH_PARTICLE_SIZE_MAX 4.0f +#define COLDBREATH_PARTICLE_SIZE_SCALE 1.1f +#define COLDBREATH_PARTICLE_COUNT 1 +#define COLDBREATH_DURATION_MIN 0.0f +#define COLDBREATH_DURATION_MAX 1.0f +#define COLDBREATH_ALPHA_MIN 0.0f +#define COLDBREATH_ALPHA_MAX 0.3f +#define COLDBREATH_ENDSCALE_MIN 0.1f +#define COLDBREATH_ENDSCALE_MAX 0.4f + +static ConVar cl_coldbreath_forcestamina( "cl_coldbreath_forcestamina", "0", FCVAR_CHEAT ); +static ConVar cl_coldbreath_enable( "cl_coldbreath_enable", "1" ); + +//----------------------------------------------------------------------------- +// Purpose: Create the emitter of cold breath particles +//----------------------------------------------------------------------------- +bool C_DODPlayer::CreateColdBreathEmitter( void ) +{ + // Check to see if we are in a cold breath scenario. + if ( !GetClientWorldEntity()->m_bColdWorld ) + return false; + + // Set cold breath to true. + m_bColdBreathOn = true; + + // Create a cold breath emitter if one doesn't already exist. + if ( !m_hColdBreathEmitter ) + { + m_hColdBreathEmitter = ColdBreathEmitter::Create( "ColdBreath" ); + if ( !m_hColdBreathEmitter ) + return false; + + // Get the particle material. + m_hColdBreathMaterial = m_hColdBreathEmitter->GetPMaterial( "sprites/frostbreath" ); + Assert( m_hColdBreathMaterial != INVALID_MATERIAL_HANDLE ); + + // Cache off the head attachment for setting up cold breath. + m_iHeadAttach = LookupAttachment( "head" ); + } + + return true; +} + +//----------------------------------------------------------------------------- +// Purpose: Destroy the cold breath emitter +//----------------------------------------------------------------------------- +void C_DODPlayer::DestroyColdBreathEmitter( void ) +{ +#if 0 + if ( m_hColdBreathEmitter.IsValid() ) + { + UTIL_Remove( m_hColdBreathEmitter ); + } +#endif +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_DODPlayer::UpdateColdBreath( void ) +{ + if ( !cl_coldbreath_enable.GetBool() ) + return; + + // Check to see if the cold breath emitter has been created. + if ( !m_hColdBreathEmitter.IsValid() ) + { + if ( !CreateColdBreathEmitter() ) + return; + } + + // Cold breath updates. + if ( !m_bColdBreathOn ) + return; + + // Don't emit breath if we are dead. + if ( !IsAlive() || IsDormant() ) + return; + + // Check player speed, do emit cold breath when moving quickly. + float flSpeed = GetAbsVelocity().Length(); + if ( flSpeed > 60.0f ) + return; + + if ( m_flColdBreathTimeStart < gpGlobals->curtime ) + { + // Spawn cold breath particles. + EmitColdBreathParticles(); + + // Update the timer. + if ( m_flColdBreathTimeEnd < gpGlobals->curtime ) + { + // Check stamina and modify the time accordingly. + if ( m_Shared.m_flStamina < LOW_STAMINA_THRESHOLD || cl_coldbreath_forcestamina.GetBool() ) + { + m_flColdBreathTimeStart = gpGlobals->curtime + RandomFloat( COLDBREATH_EMIT_MIN * COLDBREATH_EMIT_SCALE, COLDBREATH_EMIT_MAX * COLDBREATH_EMIT_SCALE ); + float flDuration = RandomFloat( COLDBREATH_DURATION_MIN, COLDBREATH_DURATION_MAX ); + m_flColdBreathTimeEnd = m_flColdBreathTimeStart + flDuration; + } + else + { + m_flColdBreathTimeStart = gpGlobals->curtime + RandomFloat( COLDBREATH_EMIT_MIN, COLDBREATH_EMIT_MAX ); + float flDuration = RandomFloat( COLDBREATH_DURATION_MIN, COLDBREATH_DURATION_MAX ); + m_flColdBreathTimeEnd = m_flColdBreathTimeStart + flDuration; + } + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_DODPlayer::CalculateIKLocks( float currentTime ) +{ + if (!m_pIk) + return; + + int targetCount = m_pIk->m_target.Count(); + if ( targetCount == 0 ) + return; + + // In TF, we might be attaching a player's view to a walking model that's using IK. If we are, it can + // get in here during the view setup code, and it's not normally supposed to be able to access the spatial + // partition that early in the rendering loop. So we allow access right here for that special case. + SpatialPartitionListMask_t curSuppressed = partition->GetSuppressedLists(); + partition->SuppressLists( PARTITION_ALL_CLIENT_EDICTS, false ); + CBaseEntity::PushEnableAbsRecomputations( false ); + + for (int i = 0; i < targetCount; i++) + { + trace_t trace; + CIKTarget *pTarget = &m_pIk->m_target[i]; + + if (!pTarget->IsActive()) + continue; + + switch( pTarget->type) + { + case IK_GROUND: + { + pTarget->SetPos( Vector( pTarget->est.pos.x, pTarget->est.pos.y, GetRenderOrigin().z )); + pTarget->SetAngles( GetRenderAngles() ); + } + break; + + case IK_ATTACHMENT: + { + C_BaseEntity *pEntity = NULL; + float flDist = pTarget->est.radius; + + // FIXME: make entity finding sticky! + // FIXME: what should the radius check be? + for ( CEntitySphereQuery sphere( pTarget->est.pos, 64 ); ( pEntity = sphere.GetCurrentEntity() ) != NULL; sphere.NextEntity() ) + { + C_BaseAnimating *pAnim = pEntity->GetBaseAnimating( ); + if (!pAnim) + continue; + + int iAttachment = pAnim->LookupAttachment( pTarget->offset.pAttachmentName ); + if (iAttachment <= 0) + continue; + + Vector origin; + QAngle angles; + pAnim->GetAttachment( iAttachment, origin, angles ); + + // debugoverlay->AddBoxOverlay( origin, Vector( -1, -1, -1 ), Vector( 1, 1, 1 ), QAngle( 0, 0, 0 ), 255, 0, 0, 0, 0 ); + + float d = (pTarget->est.pos - origin).Length(); + + if ( d >= flDist) + continue; + + flDist = d; + pTarget->SetPos( origin ); + pTarget->SetAngles( angles ); + // debugoverlay->AddBoxOverlay( pTarget->est.pos, Vector( -pTarget->est.radius, -pTarget->est.radius, -pTarget->est.radius ), Vector( pTarget->est.radius, pTarget->est.radius, pTarget->est.radius), QAngle( 0, 0, 0 ), 0, 255, 0, 0, 0 ); + } + + if (flDist >= pTarget->est.radius) + { + // debugoverlay->AddBoxOverlay( pTarget->est.pos, Vector( -pTarget->est.radius, -pTarget->est.radius, -pTarget->est.radius ), Vector( pTarget->est.radius, pTarget->est.radius, pTarget->est.radius), QAngle( 0, 0, 0 ), 0, 0, 255, 0, 0 ); + // no solution, disable ik rule + pTarget->IKFailed( ); + } + } + break; + } + } + + CBaseEntity::PopEnableAbsRecomputations(); + partition->SuppressLists( curSuppressed, true ); +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_DODPlayer::EmitColdBreathParticles( void ) +{ + // Get the position to emit from - look into caching this off we are doing redundant work in the case + // of allies (see dod_headiconmanager.cpp). + Vector vecOrigin; + QAngle vecAngle; + GetAttachment( m_iHeadAttach, vecOrigin, vecAngle ); + Vector vecForward, vecRight, vecUp; + AngleVectors( vecAngle, &vecUp, &vecForward, &vecRight ); + + vecOrigin += ( vecForward * 8.0f ); + + SimpleParticle *pParticle = static_cast<SimpleParticle*>( m_hColdBreathEmitter->AddParticle( sizeof( SimpleParticle ),m_hColdBreathMaterial, vecOrigin ) ); + if ( pParticle ) + { + pParticle->m_flLifetime = 0.0f; + pParticle->m_flDieTime = RandomFloat( COLDBREATH_PARTICLE_LIFE_MIN, COLDBREATH_PARTICLE_LIFE_MAX ); + if ( m_Shared.m_flStamina < LOW_STAMINA_THRESHOLD || cl_coldbreath_forcestamina.GetBool() ) + { + pParticle->m_flDieTime *= COLDBREATH_PARTICLE_LIFE_SCALE; + } + + // Add just a little movement. + if ( m_Shared.m_flStamina < LOW_STAMINA_THRESHOLD || cl_coldbreath_forcestamina.GetBool() ) + { + pParticle->m_vecVelocity = ( vecForward * RandomFloat( 10.0f, 30.0f ) ) + ( vecRight * RandomFloat( -2.0f, 2.0f ) ) + + ( vecUp * RandomFloat( 0.0f, 0.5f ) ); + } + else + { + pParticle->m_vecVelocity = ( vecForward * RandomFloat( 10.0f, 20.0f ) ) + ( vecRight * RandomFloat( -2.0f, 2.0f ) ) + + ( vecUp * RandomFloat( 0.0f, 1.5f ) ); + } + + pParticle->m_uchColor[0] = 200; + pParticle->m_uchColor[1] = 200; + pParticle->m_uchColor[2] = 210; + + float flParticleSize = RandomFloat( COLDBREATH_PARTICLE_SIZE_MIN, COLDBREATH_PARTICLE_SIZE_MAX ); + float flParticleScale = RandomFloat( COLDBREATH_ENDSCALE_MIN, COLDBREATH_ENDSCALE_MAX ); + if ( m_Shared.m_flStamina < LOW_STAMINA_THRESHOLD || cl_coldbreath_forcestamina.GetBool() ) + { + pParticle->m_uchEndSize = flParticleSize * COLDBREATH_PARTICLE_SIZE_SCALE; + flParticleScale *= COLDBREATH_PARTICLE_SIZE_SCALE; + } + else + { + pParticle->m_uchEndSize = flParticleSize; + } + pParticle->m_uchStartSize = ( flParticleSize * flParticleScale ); + + float flAlpha = RandomFloat( COLDBREATH_ALPHA_MIN, COLDBREATH_ALPHA_MAX ); + pParticle->m_uchStartAlpha = flAlpha * 255; + pParticle->m_uchEndAlpha = 0; + + pParticle->m_flRoll = RandomInt( 0, 360 ); + pParticle->m_flRollDelta = RandomFloat( 0.0f, 1.25f ); + } +} + +void C_DODPlayer::ComputeWorldSpaceSurroundingBox( Vector *pVecWorldMins, Vector *pVecWorldMaxs ) +{ + m_Shared.ComputeWorldSpaceSurroundingBox( pVecWorldMins, pVecWorldMaxs ); +} + +//----------------------------------------------------------------------------- +// Purpose: Try to steer away from any players and objects we might interpenetrate +//----------------------------------------------------------------------------- +#define DOD_AVOID_MAX_RADIUS_SQR 5184.0f // Based on player extents and max buildable extents. +#define DOD_OO_AVOID_MAX_RADIUS_SQR 0.00019f + +#define DOD_MAX_SEPARATION_FORCE 256 + +extern ConVar cl_forwardspeed; +extern ConVar cl_backspeed; +extern ConVar cl_sidespeed; + +void C_DODPlayer::AvoidPlayers( CUserCmd *pCmd ) +{ + // Don't test if the player is dead. + if ( IsAlive() == false ) + return; + + C_Team *pTeam = ( C_Team * )GetTeam(); + if ( !pTeam ) + return; + + // Up vector. + static Vector vecUp( 0.0f, 0.0f, 1.0f ); + + Vector vecDODPlayerCenter = GetAbsOrigin(); + Vector vecDODPlayerMin = GetPlayerMins(); + Vector vecDODPlayerMax = GetPlayerMaxs(); + float flZHeight = vecDODPlayerMax.z - vecDODPlayerMin.z; + vecDODPlayerCenter.z += 0.5f * flZHeight; + VectorAdd( vecDODPlayerMin, vecDODPlayerCenter, vecDODPlayerMin ); + VectorAdd( vecDODPlayerMax, vecDODPlayerCenter, vecDODPlayerMax ); + + // Find an intersecting player or object. + int nAvoidPlayerCount = 0; + C_DODPlayer *pAvoidPlayerList[MAX_PLAYERS]; + + C_DODPlayer *pIntersectPlayer = NULL; + float flAvoidRadius = 0.0f; + + Vector vecAvoidCenter, vecAvoidMin, vecAvoidMax; + for ( int i = 0; i < pTeam->GetNumPlayers(); ++i ) + { + C_DODPlayer *pAvoidPlayer = static_cast< C_DODPlayer * >( pTeam->GetPlayer( i ) ); + if ( pAvoidPlayer == NULL ) + continue; + // Is the avoid player me? + if ( pAvoidPlayer == this ) + continue; + + // Save as list to check against for objects. + pAvoidPlayerList[nAvoidPlayerCount] = pAvoidPlayer; + ++nAvoidPlayerCount; + + // Check to see if the avoid player is dormant. + if ( pAvoidPlayer->IsDormant() ) + continue; + + // Is the avoid player solid? + if ( pAvoidPlayer->IsSolidFlagSet( FSOLID_NOT_SOLID ) ) + continue; + + Vector t1, t2; + + vecAvoidCenter = pAvoidPlayer->GetAbsOrigin(); + vecAvoidMin = pAvoidPlayer->GetPlayerMins(); + vecAvoidMax = pAvoidPlayer->GetPlayerMaxs(); + flZHeight = vecAvoidMax.z - vecAvoidMin.z; + vecAvoidCenter.z += 0.5f * flZHeight; + VectorAdd( vecAvoidMin, vecAvoidCenter, vecAvoidMin ); + VectorAdd( vecAvoidMax, vecAvoidCenter, vecAvoidMax ); + + if ( IsBoxIntersectingBox( vecDODPlayerMin, vecDODPlayerMax, vecAvoidMin, vecAvoidMax ) ) + { + // Need to avoid this player. + if ( !pIntersectPlayer ) + { + pIntersectPlayer = pAvoidPlayer; + break; + } + } + } + + // Anything to avoid? + if ( !pIntersectPlayer ) + { + return; + } + + // Calculate the push strength and direction. + Vector vecDelta; + + // Avoid a player - they have precedence. + if ( pIntersectPlayer ) + { + VectorSubtract( pIntersectPlayer->WorldSpaceCenter(), vecDODPlayerCenter, vecDelta ); + + Vector vRad = pIntersectPlayer->WorldAlignMaxs() - pIntersectPlayer->WorldAlignMins(); + vRad.z = 0; + + flAvoidRadius = vRad.Length(); + } + + float flPushStrength = RemapValClamped( vecDelta.Length(), flAvoidRadius, 0, 0, DOD_MAX_SEPARATION_FORCE ); //flPushScale; + + //Msg( "PushScale = %f\n", flPushStrength ); + + // Check to see if we have enough push strength to make a difference. + if ( flPushStrength < 0.01f ) + return; + + Vector vecPush; + if ( GetAbsVelocity().Length2DSqr() > 0.1f ) + { + Vector vecVelocity = GetAbsVelocity(); + vecVelocity.z = 0.0f; + CrossProduct( vecUp, vecVelocity, vecPush ); + VectorNormalize( vecPush ); + } + else + { + // We are not moving, but we're still intersecting. + QAngle angView = pCmd->viewangles; + angView.x = 0.0f; + AngleVectors( angView, NULL, &vecPush, NULL ); + } + + // Move away from the other player/object. + Vector vecSeparationVelocity; + if ( vecDelta.Dot( vecPush ) < 0 ) + { + vecSeparationVelocity = vecPush * flPushStrength; + } + else + { + vecSeparationVelocity = vecPush * -flPushStrength; + } + + // Don't allow the max push speed to be greater than the max player speed. + float flMaxPlayerSpeed = MaxSpeed(); + float flCropFraction = 1.33333333f; + + if ( ( GetFlags() & FL_DUCKING ) && ( GetGroundEntity() != NULL ) ) + { + flMaxPlayerSpeed *= flCropFraction; + } + + float flMaxPlayerSpeedSqr = flMaxPlayerSpeed * flMaxPlayerSpeed; + + if ( vecSeparationVelocity.LengthSqr() > flMaxPlayerSpeedSqr ) + { + vecSeparationVelocity.NormalizeInPlace(); + VectorScale( vecSeparationVelocity, flMaxPlayerSpeed, vecSeparationVelocity ); + } + + QAngle vAngles = pCmd->viewangles; + vAngles.x = 0; + Vector currentdir; + Vector rightdir; + + AngleVectors( vAngles, ¤tdir, &rightdir, NULL ); + + Vector vDirection = vecSeparationVelocity; + + VectorNormalize( vDirection ); + + float fwd = currentdir.Dot( vDirection ); + float rt = rightdir.Dot( vDirection ); + + float forward = fwd * flPushStrength; + float side = rt * flPushStrength; + + //Msg( "fwd: %f - rt: %f - forward: %f - side: %f\n", fwd, rt, forward, side ); + + pCmd->forwardmove += forward; + pCmd->sidemove += side; + + // Clamp the move to within legal limits, preserving direction. This is a little + // complicated because we have different limits for forward, back, and side + + //Msg( "PRECLAMP: forwardmove=%f, sidemove=%f\n", pCmd->forwardmove, pCmd->sidemove ); + + float flForwardScale = 1.0f; + if ( pCmd->forwardmove > fabs( cl_forwardspeed.GetFloat() ) ) + { + flForwardScale = fabs( cl_forwardspeed.GetFloat() ) / pCmd->forwardmove; + } + else if ( pCmd->forwardmove < -fabs( cl_backspeed.GetFloat() ) ) + { + flForwardScale = fabs( cl_backspeed.GetFloat() ) / fabs( pCmd->forwardmove ); + } + + float flSideScale = 1.0f; + if ( fabs( pCmd->sidemove ) > fabs( cl_sidespeed.GetFloat() ) ) + { + flSideScale = fabs( cl_sidespeed.GetFloat() ) / fabs( pCmd->sidemove ); + } + + float flScale = MIN( flForwardScale, flSideScale ); + pCmd->forwardmove *= flScale; + pCmd->sidemove *= flScale; + + //Msg( "Pforwardmove=%f, sidemove=%f\n", pCmd->forwardmove, pCmd->sidemove ); +} + + +//----------------------------------------------------------------------------- +// Purpose: Returns whether this player is the nemesis of the local player +//----------------------------------------------------------------------------- +bool C_DODPlayer::IsNemesisOfLocalPlayer() +{ + C_DODPlayer *pLocalPlayer = C_DODPlayer::GetLocalDODPlayer(); + if ( pLocalPlayer ) + { + // return whether this player is dominating the local player + return m_Shared.IsPlayerDominated( pLocalPlayer->entindex() ); + } + return false; +} + +//----------------------------------------------------------------------------- +// Purpose: Returns whether we should show the nemesis icon for this player +//----------------------------------------------------------------------------- +bool C_DODPlayer::ShouldShowNemesisIcon() +{ + /* + // we should show the nemesis effect on this player if he is the nemesis of the local player, + // and is not dead, cloaked or disguised + if ( IsNemesisOfLocalPlayer() && g_DODPR && g_PR->IsConnected( entindex() ) ) + { + if ( IsAlive() ) + return true; + } + */ + return false; +} + +int C_DODPlayer::GetActiveAchievementAward( void ) +{ + int iAward = ACHIEVEMENT_AWARDS_NONE; + + int iClassBit = m_Shared.PlayerClass() + 1; + + if ( m_iAchievementAwardsMask & (1<<ACHIEVEMENT_AWARDS_ALL_PACK_1) ) + { + iAward = ACHIEVEMENT_AWARDS_ALL_PACK_1; + } + else if ( m_iAchievementAwardsMask & ( 1<<iClassBit ) ) + { + iAward = iClassBit; + } + + return iAward; +} + +IMaterial *C_DODPlayer::GetHeadIconMaterial( void ) +{ + const char *pszMaterial = ""; + + int iAchievementAward = GetActiveAchievementAward(); + + if ( iAchievementAward >= 0 && iAchievementAward < NUM_ACHIEVEMENT_AWARDS ) + { + switch ( GetTeamNumber() ) + { + case TEAM_ALLIES: + pszMaterial = g_pszAchievementAwardMaterials_Allies[iAchievementAward]; + break; + case TEAM_AXIS: + pszMaterial = g_pszAchievementAwardMaterials_Axis[iAchievementAward]; + break; + default: + break; + } + } + + IMaterial *pMaterial = NULL; + if ( pszMaterial ) + { + pMaterial = materials->FindMaterial( pszMaterial, TEXTURE_GROUP_VGUI ); + } + + // clear the old one if its different + if ( m_pHeadIconMaterial != pMaterial ) + { + if ( m_pHeadIconMaterial ) + { + m_pHeadIconMaterial->DecrementReferenceCount(); + } + + m_pHeadIconMaterial = pMaterial; + m_pHeadIconMaterial->IncrementReferenceCount(); + } + + return m_pHeadIconMaterial; +} diff --git a/game/client/dod/c_dod_player.h b/game/client/dod/c_dod_player.h new file mode 100644 index 0000000..3136b71 --- /dev/null +++ b/game/client/dod/c_dod_player.h @@ -0,0 +1,284 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef C_DOD_PLAYER_H +#define C_DOD_PLAYER_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "dod_playeranimstate.h" +#include "c_baseplayer.h" +#include "dod_shareddefs.h" +#include "baseparticleentity.h" +#include "dod_player_shared.h" +#include "beamdraw.h" +#include "hintsystem.h" + +#define PRONE_MAX_SWAY 3.0 +#define PRONE_SWAY_AMOUNT 4.0 +#define RECOIL_DURATION 0.1 + +class CViewAngleAnimation; + +class C_DODPlayer : public C_BasePlayer +{ +public: + friend class CDODPlayerShared; + + DECLARE_CLASS( C_DODPlayer, C_BasePlayer ); + DECLARE_CLIENTCLASS(); + DECLARE_PREDICTABLE(); + DECLARE_INTERPOLATION(); + + C_DODPlayer(); + ~C_DODPlayer(); + + static C_DODPlayer* GetLocalDODPlayer(); + + virtual const QAngle& GetRenderAngles(); + virtual void UpdateClientSideAnimation(); + virtual void ProcessMuzzleFlashEvent(); + virtual void PostDataUpdate( DataUpdateType_t updateType ); + + virtual bool CreateMove( float flInputSampleTime, CUserCmd *pCmd ); + + virtual void FireEvent( const Vector& origin, const QAngle& angles, int event, const char *options ); + + virtual void OnDataChanged( DataUpdateType_t type ); + virtual void NotifyShouldTransmit( ShouldTransmitState_t state ); + virtual void ClientThink( void ); + virtual void GetToolRecordingState( KeyValues *msg ); + + void LocalPlayerRespawn( void ); + + // Returns true if we're allowed to show the menus right now. + bool CanShowTeamMenu() const { return true; } + + bool CanShowClassMenu(); + + bool ShouldDraw( void ); + + virtual C_BaseAnimating * BecomeRagdollOnClient(); + virtual IRagdoll* GetRepresentativeRagdoll() const; + + virtual void ReceiveMessage( int classID, bf_read &msg ); + void PopHelmet( Vector vecDir, Vector vecForceOffset, int model ); + + // Get the ID target entity index. The ID target is the player that is behind our crosshairs, used to + // display the player's name. + int GetIDTarget() const + { + return m_iIDEntIndex; + } + + void UpdateIDTarget(); + + bool ShouldAutoReload( void ); + bool ShouldAutoRezoom( void ); + + void SetSprinting( bool bIsSprinting ); + bool IsSprinting( void ); + + void LowerWeapon( void ); + void RaiseWeapon( void ); + bool IsWeaponLowered( void ); + + virtual ShadowType_t ShadowCastType( void ); + virtual void GetRenderBounds( Vector& theMins, Vector& theMaxs ); + virtual void GetShadowRenderBounds( Vector &mins, Vector &maxs, ShadowType_t shadowType ); + virtual bool GetShadowCastDirection( Vector *pDirection, ShadowType_t shadowType ) const; + + virtual int DrawModel( int flags ); + virtual void Simulate(); + + virtual float GetMinFOV() const { return 20; } + virtual bool SetFOV( CBaseEntity *pRequester, int FOV, float zoomRate = 0.0f ); + + virtual void CreateLightEffects( void ) {} //no dimlight effects + + virtual Vector GetChaseCamViewOffset( CBaseEntity *target ); + virtual const QAngle& EyeAngles(); + virtual const Vector& GetRenderOrigin(); // return ragdoll origin if dead + + bool dod_IsInterpolationEnabled( void ) { return IsInterpolationEnabled(); } + + void CreateViewAngleAnimations( void ); + + void CheckGrenadeHint( Vector vecGrenadeOrigin ); + void CheckBombTargetPlantHint( void ); + void CheckBombTargetDefuseHint( void ); + + virtual void ComputeWorldSpaceSurroundingBox( Vector *pVecWorldMins, Vector *pVecWorldMaxs ); + + // Hints + virtual CHintSystem *Hints( void ) { return &m_Hints; } + + // Player avoidance + bool ShouldCollide( int collisionGroup, int contentsMask ) const; + void AvoidPlayers( CUserCmd *pCmd ); + + virtual bool ShouldReceiveProjectedTextures( int flags ) + { + return ( this != C_BasePlayer::GetLocalPlayer() ); + } + + bool IsNemesisOfLocalPlayer(); + bool ShouldShowNemesisIcon(); + + virtual void OnAchievementAchieved( int iAchievement ); + + int GetActiveAchievementAward( void ); + IMaterial *GetHeadIconMaterial( void ); + +protected: + virtual void CalcObserverView( Vector& eyeOrigin, QAngle& eyeAngles, float& fov ); + void CalcDODDeathCamView( Vector &eyeOrigin, QAngle& eyeAngles, float& fov ); + void CalcChaseCamView(Vector& eyeOrigin, QAngle& eyeAngles, float& fov); + virtual void CalcFreezeCamView( Vector& eyeOrigin, QAngle& eyeAngles, float& fov ); + + + // Called by shared code. +public: + + void DoAnimationEvent( PlayerAnimEvent_t event, int nData = 0 ); + + DODPlayerState State_Get() const; + + IDODPlayerAnimState *m_PlayerAnimState; + + + QAngle m_angEyeAngles; + CInterpolatedVar< QAngle > m_iv_angEyeAngles; + + void FireBullets( const FireBulletsInfo_t &info ); + bool CanAttack( void ); + + void SetBazookaDeployed( bool bDeployed ) {} + + // the control point index the player is near + int GetCPIndex( void ) { return m_Shared.GetCPIndex(); } + +//Implemented in shared code +public: + virtual void SharedSpawn(); + + void CheckProneMoveSound( int groundspeed, bool onground ); + virtual void UpdateStepSound( surfacedata_t *psurface, const Vector &vecOrigin, const Vector &vecVelocity ); + virtual void PlayStepSound( Vector &vecOrigin, surfacedata_t *psurface, float fvol, bool force ); + + virtual const Vector GetPlayerMins( void ) const; // uses local player + virtual const Vector GetPlayerMaxs( void ) const; // uses local player + + // Returns true if the player is allowed to move. + bool CanMove() const; + float GetStamina( void ) const; + void SetStamina( float flStamina ); + + virtual void SetAnimation( PLAYER_ANIM playerAnim ); + + CDODPlayerShared m_Shared; + + float m_flRecoilTimeRemaining; + float m_flPitchRecoilAccumulator; + float m_flYawRecoilAccumulator; + + void GetWeaponRecoilAmount( int weaponId, float &flPitchRecoil, float &flYawRecoil ); + void DoRecoil( int iWpnID, float flWpnRecoil ); + void SetRecoilAmount( float flPitchRecoil, float flYawRecoil ); + void GetRecoilToAddThisFrame( float &flPitchRecoil, float &flYawRecoil ); + + EHANDLE m_hRagdoll; + + CWeaponDODBase* GetActiveDODWeapon() const; + + Activity TranslateActivity( Activity baseAct, bool *pRequired = NULL ); + + Vector m_lastStandingPos; // used by the gamemovement code for finding ladders + + // for stun effect + float m_flStunEffectTime; + float m_flStunAlpha; + CNetworkVar( float, m_flStunMaxAlpha ); + CNetworkVar( float, m_flStunDuration ); + + float GetDeathTime( void ) { return m_flDeathTime; } + + // How long the progress bar takes to get to the end. If this is 0, then the progress bar + // should not be drawn. + CNetworkVar( int, m_iProgressBarDuration ); + + // When the progress bar should start. + CNetworkVar( float, m_flProgressBarStartTime ); + + float m_flLastRespawnTime; + +private: + C_DODPlayer( const C_DODPlayer & ); + + CNetworkVar( DODPlayerState, m_iPlayerState ); + + CNetworkVar( float, m_flStamina ); + + float m_flProneViewOffset; + bool m_bProneSwayingRight; + Vector m_vecRagdollVelocity; + + // ID Target + int m_iIDEntIndex; + + bool m_bWeaponLowered; // should our weapon be lowered right now + + CNetworkVar( bool, m_bSpawnInterpCounter ); + bool m_bSpawnInterpCounterCache; + + CHintSystem m_Hints; + + void ReleaseFlashlight( void ); + Beam_t *m_pFlashlightBeam; + + float m_flMinNextStepSoundTime; + + float m_fNextThinkPushAway; + + bool m_bPlayingProneMoveSound; + + void StaminaSoundThink( void ); + CSoundPatch *m_pStaminaSound; + bool m_bPlayingLowStaminaSound; + + // Cold Breath + bool CreateColdBreathEmitter( void ); + void DestroyColdBreathEmitter( void ); + void UpdateColdBreath( void ); + void EmitColdBreathParticles( void ); + + bool m_bColdBreathOn; + float m_flColdBreathTimeStart; + float m_flColdBreathTimeEnd; + CSmartPtr<CSimpleEmitter> m_hColdBreathEmitter; + PMaterialHandle m_hColdBreathMaterial; + int m_iHeadAttach; + + float m_flHideHeadIconUntilTime; + + virtual void CalculateIKLocks( float currentTime ); + + int m_iAchievementAwardsMask; + IMaterial *m_pHeadIconMaterial; +}; + +inline C_DODPlayer *ToDODPlayer( CBaseEntity *pEntity ) +{ + if ( !pEntity || !pEntity->IsPlayer() ) + return NULL; + + return dynamic_cast<C_DODPlayer*>( pEntity ); +} + + +#endif // C_DOD_PLAYER_H diff --git a/game/client/dod/c_dod_playerresource.cpp b/game/client/dod/c_dod_playerresource.cpp new file mode 100644 index 0000000..15c88da --- /dev/null +++ b/game/client/dod/c_dod_playerresource.cpp @@ -0,0 +1,53 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: CS's custom C_PlayerResource +// +// $NoKeywords: $ +//=============================================================================// +#include "cbase.h" +#include "c_dod_playerresource.h" +#include <shareddefs.h> +#include <dod_shareddefs.h> +#include "hud.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + + +IMPLEMENT_CLIENTCLASS_DT(C_DOD_PlayerResource, DT_DODPlayerResource, CDODPlayerResource) + RecvPropArray3( RECVINFO_ARRAY(m_iObjScore), RecvPropInt( RECVINFO(m_iObjScore[0]))), + RecvPropArray3( RECVINFO_ARRAY(m_iPlayerClass), RecvPropInt( RECVINFO(m_iPlayerClass[0]))), +END_RECV_TABLE() + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +C_DOD_PlayerResource::C_DOD_PlayerResource() +{ + m_Colors[TEAM_ALLIES] = COLOR_DOD_GREEN; + m_Colors[TEAM_AXIS] = COLOR_DOD_RED; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +C_DOD_PlayerResource::~C_DOD_PlayerResource() +{ +} + +int C_DOD_PlayerResource::GetScore( int iIndex ) +{ + if ( !IsConnected( iIndex ) ) + return 0; + + return m_iObjScore[iIndex]; +} + +int C_DOD_PlayerResource::GetPlayerClass( int iIndex ) +{ + if ( !IsConnected( iIndex ) ) + return PLAYERCLASS_UNDEFINED; + + return m_iPlayerClass[iIndex]; +} diff --git a/game/client/dod/c_dod_playerresource.h b/game/client/dod/c_dod_playerresource.h new file mode 100644 index 0000000..65b08ac --- /dev/null +++ b/game/client/dod/c_dod_playerresource.h @@ -0,0 +1,36 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: DOD's custom C_PlayerResource +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef C_DOD_PLAYERRESOURCE_H +#define C_DOD_PLAYERRESOURCE_H +#ifdef _WIN32 +#pragma once +#endif + +#include "dod_shareddefs.h" +#include "c_playerresource.h" + +class C_DOD_PlayerResource : public C_PlayerResource +{ + DECLARE_CLASS( C_DOD_PlayerResource, C_PlayerResource ); +public: + DECLARE_CLIENTCLASS(); + + C_DOD_PlayerResource(); + virtual ~C_DOD_PlayerResource(); + + int GetScore( int iIndex ); + int GetPlayerClass( int iIndex ); + +protected: + + int m_iObjScore[MAX_PLAYERS+1]; + int m_iPlayerClass[MAX_PLAYERS+1]; +}; + + +#endif // C_DOD_PLAYERRESOURCE_H diff --git a/game/client/dod/c_dod_smokegrenade.cpp b/game/client/dod/c_dod_smokegrenade.cpp new file mode 100644 index 0000000..8af4998 --- /dev/null +++ b/game/client/dod/c_dod_smokegrenade.cpp @@ -0,0 +1,141 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#include "cbase.h" +#include "c_dod_smokegrenade.h" +#include "dod_shareddefs.h" +#include "tier1/KeyValues.h" +#include "toolframework_client.h" +#include "fx.h" +#include "view.h" +#include "smoke_fog_overlay.h" + +IMPLEMENT_NETWORKCLASS_ALIASED( DODSmokeGrenade, DT_DODSmokeGrenade ) + +BEGIN_RECV_TABLE(C_DODSmokeGrenade, DT_DODSmokeGrenade ) + RecvPropTime(RECVINFO(m_flSmokeSpawnTime)), +END_NETWORK_TABLE() + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +C_DODSmokeGrenade::C_DODSmokeGrenade( void ) +{ +} + +const char *C_DODSmokeGrenade::GetOverviewSpriteName( void ) +{ + const char *pszSprite = ""; + + switch( GetTeamNumber() ) + { + case TEAM_ALLIES: + pszSprite = "sprites/minimap_icons/minimap_smoke_us"; + break; + case TEAM_AXIS: + pszSprite = "sprites/minimap_icons/minimap_smoke_ger"; + break; + default: + break; + } + + return pszSprite; +} + +void C_DODSmokeGrenade::OnDataChanged( DataUpdateType_t updateType ) +{ + BaseClass::OnDataChanged(updateType); + + if(updateType == DATA_UPDATE_CREATED ) + { + SetNextClientThink( CLIENT_THINK_ALWAYS ); + } +} + +static inline float& EngineGetSmokeFogOverlayAlpha() +{ + return g_SmokeFogOverlayAlpha; +} + +#define SMOKE_CLOUD_RADIUS 330 +#define EXPAND_TIME 2.0 + +float C_DODSmokeGrenade::CalcSmokeCloudRadius( void ) +{ + float flLifetime = gpGlobals->curtime - m_flSmokeSpawnTime; + if( flLifetime > EXPAND_TIME ) + flLifetime = EXPAND_TIME; + + float flRadius = SMOKE_CLOUD_RADIUS * (float)sin(flLifetime * M_PI * 0.5 / EXPAND_TIME); + + return flRadius; +} + +float C_DODSmokeGrenade::CalcSmokeCloudAlpha( void ) +{ + float flLifetime = gpGlobals->curtime - m_flSmokeSpawnTime; + //if( flLifetime > SMOKESPHERE_EXPAND_TIME ) + // flLifetime = SMOKESPHERE_EXPAND_TIME; + + const float flFadedInTime = 3; + const float flStartFadingOutTime = 9; + const float flEndFadingOutTime = 12; + + float flFadeAlpha; + + // Update our fade alpha. + if( flLifetime < flFadedInTime ) + { + float fadePercent = flLifetime / flFadedInTime; + flFadeAlpha = SimpleSpline( fadePercent ); + } + else if ( flLifetime > flEndFadingOutTime ) + { + flFadeAlpha = 0.0; + } + else if ( flLifetime > flStartFadingOutTime ) + { + float fadePercent = ( flLifetime - flStartFadingOutTime ) / ( flEndFadingOutTime - flStartFadingOutTime ); + flFadeAlpha = SimpleSpline( 1.0 - fadePercent ); + } + else + { + flFadeAlpha = 1.0; + } + + return flFadeAlpha; +} + +// Add our influence to the global smoke fog alpha. +void C_DODSmokeGrenade::ClientThink( void ) +{ + if ( m_flSmokeSpawnTime > 0 ) + { + float flExpandRadius = CalcSmokeCloudRadius(); + + Vector vecSmokePos = GetAbsOrigin(); + vecSmokePos.z += 32; + + float testDist = (MainViewOrigin() - vecSmokePos).Length(); + + // The center of the smoke cloud that always gives full fog overlay + float flCoreDistance = flExpandRadius * 0.3; + + if( testDist < flExpandRadius ) + { + float flFadeAlpha = CalcSmokeCloudAlpha(); + + if( testDist < flCoreDistance ) + { + EngineGetSmokeFogOverlayAlpha() += flFadeAlpha; + } + else + { + EngineGetSmokeFogOverlayAlpha() += (1 - ( testDist - flCoreDistance ) / ( flExpandRadius - flCoreDistance ) ) * flFadeAlpha; + } + } + } +}
\ No newline at end of file diff --git a/game/client/dod/c_dod_smokegrenade.h b/game/client/dod/c_dod_smokegrenade.h new file mode 100644 index 0000000..519043b --- /dev/null +++ b/game/client/dod/c_dod_smokegrenade.h @@ -0,0 +1,38 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#ifndef C_DOD_SMOKEGRENADE_H +#define C_DOD_SMOKEGRENADE_H +#ifdef _WIN32 +#pragma once +#endif + +#include "c_dod_basegrenade.h" + +class C_DODSmokeGrenade : public C_DODBaseGrenade +{ +public: + DECLARE_CLASS( C_DODSmokeGrenade, C_DODBaseGrenade ); + DECLARE_NETWORKCLASS(); + + C_DODSmokeGrenade(); + + virtual const char *GetOverviewSpriteName( void ); + + virtual const char *GetParticleTrailName( void ) { return NULL; } + + virtual void OnDataChanged( DataUpdateType_t updateType ); + virtual void ClientThink( void ); + + float CalcSmokeCloudRadius( void ); + float CalcSmokeCloudAlpha( void ); + +private: + float m_flSmokeSpawnTime; // time the smoke starts emitting +}; + + +#endif // C_DOD_SMOKEGRENADE_H diff --git a/game/client/dod/c_dod_team.cpp b/game/client/dod/c_dod_team.cpp new file mode 100644 index 0000000..2ea296f --- /dev/null +++ b/game/client/dod/c_dod_team.cpp @@ -0,0 +1,143 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Client side C_DODTeam class +// +// $NoKeywords: $ +//=============================================================================// +#include "cbase.h" +#include "engine/IEngineSound.h" +#include "hud.h" +#include "recvproxy.h" +#include "c_dod_player.h" +#include "c_dod_team.h" +#include "dod_shareddefs.h" +#include "c_dod_playerresource.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + + +IMPLEMENT_CLIENTCLASS_DT(C_DODTeam, DT_DODTeam, CDODTeam) +END_RECV_TABLE() + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +C_DODTeam::C_DODTeam() +{ +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +C_DODTeam::~C_DODTeam() +{ +} + +void C_DODTeam::AddPlayerClass( const char *szClassName ) +{ + PLAYERCLASS_FILE_INFO_HANDLE hPlayerClassInfo; + + if ( ReadPlayerClassDataFromFileForSlot( filesystem, szClassName, &hPlayerClassInfo, GetEncryptionKey() ) ) + { + m_hPlayerClassInfoHandles.AddToTail( hPlayerClassInfo ); + } + else + { + Assert( !"missing playerclass script file" ); + Msg( "Missing playerclass script file for class: %s\n", szClassName ); + } +} + +const CDODPlayerClassInfo &C_DODTeam::GetPlayerClassInfo( int iPlayerClass ) const +{ + Assert( iPlayerClass >= 0 && iPlayerClass < m_hPlayerClassInfoHandles.Count() ); + + const FilePlayerClassInfo_t *pPlayerClassInfo = GetFilePlayerClassInfoFromHandle( m_hPlayerClassInfoHandles[iPlayerClass] ); + const CDODPlayerClassInfo *pDODInfo; + +#ifdef _DEBUG + pDODInfo = dynamic_cast< const CDODPlayerClassInfo* >( pPlayerClassInfo ); + Assert( pDODInfo ); +#else + pDODInfo = static_cast< const CDODPlayerClassInfo* >( pPlayerClassInfo ); +#endif + + return *pDODInfo; +} + +bool C_DODTeam::IsClassOnTeam( const char *pszClassName, int &iClassNum ) const +{ + iClassNum = PLAYERCLASS_UNDEFINED; + + // Random is always on every team + if( FStrEq( pszClassName, "cls_random" ) ) + { + iClassNum = PLAYERCLASS_RANDOM; + return true; + } + + for( int i=0;i<m_hPlayerClassInfoHandles.Count(); i++ ) + { + FilePlayerClassInfo_t *pPlayerClassInfo = GetFilePlayerClassInfoFromHandle( m_hPlayerClassInfoHandles[i] ); + + if( stricmp( pszClassName, pPlayerClassInfo->m_szSelectCmd ) == 0 ) + { + iClassNum = i; + return true; + } + } + + return false; +} + +bool C_DODTeam::IsClassOnTeam( int iClassNum ) const +{ + return ( iClassNum >= 0 && iClassNum < m_hPlayerClassInfoHandles.Count() ); +} + +int C_DODTeam::CountPlayersOfThisClass( int iPlayerClass ) +{ + int count = 0; + + C_DOD_PlayerResource *dod_PR = dynamic_cast<C_DOD_PlayerResource *>(g_PR); + + Assert( dod_PR ); + + for ( int i=0;i<Get_Number_Players();i++ ) + { + if ( iPlayerClass == dod_PR->GetPlayerClass(m_aPlayers[i]) ) + count++; + } + + return count; +} + +IMPLEMENT_CLIENTCLASS_DT(C_DODTeam_Allies, DT_DODTeam_Allies, CDODTeam_Allies) +END_RECV_TABLE() + +C_DODTeam_Allies::C_DODTeam_Allies() +{ + //parse our classes + int i = 0; + while( pszTeamAlliesClasses[i] != NULL ) + { + AddPlayerClass( pszTeamAlliesClasses[i] ); + i++; + } +} + + +IMPLEMENT_CLIENTCLASS_DT(C_DODTeam_Axis, DT_DODTeam_Axis, CDODTeam_Axis) +END_RECV_TABLE() + +C_DODTeam_Axis::C_DODTeam_Axis() +{ + //parse our classes + int i = 0; + while( pszTeamAxisClasses[i] != NULL ) + { + AddPlayerClass( pszTeamAxisClasses[i] ); + i++; + } +}
\ No newline at end of file diff --git a/game/client/dod/c_dod_team.h b/game/client/dod/c_dod_team.h new file mode 100644 index 0000000..8ef182a --- /dev/null +++ b/game/client/dod/c_dod_team.h @@ -0,0 +1,70 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Client side CTFTeam class +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef C_DOD_TEAM_H +#define C_DOD_TEAM_H +#ifdef _WIN32 +#pragma once +#endif + +#include "c_team.h" +#include "shareddefs.h" +#include "dod_playerclass_info_parse.h" +#include "dod_shareddefs.h" + +class C_BaseEntity; +class C_BaseObject; +class CBaseTechnology; + +//----------------------------------------------------------------------------- +// Purpose: TF's Team manager +//----------------------------------------------------------------------------- +class C_DODTeam : public C_Team +{ + DECLARE_CLASS( C_DODTeam, C_Team ); +public: + DECLARE_CLIENTCLASS(); + + C_DODTeam(); + virtual ~C_DODTeam(); + + CDODPlayerClassInfo const &GetPlayerClassInfo( int iPlayerClass ) const; + const unsigned char *GetEncryptionKey( void ) { return g_pGameRules->GetEncryptionKey(); } + + virtual void AddPlayerClass( const char *pszClassName ); + + bool IsClassOnTeam( const char *pszClassName, int &iClassNum ) const; + bool IsClassOnTeam( int iClassNum ) const; + int GetNumPlayerClasses( void ) { return m_hPlayerClassInfoHandles.Count(); } + + int CountPlayersOfThisClass( int iPlayerClass ); + +private: + CUtlVector < PLAYERCLASS_FILE_INFO_HANDLE > m_hPlayerClassInfoHandles; +}; + +class C_DODTeam_Allies : public C_DODTeam +{ + DECLARE_CLASS( C_DODTeam_Allies, C_DODTeam ); +public: + DECLARE_CLIENTCLASS(); + + C_DODTeam_Allies(); + virtual ~C_DODTeam_Allies() {} +}; + +class C_DODTeam_Axis : public C_DODTeam +{ + DECLARE_CLASS( C_DODTeam_Axis, C_DODTeam ); +public: + DECLARE_CLIENTCLASS(); + + C_DODTeam_Axis(); + virtual ~C_DODTeam_Axis() {} +}; + +#endif // C_DOD_TEAM_H diff --git a/game/client/dod/c_grenadetrail.cpp b/game/client/dod/c_grenadetrail.cpp new file mode 100644 index 0000000..36be47d --- /dev/null +++ b/game/client/dod/c_grenadetrail.cpp @@ -0,0 +1,301 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// +#include "cbase.h" +#include "c_grenadetrail.h" +#include "fx.h" +//#include "engine/ivdebugoverlay.h" +//#include "engine/IEngineSound.h" +//#include "c_te_effect_dispatch.h" +//#include "glow_overlay.h" +//#include "fx_explosion.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +class CSmokeParticle : public CSimpleEmitter +{ +public: + + CSmokeParticle( const char *pDebugName ) : CSimpleEmitter( pDebugName ) {} + + //Create + static CSmokeParticle *Create( const char *pDebugName ) + { + return new CSmokeParticle( pDebugName ); + } + + //Alpha + virtual float UpdateAlpha( const SimpleParticle *pParticle ) + { + return ( ((float)pParticle->m_uchStartAlpha/255.0f) * sin( M_PI * (pParticle->m_flLifetime / pParticle->m_flDieTime) ) ); + } + + //Color + virtual Vector UpdateColor( const SimpleParticle *pParticle ) + { + Vector color; + + float tLifetime = pParticle->m_flLifetime / pParticle->m_flDieTime; + float ramp = 1.0f - tLifetime; + + Vector endcolor(75, 75, 75); + + color[0] = ( (float) pParticle->m_uchColor[0] * ramp ) / 255.0f + ( 1-ramp) * endcolor[0]; + color[1] = ( (float) pParticle->m_uchColor[1] * ramp ) / 255.0f + ( 1-ramp) * endcolor[1]; + color[2] = ( (float) pParticle->m_uchColor[2] * ramp ) / 255.0f + ( 1-ramp) * endcolor[2]; + + return color; + } + + //Roll + virtual float UpdateRoll( SimpleParticle *pParticle, float timeDelta ) + { + pParticle->m_flRoll += pParticle->m_flRollDelta * timeDelta; + + pParticle->m_flRollDelta += pParticle->m_flRollDelta * ( timeDelta * -8.0f ); + + //Cap the minimum roll + if ( fabs( pParticle->m_flRollDelta ) < 0.5f ) + { + pParticle->m_flRollDelta = ( pParticle->m_flRollDelta > 0.0f ) ? 0.5f : -0.5f; + } + + return pParticle->m_flRoll; + } + +private: + CSmokeParticle( const CSmokeParticle & ); +}; + +// Datatable.. this can have all the smoketrail parameters when we need it to. +IMPLEMENT_CLIENTCLASS_DT(C_GrenadeTrail, DT_GrenadeTrail, CGrenadeTrail) + RecvPropFloat(RECVINFO(m_SpawnRate)), + RecvPropFloat(RECVINFO(m_ParticleLifetime)), + RecvPropFloat(RECVINFO(m_StopEmitTime)), + RecvPropInt(RECVINFO(m_bEmit)), + RecvPropInt(RECVINFO(m_nAttachment)), +END_RECV_TABLE() + +// ------------------------------------------------------------------------- // +// ParticleMovieExplosion +// ------------------------------------------------------------------------- // +C_GrenadeTrail::C_GrenadeTrail() +{ + m_MaterialHandle[0] = NULL; + m_MaterialHandle[1] = NULL; + + // things that we will change + m_SpawnRate = 10; + m_ParticleLifetime = 5; + m_bEmit = true; + m_nAttachment = -1; + m_StopEmitTime = 0; // No end time + + // invariants + m_ParticleSpawn.Init(10); + m_StartColor.Init(0.65, 0.65, 0.65); + m_MinSpeed = 2; + m_MaxSpeed = 6; + m_MinDirectedSpeed = m_MaxDirectedSpeed = 0; + m_StartSize = 2; + m_EndSize = 6; + m_SpawnRadius = 2; + m_VelocityOffset.Init(); + m_Opacity = 0.3f; + + m_pSmokeEmitter = NULL; + m_pParticleMgr = NULL; +} + +C_GrenadeTrail::~C_GrenadeTrail() +{ + if ( m_pParticleMgr ) + { + m_pParticleMgr->RemoveEffect( &m_ParticleEffect ); + } +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_GrenadeTrail::GetAimEntOrigin( IClientEntity *pAttachedTo, Vector *pAbsOrigin, QAngle *pAbsAngles ) +{ + C_BaseEntity *pEnt = pAttachedTo->GetBaseEntity(); + if (pEnt && (m_nAttachment > 0)) + { + pEnt->GetAttachment( m_nAttachment, *pAbsOrigin, *pAbsAngles ); + } + else + { + BaseClass::GetAimEntOrigin( pAttachedTo, pAbsOrigin, pAbsAngles ); + } +} + + +//----------------------------------------------------------------------------- +// Purpose: +// Input : bEmit - +//----------------------------------------------------------------------------- +void C_GrenadeTrail::SetEmit(bool bEmit) +{ + m_bEmit = bEmit; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : rate - +//----------------------------------------------------------------------------- +void C_GrenadeTrail::SetSpawnRate(float rate) +{ + m_SpawnRate = rate; + m_ParticleSpawn.Init(rate); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : bnewentity - +//----------------------------------------------------------------------------- +void C_GrenadeTrail::OnDataChanged(DataUpdateType_t updateType) +{ + C_BaseEntity::OnDataChanged(updateType); + + if ( updateType == DATA_UPDATE_CREATED ) + { + Start( ParticleMgr(), NULL ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *pParticleMgr - +// *pArgs - +//----------------------------------------------------------------------------- +void C_GrenadeTrail::Start( CParticleMgr *pParticleMgr, IPrototypeArgAccess *pArgs ) +{ + if(!pParticleMgr->AddEffect( &m_ParticleEffect, this )) + return; + + m_pParticleMgr = pParticleMgr; + m_pSmokeEmitter = CSmokeParticle::Create("smokeTrail"); + + if ( !m_pSmokeEmitter ) + { + Assert( false ); + return; + } + + m_pSmokeEmitter->SetSortOrigin( GetAbsOrigin() ); + m_pSmokeEmitter->SetNearClip( 64.0f, 128.0f ); + + m_MaterialHandle[0] = g_Mat_DustPuff[0]; + m_MaterialHandle[1] = g_Mat_DustPuff[1]; + + m_ParticleSpawn.Init( m_SpawnRate ); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : fTimeDelta - +//----------------------------------------------------------------------------- +void C_GrenadeTrail::Update( float fTimeDelta ) +{ + if ( !m_pSmokeEmitter ) + return; + + // Grenades thrown out of the PVS should not draw particles at the world origin + if ( IsDormant() ) + return; + + Vector offsetColor; + + // Add new particles + if ( !m_bEmit ) + return; + + if ( ( m_StopEmitTime != 0 ) && ( m_StopEmitTime <= gpGlobals->curtime ) ) + return; + + float tempDelta = fTimeDelta; + + SimpleParticle *pParticle; + Vector offset; + + Vector vecOrigin; + VectorMA( GetAbsOrigin(), -fTimeDelta, GetAbsVelocity(), vecOrigin ); + + Vector vecForward; + GetVectors( &vecForward, NULL, NULL ); + + while( m_ParticleSpawn.NextEvent( tempDelta ) ) + { + float fldt = fTimeDelta - tempDelta; + + offset.Random( -m_SpawnRadius, m_SpawnRadius ); + offset += vecOrigin; + VectorMA( offset, fldt, GetAbsVelocity(), offset ); + + pParticle = (SimpleParticle *) m_pSmokeEmitter->AddParticle( sizeof( SimpleParticle ), m_MaterialHandle[random->RandomInt(0,1)], offset ); + + if ( pParticle == NULL ) + continue; + + pParticle->m_flLifetime = 0.0f; + pParticle->m_flDieTime = m_ParticleLifetime; + + pParticle->m_iFlags = 0; // no wind! + + pParticle->m_vecVelocity.Random( -1.0f, 1.0f ); + pParticle->m_vecVelocity *= random->RandomFloat( m_MinSpeed, m_MaxSpeed ); + + float flDirectedVel = random->RandomFloat( m_MinDirectedSpeed, m_MaxDirectedSpeed ); + VectorMA( pParticle->m_vecVelocity, flDirectedVel, vecForward, pParticle->m_vecVelocity ); + + pParticle->m_vecVelocity[2] += 15; + + offsetColor = m_StartColor; + float flMaxVal = MAX( m_StartColor[0], m_StartColor[1] ); + if ( flMaxVal < m_StartColor[2] ) + { + flMaxVal = m_StartColor[2]; + } + offsetColor /= flMaxVal; + + offsetColor *= random->RandomFloat( -0.2f, 0.2f ); + offsetColor += m_StartColor; + + offsetColor[0] = clamp( offsetColor[0], 0.0f, 1.0f ); + offsetColor[1] = clamp( offsetColor[1], 0.0f, 1.0f ); + offsetColor[2] = clamp( offsetColor[2], 0.0f, 1.0f ); + + pParticle->m_uchColor[0] = offsetColor[0]*255.0f; + pParticle->m_uchColor[1] = offsetColor[1]*255.0f; + pParticle->m_uchColor[2] = offsetColor[2]*255.0f; + + pParticle->m_uchStartSize = m_StartSize; + pParticle->m_uchEndSize = m_EndSize; + + float alpha = random->RandomFloat( m_Opacity*0.75f, m_Opacity*1.25f ); + alpha = clamp( alpha, 0.0f, 1.0f ); + + pParticle->m_uchStartAlpha = alpha * 255; + pParticle->m_uchEndAlpha = 0; + + pParticle->m_flRoll = random->RandomInt( 0, 360 ); + pParticle->m_flRollDelta = random->RandomFloat( -1.0f, 1.0f ); + } +} + +void C_GrenadeTrail::RenderParticles( CParticleRenderIterator *pIterator ) +{ +} + + +void C_GrenadeTrail::SimulateParticles( CParticleSimulateIterator *pIterator ) +{ +} diff --git a/game/client/dod/c_grenadetrail.h b/game/client/dod/c_grenadetrail.h new file mode 100644 index 0000000..f0b37da --- /dev/null +++ b/game/client/dod/c_grenadetrail.h @@ -0,0 +1,100 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// +// This defines the client-side SmokeTrail entity. It can also be used without +// an entity, in which case you must pass calls to it and set its position each frame. + +#ifndef PARTICLE_SMOKETRAIL_H +#define PARTICLE_SMOKETRAIL_H + +#include "particlemgr.h" +#include "particle_prototype.h" +#include "particle_util.h" +#include "particles_simple.h" +#include "c_baseentity.h" +#include "baseparticleentity.h" + +#include "fx_trail.h" + +// +// Smoke Trail +// + +class C_GrenadeTrail : public C_BaseParticleEntity, public IPrototypeAppEffect +{ +public: + DECLARE_CLASS( C_GrenadeTrail, C_BaseParticleEntity ); + DECLARE_CLIENTCLASS(); + + C_GrenadeTrail(); + virtual ~C_GrenadeTrail(); + +public: + + //For attachments + void GetAimEntOrigin( IClientEntity *pAttachedTo, Vector *pAbsOrigin, QAngle *pAbsAngles ); + + // Enable/disable emission. + void SetEmit(bool bEmit); + + // Change the spawn rate. + void SetSpawnRate(float rate); + +// C_BaseEntity. +public: + virtual void OnDataChanged(DataUpdateType_t updateType); + +// IPrototypeAppEffect. +public: + virtual void Start(CParticleMgr *pParticleMgr, IPrototypeArgAccess *pArgs); + +// IParticleEffect. +public: + virtual void Update(float fTimeDelta); + virtual void RenderParticles( CParticleRenderIterator *pIterator ); + virtual void SimulateParticles( CParticleSimulateIterator *pIterator ); + + +public: + // Effect parameters. These will assume default values but you can change them. + float m_SpawnRate; // How many particles per second. + + Vector m_StartColor; // Fade between these colors. + Vector m_EndColor; + float m_Opacity; + + float m_ParticleLifetime; // How long do the particles live? + float m_StopEmitTime; // When do I stop emitting particles? (-1 = never) + + float m_MinSpeed; // Speed range. + float m_MaxSpeed; + + float m_MinDirectedSpeed; // Directed speed range. + float m_MaxDirectedSpeed; + + float m_StartSize; // Size ramp. + float m_EndSize; + + float m_SpawnRadius; + + Vector m_VelocityOffset; // Emit the particles in a certain direction. + + bool m_bEmit; // Keep emitting particles? + + int m_nAttachment; + +private: + PMaterialHandle m_MaterialHandle[2]; + TimedEvent m_ParticleSpawn; + + CParticleMgr *m_pParticleMgr; + CSmartPtr<CSimpleEmitter> m_pSmokeEmitter; + + C_GrenadeTrail( const C_GrenadeTrail & ); +}; + +#endif //PARTICLE_SMOKETRAIL_H
\ No newline at end of file diff --git a/game/client/dod/c_te_firebullets.cpp b/game/client/dod/c_te_firebullets.cpp new file mode 100644 index 0000000..19d4b10 --- /dev/null +++ b/game/client/dod/c_te_firebullets.cpp @@ -0,0 +1,63 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#include "cbase.h" +#include "fx_dod_shared.h" +#include "c_basetempentity.h" +#include <cliententitylist.h> + + +class C_TEFireBullets : public C_BaseTempEntity +{ +public: + DECLARE_CLASS( C_TEFireBullets, C_BaseTempEntity ); + DECLARE_CLIENTCLASS(); + + virtual void PostDataUpdate( DataUpdateType_t updateType ); + +public: + int m_iPlayer; + Vector m_vecOrigin; + QAngle m_vecAngles; + int m_iWeaponID; + int m_iMode; + int m_iSeed; + float m_flSpread; +}; + + +void C_TEFireBullets::PostDataUpdate( DataUpdateType_t updateType ) +{ + // Create the effect. + + m_vecAngles.z = 0; + + FX_FireBullets( + m_iPlayer+1, + m_vecOrigin, + m_vecAngles, + m_iWeaponID, + m_iMode, + m_iSeed, + m_flSpread ); +} + + +IMPLEMENT_CLIENTCLASS_EVENT( C_TEFireBullets, DT_TEFireBullets, CTEFireBullets ); + + +BEGIN_RECV_TABLE_NOBASE(C_TEFireBullets, DT_TEFireBullets) + RecvPropVector( RECVINFO( m_vecOrigin ) ), + RecvPropFloat( RECVINFO( m_vecAngles[0] ) ), + RecvPropFloat( RECVINFO( m_vecAngles[1] ) ), + RecvPropInt( RECVINFO( m_iWeaponID ) ), + RecvPropInt( RECVINFO( m_iMode ) ), + RecvPropInt( RECVINFO( m_iSeed ) ), + RecvPropInt( RECVINFO( m_iPlayer ) ), + RecvPropFloat( RECVINFO( m_flSpread ) ), +END_RECV_TABLE() + + diff --git a/game/client/dod/clientmode_dod.cpp b/game/client/dod/clientmode_dod.cpp new file mode 100644 index 0000000..abdcc99 --- /dev/null +++ b/game/client/dod/clientmode_dod.cpp @@ -0,0 +1,556 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//===========================================================================// +#include "cbase.h" +#include "hud.h" +#include "clientmode_dod.h" +#include "cdll_client_int.h" +#include "iinput.h" +#include "vgui/ISurface.h" +#include "vgui/IPanel.h" +#include <vgui_controls/AnimationController.h> +#include "ivmodemanager.h" +#include "buymenu.h" +#include "filesystem.h" +#include "vgui/IVGui.h" +#include "hud_basechat.h" +#include "view_shared.h" +#include "view.h" +#include "ivrenderview.h" +#include "model_types.h" +#include "iefx.h" +#include "dlight.h" +#include <imapoverview.h> +#include "c_playerresource.h" +#include <KeyValues.h> +#include "text_message.h" +#include "panelmetaclassmgr.h" +#include "dod_shareddefs.h" +#include "c_dod_player.h" +#include "physpropclientside.h" +#include "engine/IEngineSound.h" +#include "bitbuf.h" +#include "usermessages.h" +#include "prediction.h" +#include "vgui/ILocalize.h" +#include "dod_hud_freezepanel.h" +#include "dod_hud_chat.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +class CHudChat; + +ConVar default_fov( "default_fov", "90", FCVAR_CHEAT ); + +ConVar dod_playwinmusic( "dod_playwinmusic", "1", FCVAR_ARCHIVE ); + +IClientMode *g_pClientMode = NULL; + +void MsgFunc_KillCam(bf_read &msg) +{ + C_DODPlayer *pPlayer = C_DODPlayer::GetLocalDODPlayer(); + + if ( !pPlayer ) + return; + + int newMode = msg.ReadByte(); + + if ( newMode != g_nKillCamMode ) + { +#if !defined( NO_ENTITY_PREDICTION ) + if ( g_nKillCamMode == OBS_MODE_NONE ) + { + // kill cam is switch on, turn off prediction + g_bForceCLPredictOff = true; + } + else if ( newMode == OBS_MODE_NONE ) + { + // kill cam is switched off, restore old prediction setting is we switch back to normal mode + g_bForceCLPredictOff = false; + } +#endif + g_nKillCamMode = newMode; + } + + g_nKillCamTarget1 = msg.ReadByte(); + g_nKillCamTarget2 = msg.ReadByte(); +} + +// --------------------------------------------------------------------------------- // +// CDODModeManager. +// --------------------------------------------------------------------------------- // + +class CDODModeManager : public IVModeManager +{ +public: + virtual void Init(); + virtual void SwitchMode( bool commander, bool force ) {} + virtual void LevelInit( const char *newmap ); + virtual void LevelShutdown( void ); + virtual void ActivateMouse( bool isactive ) {} +}; + +static CDODModeManager g_ModeManager; +IVModeManager *modemanager = ( IVModeManager * )&g_ModeManager; + +// --------------------------------------------------------------------------------- // +// CDODModeManager implementation. +// --------------------------------------------------------------------------------- // + +#define SCREEN_FILE "scripts/vgui_screens.txt" + +void CDODModeManager::Init() +{ + g_pClientMode = GetClientModeNormal(); + + PanelMetaClassMgr()->LoadMetaClassDefinitionFile( SCREEN_FILE ); +} + +void CDODModeManager::LevelInit( const char *newmap ) +{ + g_pClientMode->LevelInit( newmap ); + +#if !defined( NO_ENTITY_PREDICTION ) + if ( g_nKillCamMode > OBS_MODE_NONE ) + { + g_bForceCLPredictOff = false; + } +#endif + + g_nKillCamMode = OBS_MODE_NONE; + g_nKillCamTarget1 = 0; + g_nKillCamTarget2 = 0; +} + +void CDODModeManager::LevelShutdown( void ) +{ + g_pClientMode->LevelShutdown(); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +ClientModeDODNormal::ClientModeDODNormal() +{ + m_pFreezePanel = NULL; +} + +void ClientModeDODNormal::Init() +{ + BaseClass::Init(); + + ListenForGameEvent( "dod_round_start" ); + ListenForGameEvent( "dod_broadcast_audio" ); + ListenForGameEvent( "player_team" ); + ListenForGameEvent( "dod_bomb_planted" ); + ListenForGameEvent( "dod_bomb_defused" ); + ListenForGameEvent( "dod_timer_flash" ); + + usermessages->HookMessage( "KillCam", MsgFunc_KillCam ); + + m_szLastRadioSound[0] = '\0'; + + m_pFreezePanel = ( CDODFreezePanel * )GET_HUDELEMENT( CDODFreezePanel ); + Assert( m_pFreezePanel ); +} +void ClientModeDODNormal::InitViewport() +{ + m_pViewport = new DODViewport(); + m_pViewport->Start( gameuifuncs, gameeventmanager ); +} + +ClientModeDODNormal g_ClientModeNormal; + +IClientMode *GetClientModeNormal() +{ + return &g_ClientModeNormal; +} + + +ClientModeDODNormal* GetClientModeDODNormal() +{ + Assert( dynamic_cast< ClientModeDODNormal* >( GetClientModeNormal() ) ); + + return static_cast< ClientModeDODNormal* >( GetClientModeNormal() ); +} + +ConVar r_viewmodelfov( "r_viewmodelfov", "0", FCVAR_CHEAT ); + +float ClientModeDODNormal::GetViewModelFOV( void ) +{ + float flFov = 90.0f; + + if( r_viewmodelfov.GetFloat() > 0 ) + return r_viewmodelfov.GetFloat(); + + C_DODPlayer *pPlayer = C_DODPlayer::GetLocalDODPlayer(); + + if( !pPlayer ) + return flFov; + + CWeaponDODBase *pWpn = pPlayer->GetActiveDODWeapon(); + + if( pWpn ) + { + flFov = pWpn->GetDODWpnData().m_flViewModelFOV; + } + + return flFov; +} + +int ClientModeDODNormal::GetDeathMessageStartHeight( void ) +{ + return m_pViewport->GetDeathMessageStartHeight(); +} + +void ClientModeDODNormal::FireGameEvent( IGameEvent * event) +{ + const char *eventname = event->GetName(); + + if ( !eventname || !eventname[0] ) + return; + + if ( Q_strcmp( "dod_round_start", eventname ) == 0 ) + { + // Just tell engine to clear decals + engine->ClientCmd( "r_cleardecals\n" ); + + // recreate all client side physics props + // check for physenv, because we sometimes crash on changelevel + // if we get this message before fully connecting + if ( physenv ) + { + C_PhysPropClientside::RecreateAll(); + } + } + else if( Q_strcmp( "dod_broadcast_audio", eventname ) == 0 ) + { + CLocalPlayerFilter filter; + const char *pszSoundName = event->GetString("sound"); + + if ( dod_playwinmusic.GetBool() == false ) + { + if ( FStrEq( pszSoundName, "Game.USWin" ) || FStrEq( pszSoundName, "Game.GermanWin" ) ) + { + return; + } + } + C_BaseEntity::EmitSound( filter, SOUND_FROM_LOCAL_PLAYER, pszSoundName ); + } + else if ( Q_strcmp( "dod_bomb_planted", eventname ) == 0 ) + { + int defendingTeam = event->GetInt( "team" ); + + C_DODPlayer *pLocalPlayer = C_DODPlayer::GetLocalDODPlayer(); + + if ( !pLocalPlayer ) + return; + + const char *pszSound = ""; + const char *pszMessage = ""; + + int localTeam = pLocalPlayer->GetTeamNumber(); + + const char *pPlanterName = NULL; + + int iPlanterIndex = 0; + + if ( defendingTeam == localTeam ) + { + // play defend sound + switch( localTeam ) + { + case TEAM_ALLIES: + { + pszSound = "Voice.US_C4EnemyPlanted"; + pszMessage = "#dod_bomb_us_enemy_planted"; + } + break; + case TEAM_AXIS: + { + pszSound = "Voice.German_C4EnemyPlanted"; + pszMessage = "#dod_bomb_ger_enemy_planted"; + } + break; + default: + break; + } + } + else + { + // play planting sound + switch( localTeam ) + { + case TEAM_ALLIES: + { + pszSound = "Voice.US_C4TeamPlanted"; + pszMessage = "#dod_bomb_us_team_planted"; + } + break; + case TEAM_AXIS: + { + pszSound = "Voice.German_C4TeamPlanted"; + pszMessage = "#dod_bomb_ger_team_planted"; + } + break; + default: + break; + } + + // Only show the planter name if its a team plant, not enemy plant + iPlanterIndex = engine->GetPlayerForUserID( event->GetInt("userid") ); + pPlanterName = g_PR->GetPlayerName( iPlanterIndex ); + } + + RadioMessage( pszSound, pszMessage, pPlanterName, iPlanterIndex ); + } + else if ( Q_strcmp( "dod_bomb_defused", eventname ) == 0 ) + { + int defusingTeam = event->GetInt( "team" ); + + C_DODPlayer *pLocalPlayer = C_DODPlayer::GetLocalDODPlayer(); + + if ( !pLocalPlayer ) + return; + + const char *pszSound = ""; + const char *pszMessage = ""; + + int localTeam = pLocalPlayer->GetTeamNumber(); + + if ( defusingTeam == localTeam ) + { + // play defused sound + switch( localTeam ) + { + case TEAM_ALLIES: + { + pszSound = "Voice.US_C4Defused"; + pszMessage = "#dod_bomb_us_defused"; + } + break; + case TEAM_AXIS: + { + pszSound = "Voice.German_C4Defused"; + pszMessage = "#dod_bomb_ger_defused"; + } + break; + default: + break; + } + + int iDefuser = engine->GetPlayerForUserID( event->GetInt("userid") ); + const char *pDefuserName = g_PR->GetPlayerName( iDefuser ); + + RadioMessage( pszSound, pszMessage, pDefuserName, iDefuser ); + } + } + else if ( Q_strcmp( "player_team", eventname ) == 0 ) + { + C_BasePlayer *pPlayer = USERID2PLAYER( event->GetInt("userid") ); + + if ( !pPlayer ) + return; + + bool bDisconnected = event->GetBool("disconnect"); + + if ( bDisconnected ) + return; + + int team = event->GetInt( "team" ); + + if ( pPlayer->IsLocalPlayer() ) + { + // that's me + pPlayer->TeamChange( team ); + } + + CBaseHudChat *hudChat = (CBaseHudChat *)GET_HUDELEMENT( CHudChat ); + + if ( !hudChat ) + return; + + const char *pTemplate = NULL; + + if ( team == TEAM_ALLIES ) + { + pTemplate = "#game_joined_allies"; + } + else if ( team == TEAM_AXIS ) + { + pTemplate = "#game_joined_axis"; + } + else + { + pTemplate = "#game_joined_spectators"; + } + + wchar_t szPlayerName[MAX_PLAYER_NAME_LENGTH]; + g_pVGuiLocalize->ConvertANSIToUnicode( pPlayer->GetPlayerName(), szPlayerName, sizeof(szPlayerName) ); + + wchar_t wszPrint[128]; + char szPrint[128]; + + g_pVGuiLocalize->ConstructString( wszPrint, sizeof(wszPrint), g_pVGuiLocalize->Find(pTemplate), 1, szPlayerName ); + g_pVGuiLocalize->ConvertUnicodeToANSI( wszPrint, szPrint, sizeof(szPrint) ); + + hudChat->Printf( CHAT_FILTER_TEAMCHANGE, "%s",szPrint ); + } + else if ( Q_strcmp( "dod_timer_flash", eventname ) == 0 ) + { + C_DODPlayer *pLocalPlayer = C_DODPlayer::GetLocalDODPlayer(); + + if ( !pLocalPlayer ) + return; + + const char *pszSound = ""; + const char *pszMessage = ""; + + int localTeam = pLocalPlayer->GetTeamNumber(); + + int iTimeRemaining = event->GetInt( "time_remaining", 0 ); + + switch( iTimeRemaining ) + { + case 60: + switch( localTeam ) + { + case TEAM_ALLIES: + { + pszSound = "Voice.US_OneMinute"; + pszMessage = "#dod_time_remaining_us_1_min"; + } + break; + case TEAM_AXIS: + { + pszSound = "Voice.German_OneMinute"; + pszMessage = "#dod_time_remaining_ger_1_min"; + } + break; + default: + break; + } + break; + case 120: + switch( localTeam ) + { + case TEAM_ALLIES: + { + pszSound = "Voice.US_TwoMinute"; + pszMessage = "#dod_time_remaining_us_2_min"; + } + break; + case TEAM_AXIS: + { + pszSound = "Voice.German_TwoMinute"; + pszMessage = "#dod_time_remaining_ger_2_min"; + } + break; + default: + break; + } + break; + default: + break; + } + + RadioMessage( pszSound, pszMessage ); + } + else + BaseClass::FireGameEvent( event ); +} + + +void ClientModeDODNormal::PostRenderVGui() +{ +} + +bool ClientModeDODNormal::ShouldDrawViewModel() +{ + C_DODPlayer *pPlayer = C_DODPlayer::GetLocalDODPlayer(); + + CWeaponDODBase *pWpn = pPlayer->GetActiveDODWeapon(); + + if( pWpn && pWpn->ShouldDrawViewModel() == false ) + { + return false; + } + + return BaseClass::ShouldDrawViewModel(); +} + +void ClientModeDODNormal::RadioMessage( const char *pszSoundName, const char *pszSubtitle, const char *pszSender /* = NULL */, int iSenderIndex /* = 0 */ ) +{ + C_DODPlayer *pLocalPlayer = C_DODPlayer::GetLocalDODPlayer(); + if ( !pLocalPlayer ) + { + return; + } + + int color = COLOR_PLAYERNAME; + + // stop the last played radio message + if ( Q_strlen( m_szLastRadioSound ) > 0 ) + { + C_DODPlayer *pLocalPlayer = C_DODPlayer::GetLocalDODPlayer(); + if ( pLocalPlayer ) + { + pLocalPlayer->StopSound( m_szLastRadioSound ); + } + } + + Q_strncpy( m_szLastRadioSound, pszSoundName, sizeof(m_szLastRadioSound) ); + + // Play the radio alert + char szCmd[128]; + Q_snprintf( szCmd, sizeof(szCmd), "playgamesound %s", pszSoundName ); + + engine->ClientCmd( szCmd ); + + // Print a message to chat + wchar_t wszPrint[128]; + char szPrint[128]; + + g_pVGuiLocalize->ConstructString( wszPrint, sizeof(wszPrint), g_pVGuiLocalize->Find(pszSubtitle), 0 ); + g_pVGuiLocalize->ConvertUnicodeToANSI( wszPrint, szPrint, sizeof(szPrint) ); + + CBaseHudChat *hudChat = (CBaseHudChat *)GET_HUDELEMENT( CHudChat ); + + if ( !hudChat ) + return; + + wchar_t *pwLoc = g_pVGuiLocalize->Find( "#dod_radio_prefix" ); + char szPrefix[16]; + g_pVGuiLocalize->ConvertUnicodeToANSI( pwLoc, szPrefix, sizeof(szPrefix) ); + + pwLoc = g_pVGuiLocalize->Find( pszSubtitle ); + char szSuffix[512]; + g_pVGuiLocalize->ConvertUnicodeToANSI( pwLoc, szSuffix, sizeof(szSuffix) ); + + if ( pszSender ) + { + hudChat->ChatPrintf( iSenderIndex, CHAT_FILTER_NONE, "%c%s %s %c: %s", COLOR_PLAYERNAME, szPrefix, g_PR->GetPlayerName( iSenderIndex ), COLOR_NORMAL, szSuffix ); + } + else + { + hudChat->Printf( CHAT_FILTER_NONE, "%c%s %c: %s", color, szPrefix, COLOR_NORMAL, szSuffix ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: See if hud elements want key input. Return 0 if the key is swallowed +//----------------------------------------------------------------------------- +int ClientModeDODNormal::HudElementKeyInput( int down, ButtonCode_t keynum, const char *pszCurrentBinding ) +{ + if ( m_pFreezePanel ) + { + m_pFreezePanel->HudElementKeyInput( down, keynum, pszCurrentBinding ); + } + + return BaseClass::HudElementKeyInput( down, keynum, pszCurrentBinding ); +} diff --git a/game/client/dod/clientmode_dod.h b/game/client/dod/clientmode_dod.h new file mode 100644 index 0000000..553e94e --- /dev/null +++ b/game/client/dod/clientmode_dod.h @@ -0,0 +1,60 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef DOD_CLIENTMODE_H +#define DOD_CLIENTMODE_H +#ifdef _WIN32 +#pragma once +#endif + +#include "clientmode_shared.h" +#include "dodviewport.h" + +class CDODFreezePanel; + +class ClientModeDODNormal : public ClientModeShared +{ +DECLARE_CLASS( ClientModeDODNormal, ClientModeShared ); + +private: + +// IClientMode overrides. +public: + + ClientModeDODNormal(); + + virtual void Init(); + virtual void InitViewport(); + + virtual float GetViewModelFOV( void ); + + int GetDeathMessageStartHeight( void ); + + virtual void FireGameEvent( IGameEvent * event); + virtual void PostRenderVGui(); + + virtual bool ShouldDrawViewModel( void ); + + virtual int HudElementKeyInput( int down, ButtonCode_t keynum, const char *pszCurrentBinding ); + + +private: + + // void UpdateSpectatorMode( void ); + + void RadioMessage( const char *pszSoundName, const char *pszSubtitle, const char *pszSender = NULL, int iSenderIndex = 0 ); + char m_szLastRadioSound[128]; + + CDODFreezePanel *m_pFreezePanel; + +}; + + +extern IClientMode *GetClientModeNormal(); +extern ClientModeDODNormal* GetClientModeDODNormal(); + + +#endif // DOD_CLIENTMODE_H diff --git a/game/client/dod/dod_fx_explosions.cpp b/game/client/dod/dod_fx_explosions.cpp new file mode 100644 index 0000000..ca1ce95 --- /dev/null +++ b/game/client/dod/dod_fx_explosions.cpp @@ -0,0 +1,106 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Game-specific explosion effects +// +//=============================================================================// +#include "cbase.h" +#include "c_te_effect_dispatch.h" +#include "tempent.h" +#include "c_te_legacytempents.h" +#include "dod_shareddefs.h" +#include "engine/IEngineSound.h" +#include "c_basetempentity.h" +#include "tier0/vprof.h" +#include "fx_explosion.h" + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void DODExplosionCallback( const Vector &vecOrigin, const Vector &vecNormal ) +{ + // Calculate the angles, given the normal. + bool bInAir = false; + QAngle angExplosion( 0.0f, 0.0f, 0.0f ); + + // Cannot use zeros here because we are sending the normal at a smaller bit size. + if ( fabs( vecNormal.x ) < 0.05f && fabs( vecNormal.y ) < 0.05f && fabs( vecNormal.z ) < 0.05f ) + { + bInAir = true; + angExplosion.Init(); + } + else + { + VectorAngles( vecNormal, angExplosion ); + bInAir = false; + } + + // Base explosion effect and sound. + char *pszEffect = "explosion"; + char *pszSound = "BaseExplosionEffect.Sound"; + + // Explosions. + + if ( UTIL_PointContents( vecOrigin ) & CONTENTS_WATER ) + { + WaterExplosionEffect().Create( vecOrigin, 1 /*m_nMagnitude*/, 1 /*m_fScale*/, 0 /*m_nFlags*/ ); + return; + } + else if ( bInAir ) + { + pszEffect = "explosioncore_midair"; + } + else + { + pszEffect = "explosioncore_floor"; + } + + CLocalPlayerFilter filter; + C_BaseEntity::EmitSound( filter, SOUND_FROM_WORLD, pszSound, &vecOrigin ); + + DispatchParticleEffect( pszEffect, vecOrigin, angExplosion ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class C_TEDODExplosion : public C_BaseTempEntity +{ +public: + + DECLARE_CLASS( C_TEDODExplosion, C_BaseTempEntity ); + DECLARE_CLIENTCLASS(); + + C_TEDODExplosion( void ); + + virtual void PostDataUpdate( DataUpdateType_t updateType ); + +public: + Vector m_vecOrigin; + Vector m_vecNormal; +}; + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +C_TEDODExplosion::C_TEDODExplosion( void ) +{ + m_vecOrigin.Init(); + m_vecNormal.Init(); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_TEDODExplosion::PostDataUpdate( DataUpdateType_t updateType ) +{ + VPROF( "C_TETFExplosion::PostDataUpdate" ); + DODExplosionCallback( m_vecOrigin, m_vecNormal ); +} + +IMPLEMENT_CLIENTCLASS_EVENT_DT( C_TEDODExplosion, DT_TEDODExplosion, CTEDODExplosion ) + RecvPropFloat( RECVINFO( m_vecOrigin[0] ) ), + RecvPropFloat( RECVINFO( m_vecOrigin[1] ) ), + RecvPropFloat( RECVINFO( m_vecOrigin[2] ) ), + RecvPropVector( RECVINFO( m_vecNormal ) ), +END_RECV_TABLE() + diff --git a/game/client/dod/dod_headiconmanager.cpp b/game/client/dod/dod_headiconmanager.cpp new file mode 100644 index 0000000..f24a6f1 --- /dev/null +++ b/game/client/dod/dod_headiconmanager.cpp @@ -0,0 +1,215 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= +#include "cbase.h" +#include <string.h> +#include <stdio.h> +#include "dod_headiconmanager.h" +#include "c_playerresource.h" +#include "cliententitylist.h" +#include "c_baseplayer.h" +#include "materialsystem/imesh.h" +#include "view.h" +#include "materialsystem/imaterial.h" +#include "tier0/dbg.h" +#include "cdll_int.h" + +#include "dod_shareddefs.h" +#include "c_dod_player.h" +#include "voice_status.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +using namespace vgui; + +static CHeadIconManager s_HeadIconMgr; + +CHeadIconManager* HeadIconManager() +{ + return &s_HeadIconMgr; +} + +CHeadIconManager::CHeadIconManager() +{ + m_pAlliesIconMaterial = NULL; + m_pAxisIconMaterial = NULL; +} + +CHeadIconManager::~CHeadIconManager() +{ + Shutdown(); +} + +bool CHeadIconManager::Init() +{ + if ( !m_pAlliesIconMaterial ) + { + m_pAlliesIconMaterial = materials->FindMaterial( "sprites/player_icons/american", TEXTURE_GROUP_VGUI ); + } + + if ( !m_pAxisIconMaterial ) + { + m_pAxisIconMaterial = materials->FindMaterial( "sprites/player_icons/german", TEXTURE_GROUP_VGUI ); + } + + if ( IsErrorMaterial( m_pAlliesIconMaterial ) || + IsErrorMaterial( m_pAxisIconMaterial ) ) + { + Assert(!"Can't find head icon materials"); + return false; + } + + m_pAlliesIconMaterial->IncrementReferenceCount(); + m_pAxisIconMaterial->IncrementReferenceCount(); + m_PlayerDrawn.ClearAll(); + + return true; +} + +void CHeadIconManager::Shutdown() +{ + if ( m_pAlliesIconMaterial ) + { + m_pAlliesIconMaterial->DecrementReferenceCount(); + m_pAlliesIconMaterial = NULL; + } + + if ( m_pAxisIconMaterial ) + { + m_pAxisIconMaterial->DecrementReferenceCount(); + m_pAxisIconMaterial = NULL; + } +} + + +//----------------------------------------------------------------------------- +// Call from player render calls to indicate a head icon should be drawn for this player this frame +//----------------------------------------------------------------------------- +void CHeadIconManager::PlayerDrawn( C_BasePlayer *pPlayer ) +{ + m_PlayerDrawn.Set( pPlayer->entindex() - 1 ); +} + + +ConVar cl_headiconoffset( "cl_headiconoffset", "24", FCVAR_CHEAT ); +ConVar cl_headiconsize( "cl_headiconsize", "8", FCVAR_CHEAT ); +ConVar cl_identiconmode( "cl_identiconmode", "2", FCVAR_ARCHIVE, "2 - icons over teammates' heads\n1- icons over target teammate\n0 - no head icons" ); + +void CHeadIconManager::DrawHeadIcons() +{ + CMatRenderContextPtr pRenderContext( materials ); + + CBitVec<MAX_PLAYERS> playerDrawn = m_PlayerDrawn; + m_PlayerDrawn.ClearAll(); + + if ( cl_identiconmode.GetInt() <= 0 ) + return; + + C_DODPlayer *pLocalPlayer = C_DODPlayer::GetLocalDODPlayer(); + + if ( !pLocalPlayer ) + return; + + if ( pLocalPlayer->GetTeamNumber() != TEAM_ALLIES && + pLocalPlayer->GetTeamNumber() != TEAM_AXIS ) + { + return; + } + + Vector vUp = CurrentViewUp(); + Vector vRight = CurrentViewRight(); + if ( fabs( vRight.z ) > 0.95 ) // don't draw it edge-on + return; + + vRight.z = 0; + VectorNormalize( vRight ); + + float flSize = cl_headiconsize.GetFloat(); + + for(int i=0; i < MAX_PLAYERS; i++) + { + if ( !playerDrawn.IsBitSet( i ) ) + continue; + + if ( cl_identiconmode.GetInt() == 1 ) + { + // only draw if this player is our status bar target + if ( (i+1) != pLocalPlayer->GetIDTarget() ) + continue; + } + + IClientNetworkable *pClient = cl_entitylist->GetClientEntity( i+1 ); + + // Don't show an icon if the player is not in our PVS. + if ( !pClient || pClient->IsDormant() ) + continue; + + C_DODPlayer *pPlayer = dynamic_cast<C_DODPlayer*>(pClient); + if( !pPlayer ) + continue; + + // Don't show an icon for dead or spectating players (ie: invisible entities). + if( pPlayer->IsPlayerDead() ) + continue; + + if( pPlayer == pLocalPlayer ) + continue; + + if( pPlayer->GetTeamNumber() != pLocalPlayer->GetTeamNumber() ) + continue; + + if ( GetClientVoiceMgr()->IsPlayerSpeaking( i+1 ) ) + continue; + + if ( C_BasePlayer::GetLocalPlayer()->GetObserverMode() == OBS_MODE_IN_EYE && + C_BasePlayer::GetLocalPlayer()->GetObserverTarget() == pPlayer ) + continue; + + IMaterial *pMaterial = pPlayer->GetHeadIconMaterial(); + if ( !pMaterial ) + continue; + + pRenderContext->Bind( pMaterial ); + + Vector vOrigin; + QAngle vAngle; + + int iHeadAttach = pPlayer->LookupAttachment( "head" ); + + pPlayer->GetAttachment( iHeadAttach, vOrigin, vAngle ); + + vOrigin.z += cl_headiconoffset.GetFloat(); + + // Align it towards the viewer + + IMesh *pMesh = pRenderContext->GetDynamicMesh(); + CMeshBuilder meshBuilder; + meshBuilder.Begin( pMesh, MATERIAL_QUADS, 1 ); + + meshBuilder.Color3f( 1.0, 1.0, 1.0 ); + meshBuilder.TexCoord2f( 0,0,0 ); + meshBuilder.Position3fv( (vOrigin + (vRight * -flSize) + (vUp * flSize)).Base() ); + meshBuilder.AdvanceVertex(); + + meshBuilder.Color3f( 1.0, 1.0, 1.0 ); + meshBuilder.TexCoord2f( 0,1,0 ); + meshBuilder.Position3fv( (vOrigin + (vRight * flSize) + (vUp * flSize)).Base() ); + meshBuilder.AdvanceVertex(); + + meshBuilder.Color3f( 1.0, 1.0, 1.0 ); + meshBuilder.TexCoord2f( 0,1,1 ); + meshBuilder.Position3fv( (vOrigin + (vRight * flSize) + (vUp * -flSize)).Base() ); + meshBuilder.AdvanceVertex(); + + meshBuilder.Color3f( 1.0, 1.0, 1.0 ); + meshBuilder.TexCoord2f( 0,0,1 ); + meshBuilder.Position3fv( (vOrigin + (vRight * -flSize) + (vUp * -flSize)).Base() ); + meshBuilder.AdvanceVertex(); + meshBuilder.End(); + pMesh->Draw(); + } +}
\ No newline at end of file diff --git a/game/client/dod/dod_headiconmanager.h b/game/client/dod/dod_headiconmanager.h new file mode 100644 index 0000000..629ad33 --- /dev/null +++ b/game/client/dod/dod_headiconmanager.h @@ -0,0 +1,45 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//===========================================================================// + +#ifndef DOD_HEADICONMANAGER_H +#define DOD_HEADICONMANAGER_H +#ifdef _WIN32 +#pragma once +#endif + +#include "bitvec.h" + +class IMaterial; + +class CHeadIconManager : CAutoGameSystem +{ +public: + CHeadIconManager(); + ~CHeadIconManager(); + + virtual bool Init(); + virtual void Shutdown(); + +public: + // Call from the HUD_CreateEntities function so it can add sprites above player heads. + void DrawHeadIcons(); + + // Call from player render calls to indicate a head icon should be drawn for this player this frame + void PlayerDrawn( C_BasePlayer *pPlayer ); + +private: + IMaterial *m_pAlliesIconMaterial; // For labels above players' heads. + IMaterial *m_pAxisIconMaterial; // For labels above players' heads. + CBitVec<MAX_PLAYERS> m_PlayerDrawn; // Was the player drawn this frame? +}; + + +// Get the (global) head icon manager. +CHeadIconManager* HeadIconManager(); + + +#endif // DOD_HEADICONMANAGER_H diff --git a/game/client/dod/dod_hud_ammo.cpp b/game/client/dod/dod_hud_ammo.cpp new file mode 100644 index 0000000..94b4ef0 --- /dev/null +++ b/game/client/dod/dod_hud_ammo.cpp @@ -0,0 +1,508 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#include "cbase.h" +#include "hud.h" +#include "hudelement.h" +#include "hud_macros.h" +#include "hud_bitmapnumericdisplay.h" +#include "iclientmode.h" +#include "c_dod_player.h" +#include "ihudlcd.h" + +#include <vgui/ISurface.h> +#include <vgui_controls/AnimationController.h> + +//----------------------------------------------------------------------------- +// Purpose: Displays current ammunition level +//----------------------------------------------------------------------------- +class CHudAmmo : public CHudElement, public vgui::Panel +{ + DECLARE_CLASS_SIMPLE( CHudAmmo, vgui::Panel ); + +public: + CHudAmmo( const char *pElementName ); + void Init( void ); + void VidInit( void ); + + void SetAmmo(int ammo, bool playAnimation); + void SetAmmo2(int ammo2, bool playAnimation); + +protected: + virtual void OnThink(); + virtual void Paint( void ); + virtual void ApplySchemeSettings(vgui::IScheme *pScheme); + +private: + void DrawText( char *text, int x, int y, Color clrText ); + void DrawNumbers( int num, int x, int y ); + + void PaintGrenadeAmmo( CWeaponDODBase *pWpn ); + void PaintBazookaAmmo( CWeaponDODBase *pWpn ); + void PaintMGAmmo( CWeaponDODBase *pWpn ); + void PaintGunAmmo( CWeaponDODBase *pWpn ); + void PaintRifleGrenadeAmmo( CWeaponDODBase *pWpn ); + + CHandle< C_BaseCombatWeapon > m_hCurrentActiveWeapon; + int m_iAmmo; + int m_iAmmo2; + + bool m_bUsesClips; + + int m_iAdditiveWhiteID; + + CPanelAnimationVarAliasType( float, digit2_xpos, "digit2_xpos", "0", "proportional_float" ); + CPanelAnimationVarAliasType( float, digit2_ypos, "digit2_ypos", "0", "proportional_float" ); + CPanelAnimationVarAliasType( float, bar_xpos, "bar_xpos", "0", "proportional_float" ); + CPanelAnimationVarAliasType( float, bar_ypos, "bar_ypos", "0", "proportional_float" ); + CPanelAnimationVarAliasType( float, bar_width, "bar_width", "2", "proportional_float" ); + CPanelAnimationVarAliasType( float, bar_height, "bar_height", "2", "proportional_float" ); + CPanelAnimationVarAliasType( float, icon_xpos, "icon_xpos", "0", "proportional_float" ); + CPanelAnimationVarAliasType( float, icon_ypos, "icon_ypos", "0", "proportional_float" ); + + CPanelAnimationVar( vgui::HFont, m_hNumberFont, "NumberFont", "HudSelectionNumbers" ); + + Color m_clrIcon; + + CHudTexture *m_pMGNumbers[10]; +}; + +//DECLARE_HUDELEMENT( CHudAmmo ); + +//----------------------------------------------------------------------------- +// Purpose: Constructor +//----------------------------------------------------------------------------- +CHudAmmo::CHudAmmo( const char *pElementName ) : vgui::Panel( NULL, "HudAmmo" ), CHudElement( pElementName ) +{ + SetParent( g_pClientMode->GetViewport() ); + + m_iAdditiveWhiteID = vgui::surface()->CreateNewTextureID(); + vgui::surface()->DrawSetTextureFile( m_iAdditiveWhiteID, "vgui/white_additive" , true, false); + + SetActive( true ); + + m_clrIcon = Color(255,255,255,255); + + SetHiddenBits( HIDEHUD_HEALTH | HIDEHUD_PLAYERDEAD | HIDEHUD_WEAPONSELECTION ); + + hudlcd->SetGlobalStat( "(ammo_primary)", "0" ); + hudlcd->SetGlobalStat( "(ammo_secondary)", "0" ); + hudlcd->SetGlobalStat( "(weapon_print_name)", "" ); + hudlcd->SetGlobalStat( "(weapon_name)", "" ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CHudAmmo::Init( void ) +{ + m_iAmmo = -1; + m_iAmmo2 = -1; +} + +void CHudAmmo::ApplySchemeSettings(vgui::IScheme *pScheme) +{ + BaseClass::ApplySchemeSettings(pScheme); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CHudAmmo::VidInit( void ) +{ +} + +//----------------------------------------------------------------------------- +// Purpose: called every frame to get ammo info from the weapon +//----------------------------------------------------------------------------- +void CHudAmmo::OnThink() +{ + C_BaseCombatWeapon *wpn = GetActiveWeapon(); + + hudlcd->SetGlobalStat( "(weapon_print_name)", wpn ? wpn->GetPrintName() : " " ); + hudlcd->SetGlobalStat( "(weapon_name)", wpn ? wpn->GetName() : " " ); + + C_BasePlayer *player = C_BasePlayer::GetLocalPlayer(); + if (!wpn || !player || !wpn->UsesPrimaryAmmo()) + { + hudlcd->SetGlobalStat( "(ammo_primary)", "n/a" ); + hudlcd->SetGlobalStat( "(ammo_secondary)", "n/a" ); + + SetPaintEnabled(false); + SetPaintBackgroundEnabled(false); + return; + } + else + { + SetPaintEnabled(true); + SetPaintBackgroundEnabled(true); + } + + // get the ammo in our clip + int ammo1 = wpn->Clip1(); + int ammo2; + if (ammo1 < 0) + { + // we don't use clip ammo, just use the total ammo count + ammo1 = player->GetAmmoCount(wpn->GetPrimaryAmmoType()); + ammo2 = 0; + } + else + { + // we use clip ammo, so the second ammo is the total ammo + ammo2 = player->GetAmmoCount(wpn->GetPrimaryAmmoType()); + } + + hudlcd->SetGlobalStat( "(ammo_primary)", VarArgs( "%d", ammo1 ) ); + hudlcd->SetGlobalStat( "(ammo_secondary)", VarArgs( "%d", ammo2 ) ); + + if (wpn == m_hCurrentActiveWeapon) + { + // same weapon, just update counts + SetAmmo(ammo1, true); + SetAmmo2(ammo2, true); + } + else + { + // diferent weapon, change without triggering + SetAmmo(ammo1, false); + SetAmmo2(ammo2, false); + + // update whether or not we show the total ammo display + if (wpn->UsesClipsForAmmo1()) + { + m_bUsesClips = true; + + } + else + { + m_bUsesClips = false; + } + + m_hCurrentActiveWeapon = wpn; + } +} + +//----------------------------------------------------------------------------- +// Purpose: Updates ammo display +//----------------------------------------------------------------------------- +void CHudAmmo::SetAmmo(int ammo, bool playAnimation) +{ + if (ammo != m_iAmmo) + { + m_iAmmo = ammo; + } +} + +//----------------------------------------------------------------------------- +// Purpose: Updates 2nd ammo display +//----------------------------------------------------------------------------- +void CHudAmmo::SetAmmo2(int ammo2, bool playAnimation) +{ + if (ammo2 != m_iAmmo2) + { + m_iAmmo2 = ammo2; + } +} + +void CHudAmmo::PaintGrenadeAmmo( CWeaponDODBase *pWpn ) +{ + const CHudTexture *pAmmoIcon = pWpn->GetSpriteAmmo(); + + Assert( pAmmoIcon ); + + int x,y,w,h; + GetBounds( x, y, w, h ); + + if (m_iAmmo > 0 && pAmmoIcon ) + { + int xpos = w - 2 * pAmmoIcon->Width(); + int ypos = h - pAmmoIcon->Height(); + + pAmmoIcon->DrawSelf( xpos, ypos, pAmmoIcon->Width(), pAmmoIcon->Height(), m_clrIcon ); + + char buf[16]; + Q_snprintf( buf, sizeof(buf), "x %d", m_iAmmo ); + + DrawText( buf, xpos + pAmmoIcon->Width(), ypos + pAmmoIcon->Height() / 2, m_clrIcon ); + } +} + +void CHudAmmo::PaintRifleGrenadeAmmo( CWeaponDODBase *pWpn ) +{ + const CHudTexture *pAmmoIcon = pWpn->GetSpriteAmmo(); + + Assert( pAmmoIcon ); + + int x,y,w,h; + GetBounds( x, y, w, h ); + + int ammo = m_iAmmo + m_iAmmo2; + + if (ammo > 0 && pAmmoIcon ) + { + int xpos = w - 2 * pAmmoIcon->Width(); + int ypos = h - pAmmoIcon->Height(); + + pAmmoIcon->DrawSelf( xpos, ypos, pAmmoIcon->Width(), pAmmoIcon->Height(), m_clrIcon ); + + char buf[16]; + Q_snprintf( buf, sizeof(buf), "x %d", ammo ); + + DrawText( buf, xpos + pAmmoIcon->Width(), ypos + pAmmoIcon->Height() / 2, m_clrIcon ); + } +} + +void CHudAmmo::PaintBazookaAmmo( CWeaponDODBase *pWpn ) +{ + const CHudTexture *pTubeIcon = pWpn->GetSpriteAmmo2(); + const CHudTexture *pRocketIcon = pWpn->GetSpriteAmmo(); + const CHudTexture *pExtraIcon = pWpn->GetSpriteAutoaim(); + + Assert( pTubeIcon ); + Assert( pRocketIcon ); + Assert( pExtraIcon ); + + int xpos = 0; + int ypos = 0; + + int x, y, w, h; + GetBounds(x,y,w,h); + + //Draw the rocket tube + if( pTubeIcon ) + { + xpos = w - 2 * pTubeIcon->Width(); + ypos = h - pTubeIcon->Height(); + pTubeIcon->DrawSelf( xpos, ypos, m_clrIcon ); + } + + //If our clip is full, draw the rocket + if( pRocketIcon ) + { + if( m_iAmmo > 0 ) + pRocketIcon->DrawSelf( xpos, ypos, m_clrIcon ); + + xpos += pRocketIcon->Width() + 10; + ypos += pRocketIcon->Height(); + } + + char buf[16]; + Q_snprintf( buf, sizeof(buf), "%d %d", m_iAmmo, m_iAmmo2 ); + DrawText( buf, xpos, ypos, m_clrIcon ); + + //Draw the extra rockets + if( m_iAmmo2 > 0 && pExtraIcon ) + { + ypos -= pExtraIcon->Height(); + + pExtraIcon->DrawSelf( xpos, ypos, m_clrIcon ); + + xpos += pExtraIcon->Width(); + + char buf[16]; + Q_snprintf( buf, sizeof(buf), "x %d", m_iAmmo2 ); + DrawText( buf, xpos, ypos + ( pExtraIcon->Height() * 0.75 ), m_clrIcon ); + } +} + +void CHudAmmo::PaintMGAmmo( CWeaponDODBase *pWpn ) +{ + const CHudTexture *pFullClip = pWpn->GetSpriteAmmo(); + const CHudTexture *pExtraClip = pWpn->GetSpriteAmmo2(); + + int xpos = 0; + int ypos = 0; + + int x, y, w, h; + GetBounds(x,y,w,h); + + if( pFullClip ) + { + xpos = w - pFullClip->Width() * 3; + ypos = h - pFullClip->Height(); + pFullClip->DrawSelf( xpos, ypos, m_clrIcon ); + + //Haxoration! The box that contains the numbers must be in the same position + // in both the webley and mg34/mg42/30cal sprites. + DrawNumbers( m_iAmmo, xpos + 36, ypos + pFullClip->Height() - 16 ); + + xpos += pFullClip->Width(); + ypos += pFullClip->Height(); + } + + //how many full or partially full clips do we have? + int clips = m_iAmmo2 / pWpn->GetMaxClip1(); + + //account for the partial clip, if it exists + if( clips * pWpn->GetMaxClip1() < m_iAmmo2 ) + clips++; + + if( pExtraClip && clips > 0 ) + { + ypos -= pExtraClip->Height(); + + pExtraClip->DrawSelf( xpos, ypos, m_clrIcon ); + + char buf[16]; + Q_snprintf( buf, sizeof(buf), "x %d", clips ); + DrawText( buf, xpos + pExtraClip->Width(), ypos + pExtraClip->Height() / 2, m_clrIcon ); + } +} + +void CHudAmmo::PaintGunAmmo( CWeaponDODBase *pWpn ) +{ + //regular gun + const CHudTexture *pEmptyClip = pWpn->GetSpriteAmmo(); + const CHudTexture *pFullClip = pWpn->GetSpriteAmmo2(); + const CHudTexture *pExtraClip = pWpn->GetSpriteAutoaim(); + + Assert( pEmptyClip ); + Assert( pFullClip ); + Assert( pExtraClip ); + + int x, y, w, h; + GetBounds( x, y, w, h ); + + int xpos = 0; + int ypos = 0; + + if( pFullClip ) + { + xpos = w - 3 * pFullClip->Width(); + ypos = h - pFullClip->Height() * 1.2; + + //Always draw the empty clip + pFullClip->DrawSelf( xpos, ypos, Color(255,255,255,255) ); + } + + if( pEmptyClip ) + { + // base percent is how much of the bullet clip to always draw. + // total cropped height of the bullet sprite will be + // base percent + bullet height * bullets + float flBasePercent = (float)pWpn->GetDODWpnData().m_iHudClipBaseHeight / (float)pWpn->GetDODWpnData().m_iHudClipHeight; + float flBulletHeightPercent = (float)pWpn->GetDODWpnData().m_iHudClipBulletHeight / (float)pWpn->GetDODWpnData().m_iHudClipHeight; + + float flHeight = (float)pEmptyClip->Height(); + + //Now we draw the bullets inside based on how full our clip is + float flDrawHeight = flHeight * ( 1.0 - ( flBasePercent + flBulletHeightPercent * m_iAmmo ) ); + + int nOffset = (int)flDrawHeight; + + pEmptyClip->DrawSelfCropped( xpos, ypos + nOffset, 0, nOffset, pEmptyClip->Width(), pEmptyClip->Height() - nOffset, Color(255,255,255,255) ); + + ypos += pEmptyClip->Height(); + + xpos += pEmptyClip->Width() + 10; + } + + //how many full or partially full clips do we have? + int clips = m_iAmmo2 / pWpn->GetMaxClip1(); + + //account for the partial clip, if it exists + if( clips * pWpn->GetMaxClip1() < m_iAmmo2 ) + clips++; + + if( pExtraClip && clips > 0 ) + { + //align the extra clip on the same baseline as the large clip + ypos -= pExtraClip->Height(); + + pExtraClip->DrawSelf( xpos, ypos, Color(255,255,255,255) ); + + char buf[16]; + Q_snprintf( buf, sizeof(buf), "x %d", clips ); + DrawText( buf, xpos + pExtraClip->Width(), ypos + pExtraClip->Height() / 2, m_clrIcon ); + } +} + +void CHudAmmo::Paint( void ) +{ + C_DODPlayer *pPlayer = C_DODPlayer::GetLocalDODPlayer(); + + if( !pPlayer ) + return; + + CWeaponDODBase *pWpn = pPlayer->GetActiveDODWeapon(); + + if( !pWpn ) + return; + + switch( pWpn->GetDODWpnData().m_WeaponType ) + { + case WPN_TYPE_GRENADE: + PaintGrenadeAmmo(pWpn); + break; + + case WPN_TYPE_RIFLEGRENADE: + PaintRifleGrenadeAmmo(pWpn); + break; + + case WPN_TYPE_BAZOOKA: + PaintBazookaAmmo(pWpn); + break; + + case WPN_TYPE_MG: + PaintMGAmmo(pWpn); + break; + + default: + PaintGunAmmo(pWpn); + break; + } +} + +void CHudAmmo::DrawText( char *text, int x, int y, Color clrText ) +{ + vgui::surface()->DrawSetTextColor( clrText ); + vgui::surface()->DrawSetTextFont( m_hNumberFont ); + vgui::surface()->DrawSetTextPos( x, y ); + + for (char *pch = text; *pch != 0; pch++) + { + vgui::surface()->DrawUnicodeChar(*pch); + } +} + +void CHudAmmo::DrawNumbers( int num, int x, int y ) +{ + if( !m_pMGNumbers[0] ) + { + int i; + for( i=0;i<10;i++ ) + { + char buf[8]; + Q_snprintf( buf, sizeof(buf), "mg_%d", i ); + m_pMGNumbers[i] = gHUD.GetIcon( buf ); + } + } + + Assert( num < 1000 ); + + int xpos = x; + int ypos = y; + int num_working = num; + + int iconWidth = m_pMGNumbers[0]->Width(); + + int hundreds = num_working / 100; + num_working -= hundreds * 100; + + m_pMGNumbers[hundreds]->DrawSelf( xpos, ypos, m_clrIcon ); + xpos += iconWidth; + + int tens = num_working / 10; + num_working -= tens * 10; + + m_pMGNumbers[tens]->DrawSelf( xpos, ypos, m_clrIcon ); + xpos += iconWidth; + + m_pMGNumbers[num_working]->DrawSelf( xpos, ypos, m_clrIcon ); + xpos += iconWidth; +} + diff --git a/game/client/dod/dod_hud_areacapicon.cpp b/game/client/dod/dod_hud_areacapicon.cpp new file mode 100644 index 0000000..0437374 --- /dev/null +++ b/game/client/dod/dod_hud_areacapicon.cpp @@ -0,0 +1,89 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#include "cbase.h" +#include "hudelement.h" +#include <vgui_controls/Panel.h> +#include <vgui/ISurface.h> +#include "c_dod_player.h" +#include "iclientmode.h" + +class CHudAreaCapIcon : public CHudElement, public vgui::Panel +{ +public: + DECLARE_CLASS_SIMPLE( CHudAreaCapIcon, vgui::Panel ); + + CHudAreaCapIcon( const char *name ); + + virtual void Paint(); + virtual void Init(); + virtual bool ShouldDraw(); + +private: + int m_iAreaTexture; + int m_iPrevMaterialIndex; + Color m_clrIcon; +}; + + +// DECLARE_HUDELEMENT( CHudAreaCapIcon ); + + +CHudAreaCapIcon::CHudAreaCapIcon( const char *pName ) : + vgui::Panel( NULL, "HudAreaCapIcon" ), CHudElement( pName ) +{ + SetParent( g_pClientMode->GetViewport() ); + + m_clrIcon = Color(255,255,255,255); + + m_iPrevMaterialIndex = 0; + + SetHiddenBits( HIDEHUD_PLAYERDEAD ); +} + +void CHudAreaCapIcon::Init() +{ + m_iAreaTexture = vgui::surface()->CreateNewTextureID(); +} + +bool CHudAreaCapIcon::ShouldDraw() +{ + return false; +} + +void CHudAreaCapIcon::Paint() +{ + /* + C_DODPlayer *pPlayer = C_DODPlayer::GetLocalDODPlayer(); + + if( !pPlayer ) + return; + + int x,y,w,h; + GetBounds( x,y,w,h ); + + // The player knows what material to show as our area icon + int iMaterialIndex = pPlayer->m_Shared.GetAreaIconMaterial(); + + if( iMaterialIndex <= 0 ) + return; + + // if the icon is changed from last draw, force the texture to reload + bool bForceReload = ( m_iPrevMaterialIndex != iMaterialIndex ); + + // get the material name from the material string table + const char *szMatName = GetMaterialNameFromIndex( iMaterialIndex ); + + // draw the icon + vgui::surface()->DrawSetTextureFile( m_iAreaTexture, szMatName , true, bForceReload); + vgui::surface()->DrawSetColor( m_clrIcon ); + vgui::surface()->DrawTexturedRect( 0, 0, w, h ); + + // store the previous material index to compare next frame + m_iPrevMaterialIndex = iMaterialIndex;*/ + +} + diff --git a/game/client/dod/dod_hud_capturepanel.cpp b/game/client/dod/dod_hud_capturepanel.cpp new file mode 100644 index 0000000..bad9a9b --- /dev/null +++ b/game/client/dod/dod_hud_capturepanel.cpp @@ -0,0 +1,629 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#include "cbase.h" +#include "hudelement.h" +#include <vgui_controls/Panel.h> +#include <vgui_controls/EditablePanel.h> +#include <vgui_controls/ImagePanel.h> +#include <vgui/ISurface.h> +#include "c_dod_player.h" +#include "clientmode_dod.h" + +#include "c_dod_objective_resource.h" +#include "c_dod_playerresource.h" + +#include "dod_hud_capturepanel.h" + +DECLARE_HUDELEMENT( CDoDHudCapturePanel ); + +ConVar hud_capturepanel( "hud_capturepanel", "1", FCVAR_CLIENTDLL | FCVAR_ARCHIVE, "Set to 0 to not draw the HUD capture panel" ); + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +CDoDCapturePanelProgressBar::CDoDCapturePanelProgressBar( vgui::Panel *parent, const char *name ) : vgui::ImagePanel( parent, name ) +{ + m_flPercent = 0.0f; + + m_iTexture = vgui::surface()->DrawGetTextureId( "vgui/progress_bar" ); + if ( m_iTexture == -1 ) // we didn't find it, so create a new one + { + m_iTexture = vgui::surface()->CreateNewTextureID(); + } + + vgui::surface()->DrawSetTextureFile( m_iTexture, "vgui/progress_bar", true, false ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CDoDCapturePanelProgressBar::Paint() +{ + int wide, tall; + GetSize( wide, tall ); + + float uv1 = 0.0f, uv2 = 1.0f; + Vector2D uv11( uv1, uv1 ); + Vector2D uv21( uv2, uv1 ); + Vector2D uv22( uv2, uv2 ); + Vector2D uv12( uv1, uv2 ); + + vgui::Vertex_t verts[4]; + verts[0].Init( Vector2D( 0, 0 ), uv11 ); + verts[1].Init( Vector2D( wide, 0 ), uv21 ); + verts[2].Init( Vector2D( wide, tall ), uv22 ); + verts[3].Init( Vector2D( 0, tall ), uv12 ); + + // first, just draw the whole thing inactive. + vgui::surface()->DrawSetTexture( m_iTexture ); + vgui::surface()->DrawSetColor( m_clrInActive ); + vgui::surface()->DrawTexturedPolygon( 4, verts ); + + // now, let's calculate the "active" part of the progress bar + vgui::surface()->DrawSetColor( m_clrActive ); + + // we're going to do this using quadrants + // ------------------------- + // | | | + // | | | + // | 4 | 1 | + // | | | + // | | | + // ------------------------- + // | | | + // | | | + // | 3 | 2 | + // | | | + // | | | + // ------------------------- + + float flCompleteCircle = ( 2.0f * M_PI ); + float fl90degrees = flCompleteCircle / 4.0f; + + float flEndAngle = flCompleteCircle * ( 1.0f - m_flPercent ); // count DOWN (counter-clockwise) + // float flEndAngle = flCompleteCircle * m_flPercent; // count UP (clockwise) + + float flHalfWide = (float)wide / 2.0f; + float flHalfTall = (float)tall / 2.0f; + + if ( flEndAngle >= fl90degrees * 3.0f ) // >= 270 degrees + { + // draw the first and second quadrants + uv11.Init( 0.5f, 0.0f ); + uv21.Init( 1.0f, 0.0f ); + uv22.Init( 1.0f, 1.0f ); + uv12.Init( 0.5, 1.0f ); + + verts[0].Init( Vector2D( flHalfWide, 0.0f ), uv11 ); + verts[1].Init( Vector2D( wide, 0.0f ), uv21 ); + verts[2].Init( Vector2D( wide, tall ), uv22 ); + verts[3].Init( Vector2D( flHalfWide, tall ), uv12 ); + + vgui::surface()->DrawTexturedPolygon( 4, verts ); + + // draw the third quadrant + uv11.Init( 0.0f, 0.5f ); + uv21.Init( 0.5f, 0.5f ); + uv22.Init( 0.5f, 1.0f ); + uv12.Init( 0.0f, 1.0f ); + + verts[0].Init( Vector2D( 0.0f, flHalfTall ), uv11 ); + verts[1].Init( Vector2D( flHalfWide, flHalfTall ), uv21 ); + verts[2].Init( Vector2D( flHalfWide, tall ), uv22 ); + verts[3].Init( Vector2D( 0.0f, tall ), uv12 ); + + vgui::surface()->DrawTexturedPolygon( 4, verts ); + + // draw the partial fourth quadrant + if ( flEndAngle > fl90degrees * 3.5f ) // > 315 degrees + { + uv11.Init( 0.0f, 0.0f ); + uv21.Init( 0.5f - ( tan(fl90degrees * 4.0f - flEndAngle) * 0.5 ), 0.0f ); + uv22.Init( 0.5f, 0.5f ); + uv12.Init( 0.0f, 0.5f ); + + verts[0].Init( Vector2D( 0.0f, 0.0f ), uv11 ); + verts[1].Init( Vector2D( flHalfWide - ( tan(fl90degrees * 4.0f - flEndAngle) * flHalfTall ), 0.0f ), uv21 ); + verts[2].Init( Vector2D( flHalfWide, flHalfTall ), uv22 ); + verts[3].Init( Vector2D( 0.0f, flHalfTall ), uv12 ); + + vgui::surface()->DrawTexturedPolygon( 4, verts ); + } + else // <= 315 degrees + { + uv11.Init( 0.0f, 0.5f ); + uv21.Init( 0.0f, 0.5f - ( tan(flEndAngle - fl90degrees * 3.0f) * 0.5 ) ); + uv22.Init( 0.5f, 0.5f ); + uv12.Init( 0.0f, 0.5f ); + + verts[0].Init( Vector2D( 0.0f, flHalfTall ), uv11 ); + verts[1].Init( Vector2D( 0.0f, flHalfTall - ( tan(flEndAngle - fl90degrees * 3.0f) * flHalfWide ) ), uv21 ); + verts[2].Init( Vector2D( flHalfWide, flHalfTall ), uv22 ); + verts[3].Init( Vector2D( 0.0f, flHalfTall ), uv12 ); + + vgui::surface()->DrawTexturedPolygon( 4, verts ); + } + } + else if ( flEndAngle >= fl90degrees * 2.0f ) // >= 180 degrees + { + // draw the first and second quadrants + uv11.Init( 0.5f, 0.0f ); + uv21.Init( 1.0f, 0.0f ); + uv22.Init( 1.0f, 1.0f ); + uv12.Init( 0.5, 1.0f ); + + verts[0].Init( Vector2D( flHalfWide, 0.0f ), uv11 ); + verts[1].Init( Vector2D( wide, 0.0f ), uv21 ); + verts[2].Init( Vector2D( wide, tall ), uv22 ); + verts[3].Init( Vector2D( flHalfWide, tall ), uv12 ); + + vgui::surface()->DrawTexturedPolygon( 4, verts ); + + // draw the partial third quadrant + if ( flEndAngle > fl90degrees * 2.5f ) // > 225 degrees + { + uv11.Init( 0.5f, 0.5f ); + uv21.Init( 0.5f, 1.0f ); + uv22.Init( 0.0f, 1.0f ); + uv12.Init( 0.0f, 0.5f + ( tan(fl90degrees * 3.0f - flEndAngle) * 0.5 ) ); + + verts[0].Init( Vector2D( flHalfWide, flHalfTall ), uv11 ); + verts[1].Init( Vector2D( flHalfWide, tall ), uv21 ); + verts[2].Init( Vector2D( 0.0f, tall ), uv22 ); + verts[3].Init( Vector2D( 0.0f, flHalfTall + ( tan(fl90degrees * 3.0f - flEndAngle) * flHalfWide ) ), uv12 ); + + vgui::surface()->DrawTexturedPolygon( 4, verts ); + } + else // <= 225 degrees + { + uv11.Init( 0.5f, 0.5f ); + uv21.Init( 0.5f, 1.0f ); + uv22.Init( 0.5f - ( tan( flEndAngle - fl90degrees * 2.0f) * 0.5 ), 1.0f ); + uv12.Init( 0.5f, 0.5f ); + + verts[0].Init( Vector2D( flHalfWide, flHalfTall ), uv11 ); + verts[1].Init( Vector2D( flHalfWide, tall ), uv21 ); + verts[2].Init( Vector2D( flHalfWide - ( tan(flEndAngle - fl90degrees * 2.0f) * flHalfTall ), tall ), uv22 ); + verts[3].Init( Vector2D( flHalfWide, flHalfTall ), uv12 ); + + vgui::surface()->DrawTexturedPolygon( 4, verts ); + } + } + else if ( flEndAngle >= fl90degrees ) // >= 90 degrees + { + // draw the first quadrant + uv11.Init( 0.5f, 0.0f ); + uv21.Init( 1.0f, 0.0f ); + uv22.Init( 1.0f, 0.5f ); + uv12.Init( 0.5f, 0.5f ); + + verts[0].Init( Vector2D( flHalfWide, 0.0f ), uv11 ); + verts[1].Init( Vector2D( wide, 0.0f ), uv21 ); + verts[2].Init( Vector2D( wide, flHalfTall ), uv22 ); + verts[3].Init( Vector2D( flHalfWide, flHalfTall ), uv12 ); + + vgui::surface()->DrawTexturedPolygon( 4, verts ); + + // draw the partial second quadrant + if ( flEndAngle > fl90degrees * 1.5f ) // > 135 degrees + { + uv11.Init( 0.5f, 0.5f ); + uv21.Init( 1.0f, 0.5f ); + uv22.Init( 1.0f, 1.0f ); + uv12.Init( 0.5f + ( tan(fl90degrees * 2.0f - flEndAngle) * 0.5f ), 1.0f ); + + verts[0].Init( Vector2D( flHalfWide, flHalfTall ), uv11 ); + verts[1].Init( Vector2D( wide, flHalfTall ), uv21 ); + verts[2].Init( Vector2D( wide, tall ), uv22 ); + verts[3].Init( Vector2D( flHalfWide + ( tan(fl90degrees * 2.0f - flEndAngle) * flHalfTall ), tall ), uv12 ); + + vgui::surface()->DrawTexturedPolygon( 4, verts ); + } + else // <= 135 degrees + { + uv11.Init( 0.5f, 0.5f ); + uv21.Init( 1.0f, 0.5f ); + uv22.Init( 1.0f, 0.5f + ( tan(flEndAngle - fl90degrees) * 0.5f ) ); + uv12.Init( 0.5f, 0.5f ); + + verts[0].Init( Vector2D( flHalfWide, flHalfTall ), uv11 ); + verts[1].Init( Vector2D( wide, flHalfTall ), uv21 ); + verts[2].Init( Vector2D( wide, flHalfTall + ( tan(flEndAngle - fl90degrees) * flHalfWide ) ), uv22 ); + verts[3].Init( Vector2D( flHalfWide, flHalfTall ), uv12 ); + + vgui::surface()->DrawTexturedPolygon( 4, verts ); + } + } + else // > 0 degrees + { + if ( flEndAngle > fl90degrees / 2.0f ) // > 45 degrees + { + uv11.Init( 0.5f, 0.0f ); + uv21.Init( 1.0f, 0.0f ); + uv22.Init( 1.0f, 0.5f - ( tan(fl90degrees - flEndAngle) * 0.5 ) ); + uv12.Init( 0.5f, 0.5f ); + + verts[0].Init( Vector2D( flHalfWide, 0.0f ), uv11 ); + verts[1].Init( Vector2D( wide, 0.0f ), uv21 ); + verts[2].Init( Vector2D( wide, flHalfTall - ( tan(fl90degrees - flEndAngle) * flHalfWide ) ), uv22 ); + verts[3].Init( Vector2D( flHalfWide, flHalfTall ), uv12 ); + + vgui::surface()->DrawTexturedPolygon( 4, verts ); + } + else // <= 45 degrees + { + uv11.Init( 0.5f, 0.0f ); + uv21.Init( 0.5 + ( tan(flEndAngle) * 0.5 ), 0.0f ); + uv22.Init( 0.5f, 0.5f ); + uv12.Init( 0.5f, 0.0f ); + + verts[0].Init( Vector2D( flHalfWide, 0.0f ), uv11 ); + verts[1].Init( Vector2D( flHalfWide + ( tan(flEndAngle) * flHalfTall ), 0.0f ), uv21 ); + verts[2].Init( Vector2D( flHalfWide, flHalfTall ), uv22 ); + verts[3].Init( Vector2D( flHalfWide, 0.0f ), uv12 ); + + vgui::surface()->DrawTexturedPolygon( 4, verts ); + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +CDoDCapturePanelIcon::CDoDCapturePanelIcon( vgui::Panel *parent, const char *name ) : vgui::ImagePanel( parent, name ) +{ + m_bActive = false; + + m_iTexture = vgui::surface()->DrawGetTextureId( "vgui/capture_icon" ); + if ( m_iTexture == -1 ) // we didn't find it, so create a new one + { + m_iTexture = vgui::surface()->CreateNewTextureID(); + } + + vgui::surface()->DrawSetTextureFile( m_iTexture, "vgui/capture_icon", true, false ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CDoDCapturePanelIcon::Paint() +{ + int wide, tall; + GetSize( wide, tall ); + + float uv1 = 0.0f, uv2 = 1.0f; + Vector2D uv11( uv1, uv1 ); + Vector2D uv12( uv1, uv2 ); + Vector2D uv21( uv2, uv1 ); + Vector2D uv22( uv2, uv2 ); + + vgui::Vertex_t verts[4]; + verts[0].Init( Vector2D( 0, 0 ), uv11 ); + verts[1].Init( Vector2D( wide, 0 ), uv21 ); + verts[2].Init( Vector2D( wide, tall ), uv22 ); + verts[3].Init( Vector2D( 0, tall ), uv12 ); + + // just draw the whole thing + vgui::surface()->DrawSetTexture( m_iTexture ); + vgui::surface()->DrawSetColor( m_bActive ? m_clrActive : m_clrInActive ); + vgui::surface()->DrawTexturedPolygon( 4, verts ); +} + +//----------------------------------------------------------------------------- +// Purpose: Constructor +//----------------------------------------------------------------------------- +CDoDHudCapturePanel::CDoDHudCapturePanel( const char *pElementName ) : CHudElement( pElementName ), BaseClass( NULL, "HudCapturePanel" ) +{ + SetParent( g_pClientMode->GetViewport() ); + + m_pBackground = new vgui::Panel( this, "CapturePanelBackground" ); + m_pProgressBar = new CDoDCapturePanelProgressBar( this, "CapturePanelProgressBar" ); + + for ( int i = 0 ; i < 5 ; i++ ) + { + CDoDCapturePanelIcon *pPanel; + char szName[64]; + + Q_snprintf( szName, sizeof( szName ), "CapturePanelPlayerIcon%d", i + 1 ); + pPanel = new CDoDCapturePanelIcon( this, szName ); + + m_PlayerIcons.AddToTail( pPanel ); + } + + m_pAlliesFlag = new vgui::ImagePanel( this, "CapturePanelAlliesFlag" ); + m_pAxisFlag = new vgui::ImagePanel( this, "CapturePanelAxisFlag" ); + m_pNeutralFlag = new vgui::ImagePanel( this, "CapturePanelNeutralFlag" ); + + m_pMessage = new vgui::Label( this, "CapturePanelMessage", " " ); + + // load control settings... + LoadControlSettings( "resource/UI/HudCapturePanel.res" ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CDoDHudCapturePanel::OnScreenSizeChanged( int iOldWide, int iOldTall ) +{ + LoadControlSettings( "resource/UI/HudCapturePanel.res" ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CDoDHudCapturePanel::ApplySchemeSettings( vgui::IScheme *pScheme ) +{ + BaseClass::ApplySchemeSettings( pScheme ); + + if ( m_pBackground ) + { + m_pBackground->SetBgColor( GetSchemeColor( "HintMessageBg", pScheme ) ); + m_pBackground->SetPaintBackgroundType( 2 ); + } + + SetFgColor( GetSchemeColor( "HudProgressBar.Active", pScheme ) ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CDoDHudCapturePanel::OnThink() +{ + BaseClass::OnThink(); + + C_DODPlayer *pPlayer = C_DODPlayer::GetLocalDODPlayer(); + + if ( pPlayer ) + { + int iCPIndex = pPlayer->GetCPIndex(); + bool bInCapZone = ( iCPIndex >= 0 ); + + // turn off the panel and children if the player is dead or not in a cap zone + if ( !pPlayer->IsAlive() ) + { + if ( IsVisible() ) + { + SetVisible( false ); + } + return; + } + + if ( !bInCapZone || !hud_capturepanel.GetBool() ) + { + // see if the player progress bar wants to draw + + // then return, we're not in an area cap + if ( pPlayer->m_iProgressBarDuration > 0 && pPlayer ) + { + if ( !IsVisible() ) + { + SetVisible( true ); + } + + // hide the other stuff + m_pAlliesFlag->SetVisible( false ); + m_pAxisFlag->SetVisible( false ); + m_pNeutralFlag->SetVisible( false ); + + m_pMessage->SetVisible( false ); + + int i; + for ( i = 0 ; i < m_PlayerIcons.Count() ; i++ ) + { + m_PlayerIcons[i]->SetVisible( false ); + } + + // turn on the progress bar, we're capping + if ( m_pProgressBar ) + { + if ( !m_pProgressBar->IsVisible() ) + { + m_pProgressBar->SetVisible( true ); + } + + float flPercent = (pPlayer->m_flSimulationTime - pPlayer->m_flProgressBarStartTime) / (float)pPlayer->m_iProgressBarDuration; + flPercent = clamp( flPercent, 0, 1 ); + + m_pProgressBar->SetPercentage( flPercent ); + } + } + else + { + if ( IsVisible() ) + { + SetVisible( false ); + } + } + return; + } + + int nOwningTeam = g_pObjectiveResource->GetOwningTeam( iCPIndex ); + int nPlayerTeam = pPlayer->GetTeamNumber(); + + int nNumTeammates = g_pObjectiveResource->GetNumPlayersInArea( iCPIndex, nPlayerTeam == TEAM_ALLIES ? TEAM_ALLIES : TEAM_AXIS ); + int nRequiredTeammates = g_pObjectiveResource->GetRequiredCappers( iCPIndex, nPlayerTeam == TEAM_ALLIES ? TEAM_ALLIES : TEAM_AXIS ); + + int nNumEnemies = g_pObjectiveResource->GetNumPlayersInArea( iCPIndex, nPlayerTeam == TEAM_ALLIES ? TEAM_AXIS : TEAM_ALLIES ); + int nRequiredEnemies = g_pObjectiveResource->GetRequiredCappers( iCPIndex, nPlayerTeam == TEAM_ALLIES ? TEAM_AXIS : TEAM_ALLIES ); + + int iCappingTeam = g_pObjectiveResource->GetCappingTeam( iCPIndex ); + + // if we already own this capture point and there are no enemies in the area + if ( nOwningTeam == nPlayerTeam && nNumEnemies < nRequiredEnemies ) + { + // don't need to do anything + if ( IsVisible() ) + { + SetVisible( false ); + } + return; + } + + // okay, turn on the capture point panel + if ( !IsVisible() ) + { + SetVisible( true ); + } + + // set the correct flag image + switch( nOwningTeam ) + { + case TEAM_ALLIES: + if ( m_pAlliesFlag && !m_pAlliesFlag->IsVisible() ) + m_pAlliesFlag->SetVisible( true ); + if ( m_pAxisFlag && m_pAxisFlag->IsVisible() ) + m_pAxisFlag->SetVisible( false ); + if ( m_pNeutralFlag && m_pNeutralFlag->IsVisible() ) + m_pNeutralFlag->SetVisible( false ); + break; + case TEAM_AXIS: + if ( m_pAlliesFlag && m_pAlliesFlag->IsVisible() ) + m_pAlliesFlag->SetVisible( false ); + if ( m_pAxisFlag && !m_pAxisFlag->IsVisible() ) + m_pAxisFlag->SetVisible( true ); + if ( m_pNeutralFlag && m_pNeutralFlag->IsVisible() ) + m_pNeutralFlag->SetVisible( false ); + break; + default: + if ( m_pAlliesFlag && m_pAlliesFlag->IsVisible() ) + m_pAlliesFlag->SetVisible( false ); + if ( m_pAxisFlag && m_pAxisFlag->IsVisible() ) + m_pAxisFlag->SetVisible( false ); + if ( m_pNeutralFlag && !m_pNeutralFlag->IsVisible() ) + m_pNeutralFlag->SetVisible( true ); + break; + } + + // arrange the player icons + int i = 0; + for ( i = 0 ; i < m_PlayerIcons.Count() ; i++ ) + { + CDoDCapturePanelIcon *pPanel = m_PlayerIcons[i]; + + if ( !pPanel ) + { + continue; + } + + if ( i < nRequiredTeammates ) + { + if ( i < nNumTeammates ) + { + pPanel->SetActive( true ); + + if ( !pPanel->IsVisible() ) + pPanel->SetVisible( true ); + } + else + { + pPanel->SetActive( false ); + + if ( !pPanel->IsVisible() ) + pPanel->SetVisible( true ); + } + } + else + { + if ( pPanel->IsVisible() ) + pPanel->SetVisible( false ); + } + } + + int wide = 0, tall = 0, iconWide = 0, iconTall = 0; + GetSize( wide, tall ); + + vgui::ImagePanel *pPanel = m_PlayerIcons[0]; + if ( pPanel ) + pPanel->GetSize( iconWide, iconTall ); + + int width = ( nRequiredTeammates * iconWide ) + ( ( nRequiredTeammates - 1 ) * m_nSpaceBetweenIcons ); + int xpos = wide / 2.0 - width / 2.0; + + // rearrange the player icon panels + for ( i = 0 ; i < nRequiredTeammates ; i++ ) + { + CDoDCapturePanelIcon *pPanel = m_PlayerIcons[i]; + + if ( pPanel ) + { + int x, y, w, t; + pPanel->GetBounds( x, y, w, t ); + pPanel->SetBounds( xpos, y, w, t ); + } + + xpos += iconWide + m_nSpaceBetweenIcons; + } + + // are we capping an area? + if ( iCappingTeam == TEAM_UNASSIGNED || iCappingTeam != nPlayerTeam ) + { + // turn off the progress bar, we're not capping + if ( m_pProgressBar && m_pProgressBar->IsVisible() ) + { + m_pProgressBar->SetVisible( false ); + } + + // turn on the message + if ( m_pMessage ) + { + m_pMessage->SetFgColor( GetFgColor() ); + + if ( !m_pMessage->IsVisible() ) + { + m_pMessage->SetVisible( true ); + } + + if ( nNumTeammates >= nRequiredTeammates && nNumEnemies > 0 ) + { + m_pMessage->SetText( "#Dod_Capture_Blocked" ); + } + else if ( nNumEnemies > 0 /*nNumEnemies >= nRequiredEnemies*/ ) + { + m_pMessage->SetText( "#Dod_Blocking_Capture" ); + } + else + { + m_pMessage->SetText( "#Dod_Waiting_for_teammate" ); + } + + if ( m_pBackground ) + { + // do we need to resize our background? + int textW, textH, bgX, bgY, bgW, bgH; + m_pMessage->GetContentSize( textW, textH ); + m_pBackground->GetBounds( bgX, bgY, bgW, bgH ); + + if ( bgW < textW ) + { + m_pBackground->SetBounds( bgX + ( bgW / 2.0 ) - ( ( textW + XRES(3) ) / 2.0 ), bgY, textW + XRES(3), bgH ); + } + } + } + } + else + { + // turn on the progress bar, we're capping + if ( m_pProgressBar ) + { + if ( !m_pProgressBar->IsVisible() ) + { + m_pProgressBar->SetVisible( true ); + } + + m_pProgressBar->SetPercentage( g_pObjectiveResource->GetCPCapPercentage( pPlayer->GetCPIndex() ) ); + } + + // turn off the message + if ( m_pMessage && m_pMessage->IsVisible() ) + { + m_pMessage->SetVisible( false ); + } + } + } +} + + diff --git a/game/client/dod/dod_hud_capturepanel.h b/game/client/dod/dod_hud_capturepanel.h new file mode 100644 index 0000000..014236c --- /dev/null +++ b/game/client/dod/dod_hud_capturepanel.h @@ -0,0 +1,91 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef DOD_HUD_CAPTUREPANEL_H +#define DOD_HUD_CAPTUREPANEL_H +#ifdef _WIN32 +#pragma once +#endif + +//----------------------------------------------------------------------------- +// Purpose: Draws the progress bar +//----------------------------------------------------------------------------- +class CDoDCapturePanelProgressBar : public vgui::ImagePanel +{ +public: + DECLARE_CLASS_SIMPLE( CDoDCapturePanelProgressBar, vgui::ImagePanel ); + + CDoDCapturePanelProgressBar( vgui::Panel *parent, const char *name ); + + virtual void Paint(); + + void SetPercentage( float flPercentage ){ m_flPercent = flPercentage; } + +private: + + float m_flPercent; + int m_iTexture; + + CPanelAnimationVar( Color, m_clrActive, "color_active", "HudCaptureProgressBar.Active" ); + CPanelAnimationVar( Color, m_clrInActive, "color_inactive", "HudCaptureProgressBar.InActive" ); +}; + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class CDoDCapturePanelIcon : public vgui::ImagePanel +{ +public: + DECLARE_CLASS_SIMPLE( CDoDCapturePanelIcon, vgui::ImagePanel ); + + CDoDCapturePanelIcon( vgui::Panel *parent, const char *name ); + + virtual void Paint(); + + void SetActive( bool state ){ m_bActive = state; } + +private: + + bool m_bActive; + int m_iTexture; + + CPanelAnimationVar( Color, m_clrActive, "color_active", "HudCaptureIcon.Active" ); + CPanelAnimationVar( Color, m_clrInActive, "color_inactive", "HudCaptureIcon.InActive" ); +}; + +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- +class CDoDHudCapturePanel : public CHudElement, public vgui::EditablePanel +{ +public: + DECLARE_CLASS_SIMPLE( CDoDHudCapturePanel, vgui::EditablePanel ); + + CDoDHudCapturePanel( const char *pElementName ); + + virtual void OnThink(); + virtual void ApplySchemeSettings( vgui::IScheme *pScheme ); + virtual void OnScreenSizeChanged( int iOldWide, int iOldTall ); + +private: + + CDoDCapturePanelProgressBar *m_pProgressBar; + + CUtlVector<CDoDCapturePanelIcon *> m_PlayerIcons; + + vgui::ImagePanel *m_pAlliesFlag; + vgui::ImagePanel *m_pAxisFlag; + vgui::ImagePanel *m_pNeutralFlag; + + vgui::Label *m_pMessage; + + vgui::Panel *m_pBackground; + + CPanelAnimationVarAliasType( float, m_nSpaceBetweenIcons, "icon_space", "2", "proportional_float" ); +}; + +#endif // DOD_HUD_CAPTUREPANEL_H
\ No newline at end of file diff --git a/game/client/dod/dod_hud_chat.cpp b/game/client/dod/dod_hud_chat.cpp new file mode 100644 index 0000000..9dff533 --- /dev/null +++ b/game/client/dod/dod_hud_chat.cpp @@ -0,0 +1,533 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#include "cbase.h" +#include "dod_hud_chat.h" +#include "c_dod_player.h" +#include "c_dod_playerresource.h" +#include "hud_macros.h" +#include "text_message.h" +#include "vguicenterprint.h" +#include "vgui/ILocalize.h" +#include "dodoverview.h" +#include <voice_status.h> +#include "menu.h" // for CHudMenu defs +#include "dod_hud_freezepanel.h" + +ConVar cl_voicesubtitles( "cl_voicesubtitles", "1", 0, "Enable/disable subtitle printing on voice commands and hand signals." ); + +Color g_DoDColorGrey( 200, 200, 200, 255 ); + +#define DOD_MAX_CHAT_LENGTH 128 + +// Stuff for the Radio Menus +static void voicemenu1_f( void ); +static void voicemenu2_f( void ); +static void voicemenu3_f( void ); + +static ConCommand voicemenu1( "voicemenu1", voicemenu1_f, "Opens a voice menu" ); +static ConCommand voicemenu2( "voicemenu2", voicemenu2_f, "Opens a voice menu" ); +static ConCommand voicemenu3( "voicemenu3", voicemenu3_f, "Opens a voice menu" ); + + +// +//-------------------------------------------------------------- +// +// These methods will bring up the radio menus from the client side. +// They mimic the old server commands of the same name, which used +// to require a round-trip causing latency and unreliability in +// menu responses. Only 1 message is sent to the server now which +// includes both the menu name and the selected item. The server +// is never informed that the menu has been displayed. +// +//-------------------------------------------------------------- +// + +static int g_ActiveVoiceMenu = 0; + +void OpenVoiceMenu( int index ) +{ + // do not show the menu if the player is dead or is an observer + C_DODPlayer *pPlayer = C_DODPlayer::GetLocalDODPlayer(); + if ( !pPlayer ) + return; + + if ( !pPlayer->IsAlive() || pPlayer->IsObserver() ) + return; + + CHudMenu *pMenu = (CHudMenu *) gHUD.FindElement( "CHudMenu" ); + if ( !pMenu ) + return; + + // if they hit the key again, close the menu + if ( g_ActiveVoiceMenu == index ) + { + pMenu->HideMenu(); + g_ActiveVoiceMenu = 0; + return; + } + + switch( index ) + { + case 1: + case 2: + case 3: + { + char *pszNation; + + if( pPlayer->GetTeamNumber() == TEAM_ALLIES ) + { + pszNation = "Amer"; + } + else + { + pszNation = "Ger"; + } + + char cMenuNumber = 'A' + index - 1; // map 1,2,3 to A,B,C + + char szMenu[128]; + Q_snprintf( szMenu, sizeof(szMenu), "#Menu_%sVoice%c", pszNation, cMenuNumber ); + + pMenu->ShowMenu( szMenu, 0x3FF ); + + g_ActiveVoiceMenu = index; + } + break; + case 0: + default: + g_ActiveVoiceMenu = 0; + break; + } +} + +static void voicemenu1_f( void ) +{ + OpenVoiceMenu( 1 ); +} + +static void voicemenu2_f( void ) +{ + OpenVoiceMenu( 2 ); +} + +static void voicemenu3_f( void ) +{ + OpenVoiceMenu( 3 ); +} + +CON_COMMAND( menuselect, "menuselect" ) +{ + if ( args.ArgC() < 2 ) + return; + + int iSlot = atoi( args[1] ); + + switch( g_ActiveVoiceMenu ) + { + case 1: //RadioA + case 2: + case 3: + { + // check for cancel + if( iSlot == 10 ) + { + g_ActiveVoiceMenu = 0; + return; + } + + // find the voice command index from the menu and slot + int iVoiceCommand = (g_ActiveVoiceMenu-1) * 9 + (iSlot-1); + + Assert( iVoiceCommand >= 0 && iVoiceCommand < (3*9) ); + + // emit a voice command + engine->ClientCmd( g_VoiceCommands[iVoiceCommand].pszCommandName ); + } + break; + case 0: + default: + // if we didn't have a menu open, maybe a plugin did. send it on to the server. + const char *cmd = VarArgs( "menuselect %d", iSlot ); + engine->ServerCmd( cmd ); + break; + } + + // reset menu + g_ActiveVoiceMenu = 0; +} + +DECLARE_HUDELEMENT( CHudChat ); + +DECLARE_HUD_MESSAGE( CHudChat, SayText ); +DECLARE_HUD_MESSAGE( CHudChat, TextMsg ); +DECLARE_HUD_MESSAGE( CHudChat, VoiceSubtitle ); +DECLARE_HUD_MESSAGE( CHudChat, HandSignalSubtitle ); + + +//===================== +//CHudChatLine +//===================== + +CHudChatLine::CHudChatLine( vgui::Panel *parent, const char *panelName ) : CBaseHudChatLine( parent, panelName ) +{ + m_text = NULL; +} + +void CHudChatLine::ApplySchemeSettings(vgui::IScheme *pScheme) +{ + BaseClass::ApplySchemeSettings( pScheme ); +} + +//===================== +//CHudChatInputLine +//===================== + +void CHudChatInputLine::ApplySchemeSettings(vgui::IScheme *pScheme) +{ + BaseClass::ApplySchemeSettings(pScheme); +} + + + +//===================== +//CHudChat +//===================== + +CHudChat::CHudChat( const char *pElementName ) : BaseClass( pElementName ) +{ + +} + +void CHudChat::CreateChatInputLine( void ) +{ + m_pChatInput = new CHudChatInputLine( this, "ChatInputLine" ); + m_pChatInput->SetVisible( false ); +} + +void CHudChat::CreateChatLines( void ) +{ + m_ChatLine = new CHudChatLine( this, "ChatLine1" ); + m_ChatLine->SetVisible( false ); +} + +void CHudChat::ApplySchemeSettings( vgui::IScheme *pScheme ) +{ + BaseClass::ApplySchemeSettings( pScheme ); +} + + +void CHudChat::Init( void ) +{ + BaseClass::Init(); + + HOOK_HUD_MESSAGE( CHudChat, SayText ); + HOOK_HUD_MESSAGE( CHudChat, TextMsg ); + HOOK_HUD_MESSAGE( CHudChat, VoiceSubtitle ); + HOOK_HUD_MESSAGE( CHudChat, HandSignalSubtitle ); +} + +//----------------------------------------------------------------------------- +// Purpose: Overrides base reset to not cancel chat at round restart +//----------------------------------------------------------------------------- +void CHudChat::Reset( void ) +{ +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *pszName - +// iSize - +// *pbuf - +//----------------------------------------------------------------------------- +void CHudChat::MsgFunc_SayText( bf_read &msg ) +{ + // Got message during connection + if ( !g_PR ) + return; + + char szString[DOD_MAX_CHAT_LENGTH]; + + int client = msg.ReadByte(); + msg.ReadString( szString, sizeof(szString) ); + bool bWantsToChat = msg.ReadByte(); + + if ( GetClientVoiceMgr()->IsPlayerBlocked( client ) ) + return; + + if ( client > 0 ) + GetDODOverview()->PlayerChat( client ); + + if ( bWantsToChat ) + { + int iFilter = CHAT_FILTER_NONE; + + if ( client > 0 && (g_PR->GetTeam( client ) != g_PR->GetTeam( GetLocalPlayerIndex() )) ) + { + iFilter = CHAT_FILTER_PUBLICCHAT; + } + + // Localize any words in the chat that start with # + FindLocalizableSubstrings( szString, sizeof(szString) ); + + // print raw chat text + ChatPrintf( client, iFilter, "%c%s", COLOR_USEOLDCOLORS, szString ); + } + else + { + // try to lookup translated string + Printf( GetFilterForString( szString ), "%s", hudtextmessage->LookupString( szString ) ); + } + + Msg( "%s", szString ); +} + +void CHudChat::MsgFunc_VoiceSubtitle( bf_read &msg ) +{ + // Got message during connection + if ( !g_PR ) + return; + + if ( !cl_showtextmsg.GetInt() ) + return; + + if ( !cl_voicesubtitles.GetInt() ) + return; + + char szString[2048]; + char szPrefix[64]; //(Voice) + wchar_t szBuf[128]; + + int client = msg.ReadByte(); + + if ( GetClientVoiceMgr()->IsPlayerBlocked( client ) ) + return; + + if ( client > 0 ) + GetDODOverview()->PlayerChat( client ); + + int iTeam = msg.ReadByte(); + int iVoiceCommand = msg.ReadByte(); + + //Assert( iVoiceCommand <= ARRAYSIZE(g_VoiceCommands) ); + Assert( iTeam == TEAM_ALLIES || iTeam == TEAM_AXIS ); + + const char *pszSubtitle = g_VoiceCommands[iVoiceCommand].pszAlliedSubtitle; + + if( iTeam == TEAM_AXIS && g_VoiceCommands[iVoiceCommand].pszAxisSubtitle != NULL ) + pszSubtitle = g_VoiceCommands[iVoiceCommand].pszAxisSubtitle; + + const wchar_t *pBuf = g_pVGuiLocalize->Find( pszSubtitle ); + if ( pBuf ) + { + // Copy pBuf into szBuf[i]. + int nMaxChars = sizeof( szBuf ) / sizeof( wchar_t ); + wcsncpy( szBuf, pBuf, nMaxChars ); + szBuf[nMaxChars-1] = 0; + } + else + { + g_pVGuiLocalize->ConvertANSIToUnicode( pszSubtitle, szBuf, sizeof(szBuf) ); + } + + int len; + g_pVGuiLocalize->ConvertUnicodeToANSI( szBuf, szString, sizeof(szString) ); + len = strlen( szString ); + if ( len && szString[len-1] != '\n' && szString[len-1] != '\r' ) + { + Q_strncat( szString, "\n", sizeof(szString), 1 ); + } + + const wchar_t *pVoicePrefix = g_pVGuiLocalize->Find( "#Voice" ); + g_pVGuiLocalize->ConvertUnicodeToANSI( pVoicePrefix, szPrefix, sizeof(szPrefix) ); + + ChatPrintf( client, CHAT_FILTER_NONE, "%c(%s) %s%c: %s", COLOR_PLAYERNAME, szPrefix, g_PR->GetPlayerName( client ), COLOR_NORMAL, ConvertCRtoNL( szString ) ); +} + +void CHudChat::MsgFunc_HandSignalSubtitle( bf_read &msg ) +{ + // Got message during connection + if ( !g_PR ) + return; + + if ( !cl_showtextmsg.GetInt() ) + return; + + if ( !cl_voicesubtitles.GetInt() ) + return; + + char szString[2048]; + char szPrefix[64]; //(HandSignal) + wchar_t szBuf[128]; + + int client = msg.ReadByte(); + int iSignal = msg.ReadByte(); + + if ( GetClientVoiceMgr()->IsPlayerBlocked( client ) ) + return; + + if ( client > 0 ) + GetDODOverview()->PlayerChat( client ); + + const char *pszSubtitle = g_HandSignals[iSignal].pszSubtitle; + + const wchar_t *pBuf = g_pVGuiLocalize->Find( pszSubtitle ); + if ( pBuf ) + { + // Copy pBuf into szBuf[i]. + int nMaxChars = sizeof( szBuf ) / sizeof( wchar_t ); + wcsncpy( szBuf, pBuf, nMaxChars ); + szBuf[nMaxChars-1] = 0; + } + else + { + g_pVGuiLocalize->ConvertANSIToUnicode( pszSubtitle, szBuf, sizeof(szBuf) ); + } + + int len; + g_pVGuiLocalize->ConvertUnicodeToANSI( szBuf, szString, sizeof(szString) ); + len = strlen( szString ); + if ( len && szString[len-1] != '\n' && szString[len-1] != '\r' ) + { + Q_strncat( szString, "\n", sizeof(szString), 1 ); + } + + const wchar_t *pVoicePrefix = g_pVGuiLocalize->Find( "#HandSignal" ); + g_pVGuiLocalize->ConvertUnicodeToANSI( pVoicePrefix, szPrefix, sizeof(szPrefix) ); + + Assert( g_PR ); + + ChatPrintf( client, CHAT_FILTER_NONE, "%c(%s) %s%c: %s", COLOR_USEOLDCOLORS, szPrefix, g_PR->GetPlayerName( client ), COLOR_NORMAL, ConvertCRtoNL( szString ) ); +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +int CHudChat::GetChatInputOffset( void ) +{ + if ( m_pChatInput->IsVisible() ) + { + return m_iFontHeight; + } + else + { + return 0; + } +} + +wchar_t* ReadLocalizedVoiceCommandString( bf_read &msg, wchar_t *pOut, int outSize, bool bStripNewline ) +{ + char szString[2048]; + msg.ReadString( szString, sizeof(szString) ); + + const wchar_t *pBuf = g_pVGuiLocalize->Find( szString ); + if ( pBuf ) + { + wcsncpy( pOut, pBuf, outSize/sizeof(wchar_t) ); + pOut[outSize/sizeof(wchar_t)-1] = 0; + } + else + { + g_pVGuiLocalize->ConvertANSIToUnicode( szString, pOut, outSize ); + } + + if ( bStripNewline ) + StripEndNewlineFromString( pOut ); + + return pOut; +} + +// Find words in the chat that can be localized and replace them with localized text +void CHudChat::FindLocalizableSubstrings( char *szChat, int chatLength ) +{ + static char buf[DOD_MAX_CHAT_LENGTH]; + buf[0] = '\0'; + + int pos = 0; + + static char szTemp[DOD_MAX_CHAT_LENGTH]; + + wchar_t *pwcLocalized; + + for ( char *pSrc = szChat; pSrc != NULL && *pSrc != 0 && pos < chatLength-1; pSrc++ ) + { + // if its a # + if ( *pSrc == '#' ) + { + // trim into a word + char *pWord = pSrc; + int iWordPos = 0; + while ( *pWord != ' ' && + *pWord != '\0' && + *pWord != '\n' ) + { + szTemp[iWordPos] = *pWord; + iWordPos++; + pWord++; + } + + szTemp[iWordPos] = '\0'; + + pwcLocalized = g_pVGuiLocalize->Find( szTemp ); + + // localize word + + if ( pwcLocalized ) + { + // print it into the buf + g_pVGuiLocalize->ConvertUnicodeToANSI( pwcLocalized, szTemp, sizeof(szTemp) ); + } + + // copy the string to chat + buf[pos] = '\0'; + Q_strncat( buf, szTemp, DOD_MAX_CHAT_LENGTH, COPY_ALL_CHARACTERS ); + + int remainingSpace = chatLength - pos - 2; // minus one for the NULL and one for the space + pos += MIN( Q_strlen(szTemp), remainingSpace ); + + pSrc += iWordPos-1; // progress pSrc to the end of the word + } + else + { + // copy each char across + buf[pos] = *pSrc; + pos++; + } + } + + buf[pos] = '\0'; + pos++; + + //copy buf back to szChat + Q_strncpy( szChat, buf, MIN(chatLength, pos) ); +} + +Color CHudChat::GetDefaultTextColor( void ) +{ + return g_DoDColorGrey; +} + +Color CHudChat::GetClientColor( int clientIndex ) +{ + // If player resource is bogus, return some obvious colour + // or if we want a generic colour + if ( !g_PR || clientIndex < 1 ) + return GetDefaultTextColor(); + + return g_PR->GetTeamColor( g_PR->GetTeam( clientIndex ) ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +bool CHudChat::IsVisible( void ) +{ + if ( IsTakingAFreezecamScreenshot() ) + return false; + + return BaseClass::IsVisible(); +}
\ No newline at end of file diff --git a/game/client/dod/dod_hud_chat.h b/game/client/dod/dod_hud_chat.h new file mode 100644 index 0000000..cabe793 --- /dev/null +++ b/game/client/dod/dod_hud_chat.h @@ -0,0 +1,74 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef DOD_HUD_CHAT_H +#define DOD_HUD_CHAT_H +#ifdef _WIN32 +#pragma once +#endif + +#include <hud_basechat.h> + +//----------------------------------------------------------------------------- + +class CHudChatLine : public CBaseHudChatLine +{ + DECLARE_CLASS_SIMPLE( CHudChatLine, CBaseHudChatLine ); + +public: + CHudChatLine( vgui::Panel *parent, const char *panelName ); + + virtual void ApplySchemeSettings(vgui::IScheme *pScheme); + void MsgFunc_SayText(bf_read &msg); + +private: + CHudChatLine( const CHudChatLine & ); // not defined, not accessible + +}; + +//----------------------------------------------------------------------------- +// Purpose: The prompt and text entry area for chat messages +//----------------------------------------------------------------------------- +class CHudChatInputLine : public CBaseHudChatInputLine +{ + DECLARE_CLASS_SIMPLE( CHudChatInputLine, CBaseHudChatInputLine ); + +public: + CHudChatInputLine( CBaseHudChat *parent, char const *panelName ) : CBaseHudChatInputLine( parent, panelName ) {} + + virtual void ApplySchemeSettings(vgui::IScheme *pScheme); +}; + +class CHudChat : public CBaseHudChat +{ + DECLARE_CLASS_SIMPLE( CHudChat, CBaseHudChat ); + +public: + CHudChat( const char *pElementName ); + + virtual void CreateChatInputLine( void ); + virtual void CreateChatLines( void ); + + virtual void Init( void ); + virtual void Reset( void ); + virtual void ApplySchemeSettings(vgui::IScheme *pScheme); + + void MsgFunc_SayText( bf_read &msg ); + virtual void MsgFunc_VoiceSubtitle( bf_read &msg ); + void MsgFunc_HandSignalSubtitle( bf_read &msg ); + int GetChatInputOffset( void ); + + void FindLocalizableSubstrings( char *szChat, int chatLength ); + + virtual Color GetDefaultTextColor( void ); + virtual Color GetClientColor( int clientIndex ); + + virtual bool IsVisible( void ); + +}; + +#endif //DOD_HUD_CHAT_H
\ No newline at end of file diff --git a/game/client/dod/dod_hud_crosshair.cpp b/game/client/dod/dod_hud_crosshair.cpp new file mode 100644 index 0000000..7b9c719 --- /dev/null +++ b/game/client/dod/dod_hud_crosshair.cpp @@ -0,0 +1,183 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#include "cbase.h" +#include "hudelement.h" +#include <vgui_controls/Panel.h> +#include <vgui/ISurface.h> +#include "clientmode.h" +#include "c_dod_player.h" +#include "dod_hud_crosshair.h" +#include "materialsystem/imaterial.h" +#include "materialsystem/imesh.h" +#include "materialsystem/imaterialvar.h" +#include "mathlib/mathlib.h" + +ConVar cl_crosshair_red( "cl_crosshair_red", "200", FCVAR_ARCHIVE ); +ConVar cl_crosshair_green( "cl_crosshair_green", "200", FCVAR_ARCHIVE ); +ConVar cl_crosshair_blue( "cl_crosshair_blue", "200", FCVAR_ARCHIVE ); +ConVar cl_crosshair_alpha( "cl_crosshair_alpha", "200", FCVAR_ARCHIVE ); + +ConVar cl_crosshair_file( "cl_crosshair_file", "crosshair1", FCVAR_ARCHIVE ); + +ConVar cl_crosshair_scale( "cl_crosshair_scale", "32.0", FCVAR_ARCHIVE ); +ConVar cl_crosshair_approach_speed( "cl_crosshair_approach_speed", "0.015" ); + +ConVar cl_dynamic_crosshair( "cl_dynamic_crosshair", "1", FCVAR_ARCHIVE ); + +using namespace vgui; + +DECLARE_HUDELEMENT( CHudDODCrosshair ); + +CHudDODCrosshair::CHudDODCrosshair( const char *pName ) : + vgui::Panel( NULL, "HudDODCrosshair" ), CHudElement( pName ) +{ + SetParent( g_pClientMode->GetViewport() ); + + SetHiddenBits( HIDEHUD_PLAYERDEAD ); + + m_szPreviousCrosshair[0] = '\0'; + m_pFrameVar = NULL; + m_flAccuracy = 0.1; +} + +void CHudDODCrosshair::ApplySchemeSettings( IScheme *scheme ) +{ + BaseClass::ApplySchemeSettings( scheme ); + + SetSize( ScreenWidth(), ScreenHeight() ); +} + +void CHudDODCrosshair::LevelShutdown( void ) +{ + // forces m_pFrameVar to recreate next map + m_szPreviousCrosshair[0] = '\0'; + + if ( m_pCrosshair ) + { + delete m_pCrosshair; + m_pCrosshair = NULL; + } + + if ( m_pFrameVar ) + { + delete m_pFrameVar; + m_pFrameVar = NULL; + } +} + +void CHudDODCrosshair::Init() +{ + m_iCrosshairTextureID = vgui::surface()->CreateNewTextureID(); +} + +bool CHudDODCrosshair::ShouldDraw() +{ + C_DODPlayer *pPlayer = C_DODPlayer::GetLocalDODPlayer(); + + if ( !pPlayer ) + return false; + + CWeaponDODBase *pWeapon = pPlayer->GetActiveDODWeapon(); + + if ( !pWeapon ) + return false; + + return pWeapon->ShouldDrawCrosshair(); +} + +void CHudDODCrosshair::Paint() +{ + C_DODPlayer *pPlayer = C_DODPlayer::GetLocalDODPlayer(); + + if( !pPlayer ) + return; + + const char *crosshairfile = cl_crosshair_file.GetString(); + + if ( !crosshairfile ) + return; + + if ( Q_stricmp( m_szPreviousCrosshair, crosshairfile ) != 0 ) + { + char buf[256]; + Q_snprintf( buf, sizeof(buf), "vgui/crosshairs/%s", crosshairfile ); + + vgui::surface()->DrawSetTextureFile( m_iCrosshairTextureID, buf, true, false ); + + if ( m_pCrosshair ) + { + delete m_pCrosshair; + } + + m_pCrosshair = vgui::surface()->DrawGetTextureMatInfoFactory( m_iCrosshairTextureID ); + + if ( !m_pCrosshair ) + return; + + if ( m_pFrameVar ) + { + delete m_pFrameVar; + } + + bool bFound = false; + m_pFrameVar = m_pCrosshair->FindVarFactory( "$frame", &bFound ); + Assert( bFound ); + + m_nNumFrames = m_pCrosshair->GetNumAnimationFrames(); + + // save the name to compare with the cvar in the future + Q_strncpy( m_szPreviousCrosshair, crosshairfile, sizeof(m_szPreviousCrosshair) ); + } + + if ( m_pFrameVar ) + { + if ( cl_dynamic_crosshair.GetBool() == false ) + { + m_pFrameVar->SetIntValue( 0 ); + } + else + { + CWeaponDODBase *pWeapon = pPlayer->GetActiveDODWeapon(); + + if ( !pWeapon ) + return; + + float accuracy = pWeapon->GetWeaponAccuracy( pPlayer->GetAbsVelocity().Length2D() ); + + float flMin = 0.02; + + float flMax = 0.125; + + accuracy = clamp( accuracy, flMin, flMax ); + + // approach this accuracy from our current accuracy + m_flAccuracy = Approach( accuracy, m_flAccuracy, cl_crosshair_approach_speed.GetFloat() ); + + float flFrame = RemapVal( m_flAccuracy, flMin, flMax, 0, m_nNumFrames-1 ); + + m_pFrameVar->SetIntValue( (int)flFrame ); + } + } + + Color clr( cl_crosshair_red.GetInt(), cl_crosshair_green.GetInt(), cl_crosshair_blue.GetInt(), 255 ); + + int screenWide, screenTall; + GetHudSize(screenWide, screenTall); + + int iX = screenWide / 2; + int iY = screenTall / 2; + + int iWidth, iHeight; + + iWidth = iHeight = cl_crosshair_scale.GetInt(); + + vgui::surface()->DrawSetColor( clr ); + vgui::surface()->DrawSetTexture( m_iCrosshairTextureID ); + vgui::surface()->DrawTexturedRect( iX-iWidth, iY-iHeight, iX+iWidth, iY+iHeight ); + vgui::surface()->DrawSetTexture(0); +} + diff --git a/game/client/dod/dod_hud_crosshair.h b/game/client/dod/dod_hud_crosshair.h new file mode 100644 index 0000000..0d39d91 --- /dev/null +++ b/game/client/dod/dod_hud_crosshair.h @@ -0,0 +1,58 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef HUD_DOD_CROSSHAIR_H +#define HUD_DOD_CROSSHAIR_H +#ifdef _WIN32 +#pragma once +#endif + +#include "hudelement.h" +#include <vgui_controls/Panel.h> + +namespace vgui +{ + class IScheme; +}; + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class CHudDODCrosshair : public CHudElement, public vgui::Panel +{ +public: + DECLARE_CLASS_SIMPLE( CHudDODCrosshair, vgui::Panel ); + + CHudDODCrosshair( const char *name ); + + virtual void Paint(); + virtual void Init(); + virtual bool ShouldDraw(); + virtual void ApplySchemeSettings( vgui::IScheme *scheme ); + + virtual void LevelShutdown( void ); + + //stub + void SetCrosshair( CHudTexture *texture, Color& clr ) {} + void ResetCrosshair() {} + +private: + int m_iCrosshairTextureID; + IVguiMatInfo *m_pCrosshair; + IVguiMatInfoVar *m_pFrameVar; // interface for material frame + int m_nNumFrames; // how many frames this crosshair has + + char m_szPreviousCrosshair[256]; // name of the current crosshair + float m_flAccuracy; +}; + + +// Enable/disable crosshair rendering. +extern ConVar crosshair; + + +#endif // HUD_DOD_CROSSHAIR_H diff --git a/game/client/dod/dod_hud_damageindicator.cpp b/game/client/dod/dod_hud_damageindicator.cpp new file mode 100644 index 0000000..c4f96b0 --- /dev/null +++ b/game/client/dod/dod_hud_damageindicator.cpp @@ -0,0 +1,425 @@ +//========= 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 "dod_shareddefs.h" +// NVNT damage +#include "haptics/haptic_utils.h" + +using namespace vgui; + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + + +//----------------------------------------------------------------------------- +// Purpose: HUD Damage indication +//----------------------------------------------------------------------------- +class CHudDODDamageIndicator : public CHudElement, public vgui::Panel +{ + DECLARE_CLASS_SIMPLE( CHudDODDamageIndicator, vgui::Panel ); + +public: + CHudDODDamageIndicator( 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( CHudDODDamageIndicator ); +DECLARE_HUD_MESSAGE( CHudDODDamageIndicator, 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[] = +{ + { "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 +//----------------------------------------------------------------------------- +CHudDODDamageIndicator::CHudDODDamageIndicator( 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 CHudDODDamageIndicator::Reset( void ) +{ + m_DmgColorLeft[3] = 0; + m_DmgColorRight[3] = 0; + m_DmgHighColorLeft[3] = 0; + m_DmgHighColorRight[3] = 0; + m_DmgFullscreenColor[3] = 0; +} + +void CHudDODDamageIndicator::Init( void ) +{ + HOOK_HUD_MESSAGE( CHudDODDamageIndicator, Damage ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +bool CHudDODDamageIndicator::ShouldDraw( void ) +{ + if ( !CHudElement::ShouldDraw() ) + return false; + + if ( !m_DmgColorLeft[3] && !m_DmgColorRight[3] && !m_DmgHighColorLeft[3] && !m_DmgHighColorRight[3] + && !m_DmgFullscreenColor[3] ) + return false; + + return true; +} + +//----------------------------------------------------------------------------- +// Purpose: Draws a damage quad +//----------------------------------------------------------------------------- +void CHudDODDamageIndicator::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; + + switch ( side ) + { + case 0: // left + { + 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(); + } + break; + case 1: // right + { + 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(); + } + break; + } + + meshBuilder.End(); + pMesh->Draw(); +} + +//----------------------------------------------------------------------------- +// Purpose: Draws full screen damage fade +//----------------------------------------------------------------------------- +void CHudDODDamageIndicator::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 CHudDODDamageIndicator::Paint() +{ + // draw fullscreen damage indicators + DrawFullscreenDamageIndicator(); + + // draw side damage indicators + DrawDamageIndicator(0); + DrawDamageIndicator(1); +} + +// NVNT - hacky way of passing damage +static long lastDamage_s = 0; + +//----------------------------------------------------------------------------- +// Purpose: Message handler for Damage message +//----------------------------------------------------------------------------- +void CHudDODDamageIndicator::MsgFunc_Damage( bf_read &msg ) +{ + int damageTaken = msg.ReadByte(); // health + long bitsDamage = msg.ReadLong(); // damage bits + + Vector vecFrom; + msg.ReadBitVec3Coord( vecFrom ); + + C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer(); + if ( !pPlayer ) + return; + + Vector vecDelta = (vecFrom - MainViewOrigin()); + VectorNormalize( vecDelta ); + + if ( damageTaken > 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; + + // 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 CHudDODDamageIndicator::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 top = DotProduct(vecDelta, up); + // NVNT pass damage. (use hap_damage amount to apply) + // do rotation + Vector hapDir(side,-top,front); + if ( haptics ) + haptics->ApplyDamageEffect(((float)lastDamage_s), 0, hapDir); + + 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)((ScreenWidth() / 2) + (flRadius * sa)); + ypos = (int)((ScreenHeight() / 2) - (flRadius * ca)); +} + +//----------------------------------------------------------------------------- +// Purpose: hud scheme settings +//----------------------------------------------------------------------------- +void CHudDODDamageIndicator::ApplySchemeSettings(vgui::IScheme *pScheme) +{ + BaseClass::ApplySchemeSettings(pScheme); + SetPaintBackgroundEnabled(false); + + int wide, tall; + GetHudSize(wide, tall); + SetSize(wide, tall); +} diff --git a/game/client/dod/dod_hud_deathnotice.cpp b/game/client/dod/dod_hud_deathnotice.cpp new file mode 100644 index 0000000..c00be07 --- /dev/null +++ b/game/client/dod/dod_hud_deathnotice.cpp @@ -0,0 +1,942 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Draws DoD:S's death notices +// +// $NoKeywords: $ +//=============================================================================// +#include "cbase.h" +#include "hudelement.h" +#include "hud_macros.h" +#include "c_playerresource.h" +#include "iclientmode.h" +#include <vgui_controls/Controls.h> +#include <vgui_controls/Panel.h> +#include <vgui/ISurface.h> +#include <vgui/ILocalize.h> +#include <KeyValues.h> +#include "c_baseplayer.h" +#include "c_team.h" + +#include "dod_shareddefs.h" +#include "clientmode_dod.h" +#include "c_dod_player.h" +#include "c_dod_playerresource.h" +#include "c_dod_objective_resource.h" +#include "dod_hud_freezepanel.h" +#include "engine/IEngineSound.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +ConVar hud_deathnotice_time( "hud_deathnotice_time", "6", 0 ); +ConVar cl_deathicon_width( "cl_deathicon_width", "57" ); +ConVar cl_deathicon_height( "cl_deathicon_height", "18" ); + +#define MAX_DEATHNOTICE_NAME_LENGTH 128 // to hold multiple player cappers + +// a very useful function for getting the ideal scale factor of a sprite that's to be +// scaled into a space +float GetScale( int nIconWidth, int nIconHeight, int nWidth, int nHeight ); + +// Player entries in a death notice +struct DeathNoticePlayer +{ + char szName[MAX_DEATHNOTICE_NAME_LENGTH]; + int iEntIndex; +}; + +// Contents of each entry in our list of death notices +struct DeathNoticeItem +{ + DeathNoticeItem() + { + iconDeath = NULL; + bSuicide = false; + bCapMsg = false; + bLocalPlayerInvolved = false; + bDefense = false; + bDominating = false; + } + + DeathNoticePlayer Killer; + DeathNoticePlayer Victim; + CHudTexture *iconDeath; + bool bSuicide; + float flDisplayTime; + + // When I see a boolean like this, I know serious bullshit is afoot! + bool bCapMsg; // if this is set, this is a flag cap msg. + // Killer.szName is the list of players that capped + // Victim.szName is the localized point name + // iMaterial is the material index of the flag icon to show + // iEntIndex in Killer is the capping team + + + int iMaterial; + + bool bLocalPlayerInvolved; // Is the local player a capper, killer or victim in this message + + bool bDefense; + + bool bDominating; + wchar_t wzInfoText[32]; // any additional text to display next to icon + +}; + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class CHudDeathNotice : public CHudElement, public vgui::Panel +{ + DECLARE_CLASS_SIMPLE( CHudDeathNotice, vgui::Panel ); +public: + CHudDeathNotice( const char *pElementName ); + + void Init( void ); + void VidInit( void ); + virtual bool ShouldDraw( void ); + virtual void Paint( void ); + virtual void ApplySchemeSettings( vgui::IScheme *scheme ); + + void SetColorForNoticePlayer( int iTeamNumber ); + void RetireExpiredDeathNotices( void ); + + void FireGameEvent( IGameEvent * event); + + void DrawBackgroundBox( int x, int y, int w, int h, bool bLocalPlayerInvolved ); + + int DrawDefenseItem( DeathNoticeItem *pItem, int xRight, int y ); + int DrawDeathNoticeItem( DeathNoticeItem *pItem, int x, int y ); + int DrawDominationNoticeItem( DeathNoticeItem *pItem, int xRight, int y ); + + virtual bool IsVisible( void ); + + void AddAdditionalMsg( int iKillerID, int iVictimID, const char *pMsgKey ); + + void PlayRivalrySounds( int iKillerIndex, int iVictimIndex, int iType ); + +private: + + CPanelAnimationVarAliasType( float, m_flLineHeight, "LineHeight", "15", "proportional_float" ); + + CPanelAnimationVar( float, m_flMaxDeathNotices, "MaxDeathNotices", "4" ); + + CPanelAnimationVar( vgui::HFont, m_hTextFont, "TextFont", "HudNumbersTimer" ); + + CPanelAnimationVar( Color, m_BackgroundColor, "BackgroundColor", "255 255 255 100" ); + CPanelAnimationVar( Color, m_ActiveBackgroundColor, "ActiveBackgroundColor", "255 255 255 140" ); + + // Special death notice icons + CHudTexture *m_iconD_skull; + CHudTexture *m_pIconDefended; + CHudTexture *m_iconDomination; + + CUtlVector<DeathNoticeItem> m_DeathNotices; + + int m_iMaterialTexture; +}; + +using namespace vgui; + +DECLARE_HUDELEMENT( CHudDeathNotice ); + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +CHudDeathNotice::CHudDeathNotice( const char *pElementName ) : + CHudElement( pElementName ), BaseClass( NULL, "HudDeathNotice" ) +{ + vgui::Panel *pParent = g_pClientMode->GetViewport(); + SetParent( pParent ); + + m_iconD_skull = NULL; + m_iconDomination = NULL; + + SetHiddenBits( HIDEHUD_MISCSTATUS ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CHudDeathNotice::ApplySchemeSettings( IScheme *scheme ) +{ + BaseClass::ApplySchemeSettings( scheme ); + SetPaintBackgroundEnabled( false ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CHudDeathNotice::Init( void ) +{ + ListenForGameEvent( "player_death" ); + ListenForGameEvent( "dod_point_captured" ); + ListenForGameEvent( "dod_capture_blocked" ); + + m_iMaterialTexture = vgui::surface()->CreateNewTextureID(); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CHudDeathNotice::VidInit( void ) +{ + m_iconD_skull = gHUD.GetIcon( "d_skull_dod" ); + m_pIconDefended = gHUD.GetIcon( "icon_defended" ); + m_iconDomination = gHUD.GetIcon( "leaderboard_dominated" ); + m_DeathNotices.Purge(); +} + +//----------------------------------------------------------------------------- +// Purpose: Draw if we've got at least one death notice in the queue +//----------------------------------------------------------------------------- +bool CHudDeathNotice::ShouldDraw( void ) +{ + return ( CHudElement::ShouldDraw() && ( m_DeathNotices.Count() ) ); +} + +//----------------------------------------------------------------------------- +// Purpose: Hide if we just took a freezecam screenshot +//----------------------------------------------------------------------------- +bool CHudDeathNotice::IsVisible( void ) +{ + if ( IsTakingAFreezecamScreenshot() ) + return false; + + return BaseClass::IsVisible(); + +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CHudDeathNotice::SetColorForNoticePlayer( int iTeamNumber ) +{ + Color c = g_PR->GetTeamColor( iTeamNumber ); + surface()->DrawSetTextColor( c ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CHudDeathNotice::Paint() +{ + int yStart = GetClientModeDODNormal()->GetDeathMessageStartHeight(); + + surface()->DrawSetTextFont( m_hTextFont ); + + int y = yStart; + int x = GetWide(); + + int iCount = m_DeathNotices.Count(); + for ( int i = 0; i < iCount; i++ ) + { + if ( m_DeathNotices[i].bDefense ) + y += DrawDefenseItem( &m_DeathNotices[i], x, y ); + else + y += DrawDeathNoticeItem( &m_DeathNotices[i], x, y ); + } + + // Now retire any death notices that have expired + RetireExpiredDeathNotices(); +} + +int CHudDeathNotice::DrawDefenseItem( DeathNoticeItem *pItem, int xRight, int y ) +{ + // Get the team numbers for the players involved + int iKillerTeam = pItem->Killer.iEntIndex; + int iVictimTeam = TEAM_UNASSIGNED; + + wchar_t victim[ 256 ]; + wchar_t killer[ 256 ]; + + g_pVGuiLocalize->ConvertANSIToUnicode( pItem->Victim.szName, victim, sizeof( victim ) ); + g_pVGuiLocalize->ConvertANSIToUnicode( pItem->Killer.szName, killer, sizeof( killer ) ); + + // Get the local position for this notice + int len = UTIL_ComputeStringWidth( m_hTextFont, victim ); + + int iconWide; + int iconTall; + + float scale = ( (float)ScreenHeight() / 480.0f ) * 0.6; //scale based on 800x600 + iconWide = iconTall = (int)( scale * 16.0 ); + + int iconDefSize = (int)( scale * 32.0 ); + + int spacerX = XRES(5); + + int x = xRight - len - spacerX - iconWide - XRES(10); + + x -= iconDefSize; + + surface()->DrawSetTextFont( m_hTextFont ); + int iFontTall = vgui::surface()->GetFontTall( m_hTextFont ); + int yText = y + ( iconDefSize - iFontTall ) / 2; + + int boxWidth = len + iconWide + spacerX; + + boxWidth += iconDefSize; + + int boxHeight = m_flLineHeight; + int boxBorder = XRES(2); + + // Draw Defender's name + int nameWidth = UTIL_ComputeStringWidth( m_hTextFont, killer ) + spacerX; // gap + + x -= nameWidth; + boxWidth += nameWidth; + + DrawBackgroundBox( x-boxBorder, y-boxBorder, boxWidth+2*boxBorder, boxHeight+2*boxBorder, pItem->bLocalPlayerInvolved ); + + SetColorForNoticePlayer( iKillerTeam ); + + // Draw killer's name + surface()->DrawSetTextPos( x, yText ); + surface()->DrawUnicodeString( killer ); + surface()->DrawGetTextPos( x, yText ); + + x += spacerX; + + Color iconColor( 255, 80, 0, 255 ); + + // Draw shield + cap icon + m_pIconDefended->DrawSelf( x, y, iconDefSize, iconDefSize, Color(255,255,255,255) ); + x += iconDefSize + spacerX; + + const char *szMatName = GetMaterialNameFromIndex( pItem->iMaterial ); + + vgui::surface()->DrawSetColor( Color(255,255,255,255) ); + vgui::surface()->DrawSetTextureFile( m_iMaterialTexture, szMatName, true, false); + + int iconY = y + iconDefSize / 2 - iconTall / 2; + vgui::surface()->DrawTexturedRect( x, iconY, x + iconWide, iconY + iconTall ); + x += iconWide; + + SetColorForNoticePlayer( iVictimTeam ); + + // Draw location name + surface()->DrawSetTextFont( m_hTextFont ); //reset the font, draw icon can change it + surface()->DrawSetTextPos( x, yText ); + + surface()->DrawUnicodeString( victim ); + + // return height of this item + // base spacing on the height of the background box + return boxHeight + boxBorder*2 + YRES(4); +} + +// X is right side, do a right align! +int CHudDeathNotice::DrawDeathNoticeItem( DeathNoticeItem *pItem, int xRight, int y ) +{ + if ( pItem->bDominating ) + { + return DrawDominationNoticeItem( pItem, xRight, y ); + } + + bool bCapMsg = pItem->bCapMsg; + + // Get the team numbers for the players involved + int iKillerTeam = TEAM_UNASSIGNED; + int iVictimTeam = TEAM_UNASSIGNED; + + if ( bCapMsg ) + { + iKillerTeam = pItem->Killer.iEntIndex; + iVictimTeam = TEAM_UNASSIGNED; + } + else + { + if( g_PR ) + { + iKillerTeam = g_PR->GetTeam( pItem->Killer.iEntIndex ); + iVictimTeam = g_PR->GetTeam( pItem->Victim.iEntIndex ); + } + } + + wchar_t victim[ 256 ]; + wchar_t killer[ 256 ]; + + g_pVGuiLocalize->ConvertANSIToUnicode( pItem->Victim.szName, victim, sizeof( victim ) ); + g_pVGuiLocalize->ConvertANSIToUnicode( pItem->Killer.szName, killer, sizeof( killer ) ); + + // Get the local position for this notice + int len = UTIL_ComputeStringWidth( m_hTextFont, victim ); + + int iconWide; + int iconTall; + + CHudTexture *icon = pItem->iconDeath; + + Assert( icon ); + + if ( bCapMsg ) + { + float scale = ( (float)ScreenHeight() / 480.0f ) * 0.6; //scale based on 800x600 + iconWide = iconTall = (int)( scale * 32.0 ); + } + else + { + if ( !icon ) + return 0; + + if( icon->bRenderUsingFont ) + { + iconWide = surface()->GetCharacterWidth( icon->hFont, icon->cCharacterInFont ); + iconTall = surface()->GetFontTall( icon->hFont ); + } + else + { + float scale = GetScale( icon->Width(), icon->Height(), XRES(cl_deathicon_width.GetInt()), YRES(cl_deathicon_height.GetInt()) ); + iconWide = (int)( scale * (float)icon->Width() ); + iconTall = (int)( scale * (float)icon->Height() ); + } + } + + int spacerX = XRES(5); + + int x = xRight - len - spacerX - iconWide - XRES(10); + + if ( pItem->bDefense ) + { + x -= iconWide; //m_iDefendedIconSize; + } + + surface()->DrawSetTextFont( m_hTextFont ); + int iFontTall = vgui::surface()->GetFontTall( m_hTextFont ); + int boxWidth = len + iconWide + spacerX; + + if ( pItem->bDefense ) + { + boxWidth += iconWide; //m_iDefendedIconSize; + } + + int boxHeight = m_flLineHeight; //MIN( iconTall, m_flLineHeight ); + int boxBorder = XRES(2); + + int yText = y + ( m_flLineHeight - iFontTall ) / 2; + int yIcon = y + ( m_flLineHeight - iconTall ) / 2; + + // Only draw killers name if it wasn't a suicide + if ( !pItem->bSuicide ) + { + int nameWidth = UTIL_ComputeStringWidth( m_hTextFont, killer ) + spacerX; // gap + + x -= nameWidth; + boxWidth += nameWidth; + + DrawBackgroundBox( x-boxBorder, y-boxBorder, boxWidth+2*boxBorder, boxHeight+2*boxBorder, pItem->bLocalPlayerInvolved ); + + SetColorForNoticePlayer( iKillerTeam ); + + // Draw killer's name + surface()->DrawSetTextPos( x, yText ); + const wchar_t *p = killer; + while ( *p ) + { + surface()->DrawUnicodeChar( *p++ ); + } + surface()->DrawGetTextPos( x, yText ); + + x += spacerX; + } + else + { + DrawBackgroundBox( x-boxBorder, y-boxBorder, boxWidth+2*boxBorder, boxHeight+2*boxBorder, pItem->bLocalPlayerInvolved ); + } + + Color iconColor( 255, 80, 0, 255 ); + + // Draw death weapon or cap icon + if ( bCapMsg ) + { + const char *szMatName = GetMaterialNameFromIndex( pItem->iMaterial ); + + vgui::surface()->DrawSetColor( Color(255,255,255,255) ); + vgui::surface()->DrawSetTextureFile( m_iMaterialTexture, szMatName, true, false); + vgui::surface()->DrawTexturedRect( x, yIcon, x + iconWide, yIcon + iconTall ); + x += iconWide + spacerX; + } + else + { + //If we're using a font char, this will ignore iconTall and iconWide + icon->DrawSelf( x, yIcon, iconWide, iconTall, iconColor ); + x += iconWide + spacerX; + } + + SetColorForNoticePlayer( iVictimTeam ); + + // Draw victims name + surface()->DrawSetTextFont( m_hTextFont ); //reset the font, draw icon can change it + surface()->DrawSetTextPos( x, yText ); + const wchar_t *p = victim; + while ( *p ) + { + surface()->DrawUnicodeChar( *p++ ); + } + + // return height of this item + // base spacing on the height of the background box + return boxHeight + boxBorder*2 + YRES(4); +} + +int CHudDeathNotice::DrawDominationNoticeItem( DeathNoticeItem *pItem, int xRight, int y ) +{ + // Get the team numbers for the players involved + int iKillerTeam = TEAM_UNASSIGNED; + int iVictimTeam = TEAM_UNASSIGNED; + + if( g_PR ) + { + iKillerTeam = g_PR->GetTeam( pItem->Killer.iEntIndex ); + iVictimTeam = g_PR->GetTeam( pItem->Victim.iEntIndex ); + } + + wchar_t victim[ 256 ]; + wchar_t killer[ 256 ]; + + g_pVGuiLocalize->ConvertANSIToUnicode( pItem->Victim.szName, victim, sizeof( victim ) ); + g_pVGuiLocalize->ConvertANSIToUnicode( pItem->Killer.szName, killer, sizeof( killer ) ); + + // Get the local position for this notice + int len = UTIL_ComputeStringWidth( m_hTextFont, victim ); + + int iconWide; + int iconTall; + + Assert( pItem->iconDeath ); + + CHudTexture *icon = pItem->iconDeath; + + if ( !icon ) + return 0; + + if( icon->bRenderUsingFont ) + { + iconWide = surface()->GetCharacterWidth( icon->hFont, icon->cCharacterInFont ); + iconTall = surface()->GetFontTall( icon->hFont ); + } + else + { + float scale = GetScale( icon->Width(), icon->Height(), XRES(cl_deathicon_width.GetInt()), YRES(cl_deathicon_height.GetInt()) ); + iconWide = (int)( scale * (float)icon->Width() ); + iconTall = (int)( scale * (float)icon->Height() ); + } + + int spacerX = XRES(5); + + int x = xRight - len - spacerX - iconWide - XRES(10); + + surface()->DrawSetTextFont( m_hTextFont ); + int iFontTall = vgui::surface()->GetFontTall( m_hTextFont ); + int boxWidth = len + iconWide + spacerX; + + int iDominatingLen = UTIL_ComputeStringWidth( m_hTextFont, pItem->wzInfoText ) + XRES(2); + x -= iDominatingLen; + boxWidth += iDominatingLen; + + int boxHeight = m_flLineHeight; //MIN( iconTall, m_flLineHeight ); + int boxBorder = XRES(2); + + int yText = y + ( m_flLineHeight - iFontTall ) / 2; + int yIcon = y + ( m_flLineHeight - iconTall ) / 2; + + int nameWidth = UTIL_ComputeStringWidth( m_hTextFont, killer ) + spacerX; // gap + + x -= nameWidth; + boxWidth += nameWidth; + + DrawBackgroundBox( x-boxBorder, y-boxBorder, boxWidth+2*boxBorder, boxHeight+2*boxBorder, pItem->bLocalPlayerInvolved ); + + SetColorForNoticePlayer( iKillerTeam ); + + // Draw killer's name + surface()->DrawSetTextPos( x, yText ); + const wchar_t *p = killer; + while ( *p ) + { + surface()->DrawUnicodeChar( *p++ ); + } + surface()->DrawGetTextPos( x, yText ); + + x += spacerX; + + Color iconColor( 255, 80, 0, 255 ); + + //If we're using a font char, this will ignore iconTall and iconWide + icon->DrawSelf( x, yIcon, iconWide, iconTall, iconColor ); + x += iconWide + spacerX; + + surface()->DrawSetTextColor( Color(255,255,255,255) ); + + // Draw dominating string + surface()->DrawSetTextFont( m_hTextFont ); //reset the font, draw icon can change it + surface()->DrawSetTextPos( x, yText ); + p = pItem->wzInfoText; + while ( *p ) + { + surface()->DrawUnicodeChar( *p++ ); + } + x += iDominatingLen; + + SetColorForNoticePlayer( iVictimTeam ); + + // Draw victims name + //surface()->DrawSetTextFont( m_hTextFont ); //reset the font, draw icon can change it + surface()->DrawSetTextPos( x, yText ); + p = victim; + while ( *p ) + { + surface()->DrawUnicodeChar( *p++ ); + } + + // return height of this item + // base spacing on the height of the background box + return boxHeight + boxBorder*2 + YRES(4); +} + +ConVar cl_deathicon_bg_alpha( "cl_deathicon_bg_alpha", "1.0" ); + +void CHudDeathNotice::DrawBackgroundBox( int x, int y, int w, int h, bool bLocalPlayerInvolved ) +{ + Panel::DrawBox( x, y, w, h, + bLocalPlayerInvolved ? m_ActiveBackgroundColor : m_BackgroundColor, + cl_deathicon_bg_alpha.GetFloat() ); +} + +//----------------------------------------------------------------------------- +// Purpose: This message handler may be better off elsewhere +//----------------------------------------------------------------------------- +void CHudDeathNotice::RetireExpiredDeathNotices( void ) +{ + // Loop backwards because we might remove one + int iSize = m_DeathNotices.Size(); + for ( int i = iSize-1; i >= 0; i-- ) + { + if ( m_DeathNotices[i].flDisplayTime < gpGlobals->curtime ) + { + m_DeathNotices.Remove(i); + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: Server's told us that someone's died +//----------------------------------------------------------------------------- +void CHudDeathNotice::FireGameEvent( IGameEvent * event) +{ + if (!g_PR) + return; + + if ( hud_deathnotice_time.GetFloat() == 0 ) + return; + + C_DODPlayer *pLocal = C_DODPlayer::GetLocalDODPlayer(); + + Assert( pLocal ); + + if ( !pLocal ) + return; + + int iLocalPlayerIndex = pLocal->entindex(); + + const char *pEventName = event->GetName(); + + if ( Q_strcmp( "dod_point_captured", pEventName ) == 0 ) + { + // Cap point index + int cp = event->GetInt( "cp", -1 ); + Assert( cp >= 0 ); + + // Cap point name ( MATTTODO: can't we find this from the point index ? ) + const char *pName = event->GetString( "cpname", "Unnamed Control Point" ); + const wchar_t *pBuf = g_pVGuiLocalize->Find( pName ); + + // Array of capper indeces + const char *cappers = event->GetString("cappers"); + + DeathNoticeItem capMsg; + capMsg.bCapMsg = true; + capMsg.bSuicide = false; + capMsg.bDefense = false; + capMsg.flDisplayTime = gpGlobals->curtime + hud_deathnotice_time.GetFloat(); + capMsg.bLocalPlayerInvolved = false; + + char szCappers[256]; + szCappers[0] = '\0'; + + int len = Q_strlen(cappers); + for( int i=0;i<len;i++ ) + { + int iPlayerIndex = (int)cappers[i]; + + if ( iPlayerIndex == iLocalPlayerIndex ) + capMsg.bLocalPlayerInvolved = true; + + Assert( iPlayerIndex > 0 && iPlayerIndex <= gpGlobals->maxClients ); + + const char *pPlayerName = g_PR->GetPlayerName( iPlayerIndex ); + + if ( i == 0 ) + { + // use first player as the team + capMsg.Killer.iEntIndex = g_PR->GetTeam( iPlayerIndex ); + capMsg.iMaterial = g_pObjectiveResource->GetIconForTeam( cp, capMsg.Killer.iEntIndex ); + + if ( g_pObjectiveResource->GetBombsRequired( cp ) > 0 ) + { + capMsg.iMaterial = g_pObjectiveResource->GetCPBombedIcon( cp ); + } + } + else + { + Q_strncat( szCappers, ", ", sizeof(szCappers), 2 ); + } + + Q_strncat( szCappers, pPlayerName, sizeof(szCappers), COPY_ALL_CHARACTERS ); + } + + Q_strncpy( capMsg.Killer.szName, szCappers, sizeof(capMsg.Killer.szName) ); + + if ( pBuf ) + { + g_pVGuiLocalize->ConvertUnicodeToANSI( pBuf, capMsg.Victim.szName, sizeof(capMsg.Victim.szName) ); + } + else + { + Q_strncpy( capMsg.Victim.szName, pName, sizeof(capMsg.Victim.szName) ); + } + + // Do we have too many death messages in the queue? + if ( m_DeathNotices.Count() > 0 && + m_DeathNotices.Count() >= (int)m_flMaxDeathNotices ) + { + // Remove the oldest one in the queue, which will always be the first + m_DeathNotices.Remove(0); + } + + m_DeathNotices.AddToTail( capMsg ); + + // print a log message + + char szLogMsg[512]; + + Q_snprintf( szLogMsg, sizeof( szLogMsg ), "%s captured %s for the %s\n", + capMsg.Killer.szName, + capMsg.Victim.szName, + capMsg.Killer.iEntIndex == TEAM_ALLIES ? "U.S. Army" : "Wermacht" ); + + Msg( "%s",szLogMsg ); + } + else if ( Q_strcmp( "dod_capture_blocked", pEventName ) == 0 ) + { + // Cap point index + int cp = event->GetInt( "cp", -1 ); + Assert( cp >= 0 ); + + // Cap point name + const char *pName = event->GetString( "cpname", "Unnamed Control Point" ); + const wchar_t *pBuf = g_pVGuiLocalize->Find( pName ); + + // A single blocker entindex + int iBlocker = event->GetInt("blocker"); + + DeathNoticeItem capMsg; + capMsg.bCapMsg = true; + capMsg.bSuicide = false; + capMsg.bDefense = true; + capMsg.flDisplayTime = gpGlobals->curtime + hud_deathnotice_time.GetFloat(); + capMsg.bLocalPlayerInvolved = false; + + capMsg.Killer.iEntIndex = g_PR->GetTeam( iBlocker ); + capMsg.iMaterial = g_pObjectiveResource->GetIconForTeam( cp, capMsg.Killer.iEntIndex ); + + if ( iBlocker == iLocalPlayerIndex ) + capMsg.bLocalPlayerInvolved = true; + + Q_strncpy( capMsg.Killer.szName, g_PR->GetPlayerName( iBlocker ), sizeof(capMsg.Killer.szName) ); + + char buf[128]; + + if ( pBuf ) + { + g_pVGuiLocalize->ConvertUnicodeToANSI( pBuf, buf, sizeof(buf) ); + pName = buf; + } + + Q_snprintf( capMsg.Victim.szName, sizeof(capMsg.Victim.szName), " - %s", pName ); + + // Do we have too many death messages in the queue? + if ( m_DeathNotices.Count() > 0 && + m_DeathNotices.Count() >= (int)m_flMaxDeathNotices ) + { + // Remove the oldest one in the queue, which will always be the first + m_DeathNotices.Remove(0); + } + + m_DeathNotices.AddToTail( capMsg ); + } + else if ( Q_strcmp( "player_death", pEventName ) == 0 ) + { + int killer = engine->GetPlayerForUserID( event->GetInt("attacker") ); + int victim = engine->GetPlayerForUserID( event->GetInt("userid") ); + const char *killedwith = event->GetString( "weapon" ); + + char fullkilledwith[128]; + if ( killedwith && *killedwith ) + { + Q_snprintf( fullkilledwith, sizeof(fullkilledwith), "d_%s", killedwith ); + } + else + { + fullkilledwith[0] = 0; + } + + // Do we have too many death messages in the queue? + if ( m_DeathNotices.Count() > 0 && + m_DeathNotices.Count() >= (int)m_flMaxDeathNotices ) + { + // Remove the oldest one in the queue, which will always be the first + m_DeathNotices.Remove(0); + } + + // Get the names of the players + const char *killer_name = g_PR->GetPlayerName( killer ); + const char *victim_name = g_PR->GetPlayerName( victim ); + + if ( !killer_name ) + killer_name = ""; + if ( !victim_name ) + victim_name = ""; + + // Make a new death notice + DeathNoticeItem deathMsg; + deathMsg.Killer.iEntIndex = killer; + deathMsg.Victim.iEntIndex = victim; + Q_strncpy( deathMsg.Killer.szName, killer_name, MAX_PLAYER_NAME_LENGTH ); + Q_strncpy( deathMsg.Victim.szName, victim_name, MAX_PLAYER_NAME_LENGTH ); + deathMsg.flDisplayTime = gpGlobals->curtime + hud_deathnotice_time.GetFloat(); + deathMsg.bSuicide = ( !killer || killer == victim ); + deathMsg.bCapMsg = false; + deathMsg.bDefense = false; + deathMsg.iMaterial = -1; + deathMsg.bLocalPlayerInvolved = ( killer == iLocalPlayerIndex || victim == iLocalPlayerIndex ); + + // Try and find the death identifier in the icon list + deathMsg.iconDeath = gHUD.GetIcon( fullkilledwith ); + + if ( !deathMsg.iconDeath ) + { + // Can't find it, so use the default skull & crossbones icon + deathMsg.iconDeath = m_iconD_skull; + } + + // Add it to our list of death notices + m_DeathNotices.AddToTail( deathMsg ); + + if ( event->GetInt( "dominated" ) > 0 ) + { + AddAdditionalMsg( killer, victim, "#Msg_Dominating" ); + PlayRivalrySounds( killer, victim, DOD_DEATHFLAG_DOMINATION ); + } + if ( event->GetInt( "revenge" ) > 0 ) + { + AddAdditionalMsg( killer, victim, "#Msg_Revenge" ); + PlayRivalrySounds( killer, victim, DOD_DEATHFLAG_REVENGE ); + } + + char sDeathMsg[512]; + + // Record the death notice in the console + if ( deathMsg.bSuicide ) + { + if ( !strcmp( fullkilledwith, "d_worldspawn" ) ) + { + Q_snprintf( sDeathMsg, sizeof( sDeathMsg ), "%s died.\n", deathMsg.Victim.szName ); + } + else //d_world + { + Q_snprintf( sDeathMsg, sizeof( sDeathMsg ), "%s suicided.\n", deathMsg.Victim.szName ); + } + } + else + { + Q_snprintf( sDeathMsg, sizeof( sDeathMsg ), "%s killed %s", deathMsg.Killer.szName, deathMsg.Victim.szName ); + + if ( fullkilledwith && *fullkilledwith && (*fullkilledwith > 13 ) ) + { + Q_strncat( sDeathMsg, VarArgs( " with %s.\n", fullkilledwith+2 ), sizeof( sDeathMsg ), COPY_ALL_CHARACTERS ); + } + } + + Msg( "%s",sDeathMsg ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: Adds an additional death message +//----------------------------------------------------------------------------- +void CHudDeathNotice::AddAdditionalMsg( int iKillerID, int iVictimID, const char *pMsgKey ) +{ + int iMsg = m_DeathNotices.AddToTail(); + DeathNoticeItem &msg = m_DeathNotices[iMsg]; + + msg.Killer.iEntIndex = iKillerID; + msg.Victim.iEntIndex = iVictimID; + Q_strncpy( msg.Killer.szName, g_PR->GetPlayerName( iKillerID ), ARRAYSIZE( msg.Killer.szName ) ); + Q_strncpy( msg.Victim.szName, g_PR->GetPlayerName( iVictimID ), ARRAYSIZE( msg.Victim.szName ) ); + msg.flDisplayTime = gpGlobals->curtime + hud_deathnotice_time.GetFloat(); + msg.bSuicide = false; + msg.bCapMsg = false; + msg.bDefense = false; + msg.iMaterial = -1; + + msg.bDominating = true; + const wchar_t *wzMsg = g_pVGuiLocalize->Find( pMsgKey ); + if ( wzMsg ) + { + V_wcsncpy( msg.wzInfoText, wzMsg, sizeof( msg.wzInfoText ) ); + } + msg.iconDeath = m_iconDomination; + + int iLocalPlayerIndex = GetLocalPlayerIndex(); + if ( iLocalPlayerIndex == iVictimID || iLocalPlayerIndex == iKillerID ) + { + msg.bLocalPlayerInvolved = true; + } +} + +ConVar dod_playrivalrysounds( "dod_playrivalrysounds", "1", FCVAR_ARCHIVE ); + +void CHudDeathNotice::PlayRivalrySounds( int iKillerIndex, int iVictimIndex, int iType ) +{ + if ( dod_playrivalrysounds.GetBool() == false ) + return; + + int iLocalPlayerIndex = GetLocalPlayerIndex(); + + //We're not involved in this kill + if ( iKillerIndex != iLocalPlayerIndex && iVictimIndex != iLocalPlayerIndex ) + return; + + const char *pszSoundName = NULL; + + if ( iType == DOD_DEATHFLAG_DOMINATION ) + { + if ( iKillerIndex == iLocalPlayerIndex ) + { + pszSoundName = "Game.Domination"; + } + else if ( iVictimIndex == iLocalPlayerIndex ) + { + pszSoundName = "Game.Nemesis"; + } + } + else if ( iType == DOD_DEATHFLAG_REVENGE ) + { + pszSoundName = "Game.Revenge"; + } + + CLocalPlayerFilter filter; + C_BaseEntity::EmitSound( filter, SOUND_FROM_LOCAL_PLAYER, pszSoundName ); +}
\ No newline at end of file diff --git a/game/client/dod/dod_hud_deathstats.cpp b/game/client/dod/dod_hud_deathstats.cpp new file mode 100644 index 0000000..90fa064 --- /dev/null +++ b/game/client/dod/dod_hud_deathstats.cpp @@ -0,0 +1,383 @@ + +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#include "cbase.h" +#include "dod_hud_deathstats.h" +#include "vgui_controls/AnimationController.h" +#include "iclientmode.h" +#include <vgui_controls/Label.h> +#include <vgui/ILocalize.h> +#include <vgui/ISurface.h> +#include "hud_macros.h" +#include "c_dod_playerresource.h" +#include "c_dod_team.h" +#include "c_dod_player.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +extern ConVar cl_deathicon_width; +extern ConVar cl_deathicon_height; + +//DECLARE_HUDELEMENT( CDODDeathStatsPanel ); + +//----------------------------------------------------------------------------- +// Purpose: Constructor +//----------------------------------------------------------------------------- +CDODDeathStatsPanel::CDODDeathStatsPanel( const char *pElementName ) +: EditablePanel( NULL, "DeathStats" ), CHudElement( pElementName ) +{ + vgui::Panel *pParent = g_pClientMode->GetViewport(); + SetParent( pParent ); + SetVisible( false ); + SetAlpha( 0 ); + SetScheme( "ClientScheme" ); + + m_pAttackerHistoryLabel = new vgui::Label( this, "AttackerDmgLabel", "..." ); + m_pSummaryLabel = new vgui::Label( this, "LifeSummaryLabel", "..." ); + + memset( &m_DeathRecord, 0, sizeof(m_DeathRecord) ); + + LoadControlSettings("Resource/UI/DeathStats.res"); +} + +void CDODDeathStatsPanel::OnScreenSizeChanged( int iOldWide, int iOldTall ) +{ + LoadControlSettings( "resource/UI/DeathStats.res" ); +} + +void CDODDeathStatsPanel::ApplySchemeSettings( vgui::IScheme *pScheme ) +{ + BaseClass::ApplySchemeSettings( pScheme ); + + SetBgColor( GetSchemeColor("TransparentLightBlack", pScheme) ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CDODDeathStatsPanel::Reset() +{ + Hide(); +} + +void CDODDeathStatsPanel::Init() +{ + Hide(); + + ListenForGameEvent( "player_death" ); + + m_iMaterialTexture = vgui::surface()->CreateNewTextureID(); + + CHudElement::Init(); +} + +void CDODDeathStatsPanel::VidInit( void ) +{ + m_iconD_skull = gHUD.GetIcon( "d_skull_dod" ); + m_pIconKill = gHUD.GetIcon( "stats_kill" ); + m_pIconWounded = gHUD.GetIcon( "stats_wounded" ); + m_pIconCap = gHUD.GetIcon( "stats_cap" ); + m_pIconDefended = gHUD.GetIcon( "stats_defended" ); +} + +//----------------------------------------------------------------------------- +// Purpose: Handle player_death message +//----------------------------------------------------------------------------- +void CDODDeathStatsPanel::FireGameEvent( IGameEvent * event) +{ + if ( Q_strcmp( "player_death", event->GetName() ) == 0 ) + { + C_BasePlayer *pLocalPlayer = C_BasePlayer::GetLocalPlayer(); + + if ( !pLocalPlayer ) + return; + + if ( !g_PR ) + return; + + int victim = engine->GetPlayerForUserID( event->GetInt("userid") ); + + // only deal with deathnotices where we die + if ( victim != pLocalPlayer->entindex() ) + { + return; + } + + int killer = engine->GetPlayerForUserID( event->GetInt("attacker") ); + + const char *killedwith = event->GetString( "weapon" ); + + char fullkilledwith[128]; + if ( killedwith && *killedwith ) + { + Q_snprintf( fullkilledwith, sizeof(fullkilledwith), "d_%s", killedwith ); + } + else + { + fullkilledwith[0] = 0; + } + + // Get the names of the players + const char *killer_name = g_PR->GetPlayerName( killer ); + const char *victim_name = g_PR->GetPlayerName( victim ); + + if ( !killer_name ) + killer_name = ""; + if ( !victim_name ) + victim_name = ""; + + m_DeathRecord.Killer.iEntIndex = killer; + m_DeathRecord.Victim.iEntIndex = victim; + Q_strncpy( m_DeathRecord.Killer.szName, killer_name, MAX_PLAYER_NAME_LENGTH ); + Q_strncpy( m_DeathRecord.Victim.szName, victim_name, MAX_PLAYER_NAME_LENGTH ); + m_DeathRecord.bSuicide = ( !killer || killer == victim ); + + // Try and find the death identifier in the icon list + m_DeathRecord.iconDeath = gHUD.GetIcon( fullkilledwith ); + + if ( !m_DeathRecord.iconDeath ) + { + // Can't find it, so use the default skull & crossbones icon + m_DeathRecord.iconDeath = m_iconD_skull; + } + + // Info we get from this message: + // - who killed us with what + + // Info that is networked to the local player + // - the hitgroups we hit the guy who killed us with + // - life kills + // - life woundings + // - life caps + // - life defenses + + Show(); + } +} + +const char *szHitgroupNames[] = +{ + "head", + "chest", + "arm", + "leg" +}; + +void CDODDeathStatsPanel::Paint( void ) +{ + int deathNoticeWidth = 0; + + if ( m_DeathRecord.Victim.iEntIndex > 0 ) + deathNoticeWidth = DrawDeathNoticeItem( m_iDeathNoticeX, m_iDeathNoticeY ); + + const int minWidth = XRES(160); + + int panelWidth = ( deathNoticeWidth < minWidth ? minWidth : deathNoticeWidth ); + + int wide, tall; + + // set width of summary label to death notice width + m_pSummaryLabel->GetSize( wide, tall ); + m_pSummaryLabel->SetSize( panelWidth, tall ); + + C_DODPlayer *pLocalPlayer = C_DODPlayer::GetLocalDODPlayer(); + + if ( !pLocalPlayer ) + return; + + char buf[512]; + buf[0] = '\0'; + + if ( !m_DeathRecord.bSuicide ) + { + bool bStart = true; + bool bHit = false; + + for ( int i=0;i<4;i++ ) + { + if ( pLocalPlayer->m_iHitsOnAttacker[i] > 0 ) + { + bHit = true; + if ( bStart ) + { + Q_snprintf( buf, sizeof(buf), "You hit %s %i %s in the %s\n", + m_DeathRecord.Killer.szName, + pLocalPlayer->m_iHitsOnAttacker[i], + pLocalPlayer->m_iHitsOnAttacker[i] == 1 ? "time" : "times", + szHitgroupNames[i] ); + + bStart = false; + } + else + { + Q_snprintf( buf, sizeof(buf), "%s and %i %s in the %s\n", + buf, + pLocalPlayer->m_iHitsOnAttacker[i], + pLocalPlayer->m_iHitsOnAttacker[i] == 1 ? "time" : "times", + szHitgroupNames[i] ); + } + } + } + } + + Q_strncat( buf, "\n", sizeof(buf), COPY_ALL_CHARACTERS ); + + if ( pLocalPlayer->m_iPerLifeKills ) + { + Q_snprintf( buf, sizeof(buf), "%sKills: %i\n\n", + buf, + pLocalPlayer->m_iPerLifeKills ); + } + + if ( pLocalPlayer->m_iPerLifeWounded ) + { + Q_snprintf( buf, sizeof(buf), "%sWounded: %i\n\n", + buf, + pLocalPlayer->m_iPerLifeWounded ); + } + + if ( pLocalPlayer->m_iPerLifeCaptures ) + { + Q_snprintf( buf, sizeof(buf), "%sFlag Captures: %i\n\n", + buf, + pLocalPlayer->m_iPerLifeCaptures ); + } + + if ( pLocalPlayer->m_iPerLifeDefenses ) + { + Q_snprintf( buf, sizeof(buf), "%sFlag Defenses: %i\n\n", + buf, + pLocalPlayer->m_iPerLifeDefenses ); + } + + m_pAttackerHistoryLabel->SetText( buf ); + m_pAttackerHistoryLabel->SizeToContents(); + + int panel_h = YRES(160); + + SetSize( panelWidth, panel_h ); +} + +float GetScale( int nIconWidth, int nIconHeight, int nWidth, int nHeight ); + +int CDODDeathStatsPanel::DrawDeathNoticeItem( int x, int y ) +{ + // Get the team numbers for the players involved + int iKillerTeam = TEAM_UNASSIGNED; + int iVictimTeam = TEAM_UNASSIGNED; + + if( g_PR ) + { + iKillerTeam = g_PR->GetTeam( m_DeathRecord.Killer.iEntIndex ); + iVictimTeam = g_PR->GetTeam( m_DeathRecord.Victim.iEntIndex ); + } + + wchar_t victim[ 256 ]; + wchar_t killer[ 256 ]; + + g_pVGuiLocalize->ConvertANSIToUnicode( m_DeathRecord.Victim.szName, victim, sizeof( victim ) ); + g_pVGuiLocalize->ConvertANSIToUnicode( m_DeathRecord.Killer.szName, killer, sizeof( killer ) ); + + // Get the local position for this notice + int len = UTIL_ComputeStringWidth( m_hTextFont, victim ); + + int iconWide; + int iconTall; + + CHudTexture *icon = m_DeathRecord.iconDeath; + + Assert( icon ); + + if ( !icon ) + return 0; + + if( icon->bRenderUsingFont ) + { + iconWide = surface()->GetCharacterWidth( icon->hFont, icon->cCharacterInFont ); + iconTall = surface()->GetFontTall( icon->hFont ); + } + else + { + float scale = GetScale( icon->Width(), icon->Height(), XRES(cl_deathicon_width.GetInt()), YRES(cl_deathicon_height.GetInt()) ); + iconWide = (int)( scale * (float)icon->Width() ); + iconTall = (int)( scale * (float)icon->Height() ); + } + + int spacerX = XRES(5); + + //int x = xRight - len - spacerX - iconWide - XRES(10); + + surface()->DrawSetTextFont( m_hTextFont ); + int iFontTall = vgui::surface()->GetFontTall( m_hTextFont ); + int yText = y + ( iconTall - iFontTall ) / 2; + + int boxWidth = len + iconWide + spacerX; + int boxHeight = MIN( iconTall, m_flLineHeight ); + int boxBorder = XRES(2); + + // Only draw killers name if it wasn't a suicide + if ( !m_DeathRecord.bSuicide ) + { + int nameWidth = UTIL_ComputeStringWidth( m_hTextFont, killer ) + spacerX; // gap + + //x -= nameWidth; + boxWidth += nameWidth; + + Panel::DrawBox( x-boxBorder, + y-boxBorder, + boxWidth+2*boxBorder, + boxHeight+2*boxBorder, + m_ActiveBackgroundColor, + 1.0 ); + + Color c = g_PR->GetTeamColor( iKillerTeam ); + surface()->DrawSetTextColor( c ); + + // Draw killer's name + surface()->DrawSetTextPos( x, yText ); + const wchar_t *p = killer; + while ( *p ) + { + surface()->DrawUnicodeChar( *p++ ); + } + surface()->DrawGetTextPos( x, yText ); + + x += spacerX; + } + else + { + Panel::DrawBox( x-boxBorder, + y-boxBorder, + boxWidth+2*boxBorder, + boxHeight+2*boxBorder, + m_ActiveBackgroundColor, + 1.0 ); + } + + Color iconColor( 255, 80, 0, 255 ); + + // Draw death weapon + //If we're using a font char, this will ignore iconTall and iconWide + icon->DrawSelf( x, y, iconWide, iconTall, iconColor ); + x += iconWide + spacerX; + + Color c = g_PR->GetTeamColor( iVictimTeam ); + surface()->DrawSetTextColor( c ); + + // Draw victims name + surface()->DrawSetTextFont( m_hTextFont ); //reset the font, draw icon can change it + surface()->DrawSetTextPos( x, yText ); + const wchar_t *p = victim; + while ( *p ) + { + surface()->DrawUnicodeChar( *p++ ); + } + + return boxWidth; +} diff --git a/game/client/dod/dod_hud_deathstats.h b/game/client/dod/dod_hud_deathstats.h new file mode 100644 index 0000000..e088719 --- /dev/null +++ b/game/client/dod/dod_hud_deathstats.h @@ -0,0 +1,90 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef DOD_HUD_DEATHSTATS_H +#define DOD_HUD_DEATHSTATS_H +#ifdef _WIN32 +#pragma once +#endif + +#include <vgui_controls/EditablePanel.h> +#include <game/client/iviewport.h> +#include <vgui/IScheme.h> +#include <vgui_controls/Label.h> +#include "hud.h" +#include "hudelement.h" +#include "dod_shareddefs.h" + +using namespace vgui; + +#define MAX_DEATHSTATS_NAME_LENGTH 128 // to hold multiple player cappers + +// Player entries in a death notice +struct DeathStatsPlayer +{ + char szName[MAX_DEATHSTATS_NAME_LENGTH]; + int iEntIndex; +}; + +// Contents of each entry in our list of death notices +struct DeathStatsRecord +{ + DeathStatsPlayer Killer; + DeathStatsPlayer Victim; + CHudTexture *iconDeath; + bool bSuicide; +}; + +class CDODDeathStatsPanel : public EditablePanel, public CHudElement +{ +private: + DECLARE_CLASS_SIMPLE( CDODDeathStatsPanel, EditablePanel ); + +public: + CDODDeathStatsPanel( const char *pElementName ); + + virtual void Reset(); + virtual void Init(); + virtual void VidInit(); + virtual void ApplySchemeSettings( vgui::IScheme *pScheme ); + virtual void OnScreenSizeChanged( int iOldWide, int iOldTall ); + + virtual void FireGameEvent( IGameEvent * event); + virtual void Paint( void ); + int DrawDeathNoticeItem( int xRight, int y ); + + void Show() { SetAlpha( 255 ); } + void Hide() { SetAlpha( 0 ); } + +protected: + + vgui::Label *m_pSummaryLabel; + vgui::Label *m_pAttackerHistoryLabel; + + DeathStatsRecord m_DeathRecord; + + int m_iMaterialTexture; + + // Special death notice icons + CHudTexture *m_iconD_skull; + + // Icons for stats + CHudTexture *m_pIconKill; + CHudTexture *m_pIconWounded; + CHudTexture *m_pIconCap; + CHudTexture *m_pIconDefended; + + + CPanelAnimationVar( vgui::HFont, m_hTextFont, "TextFont", "HudNumbersTimer" ); + CPanelAnimationVarAliasType( float, m_flLineHeight, "LineHeight", "15", "proportional_float" ); + CPanelAnimationVar( Color, m_ActiveBackgroundColor, "ActiveBackgroundColor", "255 255 255 140" ); + + CPanelAnimationVarAliasType( int, m_iDeathNoticeX, "DeathNoticeX", "5", "proportional_int" ); + CPanelAnimationVarAliasType( int, m_iDeathNoticeY, "DeathNoticeY", "5", "proportional_int" ); +}; + +#endif //DOD_HUD_DEATHSTATS_H
\ No newline at end of file diff --git a/game/client/dod/dod_hud_freezepanel.cpp b/game/client/dod/dod_hud_freezepanel.cpp new file mode 100644 index 0000000..0d28970 --- /dev/null +++ b/game/client/dod/dod_hud_freezepanel.cpp @@ -0,0 +1,667 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#include "cbase.h" +#include "dod_hud_freezepanel.h" +#include "vgui_controls/AnimationController.h" +#include "iclientmode.h" +#include "c_dod_player.h" +#include "c_dod_playerresource.h" +#include <vgui_controls/Label.h> +#include <vgui/ILocalize.h> +#include <vgui/ISurface.h> +#include "fmtstr.h" +#include "dod_gamerules.h" +#include "view.h" +#include "ivieweffects.h" +#include "viewrender.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +DECLARE_HUDELEMENT_DEPTH( CDODFreezePanel, 1 ); + +#define CALLOUT_WIDE (XRES(100)) +#define CALLOUT_TALL (XRES(50)) + +extern float g_flFreezeFlash; + +ConVar cl_dod_freezecam( "cl_dod_freezecam", "1", FCVAR_ARCHIVE, "Client option to not show freeze camera on death" ); + +#define FREEZECAM_SCREENSHOT_STRING "is looking good!" + +bool IsTakingAFreezecamScreenshot( void ) +{ + // Don't draw in freezecam, or when the game's not running + C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer(); + bool bInFreezeCam = ( pPlayer && pPlayer->GetObserverMode() == OBS_MODE_FREEZECAM ); + + if ( bInFreezeCam == true && engine->IsTakingScreenshot() ) + return true; + + CDODFreezePanel *pPanel = GET_HUDELEMENT( CDODFreezePanel ); + if ( pPanel ) + { + if ( pPanel->IsHoldingAfterScreenShot() ) + return true; + } + + return false; +} + +//----------------------------------------------------------------------------- +// Purpose: Constructor +//----------------------------------------------------------------------------- +CDODFreezePanel::CDODFreezePanel( const char *pElementName ) +: EditablePanel( NULL, "FreezePanel" ), CHudElement( pElementName ) +{ + vgui::Panel *pParent = g_pClientMode->GetViewport(); + SetParent( pParent ); + SetVisible( false ); + SetScheme( "ClientScheme" ); + + m_iKillerIndex = 0; + m_iShowNemesisPanel = SHOW_NO_NEMESIS; + m_iYBase = -1; + m_flShowCalloutsAt = 0; + + m_iBasePanelOriginalX = -1; + m_iBasePanelOriginalY = -1; + + RegisterForRenderGroup( "winpanel" ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CDODFreezePanel::Reset() +{ + Hide(); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CDODFreezePanel::Init() +{ + // listen for events + ListenForGameEvent( "show_freezepanel" ); + ListenForGameEvent( "hide_freezepanel" ); + ListenForGameEvent( "freezecam_started" ); + ListenForGameEvent( "player_death" ); + ListenForGameEvent( "dod_win_panel" ); + + Hide(); + + CHudElement::Init(); +} + +//----------------------------------------------------------------------------- +// Purpose: Applies scheme settings +//----------------------------------------------------------------------------- +void CDODFreezePanel::ApplySchemeSettings( vgui::IScheme *pScheme ) +{ + BaseClass::ApplySchemeSettings( pScheme ); + + LoadControlSettings( "resource/UI/FreezePanel_Basic.res" ); + + m_pBasePanel = dynamic_cast<EditablePanel *>( FindChildByName("FreezePanelBase") ); + + Assert( m_pBasePanel ); + + if ( m_pBasePanel ) + { + m_pFreezeLabel = dynamic_cast<Label *>( m_pBasePanel->FindChildByName("FreezeLabel") ); + m_pFreezePanelBG = m_pBasePanel->FindChildByName( "FreezePanelBG" ); + m_pNemesisSubPanel = dynamic_cast<EditablePanel *>( m_pBasePanel->FindChildByName( "NemesisSubPanel" ) ); + m_pHealthStatus = dynamic_cast<CDoDHudHealth *>( m_pBasePanel->FindChildByName( "PlayerStatusHealth" ) ); + m_pAvatar = dynamic_cast<CAvatarImagePanel *>( m_pBasePanel->FindChildByName("AvatarImage") ); + + if ( m_pAvatar ) + { + m_pAvatar->SetShouldScaleImage( true ); + m_pAvatar->SetShouldDrawFriendIcon( false ); + } + } + + m_pScreenshotPanel = dynamic_cast<EditablePanel *>( FindChildByName( "ScreenshotPanel" ) ); + Assert( m_pScreenshotPanel ); + + // Move killer panels when the win panel is up + int xp,yp; + GetPos( xp, yp ); + m_iYBase = yp; + + int w, h; + m_pBasePanel->GetBounds( m_iBasePanelOriginalX, m_iBasePanelOriginalY, w, h ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CDODFreezePanel::FireGameEvent( IGameEvent * event ) +{ + if ( !cl_dod_freezecam.GetBool() ) + { + if ( IsVisible() ) + { + Hide(); + } + return; + } + + const char *pEventName = event->GetName(); + + if ( Q_strcmp( "player_death", pEventName ) == 0 ) + { + // see if the local player died + int iPlayerIndexVictim = engine->GetPlayerForUserID( event->GetInt( "userid" ) ); + C_DODPlayer *pLocalPlayer = C_DODPlayer::GetLocalDODPlayer(); + if ( pLocalPlayer && iPlayerIndexVictim == pLocalPlayer->entindex() ) + { + // the local player is dead, see if this is a new nemesis or a revenge + if ( event->GetInt( "dominated" ) > 0 ) + { + m_iShowNemesisPanel = SHOW_NEW_NEMESIS; + } + else if ( event->GetInt( "revenge" ) > 0 ) + { + m_iShowNemesisPanel = SHOW_REVENGE; + } + else + { + m_iShowNemesisPanel = SHOW_NO_NEMESIS; + } + } + } + else if ( Q_strcmp( "hide_freezepanel", pEventName ) == 0 ) + { + Hide(); + } + else if ( Q_strcmp( "freezecam_started", pEventName ) == 0 ) + { + ShowCalloutsIn( 1.0 ); + ShowSnapshotPanelIn( 1.0 ); + } + else if ( Q_strcmp( "dod_win_panel", pEventName ) == 0 ) + { + Hide(); + } + else if ( Q_strcmp( "show_freezepanel", pEventName ) == 0 ) + { + C_DOD_PlayerResource *tf_PR = dynamic_cast<C_DOD_PlayerResource *>(g_PR); + if ( !tf_PR ) + { + m_pNemesisSubPanel->SetDialogVariable( "nemesisname", NULL ); + return; + } + + Show(); + + ShowSnapshotPanel( false ); + m_bHoldingAfterScreenshot = false; + + if ( m_iBasePanelOriginalX > -1 && m_iBasePanelOriginalY > -1 ) + { + m_pBasePanel->SetPos( m_iBasePanelOriginalX, m_iBasePanelOriginalY ); + } + + // Get the entity who killed us + m_iKillerIndex = event->GetInt( "killer" ); + C_BaseEntity *pKiller = ClientEntityList().GetBaseEntity( m_iKillerIndex ); + + int xp,yp; + GetPos( xp, yp ); + SetPos( xp, m_iYBase ); + + bool bShowHealth = pKiller && pKiller->IsPlayer(); + m_pHealthStatus->SetVisible( bShowHealth ); + if ( bShowHealth ) + { + m_pHealthStatus->SetHealthDelegatePlayer( ToDODPlayer(pKiller) ); + } + + if ( pKiller ) + { + if ( pKiller->IsPlayer() ) + { + C_DODPlayer *pVictim = C_DODPlayer::GetLocalDODPlayer(); + C_DODPlayer *pDODKiller = ToDODPlayer( pKiller ); + + //If this was just a regular kill but this guy is our nemesis then just show it. + if ( pVictim && pDODKiller && pDODKiller->m_Shared.IsPlayerDominated( pVictim->entindex() ) ) + { + if ( !pKiller->IsAlive() ) + { + m_pFreezeLabel->SetText( "#FreezePanel_Nemesis_Dead" ); + } + else + { + m_pFreezeLabel->SetText( "#FreezePanel_Nemesis" ); + } + } + else + { + if ( !pKiller->IsAlive() ) + { + m_pFreezeLabel->SetText( "#FreezePanel_Killer_Dead" ); + } + else + { + m_pFreezeLabel->SetText( "#FreezePanel_Killer" ); + } + } + + m_pBasePanel->SetDialogVariable( "killername", g_PR->GetPlayerName( m_iKillerIndex ) ); + + if ( m_pAvatar ) + { + m_pAvatar->SetPlayer( (C_BasePlayer*)pKiller ); + } + } + else if ( m_pFreezeLabel ) + { + if ( !pKiller->IsAlive() ) + { + m_pFreezeLabel->SetText( "#FreezePanel_Killer_Dead" ); + } + else + { + m_pFreezeLabel->SetText( "#FreezePanel_Killer" ); + } + } + } + + // see if we should show nemesis panel + const wchar_t *pchNemesisText = NULL; + switch ( m_iShowNemesisPanel ) + { + case SHOW_NO_NEMESIS: + { + C_DODPlayer *pVictim = C_DODPlayer::GetLocalDODPlayer(); + C_DODPlayer *pTFKiller = ToDODPlayer( pKiller ); + + //If this was just a regular kill but this guy is our nemesis then just show it. + if ( pTFKiller && pTFKiller->m_Shared.IsPlayerDominated( pVictim->entindex() ) ) + { + pchNemesisText = g_pVGuiLocalize->Find( "#FreezePanel_FreezeNemesis" ); + } + } + break; + case SHOW_NEW_NEMESIS: + { + C_DODPlayer *pVictim = C_DODPlayer::GetLocalDODPlayer(); + C_DODPlayer *pTFKiller = ToDODPlayer( pKiller ); + // check to see if killer is still the nemesis of victim; victim may have managed to kill him after victim's + // death by grenade or some such, extracting revenge and clearing nemesis condition + if ( pTFKiller && pTFKiller->m_Shared.IsPlayerDominated( pVictim->entindex() ) ) + { + pchNemesisText = g_pVGuiLocalize->Find( "#FreezePanel_NewNemesis" ); + } + } + break; + case SHOW_REVENGE: + pchNemesisText = g_pVGuiLocalize->Find( "#FreezePanel_GotRevenge" ); + break; + default: + Assert( false ); // invalid value + break; + } + m_pNemesisSubPanel->SetDialogVariable( "nemesisname", pchNemesisText ); + + ShowNemesisPanel( NULL != pchNemesisText ); + m_iShowNemesisPanel = SHOW_NO_NEMESIS; + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CDODFreezePanel::ShowCalloutsIn( float flTime ) +{ + m_flShowCalloutsAt = gpGlobals->curtime + flTime; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +CDODFreezePanelCallout *CDODFreezePanel::TestAndAddCallout( Vector &origin, Vector &vMins, Vector &vMaxs, CUtlVector<Vector> *vecCalloutsTL, + CUtlVector<Vector> *vecCalloutsBR, Vector &vecFreezeTL, Vector &vecFreezeBR, Vector &vecStatTL, Vector &vecStatBR, int *iX, int *iY ) +{ + // This is the offset from the topleft of the callout to the arrow tip + const int iXOffset = XRES(25); + const int iYOffset = YRES(50); + + //if ( engine->IsBoxInViewCluster( vMins + origin, vMaxs + origin) && !engine->CullBox( vMins + origin, vMaxs + origin ) ) + { + if ( GetVectorInHudSpace( origin, *iX, *iY ) ) // TODO: GetVectorInHudSpace or GetVectorInScreenSpace? + { + *iX -= iXOffset; + *iY -= iYOffset; + int iRight = *iX + CALLOUT_WIDE; + int iBottom = *iY + CALLOUT_TALL; + if ( *iX > 0 && *iY > 0 && (iRight < ScreenWidth()) && (iBottom < (ScreenHeight()-YRES(40))) ) + { + // Make sure it wouldn't be over the top of the freezepanel or statpanel + Vector vecCalloutTL( *iX, *iY, 0 ); + Vector vecCalloutBR( iRight, iBottom, 1 ); + if ( !QuickBoxIntersectTest( vecCalloutTL, vecCalloutBR, vecFreezeTL, vecFreezeBR ) && + !QuickBoxIntersectTest( vecCalloutTL, vecCalloutBR, vecStatTL, vecStatBR ) ) + { + // Make sure it doesn't intersect any other callouts + bool bClear = true; + for ( int iCall = 0; iCall < vecCalloutsTL->Count(); iCall++ ) + { + if ( QuickBoxIntersectTest( vecCalloutTL, vecCalloutBR, vecCalloutsTL->Element(iCall), vecCalloutsBR->Element(iCall) ) ) + { + bClear = false; + break; + } + } + + if ( bClear ) + { + // Verify that we have LOS to the gib + trace_t tr; + UTIL_TraceLine( origin, MainViewOrigin(), MASK_OPAQUE, NULL, COLLISION_GROUP_NONE, &tr ); + bClear = ( tr.fraction >= 1.0f ); + } + + if ( bClear ) + { + CDODFreezePanelCallout *pCallout = new CDODFreezePanelCallout( g_pClientMode->GetViewport(), "FreezePanelCallout" ); + m_pCalloutPanels.AddToTail( vgui::SETUP_PANEL(pCallout) ); + vecCalloutsTL->AddToTail( vecCalloutTL ); + vecCalloutsBR->AddToTail( vecCalloutBR ); + pCallout->SetVisible( true ); + pCallout->SetBounds( *iX, *iY, CALLOUT_WIDE, CALLOUT_TALL ); + return pCallout; + } + } + } + } + } + + return NULL; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CDODFreezePanel::UpdateCallout( void ) +{ + CDODPlayer *pPlayer = C_DODPlayer::GetLocalDODPlayer(); + if ( !pPlayer ) + return; + + // Abort early if we have no ragdoll + IRagdoll *pRagdoll = pPlayer->GetRepresentativeRagdoll(); + if ( !pRagdoll ) + return; + + if ( m_pFreezePanelBG == NULL ) + return; + + // Precalc the vectors of the freezepanel & statpanel + int iX, iY; + m_pFreezePanelBG->GetPos( iX, iY ); + Vector vecFreezeTL( iX, iY, 0 ); + Vector vecFreezeBR( iX + m_pFreezePanelBG->GetWide(), iY + m_pFreezePanelBG->GetTall(), 1 ); + + CUtlVector<Vector> vecCalloutsTL; + CUtlVector<Vector> vecCalloutsBR; + + Vector vecStatTL(0,0,0); + Vector vecStatBR(0,0,1); + + Vector vMins, vMaxs; + + if ( pRagdoll ) + { + Vector origin = pRagdoll->GetRagdollOrigin(); + pRagdoll->GetRagdollBounds( vMins, vMaxs ); + + // Try and add the callout + //CDODFreezePanelCallout *pCallout = + + TestAndAddCallout( origin, vMins, vMaxs, &vecCalloutsTL, &vecCalloutsBR, + vecFreezeTL, vecFreezeBR, vecStatTL, vecStatBR, &iX, &iY ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CDODFreezePanel::Show() +{ + m_flShowCalloutsAt = 0; + SetVisible( true ); + + int iRenderGroup = gHUD.LookupRenderGroupIndexByName( "freezepanel" ); + if ( iRenderGroup >= 0 ) + { + gHUD.LockRenderGroup( iRenderGroup ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CDODFreezePanel::Hide() +{ + SetVisible( false ); + m_bHoldingAfterScreenshot = false; + + // Delete all our callout panels + for ( int i = m_pCalloutPanels.Count()-1; i >= 0; i-- ) + { + m_pCalloutPanels[i]->MarkForDeletion(); + } + m_pCalloutPanels.RemoveAll(); + + int iRenderGroup = gHUD.LookupRenderGroupIndexByName( "winpanel" ); + if ( iRenderGroup >= 0 ) + { + gHUD.UnlockRenderGroup( iRenderGroup ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +bool CDODFreezePanel::ShouldDraw( void ) +{ + if ( !CHudElement::ShouldDraw() ) + return false; + + return ( IsVisible() ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CDODFreezePanel::OnThink( void ) +{ + BaseClass::OnThink(); + + if ( m_flShowCalloutsAt && m_flShowCalloutsAt < gpGlobals->curtime ) + { + if ( ShouldDraw() ) + { + UpdateCallout(); + } + m_flShowCalloutsAt = 0; + } + + if ( m_flShowSnapshotReminderAt && m_flShowSnapshotReminderAt < gpGlobals->curtime ) + { + if ( ShouldDraw() ) + { + ShowSnapshotPanel( true ); + } + m_flShowSnapshotReminderAt = 0; + } +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CDODFreezePanel::ShowSnapshotPanelIn( float flTime ) +{ + m_flShowSnapshotReminderAt = gpGlobals->curtime + flTime; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CDODFreezePanel::ShowSnapshotPanel( bool bShow ) +{ + if ( !m_pScreenshotPanel ) + return; + + const char *key = engine->Key_LookupBinding( "screenshot" ); + + if ( key == NULL || FStrEq( key, "(null)" ) ) + { + bShow = false; + key = " "; + } + + if ( bShow ) + { + char szKey[16]; + Q_snprintf( szKey, sizeof(szKey), "%s", key ); + wchar_t wKey[16]; + wchar_t wLabel[256]; + + g_pVGuiLocalize->ConvertANSIToUnicode(szKey, wKey, sizeof(wKey)); + g_pVGuiLocalize->ConstructString( wLabel, sizeof( wLabel ), g_pVGuiLocalize->Find("#TF_freezecam_snapshot" ), 1, wKey ); + + m_pScreenshotPanel->SetDialogVariable( "text", wLabel ); + + g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( this, "HudSnapShotReminderIn" ); + } + + m_pScreenshotPanel->SetVisible( bShow ); +} + +int CDODFreezePanel::HudElementKeyInput( int down, ButtonCode_t keynum, const char *pszCurrentBinding ) +{ + if ( ShouldDraw() && pszCurrentBinding ) + { + if ( FStrEq( pszCurrentBinding, "screenshot" ) || FStrEq( pszCurrentBinding, "jpeg" ) ) + { + // move the target id to the corner + if ( m_pBasePanel ) + { + int w, h; + m_pBasePanel->GetSize( w, h ); + m_pBasePanel->SetPos( ScreenWidth() - w, ScreenHeight() - h ); + } + + // Get the local player. + C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer(); + if ( pPlayer ) + { + //Do effects + g_flFreezeFlash = gpGlobals->curtime + 0.75f; + pPlayer->EmitSound( "Camera.SnapShot" ); + + //Extend Freezecam by a couple more seconds. + engine->ClientCmd( "extendfreeze" ); + view->FreezeFrame( 3.0f ); + + //Hide the reminder panel + m_flShowSnapshotReminderAt = 0; + ShowSnapshotPanel( false ); + + m_bHoldingAfterScreenshot = true; + + //Set the screenshot name + if ( m_iKillerIndex <= MAX_PLAYERS ) + { + const char *pszKillerName = g_PR->GetPlayerName( m_iKillerIndex ); + + if ( pszKillerName ) + { + ConVarRef cl_screenshotname( "cl_screenshotname" ); + + if ( cl_screenshotname.IsValid() ) + { + char szScreenShotName[512]; + + Q_snprintf( szScreenShotName, sizeof( szScreenShotName ), "%s %s", pszKillerName, FREEZECAM_SCREENSHOT_STRING ); + + cl_screenshotname.SetValue( szScreenShotName ); + } + } + } + } + } + } + + return 0; +} + +//----------------------------------------------------------------------------- +// Purpose: Shows or hides the nemesis part of the panel +//----------------------------------------------------------------------------- +void CDODFreezePanel::ShowNemesisPanel( bool bShow ) +{ + m_pNemesisSubPanel->SetVisible( bShow ); + + if ( bShow ) + { + vgui::Label *pLabel = dynamic_cast< vgui::Label *>( m_pNemesisSubPanel->FindChildByName( "NemesisLabel" ) ); + vgui::Panel *pBG = m_pNemesisSubPanel->FindChildByName( "NemesisPanelBG" ); + vgui::ImagePanel *pIcon = dynamic_cast< vgui::ImagePanel *>( m_pNemesisSubPanel->FindChildByName( "NemesisIcon" ) ); + + // check that our Nemesis panel and resize it to the length of the string (the right side is pinned and doesn't move) + if ( pLabel && pBG && pIcon ) + { + int wide, tall; + pLabel->GetContentSize( wide, tall ); + + int nDiff = wide - pLabel->GetWide(); + + if ( nDiff != 0 ) + { + int x, y, w, t; + + // move the icon + pIcon->GetBounds( x, y, w, t ); + pIcon->SetBounds( x - nDiff, y, w, t ); + + // move/resize the label + pLabel->GetBounds( x, y, w, t ); + pLabel->SetBounds( x - nDiff, y, w + nDiff, t ); + + // move/resize the background + pBG->GetBounds( x, y, w, t ); + pBG->SetBounds( x - nDiff, y, w + nDiff, t ); + } + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +CDODFreezePanelCallout::CDODFreezePanelCallout( Panel *parent, const char *name ) : EditablePanel(parent,name) +{ +} + +//----------------------------------------------------------------------------- +// Purpose: Applies scheme settings +//----------------------------------------------------------------------------- +void CDODFreezePanelCallout::ApplySchemeSettings( vgui::IScheme *pScheme ) +{ + BaseClass::ApplySchemeSettings( pScheme ); + + LoadControlSettings( "resource/UI/FreezePanelCallout.res" ); +}
\ No newline at end of file diff --git a/game/client/dod/dod_hud_freezepanel.h b/game/client/dod/dod_hud_freezepanel.h new file mode 100644 index 0000000..86fc847 --- /dev/null +++ b/game/client/dod/dod_hud_freezepanel.h @@ -0,0 +1,122 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#ifndef DOD_HUD_FREEZEPANEL_H +#define DOD_HUD_FREEZEPANEL_H +#ifdef _WIN32 +#pragma once +#endif + +#include <vgui_controls/EditablePanel.h> +#include <game/client/iviewport.h> +#include <vgui/IScheme.h> +#include "hud.h" +#include "hudelement.h" +#include "vgui_controls/ImagePanel.h" +#include "vgui_avatarimage.h" +#include "dod_hud_playerstatus_health.h" + +using namespace vgui; + +bool IsTakingAFreezecamScreenshot( void ); + +/* +//----------------------------------------------------------------------------- +// Purpose: Custom health panel used in the freeze panel to show killer's health +//----------------------------------------------------------------------------- +class CDODFreezePanelHealth : public CTFHudPlayerHealth +{ +public: + CTFFreezePanelHealth( Panel *parent, const char *name ) : CTFHudPlayerHealth( parent, name ) + { + } + + virtual const char *GetResFilename( void ) { return "resource/UI/FreezePanelKillerHealth.res"; } + virtual void OnThink() + { + // Do nothing. We're just preventing the base health panel from updating. + } +}; +*/ + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class CDODFreezePanelCallout : public EditablePanel +{ + DECLARE_CLASS_SIMPLE( CDODFreezePanelCallout, EditablePanel ); +public: + CDODFreezePanelCallout( Panel *parent, const char *name ); + + virtual void ApplySchemeSettings( vgui::IScheme *pScheme ); +}; + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class CDODFreezePanel : public EditablePanel, public CHudElement +{ +private: + DECLARE_CLASS_SIMPLE( CDODFreezePanel, EditablePanel ); + +public: + CDODFreezePanel( const char *pElementName ); + + virtual void Reset(); + virtual void Init(); + virtual void ApplySchemeSettings( vgui::IScheme *pScheme ); + virtual void FireGameEvent( IGameEvent * event ); + + void ShowSnapshotPanel( bool bShow ); + void UpdateCallout( void ); + void ShowCalloutsIn( float flTime ); + void ShowSnapshotPanelIn( float flTime ); + void Show(); + void Hide(); + virtual bool ShouldDraw( void ); + void OnThink( void ); + + int HudElementKeyInput( int down, ButtonCode_t keynum, const char *pszCurrentBinding ); + + bool IsHoldingAfterScreenShot( void ) { return m_bHoldingAfterScreenshot; } + +protected: + CDODFreezePanelCallout *TestAndAddCallout( Vector &origin, Vector &vMins, Vector &vMaxs, CUtlVector<Vector> *vecCalloutsTL, + CUtlVector<Vector> *vecCalloutsBR, Vector &vecFreezeTL, Vector &vecFreezeBR, Vector &vecStatTL, Vector &vecStatBR, int *iX, int *iY ); + +private: + void ShowNemesisPanel( bool bShow ); + + int m_iYBase; + int m_iKillerIndex; + //CTFHudPlayerHealth *m_pKillerHealth; + int m_iShowNemesisPanel; + CUtlVector<CDODFreezePanelCallout*> m_pCalloutPanels; + float m_flShowCalloutsAt; + float m_flShowSnapshotReminderAt; + EditablePanel *m_pNemesisSubPanel; + vgui::Label *m_pFreezeLabel; + vgui::Panel *m_pFreezePanelBG; + CAvatarImagePanel *m_pAvatar; + vgui::EditablePanel *m_pScreenshotPanel; + vgui::EditablePanel *m_pBasePanel; + + int m_iBasePanelOriginalX; + int m_iBasePanelOriginalY; + + bool m_bHoldingAfterScreenshot; + + CDoDHudHealth *m_pHealthStatus; + + enum + { + SHOW_NO_NEMESIS = 0, + SHOW_NEW_NEMESIS, + SHOW_REVENGE + }; +}; + +#endif // DOD_HUD_FREEZEPANEL_H diff --git a/game/client/dod/dod_hud_health.cpp b/game/client/dod/dod_hud_health.cpp new file mode 100644 index 0000000..3cd21f5 --- /dev/null +++ b/game/client/dod/dod_hud_health.cpp @@ -0,0 +1,191 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// +// +// Health.cpp +// +// implementation of CHudHealth class +// +#include "cbase.h" +#include "hud.h" +#include "hud_macros.h" +#include "view.h" + +#include "iclientmode.h" + +#include <KeyValues.h> +#include <vgui/ISurface.h> +#include <vgui/ISystem.h> +#include <vgui_controls/AnimationController.h> +#include <vgui_controls/Panel.h> + +using namespace vgui; + +#include "hudelement.h" +#include "convar.h" +#include "c_dod_player.h" + +//----------------------------------------------------------------------------- +// Purpose: Health panel +//----------------------------------------------------------------------------- +class CHudHealth : public CHudElement, public vgui::Panel +{ + DECLARE_CLASS_SIMPLE( CHudHealth, vgui::Panel ); + +public: + CHudHealth( const char *pElementName ); + virtual void Init( void ); + virtual void VidInit( void ); + virtual void Reset( void ); + virtual void OnThink(); + + virtual bool ShouldDraw( void ); + virtual void Paint( void ); + virtual void ApplySchemeSettings( IScheme *scheme ); + +private: + int m_iHealth; + int m_iStamina; + + CHudTexture *m_pIconHealthBar; + CHudTexture *m_pIconHealthOverlay; + CHudTexture *m_pIconBG; + CHudTexture *m_pIconStaminaBar; +}; + +//DECLARE_HUDELEMENT( CHudHealth ); + +//----------------------------------------------------------------------------- +// Purpose: Constructor +//----------------------------------------------------------------------------- +CHudHealth::CHudHealth( const char *pElementName ) : CHudElement( pElementName ), BaseClass(NULL, "HudHealth") +{ + SetParent( g_pClientMode->GetViewport() ); + SetHiddenBits( HIDEHUD_HEALTH | HIDEHUD_PLAYERDEAD ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CHudHealth::Init() +{ + m_iHealth = 100; +} + +void CHudHealth::ApplySchemeSettings( IScheme *scheme ) +{ + BaseClass::ApplySchemeSettings( scheme ); + + if( !m_pIconHealthBar ) + { + m_pIconHealthBar = gHUD.GetIcon( "hud_healthbar" ); + } + + if( !m_pIconHealthOverlay ) + { + m_pIconHealthOverlay = gHUD.GetIcon( "hud_health_overlay" ); + } + + if( !m_pIconBG ) + { + m_pIconBG = gHUD.GetIcon( "hud_main" ); + } + + if( !m_pIconStaminaBar ) + { + m_pIconStaminaBar = gHUD.GetIcon( "hud_staminabar" ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CHudHealth::Reset() +{ +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CHudHealth::VidInit() +{ +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CHudHealth::OnThink() +{ + int realHealth = 0; + C_DODPlayer *local = C_DODPlayer::GetLocalDODPlayer(); + if ( local ) + { + // Never below zero + realHealth = MAX( local->GetHealth(), 0 ); + + m_iStamina = local->m_Shared.GetStamina(); + } + + // Only update the fade if we've changed health + if ( realHealth == m_iHealth ) + { + return; + } + +#ifdef _DEBUG + g_pClientMode->GetViewportAnimationController()->SetAutoReloadScript(true); +#endif + + m_iHealth = realHealth; +} + +bool CHudHealth::ShouldDraw( void ) +{ + // No local player yet? + C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer(); + if ( !pPlayer ) + return false; + + if( pPlayer->GetTeamNumber() != TEAM_ALLIES && + pPlayer->GetTeamNumber() != TEAM_AXIS ) + return false; + + return CHudElement::ShouldDraw(); +} + +void CHudHealth::Paint( void ) +{ + int x, y, w, h; + GetBounds( x, y, w, h ); + + Color clrIcon(255,255,255,255); + + int xpos = 0; + int ypos = h - m_pIconBG->Height(); + + m_pIconBG->DrawSelf( xpos, ypos, clrIcon ); + + int nOffset = m_pIconHealthOverlay->Height() * ( 1.0 - ( (float)m_iHealth / 100.0 ) ); + if ( nOffset < m_pIconHealthOverlay->Height() ) + { + m_pIconHealthOverlay->DrawSelfCropped( xpos + 55, ypos + 27, 0, 0, m_pIconHealthOverlay->Width(), nOffset, clrIcon ); + } + + nOffset = m_pIconHealthBar->Height() * ( 1.0 - ( (float)m_iHealth / 100.0 ) ); + if ( nOffset < m_pIconHealthBar->Height() ) + { + m_pIconHealthBar->DrawSelfCropped( xpos + 99, ypos + 27 + nOffset, 0, nOffset, m_pIconHealthBar->Width(), m_pIconHealthBar->Height() - nOffset, clrIcon ); + } + + nOffset = m_pIconStaminaBar->Height() * ( 1.0 - ( (float)m_iStamina / 100.0 ) ); + if ( nOffset < m_pIconStaminaBar->Height() ) + { + m_pIconStaminaBar->DrawSelfCropped( xpos + 8, ypos + 12 + nOffset, 0, nOffset, m_pIconStaminaBar->Width(), m_pIconStaminaBar->Height() - nOffset, clrIcon ); + } + + BaseClass::Paint(); +} diff --git a/game/client/dod/dod_hud_hintdisplay.cpp b/game/client/dod/dod_hud_hintdisplay.cpp new file mode 100644 index 0000000..0c81c13 --- /dev/null +++ b/game/client/dod/dod_hud_hintdisplay.cpp @@ -0,0 +1,397 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#include "cbase.h" +#include "hud.h" +#include "hudelement.h" +#include "hud_macros.h" +#include "iclientmode.h" +#include "vgui_controls/AnimationController.h" +#include "vgui_controls/Label.h" +#include "vgui/ILocalize.h" +#include "vgui/ISurface.h" +#include "text_message.h" +#include "dod_hud_freezepanel.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +//----------------------------------------------------------------------------- +// Purpose: Displays current ammunition level +//----------------------------------------------------------------------------- +class CDODHudHintDisplay : public vgui::Panel, public CHudElement +{ + DECLARE_CLASS_SIMPLE( CDODHudHintDisplay, vgui::Panel ); + +public: + CDODHudHintDisplay( const char *pElementName ); + + void Init(); + void Reset(); + void MsgFunc_HintText( bf_read &msg ); + void FireGameEvent( IGameEvent * event); + + bool SetHintText( wchar_t *text ); + + virtual void PerformLayout(); + + virtual bool IsVisible( void ); + +protected: + virtual void ApplySchemeSettings( vgui::IScheme *pScheme ); + virtual void OnThink(); + +private: + vgui::HFont m_hFont; + Color m_bgColor; + vgui::Label *m_pLabel; + CUtlVector<vgui::Label *> m_Labels; + CPanelAnimationVarAliasType( int, m_iTextX, "text_xpos", "8", "proportional_int" ); + CPanelAnimationVarAliasType( int, m_iTextY, "text_ypos", "8", "proportional_int" ); + CPanelAnimationVarAliasType( int, m_iCenterX, "center_x", "0", "proportional_int" ); + CPanelAnimationVarAliasType( int, m_iCenterY, "center_y", "0", "proportional_int" ); +}; + +DECLARE_HUDELEMENT( CDODHudHintDisplay ); +DECLARE_HUD_MESSAGE( CDODHudHintDisplay, HintText ); + +#define MAX_HINT_STRINGS 5 + + +//----------------------------------------------------------------------------- +// Purpose: Constructor +//----------------------------------------------------------------------------- +CDODHudHintDisplay::CDODHudHintDisplay( const char *pElementName ) : BaseClass(NULL, "HudHintDisplay"), CHudElement( pElementName ) +{ + vgui::Panel *pParent = g_pClientMode->GetViewport(); + SetParent( pParent ); + SetVisible( false ); + SetAlpha( 0 ); + m_pLabel = new vgui::Label( this, "HudHintDisplayLabel", "" ); + + RegisterForRenderGroup( "winpanel" ); + RegisterForRenderGroup( "freezepanel" ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CDODHudHintDisplay::Init() +{ + HOOK_HUD_MESSAGE( CDODHudHintDisplay, HintText ); + + // listen for client side events + ListenForGameEvent( "player_hintmessage" ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CDODHudHintDisplay::Reset() +{ + SetHintText( NULL ); + SetAlpha( 0 ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CDODHudHintDisplay::ApplySchemeSettings( vgui::IScheme *pScheme ) +{ + BaseClass::ApplySchemeSettings( pScheme ); + + SetFgColor( GetSchemeColor("HintMessageFg", pScheme) ); + m_hFont = pScheme->GetFont( "HudHintText", true ); + m_pLabel->SetBgColor( GetSchemeColor("HintMessageBg", pScheme) ); + m_pLabel->SetPaintBackgroundType( 2 ); +} + +//----------------------------------------------------------------------------- +// Purpose: Sets the hint text, replacing variables as necessary +//----------------------------------------------------------------------------- +bool CDODHudHintDisplay::SetHintText( wchar_t *text ) +{ + // clear the existing text + for (int i = 0; i < m_Labels.Count(); i++) + { + m_Labels[i]->MarkForDeletion(); + } + m_Labels.RemoveAll(); + + wchar_t *p = text; + + while ( p ) + { + wchar_t *line = p; + wchar_t *end = wcschr( p, L'\n' ); + if ( end ) + { + //*end = 0; //eek + p = end+1; + } + else + { + p = NULL; + } + + // copy to a new buf if there are vars + wchar_t buf[512]; + buf[0] = '\0'; + int pos = 0; + + wchar_t *ws = line; + while( ws != end && *ws != 0 ) + { + // check for variables + if ( *ws == '%' ) + { + ++ws; + + wchar_t *end = wcschr( ws, '%' ); + if ( end ) + { + wchar_t token[64]; + wcsncpy( token, ws, end - ws ); + token[end - ws] = 0; + + ws += end - ws; + + // lookup key names + char binding[64]; + g_pVGuiLocalize->ConvertUnicodeToANSI( token, binding, sizeof(binding) ); + + const char *key = engine->Key_LookupBinding( *binding == '+' ? binding + 1 : binding ); + if ( !key ) + { + key = "< not bound >"; + } + + //!! change some key names into better names + char friendlyName[64]; + Q_snprintf( friendlyName, sizeof(friendlyName), "%s", key ); + Q_strupr( friendlyName ); + + g_pVGuiLocalize->ConvertANSIToUnicode( friendlyName, token, sizeof(token) ); + + buf[pos] = '\0'; + wcscat( buf, token ); + pos += wcslen(token); + } + else + { + buf[pos] = *ws; + ++pos; + } + } + else + { + buf[pos] = *ws; + ++pos; + } + + ++ws; + } + + buf[pos] = '\0'; + + // put it in a label + //vgui::Label *label = vgui::SETUP_PANEL(new vgui::Label(this, NULL, line)); + vgui::Label *label = vgui::SETUP_PANEL(new vgui::Label(this, NULL, buf)); + label->SetFont( m_hFont ); + label->SetPaintBackgroundEnabled( false ); + label->SetPaintBorderEnabled( false ); + label->SizeToContents(); + label->SetContentAlignment( vgui::Label::a_west ); + label->SetFgColor( GetFgColor() ); + m_Labels.AddToTail( vgui::SETUP_PANEL(label) ); + } + InvalidateLayout( true ); + + return true; +} + +//----------------------------------------------------------------------------- +// Purpose: Resizes the label +//----------------------------------------------------------------------------- +void CDODHudHintDisplay::PerformLayout() +{ + BaseClass::PerformLayout(); + int i; + + int wide, tall; + GetSize( wide, tall ); + + // find the widest line + int labelWide = 0; + for ( i=0; i<m_Labels.Count(); ++i ) + { + labelWide = MAX( labelWide, m_Labels[i]->GetWide() ); + } + + // find the total height + int fontTall = vgui::surface()->GetFontTall( m_hFont ); + int labelTall = fontTall * m_Labels.Count(); + + labelWide += m_iTextX*2; + labelTall += m_iTextY*2; + int x, y; + if ( m_iCenterX < 0 ) + { + x = 0; + } + else if ( m_iCenterX > 0 ) + { + x = wide - labelWide; + } + else + { + x = (wide - labelWide) / 2; + } + + if ( m_iCenterY > 0 ) + { + y = 0; + } + else if ( m_iCenterY < 0 ) + { + y = tall - labelTall; + } + else + { + y = (tall - labelTall) / 2; + } + m_pLabel->SetBounds( x, y, labelWide, labelTall ); + + // now lay out the sub-labels + for ( i=0; i<m_Labels.Count(); ++i ) + { + int xOffset = (labelWide - m_Labels[i]->GetWide())/2; + m_Labels[i]->SetPos( x + xOffset, y + m_iTextY + i*fontTall ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: Updates the label color each frame +//----------------------------------------------------------------------------- +void CDODHudHintDisplay::OnThink() +{ + m_pLabel->SetFgColor(GetFgColor()); + for (int i = 0; i < m_Labels.Count(); i++) + { + m_Labels[i]->SetFgColor(GetFgColor()); + } +} + +//----------------------------------------------------------------------------- +// Purpose: Activates the hint display +//----------------------------------------------------------------------------- +void CDODHudHintDisplay::MsgFunc_HintText( bf_read &msg ) +{ + // read the string(s) + char szString[255]; + static wchar_t szBuf[128]; + static wchar_t *pszBuf; + + // init buffers & pointers + szBuf[0] = 0; + pszBuf = szBuf; + + // read string and localize it + msg.ReadString( szString, sizeof(szString) ); + + char *tmpStr = hudtextmessage->LookupString( szString, NULL ); + + // try to localize + if ( tmpStr ) + { + pszBuf = g_pVGuiLocalize->Find( tmpStr ); + } + else + { + pszBuf = g_pVGuiLocalize->Find( szString ); + } + + if ( !pszBuf ) + { + // use plain ASCII string + g_pVGuiLocalize->ConvertANSIToUnicode( szString, szBuf, sizeof(szBuf) ); + pszBuf = szBuf; + } + + // make it visible + if ( SetHintText( pszBuf ) ) + { + SetVisible( true ); + //SetAlpha( 255 ); + g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( "HintMessageShow" ); + } + else + { + // it's being cleared, hide the panel + //SetAlpha( 0 ); + g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( "HintMessageHide" ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: Activates the hint display upon recieving a hint +//----------------------------------------------------------------------------- +void CDODHudHintDisplay::FireGameEvent( IGameEvent * event) +{ + // we sometimes hide the element when it's covered, don't start + // a hint during that time + if ( !ShouldDraw() ) + return; + + static wchar_t *pszBuf; + static wchar_t szBuf[128]; + + const char *hintmessage = event->GetString( "hintmessage" ); + + char *tmpStr = hudtextmessage->LookupString( hintmessage, NULL ); + + // try to localize + if ( tmpStr ) + { + pszBuf = g_pVGuiLocalize->Find( tmpStr ); + } + else + { + pszBuf = g_pVGuiLocalize->Find( hintmessage ); + } + + if ( !pszBuf ) + { + // its not in titles.txt or dod_english.txt, just print the text of it + // use plain ASCII string + g_pVGuiLocalize->ConvertANSIToUnicode( hintmessage, szBuf, sizeof(szBuf) ); + pszBuf = szBuf; + } + + // make it visible + if ( SetHintText( pszBuf ) ) + { + SetVisible( true ); + g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( "HintMessageShow" ); + } + else + { + // it's being cleared, hide the panel + g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( "HintMessageHide" ); + } +} + +bool CDODHudHintDisplay::IsVisible( void ) +{ + if ( IsTakingAFreezecamScreenshot() ) + return false; + + if ( !ShouldDraw() ) + return false; + + return BaseClass::IsVisible(); +} + diff --git a/game/client/dod/dod_hud_history_resource.cpp b/game/client/dod/dod_hud_history_resource.cpp new file mode 100644 index 0000000..41a6753 --- /dev/null +++ b/game/client/dod/dod_hud_history_resource.cpp @@ -0,0 +1,113 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Item pickup history displayed onscreen when items are picked up. +// +// $NoKeywords: $ +//=============================================================================// +#include "cbase.h" +#include "history_resource.h" +#include "hud_macros.h" +#include <vgui_controls/Controls.h> +#include <vgui/ISurface.h> +#include "iclientmode.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +using namespace vgui; + +extern ConVar hud_drawhistory_time; + +#define HISTORY_PICKUP_GAP (m_iHistoryGap + 5) +#define HISTORY_PICKUP_PICK_HEIGHT (32 + (m_iHistoryGap * 2)) +#define HISTORY_PICKUP_HEIGHT_MAX (GetTall() - 100) +#define ITEM_GUTTER_SIZE 48 + + +DECLARE_HUDELEMENT( CHudHistoryResource ); +DECLARE_HUD_MESSAGE( CHudHistoryResource, ItemPickup ); + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +CHudHistoryResource::CHudHistoryResource( const char *pElementName ) : + CHudElement( pElementName ), BaseClass( NULL, "HudHistoryResource" ) +{ + vgui::Panel *pParent = g_pClientMode->GetViewport(); + SetParent( pParent ); + SetHiddenBits( HIDEHUD_MISCSTATUS ); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *pScheme - +//----------------------------------------------------------------------------- +void CHudHistoryResource::ApplySchemeSettings( IScheme *pScheme ) +{ + BaseClass::ApplySchemeSettings( pScheme ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CHudHistoryResource::Init( void ) +{ + HOOK_HUD_MESSAGE( CHudHistoryResource, ItemPickup ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CHudHistoryResource::Reset( void ) +{ +} + +//----------------------------------------------------------------------------- +// Purpose: Set a new minimum size gap between history icons +//----------------------------------------------------------------------------- +void CHudHistoryResource::SetHistoryGap( int iNewHistoryGap ) +{ +} + +void CHudHistoryResource::AddToHistory( int iType, int iId, int iCount ) +{ +} + +void CHudHistoryResource::AddToHistory( int iType, const char *szName, int iCount ) +{ +} + +void CHudHistoryResource::AddToHistory( C_BaseCombatWeapon *weapon ) +{ +} + +//----------------------------------------------------------------------------- +// Purpose: Handle an item pickup event from the server +//----------------------------------------------------------------------------- +void CHudHistoryResource::MsgFunc_ItemPickup( bf_read &msg ) +{ +} + +//----------------------------------------------------------------------------- +// Purpose: If there aren't any items in the history, clear it out. +//----------------------------------------------------------------------------- +void CHudHistoryResource::CheckClearHistory( void ) +{ +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +bool CHudHistoryResource::ShouldDraw( void ) +{ + return false; +} + +//----------------------------------------------------------------------------- +// Purpose: Draw the pickup history +//----------------------------------------------------------------------------- +void CHudHistoryResource::Paint( void ) +{ +} + + diff --git a/game/client/dod/dod_hud_mgheaticon.cpp b/game/client/dod/dod_hud_mgheaticon.cpp new file mode 100644 index 0000000..19ba64f --- /dev/null +++ b/game/client/dod/dod_hud_mgheaticon.cpp @@ -0,0 +1,121 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#include "cbase.h" +#include "hudelement.h" +#include <vgui_controls/Panel.h> +#include <vgui/ISurface.h> +#include "c_dod_player.h" +#include "iclientmode.h" +#include "c_dod_playerresource.h" +#include "weapon_mg42.h" + + +class CHudMGHeatIcon : public CHudElement, public vgui::Panel +{ +public: + DECLARE_CLASS_SIMPLE( CHudMGHeatIcon, vgui::Panel ); + + CHudMGHeatIcon( const char *name ); + + virtual void Paint(); + virtual void Init(); + virtual bool ShouldDraw(); + +private: + CHudTexture *m_pBarrel; + CHudTexture *m_pHotBarrel; + + Color m_clrIcon; +}; + + +DECLARE_HUDELEMENT( CHudMGHeatIcon ); + + +CHudMGHeatIcon::CHudMGHeatIcon( const char *pName ) : + vgui::Panel( NULL, "HudMGHeatIcon" ), CHudElement( pName ) +{ + SetParent( g_pClientMode->GetViewport() ); + + m_clrIcon = Color(255,255,255,255); + + SetHiddenBits( HIDEHUD_PLAYERDEAD ); +} + +void CHudMGHeatIcon::Init() +{ + if( !m_pBarrel ) + { + m_pBarrel = gHUD.GetIcon( "hud_barrel" ); + } + + if( !m_pHotBarrel ) + { + m_pHotBarrel = gHUD.GetIcon( "hud_barrelo" ); + } +} + +bool CHudMGHeatIcon::ShouldDraw() +{ + C_DODPlayer *pPlayer = C_DODPlayer::GetLocalDODPlayer(); + + if( !pPlayer ) + return false; + + //is their active weapon an mg42 ? + CWeaponDODBase *pWeapon = pPlayer->GetActiveDODWeapon(); + if( pWeapon && pWeapon->IsA( WEAPON_MG42 ) ) + return true; + + return false; +} + +void CHudMGHeatIcon::Paint() +{ + int x,y,w,h; + GetBounds( x,y,w,h ); + + if( !m_pBarrel ) + { + m_pBarrel = gHUD.GetIcon( "hud_barrel" ); + } + + if( !m_pHotBarrel ) + { + m_pHotBarrel = gHUD.GetIcon( "hud_barrelo" ); + } + + //draw the base + m_pBarrel->DrawSelf( 0, 0, m_clrIcon ); + + float flPercentHotness = 0.0f; + + C_DODPlayer *pPlayer = C_DODPlayer::GetLocalDODPlayer(); + + if( !pPlayer ) + return; + + CWeaponDODBase *pWeapon = pPlayer->GetActiveDODWeapon(); + if( pWeapon && pWeapon->IsA( WEAPON_MG42 ) ) + { + CWeaponMG42 *pMG42 = (CWeaponMG42 *)pWeapon; + + if( pMG42 ) + { + flPercentHotness = (float)pMG42->GetWeaponHeat() / 100.0; + } + } + + int nOffset = m_pHotBarrel->Height() * ( 1.0 - flPercentHotness ); + if ( nOffset < m_pHotBarrel->Height() ) + { + m_pHotBarrel->DrawSelfCropped( 0, nOffset, 0, nOffset, m_pHotBarrel->Width(), m_pHotBarrel->Height() - nOffset, m_clrIcon ); + } + + +} + diff --git a/game/client/dod/dod_hud_objectiveicons.cpp b/game/client/dod/dod_hud_objectiveicons.cpp new file mode 100644 index 0000000..0fb260a --- /dev/null +++ b/game/client/dod/dod_hud_objectiveicons.cpp @@ -0,0 +1,903 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#include "cbase.h" +#include "hudelement.h" +#include <vgui_controls/Panel.h> +#include <vgui_controls/Label.h> +#include <vgui/ISurface.h> +#include "c_baseplayer.h" +#include <vgui_controls/Panel.h> +#include "dod_gamerules.h" +#include "iclientmode.h" +#include "c_dod_objective_resource.h" +#include "c_dod_playerresource.h" +#include "c_dod_player.h" +#include "VGuiMatSurface/IMatSystemSurface.h" +#include "hud_macros.h" +#include <baseviewport.h> //for IViewPortPanel +#include "spectatorgui.h" +#include "dod_round_timer.h" +#include "vgui_controls/AnimationController.h" +#include "dod_hud_freezepanel.h" + +class CHudObjectiveIcons : public CHudElement, public vgui::Panel +{ +public: + DECLARE_CLASS_SIMPLE( CHudObjectiveIcons, vgui::Panel ); + + CHudObjectiveIcons( const char *pName ); + + virtual void ApplySchemeSettings( IScheme *scheme ); + virtual void Paint(); + virtual void Init(); + virtual void VidInit(); + virtual void Reset(); + + virtual void FireGameEvent( IGameEvent *event ); + + void DrawBackgroundBox( int xpos, int ypos, int nBoxWidth, int nBoxHeight, bool bCutCorner ); + + virtual bool IsVisible( void ); + +private: + + vgui::Label *m_pTimer; + vgui::Label *m_pTimeAdded; + + CHudTexture *m_pIconDefended; + + int m_iCPTextures[8]; + int m_iCPCappingTextures[8]; + + int m_iBackgroundTexture; + Color m_clrBackground; + Color m_clrBorder; + + int m_iLastCP; // the index of the area we were last in + + CHudTexture *m_pC4Icon; + CHudTexture *m_pExplodedIcon; + CHudTexture *m_pC4PlantedBG; + + int m_iSecondsAdded; // how many seconds were added in the last time_added event + bool bInTimerWarningAnim; + float m_flDrawTimeAddedUntil; + + CPanelAnimationVar( vgui::HFont, m_hTimerFont, "TimerFont", "Default" ); + CPanelAnimationVar( vgui::HFont, m_hTimerFontSmall, "TimerFontSmall", "DefaultSmall" ); + + CPanelAnimationVar( vgui::HFont, m_hTextFont, "ChatFont", "Default" ); + + CPanelAnimationVarAliasType( int, m_nIconSize, "iconsize", "24", "proportional_int" ); + CPanelAnimationVarAliasType( int, m_nSeparatorWidth, "separator_width", "7", "proportional_int" ); + CPanelAnimationVarAliasType( int, m_nCornerCutSize, "CornerCutSize", "5", "proportional_int" ); + CPanelAnimationVarAliasType( int, m_nBackgroundOverlap, "BackgroundOverlap", "5", "proportional_int" ); + + CPanelAnimationVarAliasType( int, m_iIconStartX, "icon_start_x", "10", "proportional_int" ); + CPanelAnimationVarAliasType( int, m_iIconStartY, "icon_start_y", "10", "proportional_int" ); + CPanelAnimationVarAliasType( float, m_flIconExpand, "icon_expand", "0", "proportional_float" ); + + CPanelAnimationVar( Color, m_clrTimer, "TimerBG", "255 0 0 128" ); + + CPanelAnimationVarAliasType( int, m_nTimeAddedHeight, "time_added_height", "12", "proportional_int" ); + CPanelAnimationVar( float, m_flTimeAddedExpandPercent, "time_added_height_anim", "0.0" ); + CPanelAnimationVar( float, m_flTimeAddedAlpha, "time_added_alpha", "0" ); + + CPanelAnimationVar( float, m_flTimeAddedDuration, "time_added_duration", "3.5" ); +}; + +DECLARE_HUDELEMENT( CHudObjectiveIcons ); + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +CHudObjectiveIcons::CHudObjectiveIcons( const char *pName ) : vgui::Panel( NULL, "HudObjectiveIcons" ), CHudElement( pName ) +{ + SetParent( g_pClientMode->GetViewport() ); + SetHiddenBits( 0 ); + + m_pTimer = new vgui::Label( this, "HudObjectivesRoundTimer", " " ); + if ( m_pTimer ) + { + m_pTimer->SetContentAlignment( Label::a_center ); + } + + m_pTimeAdded = new vgui::Label( this, "HudObjectivesTimeAdded", " " ); + if ( m_pTimeAdded ) + { + m_pTimeAdded->SetContentAlignment( Label::a_center ); + } + + m_iBackgroundTexture = vgui::surface()->DrawGetTextureId( "vgui/white" ); + if ( m_iBackgroundTexture == -1 ) + { + m_iBackgroundTexture = vgui::surface()->CreateNewTextureID(); + } + vgui::surface()->DrawSetTextureFile( m_iBackgroundTexture, "vgui/white", true, true ); + + m_iLastCP = -1; + + m_iSecondsAdded = 0; + bInTimerWarningAnim = false; + + m_flDrawTimeAddedUntil = -1; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CHudObjectiveIcons::Init( void ) +{ + for( int i = 0 ; i < 8 ; i++ ) + { + m_iCPTextures[i] = vgui::surface()->CreateNewTextureID(); + m_iCPCappingTextures[i] = vgui::surface()->CreateNewTextureID(); + } + + ListenForGameEvent( "dod_timer_time_added" ); + ListenForGameEvent( "dod_timer_flash" ); +} + +void CHudObjectiveIcons::VidInit( void ) +{ + m_flTimeAddedExpandPercent = 0.0; + m_flTimeAddedAlpha = 0.0; + m_flDrawTimeAddedUntil = -1; + + CHudElement::VidInit(); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CHudObjectiveIcons::Reset( void ) +{ + m_iLastCP = -1; + m_flIconExpand = 0; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +bool CHudObjectiveIcons::IsVisible( void ) +{ + if ( IsTakingAFreezecamScreenshot() ) + return false; + + return BaseClass::IsVisible(); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CHudObjectiveIcons::FireGameEvent( IGameEvent *event ) +{ + const char *eventname = event->GetName(); + + if ( FStrEq( "dod_timer_time_added", eventname ) ) + { + // show time added under the timer, flash + m_iSecondsAdded = event->GetInt( "seconds_added" ); + + g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( "TimerFlash" ); + + g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( "ShowTimeAdded" ); + + if ( !m_pTimeAdded->IsVisible() ) + { + m_pTimeAdded->SetVisible( true ); + } + + wchar_t wText[12]; + + int iSecondsToDraw = abs(m_iSecondsAdded); + bool bNegative = ( m_iSecondsAdded < 0 ); + +#ifdef WIN32 + _snwprintf( wText, sizeof(wText)/sizeof(wchar_t), L"%s %d:%02d", bNegative ? L"-" : L"+", iSecondsToDraw / 60, iSecondsToDraw % 60 ); +#else + _snwprintf( wText, sizeof(wText)/sizeof(wchar_t), L"%S %d:%02d", bNegative ? L"-" : L"+", iSecondsToDraw / 60, iSecondsToDraw % 60 ); +#endif + + m_pTimeAdded->SetText( wText ); + + m_flDrawTimeAddedUntil = gpGlobals->curtime + m_flTimeAddedDuration; + + } + else if ( FStrEq( "dod_timer_flash", eventname ) ) + { + // generic flash, used for 5, 2, 1 minute warnings + g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( "TimerFlash" ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CHudObjectiveIcons::ApplySchemeSettings( IScheme *pScheme ) +{ + BaseClass::ApplySchemeSettings( pScheme ); + + m_hTextFont = pScheme->GetFont( "ChatFont" ); + m_hTimerFontSmall = pScheme->GetFont( "TimerFontSmall" ); + + m_clrBackground = pScheme->GetColor( "HudPanelBackground", GetFgColor() ); + m_clrBorder = pScheme->GetColor( "HudPanelBorder", GetBgColor() ); + + m_pC4Icon = gHUD.GetIcon( "icon_c4" ); + m_pExplodedIcon = gHUD.GetIcon( "icon_c4_exploded" ); + m_pC4PlantedBG = gHUD.GetIcon( "icon_c4_planted_bg" ); + m_pIconDefended = gHUD.GetIcon( "icon_defended" ); + + m_pTimer->SetFont( m_hTimerFont ); + m_pTimeAdded->SetFont( m_hTimerFontSmall ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CHudObjectiveIcons::DrawBackgroundBox( int xpos, int ypos, int nBoxWidth, int nBoxHeight, bool bCutCorner ) +{ + int nCornerCutSize = bCutCorner ? m_nCornerCutSize : 0; + vgui::Vertex_t verts[5]; + + verts[0].Init( Vector2D( xpos, ypos ) ); + verts[1].Init( Vector2D( xpos + nBoxWidth, ypos ) ); + verts[2].Init( Vector2D( xpos + nBoxWidth + 1, ypos + nBoxHeight - nCornerCutSize + 1 ) ); + verts[3].Init( Vector2D( xpos + nBoxWidth - nCornerCutSize + 1, ypos + nBoxHeight + 1 ) ); + verts[4].Init( Vector2D( xpos, ypos + nBoxHeight ) ); + + vgui::surface()->DrawSetTexture( m_iBackgroundTexture ); + vgui::surface()->DrawSetColor( Color( m_clrBackground ) ); + vgui::surface()->DrawTexturedPolygon( 5, verts ); + + vgui::Vertex_t borderverts[5]; + + borderverts[0].Init( Vector2D( xpos, ypos ) ); + borderverts[1].Init( Vector2D( xpos + nBoxWidth, ypos ) ); + borderverts[2].Init( Vector2D( xpos + nBoxWidth, ypos + nBoxHeight - nCornerCutSize ) ); + borderverts[3].Init( Vector2D( xpos + nBoxWidth - nCornerCutSize, ypos + nBoxHeight ) ); + borderverts[4].Init( Vector2D( xpos, ypos + nBoxHeight ) ); + + vgui::surface()->DrawSetColor( Color( m_clrBorder ) ); + vgui::surface()->DrawTexturedPolyLine( borderverts, 5 ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CHudObjectiveIcons::Paint() +{ + int ypos = m_iIconStartY; + int xpos = m_iIconStartX; + static Color clrIcon( 255, 255, 255, 255 ); + + if( !g_pObjectiveResource ) // MATTTODO: hasn't been transmited yet .. fix ? + { + return; + } + + // Hide the time added if it is time to do so + if ( m_flDrawTimeAddedUntil > 0 && m_flDrawTimeAddedUntil < gpGlobals->curtime ) + { + g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( "HideTimeAdded" ); + + m_flDrawTimeAddedUntil = -1; + } + + vgui::surface()->DrawSetTextFont( m_hTextFont ); + vgui::surface()->DrawSetColor( clrIcon ); + + if ( g_pSpectatorGUI && g_pSpectatorGUI->IsVisible() ) + { + ypos += g_pSpectatorGUI->GetTopBarHeight(); + } + + int num = g_pObjectiveResource->GetNumControlPoints(); + bool bShowTimer = ( g_DODRoundTimer != NULL ); + + if ( num <= 0 && !bShowTimer ) + { + if ( m_pTimer && m_pTimer->IsVisible() ) + { + m_pTimer->SetVisible( false ); + } + + if ( m_pTimeAdded && m_pTimeAdded->IsVisible() ) + { + m_pTimeAdded->SetVisible( false ); + } + + return; // nothing to draw yet + } + + int iLastVisible = 0; + + int k; + + // let's count how many visible capture points we have (for cutting the corner of the last visible one) + for( k = 0 ; k < num ; k++ ) + { + if( g_pObjectiveResource->IsCPVisible( k ) ) + { + iLastVisible = k; + } + } + + // do we have a round timer? + if( bShowTimer ) + { + if ( m_pTimer ) + { + if ( !m_pTimer->IsVisible() ) + { + m_pTimer->SetVisible( true ); + } + + m_pTimer->SetBounds( xpos, ypos, 2 * m_nIconSize, m_nIconSize ); + m_pTimer->SetBgColor( m_clrTimer ); + + m_pTimeAdded->SetBounds( xpos, ypos + m_nIconSize, 2 * m_nIconSize, m_nTimeAddedHeight + m_nBackgroundOverlap ); + m_pTimeAdded->SetBgColor( Color(0,0,0,0) ); + + int iRoundTime = (int)g_DODRoundTimer->GetTimeRemaining(); + + int minutes = iRoundTime / 60; + int seconds = iRoundTime % 60; + + if( minutes < 0 ) minutes = 0; + if( minutes > 99 ) minutes = 99; + if( seconds < 0 ) seconds = 0; + + // cut the corner if this is all we're drawing + + // figure out the height. will change if we're drawing the +1:00 below it + int boxHeight = 2*m_nBackgroundOverlap + m_nIconSize + (int)( (float)m_nTimeAddedHeight * m_flTimeAddedExpandPercent ); + + DrawBackgroundBox( xpos - m_nBackgroundOverlap, ypos - m_nBackgroundOverlap, m_pTimer->GetWide() + 2 * m_nBackgroundOverlap, boxHeight, ( num <= 0 ) ? true : false ); + + // set the time + char szTime[16]; + Q_snprintf( szTime, sizeof( szTime ), "%02d:%02d", minutes, seconds ); + m_pTimer->SetText( szTime ); + + m_pTimeAdded->SetAlpha( (int)m_flTimeAddedAlpha ); + + xpos += ( m_pTimer->GetWide() + m_nSeparatorWidth + m_nBackgroundOverlap * 2 ); + } + } + else + { + if ( m_pTimer && m_pTimer->IsVisible() ) + { + m_pTimer->SetVisible( false ); + } + } + + C_DODPlayer *pPlayer = C_DODPlayer::GetLocalDODPlayer(); + int iCurrentCapAreaIndex = pPlayer->GetCPIndex(); + + if ( pPlayer->IsAlive() == false ) + { + m_iLastCP = -1; + } + + int index; + + for( index = 0 ; index < num ; index++ ) + { + if( g_pObjectiveResource->IsCPVisible( index ) ) + { + int iOwnerIcon = g_pObjectiveResource->GetCPCurrentOwnerIcon( index ); + + float uv1 = 0.0f; + float uv2 = 1.0f; + + float flXPos = (float)xpos; + float flYPos = (float)ypos; + float flIconSize = (float)m_nIconSize; + + if ( index == iCurrentCapAreaIndex ) + { + // animate the current cp + flXPos -= m_flIconExpand; + flYPos -= m_flIconExpand; + flIconSize += m_flIconExpand*2; + + m_iLastCP = iCurrentCapAreaIndex; + } + else if ( m_iLastCP == index ) + { + // as a backup, animate out of the one we just left + flXPos -= m_flIconExpand; + flYPos -= m_flIconExpand; + flIconSize += m_flIconExpand*2; + } + + + int iBombsRequired = g_pObjectiveResource->GetBombsRequired( index ); + + if ( iBombsRequired > 0 ) + { + DrawBackgroundBox( flXPos - m_nBackgroundOverlap, flYPos - m_nBackgroundOverlap, flIconSize + 2 * m_nBackgroundOverlap, flIconSize + 2 * m_nBackgroundOverlap + m_nTimeAddedHeight, ( index != iLastVisible ) ? false : true ); + } + else + { + DrawBackgroundBox( flXPos - m_nBackgroundOverlap, flYPos - m_nBackgroundOverlap, flIconSize + 2 * m_nBackgroundOverlap, flIconSize + 2 * m_nBackgroundOverlap, ( index != iLastVisible ) ? false : true ); + } + + // Draw the background for the icon + + // allow for error + if ( g_pObjectiveResource->IsBombSetAtPoint( index ) ) + { + // if bomb timer is > 0, draw swipe + float flBombTime = g_pObjectiveResource->GetBombTimeForPoint( index ); // round up + + // draw the 'white' version underneath + int iBlankIcon = g_pObjectiveResource->GetCPTimerCapIcon( index ); + + if ( iBlankIcon == 0 ) + { + iBlankIcon = g_pObjectiveResource->GetIconForTeam( index, TEAM_UNASSIGNED ); + } + + const char *szMatName = GetMaterialNameFromIndex( iBlankIcon ); + + vgui::surface()->DrawSetTextureFile( m_iCPTextures[index], szMatName, true, false ); + + Vector2D uv11( uv1, uv1 ); + Vector2D uv21( uv2, uv1 ); + Vector2D uv22( uv2, uv2 ); + Vector2D uv12( uv1, uv2 ); + + vgui::Vertex_t vert[4]; + vert[0].Init( Vector2D( flXPos, flYPos ), uv11 ); + vert[1].Init( Vector2D( flXPos + flIconSize, flYPos ), uv21 ); + vert[2].Init( Vector2D( flXPos + flIconSize, flYPos + flIconSize ), uv22 ); + vert[3].Init( Vector2D( flXPos, flYPos + flIconSize ), uv12 ); + + vgui::surface()->DrawSetColor( Color(255,255,255,255) ); + vgui::surface()->DrawTexturedPolygon( 4, vert ); + + // draw the real version in a circular swipe + float flPercentRemaining = ( flBombTime / DOD_BOMB_TIMER_LENGTH ); + + float flHalfWide = (float)flIconSize / 2.0f; + float flHalfTall = (float)flIconSize / 2.0f; + + const float flCompleteCircle = ( 2.0f * M_PI ); + const float fl90degrees = flCompleteCircle * 0.25f; + const float fl45degrees = fl90degrees * 0.5f; + + float flEndAngle = flCompleteCircle * flPercentRemaining; // clockwise + + typedef struct + { + Vector2D vecTrailing; + Vector2D vecLeading; + } icon_quadrant_t; + + /* + Quadrants are numbered 0 - 7 counter-clockwise + _________________ + | 0 | 7 | + | | | + | 1 | 6 | + ----------------- + | 2 | 5 | + | | | + | 3 | 4 | + ----------------- + */ + + // Encode the leading and trailing edge of each quadrant + // in the range 0.0 -> 1.0 + + icon_quadrant_t quadrants[8]; + quadrants[0].vecTrailing.Init( 0.5, 0.0 ); + quadrants[0].vecLeading.Init( 0.0, 0.0 ); + + quadrants[1].vecTrailing.Init( 0.0, 0.0 ); + quadrants[1].vecLeading.Init( 0.0, 0.5 ); + + quadrants[2].vecTrailing.Init( 0.0, 0.5 ); + quadrants[2].vecLeading.Init( 0.0, 1.0 ); + + quadrants[3].vecTrailing.Init( 0.0, 1.0 ); + quadrants[3].vecLeading.Init( 0.5, 1.0 ); + + quadrants[4].vecTrailing.Init( 0.5, 1.0 ); + quadrants[4].vecLeading.Init( 1.0, 1.0 ); + + quadrants[5].vecTrailing.Init( 1.0, 1.0 ); + quadrants[5].vecLeading.Init( 1.0, 0.5 ); + + quadrants[6].vecTrailing.Init( 1.0, 0.5 ); + quadrants[6].vecLeading.Init( 1.0, 0.0 ); + + quadrants[7].vecTrailing.Init( 1.0, 0.0 ); + quadrants[7].vecLeading.Init( 0.5, 0.0 ); + + szMatName = GetMaterialNameFromIndex( iOwnerIcon ); + + vgui::surface()->DrawSetTextureFile( m_iCPTextures[index], szMatName, true, false ); + vgui::surface()->DrawSetColor( Color(255,255,255,255) ); + + Vector2D uvMid( 0.5, 0.5 ); + Vector2D vecMid( flXPos + flHalfWide, flYPos + flHalfTall ); + + int j; + for ( j=0;j<=7;j++ ) + { + float flMinAngle = j * fl45degrees; + + float flAngle = clamp( flEndAngle - flMinAngle, 0, fl45degrees ); + + if ( flAngle <= 0 ) + { + // past our quadrant, draw nothing + continue; + } + else + { + // draw our segment + vgui::Vertex_t vert[3]; + + // vert 0 is mid ( 0.5, 0.5 ) + vert[0].Init( vecMid, uvMid ); + + int xdir = 0, ydir = 0; + + switch( j ) + { + case 0: + case 7: + //right + xdir = 1; + ydir = 0; + break; + + case 1: + case 2: + //up + xdir = 0; + ydir = -1; + break; + + case 3: + case 4: + //left + xdir = -1; + ydir = 0; + break; + + case 5: + case 6: + //down + xdir = 0; + ydir = 1; + break; + } + + Vector2D vec1; + Vector2D uv1; + + // vert 1 is the variable vert based on leading edge + vec1.x = flXPos + quadrants[j].vecTrailing.x * flIconSize - xdir * tan(flAngle) * flHalfWide; + vec1.y = flYPos + quadrants[j].vecTrailing.y * flIconSize - ydir * tan(flAngle) * flHalfTall; + + uv1.x = quadrants[j].vecTrailing.x - xdir * abs( quadrants[j].vecLeading.x - quadrants[j].vecTrailing.x ) * tan(flAngle); + uv1.y = quadrants[j].vecTrailing.y - ydir * abs( quadrants[j].vecLeading.y - quadrants[j].vecTrailing.y ) * tan(flAngle); + + vert[1].Init( vec1, uv1 ); + + // vert 2 is our trailing edge + vert[2].Init( Vector2D( flXPos + quadrants[j].vecTrailing.x * flIconSize, + flYPos + quadrants[j].vecTrailing.y * flIconSize ), + quadrants[j].vecTrailing ); + + vgui::surface()->DrawTexturedPolygon( 3, vert ); + } + } + + if ( g_pObjectiveResource->IsBombBeingDefused( index ) ) + { + float flSize = 0.75; + int iconX = (int)( flXPos + flIconSize * ( ( 1.0 - flSize ) / 2 ) ); + int iconY = (int)( flYPos + flIconSize * ( ( 1.0 - flSize ) / 2 ) ); + int iconW = (int)( flIconSize * flSize ); + + Color c(255,255,255,255); + m_pIconDefended->DrawSelf( iconX, iconY, iconW, iconW, c ); + } + } + else + { + // Draw the owner's icon + if( iOwnerIcon != 0 ) + { + const char *szMatName = GetMaterialNameFromIndex( iOwnerIcon ); + + vgui::surface()->DrawSetTextureFile( m_iCPTextures[index], szMatName, true, false ); + + /* + // re-enable if we want to have animating cp icons + // todo: framerate + IVguiMatInfo *pMat = vgui::surface()->DrawGetTextureMatInfoFactory( m_iCPTextures[index] ); + + if ( !pMat ) + return; + + int iNumFrames = pMat->GetNumAnimationFrames(); + + IVguiMatInfoVar *m_pFrameVar; + + bool bFound = false; + m_pFrameVar = pMat->FindVarFactory( "$frame", &bFound ); + + static int frame = 0; + + if ( bFound ) + { + frame++; + m_pFrameVar->SetIntValue( frame % iNumFrames ); + } + */ + + Vector2D uv11( uv1, uv1 ); + Vector2D uv21( uv2, uv1 ); + Vector2D uv22( uv2, uv2 ); + Vector2D uv12( uv1, uv2 ); + + vgui::Vertex_t vert[4]; + vert[0].Init( Vector2D( flXPos, flYPos ), uv11 ); + vert[1].Init( Vector2D( flXPos + flIconSize, flYPos ), uv21 ); + vert[2].Init( Vector2D( flXPos + flIconSize, flYPos + flIconSize ), uv22 ); + vert[3].Init( Vector2D( flXPos, flYPos + flIconSize ), uv12 ); + + vgui::surface()->DrawSetColor( Color(255,255,255,255) ); + vgui::surface()->DrawTexturedPolygon( 4, vert ); + } + } + + // see if there are players in the area + int iNumAllies = g_pObjectiveResource->GetNumPlayersInArea( index, TEAM_ALLIES ); + int iNumAxis = g_pObjectiveResource->GetNumPlayersInArea( index, TEAM_AXIS ); + + int iCappingTeam = g_pObjectiveResource->GetCappingTeam( index ); + + // Draw bomb icons under cap points + if ( iBombsRequired > 0 ) + { + int iBombsRemaining = g_pObjectiveResource->GetBombsRemaining( index ); + + bool bBombPlanted = g_pObjectiveResource->IsBombSetAtPoint( index ); + + int yIcon = ypos + flIconSize + YRES(2); + + int iIconHalfWidth = XRES(5); + int iIconWidth = iIconHalfWidth * 2; + + Color c(255,255,255,255); + + switch( iBombsRequired ) + { + case 1: + { + int xMid = xpos + ( flIconSize * 0.50f ); + + switch( iBombsRemaining ) + { + case 0: + m_pExplodedIcon->DrawSelf( xMid - iIconHalfWidth, yIcon, iIconWidth, iIconWidth, c ); + break; + case 1: + if ( bBombPlanted ) + { + // draw the background behind 1 + int alpha = (float)( abs( sin(2*gpGlobals->curtime) ) * 205.0 + 50.0 ); + m_pC4PlantedBG->DrawSelf( xMid - iIconWidth, yIcon - iIconHalfWidth, iIconWidth*2, iIconWidth*2, Color( 255,255,255,alpha) ); + } + m_pC4Icon->DrawSelf( xMid - iIconHalfWidth, yIcon, iIconWidth, iIconWidth, c ); + break; + } + } + break; + case 2: + { + int xMid1 = xpos + ( flIconSize * 0.25f ); + int xMid2 = xpos + ( flIconSize * 0.75f ); + + switch( iBombsRemaining ) + { + case 0: + m_pExplodedIcon->DrawSelf( xMid1 - iIconHalfWidth, yIcon, iIconWidth, iIconWidth, c ); + m_pExplodedIcon->DrawSelf( xMid2 - iIconHalfWidth, yIcon, iIconWidth, iIconWidth, c ); + break; + case 1: + if ( bBombPlanted ) + { + // draw the background behind 1 + int alpha = (float)( abs( sin(2*gpGlobals->curtime) ) * 205.0 + 50.0 ); + m_pC4PlantedBG->DrawSelf( xMid1 - iIconWidth, yIcon - iIconHalfWidth, iIconWidth*2, iIconWidth*2, Color( 255,255,255,alpha) ); + } + m_pC4Icon->DrawSelf( xMid1 - iIconHalfWidth, yIcon, iIconWidth, iIconWidth, c ); + m_pExplodedIcon->DrawSelf( xMid2 - iIconHalfWidth, yIcon, iIconWidth, iIconWidth, c ); + break; + case 2: + if ( bBombPlanted ) + { + // draw the background behind 2 + int alpha = (float)( abs( sin(2*gpGlobals->curtime) ) * 205.0 + 50.0 ); + m_pC4PlantedBG->DrawSelf( xMid2 - iIconWidth, yIcon - iIconHalfWidth, iIconWidth*2, iIconWidth*2, Color( 255,255,255,alpha) ); + } + m_pC4Icon->DrawSelf( xMid1 - iIconHalfWidth, yIcon, iIconWidth, iIconWidth, c ); + m_pC4Icon->DrawSelf( xMid2 - iIconHalfWidth, yIcon, iIconWidth, iIconWidth, c ); + break; + } + } + break; + default: + { + // general solution for > 2 bombs + + if ( iBombsRemaining > 0 ) + { + // draw a bomb icon, then a 'x 3' for how many there are remaining + + if ( bBombPlanted ) + { + // draw the background behind 2 + int alpha = (float)( abs( sin( 2*gpGlobals->curtime) ) * 205.0 + 50.0 ); + m_pC4PlantedBG->DrawSelf( xpos - iIconHalfWidth, yIcon - iIconHalfWidth, iIconWidth*2, iIconWidth*2, Color( 255,255,255,alpha) ); + } + + m_pC4Icon->DrawSelf( xpos, yIcon, iIconWidth, iIconWidth, c ); + + // draw text saying how many bombs there are + { + wchar_t wText[6]; + _snwprintf( wText, sizeof(wText)/sizeof(wchar_t), L"x %d", iBombsRemaining ); + + vgui::surface()->DrawSetTextColor( g_PR->GetTeamColor( TEAM_SPECTATOR ) ); + + // set pos centered under icon + vgui::surface()->DrawSetTextPos( xpos + ( flIconSize * 0.50f ), yIcon + YRES(2) ); + + for ( wchar_t *wch = wText ; *wch != 0 ; wch++ ) + { + vgui::surface()->DrawUnicodeChar( *wch ); + } + } + + } + else + { + int xMid = xpos + ( flIconSize * 0.50f ); + m_pExplodedIcon->DrawSelf( xMid - iIconHalfWidth, yIcon, iIconWidth, iIconWidth, c ); + } + } + break; + } + } + + // see if one team is partially capping, + // should show a 1/2 under the cap icon + if ( iCappingTeam == TEAM_UNASSIGNED ) + { + if ( iNumAllies > 0 && iNumAxis == 0 ) + { + iCappingTeam = TEAM_ALLIES; + } + else if ( iNumAxis > 0 && iNumAllies == 0 ) + { + iCappingTeam = TEAM_AXIS; + } + + if ( iCappingTeam == TEAM_UNASSIGNED || iCappingTeam == g_pObjectiveResource->GetOwningTeam( index ) ) + { + // no team is capping, even partially + // or the person in the area already owns it + xpos += ( m_nIconSize + m_nSeparatorWidth + m_nBackgroundOverlap * 2 ); + continue; + } + } + + // Draw the number of cappers below the icon + int numPlayers = g_pObjectiveResource->GetNumPlayersInArea( index, iCappingTeam ); + int requiredPlayers = g_pObjectiveResource->GetRequiredCappers( index, iCappingTeam ); + + if ( requiredPlayers > 1 ) + { + numPlayers = MIN( numPlayers, requiredPlayers ); + + wchar_t wText[6]; + _snwprintf( wText, sizeof(wText)/sizeof(wchar_t), L"%d/%d", numPlayers, requiredPlayers ); + + vgui::surface()->DrawSetTextColor( g_PR->GetTeamColor( iCappingTeam ) ); + + // get string length + int len = g_pMatSystemSurface->DrawTextLen( m_hTextFont, "2/2" ); + + // set pos centered under icon + vgui::surface()->DrawSetTextPos( xpos + ( m_nIconSize / 2.0f ) - ( len / 2 ), ypos + flIconSize + m_nBackgroundOverlap + YRES( 2 ) ); // + 2 to account for the outlined box + + for ( wchar_t *wch = wText ; *wch != 0 ; wch++ ) + { + vgui::surface()->DrawUnicodeChar( *wch ); + } + } + + if ( g_pObjectiveResource->GetCappingTeam( index ) != TEAM_UNASSIGNED ) + { + int iCapperIcon = g_pObjectiveResource->GetCPCappingIcon( index ); + + // Draw the capper's icon + if( iOwnerIcon != iCapperIcon && iCapperIcon != 0 ) + { + // axis caps swipe from right to left...allied from left to right + bool bAxis = ( g_pObjectiveResource->GetCappingTeam(index) == TEAM_AXIS ) ? true : false; + + //swipe! + float flCapPercentage = g_pObjectiveResource->GetCPCapPercentage(index); + + // reversing the direction of the swipe effect + if ( bAxis ) + { + flCapPercentage = 1.0f - g_pObjectiveResource->GetCPCapPercentage(index); + } + + float width = ( flIconSize * flCapPercentage ); + const char *szCappingMatName = GetMaterialNameFromIndex( iCapperIcon ); + + vgui::surface()->DrawSetTextureFile( m_iCPCappingTextures[index], szCappingMatName, true, false ); + + vgui::Vertex_t vert[4]; + + Vector2D uv11( uv1, uv1 ); + Vector2D uv21( flCapPercentage, uv1 ); + Vector2D uv22( flCapPercentage, uv2 ); + Vector2D uv12( uv1, uv2 ); + + // reversing the direction of the swipe effect + if ( bAxis ) + { + uv11.x = flCapPercentage; + uv21.x = uv2; + uv22.x = uv2; + uv12.x = flCapPercentage; + } + + Vector2D upperLeft ( flXPos, flYPos ); + Vector2D upperRight( flXPos + width, flYPos ); + Vector2D lowerRight( flXPos + width, flYPos + flIconSize ); + Vector2D lowerLeft ( flXPos, flYPos + flIconSize ); + + /// reversing the direction of the swipe effect + if ( bAxis ) + { + upperLeft.x = flXPos + width; + upperRight.x = flXPos + flIconSize; + lowerRight.x = flXPos + flIconSize; + lowerLeft.x = flXPos + width; + } + + vert[0].Init( upperLeft, uv11 ); + vert[1].Init( upperRight, uv21 ); + vert[2].Init( lowerRight, uv22 ); + vert[3].Init( lowerLeft, uv12 ); + + vgui::surface()->DrawSetColor( Color(255,255,255,255) ); + vgui::surface()->DrawTexturedPolygon( 4, vert ); + } + } + + xpos += ( m_nIconSize + m_nSeparatorWidth + m_nBackgroundOverlap * 2 ); + } + } +} diff --git a/game/client/dod/dod_hud_playerstatus_ammo.cpp b/game/client/dod/dod_hud_playerstatus_ammo.cpp new file mode 100644 index 0000000..0e8efac --- /dev/null +++ b/game/client/dod/dod_hud_playerstatus_ammo.cpp @@ -0,0 +1,700 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#include "cbase.h" +#include "iclientmode.h" +#include "c_dod_player.h" + +#include <vgui/IScheme.h> +#include <vgui/ISurface.h> +#include <vgui_controls/AnimationController.h> + +#include "dod_hud_playerstatus_ammo.h" +#include "ihudlcd.h" + +float GetScale( int nIconWidth, int nIconHeight, int nWidth, int nHeight ) +{ + float flScale = 1.0; + + if ( nIconWidth == nWidth && nIconHeight <= nHeight ) // no scaling necessary + { + return flScale; + } + else if ( nIconHeight == nHeight && nIconWidth <= nWidth ) // no scaling necessary + { + return flScale; + } + else if ( nIconWidth < nWidth && nIconHeight < nHeight ) // scale the image up + { + float scaleW = 0.0, scaleH = 0.0; + + if ( nIconWidth < nWidth ) + { + scaleW = (float)nWidth / (float)nIconWidth; + } + + if ( nIconHeight < nHeight ) + { + scaleH = (float)nHeight / (float)nIconHeight; + } + + if ( scaleW != 0.0 && scaleH != 0.0 ) + { + if ( scaleW < scaleH ) + { + flScale = scaleW; + } + else + { + flScale = scaleH; + } + } + else if ( scaleW != 0.0 ) + { + flScale = scaleW; + } + else + { + flScale = scaleH; + } + } + else // scale the image down + { + float scaleW = 0.0, scaleH = 0.0; + + if ( nIconWidth > nWidth ) + { + scaleW = (float)nWidth / (float)nIconWidth; + } + + if ( nIconHeight > nHeight ) + { + scaleH = (float)nHeight / (float)nIconHeight; + } + + if ( scaleW != 0.0 && scaleH != 0.0 ) + { + if ( scaleW < scaleH ) + { + flScale = scaleW; + } + else + { + flScale = scaleH; + } + } + else if ( scaleW != 0.0 ) + { + flScale = scaleW; + } + else + { + flScale = scaleH; + } + } + + return flScale; +} + +//----------------------------------------------------------------------------- +// Purpose: Constructor +//----------------------------------------------------------------------------- +CDoDHudAmmo::CDoDHudAmmo( vgui::Panel *parent, const char *name ) : vgui::Panel( parent, name ) +{ + m_iAdditiveWhiteID = vgui::surface()->CreateNewTextureID(); + vgui::surface()->DrawSetTextureFile( m_iAdditiveWhiteID, "vgui/white_additive", true, false ); + + m_clrIcon = Color( 255, 255, 255, 255 ); + + hudlcd->SetGlobalStat( "(ammo_primary)", "0" ); + hudlcd->SetGlobalStat( "(ammo_secondary)", "0" ); + hudlcd->SetGlobalStat( "(weapon_print_name)", "" ); + hudlcd->SetGlobalStat( "(weapon_name)", "" ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CDoDHudAmmo::Init( void ) +{ + m_iAmmo = -1; + m_iAmmo2 = -1; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CDoDHudAmmo::ApplySchemeSettings( vgui::IScheme *pScheme ) +{ + BaseClass::ApplySchemeSettings( pScheme ); + + m_clrTextColor = pScheme->GetColor( "HudAmmoCount", GetFgColor() ); + m_clrTextXColor = pScheme->GetColor( "HudPanelBorder", GetFgColor() ); +} + +//----------------------------------------------------------------------------- +// Purpose: called every frame to get ammo info from the weapon +//----------------------------------------------------------------------------- +void CDoDHudAmmo::OnThink() +{ + C_BaseCombatWeapon *wpn = GetActiveWeapon(); + C_BasePlayer *player = C_BasePlayer::GetLocalPlayer(); + + hudlcd->SetGlobalStat( "(weapon_print_name)", wpn ? wpn->GetPrintName() : " " ); + hudlcd->SetGlobalStat( "(weapon_name)", wpn ? wpn->GetName() : " " ); + + if ( !wpn || !player || !wpn->UsesPrimaryAmmo() ) + { + hudlcd->SetGlobalStat( "(ammo_primary)", "n/a" ); + hudlcd->SetGlobalStat( "(ammo_secondary)", "n/a" ); + + SetPaintEnabled( false ); + SetPaintBackgroundEnabled( false ); + return; + } + else + { + SetPaintEnabled( true ); + SetPaintBackgroundEnabled( true ); + } + + // get the ammo in our clip + int ammo1 = wpn->Clip1(); + int ammo2; + if ( ammo1 < 0 ) + { + // we don't use clip ammo, just use the total ammo count + ammo1 = player->GetAmmoCount( wpn->GetPrimaryAmmoType() ); + ammo2 = 0; + } + else + { + // we use clip ammo, so the second ammo is the total ammo + ammo2 = player->GetAmmoCount( wpn->GetPrimaryAmmoType() ); + } + + hudlcd->SetGlobalStat( "(ammo_primary)", VarArgs( "%d", ammo1 ) ); + hudlcd->SetGlobalStat( "(ammo_secondary)", VarArgs( "%d", ammo2 ) ); + + if ( wpn == m_hCurrentActiveWeapon ) + { + // same weapon, just update counts + SetAmmo( ammo1, true ); + SetAmmo2( ammo2, true ); + } + else + { + // diferent weapon, change without triggering + SetAmmo( ammo1, false ); + SetAmmo2( ammo2, false ); + + // update whether or not we show the total ammo display + m_bUsesClips = wpn->UsesClipsForAmmo1(); + m_hCurrentActiveWeapon = wpn; + } +} + +//----------------------------------------------------------------------------- +// Purpose: Updates ammo display +//----------------------------------------------------------------------------- +void CDoDHudAmmo::SetAmmo( int ammo, bool playAnimation ) +{ + if ( ammo != m_iAmmo ) + { + m_iAmmo = ammo; + } +} + +//----------------------------------------------------------------------------- +// Purpose: Updates 2nd ammo display +//----------------------------------------------------------------------------- +void CDoDHudAmmo::SetAmmo2( int ammo2, bool playAnimation ) +{ + if ( ammo2 != m_iAmmo2 ) + { + m_iAmmo2 = ammo2; + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CDoDHudAmmo::DrawAmmoCount( int count ) +{ + char buf[16]; + Q_snprintf( buf, sizeof(buf), "x" ); + DrawText( buf, clip_count_text_xpos, clip_count_text_ypos, m_clrTextXColor ); + + Q_snprintf( buf, sizeof(buf), " %d", count ); + DrawText( buf, clip_count_text_xpos, clip_count_text_ypos, m_clrTextColor ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CDoDHudAmmo::PaintGrenadeAmmo( CWeaponDODBase *pWpn ) +{ + const CHudTexture *pAmmoIcon = pWpn->GetSpriteAmmo(); + + Assert( pAmmoIcon ); + + int xpos = small_icon_xpos, ypos = small_icon_ypos; + int w = small_icon_width, t = small_icon_height; + + int nIconWidth = 0, nIconHeight = 0; + float scale = 1.0f; + + if ( pAmmoIcon ) + { + nIconWidth = pAmmoIcon->Width(); + nIconHeight = pAmmoIcon->Height(); + + scale = GetScale( nIconWidth, nIconHeight, w, t ); + + nIconWidth *= scale; + nIconHeight *= scale; + + if ( nIconWidth < small_icon_width - XRES(2) ) // 2 is our buffer for when we need to re-calculate the xpos + { + xpos = small_icon_xpos + small_icon_width / 2.0 - nIconWidth / 2.0; + } + + if ( nIconHeight < small_icon_height - YRES(2) ) // 2 is our buffer for when we need to re-calculate the ypos + { + ypos = small_icon_ypos + small_icon_height / 2.0 - nIconHeight / 2.0; + } + + if ( m_iAmmo > 0 ) + { + pAmmoIcon->DrawSelf( xpos, ypos, nIconWidth, nIconHeight, m_clrIcon ); + DrawAmmoCount( m_iAmmo ); + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CDoDHudAmmo::PaintRifleGrenadeAmmo( CWeaponDODBase *pWpn ) +{ + const CHudTexture *pAmmoIcon = pWpn->GetSpriteAmmo(); + + Assert( pAmmoIcon ); + + int xpos = small_icon_xpos, ypos = small_icon_ypos; + int w = small_icon_width, t = small_icon_height; + + int nIconWidth = 0, nIconHeight = 0; + float scale = 1.0f; + + if ( pAmmoIcon ) + { + nIconWidth = pAmmoIcon->Width(); + nIconHeight = pAmmoIcon->Height(); + + scale = GetScale( nIconWidth, nIconHeight, w, t ); + + nIconWidth *= scale; + nIconHeight *= scale; + + if ( nIconWidth < small_icon_width - XRES(2) ) // 2 is our buffer for when we need to re-calculate the xpos + { + xpos = small_icon_xpos + small_icon_width / 2.0 - nIconWidth / 2.0; + } + + if ( nIconHeight < small_icon_height - YRES(2) ) // 2 is our buffer for when we need to re-calculate the ypos + { + ypos = small_icon_ypos + small_icon_height / 2.0 - nIconHeight / 2.0; + } + + int ammo = m_iAmmo + m_iAmmo2; + + if ( ammo > 0 ) + { + pAmmoIcon->DrawSelf( xpos, ypos, nIconWidth, nIconHeight, m_clrIcon ); + DrawAmmoCount( ammo ); + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CDoDHudAmmo::PaintBazookaAmmo( CWeaponDODBase *pWpn ) +{ + int panelX, panelY, panelW, panelT; + GetBounds( panelX, panelY, panelW, panelT ); + + const CHudTexture *pTubeIcon = pWpn->GetSpriteAmmo2(); + const CHudTexture *pRocketIcon = pWpn->GetSpriteAmmo(); + const CHudTexture *pExtraIcon = pWpn->GetSpriteAutoaim(); + + Assert( pTubeIcon ); + Assert( pRocketIcon ); + Assert( pExtraIcon ); + + int xpos = 0, ypos = 0; + int nIconWidth = 0, nIconHeight = 0; + float scale = 1.0f; + + if ( pTubeIcon && pRocketIcon ) + { + nIconWidth = pTubeIcon->Width(); + nIconHeight = pTubeIcon->Height(); + + xpos = large_icon_xpos; + ypos = large_icon_ypos; + + // mad hax + int width = large_icon_width + XRES(10); + + scale = GetScale( nIconWidth, nIconHeight, width, large_icon_height ); + + nIconWidth *= scale; + nIconHeight *= scale; + + if ( nIconWidth < large_icon_width - XRES(2) ) // 2 is our buffer for when we need to re-calculate the xpos + { + xpos = small_icon_xpos + small_icon_width / 2.0 - nIconWidth / 2.0; + } + + if ( nIconHeight < large_icon_height - YRES(2) ) // 2 is our buffer for when we need to re-calculate the ypos + { + ypos = small_icon_ypos + small_icon_height / 2.0 - nIconHeight / 2.0; + } + + pTubeIcon->DrawSelf( xpos, ypos, nIconWidth, nIconHeight, m_clrIcon ); + + // If our clip is full, draw the rocket + if( pRocketIcon ) + { + if( m_iAmmo > 0 ) + { + pRocketIcon->DrawSelf( xpos, ypos, nIconWidth, nIconHeight, m_clrIcon ); + } + } + } + + // Draw the extra rockets + if( m_iAmmo2 > 0 && pExtraIcon ) + { + // Align the extra clip on the same baseline as the large clip + xpos = extra_clip_xpos; + ypos = extra_clip_ypos; + + nIconWidth = pExtraIcon->Width(); + nIconHeight = pExtraIcon->Height(); + + if ( nIconWidth > extra_clip_width || nIconHeight > extra_clip_height ) + { + scale = GetScale( nIconWidth, nIconHeight, extra_clip_width, extra_clip_height ); + nIconWidth *= scale; + nIconHeight *= scale; + } + + if ( nIconWidth < extra_clip_width - XRES(2) ) // 2 is our buffer for when we need to re-calculate the ypos + { + xpos = extra_clip_xpos + extra_clip_width / 2.0 - nIconWidth / 2.0; + } + + if ( nIconHeight < extra_clip_height - YRES(2) ) // 2 is our buffer for when we need to re-calculate the ypos + { + ypos = extra_clip_ypos + extra_clip_height / 2.0 - nIconHeight / 2.0; + } + + pExtraIcon->DrawSelf( xpos, ypos, pExtraIcon->Width() * scale, pExtraIcon->Height() * scale, m_clrIcon ); + DrawAmmoCount( m_iAmmo2 ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CDoDHudAmmo::PaintMGAmmo( CWeaponDODBase *pWpn ) +{ + int panelX, panelY, panelW, panelT; + GetBounds( panelX, panelY, panelW, panelT ); + + const CHudTexture *pFullClip = pWpn->GetSpriteAmmo(); + const CHudTexture *pExtraClip = pWpn->GetSpriteAmmo2(); + + Assert( pFullClip ); + Assert( pExtraClip ); + + int xpos = 0, ypos = 0; + int nIconWidth = 0, nIconHeight = 0; + float scale = 1.0f; + + if ( pFullClip ) + { + nIconWidth = pFullClip->Width(); + nIconHeight = pFullClip->Height(); + + xpos = large_icon_xpos; + ypos = large_icon_ypos; + + scale = GetScale( nIconWidth, nIconHeight, large_icon_width, large_icon_height ); + + nIconWidth *= scale; + nIconHeight *= scale; + + if ( nIconWidth < large_icon_width - XRES(2) ) // 2 is our buffer for when we need to re-calculate the xpos + { + xpos = small_icon_xpos + small_icon_width / 2.0 - nIconWidth / 2.0; + } + + if ( nIconHeight < large_icon_height - YRES(2) ) // 2 is our buffer for when we need to re-calculate the ypos + { + ypos = small_icon_ypos + small_icon_height / 2.0 - nIconHeight / 2.0; + } + + pFullClip->DrawSelf( xpos, ypos, nIconWidth, nIconHeight, m_clrIcon ); + + char buf[16]; + Q_snprintf( buf, sizeof(buf), "%d", m_iAmmo ); + DrawText( buf, xpos + nIconWidth - ( (float)nIconWidth / 3.0 ), ypos + nIconHeight - ( (float)nIconHeight / 3.0 ), m_clrTextColor ); + } + + //how many full or partially full clips do we have? + int clips = m_iAmmo2 / pWpn->GetMaxClip1(); + + //account for the partial clip, if it exists + if( clips * pWpn->GetMaxClip1() < m_iAmmo2 ) + { + clips++; + } + + if( clips > 0 && pExtraClip ) + { + //align the extra clip on the same baseline as the large clip + xpos = extra_clip_xpos; + ypos = extra_clip_ypos; + + nIconWidth = pExtraClip->Width(); + nIconHeight = pExtraClip->Height(); + + if ( nIconWidth > extra_clip_width || nIconHeight > extra_clip_height ) + { + scale = GetScale( nIconWidth, nIconHeight, extra_clip_width, extra_clip_height ); + nIconWidth *= scale; + nIconHeight *= scale; + } + + if ( nIconWidth < extra_clip_width - XRES(2) ) // 2 is our buffer for when we need to re-calculate the ypos + { + xpos = extra_clip_xpos + extra_clip_width / 2.0 - nIconWidth / 2.0; + } + + if ( nIconHeight < extra_clip_height - YRES(2) ) // 2 is our buffer for when we need to re-calculate the ypos + { + ypos = extra_clip_ypos + extra_clip_height / 2.0 - nIconHeight / 2.0; + } + + pExtraClip->DrawSelf( xpos, ypos, pExtraClip->Width() * scale, pExtraClip->Height() * scale, m_clrIcon ); + DrawAmmoCount( clips ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CDoDHudAmmo::PaintGunAmmo( CWeaponDODBase *pWpn ) +{ + int panelX, panelY, panelW, panelT; + GetBounds( panelX, panelY, panelW, panelT ); + + //regular gun + const CHudTexture *pEmptyClip = pWpn->GetSpriteAmmo(); + const CHudTexture *pFullClip = pWpn->GetSpriteAmmo2(); + const CHudTexture *pExtraClip = pWpn->GetSpriteAutoaim(); + + Assert( pEmptyClip ); + Assert( pFullClip ); + Assert( pExtraClip ); + + int xpos = 0, ypos = 0; + int nIconWidth = 0, nIconHeight = 0; + float scale = 1.0f; + + if ( pFullClip && pEmptyClip ) + { + nIconWidth = pFullClip->Width(); + nIconHeight = pFullClip->Height(); + + xpos = large_icon_xpos; + ypos = large_icon_ypos; + + scale = GetScale( nIconWidth, nIconHeight, large_icon_width, large_icon_height ); + + nIconWidth *= scale; + nIconHeight *= scale; + + if ( nIconWidth < large_icon_width - XRES(2) ) // 2 is our buffer for when we need to re-calculate the xpos + { + xpos = small_icon_xpos + small_icon_width / 2.0 - nIconWidth / 2.0; + } + + if ( nIconHeight < large_icon_height - YRES(2) ) // 2 is our buffer for when we need to re-calculate the ypos + { + ypos = small_icon_ypos + small_icon_height / 2.0 - nIconHeight / 2.0; + } + + pFullClip->DrawSelf( xpos, ypos, nIconWidth, nIconHeight, m_clrIcon ); + + // base percent is how much of the bullet clip to always draw. + // total cropped height of the bullet sprite will be + // base percent + bullet height * bullets + float flBasePercent = (float)pWpn->GetDODWpnData().m_iHudClipBaseHeight / (float)pWpn->GetDODWpnData().m_iHudClipHeight; + float flBulletHeightPercent = (float)pWpn->GetDODWpnData().m_iHudClipBulletHeight / (float)pWpn->GetDODWpnData().m_iHudClipHeight; + + float flHeight = (float)pEmptyClip->Height(); + + //Now we draw the bullets inside based on how full our clip is + float flDrawHeight = flHeight * ( 1.0 - ( flBasePercent + flBulletHeightPercent * m_iAmmo ) ); + + int nOffset = (int)flDrawHeight; + int yPosOffset = nOffset * scale; + + pEmptyClip->DrawSelfCropped( xpos, ypos + yPosOffset, 0, nOffset, pEmptyClip->Width(), pEmptyClip->Height() - nOffset, nIconWidth, nIconHeight - yPosOffset, m_clrIcon ); + } + + // how many full or partially full clips do we have? + int clips = m_iAmmo2 / pWpn->GetMaxClip1(); + + // account for the partial clip, if it exists + if( clips * pWpn->GetMaxClip1() < m_iAmmo2 ) + { + clips++; + } + + if( clips > 0 && pExtraClip ) + { + //align the extra clip on the same baseline as the large clip + xpos = extra_clip_xpos; + ypos = extra_clip_ypos; + + nIconWidth = pExtraClip->Width(); + nIconHeight = pExtraClip->Height(); + + if ( nIconWidth > extra_clip_width || nIconHeight > extra_clip_height ) + { + scale = GetScale( nIconWidth, nIconHeight, extra_clip_width, extra_clip_height ); + nIconWidth *= scale; + nIconHeight *= scale; + } + + if ( nIconWidth < extra_clip_width - XRES(2) ) // 2 is our buffer for when we need to re-calculate the ypos + { + xpos = extra_clip_xpos + extra_clip_width / 2.0 - nIconWidth / 2.0; + } + + if ( nIconHeight < extra_clip_height - YRES(2) ) // 2 is our buffer for when we need to re-calculate the ypos + { + ypos = extra_clip_ypos + extra_clip_height / 2.0 - nIconHeight / 2.0; + } + + pExtraClip->DrawSelf( xpos, ypos, pExtraClip->Width() * scale, pExtraClip->Height() * scale, m_clrIcon ); + DrawAmmoCount( clips ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CDoDHudAmmo::Paint( void ) +{ + C_DODPlayer *pPlayer = C_DODPlayer::GetLocalDODPlayer(); + + if( !pPlayer ) + return; + + CWeaponDODBase *pWpn = pPlayer->GetActiveDODWeapon(); + + if( !pWpn ) + return; + + switch( pWpn->GetDODWpnData().m_WeaponType ) + { + case WPN_TYPE_GRENADE: + PaintGrenadeAmmo( pWpn ); + break; + + case WPN_TYPE_RIFLEGRENADE: + PaintRifleGrenadeAmmo( pWpn ); + break; + + case WPN_TYPE_BAZOOKA: + PaintBazookaAmmo( pWpn ); + break; + + case WPN_TYPE_MG: + PaintMGAmmo( pWpn ); + break; + + case WPN_TYPE_CAMERA: + break; + + default: + PaintGunAmmo( pWpn ); + break; + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CDoDHudAmmo::DrawText( char *text, int x, int y, Color clrText ) +{ + vgui::surface()->DrawSetTextColor( clrText ); + vgui::surface()->DrawSetTextFont( m_hNumberFont ); + vgui::surface()->DrawSetTextPos( x, y ); + + for (char *pch = text; *pch != 0; pch++) + { + vgui::surface()->DrawUnicodeChar(*pch); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CDoDHudAmmo::DrawNumbers( int num, int x, int y ) +{ + if ( !m_pMGNumbers[0] ) + { + int i; + for ( i = 0 ; i < 10 ; i++ ) + { + char buf[8]; + Q_snprintf( buf, sizeof(buf), "mg_%d", i ); + m_pMGNumbers[i] = gHUD.GetIcon( buf ); + } + } + + Assert( num < 1000 ); + + int xpos = x; + int ypos = y; + int num_working = num; + + int iconWidth = m_pMGNumbers[0]->Width(); + + int hundreds = num_working / 100; + num_working -= hundreds * 100; + + m_pMGNumbers[hundreds]->DrawSelf( xpos, ypos, m_clrIcon ); + xpos += iconWidth; + + int tens = num_working / 10; + num_working -= tens * 10; + + m_pMGNumbers[tens]->DrawSelf( xpos, ypos, m_clrIcon ); + xpos += iconWidth; + + m_pMGNumbers[num_working]->DrawSelf( xpos, ypos, m_clrIcon ); + xpos += iconWidth; +} + diff --git a/game/client/dod/dod_hud_playerstatus_ammo.h b/game/client/dod/dod_hud_playerstatus_ammo.h new file mode 100644 index 0000000..2a3f437 --- /dev/null +++ b/game/client/dod/dod_hud_playerstatus_ammo.h @@ -0,0 +1,79 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef DOD_HUD_PLAYERSTATUS_AMMO_H +#define DOD_HUD_PLAYERSTATUS_AMMO_H +#ifdef _WIN32 +#pragma once +#endif + +//----------------------------------------------------------------------------- +// Purpose: Displays current ammunition level +//----------------------------------------------------------------------------- +class CDoDHudAmmo : public vgui::Panel +{ + DECLARE_CLASS_SIMPLE( CDoDHudAmmo, vgui::Panel ); + +public: + CDoDHudAmmo( vgui::Panel *parent, const char *name ); + void Init( void ); + + void SetAmmo( int ammo, bool playAnimation ); + void SetAmmo2( int ammo2, bool playAnimation ); + + virtual void OnThink(); + virtual void Paint( void ); + virtual void ApplySchemeSettings( vgui::IScheme *pScheme ); + +private: + void DrawAmmoCount( int count ); + void DrawText( char *text, int x, int y, Color clrText ); + void DrawNumbers( int num, int x, int y ); + + void PaintGrenadeAmmo( CWeaponDODBase *pWpn ); + void PaintBazookaAmmo( CWeaponDODBase *pWpn ); + void PaintMGAmmo( CWeaponDODBase *pWpn ); + void PaintGunAmmo( CWeaponDODBase *pWpn ); + void PaintRifleGrenadeAmmo( CWeaponDODBase *pWpn ); + + CHandle< C_BaseCombatWeapon > m_hCurrentActiveWeapon; + int m_iAmmo; + int m_iAmmo2; + + bool m_bUsesClips; + + int m_iAdditiveWhiteID; + + Color m_clrTextColor; + Color m_clrTextXColor; + + CPanelAnimationVarAliasType( float, clip_count_text_xpos, "clip_count_text_xpos", "54", "proportional_float" ); + CPanelAnimationVarAliasType( float, clip_count_text_ypos, "clip_count_text_ypos", "16", "proportional_float" ); + + CPanelAnimationVarAliasType( float, large_icon_xpos, "large_icon_xpos", "0", "proportional_float" ); + CPanelAnimationVarAliasType( float, large_icon_ypos, "large_icon_ypos", "0", "proportional_float" ); + CPanelAnimationVarAliasType( float, large_icon_width, "large_icon_width", "32", "proportional_float" ); + CPanelAnimationVarAliasType( float, large_icon_height, "large_icon_height", "51", "proportional_float" ); + + CPanelAnimationVarAliasType( float, small_icon_xpos, "small_icon_xpos", "0", "proportional_float" ); + CPanelAnimationVarAliasType( float, small_icon_ypos, "small_icon_ypos", "0", "proportional_float" ); + CPanelAnimationVarAliasType( float, small_icon_width, "small_icon_width", "2", "proportional_float" ); + CPanelAnimationVarAliasType( float, small_icon_height, "small_icon_height", "2", "proportional_float" ); + + CPanelAnimationVarAliasType( float, extra_clip_xpos, "extra_clip_xpos", "35", "proportional_float" ); + CPanelAnimationVarAliasType( float, extra_clip_ypos, "extra_clip_ypos", "20", "proportional_float" ); + CPanelAnimationVarAliasType( float, extra_clip_width, "extra_clip_width", "16", "proportional_float" ); + CPanelAnimationVarAliasType( float, extra_clip_height, "extra_clip_height", "16", "proportional_float" ); + + CPanelAnimationVar( vgui::HFont, m_hNumberFont, "NumberFont", "HudSelectionNumbers" ); + + Color m_clrIcon; + + CHudTexture *m_pMGNumbers[10]; +}; + +#endif // DOD_HUD_PLAYERSTATUS_AMMO_H diff --git a/game/client/dod/dod_hud_playerstatus_fireselect.cpp b/game/client/dod/dod_hud_playerstatus_fireselect.cpp new file mode 100644 index 0000000..7540b99 --- /dev/null +++ b/game/client/dod/dod_hud_playerstatus_fireselect.cpp @@ -0,0 +1,123 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#include "cbase.h" +#include <KeyValues.h> +#include <vgui/IScheme.h> +#include <vgui/ISurface.h> +#include <vgui/ISystem.h> +#include <vgui_controls/AnimationController.h> +#include <vgui_controls/EditablePanel.h> +#include <vgui_controls/ImagePanel.h> + +#include <vgui/ISurface.h> + +#include "c_dod_team.h" +#include "c_dod_playerresource.h" +#include "c_dod_player.h" + +#include "weapon_dodfireselect.h" +#include "dodcornercutpanel.h" +#include "dod_hud_playerstatus_fireselect.h" + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +CDoDHudFireSelect::CDoDHudFireSelect( vgui::Panel *parent, const char *name ) : vgui::EditablePanel( parent, name ) +{ + m_pBackground = new CDoDCutEditablePanel( this, "FireSelectBackground" ); + + m_pIconMP44 = new CIconPanel( this, "Icon_MP44" ); + m_pIconBAR = new CIconPanel( this, "Icon_BAR" ); + + m_pBulletLeft = new CIconPanel( this, "Bullet_Left" ); + m_pBulletCenter = new CIconPanel( this, "Bullet_Center" ); + m_pBulletRight = new CIconPanel( this, "Bullet_Right" ); + + m_pBulletRight->SetVisible( true ); +} + +void CDoDHudFireSelect::ApplySchemeSettings( vgui::IScheme *pScheme ) +{ + LoadControlSettings( "resource/UI/HudPlayerStatusFireSelect.res" ); + + BaseClass::ApplySchemeSettings( pScheme ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CDoDHudFireSelect::SetVisible( bool state ) +{ + if ( m_pBackground && m_pBackground->IsVisible() != state ) + { + m_pBackground->SetVisible( state ); + } + + m_pBulletLeft->SetVisible( state ); + m_pBulletCenter->SetVisible( state ); + m_pBulletRight->SetVisible( state ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CDoDHudFireSelect::OnThink() +{ + BaseClass::OnThink(); + + C_DODPlayer *pPlayer = C_DODPlayer::GetLocalDODPlayer(); + if ( pPlayer ) + { + CWeaponDODBase *pWeapon = pPlayer->GetActiveDODWeapon(); + if ( pWeapon ) + { + bool bSemiAutoWpn = false; + + if ( pWeapon->IsA( WEAPON_MP44 ) ) + { + m_pIconBAR->SetVisible( false ); + m_pIconMP44->SetVisible( true ); + + bSemiAutoWpn = true; + } + else if ( pWeapon->IsA( WEAPON_BAR ) ) + { + m_pIconBAR->SetVisible( true ); + m_pIconMP44->SetVisible( false ); + + bSemiAutoWpn = true; + } + else + { + m_pIconBAR->SetVisible( false ); + m_pIconMP44->SetVisible( false ); + } + + if ( bSemiAutoWpn ) + { + SetVisible( true ); + + CDODFireSelectWeapon *pFireSelect = dynamic_cast<CDODFireSelectWeapon *>(pWeapon); + + if ( pFireSelect && pFireSelect->IsSemiAuto() ) + { + m_pBulletLeft->SetVisible( false ); + m_pBulletCenter->SetVisible( false ); + } + else + { + m_pBulletLeft->SetVisible( true ); + m_pBulletCenter->SetVisible( true ); + } + } + else + { + SetVisible( false ); + } + } + } +} diff --git a/game/client/dod/dod_hud_playerstatus_fireselect.h b/game/client/dod/dod_hud_playerstatus_fireselect.h new file mode 100644 index 0000000..2718551 --- /dev/null +++ b/game/client/dod/dod_hud_playerstatus_fireselect.h @@ -0,0 +1,45 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef DOD_HUD_PLAYERSTATUS_FIRESELECT_H +#define DOD_HUD_PLAYERSTATUS_FIRESELECT_H +#ifdef _WIN32 +#pragma once +#endif + +#include <vgui_controls/EditablePanel.h> +#include "IconPanel.h" + +using namespace vgui; + +//----------------------------------------------------------------------------- +// Purpose: FireSelect panel +//----------------------------------------------------------------------------- +class CDoDHudFireSelect : public vgui::EditablePanel +{ + DECLARE_CLASS_SIMPLE( CDoDHudFireSelect, vgui::EditablePanel ); + +public: + CDoDHudFireSelect( vgui::Panel *parent, const char *name ); + + virtual void ApplySchemeSettings( vgui::IScheme *pScheme ); + virtual void OnThink(); + virtual void SetVisible( bool state ); + +private: + + CDoDCutEditablePanel *m_pBackground; + + CIconPanel *m_pIconMP44; + CIconPanel *m_pIconBAR; + + CIconPanel *m_pBulletLeft; + CIconPanel *m_pBulletCenter; + CIconPanel *m_pBulletRight; +}; + +#endif // DOD_HUD_PLAYERSTATUS_FIRESELECT_H
\ No newline at end of file diff --git a/game/client/dod/dod_hud_playerstatus_health.cpp b/game/client/dod/dod_hud_playerstatus_health.cpp new file mode 100644 index 0000000..7e487f8 --- /dev/null +++ b/game/client/dod/dod_hud_playerstatus_health.cpp @@ -0,0 +1,255 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// +// + +#include "cbase.h" +#include "view.h" + +#include "iclientmode.h" + +#include <KeyValues.h> +#include <vgui/ISurface.h> +#include <vgui/ISystem.h> +#include <vgui_controls/AnimationController.h> +#include <vgui_controls/EditablePanel.h> +#include <vgui_controls/ImagePanel.h> + +#include "convar.h" +#include "c_dod_team.h" +#include "c_dod_playerresource.h" +#include "c_dod_player.h" + +#include "dod_hud_playerstatus_health.h" + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +CDoDHudHealthBar::CDoDHudHealthBar( vgui::Panel *parent, const char *name ) : vgui::ImagePanel( parent, name ) +{ + m_flPercentage = 1.0f; + + m_iMaterialIndex = vgui::surface()->DrawGetTextureId( "vgui/white" ); + if ( m_iMaterialIndex == -1 ) // we didn't find it, so create a new one + { + m_iMaterialIndex = vgui::surface()->CreateNewTextureID(); + } + + vgui::surface()->DrawSetTextureFile( m_iMaterialIndex, "vgui/white", true, false ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CDoDHudHealthBar::OnThink() +{ + BaseClass::OnThink(); + + C_DODPlayer *pPlayer = GetHealthDelegatePlayer(); + if ( pPlayer ) + { + // m_nHealth >= 0 + int nHealth = MAX( pPlayer->GetHealth(), 0 ); + m_flPercentage = nHealth / 100.0f; + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CDoDHudHealthBar::ApplySchemeSettings( vgui::IScheme *pScheme ) +{ + BaseClass::ApplySchemeSettings( pScheme ); + + m_clrHealthHigh = pScheme->GetColor( "HudHealthGreen", GetFgColor() ); + m_clrHealthMed = pScheme->GetColor( "HudHealthYellow", GetFgColor() ); + m_clrHealthLow = pScheme->GetColor( "HudHealthRed", GetFgColor() ); + m_clrBackground = pScheme->GetColor( "HudHealthBG", GetBgColor() ); + m_clrBorder = pScheme->GetColor( "HudHealthBorder", GetBgColor() ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CDoDHudHealthBar::Paint( void ) +{ + BaseClass::Paint(); + + int x, y, w, h; + GetBounds( x, y, w, h ); + + int xpos = 0, ypos = 0; + float flDamageY = h * ( 1.0f - m_flPercentage ); + + Color *pclrHealth; + + if ( m_flPercentage > m_flFirstWarningLevel ) + { + pclrHealth = &m_clrHealthHigh; + } + else if ( m_flPercentage > m_flSecondWarningLevel ) + { + pclrHealth = &m_clrHealthMed; + } + else + { + pclrHealth = &m_clrHealthLow; + } + + // blend in the red "damage" part + float uv1 = 0.0f; + float uv2 = 1.0f; + + vgui::surface()->DrawSetTexture( m_iMaterialIndex ); + + Vector2D uv11( uv1, uv1 ); + Vector2D uv21( uv2, uv1 ); + Vector2D uv22( uv2, uv2 ); + Vector2D uv12( uv1, uv2 ); + + vgui::Vertex_t vert[4]; + + // background + vert[0].Init( Vector2D( xpos, ypos ), uv11 ); + vert[1].Init( Vector2D( xpos + w, ypos ), uv21 ); + vert[2].Init( Vector2D( xpos + w, ypos + h ), uv22 ); + vert[3].Init( Vector2D( xpos, ypos + h ), uv12 ); + + if ( m_flPercentage <= 0.01 ) + { + vgui::surface()->DrawSetColor( m_clrHealthLow ); + } + else + { + vgui::surface()->DrawSetColor( m_clrBackground ); + } + vgui::surface()->DrawTexturedPolygon( 4, vert ); + + // damage part + vert[0].Init( Vector2D( xpos, flDamageY ), uv11 ); + vert[1].Init( Vector2D( xpos + w, flDamageY ), uv21 ); + vert[2].Init( Vector2D( xpos + w, ypos + h ), uv22 ); + vert[3].Init( Vector2D( xpos, ypos + h ), uv12 ); + + vgui::surface()->DrawSetColor( *pclrHealth ); + vgui::surface()->DrawTexturedPolygon( 4, vert ); + + // outline + vert[0].Init( Vector2D( xpos, ypos ), uv11 ); + vert[1].Init( Vector2D( xpos + w - 1, ypos ), uv21 ); + vert[2].Init( Vector2D( xpos + w - 1, ypos + h - 1 ), uv22 ); + vert[3].Init( Vector2D( xpos, ypos + h - 1 ), uv12 ); + + vgui::surface()->DrawSetColor( m_clrBorder ); + vgui::surface()->DrawTexturedPolyLine( vert, 4 ); +} + +// Show the health / class for a player other than the local player +void CDoDHudHealthBar::SetHealthDelegatePlayer( C_DODPlayer *pPlayer ) +{ + m_hHealthDelegatePlayer = pPlayer; +} + +C_DODPlayer *CDoDHudHealthBar::GetHealthDelegatePlayer( void ) +{ + if ( m_hHealthDelegatePlayer.Get() ) + { + C_DODPlayer *pPlayer = dynamic_cast<C_DODPlayer *>( m_hHealthDelegatePlayer.Get() ); + if ( pPlayer ) + return pPlayer; + } + + return C_DODPlayer::GetLocalDODPlayer(); +} + +DECLARE_BUILD_FACTORY( CDoDHudHealth ); + +//----------------------------------------------------------------------------- +// Purpose: Constructor +//----------------------------------------------------------------------------- +CDoDHudHealth::CDoDHudHealth( vgui::Panel *parent, const char *name ) : vgui::EditablePanel( parent, name ) +{ + SetProportional( true ); + + m_pHealthBar = new CDoDHudHealthBar( this, "HealthBar" ); + m_pClassImageBG = new vgui::ImagePanel( this, "HealthClassImageBG" ); + m_pClassImage = new vgui::ImagePanel( this, "HealthClassImage" ); + + m_nPrevClass = PLAYERCLASS_UNDEFINED; + m_nPrevTeam = TEAM_INVALID; + + // load control settings... + LoadControlSettings( "resource/UI/HudPlayerStatusHealth.res" ); + + m_hHealthDelegatePlayer = NULL; +} + +void CDoDHudHealth::OnScreenSizeChanged(int iOldWide, int iOldTall) +{ + LoadControlSettings( "resource/UI/HudPlayerStatusHealth.res" ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CDoDHudHealth::OnThink() +{ + BaseClass::OnThink(); + + C_DODPlayer *pPlayer = GetHealthDelegatePlayer(); + if ( pPlayer ) + { + int nTeam = pPlayer->GetTeamNumber(); + + if ( nTeam == TEAM_ALLIES || nTeam == TEAM_AXIS ) + { + C_DODTeam *pTeam = dynamic_cast<C_DODTeam *>( GetGlobalTeam( nTeam ) ); + C_DOD_PlayerResource *dod_PR = dynamic_cast<C_DOD_PlayerResource *>( g_PR ); + int nClass = dod_PR->GetPlayerClass( pPlayer->entindex() ); + + if ( nClass != PLAYERCLASS_UNDEFINED ) + { + if ( ( nClass != m_nPrevClass ) || + ( nTeam != TEAM_INVALID && ( nTeam == TEAM_AXIS || nTeam == TEAM_ALLIES ) && nTeam != m_nPrevTeam ) ) + { + m_nPrevClass = nClass; + m_nPrevTeam = nTeam; + + if ( m_pClassImage ) + { + m_pClassImage->SetImage( ( pTeam->GetPlayerClassInfo( nClass ) ).m_szClassHealthImage ); + } + + if ( m_pClassImageBG ) + { + m_pClassImageBG->SetImage( ( pTeam->GetPlayerClassInfo( nClass ) ).m_szClassHealthImageBG ); + } + } + } + } + } +} + +// Show the health / class for a player other than the local player +void CDoDHudHealth::SetHealthDelegatePlayer( C_DODPlayer *pPlayer ) +{ + m_hHealthDelegatePlayer = pPlayer; + + m_pHealthBar->SetHealthDelegatePlayer( pPlayer ); +} + +C_DODPlayer *CDoDHudHealth::GetHealthDelegatePlayer( void ) +{ + if ( m_hHealthDelegatePlayer.Get() ) + { + C_DODPlayer *pPlayer = dynamic_cast<C_DODPlayer *>( m_hHealthDelegatePlayer.Get() ); + if ( pPlayer ) + return pPlayer; + } + + return C_DODPlayer::GetLocalDODPlayer(); +}
\ No newline at end of file diff --git a/game/client/dod/dod_hud_playerstatus_health.h b/game/client/dod/dod_hud_playerstatus_health.h new file mode 100644 index 0000000..0b14716 --- /dev/null +++ b/game/client/dod/dod_hud_playerstatus_health.h @@ -0,0 +1,78 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef DOD_HUD_PLAYERSTATUS_HEALTH_H +#define DOD_HUD_PLAYERSTATUS_HEALTH_H +#ifdef _WIN32 +#pragma once +#endif + +class C_DODPlayer; + +//----------------------------------------------------------------------------- +// Purpose: Health playerclass image (with red transparency) +//----------------------------------------------------------------------------- +class CDoDHudHealthBar : public vgui::ImagePanel +{ + DECLARE_CLASS_SIMPLE( CDoDHudHealthBar, vgui::ImagePanel ); + +public: + CDoDHudHealthBar( vgui::Panel *parent, const char *name ); + + virtual void ApplySchemeSettings( vgui::IScheme *pScheme ); + + virtual void OnThink(); + virtual void Paint( void ); + + void SetHealthDelegatePlayer( C_DODPlayer *pPlayer ); + C_DODPlayer *GetHealthDelegatePlayer( void ); + +private: + float m_flPercentage; + + int m_iMaterialIndex; + Color m_clrHealthHigh; + Color m_clrHealthMed; + Color m_clrHealthLow; + Color m_clrBackground; + Color m_clrBorder; + + EHANDLE m_hHealthDelegatePlayer; + + CPanelAnimationVar( float, m_flFirstWarningLevel, "FirstWarning", "0.50" ); + CPanelAnimationVar( float, m_flSecondWarningLevel, "SecondWarning", "0.25" ); +}; + +//----------------------------------------------------------------------------- +// Purpose: Health panel +//----------------------------------------------------------------------------- +class CDoDHudHealth : public vgui::EditablePanel +{ + DECLARE_CLASS_SIMPLE( CDoDHudHealth, vgui::EditablePanel ); + +public: + CDoDHudHealth( vgui::Panel *parent, const char *name ); + + virtual void OnThink(); + virtual void OnScreenSizeChanged(int iOldWide, int iOldTall); + + void SetHealthDelegatePlayer( C_DODPlayer *pPlayer ); + C_DODPlayer *GetHealthDelegatePlayer( void ); + +private: + int m_nPrevClass; // used to store the player's class so we don't have to keep setting the image + int m_nPrevTeam; + + CDoDHudHealthBar *m_pHealthBar; + + vgui::ImagePanel *m_pClassImage; // draws the class image and the red "damage taken" part + vgui::ImagePanel *m_pClassImageBG; // draws the class image outline + + EHANDLE m_hHealthDelegatePlayer; +}; + +#endif // DOD_HUD_PLAYERSTATUS_HEALTH_H diff --git a/game/client/dod/dod_hud_playerstatus_mgheat.cpp b/game/client/dod/dod_hud_playerstatus_mgheat.cpp new file mode 100644 index 0000000..b2e742d --- /dev/null +++ b/game/client/dod/dod_hud_playerstatus_mgheat.cpp @@ -0,0 +1,250 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#include "cbase.h" +#include <KeyValues.h> +#include <vgui/IScheme.h> +#include <vgui/ISurface.h> +#include <vgui/ISystem.h> +#include <vgui_controls/AnimationController.h> +#include <vgui_controls/EditablePanel.h> +#include <vgui_controls/ImagePanel.h> + +#include <vgui/ISurface.h> + +#include "c_dod_team.h" +#include "c_dod_playerresource.h" +#include "c_dod_player.h" + +#include "weapon_mg42.h" + +#include "dodcornercutpanel.h" +#include "dod_hud_playerstatus_mgheat.h" + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CDoDHudMGHeatProgressBar::ApplySchemeSettings( vgui::IScheme *pScheme ) +{ + BaseClass::ApplySchemeSettings( pScheme ); + + m_clrActive = pScheme->GetColor( "HudMGHeatBar.Active", GetFgColor() ); + m_clrActiveLow = pScheme->GetColor( "HudMGHeatBar.ActiveLow", GetFgColor() ); + m_clrInactive = pScheme->GetColor( "HudMGHeatBar.InActive", GetFgColor() ); + m_clrInactiveLow = pScheme->GetColor( "HudMGHeatBar.InActiveLow", GetFgColor() ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CDoDHudMGHeatProgressBar::Paint() +{ + BaseClass::Paint(); + + int xpos = 0, ypos = 0; + int x, y, w, t; + GetBounds( x, y, w, t ); + + if ( m_flPercentage > m_flWarningLevel ) + { + vgui::surface()->DrawSetColor( m_clrInactiveLow ); + } + else + { + vgui::surface()->DrawSetColor( m_clrInactive ); + } + + int nActiveLimit = w * ( 1.0f - m_flPercentage ); + + while ( xpos + m_flSliceWidth < w ) + { + if ( xpos + m_flSliceWidth > nActiveLimit ) + { + if ( m_flPercentage > m_flWarningLevel ) + { + vgui::surface()->DrawSetColor( m_clrActiveLow ); + } + else + { + vgui::surface()->DrawSetColor( m_clrActive ); + } + } + + vgui::surface()->DrawFilledRect( xpos, ypos, xpos + m_flSliceWidth, ypos + t ); + xpos += m_flSliceWidth + m_flSliceSpacer; + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CDoDHudMGHeatIcon::SetType( int nType ) +{ + m_nType = nType; + + switch( nType ) + { +// case WEAPON_30CAL: +// m_icon = gHUD.GetIcon( m_szIcon30cal ); +// break; + case WEAPON_MG42: + default: + m_icon = gHUD.GetIcon( m_szIconMg42 ); + break; + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CDoDHudMGHeatIcon::ApplySettings( KeyValues *inResourceData ) +{ +// Q_strncpy( m_szIcon30cal, inResourceData->GetString( "icon_30cal", "mgheat_30cal" ), sizeof( m_szIcon30cal ) ); + Q_strncpy( m_szIconMg42, inResourceData->GetString( "icon_mg42", "mgheat_mg42" ), sizeof( m_szIconMg42 ) ); + + BaseClass::ApplySettings( inResourceData ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CDoDHudMGHeatIcon::ApplySchemeSettings( vgui::IScheme *pScheme ) +{ + BaseClass::ApplySchemeSettings( pScheme ); + + m_clrActive = pScheme->GetColor( "HudMGHeatIcon.Active", GetFgColor() ); + m_clrActiveLow = pScheme->GetColor( "HudMGHeatIcon.ActiveLow", GetFgColor() ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CDoDHudMGHeatIcon::Paint() +{ + BaseClass::Paint(); + + int x, y, w, t; + GetBounds( x, y, w, t ); + + if ( m_icon ) + { + m_icon->DrawSelf( 0, 0, w, t, ( m_flPercentage > m_flWarningLevel ) ? m_clrActiveLow : m_clrActive ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +CDoDHudMGHeat::CDoDHudMGHeat( vgui::Panel *parent, const char *name ) : vgui::EditablePanel( parent, name ) +{ + m_pBackground = new CDoDCutEditablePanel( this, "MGHeatBackground" ); + m_pIcon = new CDoDHudMGHeatIcon( this, "MGHeatIcon" ); + m_pProgressBar = new CDoDHudMGHeatProgressBar( this, "MGHeatProgressBar" ); +} + +void CDoDHudMGHeat::ApplySchemeSettings( vgui::IScheme *pScheme ) +{ + // load control settings... + LoadControlSettings( "resource/UI/HudPlayerStatusMGHeat.res" ); + + BaseClass::ApplySchemeSettings( pScheme ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CDoDHudMGHeat::SetVisible( bool state ) +{ + if ( m_pBackground && m_pBackground->IsVisible() != state ) + { + m_pBackground->SetVisible( state ); + } + + if ( m_pIcon && m_pIcon->IsVisible() != state ) + { + m_pIcon->SetVisible( state ); + } + + if ( m_pProgressBar && m_pProgressBar->IsVisible() != state ) + { + m_pProgressBar->SetVisible( state ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CDoDHudMGHeat::OnThink() +{ + BaseClass::OnThink(); + + C_DODPlayer *pPlayer = C_DODPlayer::GetLocalDODPlayer(); + if ( pPlayer ) + { + CWeaponDODBase *pWeapon = pPlayer->GetActiveDODWeapon(); + if ( pWeapon ) + { +/* if ( pWeapon->IsA( WEAPON_30CAL ) ) + { + CWeapon30cal *p30Cal = (CWeapon30cal *)pWeapon; + + if( p30Cal ) + { + float flPercentage = (float)p30Cal->GetWeaponHeat() / 100.0; + + if ( m_pProgressBar ) + { + m_pProgressBar->SetPercentage( flPercentage ); + } + + if ( m_pIcon ) + { + m_pIcon->SetPercentage( flPercentage ); + } + } + + if ( m_pIcon ) + { + m_pIcon->SetType( WEAPON_30CAL ); + } + + SetVisible( true ); + } +*/ + if ( pWeapon->IsA( WEAPON_MG42 ) ) + { + CWeaponMG42 *pMG42 = (CWeaponMG42 *)pWeapon; + + if( pMG42 ) + { + float flPercentage = (float)pMG42->GetWeaponHeat() / 100.0; + + if ( m_pProgressBar ) + { + m_pProgressBar->SetPercentage( flPercentage ); + } + + if ( m_pIcon ) + { + m_pIcon->SetPercentage( flPercentage ); + } + } + + if ( m_pIcon ) + { + m_pIcon->SetType( WEAPON_MG42 ); + } + + SetVisible( true ); + } + else + { + SetVisible( false ); + } + } + } +} diff --git a/game/client/dod/dod_hud_playerstatus_mgheat.h b/game/client/dod/dod_hud_playerstatus_mgheat.h new file mode 100644 index 0000000..78573b8 --- /dev/null +++ b/game/client/dod/dod_hud_playerstatus_mgheat.h @@ -0,0 +1,95 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef DOD_HUD_PLAYERSTATUS_MGHEAT_H +#define DOD_HUD_PLAYERSTATUS_MGHEAT_H +#ifdef _WIN32 +#pragma once +#endif + +//----------------------------------------------------------------------------- +// Purpose: MGHeat progress bar +//----------------------------------------------------------------------------- +class CDoDHudMGHeatProgressBar : public vgui::Panel +{ + DECLARE_CLASS_SIMPLE( CDoDHudMGHeatProgressBar, vgui::Panel ); + +public: + CDoDHudMGHeatProgressBar( vgui::Panel *parent, const char *name ) : vgui::Panel( parent, name ){} + + virtual void Paint(); + virtual void ApplySchemeSettings( vgui::IScheme *pScheme ); + void SetPercentage( float flPercentage ){ m_flPercentage = flPercentage; } + +private: + + float m_flPercentage; + + Color m_clrActive; + Color m_clrActiveLow; + Color m_clrInactive; + Color m_clrInactiveLow; + + CPanelAnimationVarAliasType( float, m_flSliceWidth, "slice_width", "5", "proportional_float" ); + CPanelAnimationVarAliasType( float, m_flSliceSpacer, "slice_spacer", "2", "proportional_float" ); + CPanelAnimationVar( float, m_flWarningLevel, "warning_level", "0.75" ); +}; + +//----------------------------------------------------------------------------- +// Purpose: MGHeat icon +//----------------------------------------------------------------------------- +class CDoDHudMGHeatIcon : public vgui::ImagePanel +{ + DECLARE_CLASS_SIMPLE( CDoDHudMGHeatIcon, vgui::ImagePanel ); + +public: + CDoDHudMGHeatIcon( vgui::Panel *parent, const char *name ) : vgui::ImagePanel( parent, name ){}; + + void Init( void ); + virtual void Paint(); + virtual void ApplySettings( KeyValues *inResourceData ); + virtual void ApplySchemeSettings( vgui::IScheme *pScheme ); + void SetType( int nType ); + void SetPercentage( float flPercentage ){ m_flPercentage = flPercentage; } + +private: + + float m_flPercentage; + CHudTexture *m_icon; + + CPanelAnimationVar( float, m_flWarningLevel, "warning_level", "0.75" ); + +// char m_szIcon30cal[128]; + char m_szIconMg42[128]; + + int m_nType; + Color m_clrActive; + Color m_clrActiveLow; +}; + +//----------------------------------------------------------------------------- +// Purpose: MGHeat panel +//----------------------------------------------------------------------------- +class CDoDHudMGHeat : public vgui::EditablePanel +{ + DECLARE_CLASS_SIMPLE( CDoDHudMGHeat, vgui::EditablePanel ); + +public: + CDoDHudMGHeat( vgui::Panel *parent, const char *name ); + + virtual void ApplySchemeSettings( vgui::IScheme *pScheme ); + virtual void OnThink(); + virtual void SetVisible( bool state ); + +private: + + CDoDCutEditablePanel *m_pBackground; + CDoDHudMGHeatIcon *m_pIcon; + CDoDHudMGHeatProgressBar *m_pProgressBar; +}; + +#endif // DOD_HUD_PLAYERSTATUS_MGHEAT_H
\ No newline at end of file diff --git a/game/client/dod/dod_hud_playerstatus_stamina.cpp b/game/client/dod/dod_hud_playerstatus_stamina.cpp new file mode 100644 index 0000000..7edbed7 --- /dev/null +++ b/game/client/dod/dod_hud_playerstatus_stamina.cpp @@ -0,0 +1,172 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#include "cbase.h" +#include <KeyValues.h> +#include <vgui/IScheme.h> +#include <vgui/ISurface.h> +#include <vgui/ISystem.h> +#include <vgui_controls/AnimationController.h> +#include <vgui_controls/EditablePanel.h> +#include <vgui_controls/ImagePanel.h> + +#include <vgui/ISurface.h> + +#include "c_dod_team.h" +#include "c_dod_playerresource.h" +#include "c_dod_player.h" + +#include "dodcornercutpanel.h" +#include "dod_hud_playerstatus_stamina.h" + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CDoDHudStaminaProgressBar::ApplySchemeSettings( vgui::IScheme *pScheme ) +{ + BaseClass::ApplySchemeSettings( pScheme ); + + m_clrActive = pScheme->GetColor( "HudStaminaBar.Active", GetFgColor() ); + m_clrActiveLow = pScheme->GetColor( "HudStaminaBar.ActiveLow", GetFgColor() ); + m_clrInactive = pScheme->GetColor( "HudStaminaBar.InActive", GetFgColor() ); + m_clrInactiveLow = pScheme->GetColor( "HudStaminaBar.InActiveLow", GetFgColor() ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CDoDHudStaminaProgressBar::Paint() +{ + BaseClass::Paint(); + + int xpos = 0, ypos = 0; + int x, y, w, t; + GetBounds( x, y, w, t ); + + if ( m_flPercentage < m_flWarningLevel ) + { + vgui::surface()->DrawSetColor( m_clrActiveLow ); + } + else + { + vgui::surface()->DrawSetColor( m_clrActive ); + } + + int nActiveLimit = w * m_flPercentage; + + while ( xpos + m_flSliceWidth < w ) + { + if ( xpos + m_flSliceWidth > nActiveLimit ) + { + if ( m_flPercentage < m_flWarningLevel ) + { + vgui::surface()->DrawSetColor( m_clrInactiveLow ); + } + else + { + vgui::surface()->DrawSetColor( m_clrInactive ); + } + } + + vgui::surface()->DrawFilledRect( xpos, ypos, xpos + m_flSliceWidth, ypos + t ); + xpos += m_flSliceWidth + m_flSliceSpacer; + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +CDoDHudStaminaIcon::CDoDHudStaminaIcon( vgui::Panel *parent, const char *name ) : vgui::ImagePanel( parent, name ) +{ + m_icon = NULL; + memset( m_szIcon, 0, sizeof( m_szIcon ) ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CDoDHudStaminaIcon::ApplySettings( KeyValues *inResourceData ) +{ + BaseClass::ApplySettings( inResourceData ); + + Q_strncpy( m_szIcon, inResourceData->GetString( "stamina_icon", "stamina_icon" ), sizeof( m_szIcon ) ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CDoDHudStaminaIcon::ApplySchemeSettings( vgui::IScheme *pScheme ) +{ + BaseClass::ApplySchemeSettings( pScheme ); + + m_clrActive = pScheme->GetColor( "HudStaminaIcon.Active", GetFgColor() ); + m_clrActiveLow = pScheme->GetColor( "HudStaminaIcon.ActiveLow", GetFgColor() ); + + if ( !m_icon ) + { + m_icon = gHUD.GetIcon( m_szIcon ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CDoDHudStaminaIcon::Paint() +{ + int x, y, w, t; + GetBounds( x, y, w, t ); + + if ( m_icon ) + { + m_icon->DrawSelf( 0, -3, w, t, ( m_flPercentage < m_flWarningLevel ) ? m_clrActiveLow : m_clrActive ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +CDoDHudStamina::CDoDHudStamina( vgui::Panel *parent, const char *name ) : vgui::EditablePanel( parent, name ) +{ + m_pBackground = new CDoDCutEditablePanel( this, "StaminaBackground" ); + m_pIcon = new CDoDHudStaminaIcon( this, "StaminaIcon" ); + m_pProgressBar = new CDoDHudStaminaProgressBar( this, "StaminaProgressBar" ); + + // load control settings... + LoadControlSettings( "resource/UI/HudPlayerStatusStamina.res" ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CDoDHudStamina::OnScreenSizeChanged( int iOldWide, int iOldTall ) +{ + LoadControlSettings( "resource/UI/HudPlayerStatusStamina.res" ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CDoDHudStamina::OnThink() +{ + BaseClass::OnThink(); + + C_DODPlayer *pPlayer = C_DODPlayer::GetLocalDODPlayer(); + if ( pPlayer ) + { + float flPercentage = (float)( pPlayer->m_Shared.GetStamina() ) / 100.0f; + + if ( m_pProgressBar ) + { + m_pProgressBar->SetPercentage( flPercentage ); + } + + if ( m_pIcon ) + { + m_pIcon->SetPercentage( flPercentage ); + } + } +} diff --git a/game/client/dod/dod_hud_playerstatus_stamina.h b/game/client/dod/dod_hud_playerstatus_stamina.h new file mode 100644 index 0000000..27c3217 --- /dev/null +++ b/game/client/dod/dod_hud_playerstatus_stamina.h @@ -0,0 +1,91 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef DOD_HUD_PLAYERSTATUS_STAMINA_H +#define DOD_HUD_PLAYERSTATUS_STAMINA_H +#ifdef _WIN32 +#pragma once +#endif + +//----------------------------------------------------------------------------- +// Purpose: Stamina progress bar +//----------------------------------------------------------------------------- +class CDoDHudStaminaProgressBar : public vgui::Panel +{ + DECLARE_CLASS_SIMPLE( CDoDHudStaminaProgressBar, vgui::Panel ); + +public: + CDoDHudStaminaProgressBar( vgui::Panel *parent, const char *name ) : vgui::Panel( parent, name ){} + + virtual void Paint(); + virtual void ApplySchemeSettings( vgui::IScheme *pScheme ); + void SetPercentage( float flPercentage ){ m_flPercentage = flPercentage; } + +private: + + float m_flPercentage; + + Color m_clrActive; + Color m_clrActiveLow; + Color m_clrInactive; + Color m_clrInactiveLow; + + CPanelAnimationVarAliasType( float, m_flSliceWidth, "slice_width", "5", "proportional_float" ); + CPanelAnimationVarAliasType( float, m_flSliceSpacer, "slice_spacer", "2", "proportional_float" ); + CPanelAnimationVar( float, m_flWarningLevel, "warning_level", "0.25" ); +}; + +//----------------------------------------------------------------------------- +// Purpose: Stamina icon +//----------------------------------------------------------------------------- +class CDoDHudStaminaIcon : public vgui::ImagePanel +{ + DECLARE_CLASS_SIMPLE( CDoDHudStaminaIcon, vgui::ImagePanel ); + +public: + CDoDHudStaminaIcon( vgui::Panel *parent, const char *name ); + + virtual void Paint(); + virtual void ApplySettings( KeyValues *inResourceData ); + virtual void ApplySchemeSettings( vgui::IScheme *pScheme ); + + void SetPercentage( float flPercentage ){ m_flPercentage = flPercentage; } + +private: + + float m_flPercentage; + CHudTexture *m_icon; + + CPanelAnimationVar( float, m_flWarningLevel, "warning_level", "0.25" ); + + char m_szIcon[128]; + + Color m_clrActive; + Color m_clrActiveLow; +}; + +//----------------------------------------------------------------------------- +// Purpose: Stamina panel +//----------------------------------------------------------------------------- +class CDoDHudStamina : public vgui::EditablePanel +{ + DECLARE_CLASS_SIMPLE( CDoDHudStamina, vgui::EditablePanel ); + +public: + CDoDHudStamina( vgui::Panel *parent, const char *name ); + + virtual void OnThink(); + virtual void OnScreenSizeChanged( int iOldWide, int iOldTall ); + +private: + + CDoDCutEditablePanel *m_pBackground; + CDoDHudStaminaIcon *m_pIcon; + CDoDHudStaminaProgressBar *m_pProgressBar; +}; + +#endif // DOD_HUD_PLAYERSTATUS_STAMINA_H
\ No newline at end of file diff --git a/game/client/dod/dod_hud_playerstatus_tnt.cpp b/game/client/dod/dod_hud_playerstatus_tnt.cpp new file mode 100644 index 0000000..cca78ff --- /dev/null +++ b/game/client/dod/dod_hud_playerstatus_tnt.cpp @@ -0,0 +1,133 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#include "cbase.h" +#include <KeyValues.h> +#include <vgui/IScheme.h> +#include <vgui/ISurface.h> +#include <vgui/ISystem.h> +#include <vgui_controls/EditablePanel.h> +#include <vgui_controls/ImagePanel.h> + +#include <vgui/ISurface.h> + +#include "c_dod_player.h" + +#include "dodcornercutpanel.h" +#include "dod_hud_playerstatus_tnt.h" +#include "dod_gamerules.h" +#include "clientmode_dod.h" + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +CDoDHudTNT::CDoDHudTNT( vgui::Panel *parent, const char *name ) : CDoDCutEditablePanel( parent, name ) +{ + m_pIconTNT = new CIconPanel( this, "Icon_TNT" ); + m_pIconTNT_Missing = new CIconPanel( this, "Icon_TNT_Missing" ); + + SetProportional( true ); + LoadControlSettings( "resource/UI/HudPlayerStatusTNT.res" ); + + m_pIconTNT->SetVisible( false ); + m_pIconTNT_Missing->SetVisible( true ); + + m_bHasTNT = false; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CDoDHudTNT::ApplySchemeSettings( vgui::IScheme *pScheme ) +{ + LoadControlSettings( "resource/UI/HudPlayerStatusTNT.res" ); + + BaseClass::ApplySchemeSettings( pScheme ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CDoDHudTNT::ApplySettings( KeyValues *inResourceData ) +{ + BaseClass::ApplySettings( inResourceData ); + + // Get icon loc, dims + + m_iIconX = vgui::scheme()->GetProportionalScaledValueEx( GetScheme(), inResourceData->GetInt( "icon_x", 0 ) ); + m_iIconY = vgui::scheme()->GetProportionalScaledValueEx( GetScheme(), inResourceData->GetInt( "icon_y", 0 ) ); + m_iIconW = vgui::scheme()->GetProportionalScaledValueEx( GetScheme(), inResourceData->GetInt( "icon_w", 32 ) ); + m_iIconH = vgui::scheme()->GetProportionalScaledValueEx( GetScheme(), inResourceData->GetInt( "icon_h", 32 ) ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CDoDHudTNT::SetVisible( bool state ) +{ +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CDoDHudTNT::OnThink() +{ + BaseClass::OnThink(); + + C_DODPlayer *pPlayer = C_DODPlayer::GetLocalDODPlayer(); + if ( !pPlayer ) + { + return; + } + + if ( DODGameRules()->IsBombingTeam( pPlayer->GetTeamNumber() ) ) + { + SetAlpha( 255 ); + + C_BaseCombatWeapon *pBomb = NULL; + + for ( int i = 0; i < MAX_WEAPONS; i++ ) + { + C_BaseCombatWeapon *pWeapon = pPlayer->GetWeapon( i ); + + if ( pWeapon == NULL ) + { + continue; + } + + if ( pWeapon->GetSlot() == WPN_SLOT_BOMB ) + { + pBomb = pWeapon; + break; + } + } + + if ( pBomb ) + { + if ( m_bHasTNT == false ) + { + m_bHasTNT = true; + + m_pIconTNT->SetVisible( true ); + m_pIconTNT_Missing->SetVisible( false ); + } + } + else + { + if ( m_bHasTNT == true ) + { + m_bHasTNT = false; + + m_pIconTNT->SetVisible( false ); + m_pIconTNT_Missing->SetVisible( true ); + } + } + } + else + { + SetAlpha( 0 ); + } +}
\ No newline at end of file diff --git a/game/client/dod/dod_hud_playerstatus_tnt.h b/game/client/dod/dod_hud_playerstatus_tnt.h new file mode 100644 index 0000000..3d190a1 --- /dev/null +++ b/game/client/dod/dod_hud_playerstatus_tnt.h @@ -0,0 +1,49 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef DOD_HUD_PLAYERSTATUS_TNT_H +#define DOD_HUD_PLAYERSTATUS_TNT_H +#ifdef _WIN32 +#pragma once +#endif + +#include "dodcornercutpanel.h" +#include "IconPanel.h" + +using namespace vgui; + +//----------------------------------------------------------------------------- +// Purpose: FireSelect panel +//----------------------------------------------------------------------------- +class CDoDHudTNT : public CDoDCutEditablePanel +{ + DECLARE_CLASS_SIMPLE( CDoDHudTNT, CDoDCutEditablePanel ); + +public: + CDoDHudTNT( vgui::Panel *parent, const char *name ); + + virtual void ApplySchemeSettings( vgui::IScheme *pScheme ); + virtual void ApplySettings( KeyValues *inResourceData ); + virtual void OnThink(); + virtual void SetVisible( bool state ); + +private: + + CIconPanel *m_pIconTNT; + CIconPanel *m_pIconTNT_Missing; + + bool m_bHasTNT; + + int m_iIconX; + int m_iIconY; + int m_iIconW; + int m_iIconH; + + CPanelAnimationVar( float, m_flIconAlpha, "icon_alpha", "255" ); +}; + +#endif // DOD_HUD_PLAYERSTATUS_TNT_H
\ No newline at end of file diff --git a/game/client/dod/dod_hud_playerstatus_weapon.cpp b/game/client/dod/dod_hud_playerstatus_weapon.cpp new file mode 100644 index 0000000..1301e35 --- /dev/null +++ b/game/client/dod/dod_hud_playerstatus_weapon.cpp @@ -0,0 +1,62 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#include "cbase.h" +#include <KeyValues.h> +#include <vgui/IScheme.h> +#include <vgui/ISurface.h> +#include <vgui/ISystem.h> +#include <vgui_controls/AnimationController.h> +#include <vgui_controls/EditablePanel.h> +#include <vgui_controls/ImagePanel.h> + +#include "c_dod_team.h" +#include "c_dod_playerresource.h" +#include "c_dod_player.h" + +#include "weapon_dodbase.h" + +#include "dod_hud_playerstatus_weapon.h" + +float GetScale( int nIconWidth, int nIconHeight, int nWidth, int nHeight ); + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CDoDHudCurrentWeapon::Paint() +{ + C_DODPlayer *pPlayer = C_DODPlayer::GetLocalDODPlayer(); + if ( pPlayer ) + { + C_WeaponDODBase *pWeapon = pPlayer->GetActiveDODWeapon(); + + if ( pWeapon ) + { + const CHudTexture *pWpnSprite = pWeapon->GetSpriteActive(); + + if ( pWpnSprite ) + { + int x, y, w, h; + GetBounds( x, y, w, h ); + + int spriteWidth = pWpnSprite->Width(), spriteHeight = pWpnSprite->Height(); + float scale = GetScale( spriteWidth, spriteHeight, w, h ); + + spriteWidth *= scale; + spriteHeight *= scale; + + int xpos = ( w / 2.0f ) - ( spriteWidth / 2.0f ); + int ypos = ( h / 2.0f ) - ( spriteHeight / 2.0f ); + + pWpnSprite->DrawSelf( xpos, ypos, spriteWidth, spriteHeight, Color( 255, 255, 255, 255 ) ); + } + } + } +} + + + + diff --git a/game/client/dod/dod_hud_playerstatus_weapon.h b/game/client/dod/dod_hud_playerstatus_weapon.h new file mode 100644 index 0000000..4a9d51f --- /dev/null +++ b/game/client/dod/dod_hud_playerstatus_weapon.h @@ -0,0 +1,28 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef DOD_HUD_PLAYERSTATUS_WEAPON_H +#define DOD_HUD_PLAYERSTATUS_WEAPON_H +#ifdef _WIN32 +#pragma once +#endif + +//----------------------------------------------------------------------------- +// Purpose: Weapon Selection panel +//----------------------------------------------------------------------------- +class CDoDHudCurrentWeapon : public vgui::EditablePanel +{ + DECLARE_CLASS_SIMPLE( CDoDHudCurrentWeapon, vgui::EditablePanel ); + +public: + CDoDHudCurrentWeapon( vgui::Panel *parent, const char *name ) : vgui::EditablePanel( parent, name ){} + + virtual void Paint(); + +}; + +#endif // DOD_HUD_PLAYERSTATUS_WEAPON_H
\ No newline at end of file diff --git a/game/client/dod/dod_hud_playerstatuspanel.cpp b/game/client/dod/dod_hud_playerstatuspanel.cpp new file mode 100644 index 0000000..5419869 --- /dev/null +++ b/game/client/dod/dod_hud_playerstatuspanel.cpp @@ -0,0 +1,184 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#include "cbase.h" +#include "hudelement.h" +#include <vgui_controls/EditablePanel.h> +#include <vgui_controls/ImagePanel.h> +#include <vgui/ISurface.h> +#include "c_dod_player.h" +#include "clientmode_dod.h" + +#include "dodcornercutpanel.h" + +#include "c_dod_objective_resource.h" +#include "c_dod_playerresource.h" + +#include "dod_hud_playerstatus_ammo.h" +#include "dod_hud_playerstatus_health.h" +#include "dod_hud_playerstatus_weapon.h" +#include "dod_hud_playerstatus_stamina.h" +#include "dod_hud_playerstatus_mgheat.h" +#include "dod_hud_playerstatus_fireselect.h" +#include "dod_hud_playerstatus_tnt.h" + +class CDoDHudPlayerStatusPanel : public CHudElement, public vgui::EditablePanel +{ +public: + DECLARE_CLASS_SIMPLE( CDoDHudPlayerStatusPanel, vgui::EditablePanel ); + + CDoDHudPlayerStatusPanel( const char *pElementName ); + + virtual void Init(); + virtual void OnThink(); + virtual void PerformLayout(); + virtual void ApplySchemeSettings( IScheme *pScheme ); + +private: + + CDoDCutEditablePanel *m_pMainBar; + ImagePanel *m_pAlliesIcon; + ImagePanel *m_pAxisIcon; + CDoDHudAmmo *m_pAmmoStatus; + CDoDHudHealth *m_pHealthStatus; + CDoDHudCurrentWeapon *m_pCurrentWeapon; + CDoDHudStamina *m_pStamina; + CDoDHudMGHeat *m_pMGHeat; + CDoDHudFireSelect *m_pFireSelect; + CDoDHudTNT *m_pTNT; +}; + +DECLARE_HUDELEMENT( CDoDHudPlayerStatusPanel ); + +//----------------------------------------------------------------------------- +// Purpose: Constructor +//----------------------------------------------------------------------------- +CDoDHudPlayerStatusPanel::CDoDHudPlayerStatusPanel( const char *pElementName ) : CHudElement( pElementName ), BaseClass( NULL, "HudPlayerStatusPanel" ) +{ + SetParent( g_pClientMode->GetViewport() ); + + m_pMainBar = new CDoDCutEditablePanel( this, "PlayerStatusMainBackground" ); + m_pAlliesIcon = new ImagePanel( this, "PlayerStatusAlliesIcon" ); + m_pAxisIcon = new ImagePanel( this, "PlayerStatusAxisIcon" ); + m_pAmmoStatus = new CDoDHudAmmo( this, "PlayerStatusAmmo" ); + m_pCurrentWeapon = new CDoDHudCurrentWeapon( this, "PlayerStatusCurrentWeapon" ); + m_pHealthStatus = new CDoDHudHealth( this, "PlayerStatusHealth" ); + m_pStamina = new CDoDHudStamina( this, "PlayerStatusStamina" ); + m_pMGHeat = new CDoDHudMGHeat( this, "PlayerStatusMGHeat" ); + m_pFireSelect = new CDoDHudFireSelect( this, "PlayerStatusFireSelect" ); + m_pTNT = new CDoDHudTNT( this, "PlayerStatusTNT" ); +} + +void CDoDHudPlayerStatusPanel::ApplySchemeSettings( IScheme *pScheme ) +{ + // load control settings... + LoadControlSettings( "resource/UI/HudPlayerStatusPanel.res" ); + + BaseClass::ApplySchemeSettings( pScheme ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CDoDHudPlayerStatusPanel::Init() +{ + if ( m_pMainBar ) + { + m_pMainBar->SetVisible( true ); + } + + if ( m_pStamina ) + { + m_pStamina->SetVisible( true ); + } + + if ( m_pAlliesIcon ) + { + m_pAlliesIcon->SetVisible( false ); + } + + if ( m_pAxisIcon ) + { + m_pAxisIcon->SetVisible( false ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CDoDHudPlayerStatusPanel::PerformLayout() +{ + BaseClass::PerformLayout(); + + int x, y, w, t; + GetBounds( x, y, w, t ); + + if ( w != ScreenWidth() ) + { + // doing this because of the 16:9 and 16:10 resolutions (VGUI doesn't scale properly for them) + SetBounds( x, y, ScreenWidth(), t ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CDoDHudPlayerStatusPanel::OnThink() +{ + BaseClass::OnThink(); + + C_DODPlayer *pPlayer = C_DODPlayer::GetLocalDODPlayer(); + + if ( pPlayer ) + { + // turn off the panel and children if the player is dead + if ( !pPlayer->IsAlive() ) + { + if ( IsVisible() ) + { + SetVisible( false ); + } + return; + } + else + { + if ( !IsVisible() ) + { + SetVisible( true ); + } + } + + // set our team icon + int nTeam = pPlayer->GetTeamNumber(); + + switch( nTeam ) + { + case TEAM_AXIS: + if ( m_pAlliesIcon && m_pAlliesIcon->IsVisible() ) + { + m_pAlliesIcon->SetVisible( false ); + } + if ( m_pAxisIcon && !m_pAxisIcon->IsVisible() ) + { + m_pAxisIcon->SetVisible( true ); + } + break; + case TEAM_ALLIES: + default: + if ( m_pAlliesIcon && !m_pAlliesIcon->IsVisible() ) + { + m_pAlliesIcon->SetVisible( true ); + } + if ( m_pAxisIcon && m_pAxisIcon->IsVisible() ) + { + m_pAxisIcon->SetVisible( false ); + } + break; + } + } +} + + diff --git a/game/client/dod/dod_hud_readyrestart.cpp b/game/client/dod/dod_hud_readyrestart.cpp new file mode 100644 index 0000000..756066f --- /dev/null +++ b/game/client/dod/dod_hud_readyrestart.cpp @@ -0,0 +1,206 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#include "cbase.h" +#include "hud.h" +#include "hudelement.h" +#include "hud_macros.h" +#include "iclientmode.h" +#include "vgui_controls/AnimationController.h" +#include "vgui_controls/Label.h" +#include "vgui/ILocalize.h" +#include "vgui/ISurface.h" +#include "text_message.h" +#include "dod_gamerules.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +//----------------------------------------------------------------------------- +// Purpose: Displays current ammunition level +//----------------------------------------------------------------------------- +class CDODReadyRestartLabel : public vgui::Panel, public CHudElement +{ + DECLARE_CLASS_SIMPLE( CDODReadyRestartLabel, vgui::Panel ); + +public: + CDODReadyRestartLabel( const char *pElementName ); + + virtual void Reset(); + virtual void Init(); + + virtual void PerformLayout(); + + void FireGameEvent( IGameEvent * event); + +protected: + virtual void ApplySchemeSettings( vgui::IScheme *pScheme ); + virtual void OnThink(); + +private: + vgui::HFont m_hFont; + Color m_bgColor; + + vgui::Label *m_pRestartLabel; // "Round will restart in 0:00" + vgui::Label *m_pAlliesReady; // "Allies are READY" + vgui::Label *m_pAxisReady; // "Axis are NOT READY" + + vgui::Label *m_pBackground; + + float m_flLastRestartTime; + + CPanelAnimationVarAliasType( int, m_iTextX, "text_xpos", "8", "proportional_int" ); + CPanelAnimationVarAliasType( int, m_iTextY, "text_ypos", "8", "proportional_int" ); +}; + +DECLARE_HUDELEMENT( CDODReadyRestartLabel ); + +//----------------------------------------------------------------------------- +// Purpose: Constructor +//----------------------------------------------------------------------------- +CDODReadyRestartLabel::CDODReadyRestartLabel( const char *pElementName ) : BaseClass(NULL, "ReadyRestartLabel"), CHudElement( pElementName ) +{ + vgui::Panel *pParent = g_pClientMode->GetViewport(); + SetParent( pParent ); + SetVisible( false ); + SetAlpha( 0 ); + + m_pBackground = new vgui::Label( this, "Background", "" ); + + wchar_t labelText[128]; + g_pVGuiLocalize->ConstructString( labelText, sizeof(labelText), g_pVGuiLocalize->Find( "#clan_game_restart" ), 2, L"0", L"00" ); + + m_pRestartLabel = new vgui::Label( this, "RoundState_waiting", g_pVGuiLocalize->Find( "#Clan_awaiting_ready" ) ); + m_pRestartLabel->SetFgColor( GetFgColor() ); + m_pRestartLabel->SizeToContents(); + + m_pAlliesReady = new vgui::Label( this, "RoundState_allies", L"" ); + m_pAlliesReady->SetFgColor( GetFgColor() ); + + m_pAxisReady = new vgui::Label( this, "RoundState_axis", L"" ); + m_pAxisReady->SetFgColor( GetFgColor() ); + + m_flLastRestartTime = 0; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CDODReadyRestartLabel::Reset() +{ + g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( "ReadyRestartLabelHide" ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CDODReadyRestartLabel::Init() +{ + // listen for events + ListenForGameEvent( "dod_round_start" ); + ListenForGameEvent( "dod_ready_restart" ); + ListenForGameEvent( "dod_allies_ready" ); + ListenForGameEvent( "dod_axis_ready" ); + + g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( "ReadyRestartLabelHide" ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CDODReadyRestartLabel::ApplySchemeSettings( vgui::IScheme *pScheme ) +{ + BaseClass::ApplySchemeSettings( pScheme ); + + SetFgColor( Color(0,0,0,0) ); + m_hFont = pScheme->GetFont( "HudHintText", true ); + + m_pBackground->SetBgColor( GetSchemeColor("HintMessageBg", pScheme) ); + m_pBackground->SetPaintBackgroundType( 2 ); + + SetAlpha( 0 ); +} + +//----------------------------------------------------------------------------- +// Purpose: Resizes the label +//----------------------------------------------------------------------------- +void CDODReadyRestartLabel::PerformLayout() +{ + BaseClass::PerformLayout(); + + int wide, tall; + GetSize( wide, tall ); + + // find the widest line + int labelWide = m_pRestartLabel->GetWide(); + + // find the total height + int fontTall = vgui::surface()->GetFontTall( m_hFont ); + + labelWide += m_iTextX*2; + int labelTall = fontTall*3 + m_iTextY*2; + + m_pBackground->SetBounds( 0, 0, labelWide, labelTall ); + + int xOffset = (labelWide - m_pRestartLabel->GetWide())/2; + + m_pRestartLabel->SetPos( xOffset, m_iTextY ); + m_pAlliesReady->SetPos( xOffset, m_iTextY + fontTall ); + m_pAxisReady->SetPos( xOffset, m_iTextY + 2 *fontTall ); +} + +//----------------------------------------------------------------------------- +// Purpose: Updates the label color each frame +//----------------------------------------------------------------------------- +void CDODReadyRestartLabel::OnThink() +{ + float flRoundRestartTime = DODGameRules()->GetRoundRestartTime(); + + if( flRoundRestartTime != m_flLastRestartTime ) + { + if( flRoundRestartTime > 0 ) + { + g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( "ReadyRestartLabelHide" ); + } + m_flLastRestartTime = flRoundRestartTime; + } + + m_pBackground->SetFgColor(GetFgColor()); + m_pRestartLabel->SetFgColor(GetFgColor()); + m_pAlliesReady->SetFgColor(GetFgColor()); + m_pAxisReady->SetFgColor(GetFgColor()); +} + +//----------------------------------------------------------------------------- +// Purpose: Activates the hint display upon receiving a hint +//----------------------------------------------------------------------------- +void CDODReadyRestartLabel::FireGameEvent( IGameEvent * event) +{ + if( Q_strcmp( "dod_round_start", event->GetName() ) == 0 ) + { + g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( "ReadyRestartLabelHide" ); + } + else if( Q_strcmp( "dod_ready_restart", event->GetName() ) == 0 ) + { + g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( "ReadyRestartLabelShow" ); + + m_pAlliesReady->SetText( g_pVGuiLocalize->Find( "#clan_allies_not_ready" ) ); + m_pAlliesReady->SizeToContents(); + + m_pAxisReady->SetText( g_pVGuiLocalize->Find( "#clan_axis_not_ready" ) ); + m_pAxisReady->SizeToContents(); + } + else if( Q_strcmp( "dod_allies_ready", event->GetName() ) == 0 ) + { + m_pAlliesReady->SetText( g_pVGuiLocalize->Find( "#clan_allies_ready" ) ); + m_pAlliesReady->SizeToContents(); + } + else if( Q_strcmp( "dod_axis_ready", event->GetName() ) == 0 ) + { + m_pAxisReady->SetText( g_pVGuiLocalize->Find( "#clan_axis_ready" ) ); + m_pAxisReady->SizeToContents(); + } +}
\ No newline at end of file diff --git a/game/client/dod/dod_hud_restartround.cpp b/game/client/dod/dod_hud_restartround.cpp new file mode 100644 index 0000000..5d50f73 --- /dev/null +++ b/game/client/dod/dod_hud_restartround.cpp @@ -0,0 +1,170 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#include "cbase.h" +#include "hud.h" +#include "hudelement.h" +#include "hud_macros.h" +#include "iclientmode.h" +#include "vgui_controls/AnimationController.h" +#include "vgui_controls/Label.h" +#include "vgui/ILocalize.h" +#include "vgui/ISurface.h" +#include "text_message.h" +#include "dod_gamerules.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +//----------------------------------------------------------------------------- +// Purpose: Displays current ammunition level +//----------------------------------------------------------------------------- +class CDODRestartRoundLabel : public vgui::Panel, public CHudElement +{ + DECLARE_CLASS_SIMPLE( CDODRestartRoundLabel, vgui::Panel ); + +public: + CDODRestartRoundLabel( const char *pElementName ); + virtual void Reset(); + + virtual void PerformLayout(); + +protected: + virtual void ApplySchemeSettings( vgui::IScheme *pScheme ); + virtual void OnThink(); + +private: + vgui::HFont m_hFont; + Color m_bgColor; + + vgui::Label *m_pRestartLabel; // "Round will restart in 0:00" + + vgui::Label *m_pBackground; + + CPanelAnimationVarAliasType( int, m_iTextX, "text_xpos", "8", "proportional_int" ); + CPanelAnimationVarAliasType( int, m_iTextY, "text_ypos", "8", "proportional_int" ); + + float m_flLastRestartTime; +}; + +DECLARE_HUDELEMENT( CDODRestartRoundLabel ); + +//----------------------------------------------------------------------------- +// Purpose: Constructor +//----------------------------------------------------------------------------- +CDODRestartRoundLabel::CDODRestartRoundLabel( const char *pElementName ) : BaseClass(NULL, "RestartRoundLabel"), CHudElement( pElementName ) +{ + vgui::Panel *pParent = g_pClientMode->GetViewport(); + SetParent( pParent ); + SetVisible( false ); + SetAlpha( 0 ); + + m_pBackground = new vgui::Label( this, "Background", "" ); + + wchar_t labelText[128]; + g_pVGuiLocalize->ConstructString( labelText, sizeof(labelText), g_pVGuiLocalize->Find( "#clan_game_restart" ), 2, L"0", L"00" ); + + m_pRestartLabel = new vgui::Label( this, "restartroundlabel", labelText ); + m_pRestartLabel->SetPaintBackgroundEnabled( false ); + m_pRestartLabel->SetPaintBorderEnabled( false ); + m_pRestartLabel->SizeToContents(); + m_pRestartLabel->SetContentAlignment( vgui::Label::a_west ); + m_pRestartLabel->SetFgColor( GetFgColor() ); + + m_flLastRestartTime = 0; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CDODRestartRoundLabel::Reset() +{ + g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( "RestartRoundLabelHide" ); + + m_flLastRestartTime = 0; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CDODRestartRoundLabel::ApplySchemeSettings( vgui::IScheme *pScheme ) +{ + BaseClass::ApplySchemeSettings( pScheme ); + + SetFgColor( Color(0,0,0,0) ); + m_hFont = pScheme->GetFont( "HudHintText", true ); + + m_pBackground->SetBgColor( GetSchemeColor("HintMessageBg", pScheme) ); + m_pBackground->SetPaintBackgroundType( 2 ); + + SetAlpha( 0 ); +} + +//----------------------------------------------------------------------------- +// Purpose: Resizes the label +//----------------------------------------------------------------------------- +void CDODRestartRoundLabel::PerformLayout() +{ + BaseClass::PerformLayout(); + + int wide, tall; + GetSize( wide, tall ); + + // find the widest line + int labelWide = m_pRestartLabel->GetWide(); + + // find the total height + int fontTall = vgui::surface()->GetFontTall( m_hFont ); + int labelTall = fontTall; + + labelWide += m_iTextX*2; + labelTall += m_iTextY*2; + + m_pBackground->SetBounds( 0, 0, labelWide, labelTall ); + + int xOffset = (labelWide - m_pRestartLabel->GetWide())/2; + m_pRestartLabel->SetPos( 0 + xOffset, 0 + m_iTextY ); +} + +//----------------------------------------------------------------------------- +// Purpose: Updates the label color each frame +//----------------------------------------------------------------------------- +void CDODRestartRoundLabel::OnThink() +{ + float flRoundRestartTime = DODGameRules()->GetRoundRestartTime(); + + if( flRoundRestartTime != m_flLastRestartTime ) + { + if( flRoundRestartTime > 0 ) + { + g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( "RestartRoundLabelShow" ); + } + m_flLastRestartTime = flRoundRestartTime; + } + + if( GetAlpha() > 0 ) + { + wchar_t minutes[4]; + wchar_t seconds[4]; + + int iSecondsRemaining = (int)( flRoundRestartTime - gpGlobals->curtime ); + + iSecondsRemaining = MAX( 0, iSecondsRemaining ); + + _snwprintf ( minutes, sizeof(minutes)/sizeof(wchar_t), L"%d", (iSecondsRemaining / 60) ); + _snwprintf ( seconds, sizeof(seconds)/sizeof(wchar_t), L"%02d", (iSecondsRemaining % 60) ); + + wchar_t labelText[128]; + g_pVGuiLocalize->ConstructString( labelText, sizeof(labelText), g_pVGuiLocalize->Find( "#clan_game_restart" ), 2, minutes, seconds ); + + m_pRestartLabel->SetText( labelText ); + m_pRestartLabel->SizeToContents(); + //InvalidateLayout(); + } + + m_pBackground->SetFgColor(GetFgColor()); + m_pRestartLabel->SetFgColor(GetFgColor()); +}
\ No newline at end of file diff --git a/game/client/dod/dod_hud_scope.cpp b/game/client/dod/dod_hud_scope.cpp new file mode 100644 index 0000000..4efd029 --- /dev/null +++ b/game/client/dod/dod_hud_scope.cpp @@ -0,0 +1,225 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#include "cbase.h" +#include "hud.h" +#include "hudelement.h" +#include "hud_macros.h" +#include "hud_numericdisplay.h" +#include "iclientmode.h" +#include "c_dod_player.h" +#include "VGuiMatSurface/IMatSystemSurface.h" +#include "materialsystem/imaterial.h" +#include "materialsystem/imesh.h" +#include "materialsystem/imaterialvar.h" + +#include <vgui/IScheme.h> +#include <vgui/ISurface.h> +#include <KeyValues.h> +#include <vgui_controls/AnimationController.h> + +//for screenfade +#include "ivieweffects.h" +#include "shake.h" + +#include "weapon_dodbasegun.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +//----------------------------------------------------------------------------- +// Purpose: Draws the zoom screen +//----------------------------------------------------------------------------- +class CHudScope : public vgui::Panel, public CHudElement +{ + DECLARE_CLASS_SIMPLE( CHudScope, vgui::Panel ); + +public: + CHudScope( const char *pElementName ); + + void Init( void ); + +protected: + virtual void ApplySchemeSettings(vgui::IScheme *scheme); + virtual void Paint( void ); + +private: + int m_iScopeSpringfield[4]; + int m_iScopeK98[4]; +}; + +DECLARE_HUDELEMENT_DEPTH( CHudScope, 100 ); + +using namespace vgui; + +//----------------------------------------------------------------------------- +// Purpose: Constructor +//----------------------------------------------------------------------------- +CHudScope::CHudScope( const char *pElementName ) : CHudElement(pElementName), BaseClass(NULL, "HudScope") +{ + vgui::Panel *pParent = g_pClientMode->GetViewport(); + SetParent( pParent ); + + SetHiddenBits( HIDEHUD_PLAYERDEAD ); +} + +//----------------------------------------------------------------------------- +// Purpose: standard hud element init function +//----------------------------------------------------------------------------- +void CHudScope::Init( void ) +{ + int i; + for( i=0;i<4;i++ ) + { + m_iScopeSpringfield[i] = vgui::surface()->CreateNewTextureID(); + m_iScopeK98[i] = vgui::surface()->CreateNewTextureID(); + } + + vgui::surface()->DrawSetTextureFile(m_iScopeSpringfield[0], "sprites/scopes/scope_spring_ul", true, false); + vgui::surface()->DrawSetTextureFile(m_iScopeSpringfield[1], "sprites/scopes/scope_spring_ur", true, false); + vgui::surface()->DrawSetTextureFile(m_iScopeSpringfield[2], "sprites/scopes/scope_spring_lr", true, false); + vgui::surface()->DrawSetTextureFile(m_iScopeSpringfield[3], "sprites/scopes/scope_spring_ll", true, false); + + vgui::surface()->DrawSetTextureFile(m_iScopeK98[0], "sprites/scopes/scope_k43_ul", true, false); + vgui::surface()->DrawSetTextureFile(m_iScopeK98[1], "sprites/scopes/scope_k43_ur", true, false); + vgui::surface()->DrawSetTextureFile(m_iScopeK98[2], "sprites/scopes/scope_k43_lr", true, false); + vgui::surface()->DrawSetTextureFile(m_iScopeK98[3], "sprites/scopes/scope_k43_ll", true, false); +} + +//----------------------------------------------------------------------------- +// Purpose: sets scheme colors +//----------------------------------------------------------------------------- +void CHudScope::ApplySchemeSettings( vgui::IScheme *scheme ) +{ + BaseClass::ApplySchemeSettings(scheme); + + SetPaintBackgroundEnabled(false); + SetPaintBorderEnabled(false); + + int screenWide, screenTall; + GetHudSize(screenWide, screenTall); + SetBounds(0, 0, screenWide, screenTall); +} + +//----------------------------------------------------------------------------- +// Purpose: draws the zoom effect +//----------------------------------------------------------------------------- +void CHudScope::Paint( void ) +{ + C_DODPlayer *pPlayer = C_DODPlayer::GetLocalDODPlayer(); + + if ( pPlayer == NULL ) + return; + + if( pPlayer->GetFOV() >= 90.0f ) + return; + + CWeaponDODBase *pWeapon = pPlayer->GetActiveDODWeapon(); + + if( !pWeapon ) + return; + + Assert( m_iScopeSpringfield ); + Assert( m_iScopeK98 ); + + int *piScopeTex = NULL; + + switch( pWeapon->GetWeaponID() ) + { + case WEAPON_SPRING: + piScopeTex = m_iScopeSpringfield; + break; + case WEAPON_K98_SCOPED: + piScopeTex = m_iScopeK98; + break; + default: + return; + } + + if( !piScopeTex ) + return; + + // see if we're zoomed with a sniper rifle + if( pPlayer->GetFOV() < 90 && + pWeapon->GetDODWpnData().m_WeaponType == WPN_TYPE_SNIPER ) + { + int screenWide, screenTall; + GetHudSize(screenWide, screenTall); + + // calculate the bounds in which we should draw the scope + int xMid = screenWide / 2; + int yMid = screenTall / 2; + + // width of the drawn scope. in widescreen, we draw the sides with primitives + int wide = ( screenTall / 3 ) * 4; + + int xLeft = xMid - wide/2; + int xRight = xMid + wide/2; + int yTop = 0; + int yBottom = screenTall; + + float uv1 = 0.5f / 256.0f, 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 ); + + vgui::surface()->DrawSetColor(0,0,0,255); + + //Draw the outline + + //upper left + vgui::surface()->DrawSetTexture(piScopeTex[0]); + vert[0].Init( Vector2D( xLeft, yTop ), uv11 ); + vert[1].Init( Vector2D( xMid, yTop ), uv21 ); + vert[2].Init( Vector2D( xMid, yMid ), uv22 ); + vert[3].Init( Vector2D( xLeft, yMid ), uv12 ); + vgui::surface()->DrawTexturedPolygon(4, vert); + + // top right + vgui::surface()->DrawSetTexture(piScopeTex[1]); + vert[0].Init( Vector2D( xMid - 1, yTop ), uv11 ); + vert[1].Init( Vector2D( xRight, yTop ), uv21 ); + vert[2].Init( Vector2D( xRight, yMid + 1 ), uv22 ); + vert[3].Init( Vector2D( xMid - 1, yMid + 1 ), uv12 ); + vgui::surface()->DrawTexturedPolygon(4, vert); + + // bottom right + vgui::surface()->DrawSetTexture(piScopeTex[2]); + vert[0].Init( Vector2D( xMid, yMid ), uv11 ); + vert[1].Init( Vector2D( xRight, yMid ), uv21 ); + vert[2].Init( Vector2D( xRight, yBottom ), uv22 ); + vert[3].Init( Vector2D( xMid, yBottom ), uv12 ); + vgui::surface()->DrawTexturedPolygon( 4, vert ); + + // bottom left + vgui::surface()->DrawSetTexture(piScopeTex[3]); + vert[0].Init( Vector2D( xLeft, yMid ), uv11 ); + vert[1].Init( Vector2D( xMid, yMid ), uv21 ); + vert[2].Init( Vector2D( xMid, yBottom ), uv22 ); + vert[3].Init( Vector2D( xLeft, yBottom), uv12 ); + vgui::surface()->DrawTexturedPolygon(4, vert); + + if ( wide < screenWide ) + { + // Left block + vgui::surface()->DrawFilledRect( 0, 0, xLeft, screenTall ); + + // Right block + vgui::surface()->DrawFilledRect( xRight, 0, screenWide, screenTall ); + } + + if ( pWeapon->GetWeaponID() == WEAPON_SPRING ) + { + //Draw the reticle with primitives + vgui::surface()->DrawLine( 0, yMid, screenWide, yMid ); + vgui::surface()->DrawLine( xMid, 0, xMid, screenTall ); + } + } +}
\ No newline at end of file diff --git a/game/client/dod/dod_hud_spec_crosshair.cpp b/game/client/dod/dod_hud_spec_crosshair.cpp new file mode 100644 index 0000000..d3b4d6e --- /dev/null +++ b/game/client/dod/dod_hud_spec_crosshair.cpp @@ -0,0 +1,87 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#include "cbase.h" +#include "hud.h" +#include "dod_hud_spec_crosshair.h" +#include "iclientmode.h" +#include "view.h" +#include "vgui_controls/Controls.h" +#include "vgui/ISurface.h" +#include "ivrenderview.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +//ConVar crosshair( "crosshair", "1", FCVAR_ARCHIVE ); +//ConVar cl_observercrosshair( "cl_observercrosshair", "1", FCVAR_ARCHIVE ); + +using namespace vgui; + +int ScreenTransform( const Vector& point, Vector& screen ); + +DECLARE_HUDELEMENT( CHudSpecCrosshair ); + +CHudSpecCrosshair::CHudSpecCrosshair( const char *pElementName ) : + CHudElement( pElementName ), BaseClass( NULL, "HudSpecCrosshair" ) +{ + vgui::Panel *pParent = g_pClientMode->GetViewport(); + SetParent( pParent ); + + m_pCrosshair = 0; + + m_clrCrosshair = Color( 255, 255, 255, 255 ); + + SetHiddenBits( HIDEHUD_CROSSHAIR ); +} + +void CHudSpecCrosshair::ApplySchemeSettings( IScheme *scheme ) +{ + BaseClass::ApplySchemeSettings( scheme ); + + m_pCrosshair = gHUD.GetIcon("crosshair_default"); + + SetPaintBackgroundEnabled( false ); +} + +void CHudSpecCrosshair::Paint( void ) +{ + if ( !g_pClientMode->ShouldDrawCrosshair() ) + return; + + if ( !m_pCrosshair ) + return; + + if ( engine->IsDrawingLoadingImage() || engine->IsPaused() ) + return; + + C_BasePlayer* pPlayer = C_BasePlayer::GetLocalPlayer(); + + if ( !pPlayer ) + return; + + // draw a crosshair only if alive or spectating in eye + bool shouldDraw = false; + + if ( pPlayer->GetObserverMode() == OBS_MODE_ROAMING /*&& cl_observercrosshair.GetBool()*/ ) + shouldDraw = true; + + if ( !shouldDraw ) + return; + + if ( pPlayer->entindex() != render->GetViewEntity() ) + return; + + float x, y; + x = ScreenWidth()/2; + y = ScreenHeight()/2; + + m_pCrosshair->DrawSelf( + x - 0.5f * m_pCrosshair->Width(), + y - 0.5f * m_pCrosshair->Height(), + m_clrCrosshair ); +}
\ No newline at end of file diff --git a/game/client/dod/dod_hud_spec_crosshair.h b/game/client/dod/dod_hud_spec_crosshair.h new file mode 100644 index 0000000..183bfd3 --- /dev/null +++ b/game/client/dod/dod_hud_spec_crosshair.h @@ -0,0 +1,49 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef HUD_SPEC_CROSSHAIR_H +#define HUD_SPEC_CROSSHAIR_H +#ifdef _WIN32 +#pragma once +#endif + +#include "hudelement.h" +#include <vgui_controls/Panel.h> + +namespace vgui +{ + class IScheme; +}; + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class CHudSpecCrosshair : public CHudElement, public vgui::Panel +{ + DECLARE_CLASS_SIMPLE( CHudSpecCrosshair, vgui::Panel ); +public: + CHudSpecCrosshair( const char *pElementName ); + + void DrawCrosshair( void ); + bool HasCrosshair( void ) { return ( m_pCrosshair != NULL ); } + +protected: + virtual void ApplySchemeSettings( vgui::IScheme *scheme ); + virtual void Paint(); + +private: + // Crosshair sprite and colors + CHudTexture *m_pCrosshair; + Color m_clrCrosshair; +}; + + +// Enable/disable crosshair rendering. +extern ConVar crosshair; + + +#endif // HUD_SPEC_CROSSHAIR_H diff --git a/game/client/dod/dod_hud_target_id.cpp b/game/client/dod/dod_hud_target_id.cpp new file mode 100644 index 0000000..98d13a9 --- /dev/null +++ b/game/client/dod/dod_hud_target_id.cpp @@ -0,0 +1,193 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: HUD Target ID element +// +// $NoKeywords: $ +//============================================================================= +#include "cbase.h" +#include "hud.h" +#include "hudelement.h" +#include "c_dod_player.h" +#include "c_playerresource.h" +#include "vgui_entitypanel.h" +#include "iclientmode.h" +#include "vgui/ILocalize.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +#define PLAYER_HINT_DISTANCE 150 +#define PLAYER_HINT_DISTANCE_SQ (PLAYER_HINT_DISTANCE*PLAYER_HINT_DISTANCE) + +static ConVar hud_centerid( "hud_centerid", "1", FCVAR_ARCHIVE ); + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class CTargetID : public CHudElement, public vgui::Panel +{ + DECLARE_CLASS_SIMPLE( CTargetID, vgui::Panel ); + +public: + CTargetID( const char *pElementName ); + void Init( void ); + virtual void ApplySchemeSettings( vgui::IScheme *scheme ); + virtual void Paint( void ); + void VidInit( void ); + +private: + vgui::HFont m_hFont; + int m_iLastEntIndex; + float m_flLastChangeTime; +}; + +DECLARE_HUDELEMENT( CTargetID ); + +using namespace vgui; + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +CTargetID::CTargetID( const char *pElementName ) : + CHudElement( pElementName ), BaseClass( NULL, "TargetID" ) +{ + vgui::Panel *pParent = g_pClientMode->GetViewport(); + SetParent( pParent ); + + m_hFont = g_hFontTrebuchet24; + m_flLastChangeTime = 0; + m_iLastEntIndex = 0; + + SetHiddenBits( HIDEHUD_MISCSTATUS ); + + RegisterForRenderGroup( "winpanel" ); +} + +//----------------------------------------------------------------------------- +// Purpose: Setup +//----------------------------------------------------------------------------- +void CTargetID::Init( void ) +{ +}; + +void CTargetID::ApplySchemeSettings( vgui::IScheme *scheme ) +{ + BaseClass::ApplySchemeSettings( scheme ); + + m_hFont = scheme->GetFont( "TargetID", IsProportional() ); + + SetPaintBackgroundEnabled( false ); +} + +//----------------------------------------------------------------------------- +// Purpose: clear out string etc between levels +//----------------------------------------------------------------------------- +void CTargetID::VidInit() +{ + CHudElement::VidInit(); + + m_flLastChangeTime = 0; + m_iLastEntIndex = 0; +} + +//----------------------------------------------------------------------------- +// Purpose: Draw function for the element +//----------------------------------------------------------------------------- +void CTargetID::Paint() +{ +#define MAX_ID_STRING 256 + wchar_t sIDString[ MAX_ID_STRING ]; + sIDString[0] = 0; + + C_DODPlayer *pPlayer = C_DODPlayer::GetLocalDODPlayer(); + + if ( !pPlayer ) + return; + + // Get our target's ent index + int iEntIndex = pPlayer->GetIDTarget(); + // Didn't find one? + if ( !iEntIndex ) + { + // Check to see if we should clear our ID + if ( m_flLastChangeTime && (gpGlobals->curtime > (m_flLastChangeTime + 0.5)) ) + { + m_flLastChangeTime = 0; + sIDString[0] = 0; + m_iLastEntIndex = 0; + } + else + { + // Keep re-using the old one + iEntIndex = m_iLastEntIndex; + } + } + else + { + m_flLastChangeTime = gpGlobals->curtime; + } + + // Is this an entindex sent by the server? + if ( iEntIndex ) + { + C_BasePlayer *pPlayer = static_cast<C_BasePlayer*>(cl_entitylist->GetEnt( iEntIndex )); + C_BasePlayer *pLocalPlayer = C_BasePlayer::GetLocalPlayer(); + C_DODPlayer *pLocalDODPlayer = C_DODPlayer::GetLocalDODPlayer(); + + wchar_t wszPlayerName[ MAX_PLAYER_NAME_LENGTH ]; + wchar_t wszHealthText[ 10 ]; + + // Some entities we always want to check, cause the text may change + // even while we're looking at it + if ( IsPlayerIndex( iEntIndex ) && pPlayer->InSameTeam(pLocalPlayer) ) + { + // Construct the wide char name string + g_pVGuiLocalize->ConvertANSIToUnicode( pPlayer->GetPlayerName(), wszPlayerName, sizeof(wszPlayerName) ); + + _snwprintf( wszHealthText, ARRAYSIZE(wszHealthText) - 1, L"%.0f", (float)pPlayer->GetHealth() ); + wszHealthText[ ARRAYSIZE(wszHealthText)-1 ] = '\0'; + + // Construct the string to display + g_pVGuiLocalize->ConstructString( sIDString, sizeof(sIDString), L"%s1 (%s2)", 2, wszPlayerName, wszHealthText ); + + if ( sIDString[0] ) + { + int wide, tall; + int ypos = YRES(260); + int xpos = XRES(10); + + vgui::surface()->GetTextSize( m_hFont, sIDString, wide, tall ); + + if( hud_centerid.GetInt() == 0 ) + { + ypos = YRES(420); + } + else + { + xpos = (ScreenWidth() - wide) / 2; + } + + vgui::surface()->DrawSetTextFont( m_hFont ); + + // draw a black dropshadow ( the default one looks horrible ) + vgui::surface()->DrawSetTextPos( xpos+1, ypos+1 ); + vgui::surface()->DrawSetTextColor( Color(0,0,0,255) ); + vgui::surface()->DrawPrintText( sIDString, wcslen(sIDString) ); + + vgui::surface()->DrawSetTextPos( xpos, ypos ); + vgui::surface()->DrawSetTextColor( g_PR->GetTeamColor( pPlayer->GetTeamNumber() ) ); + vgui::surface()->DrawPrintText( sIDString, wcslen(sIDString) ); + } + + pLocalDODPlayer->HintMessage( HINT_FRIEND_SEEN ); + } + else if( IsPlayerIndex( iEntIndex ) && + pPlayer->GetTeamNumber() != TEAM_SPECTATOR && + pPlayer->GetTeamNumber() != TEAM_UNASSIGNED && + pPlayer->IsAlive() ) + { + // must not be in the same team, enemy + pLocalDODPlayer->HintMessage( HINT_ENEMY_SEEN ); + } + } +} diff --git a/game/client/dod/dod_hud_tnt_pickup.cpp b/game/client/dod/dod_hud_tnt_pickup.cpp new file mode 100644 index 0000000..6e72811 --- /dev/null +++ b/game/client/dod/dod_hud_tnt_pickup.cpp @@ -0,0 +1,152 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#include "cbase.h" +#include "hudelement.h" +#include <vgui_controls/Panel.h> +#include <vgui_controls/EditablePanel.h> +#include <vgui_controls/ImagePanel.h> +#include <vgui/ISurface.h> +#include "c_dod_player.h" +#include "clientmode_dod.h" +#include "dod_hud_tnt_pickup.h" +#include <vgui/ILocalize.h> + +DECLARE_HUDELEMENT( CDODHudTNTPickupPanel ); + +ConVar hud_c4pickuppanel( "hud_c4pickuppanel", "1", FCVAR_CLIENTDLL | FCVAR_ARCHIVE, "Set to 0 to not draw the HUD c4 pickup panel" ); + +//----------------------------------------------------------------------------- +// Purpose: Constructor +//----------------------------------------------------------------------------- +CDODHudTNTPickupPanel::CDODHudTNTPickupPanel( const char *pElementName ) : CHudElement( pElementName ), BaseClass( NULL, "HudTNTPickupPanel" ) +{ + SetParent( g_pClientMode->GetViewport() ); + + m_pBackground = new vgui::Panel( this, "CapturePanelBackground" ); + m_pTNTImage = new CIconPanel( this, "TNTImage" ); + + m_pPickupLabel = new vgui::Label( this, "pickupLabel", "..." ); + + // load control settings... + LoadControlSettings( "resource/UI/HudTNTPickupPanel.res" ); + + SetVisible( false ); + m_flShowUntilTime = 0; + + m_bInitLayout = true; + + RegisterForRenderGroup( "winpanel" ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CDODHudTNTPickupPanel::Init() +{ + // listen for client side events + ListenForGameEvent( "dod_tnt_pickup" ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CDODHudTNTPickupPanel::VidInit() +{ + // listen for client side events + m_flShowUntilTime = 0; + + m_bInitLayout = true; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CDODHudTNTPickupPanel::OnScreenSizeChanged( int iOldWide, int iOldTall ) +{ + LoadControlSettings( "resource/UI/HudTNTPickupPanel.res" ); + + m_bInitLayout = true; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CDODHudTNTPickupPanel::ApplySchemeSettings( vgui::IScheme *pScheme ) +{ + BaseClass::ApplySchemeSettings( pScheme ); + + LoadControlSettings( "resource/UI/HudTNTPickupPanel.res" ); + m_bInitLayout = true; + + if ( m_pBackground ) + { + m_pBackground->SetBgColor( GetSchemeColor( "HintMessageBg", pScheme ) ); + m_pBackground->SetPaintBackgroundType( 2 ); + } +} + +void CDODHudTNTPickupPanel::FireGameEvent( IGameEvent *event ) +{ + const char *pszEventName = event->GetName(); + + C_DODPlayer *pPlayer = C_DODPlayer::GetLocalDODPlayer(); + + if ( !Q_strcmp( pszEventName, "dod_tnt_pickup" ) && pPlayer && pPlayer->ShouldShowHints() ) + { + if ( hud_c4pickuppanel.GetBool() ) + { + // fire the show animation + SetVisible( true ); + m_flShowUntilTime = gpGlobals->curtime + 3.5; + + m_pTNTImage->SetVisible( true ); + } + } +} + +void CDODHudTNTPickupPanel::OnThink( void ) +{ + BaseClass::OnThink(); + + // if only vgui had relative layouts for elements.. + if ( m_bInitLayout ) + { + // localize text if we need + m_pPickupLabel->SetText( g_pVGuiLocalize->Find( "dod_tnt_pickup_help" ) ); + + // size label to contents + m_pPickupLabel->SizeToContents(); + + int labelX, labelY, labelW, labelH; + m_pPickupLabel->GetBounds( labelX, labelY, labelW, labelH ); + + int imageX, imageY, imageH, imageW; + m_pTNTImage->GetBounds( imageX, imageY, imageH, imageW ); + + // total width is: + // margin + image width + margin + text + margin + int newWidth = 3 * XRES(10) + imageW + labelW; + + int bgX, bgY, bgW, bgH; + m_pBackground->GetBounds( bgX, bgY, bgW, bgH ); + + int newX = XRES(320) - newWidth/2; + + m_pBackground->SetBounds( newX, bgY, newWidth, bgH ); + + m_pTNTImage->SetPos( newX + XRES(10), imageY ); + + m_pPickupLabel->SetPos( newX + 2 * XRES(10) + imageW, bgY + ( bgH - labelY) / 2 ); + + m_bInitLayout = false; + } + + if ( IsVisible() && gpGlobals->curtime > m_flShowUntilTime ) + { + SetVisible( false ); + } +}
\ No newline at end of file diff --git a/game/client/dod/dod_hud_tnt_pickup.h b/game/client/dod/dod_hud_tnt_pickup.h new file mode 100644 index 0000000..d8211a2 --- /dev/null +++ b/game/client/dod/dod_hud_tnt_pickup.h @@ -0,0 +1,45 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef DOD_HUD_TNT_PICKUP_H +#define DOD_HUD_TNT_PICKUP_H +#ifdef _WIN32 +#pragma once +#endif + +#include <vgui_controls/EditablePanel.h> +#include "IconPanel.h" + +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- +class CDODHudTNTPickupPanel : public CHudElement, public vgui::EditablePanel +{ +public: + DECLARE_CLASS_SIMPLE( CDODHudTNTPickupPanel, vgui::EditablePanel ); + + CDODHudTNTPickupPanel( const char *pElementName ); + + virtual void Init(); + virtual void VidInit(); + virtual void ApplySchemeSettings( vgui::IScheme *pScheme ); + virtual void OnScreenSizeChanged( int iOldWide, int iOldTall ); + virtual void FireGameEvent( IGameEvent *event ); + virtual void OnThink( void ); + +private: + bool m_bInitLayout; + + CIconPanel *m_pTNTImage; + vgui::Panel *m_pBackground; + + vgui::Label *m_pPickupLabel; + + float m_flShowUntilTime; +}; + +#endif // DOD_HUD_TNT_PICKUP_H
\ No newline at end of file diff --git a/game/client/dod/dod_hud_warmuplabel.cpp b/game/client/dod/dod_hud_warmuplabel.cpp new file mode 100644 index 0000000..26d307b --- /dev/null +++ b/game/client/dod/dod_hud_warmuplabel.cpp @@ -0,0 +1,149 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#include "cbase.h" +#include "hud.h" +#include "hudelement.h" +#include "hud_macros.h" +#include "iclientmode.h" +#include "vgui_controls/AnimationController.h" +#include "vgui_controls/Label.h" +#include "vgui/ILocalize.h" +#include "vgui/ISurface.h" +#include "text_message.h" +#include "dod_gamerules.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +//----------------------------------------------------------------------------- +// Purpose: Displays current ammunition level +//----------------------------------------------------------------------------- +class CDODHudWarmupLabel : public vgui::Panel, public CHudElement +{ + DECLARE_CLASS_SIMPLE( CDODHudWarmupLabel, vgui::Panel ); + +public: + CDODHudWarmupLabel( const char *pElementName ); + virtual void Reset(); + + virtual void PerformLayout(); + +protected: + virtual void ApplySchemeSettings( vgui::IScheme *pScheme ); + virtual void OnThink(); + +private: + vgui::HFont m_hFont; + Color m_bgColor; + + vgui::Label *m_pWarmupLabel; // "Warmup Mode" + + vgui::Label *m_pBackground; // black box + + bool m_bInWarmup; + + CPanelAnimationVarAliasType( int, m_iTextX, "text_xpos", "8", "proportional_int" ); + CPanelAnimationVarAliasType( int, m_iTextY, "text_ypos", "8", "proportional_int" ); +}; + +DECLARE_HUDELEMENT( CDODHudWarmupLabel ); + +//----------------------------------------------------------------------------- +// Purpose: Constructor +//----------------------------------------------------------------------------- +CDODHudWarmupLabel::CDODHudWarmupLabel( const char *pElementName ) : BaseClass(NULL, "WarmupLabel"), CHudElement( pElementName ) +{ + vgui::Panel *pParent = g_pClientMode->GetViewport(); + SetParent( pParent ); + SetVisible( false ); + SetAlpha( 0 ); + + m_pBackground = new vgui::Label( this, "Background", "" ); + + m_pWarmupLabel = new vgui::Label( this, "RoundState_warmup", g_pVGuiLocalize->Find( "#Clan_warmup_mode" ) ); + m_pWarmupLabel->SetPaintBackgroundEnabled( false ); + m_pWarmupLabel->SetPaintBorderEnabled( false ); + m_pWarmupLabel->SizeToContents(); + m_pWarmupLabel->SetContentAlignment( vgui::Label::a_west ); + m_pWarmupLabel->SetFgColor( GetFgColor() ); + + m_bInWarmup = false; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CDODHudWarmupLabel::Reset() +{ + g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( "WarmupLabelHide" ); + + m_bInWarmup = false; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CDODHudWarmupLabel::ApplySchemeSettings( vgui::IScheme *pScheme ) +{ + BaseClass::ApplySchemeSettings( pScheme ); + + SetFgColor( Color(0,0,0,0) ); //GetSchemeColor("RoundStateFg", pScheme) ); + m_hFont = pScheme->GetFont( "HudHintText", true ); + + m_pBackground->SetBgColor( GetSchemeColor("HintMessageBg", pScheme) ); + m_pBackground->SetPaintBackgroundType( 2 ); + + SetAlpha( 0 ); +} + +//----------------------------------------------------------------------------- +// Purpose: Resizes the label +//----------------------------------------------------------------------------- +void CDODHudWarmupLabel::PerformLayout() +{ + BaseClass::PerformLayout(); + + int wide, tall; + GetSize( wide, tall ); + + // find the widest line + int labelWide = m_pWarmupLabel->GetWide(); + + // find the total height + int fontTall = vgui::surface()->GetFontTall( m_hFont ); + int labelTall = fontTall; + + labelWide += m_iTextX*2; + labelTall += m_iTextY*2; + + m_pBackground->SetBounds( 0, 0, labelWide, labelTall ); + + int xOffset = (labelWide - m_pWarmupLabel->GetWide())/2; + m_pWarmupLabel->SetPos( 0 + xOffset, 0 + m_iTextY ); +} + +//----------------------------------------------------------------------------- +// Purpose: Updates the label color each frame +//----------------------------------------------------------------------------- +void CDODHudWarmupLabel::OnThink() +{ + m_pBackground->SetFgColor(GetFgColor()); + m_pWarmupLabel->SetFgColor(GetFgColor()); + + bool bInWarmup = DODGameRules()->IsInWarmup(); + + if( bInWarmup != m_bInWarmup ) + { + if( bInWarmup ) + { + g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( "WarmupLabelShow" ); + InvalidateLayout(); + } + + m_bInWarmup = bInWarmup; + } +}
\ No newline at end of file diff --git a/game/client/dod/dod_hud_weaponselection.cpp b/game/client/dod/dod_hud_weaponselection.cpp new file mode 100644 index 0000000..cb3cdd6 --- /dev/null +++ b/game/client/dod/dod_hud_weaponselection.cpp @@ -0,0 +1,796 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#include "cbase.h" +#include "weapon_selection.h" +#include "iclientmode.h" +#include "history_resource.h" + +#include <KeyValues.h> +#include <vgui/IScheme.h> +#include <vgui/ISurface.h> +#include <vgui/ISystem.h> +#include <vgui_controls/AnimationController.h> +#include <vgui_controls/Panel.h> + +#include <string.h> +#include "weapon_dodbase.h" + +float GetScale( int nIconWidth, int nIconHeight, int nWidth, int nHeight ); + +//----------------------------------------------------------------------------- +// Purpose: cstrike weapon selection hud element +//----------------------------------------------------------------------------- +class CHudWeaponSelection : public CBaseHudWeaponSelection, public vgui::Panel +{ + DECLARE_CLASS_SIMPLE( CHudWeaponSelection, vgui::Panel ); + +public: + CHudWeaponSelection( const char *pElementName ); + + virtual void VidInit(); + virtual bool ShouldDraw(); + virtual void OnWeaponPickup( C_BaseCombatWeapon *pWeapon ); + + virtual void CycleToNextWeapon( void ); + virtual void CycleToPrevWeapon( void ); + + virtual C_BaseCombatWeapon *GetWeaponInSlot( int iSlot, int iSlotPos ); + virtual void SelectWeaponSlot( int iSlot ); + + virtual C_BaseCombatWeapon *GetSelectedWeapon( void ) + { + return m_hSelectedWeapon; + } + + virtual void OpenSelection( void ); + virtual void HideSelection( void ); + + virtual void LevelInit(); + + virtual void SelectWeapon( void ); + virtual void CancelWeaponSelection( void ); + + virtual bool IsHudMenuPreventingWeaponSelection() { return false; } + +protected: + virtual void OnThink(); + virtual void Paint(); + virtual void ApplySchemeSettings(vgui::IScheme *pScheme); + + virtual bool IsWeaponSelectable() + { + if ( IsInSelectionMode() ) + { + return true; + } + + return false; + } + +private: + C_BaseCombatWeapon *FindNextWeaponInWeaponSelection(int iCurrentSlot, int iCurrentPosition); + C_BaseCombatWeapon *FindPrevWeaponInWeaponSelection(int iCurrentSlot, int iCurrentPosition); + + virtual void SetSelectedWeapon( C_BaseCombatWeapon *pWeapon ) + { + m_hSelectedWeapon = pWeapon; + } + + void DrawBox( int x, int y, int wide, int tall, int type, int number, int valid ); + +private: + + int m_iBackgroundTexture; + + CPanelAnimationVarAliasType( float, m_flSmallBoxWide, "SmallBoxWide", "108", "proportional_float" ); + CPanelAnimationVarAliasType( float, m_flSmallBoxTall, "SmallBoxTall", "72", "proportional_float" ); + CPanelAnimationVarAliasType( float, m_flSmallBoxCutSize, "SmallBoxCutSize", "5", "proportional_float" ); + + CPanelAnimationVarAliasType( float, m_flLargeBoxWide, "LargeBoxWide", "108", "proportional_float" ); + CPanelAnimationVarAliasType( float, m_flLargeBoxTall, "LargeBoxTall", "72", "proportional_float" ); + CPanelAnimationVarAliasType( float, m_flLargeBoxCutSize, "LargeBoxCutSize", "5", "proportional_float" ); + + CPanelAnimationVarAliasType( float, m_flBoxGap, "BoxGap", "8", "proportional_float" ); + + CPanelAnimationVarAliasType( float, m_flSelectionNumberXPos, "SelectionNumberXPos", "4", "proportional_float" ); + CPanelAnimationVarAliasType( float, m_flSelectionNumberYPos, "SelectionNumberYPos", "4", "proportional_float" ); + + CPanelAnimationVarAliasType( float, m_flIconXPos, "IconXPos", "16", "proportional_float" ); + CPanelAnimationVarAliasType( float, m_flIconYPos, "IconYPos", "8", "proportional_float" ); + + CPanelAnimationVarAliasType( float, m_flTextYPos, "TextYPos", "54", "proportional_float" ); + + CPanelAnimationVar( float, m_flAlphaOverride, "Alpha", "255" ); + CPanelAnimationVar( float, m_flSelectionAlphaOverride, "SelectionAlpha", "255" ); + + CPanelAnimationVar( Color, m_ActiveTextColor, "ActiveTextColor", "255 255 255 255" ); + CPanelAnimationVar( Color, m_InactiveTextColor, "InactiveTextColor", "80 80 80 255" ); + + CPanelAnimationVar( vgui::HFont, m_hNumberFont, "NumberFont", "HudSelectionNumbers" ); + CPanelAnimationVar( vgui::HFont, m_hTextFont, "TextFont", "HudSelectionText" ); + + CPanelAnimationVar( Color, m_TextColor, "TextColor", "SelectionTextFg" ); + CPanelAnimationVar( Color, m_NumberColor, "NumberColor", "SelectionNumberFg" ); + CPanelAnimationVar( Color, m_EmptyBoxColor, "EmptyBoxColor", "SelectionEmptyBoxBg" ); + CPanelAnimationVar( Color, m_BoxColor, "BoxColor", "SelectionBoxBg" ); + CPanelAnimationVar( Color, m_SelectedBoxColor, "SelectedBoxClor", "SelectionSelectedBoxBg" ); + + CPanelAnimationVar( float, m_flWeaponPickupGrowTime, "SelectionGrowTime", "0.1" ); + + CPanelAnimationVar( float, m_flTextScan, "TextScan", "1.0" ); + + CPanelAnimationVar( int, m_iMaxSlots, "MaxSlots", "6" ); + CPanelAnimationVar( bool, m_bPlaySelectionSounds, "PlaySelectSounds", "1" ); + + CPanelAnimationVar( Color, m_ActiveBoxColor, "ActiveBoxColor", "255 255 255 255" ); + CPanelAnimationVar( Color, m_ActiveBoxBorder, "ActiveBoxBorder", "255 255 255 255" ); + CPanelAnimationVar( Color, m_InactiveBoxColor, "InactiveBoxColor", "0 0 0 0" ); + CPanelAnimationVar( Color, m_InactiveBoxBorder, "InactiveBoxBorder", "255 255 255 255" ); + + CPanelAnimationVar( Color, m_NotUseableColor, "NotUseableColor", "0 0 0 0" ); +}; + +DECLARE_HUDELEMENT( CHudWeaponSelection ); + +//----------------------------------------------------------------------------- +// Purpose: Constructor +//----------------------------------------------------------------------------- +CHudWeaponSelection::CHudWeaponSelection( const char *pElementName ) : CBaseHudWeaponSelection(pElementName), BaseClass(NULL, "HudWeaponSelection") +{ + vgui::Panel *pParent = g_pClientMode->GetViewport(); + SetParent( pParent ); + + SetHiddenBits( HIDEHUD_WEAPONSELECTION | HIDEHUD_PLAYERDEAD ); + + m_iBackgroundTexture = vgui::surface()->DrawGetTextureId( "vgui/white" ); + if ( m_iBackgroundTexture == -1 ) + { + m_iBackgroundTexture = vgui::surface()->CreateNewTextureID(); + } + vgui::surface()->DrawSetTextureFile( m_iBackgroundTexture, "vgui/white" , true, true ); +} + +void CHudWeaponSelection::VidInit(void) +{ + // If we've already loaded weapons, let's get new sprites + gWR.LoadAllWeaponSprites(); + + Reset(); +} + +//----------------------------------------------------------------------------- +// Purpose: sets up display for showing weapon pickup +//----------------------------------------------------------------------------- +void CHudWeaponSelection::OnWeaponPickup( C_BaseCombatWeapon *pWeapon ) +{ + // show tnt pickup panel + C_WeaponDODBase *pDODWpn = dynamic_cast<C_WeaponDODBase *>( pWeapon ); + + if ( pDODWpn && pDODWpn->GetDODWpnData().m_WeaponType == WPN_TYPE_BOMB ) + { + IGameEvent *event = gameeventmanager->CreateEvent( "dod_tnt_pickup" ); + if ( event ) + { + gameeventmanager->FireEventClientSide( event ); + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: updates animation status +//----------------------------------------------------------------------------- +void CHudWeaponSelection::OnThink() +{ + +} + +//----------------------------------------------------------------------------- +// Purpose: returns true if the panel should draw +//----------------------------------------------------------------------------- +bool CHudWeaponSelection::ShouldDraw() +{ + C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer(); + if ( !pPlayer ) + { + if ( IsInSelectionMode() ) + { + HideSelection(); + } + return false; + } + + bool bret = CBaseHudWeaponSelection::ShouldDraw(); + if ( !bret ) + { + return false; + } + + return ( m_bSelectionVisible ) ? true : false; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CHudWeaponSelection::LevelInit() +{ + CHudElement::LevelInit(); + + m_iMaxSlots = clamp( m_iMaxSlots, 0, MAX_WEAPON_SLOTS ); +} + +//------------------------------------------------------------------------- +// Purpose: draws the selection area +//------------------------------------------------------------------------- +void CHudWeaponSelection::Paint(void) +{ + C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer(); + if ( !pPlayer ) + { + return; + } + + // find and display our current selection + C_BaseCombatWeapon *pSelectedWeapon = GetSelectedWeapon(); + if ( !pSelectedWeapon ) + { + return; + } + + int x, y, w, h; + GetBounds( x, y, w, h ); + + int xpos = 0; + int ypos = h; + + int nType = 0; + + Color bright( 255,255,255,255 ); + + // iterate over all the weapon slots + for ( int iSlot = m_iMaxSlots - 1; iSlot >=0; iSlot-- ) + { + for( int iPos = 0; iPos < MAX_WEAPON_POSITIONS; iPos++ ) + { + C_BaseCombatWeapon *pWeapon = GetWeaponInSlot(iSlot, iPos); + + if ( !pWeapon ) + { + continue; + } + + if ( !pWeapon->CanBeSelected() ) + { + continue; + } + + if ( pWeapon->GetSpriteActive() ) + { + const CHudTexture *pWpnSprite = pWeapon->GetSpriteActive(); + Color finalColor; + + Assert( pWpnSprite ); + + float finalBoxWide, finalBoxTall; + + if ( pWeapon == pSelectedWeapon ) + { + finalBoxWide = m_flLargeBoxWide; + finalBoxTall = m_flLargeBoxTall; + finalColor = m_ActiveBoxColor; + nType = 1; + } + else + { + finalBoxWide = m_flSmallBoxWide; + finalBoxTall = m_flSmallBoxTall; + finalColor = m_InactiveBoxColor; + nType = 0; + } + + xpos = ( w / 2.0 ) - ( finalBoxWide / 2.0f ); + ypos -= finalBoxTall; + + int sprBoxWidth = finalBoxWide - XRES(4); // minus 4 (2 left, 2 right) + int sprBoxHeight = finalBoxTall - YRES(4); // minus 4 (2 top, 2 bottom) + + int sprWidth = pWpnSprite->Width(); + int sprHeight = pWpnSprite->Height(); + + float scale = GetScale( sprWidth, sprHeight, sprBoxWidth, sprBoxHeight ); + + sprWidth = sprWidth * scale; + sprHeight = sprHeight * scale; + + int wpnX = xpos + ( finalBoxWide - sprWidth ) / 2; + int wpnY = ypos + ( finalBoxTall - sprHeight ) / 2; + + bool bHasAmmo = true; + + if ( pWeapon->UsesClipsForAmmo1() ) + { + C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer(); + + if ( pPlayer ) + { + int ammo = pWeapon->Clip1() + pPlayer->GetAmmoCount( pWeapon->GetPrimaryAmmoType() ); + + if ( ammo <= 0 ) + { + bHasAmmo = false; + } + } + } + + DrawBox( xpos, ypos, finalBoxWide, finalBoxTall, nType, iSlot + 1, ( pWeapon->CanDeploy() && bHasAmmo ) ) ; + pWpnSprite->DrawSelf( wpnX, wpnY, sprWidth, sprHeight, bright ); + + ypos -= m_flBoxGap; + } + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: draws a selection box +//----------------------------------------------------------------------------- +void CHudWeaponSelection::DrawBox( int x, int y, int wide, int tall, int type, int number, int valid ) +{ + vgui::Vertex_t verts[5]; + + int nwide = wide - 1; + int ntall = tall - 1; + + int nCutSize; + + vgui::surface()->DrawSetTexture( m_iBackgroundTexture ); + + if ( type == 1 ) + { + nCutSize = m_flLargeBoxCutSize; + vgui::surface()->DrawSetColor( Color( m_ActiveBoxColor ) ); + } + else + { + nCutSize = m_flSmallBoxCutSize; + vgui::surface()->DrawSetColor( Color( m_InactiveBoxColor ) ); + } + + if ( !valid ) + { + vgui::surface()->DrawSetColor( Color( m_NotUseableColor ) ); + } + + verts[0].Init( Vector2D( x, y ) ); + verts[1].Init( Vector2D( x + nwide - nCutSize, y ) ); + verts[2].Init( Vector2D( x + nwide, y + nCutSize ) ); + verts[3].Init( Vector2D( x + nwide, y + ntall ) ); + verts[4].Init( Vector2D( x, y + ntall ) ); + + vgui::surface()->DrawTexturedPolygon( 5, verts ); + + if ( type == 1 ) + { + vgui::surface()->DrawSetColor( Color( m_ActiveBoxBorder ) ); + } + else + { + vgui::surface()->DrawSetColor( Color( m_InactiveBoxBorder ) ); + } + + vgui::surface()->DrawTexturedPolyLine( verts, 5 ); + + // draw the number + if ( number >= 0 ) + { + vgui::surface()->DrawSetTextFont( m_hNumberFont ); + + if ( type == 1 ) + { + vgui::surface()->DrawSetTextColor( Color( m_ActiveTextColor ) ); + } + else + { + vgui::surface()->DrawSetTextColor( Color( m_InactiveTextColor ) ); + } + + wchar_t wch = '0' + number; + vgui::surface()->DrawSetTextPos( x + m_flSelectionNumberXPos, y + ntall - m_flSelectionNumberYPos ); + vgui::surface()->DrawUnicodeChar( wch ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: hud scheme settings +//----------------------------------------------------------------------------- +void CHudWeaponSelection::ApplySchemeSettings( vgui::IScheme *pScheme ) +{ + BaseClass::ApplySchemeSettings( pScheme ); + SetPaintBackgroundEnabled( false ); +} + +//----------------------------------------------------------------------------- +// Purpose: Opens weapon selection control +//----------------------------------------------------------------------------- +void CHudWeaponSelection::OpenSelection( void ) +{ + Assert( !IsInSelectionMode() ); + + CBaseHudWeaponSelection::OpenSelection(); + g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( "OpenWeaponSelectionMenu" ); +} + +//----------------------------------------------------------------------------- +// Purpose: Closes weapon selection control +//----------------------------------------------------------------------------- +void CHudWeaponSelection::HideSelection( void ) +{ + CBaseHudWeaponSelection::HideSelection(); + g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( "CloseWeaponSelectionMenu" ); +} + +//----------------------------------------------------------------------------- +// Purpose: Returns the next available weapon item in the weapon selection +//----------------------------------------------------------------------------- +C_BaseCombatWeapon *CHudWeaponSelection::FindNextWeaponInWeaponSelection( int iCurrentSlot, int iCurrentPosition ) +{ + C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer(); + if ( !pPlayer ) + { + return NULL; + } + + C_BaseCombatWeapon *pNextWeapon = NULL; + + // search all the weapons looking for the closest next + int iLowestNextSlot = MAX_WEAPON_SLOTS; + int iLowestNextPosition = MAX_WEAPON_POSITIONS; + for ( int i = 0; i < MAX_WEAPONS; i++ ) + { + C_BaseCombatWeapon *pWeapon = pPlayer->GetWeapon( i ); + if ( !pWeapon ) + { + continue; + } + + if ( pWeapon->CanBeSelected() ) + { + int weaponSlot = pWeapon->GetSlot(), weaponPosition = pWeapon->GetPosition(); + + // see if this weapon is further ahead in the selection list + if ( weaponSlot > iCurrentSlot || ( weaponSlot == iCurrentSlot && weaponPosition > iCurrentPosition ) ) + { + // see if this weapon is closer than the current lowest + if ( weaponSlot < iLowestNextSlot || ( weaponSlot == iLowestNextSlot && weaponPosition < iLowestNextPosition ) ) + { + iLowestNextSlot = weaponSlot; + iLowestNextPosition = weaponPosition; + pNextWeapon = pWeapon; + } + } + } + } + + return pNextWeapon; +} + +//----------------------------------------------------------------------------- +// Purpose: Returns the prior available weapon item in the weapon selection +//----------------------------------------------------------------------------- +C_BaseCombatWeapon *CHudWeaponSelection::FindPrevWeaponInWeaponSelection( int iCurrentSlot, int iCurrentPosition ) +{ + C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer(); + if ( !pPlayer ) + { + return NULL; + } + + C_BaseCombatWeapon *pPrevWeapon = NULL; + + // search all the weapons looking for the closest next + int iLowestPrevSlot = -1; + int iLowestPrevPosition = -1; + for ( int i = 0; i < MAX_WEAPONS; i++ ) + { + C_BaseCombatWeapon *pWeapon = pPlayer->GetWeapon( i ); + if ( !pWeapon ) + { + continue; + } + + if ( pWeapon->CanBeSelected() ) + { + int weaponSlot = pWeapon->GetSlot(), weaponPosition = pWeapon->GetPosition(); + + // see if this weapon is further ahead in the selection list + if ( weaponSlot < iCurrentSlot || (weaponSlot == iCurrentSlot && weaponPosition < iCurrentPosition) ) + { + // see if this weapon is closer than the current lowest + if ( weaponSlot > iLowestPrevSlot || (weaponSlot == iLowestPrevSlot && weaponPosition > iLowestPrevPosition) ) + { + iLowestPrevSlot = weaponSlot; + iLowestPrevPosition = weaponPosition; + pPrevWeapon = pWeapon; + } + } + } + } + + return pPrevWeapon; +} + +//----------------------------------------------------------------------------- +// Purpose: Moves the selection to the next item in the menu +//----------------------------------------------------------------------------- +void CHudWeaponSelection::CycleToNextWeapon( void ) +{ + // Get the local player. + C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer(); + if ( !pPlayer ) + { + return; + } + + C_BaseCombatWeapon *pNextWeapon = NULL; + if ( IsInSelectionMode() ) + { + // find the next selection spot + C_BaseCombatWeapon *pWeapon = GetSelectedWeapon(); + if ( !pWeapon ) + { + return; + } + + pNextWeapon = FindNextWeaponInWeaponSelection( pWeapon->GetSlot(), pWeapon->GetPosition() ); + } + else + { + // open selection at the current place + pNextWeapon = pPlayer->GetActiveWeapon(); + if ( pNextWeapon ) + { + pNextWeapon = FindNextWeaponInWeaponSelection( pNextWeapon->GetSlot(), pNextWeapon->GetPosition() ); + } + } + + if ( !pNextWeapon ) + { + // wrap around back to start + pNextWeapon = FindNextWeaponInWeaponSelection( -1, -1 ); + } + + if ( pNextWeapon ) + { + SetSelectedWeapon( pNextWeapon ); + + if ( hud_fastswitch.GetInt() > 0 ) + { + SelectWeapon(); + } + else if ( !IsInSelectionMode() ) + { + OpenSelection(); + } + + // Play the "cycle to next weapon" sound + if ( m_bPlaySelectionSounds ) + { + pPlayer->EmitSound( "Player.WeaponSelectionMoveSlot" ); + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: Moves the selection to the previous item in the menu +//----------------------------------------------------------------------------- +void CHudWeaponSelection::CycleToPrevWeapon( void ) +{ + // Get the local player. + C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer(); + if ( !pPlayer ) + { + return; + } + + C_BaseCombatWeapon *pNextWeapon = NULL; + if ( IsInSelectionMode() ) + { + // find the next selection spot + C_BaseCombatWeapon *pWeapon = GetSelectedWeapon(); + if ( !pWeapon ) + { + return; + } + + pNextWeapon = FindPrevWeaponInWeaponSelection( pWeapon->GetSlot(), pWeapon->GetPosition() ); + } + else + { + // open selection at the current place + pNextWeapon = pPlayer->GetActiveWeapon(); + if ( pNextWeapon ) + { + pNextWeapon = FindPrevWeaponInWeaponSelection( pNextWeapon->GetSlot(), pNextWeapon->GetPosition() ); + } + } + + if ( !pNextWeapon ) + { + // wrap around back to end of weapon list + pNextWeapon = FindPrevWeaponInWeaponSelection( MAX_WEAPON_SLOTS, MAX_WEAPON_POSITIONS ); + } + + if ( pNextWeapon ) + { + SetSelectedWeapon( pNextWeapon ); + + if( hud_fastswitch.GetInt() > 0 ) + { + SelectWeapon(); + } + else if ( !IsInSelectionMode() ) + { + OpenSelection(); + } + + // Play the "cycle to next weapon" sound + if( m_bPlaySelectionSounds ) + { + pPlayer->EmitSound( "Player.WeaponSelectionMoveSlot" ); + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: returns the weapon in the specified slot +//----------------------------------------------------------------------------- +C_BaseCombatWeapon *CHudWeaponSelection::GetWeaponInSlot( int iSlot, int iSlotPos ) +{ + C_BasePlayer *player = C_BasePlayer::GetLocalPlayer(); + if ( !player ) + { + return NULL; + } + + for ( int i = 0; i < MAX_WEAPONS; i++ ) + { + C_BaseCombatWeapon *pWeapon = player->GetWeapon( i ); + + if ( pWeapon == NULL ) + { + continue; + } + + if ( pWeapon->GetSlot() == iSlot && pWeapon->GetPosition() == iSlotPos ) + { + return pWeapon; + } + } + + return NULL; +} + + +//----------------------------------------------------------------------------- +// Purpose: Moves selection to the specified slot +//----------------------------------------------------------------------------- +void CHudWeaponSelection::SelectWeaponSlot( int iSlot ) +{ + // iSlot is one higher than it should be, since it's the number key, not the 0-based index into the weapons + --iSlot; + + // Get the local player. + C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer(); + if ( !pPlayer ) + { + return; + } + + // Don't try and read past our possible number of slots + if ( iSlot > MAX_WEAPON_SLOTS ) + { + return; + } + + // Make sure the player's allowed to switch weapons + if ( pPlayer->IsAllowedToSwitchWeapons() == false ) + { + return; + } + + int slotPos = 0; + C_BaseCombatWeapon *pActiveWeapon = GetSelectedWeapon(); + + // start later in the list + if ( IsInSelectionMode() && pActiveWeapon && pActiveWeapon->GetSlot() == iSlot ) + { + slotPos = pActiveWeapon->GetPosition() + 1; + } + + // find the weapon in this slot + pActiveWeapon = GetNextActivePos( iSlot, slotPos ); + if ( !pActiveWeapon ) + { + pActiveWeapon = GetNextActivePos( iSlot, 0 ); + } + + if ( pActiveWeapon != NULL ) + { + // Mark the change + SetSelectedWeapon( pActiveWeapon ); + + if( hud_fastswitch.GetInt() > 0 ) + { + SelectWeapon(); + } + else if ( !IsInSelectionMode() ) + { + // open the weapon selection + OpenSelection(); + } + } + + if ( m_bPlaySelectionSounds ) + { + pPlayer->EmitSound( "Player.WeaponSelectionMoveSlot" ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: Player has chosen to draw the currently selected weapon +//----------------------------------------------------------------------------- +void CHudWeaponSelection::SelectWeapon( void ) +{ + if ( !GetSelectedWeapon() ) + { + engine->ClientCmd( "cancelselect\n" ); + return; + } + + C_BasePlayer *player = C_BasePlayer::GetLocalPlayer(); + if ( !player ) + { + return; + } + + // Don't allow selections of weapons that can't be selected (out of ammo, etc) + if ( GetSelectedWeapon()->CanBeSelected() ) + { + SetWeaponSelected(); + + m_hSelectedWeapon = NULL; + + engine->ClientCmd( "cancelselect\n" ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: Abort selecting a weapon +//----------------------------------------------------------------------------- +void CHudWeaponSelection::CancelWeaponSelection( void ) +{ + C_BasePlayer *player = C_BasePlayer::GetLocalPlayer(); + if ( !player ) + { + return; + } + + // Fastswitches happen in a single frame, so the Weapon Selection HUD Element isn't visible + // yet, but it's going to be next frame. We need to ask it if it thinks it's going to draw, + // instead of checking it's IsActive flag. + if ( ShouldDraw() ) + { + HideSelection(); + + m_hSelectedWeapon = NULL; + } + else + { + engine->ClientCmd("escape"); + } +} + + diff --git a/game/client/dod/dod_hud_winpanel.cpp b/game/client/dod/dod_hud_winpanel.cpp new file mode 100644 index 0000000..43dd74f --- /dev/null +++ b/game/client/dod/dod_hud_winpanel.cpp @@ -0,0 +1,526 @@ + +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#include "cbase.h" +#include "dod_hud_winpanel.h" +#include "vgui_controls/AnimationController.h" +#include "iclientmode.h" +#include "c_dod_playerresource.h" +#include <vgui_controls/Label.h> +#include <vgui/ILocalize.h> +#include <vgui/ISurface.h> +#include "vgui_avatarimage.h" +#include "fmtstr.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +DECLARE_HUDELEMENT_DEPTH( CDODWinPanel_Allies, 1 ); // 1 is foreground +DECLARE_HUDELEMENT_DEPTH( CDODWinPanel_Axis, 1 ); + +CDODWinPanel_Allies::CDODWinPanel_Allies( const char *pElementName ) : CDODWinPanel( "WinPanel_Allies", TEAM_ALLIES ) +{ + LoadControlSettings("Resource/UI/Win_Allies.res"); +} + +void CDODWinPanel_Allies::OnScreenSizeChanged( int iOldWide, int iOldTall ) +{ + LoadControlSettings( "resource/UI/Win_Allies.res" ); +} + +void CDODWinPanel_Allies::ApplySchemeSettings( vgui::IScheme *pScheme ) +{ + m_pIcon = gHUD.GetIcon( "icon_obj_allies" ); + + LoadControlSettings( "resource/UI/Win_Allies.res" ); + + BaseClass::ApplySchemeSettings( pScheme ); +} + +//============================ + +CDODWinPanel_Axis::CDODWinPanel_Axis( const char *pElementName ) : CDODWinPanel( "WinPanel_Axis", TEAM_AXIS ) +{ + LoadControlSettings("Resource/UI/Win_Axis.res"); +} + +void CDODWinPanel_Axis::OnScreenSizeChanged( int iOldWide, int iOldTall ) +{ + LoadControlSettings( "resource/UI/Win_Axis.res" ); +} + +void CDODWinPanel_Axis::ApplySchemeSettings( vgui::IScheme *pScheme ) +{ + m_pIcon = gHUD.GetIcon( "icon_obj_axis" ); + + LoadControlSettings( "resource/UI/Win_Axis.res" ); + + BaseClass::ApplySchemeSettings( pScheme ); +} + +//============================ + +//----------------------------------------------------------------------------- +// Purpose: Constructor +//----------------------------------------------------------------------------- +CDODWinPanel::CDODWinPanel( const char *pElementName, int iTeam ) + : EditablePanel( NULL, pElementName ), CHudElement( pElementName ) +{ + vgui::Panel *pParent = g_pClientMode->GetViewport(); + SetParent( pParent ); + SetVisible( false ); + SetAlpha( 0 ); + SetScheme( "ClientScheme" ); + + m_iTeam = iTeam; + + m_pTimerStatusLabel = new vgui::Label( this, "TimerInfo", "" ); + + m_pLastCapperHeader = new vgui::Label( this, "LastCapperHeader", "" ); + m_pLastBomberHeader = new vgui::Label( this, "LastBomberHeader", "" ); + + m_pLastCapperLabel = new vgui::Label( this, "LastCapper", "" ); + m_pLastCapperLabel_Avatar = new vgui::Label( this, "LastCapper_Avatar", "" ); + + m_pLeftCategoryHeader = new vgui::Label( this, "LeftCategoryHeader", "..." ); + m_pRightCategoryHeader = new vgui::Label( this, "RightCategoryHeader", "..." ); + + m_pLeftCategoryLabels[0] = new vgui::Label( this, "LeftCategory1", "" ); + m_pLeftCategoryLabels[1] = new vgui::Label( this, "LeftCategory2", "" ); + m_pLeftCategoryLabels[2] = new vgui::Label( this, "LeftCategory3", "" ); + + m_pRightCategoryLabels[0] = new vgui::Label( this, "RightCategory1", "" ); + m_pRightCategoryLabels[1] = new vgui::Label( this, "RightCategory2", "" ); + m_pRightCategoryLabels[2] = new vgui::Label( this, "RightCategory3", "" ); + + RegisterForRenderGroup( "winpanel" ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CDODWinPanel::Reset() +{ + Hide(); +} + +void CDODWinPanel::Init() +{ + // listen for events + ListenForGameEvent( "dod_round_win" ); + ListenForGameEvent( "dod_round_start" ); + ListenForGameEvent( "dod_point_captured" ); + ListenForGameEvent( "dod_win_panel" ); + + Hide(); + + SetFinalCaptureLabel( "", false ); + + m_pTimerStatusLabel->SetText( "" ); + + m_bShowTimerDefend = false; + m_bShowTimerAttack = false; + m_iTimerTime = 0; + + m_iFinalEventType = CAP_EVENT_NONE; + + m_iLeftCategory = WINPANEL_TOP3_NONE; + m_iRightCategory = WINPANEL_TOP3_NONE; + + for ( int i=0;i<3;i++ ) + { + m_iLeftCategoryScores[i] = 0; + m_iRightCategoryScores[i] = 0; + } + + CHudElement::Init(); +} + +void CDODWinPanel::VidInit() +{ + m_pIconCap = gHUD.GetIcon( "stats_cap" ); + m_pIconDefended = gHUD.GetIcon( "stats_defended" ); + m_pIconBomb = gHUD.GetIcon( "icon_c4" ); + m_pIconKill = gHUD.GetIcon( "stats_kill" ); +} + +void SetPlayerNameLabel( vgui::Label *pLabel, int clientIndex ) +{ + if ( !pLabel ) + return; + + if ( clientIndex >= 1 && clientIndex <= MAX_PLAYERS ) + { + char buf[48]; + Q_snprintf( buf, sizeof(buf), "%s:", g_PR->GetPlayerName(clientIndex) ); + pLabel->SetText( buf ); + } + + pLabel->SetVisible( clientIndex > 0 ); +} + +void CDODWinPanel::FireGameEvent( IGameEvent * event ) +{ + const char *pEventName = event->GetName(); + + if ( Q_strcmp( "dod_round_win", pEventName ) == 0 ) + { + if ( event->GetInt( "team" ) == m_iTeam ) + { + Show(); + } + } + else if ( Q_strcmp( "dod_round_start", pEventName ) == 0 ) + { + Hide(); + + m_pLastCapperHeader->SetVisible( false ); + m_pLastBomberHeader->SetVisible( false ); + } + else if ( Q_strcmp( "dod_point_captured", pEventName ) == 0 ) + { + if ( !g_PR ) + return; + + // Array of capper indeces + const char *cappers = event->GetString("cappers"); + + char szCappers[256]; + szCappers[0] = '\0'; + + int len = Q_strlen(cappers); + + bool bShowAvatar = ( len == 1 ); + + if ( !bShowAvatar ) + { + SetupAvatar( "top", 1, 0 ); // hide it + } + + for( int i=0;i<len;i++ ) + { + int iPlayerIndex = (int)cappers[i]; + + Assert( iPlayerIndex > 0 && iPlayerIndex <= gpGlobals->maxClients ); + + const char *pPlayerName = g_PR->GetPlayerName( iPlayerIndex ); + + if ( bShowAvatar ) + { + SetupAvatar( "top", 1, iPlayerIndex ); + } + + if ( i > 0 ) + { + Q_strncat( szCappers, ", ", sizeof(szCappers), 2 ); + } + + Q_strncat( szCappers, pPlayerName, sizeof(szCappers), COPY_ALL_CHARACTERS ); + } + + if ( event->GetBool( "bomb" ) ) + { + m_pLastCapperHeader->SetVisible( false ); + m_pLastBomberHeader->SetVisible( true ); + } + else + { + m_pLastCapperHeader->SetVisible( true ); + m_pLastBomberHeader->SetVisible( false ); + } + + SetFinalCaptureLabel( szCappers, bShowAvatar ); + } + else if ( Q_strcmp( "dod_win_panel", pEventName ) == 0 ) + { + /* + "show_timer_defend" "bool" + "show_timer_attack" "bool" + "timer_time" "int" + + "final_event" "byte" // 0 - no event, 1 - bomb exploded, 2 - flag capped, 3 - timer expired + + "category_left" "byte" // 0-4: none, bombers, cappers, defenders, killers + "left_1" "byte" // player index if first + "left_score_1" "byte" + "left_2" "byte" + "left_score_2" "byte" + "left_3" "byte" + "left_score_3" "byte" + + "right_1" "byte" + "right_score_1" "byte" + "right_2" "byte" + "right_score_2" "byte" + "right_3" "byte" + "right_score_3" "byte" + */ + + if ( !g_PR ) + return; + + m_bShowTimerDefend = event->GetBool( "show_timer_defend" ); + m_bShowTimerAttack = event->GetBool( "show_timer_attack" ); + m_iTimerTime = event->GetInt( "timer_time" ); + + int minutes = clamp( m_iTimerTime / 60, 0, 99 ); + int seconds = clamp( m_iTimerTime % 60, 0, 59 ); + + if ( m_bShowTimerDefend ) + { + // defenders win, show total time defended + // "Total Time Defended: 4:28" + + wchar_t time[8]; + _snwprintf( time, ARRAYSIZE( time ), L"%d:%02d", minutes, seconds ); + + wchar_t timerText[128]; + g_pVGuiLocalize->ConstructString( timerText, sizeof( timerText ), g_pVGuiLocalize->Find( "#winpanel_total_time" ), 1, time ); + + m_pTimerStatusLabel->SetText( timerText ); + + // zero out the final capture label, they won by timer + m_pLastCapperHeader->SetVisible( false ); + m_pLastBomberHeader->SetVisible( false ); + SetFinalCaptureLabel( "", false ); + + SetupAvatar( "top", 1, 0 ); // hide it + } + else if ( m_bShowTimerAttack ) + { + // attackers win, show time elapsed + // "Time Elapsed: 4:12" + + wchar_t time[8]; + _snwprintf( time, ARRAYSIZE( time ), L"%d:%02d", minutes, seconds ); + + wchar_t timerText[128]; + g_pVGuiLocalize->ConstructString( timerText, sizeof( timerText ), g_pVGuiLocalize->Find( "#winpanel_attack_time" ), 1, time ); + + m_pTimerStatusLabel->SetText( timerText ); + } + else + { + m_pTimerStatusLabel->SetText( "" ); + } + + m_iFinalEventType = event->GetInt( "final_event" ); + // up to client to fill in who completed the final event + + m_iLeftCategory = event->GetInt( "category_left" ); + m_iRightCategory = event->GetInt( "category_right" ); + + m_pLeftCategoryHeader->SetText( g_pVGuiLocalize->Find( pszWinPanelCategoryHeaders[m_iLeftCategory] ) ); + m_pRightCategoryHeader->SetText( g_pVGuiLocalize->Find( pszWinPanelCategoryHeaders[m_iRightCategory] ) ); + + int iPlayer; + + // Left Top 3 Category + iPlayer = event->GetInt( "left_1" ); + SetPlayerNameLabel( m_pLeftCategoryLabels[0], iPlayer ); + SetupAvatar( "left", 1, iPlayer ); + + iPlayer = event->GetInt( "left_2" ); + SetPlayerNameLabel( m_pLeftCategoryLabels[1], iPlayer ); + SetupAvatar( "left", 2, iPlayer ); + + iPlayer = event->GetInt( "left_3" ); + SetPlayerNameLabel( m_pLeftCategoryLabels[2], iPlayer ); + SetupAvatar( "left", 3, iPlayer ); + + m_iLeftCategoryScores[0] = event->GetInt( "left_score_1" ); + m_iLeftCategoryScores[1] = event->GetInt( "left_score_2" ); + m_iLeftCategoryScores[2] = event->GetInt( "left_score_3" ); + + // Right Top 3 Category + iPlayer = event->GetInt( "right_1" ); + SetPlayerNameLabel( m_pRightCategoryLabels[0], iPlayer ); + SetupAvatar( "right", 1, iPlayer ); + + iPlayer = event->GetInt( "right_2" ); + SetPlayerNameLabel( m_pRightCategoryLabels[1], iPlayer ); + SetupAvatar( "right", 2, iPlayer ); + + iPlayer = event->GetInt( "right_3" ); + SetPlayerNameLabel( m_pRightCategoryLabels[2], iPlayer ); + SetupAvatar( "right", 3, iPlayer ); + + m_iRightCategoryScores[0] = event->GetInt( "right_score_1" ); + m_iRightCategoryScores[1] = event->GetInt( "right_score_2" ); + m_iRightCategoryScores[2] = event->GetInt( "right_score_3" ); + + m_pRightCategoryHeader->SetVisible( ( m_iRightCategoryScores[0] > 0 ) ); + } +} + +void CDODWinPanel::SetupAvatar( const char *pSide, int pos, int iPlayerIndex ) +{ +#if !defined( _X360 ) + + bool bVisible = ( iPlayerIndex > 0 ); + + CAvatarImagePanel *pPlayerAvatar = dynamic_cast<CAvatarImagePanel *>( FindChildByName( CFmtStr( "%s_%d_avatar", pSide, pos ) ) ); + + if ( pPlayerAvatar ) + { + pPlayerAvatar->SetShouldScaleImage( true ); + pPlayerAvatar->SetShouldDrawFriendIcon( false ); + + if ( bVisible ) + { + CBasePlayer *pPlayer = UTIL_PlayerByIndex( iPlayerIndex ); + pPlayerAvatar->SetPlayer( pPlayer ); + } + + pPlayerAvatar->SetVisible( bVisible ); + } +#endif +} + +void CDODWinPanel::SetFinalCaptureLabel( const char *szCappers, bool bShowAvatar ) +{ + SetDialogVariable( "lastcappers", szCappers ); + + m_pLastCapperLabel->SetVisible( !bShowAvatar ); + m_pLastCapperLabel_Avatar->SetVisible( bShowAvatar ); +} + +void CDODWinPanel::Show( void ) +{ + SetAlpha( 255 ); + + int iRenderGroup = gHUD.LookupRenderGroupIndexByName( "winpanel" ); + if ( iRenderGroup >= 0 ) + { + gHUD.LockRenderGroup( iRenderGroup ); + } +} + +void CDODWinPanel::Hide( void ) +{ + SetAlpha( 0 ); + + int iRenderGroup = gHUD.LookupRenderGroupIndexByName( "winpanel" ); + if ( iRenderGroup >= 0 ) + { + gHUD.UnlockRenderGroup( iRenderGroup ); + } +} + +void CDODWinPanel::ApplySchemeSettings( vgui::IScheme *pScheme ) +{ + BaseClass::ApplySchemeSettings( pScheme ); + + SetBgColor( GetSchemeColor("TransparentLightBlack", pScheme) ); +} + +bool CDODWinPanel::ShouldDraw( void ) +{ + return ( GetAlpha() > 0 ); +} + +CHudTexture *CDODWinPanel::GetIconForCategory( int category ) +{ + CHudTexture *pTex = NULL; + + switch( category ) + { + case WINPANEL_TOP3_BOMBERS: + pTex = m_pIconBomb; + break; + case WINPANEL_TOP3_CAPPERS: + pTex = m_pIconCap; + break; + case WINPANEL_TOP3_DEFENDERS: + pTex = m_pIconDefended; + break; + case WINPANEL_TOP3_KILLERS: + pTex = m_pIconKill; + break; + default: + break; + } + + return pTex; +} + +void CDODWinPanel::Paint( void ) +{ + if ( m_pIcon ) + { + Color c(255,255,255,255); + m_pIcon->DrawSelf( m_iIconX_left, m_iIconY, m_iIconW, m_iIconH, c ); + m_pIcon->DrawSelf( m_iIconX_right, m_iIconY, m_iIconW, m_iIconH, c ); + } + + int i; + int x, y, w, h; + Color c(255,255,255,255); + + // Draw Left Category Icons + CHudTexture *pIcon = GetIconForCategory( m_iLeftCategory ); + + if ( pIcon ) + { + for ( i=0;i<3;i++ ) + { + if ( m_iLeftCategoryScores[i] > 0 ) + { + m_pLeftCategoryLabels[i]->GetBounds( x, y, w, h ); + + x = x + w + XRES(2); + y = y + ( h - m_iIconSize ) * 0.5; + + // too many, do a "(icon) 8" + pIcon->DrawSelf( x, y, m_iIconSize, m_iIconSize, c ); + x += m_iIconSize; + + char buf[10]; + Q_snprintf( buf, sizeof(buf), " %d", m_iLeftCategoryScores[i] ); + DrawText( buf, x, y, c ); + } + } + } + + // Draw Right Category Icons + pIcon = GetIconForCategory( m_iRightCategory ); + + if ( pIcon ) + { + for ( i=0;i<3;i++ ) + { + if ( m_iRightCategoryScores[i] > 0 ) + { + m_pRightCategoryLabels[i]->GetBounds( x, y, w, h ); + + x = x + w + XRES(2); + y = y + ( h - m_iIconSize ) * 0.5; + + // too many, do a "(icon) 8" + pIcon->DrawSelf( x, y, m_iIconSize, m_iIconSize, c ); + x += m_iIconSize; + + char buf[10]; + Q_snprintf( buf, sizeof(buf), " %d", m_iRightCategoryScores[i] ); + DrawText( buf, x, y, c ); + } + } + } +} + +void CDODWinPanel::DrawText( char *text, int x, int y, Color clrText ) +{ + vgui::surface()->DrawSetTextColor( clrText ); + vgui::surface()->DrawSetTextFont( m_hNumberFont ); + vgui::surface()->DrawSetTextPos( x, y ); + + for (char *pch = text; *pch != 0; pch++) + { + vgui::surface()->DrawUnicodeChar(*pch); + } +}
\ No newline at end of file diff --git a/game/client/dod/dod_hud_winpanel.h b/game/client/dod/dod_hud_winpanel.h new file mode 100644 index 0000000..5cdd3cc --- /dev/null +++ b/game/client/dod/dod_hud_winpanel.h @@ -0,0 +1,131 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef DODWINPANEL_H +#define DODWINPANEL_H +#ifdef _WIN32 +#pragma once +#endif + +#include <vgui_controls/EditablePanel.h> +#include <game/client/iviewport.h> +#include <vgui/IScheme.h> +#include "hud.h" +#include "hudelement.h" + +#include "dod_shareddefs.h" + +using namespace vgui; + +class CDODWinPanel : public EditablePanel, public CHudElement +{ +private: + DECLARE_CLASS_SIMPLE( CDODWinPanel, EditablePanel ); + +public: + CDODWinPanel( const char *pElementName, int iTeam ); + + virtual void Reset(); + virtual void Init(); + virtual void VidInit(); + virtual void ApplySchemeSettings( vgui::IScheme *pScheme ); + virtual void FireGameEvent( IGameEvent * event ); + + void Show(); + void Hide(); + + virtual bool ShouldDraw( void ); + virtual void Paint( void ); + + void SetupAvatar( const char *pSide, int pos, int iPlayerIndex ); + +protected: + void SetFinalCaptureLabel( const char *szCappers, bool bAvatar ); + void DrawText( char *text, int x, int y, Color clrText ); + + CHudTexture *GetIconForCategory( int category ); + + CHudTexture *m_pIcon; + + CHudTexture *m_pIconCap; + CHudTexture *m_pIconDefended; + CHudTexture *m_pIconBomb; + CHudTexture *m_pIconKill; + + vgui::Label *m_pLastCapperHeader; + vgui::Label *m_pLastBomberHeader; + + vgui::Label *m_pLastCapperLabel; // list of names of the final cappers + vgui::Label *m_pLastCapperLabel_Avatar; + + vgui::Label *m_pTimerStatusLabel; // shows time remaining or elapsed at round end + + int m_iLeftCategory; + vgui::Label *m_pLeftCategoryHeader; + vgui::Label *m_pLeftCategoryLabels[3]; + int m_iLeftCategoryScores[3]; + + int m_iRightCategory; + vgui::Label *m_pRightCategoryHeader; + vgui::Label *m_pRightCategoryLabels[3]; + int m_iRightCategoryScores[3]; + + bool m_bShowTimerDefend; + bool m_bShowTimerAttack; + int m_iTimerTime; + + int m_iFinalEventType; + + + +private: + CPanelAnimationVarAliasType( int, m_iIconY, "icon_ypos", "0", "proportional_int" ); + CPanelAnimationVarAliasType( int, m_iIconX_left, "icon_xpos_left", "0", "proportional_int" ); + CPanelAnimationVarAliasType( int, m_iIconX_right, "icon_xpos_right", "0", "proportional_int" ); + CPanelAnimationVarAliasType( int, m_iIconW, "icon_w", "0", "proportional_int" ); + CPanelAnimationVarAliasType( int, m_iIconH, "icon_h", "0", "proportional_int" ); + + CPanelAnimationVarAliasType( int, m_iIconSize, "icon_stat_size", "0", "proportional_int" ); + CPanelAnimationVarAliasType( int, m_iIconLeftX, "icon_left_stat_x", "0", "proportional_int" ); + CPanelAnimationVarAliasType( int, m_iIconLeftY1, "icon_left_stat_y1", "0", "proportional_int" ); + CPanelAnimationVarAliasType( int, m_iIconLeftY2, "icon_left_stat_y2", "0", "proportional_int" ); + CPanelAnimationVarAliasType( int, m_iIconLeftY3, "icon_left_stat_y3", "0", "proportional_int" ); + CPanelAnimationVarAliasType( int, m_iIconRightX, "icon_right_stat_x", "0", "proportional_int" ); + CPanelAnimationVarAliasType( int, m_iIconRightY1, "icon_right_stat_y1", "0", "proportional_int" ); + CPanelAnimationVarAliasType( int, m_iIconRightY2, "icon_right_stat_y2", "0", "proportional_int" ); + CPanelAnimationVarAliasType( int, m_iIconRightY3, "icon_right_stat_y3", "0", "proportional_int" ); + + CPanelAnimationVar( vgui::HFont, m_hNumberFont, "NumberFont", "HudSelectionNumbers" ); + + int m_iTeam; +}; + +class CDODWinPanel_Allies : public CDODWinPanel +{ +private: + DECLARE_CLASS_SIMPLE( CDODWinPanel_Allies, CDODWinPanel ); + +public: + CDODWinPanel_Allies( const char *pElementName ); + + virtual void ApplySchemeSettings( vgui::IScheme *pScheme ); + virtual void OnScreenSizeChanged( int iOldWide, int iOldTall ); +}; + +class CDODWinPanel_Axis : public CDODWinPanel +{ +private: + DECLARE_CLASS_SIMPLE( CDODWinPanel_Axis, CDODWinPanel ); + +public: + CDODWinPanel_Axis( const char *pElementName ); + + virtual void ApplySchemeSettings( vgui::IScheme *pScheme ); + virtual void OnScreenSizeChanged( int iOldWide, int iOldTall ); +}; + +#endif //DODWINPANEL_H
\ No newline at end of file diff --git a/game/client/dod/dod_in_main.cpp b/game/client/dod/dod_in_main.cpp new file mode 100644 index 0000000..b839cdc --- /dev/null +++ b/game/client/dod/dod_in_main.cpp @@ -0,0 +1,23 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: TF2 specific input handling +// +// $NoKeywords: $ +//=============================================================================// +#include "cbase.h" +#include "kbutton.h" +#include "input.h" + +//----------------------------------------------------------------------------- +// Purpose: TF Input interface +//----------------------------------------------------------------------------- +class CDODInput : public CInput +{ +public: +}; + +static CDODInput g_Input; + +// Expose this interface +IInput *input = ( IInput * )&g_Input; + diff --git a/game/client/dod/dod_playerstats.cpp b/game/client/dod/dod_playerstats.cpp new file mode 100644 index 0000000..24db375 --- /dev/null +++ b/game/client/dod/dod_playerstats.cpp @@ -0,0 +1,344 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#include "cbase.h" +#include "dod_playerstats.h" +#include "hud_macros.h" + +const char *g_pszShortTeamNames[2] = +{ + "US", + "Ger" +}; + +const char *g_pszClassNames[NUM_DOD_PLAYERCLASSES] = +{ + "Rifleman", + "Assault", + "Support", + "Sniper", + "MG", + "Rocket" +}; + +const char *g_pszStatNames[DODSTAT_MAX] = +{ + "iPlayTime", + "iRoundsWon", + "iRoundsLost", + "iKills", + "iDeaths", + "iCaptures", + "iBlocks", + "iBombsPlanted", + "iBombsDefused", + "iDominations", + "iRevenges", + "iShotsHit", + "iShotsFired", + "iHeadshots" +}; + +int iValidWeaponStatBitMask = ( (1<<DODSTAT_KILLS ) | (1<<DODSTAT_SHOTS_HIT) | (1<<DODSTAT_SHOTS_FIRED) | (1<<DODSTAT_HEADSHOTS) ); +int iValidPlayerStatBitMask = 0xFFFF & ~( (1<<DODSTAT_SHOTS_HIT) | (1<<DODSTAT_SHOTS_FIRED) | (1<<DODSTAT_HEADSHOTS) ); + +//----------------------------------------------------------------------------- +// Purpose: +// Input : &msg - +//----------------------------------------------------------------------------- +void __MsgFunc_DODPlayerStatsUpdate( bf_read &msg ) +{ + g_DODPlayerStats.MsgFunc_DODPlayerStatsUpdate( msg ); +} + +//----------------------------------------------------------------------------- +// Purpose: Constructor +//----------------------------------------------------------------------------- +CDODPlayerStats::CDODPlayerStats() +{ + m_flTimeNextForceUpload = 0; +} + +//----------------------------------------------------------------------------- +// Purpose: called at init time after all systems are init'd. We have to +// do this in PostInit because the Steam app ID is not available earlier +//----------------------------------------------------------------------------- +void CDODPlayerStats::PostInit() +{ + SetNextForceUploadTime(); + + ListenForGameEvent( "player_stats_updated" ); + ListenForGameEvent( "user_data_downloaded" ); + + HOOK_MESSAGE( DODPlayerStatsUpdate ); +} + +//----------------------------------------------------------------------------- +// Purpose: called at level shutdown +//----------------------------------------------------------------------------- +void CDODPlayerStats::LevelShutdownPreEntity() +{ + // upload user stats to Steam on every map change or when we quit + UploadStats(); +} + +//----------------------------------------------------------------------------- +// Purpose: called when the stats have changed in-game +//----------------------------------------------------------------------------- +void CDODPlayerStats::FireGameEvent( IGameEvent *event ) +{ + const char *pEventName = event->GetName(); + + if ( FStrEq( pEventName, "user_data_downloaded" ) ) + { + // Store our stat data + + Assert( steamapicontext->SteamUserStats() ); + if ( !steamapicontext->SteamUserStats() ) + return; + + CGameID gameID( engine->GetAppID() ); + + // reset everything + Q_memset( &m_PlayerStats, 0, sizeof(m_PlayerStats) ); + Q_memset( &m_WeaponStats, 0, sizeof(m_WeaponStats) ); + + // read playerclass stats + for ( int iTeam=0;iTeam<2;iTeam++ ) + { + for ( int iClass=0;iClass<NUM_DOD_PLAYERCLASSES;iClass++ ) + { + for ( int iStat=0;iStat<DODSTAT_MAX;iStat++ ) + { + if ( iValidPlayerStatBitMask & (1<<iStat) ) + { + char szStatName[256]; + int iData; + + Q_snprintf( szStatName, ARRAYSIZE( szStatName ), "%s.%s.%s", g_pszShortTeamNames[iTeam], g_pszClassNames[iClass], g_pszStatNames[iStat] ); + + if ( steamapicontext->SteamUserStats()->GetStat( szStatName, &iData ) ) + { + // use Steam's value + m_PlayerStats[iTeam][iClass].m_iStat[iStat] = iData; + } + } + } + } + } + + // read weapon stats + for ( int iWeapon=WEAPON_NONE+1;iWeapon<WEAPON_MAX;iWeapon++ ) + { + for ( int iStat=0;iStat<DODSTAT_MAX;iStat++ ) + { + if ( iValidWeaponStatBitMask & (1<<iStat) ) + { + char szStatName[256]; + int iData; + + Q_snprintf( szStatName, ARRAYSIZE( szStatName ), "%s.%s", s_WeaponAliasInfo[iWeapon], g_pszStatNames[iStat] ); + + if ( steamapicontext->SteamUserStats()->GetStat( szStatName, &iData ) ) + { + // use Steam's value + m_WeaponStats[iWeapon].m_iStat[iStat] = iData; + } + } + } + } + + IGameEvent * event = gameeventmanager->CreateEvent( "player_stats_updated" ); + if ( event ) + { + event->SetBool( "forceupload", false ); + gameeventmanager->FireEventClientSide( event ); + } + } +} + +void CDODPlayerStats::MsgFunc_DODPlayerStatsUpdate( bf_read &msg ) +{ + dod_stat_accumulator_t playerStats; + Q_memset( &playerStats, 0, sizeof(playerStats) ); + + // get the fixed-size information + int iClass = msg.ReadByte(); + int iTeam = msg.ReadByte(); + + int iPlayerStatBits = msg.ReadLong(); + + Assert( iClass >= 0 && iClass <= 5 ); + if ( iClass < 0 || iClass > 5 ) + return; + + // the bitfield indicates which stats are contained in the message. Set the stats appropriately. + int iStat = DODSTAT_FIRST; + while ( iPlayerStatBits > 0 ) + { + if ( iPlayerStatBits & 1 ) + { + playerStats.m_iStat[iStat] = msg.ReadLong(); + } + iPlayerStatBits >>= 1; + iStat++; + } + + int iNumWeapons = msg.ReadByte(); + int i; + + CUtlVector<weapon_stat_t> vecWeaponStats; + + for ( i=0;i<iNumWeapons;i++ ) + { + weapon_stat_t weaponStat; + Q_memset( &weaponStat, 0, sizeof(weaponStat) ); + + weaponStat.iWeaponID = msg.ReadByte(); + + vecWeaponStats.AddToTail( weaponStat ); + } + + for ( i=0;i<vecWeaponStats.Count();i++ ) + { + int iWeaponStatMask = msg.ReadLong(); + + int iStat = DODSTAT_FIRST; + while ( iWeaponStatMask > 0 ) + { + if ( iWeaponStatMask & 1 ) + { + vecWeaponStats[i].stats.m_iStat[iStat] = msg.ReadLong(); + } + iWeaponStatMask >>= 1; + iStat++; + } + } + + // sanity check: the message should contain exactly the # of bytes we expect based on the bit field + Assert( !msg.IsOverflowed() ); + Assert( 0 == msg.GetNumBytesLeft() ); + // if byte count isn't correct, bail out and don't use this data, rather than risk polluting player stats with garbage + if ( msg.IsOverflowed() || ( 0 != msg.GetNumBytesLeft() ) ) + return; + + UpdateStats( iClass, iTeam, &playerStats, &vecWeaponStats ); +} + +//----------------------------------------------------------------------------- +// Purpose: Uploads stats for current Steam user to Steam +//----------------------------------------------------------------------------- +void CDODPlayerStats::UploadStats() +{ + // only upload if Steam is running + if ( !steamapicontext->SteamUserStats() ) + return; + + CGameID gameID( engine->GetAppID() ); + char szStatName[256]; + + // write playerclass stats + for ( int iTeam=0;iTeam<2;iTeam++ ) + { + for ( int iClass=0;iClass<NUM_DOD_PLAYERCLASSES;iClass++ ) + { + for ( int iStat=0;iStat<DODSTAT_MAX;iStat++ ) + { + if ( iValidPlayerStatBitMask & (1<<iStat) ) + { + if ( m_PlayerStats[iTeam][iClass].m_bDirty[iStat] ) + { + Q_snprintf( szStatName, ARRAYSIZE( szStatName ), "%s.%s.%s", g_pszShortTeamNames[iTeam], g_pszClassNames[iClass], g_pszStatNames[iStat] ); + + steamapicontext->SteamUserStats()->SetStat( szStatName, m_PlayerStats[iTeam][iClass].m_iStat[iStat] ); + } + } + } + } + } + + // write weapon stats + for ( int iWeapon=WEAPON_NONE+1;iWeapon<WEAPON_MAX;iWeapon++ ) + { + for ( int iStat=0;iStat<DODSTAT_MAX;iStat++ ) + { + if ( m_WeaponStats[iWeapon].m_bDirty[iStat] ) + { + if ( iValidWeaponStatBitMask & (1<<iStat) ) + { + Q_snprintf( szStatName, ARRAYSIZE( szStatName ), "%s.%s", s_WeaponAliasInfo[iWeapon], g_pszStatNames[iStat] ); + + steamapicontext->SteamUserStats()->SetStat( szStatName, m_WeaponStats[iWeapon].m_iStat[iStat] ); + } + } + } + } + + SetNextForceUploadTime(); +} + +void CDODPlayerStats::UpdateStats( int iPlayerClass, int iTeam, dod_stat_accumulator_t *playerStats, CUtlVector<weapon_stat_t> *vecWeaponStats ) +{ + Assert( iPlayerClass >= 0 && iPlayerClass < NUM_DOD_PLAYERCLASSES ); + if ( iPlayerClass < 0 || iPlayerClass >= NUM_DOD_PLAYERCLASSES ) + return; + + // translate the team index into [0,1] + int iTeamIndex = ( iTeam == TEAM_ALLIES ) ? 0 : 1; + + // upload this class' data + + // add this stat update to our stored stats + for ( int iStat=0;iStat<DODSTAT_MAX;iStat++ ) + { + if ( iValidPlayerStatBitMask & (1<<iStat) ) + { + if ( playerStats->m_iStat[iStat] > 0 ) + { + m_PlayerStats[iTeamIndex][iPlayerClass].m_iStat[iStat] += playerStats->m_iStat[iStat]; + m_PlayerStats[iTeamIndex][iPlayerClass].m_bDirty[iStat] = true; + } + } + } + + int iWeaponStatCount = vecWeaponStats->Count(); + + for ( int i=0;i<iWeaponStatCount;i++ ) + { + int iWeaponID = vecWeaponStats->Element(i).iWeaponID; + + for ( int iStat=0;iStat<DODSTAT_MAX;iStat++ ) + { + if ( iValidWeaponStatBitMask & (1<<iStat) ) + { + int iValue = vecWeaponStats->Element(i).stats.m_iStat[iStat]; + if ( iValue > 0 ) + { + m_WeaponStats[iWeaponID].m_iStat[iStat] += iValue; + m_WeaponStats[iWeaponID].m_bDirty[iStat] = true; + } + } + } + } + + // if we haven't uploaded stats in a long time, upload them + if ( ( gpGlobals->curtime >= m_flTimeNextForceUpload ) ) + { + UploadStats(); + } +} + +//----------------------------------------------------------------------------- +// Purpose: sets the next time to force a stats upload at +//----------------------------------------------------------------------------- +void CDODPlayerStats::SetNextForceUploadTime() +{ + // pick a time a while from now (an hour +/- 15 mins) to upload stats if we haven't gotten a map change by then + m_flTimeNextForceUpload = gpGlobals->curtime + ( 60 * RandomInt( 45, 75 ) ); +} + +CDODPlayerStats g_DODPlayerStats;
\ No newline at end of file diff --git a/game/client/dod/dod_playerstats.h b/game/client/dod/dod_playerstats.h new file mode 100644 index 0000000..2fd70f6 --- /dev/null +++ b/game/client/dod/dod_playerstats.h @@ -0,0 +1,53 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef DOD_PLAYERSTATS_H +#define DOD_PLAYERSTATS_H +#ifdef _WIN32 +#pragma once +#endif + +#include "steam/steam_api.h" +#include "GameEventListener.h" +#include "dod_shareddefs.h" +#include "weapon_dodbase.h" + +typedef struct +{ + dod_stat_accumulator_t stats; + int iWeaponID; +} weapon_stat_t; + +class CDODPlayerStats : public CAutoGameSystem, public CGameEventListener +{ +public: + CDODPlayerStats(); + virtual void PostInit(); + virtual void LevelShutdownPreEntity(); + + void UploadStats(); + + void UpdateStats( int iPlayerClass, int iTeam, dod_stat_accumulator_t *playerStats, CUtlVector<weapon_stat_t> *vecWeaponStats ); + + void MsgFunc_DODPlayerStatsUpdate( bf_read &msg ); + +private: + void FireGameEvent( IGameEvent *event ); + + void SetNextForceUploadTime(); + float m_flTimeNextForceUpload; + + // 6 x dod_stat_accumulator_t + dod_stat_accumulator_t m_PlayerStats[2][NUM_DOD_PLAYERCLASSES]; + + // num_weapons x dod_stat_accumulator_t + dod_stat_accumulator_t m_WeaponStats[WEAPON_MAX]; +}; + +extern CDODPlayerStats g_DODPlayerStats; + +#endif //DOD_PLAYERSTATS_H
\ No newline at end of file diff --git a/game/client/dod/dod_prediction.cpp b/game/client/dod/dod_prediction.cpp new file mode 100644 index 0000000..43e420e --- /dev/null +++ b/game/client/dod/dod_prediction.cpp @@ -0,0 +1,55 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// +#include "cbase.h" +#include "prediction.h" +#include "c_dod_player.h" +#include "igamemovement.h" + + +static CMoveData g_MoveData; +CMoveData *g_pMoveData = &g_MoveData; + + +class CDODPrediction : public CPrediction +{ +DECLARE_CLASS( CDODPrediction, CPrediction ); + +public: + virtual void SetupMove( C_BasePlayer *player, CUserCmd *ucmd, IMoveHelper *pHelper, CMoveData *move ); + virtual void FinishMove( C_BasePlayer *player, CUserCmd *ucmd, CMoveData *move ); +}; + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CDODPrediction::SetupMove( C_BasePlayer *player, CUserCmd *ucmd, IMoveHelper *pHelper, + CMoveData *move ) +{ + player->AvoidPhysicsProps( ucmd ); + + // Call the default SetupMove code. + BaseClass::SetupMove( player, ucmd, pHelper, move ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CDODPrediction::FinishMove( C_BasePlayer *player, CUserCmd *ucmd, CMoveData *move ) +{ + // Call the default FinishMove code. + BaseClass::FinishMove( player, ucmd, move ); +} + + +// Expose interface to engine +// Expose interface to engine +static CDODPrediction g_Prediction; + +EXPOSE_SINGLE_INTERFACE_GLOBALVAR( CDODPrediction, IPrediction, VCLIENT_PREDICTION_INTERFACE_VERSION, g_Prediction ); + +CPrediction *prediction = &g_Prediction; + diff --git a/game/client/dod/dod_view_scene.cpp b/game/client/dod/dod_view_scene.cpp new file mode 100644 index 0000000..72d7a00 --- /dev/null +++ b/game/client/dod/dod_view_scene.cpp @@ -0,0 +1,333 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Responsible for drawing the scene +// +// $NoKeywords: $ +//============================================================================= + +#include "cbase.h" +#include "iviewrender.h" +#include "c_dod_player.h" +#include "view_shared.h" +#include "dod_headiconmanager.h" + +#include "clienteffectprecachesystem.h" +#include "rendertexture.h" +#include "view_scene.h" + +#include "materialsystem/imesh.h" +#include "materialsystem/itexture.h" +#include "materialsystem/imaterial.h" +#include "materialsystem/imaterialvar.h" +#include "colorcorrectionmgr.h" +#include "materialsystem/imaterialsystemhardwareconfig.h" + +#include "ScreenSpaceEffects.h" +#include "dod_view_scene.h" +#include "KeyValues.h" +#include "dod_gamerules.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +static CDODViewRender g_ViewRender; + +// Console variable for enabling camera effects +ConVar cl_enablespectatoreffects( "cl_enablespectatoreffects", "0", FCVAR_CLIENTDLL | FCVAR_ARCHIVE, "Enable/disable spectator camera effects" ); +ConVar cl_enabledeatheffects( "cl_enabledeatheffects", "1", FCVAR_CLIENTDLL | FCVAR_ARCHIVE, "Enable/disable death camera effects" ); +ConVar cl_enabledeathfilmgrain( "cl_enabledeathfilmgrain", "1", FCVAR_CLIENTDLL | FCVAR_ARCHIVE, "Enable/disable the death camera film grain" ); + +ConVar cl_deatheffect_force_on( "cl_deatheffect_always_on", "0", FCVAR_CLIENTDLL | FCVAR_ARCHIVE, "Always show the death effect" ); + +// Console variables to define lookup maps +static void UpdateCameraLookups( IConVar *var, char const *pOldString, float flOldValue ) +{ + CDODViewRender *pView = static_cast<CDODViewRender*>(view); + pView->InitColorCorrection(); +} + +static void SetSpectatorLookup( ConVar *var, char const *pOldString ); +ConVar cl_spectatorlookup( "cl_spectatorlookup", "materials\\colorcorrection\\bnw_c.raw", FCVAR_CLIENTDLL | FCVAR_CHEAT, "Sets the lookup map to use for spectator cameras", UpdateCameraLookups ); +ConVar cl_deathlookup( "cl_deathlookup", "materials\\colorcorrection\\bnw_c.raw", FCVAR_CLIENTDLL | FCVAR_CHEAT, "Sets the lookup map to use for death cameras", UpdateCameraLookups ); + +CLIENTEFFECT_REGISTER_BEGIN( PrecacheDODViewScene ) +CLIENTEFFECT_MATERIAL( "effects/stun" ) +CLIENTEFFECT_REGISTER_END() + +CDODViewRender::CDODViewRender() +{ + view = ( IViewRender * )this; + + m_SpectatorLookupHandle = (ClientCCHandle_t)0; + m_DeathLookupHandle = (ClientCCHandle_t)0; + m_bLookupActive = false; +} + +struct ConVarFlags +{ + const char *name; + int flags; +}; + +ConVarFlags s_flaggedConVars[] = +{ + { "r_screenfademinsize", FCVAR_CHEAT }, + { "r_screenfademaxsize", FCVAR_CHEAT }, +}; + +void CDODViewRender::Init() +{ + for ( int i=0; i<ARRAYSIZE( s_flaggedConVars ); ++i ) + { + ConVar *flaggedConVar = cvar->FindVar( s_flaggedConVars[i].name ); + if ( flaggedConVar ) + { + flaggedConVar->AddFlags( s_flaggedConVars[i].flags ); + } + } + + CViewRender::Init(); + + InitColorCorrection(); +} + +void CDODViewRender::Shutdown() +{ + CViewRender::Shutdown(); + + ShutdownColorCorrection(); +} + +void CDODViewRender::PerformStunEffect( const CViewSetup &view ) +{ + C_DODPlayer *pPlayer = C_DODPlayer::GetLocalDODPlayer(); + + if ( pPlayer == NULL ) + return; + + if ( pPlayer->m_flStunEffectTime < gpGlobals->curtime ) + return; + + IMaterial *pMaterial = materials->FindMaterial( "effects/stun", TEXTURE_GROUP_CLIENT_EFFECTS, true ); + + if ( !pMaterial ) + return; + + byte overlaycolor[4] = { 255, 255, 255, 255 }; + + CMatRenderContextPtr pRenderContext( materials ); + if ( pPlayer->m_flStunAlpha < pPlayer->m_flStunMaxAlpha ) + { + // copy current screen content into texture buffer + UpdateScreenEffectTexture( 0, view.x, view.y, view.width, view.height ); + + pPlayer->m_flStunAlpha += 45; + + pPlayer->m_flStunAlpha = MIN( pPlayer->m_flStunAlpha, pPlayer->m_flStunMaxAlpha ); + + overlaycolor[3] = pPlayer->m_flStunAlpha; + + m_pStunTexture = GetFullFrameFrameBufferTexture( 1 ); + + bool foundVar; + + IMaterialVar* m_BaseTextureVar = pMaterial->FindVar( "$basetexture", &foundVar, false ); + + Rect_t srcRect; + srcRect.x = view.x; + srcRect.y = view.y; + srcRect.width = view.width; + srcRect.height = view.height; + m_BaseTextureVar->SetTextureValue( m_pStunTexture ); + pRenderContext->CopyRenderTargetToTextureEx( m_pStunTexture, 0, &srcRect, NULL ); + pRenderContext->SetFrameBufferCopyTexture( m_pStunTexture ); + + render->ViewDrawFade( overlaycolor, pMaterial ); + + // just do one pass for dxlevel < 80. + if (g_pMaterialSystemHardwareConfig->GetDXSupportLevel() >= 80) + { + pRenderContext->DrawScreenSpaceQuad( pMaterial ); + render->ViewDrawFade( overlaycolor, pMaterial ); + pRenderContext->DrawScreenSpaceQuad( pMaterial ); + } + } + else if ( m_pStunTexture ) + { + float flAlpha = pPlayer->m_flStunMaxAlpha * (pPlayer->m_flStunEffectTime - gpGlobals->curtime) / pPlayer->m_flStunDuration; + + flAlpha = clamp( flAlpha, 0, pPlayer->m_flStunMaxAlpha ); + + overlaycolor[3] = flAlpha; + + render->ViewDrawFade( overlaycolor, pMaterial ); + + // just do one pass for dxlevel < 80. + if (g_pMaterialSystemHardwareConfig->GetDXSupportLevel() >= 80) + { + pRenderContext->DrawScreenSpaceQuad( pMaterial ); + render->ViewDrawFade( overlaycolor, pMaterial ); + pRenderContext->DrawScreenSpaceQuad( pMaterial ); + } + } +} + + +//----------------------------------------------------------------------------- +// Purpose: Initialise the color correction maps for spectator and death cameras +// Input : none +//----------------------------------------------------------------------------- +void CDODViewRender::InitColorCorrection( ) +{ + m_SpectatorLookupHandle = g_pColorCorrectionMgr->AddColorCorrection( "spectator", cl_spectatorlookup.GetString() ); + m_DeathLookupHandle = g_pColorCorrectionMgr->AddColorCorrection( "death", cl_deathlookup.GetString() ); +} + +//----------------------------------------------------------------------------- +// Purpose: Cleanup the color correction maps +// Input : none +//----------------------------------------------------------------------------- +void CDODViewRender::ShutdownColorCorrection( ) +{ + g_pColorCorrectionMgr->RemoveColorCorrection( m_SpectatorLookupHandle ); + g_pColorCorrectionMgr->RemoveColorCorrection( m_DeathLookupHandle ); +} + +//----------------------------------------------------------------------------- +// Purpose: Do the per-frame setup required for the spectator cam color correction +// Input : none +//----------------------------------------------------------------------------- +void CDODViewRender::SetupColorCorrection( ) +{ + C_DODPlayer *pPlayer = C_DODPlayer::GetLocalDODPlayer(); + if( !pPlayer ) + return; + + bool bResetColorCorrection = true; + + int nObsMode = pPlayer->GetObserverMode(); + + if ( pPlayer->GetTeamNumber() == TEAM_SPECTATOR ) + { + if ( cl_enablespectatoreffects.GetBool() ) + { + bResetColorCorrection = false; + + // Enable spectator color lookup for all other modes except OBS_MODE_NONE + g_pColorCorrectionMgr->SetColorCorrectionWeight( m_SpectatorLookupHandle, 1.0f ); + g_pColorCorrectionMgr->SetColorCorrectionWeight( m_DeathLookupHandle, 0.0f ); + g_pColorCorrectionMgr->SetResetable( m_SpectatorLookupHandle, false ); + g_pColorCorrectionMgr->SetResetable( m_DeathLookupHandle, true ); + + if ( cl_enabledeathfilmgrain.GetBool() ) + { + g_pScreenSpaceEffects->EnableScreenSpaceEffect( "filmgrain" ); + + KeyValues *kv = new KeyValues( "params" ); + kv->SetFloat( "effect_alpha", 1.0f ); + g_pScreenSpaceEffects->SetScreenSpaceEffectParams( "filmgrain", kv ); + + m_bLookupActive = true; + } + } + } + else if ( cl_enabledeatheffects.GetBool() ) + { + float flEffectAlpha = 0.0f; + + if ( cl_deatheffect_force_on.GetBool() ) + { + flEffectAlpha = 1.0f; + } + else if ( nObsMode != OBS_MODE_NONE ) + { + flEffectAlpha = MIN( 1.0f, ( gpGlobals->curtime - pPlayer->GetDeathTime() ) / ( 2.0f ) ); + } + else + { + DODRoundState roundstate = DODGameRules()->State_Get(); + + if ( roundstate < STATE_RND_RUNNING ) + { + flEffectAlpha = 1.0f; + } + else if ( roundstate == STATE_RND_RUNNING ) + { + // fade out of effect at last event: spawn or unfreeze at round start + float flFadeOutStartTime = MAX( DODGameRules()->m_flLastRoundStateChangeTime, pPlayer->m_flLastRespawnTime ); + + // fade in from round start time + flEffectAlpha = 1.0 - ( gpGlobals->curtime - flFadeOutStartTime ) / ( 2.0f ); + flEffectAlpha = MAX( 0.0f, flEffectAlpha ); + } + } + + if ( flEffectAlpha > 0.0f ) + { + bResetColorCorrection = false; + + // Enable death camera color lookup + + // allow us to reset the weight + g_pColorCorrectionMgr->SetResetable( m_DeathLookupHandle, true ); + g_pColorCorrectionMgr->SetResetable( m_SpectatorLookupHandle, true ); + + // reset weight to 0 + g_pColorCorrectionMgr->ResetColorCorrectionWeights(); + + g_pColorCorrectionMgr->SetColorCorrectionWeight( m_SpectatorLookupHandle, 0.0f ); + g_pColorCorrectionMgr->SetColorCorrectionWeight( m_DeathLookupHandle, flEffectAlpha ); + + if ( cl_enabledeathfilmgrain.GetBool() ) + { + g_pScreenSpaceEffects->EnableScreenSpaceEffect( "filmgrain" ); + + KeyValues *kv = new KeyValues( "params" ); + //kv->SetInt( "split_screen", 1 ); + + kv->SetFloat( "effect_alpha", flEffectAlpha ); + + g_pScreenSpaceEffects->SetScreenSpaceEffectParams( "filmgrain", kv ); + } + + m_bLookupActive = true; + } + } + + if ( bResetColorCorrection ) + { + // Disable color lookups + g_pColorCorrectionMgr->SetColorCorrectionWeight( m_SpectatorLookupHandle, 0.0f ); + g_pColorCorrectionMgr->SetColorCorrectionWeight( m_DeathLookupHandle, 0.0f ); + g_pColorCorrectionMgr->SetResetable( m_SpectatorLookupHandle, true ); + g_pColorCorrectionMgr->SetResetable( m_DeathLookupHandle, true ); + + if( m_bLookupActive ) + g_pScreenSpaceEffects->DisableScreenSpaceEffect( "filmgrain" ); + + m_bLookupActive = false; + } +} + +void CDODViewRender::RenderView( const CViewSetup &view, int nClearFlags, int whatToDraw ) +{ + // Setup the necessary parameters for color correction + SetupColorCorrection( ); + + CViewRender::RenderView( view, nClearFlags, whatToDraw ); + + // Draw screen effects here + PerformStunEffect( view ); +} + +//----------------------------------------------------------------------------- +// Purpose: Renders voice feedback and other sprites attached to players +// Input : none +//----------------------------------------------------------------------------- +void CDODViewRender::RenderPlayerSprites() +{ + CViewRender::RenderPlayerSprites(); + + // Draw head icons here + HeadIconManager()->DrawHeadIcons(); +}
\ No newline at end of file diff --git a/game/client/dod/dod_view_scene.h b/game/client/dod/dod_view_scene.h new file mode 100644 index 0000000..2ad0359 --- /dev/null +++ b/game/client/dod/dod_view_scene.h @@ -0,0 +1,47 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#ifndef DOD_VIEW_SCENE_H +#define DOD_VIEW_SCENE_H +#ifdef _WIN32 +#pragma once +#endif + +#include "iviewrender.h" +#include "viewrender.h" + +#include "colorcorrectionmgr.h" + +//----------------------------------------------------------------------------- +// Purpose: Implements the interview to view rendering for the client .dll +//----------------------------------------------------------------------------- +class CDODViewRender : public CViewRender +{ +public: + CDODViewRender(); + + void Init( ); + void Shutdown( ); + + void RenderView( const CViewSetup &view, int nClearFlags, int whatToDraw ); + void RenderPlayerSprites(); + + void PerformStunEffect( const CViewSetup &view ); + + void InitColorCorrection( ); + void ShutdownColorCorrection( ); + void SetupColorCorrection( ); + +private: + ITexture *m_pStunTexture; + + ClientCCHandle_t m_SpectatorLookupHandle; + ClientCCHandle_t m_DeathLookupHandle; + bool m_bLookupActive; +}; + +#endif //DOD_VIEW_SCENE_H
\ No newline at end of file diff --git a/game/client/dod/fx_dod_blood.cpp b/game/client/dod/fx_dod_blood.cpp new file mode 100644 index 0000000..558e2f2 --- /dev/null +++ b/game/client/dod/fx_dod_blood.cpp @@ -0,0 +1,518 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: A blood spray effect to expose successful hits. +// +//=============================================================================// + +#include "cbase.h" +#include "clienteffectprecachesystem.h" +#include "fx_sparks.h" +#include "iefx.h" +#include "c_te_effect_dispatch.h" +#include "particles_ez.h" +#include "decals.h" +#include "engine/IEngineSound.h" +#include "fx_quad.h" +#include "engine/ivdebugoverlay.h" +#include "shareddefs.h" +#include "fx_blood.h" +#include "view.h" +#include "c_dod_player.h" +#include "fx.h" + +CLIENTEFFECT_REGISTER_BEGIN( PrecacheEffectDODBloodSpray ) +CLIENTEFFECT_MATERIAL( "effects/blood_gore" ) +CLIENTEFFECT_MATERIAL( "effects/blood_drop" ) +CLIENTEFFECT_MATERIAL( "effects/blood_puff" ) +CLIENTEFFECT_REGISTER_END() + + +class CHitEffectRamp +{ +public: + float m_flDamageAmount; + + float m_flMinAlpha; + float m_flMaxAlpha; + + float m_flMinSize; + float m_flMaxSize; + + float m_flMinVelocity; + float m_flMaxVelocity; +}; + + +void InterpolateRamp( + const CHitEffectRamp &a, + const CHitEffectRamp &b, + CHitEffectRamp &out, + int iDamage ) +{ + float t = RemapVal( iDamage, a.m_flDamageAmount, b.m_flDamageAmount, 0, 1 ); + + out.m_flMinAlpha = FLerp( a.m_flMinAlpha, b.m_flMinAlpha, t ); + out.m_flMaxAlpha = FLerp( a.m_flMaxAlpha, b.m_flMaxAlpha, t ); + out.m_flMinAlpha = clamp( out.m_flMinAlpha, 0, 255 ); + out.m_flMaxAlpha = clamp( out.m_flMaxAlpha, 0, 255 ); + + out.m_flMinSize = FLerp( a.m_flMinSize, b.m_flMinSize, t ); + out.m_flMaxSize = FLerp( a.m_flMaxSize, b.m_flMaxSize, t ); + + out.m_flMinVelocity = FLerp( a.m_flMinVelocity, b.m_flMinVelocity, t ); + out.m_flMaxVelocity = FLerp( a.m_flMaxVelocity, b.m_flMaxVelocity, t ); +} + + +void FX_HitEffectSmoke( + CSmartPtr<CBloodSprayEmitter> pEmitter, + int iDamage, + const Vector &vEntryPoint, + const Vector &vDirection, + float flScale) +{ + SimpleParticle newParticle; + PMaterialHandle hMaterial = ParticleMgr()->GetPMaterial( "effects/blood_gore" ); + + // These parameters create a ramp based on how much damage the shot did. + CHitEffectRamp ramps[2] = + { + { + 0, + 30, // min/max alpha + 70, + 0.5, // min/max size + 1, + 0, // min/max velocity (not used here) + 0 + }, + + { + 50, + 30, // min/max alpha + 70, + 1, // min/max size + 2, + 0, // min/max velocity (not used here) + 0 + } + }; + + CHitEffectRamp interpolatedRamp; + InterpolateRamp( + ramps[0], + ramps[1], + interpolatedRamp, + iDamage ); + + for ( int i=0; i < 2; i++ ) + { + SimpleParticle &newParticle = *pEmitter->AddSimpleParticle( hMaterial, vEntryPoint, 0, 0 ); + + newParticle.m_flLifetime = 0.0f; + newParticle.m_flDieTime = 3.0f; + + newParticle.m_uchStartSize = random->RandomInt( + interpolatedRamp.m_flMinSize, + interpolatedRamp.m_flMaxSize ) * flScale; + newParticle.m_uchEndSize = newParticle.m_uchStartSize * 4; + + newParticle.m_vecVelocity = Vector( 0, 0, 5 ) + RandomVector( -2, 2 ); + newParticle.m_uchStartAlpha = random->RandomInt( + interpolatedRamp.m_flMinSize, + interpolatedRamp.m_flMaxSize ); + newParticle.m_uchEndAlpha = 0; + + newParticle.m_flRoll = random->RandomFloat( 0, 360 ); + newParticle.m_flRollDelta = random->RandomFloat( -1, 1 ); + + newParticle.m_iFlags = SIMPLE_PARTICLE_FLAG_NO_VEL_DECAY; + + float colorRamp = random->RandomFloat( 0.5f, 1.25f ); + + newParticle.m_uchColor[0] = MIN( 1.0f, colorRamp ) * 255.0f; + newParticle.m_uchColor[1] = MIN( 1.0f, colorRamp ) * 255.0f; + newParticle.m_uchColor[2] = MIN( 1.0f, colorRamp ) * 255.0f; + } +} + + +void FX_HitEffectBloodSpray( + CSmartPtr<CBloodSprayEmitter> pEmitter, + int iDamage, + const Vector &vEntryPoint, + const Vector &vSprayNormal, + const char *pMaterialName, + float flLODDistance, + float flDistanceScale, + float flScale, + float flSpeed ) +{ + PMaterialHandle hMaterial = ParticleMgr()->GetPMaterial( pMaterialName ); + SimpleParticle *pParticle; + + float color[3] = { 1.0, 0, 0 }; + + Vector up( 0, 0, 1 ); + Vector right = up.Cross( vSprayNormal ); + VectorNormalize( right ); + + // These parameters create a ramp based on how much damage the shot did. + CHitEffectRamp ramps[2] = + { + { + 0, + 80, // min/max alpha + 128, + flScale/2,// min/max size + flScale, + 10, // min/max velocity + 20 + }, + + { + 50, + 80, // min/max alpha + 128, + flScale/2,// min/max size + flScale, + 30, // min/max velocity + 60 + } + }; + + CHitEffectRamp interpolatedRamp; + InterpolateRamp( + ramps[0], + ramps[1], + interpolatedRamp, + iDamage ); + + for ( int i = 0; i < 6; i++ ) + { + // Originate from within a circle '2 * scale' inches in diameter. + Vector offset = vEntryPoint + ( flScale * vSprayNormal * 0.5 ); + offset += right * random->RandomFloat( -1, 1 ) * flScale; + offset += up * random->RandomFloat( -1, 1 ) * flScale; + + pParticle = pEmitter->AddSimpleParticle( hMaterial, offset, 0, 0 ); + + if ( pParticle != NULL ) + { + pParticle->m_flLifetime = 0.0f; + pParticle->m_flDieTime = random->RandomFloat( 0.7f, 1.3f); + + // All the particles are between red and white. The whiter the particle is, the slower it goes. + float whiteness = random->RandomFloat( 0.1, 0.7 ); + float speedFactor = 1 - whiteness; + + float spread = 0.5f; + pParticle->m_vecVelocity.Random( -spread, spread ); + pParticle->m_vecVelocity += vSprayNormal * random->RandomInt( interpolatedRamp.m_flMinVelocity, interpolatedRamp.m_flMaxVelocity ) * flSpeed * speedFactor; + + float colorRamp = random->RandomFloat( 0.5f, 0.75f ) + flLODDistance; + + pParticle->m_uchColor[0] = MIN( 1.0f, color[0] * colorRamp ) * 255.0f; + pParticle->m_uchColor[1] = MIN( 1.0f, whiteness * colorRamp ) * 255.0f; + pParticle->m_uchColor[2] = MIN( 1.0f, whiteness * colorRamp ) * 255.0f; + + pParticle->m_uchStartSize = random->RandomFloat( interpolatedRamp.m_flMinSize, interpolatedRamp.m_flMaxSize ) * flDistanceScale; + pParticle->m_uchEndSize = pParticle->m_uchStartSize * 4 * flDistanceScale; + + pParticle->m_uchStartAlpha = random->RandomInt( interpolatedRamp.m_flMinAlpha, interpolatedRamp.m_flMaxAlpha ); + pParticle->m_uchEndAlpha = 0; + + pParticle->m_flRoll = random->RandomInt( 0, 360 ); + pParticle->m_flRollDelta = random->RandomFloat( -4.0f, 4.0f ); + } + } +} + + +void FX_HitEffectBloodSplatter( + CSmartPtr<CBloodSprayEmitter> pTrailEmitter, + int iDamage, + const Vector &vExitPoint, + const Vector &vSplatterNormal, + float flLODDistance ) +{ + float flScale = 4; + + pTrailEmitter->SetSortOrigin( vExitPoint ); + PMaterialHandle hMaterial = ParticleMgr()->GetPMaterial( "effects/blood_drop" ); + + Vector up( 0, 0, 1 ); + Vector right = up.Cross( vSplatterNormal ); + VectorNormalize( right ); + + // These parameters create a ramp based on how much damage the shot did. + CHitEffectRamp ramps[2] = + { + { + 0, + 0, // min/max alpha + 75, + 1.5f, // min/max size + 2.0f, + 25.0f * flScale, // min/max velocity + 35.0f * flScale + }, + + { + 50, + 0, // min/max alpha + 140, + 1.5f,// min/max size + 2.0f, + 65.0f * flScale, // min/max velocity + 75.0f * flScale + } + }; + + CHitEffectRamp interpolatedRamp; + InterpolateRamp( + ramps[0], + ramps[1], + interpolatedRamp, + iDamage ); + + + for ( int i = 0; i < 20; i++ ) + { + // Originate from within a circle 'scale' inches in diameter. + Vector offset = vExitPoint; + offset += right * random->RandomFloat( -0.15f, 0.15f ) * flScale; + offset += up * random->RandomFloat( -0.15f, 0.15f ) * flScale; + + SimpleParticle *tParticle = (SimpleParticle*)pTrailEmitter->AddSimpleParticle( + hMaterial, + vExitPoint, + random->RandomFloat( 0.225f, 0.35f ), + random->RandomFloat( interpolatedRamp.m_flMinSize, interpolatedRamp.m_flMaxSize ) + ); + + if ( tParticle == NULL ) + break; + + Vector offDir = vSplatterNormal + RandomVector( -0.05f, 0.05f ); + + tParticle->m_vecVelocity = offDir * random->RandomFloat( interpolatedRamp.m_flMinVelocity, interpolatedRamp.m_flMaxVelocity ); + + tParticle->m_iFlags = SIMPLE_PARTICLE_FLAG_NO_VEL_DECAY; + tParticle->m_uchColor[0] = 150; + tParticle->m_uchColor[1] = 0; + tParticle->m_uchColor[2] = 0; + tParticle->m_uchStartAlpha = interpolatedRamp.m_flMaxAlpha / 2; + tParticle->m_uchEndAlpha = 0; + } +} + +#include "fx_dod_blood.h" + +//----------------------------------------------------------------------------- +// Purpose: +// Input : origin - +// normal - +// scale - +//----------------------------------------------------------------------------- +void FX_DOD_BloodSpray( const Vector &origin, const Vector &normal, float flDamage ) +{ + if ( UTIL_IsLowViolence() ) + return; + + static ConVar *violence_hblood = cvar->FindVar( "violence_hblood" ); + if ( violence_hblood && !violence_hblood->GetBool() ) + return; + + Vector offset; + + float half_r = 32; + float half_g = 0; + float half_b = 2; + int i; + + float scale = 0.5 + clamp( flDamage/50.f, 0.0, 1.0 ) ; + + //Find area ambient light color and use it to tint smoke + Vector worldLight = WorldGetLightForPoint( origin, true ); + + Vector color; + color.x = (float)( worldLight.x * half_r + half_r ) / 255.0f; + color.y = (float)( worldLight.y * half_g + half_g ) / 255.0f; + color.z = (float)( worldLight.z * half_b + half_b ) / 255.0f; + + float colorRamp; + + Vector offDir; + + CSmartPtr<CBloodSprayEmitter> pSimple = CBloodSprayEmitter::Create( "bloodgore" ); + if ( !pSimple ) + return; + + pSimple->SetSortOrigin( origin ); + pSimple->SetGravity( 0 ); + + // Blood impact + PMaterialHandle hMaterial = ParticleMgr()->GetPMaterial( "effects/blood_core" ); + + SimpleParticle *pParticle; + + Vector dir = normal * RandomVector( -0.5f, 0.5f ); + + offset = origin + ( 2.0f * normal ); + + pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), hMaterial, offset ); + + if ( pParticle != NULL ) + { + pParticle->m_flLifetime = 0.0f; + pParticle->m_flDieTime = 0.75f; + + pParticle->m_vecVelocity = dir * random->RandomFloat( 16.0f, 32.0f ); + pParticle->m_vecVelocity[2] -= random->RandomFloat( 8.0f, 16.0f ); + + colorRamp = random->RandomFloat( 0.75f, 2.0f ); + + pParticle->m_uchColor[0] = MIN( 1.0f, color[0] * colorRamp ) * 255.0f; + pParticle->m_uchColor[1] = MIN( 1.0f, color[1] * colorRamp ) * 255.0f; + pParticle->m_uchColor[2] = MIN( 1.0f, color[2] * colorRamp ) * 255.0f; + + pParticle->m_uchStartSize = 8; + pParticle->m_uchEndSize = 32; + + pParticle->m_uchStartAlpha = 255; + pParticle->m_uchEndAlpha = 0; + + pParticle->m_flRoll = random->RandomInt( 0, 360 ); + pParticle->m_flRollDelta = 0; + } + + hMaterial = ParticleMgr()->GetPMaterial( "effects/blood_gore" ); + + for ( i = 0; i < 4; i++ ) + { + offset = origin + ( 2.0f * normal ); + + pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), hMaterial, offset ); + + if ( pParticle != NULL ) + { + pParticle->m_flLifetime = 0.0f; + pParticle->m_flDieTime = random->RandomFloat( 0.75f, 1.0f); + + pParticle->m_vecVelocity = dir * random->RandomFloat( 16.0f, 32.0f )*(i+1); + pParticle->m_vecVelocity[2] -= random->RandomFloat( 16.0f, 32.0f )*(i+1); + + colorRamp = random->RandomFloat( 0.75f, 2.0f ); + + pParticle->m_uchColor[0] = MIN( 1.0f, color[0] * colorRamp ) * 255.0f; + pParticle->m_uchColor[1] = MIN( 1.0f, color[1] * colorRamp ) * 255.0f; + pParticle->m_uchColor[2] = MIN( 1.0f, color[2] * colorRamp ) * 255.0f; + + pParticle->m_uchStartSize = scale * random->RandomInt( 4, 8 ); + pParticle->m_uchEndSize = pParticle->m_uchStartSize * 4; + + pParticle->m_uchStartAlpha = 255; + pParticle->m_uchEndAlpha = 0; + + pParticle->m_flRoll = random->RandomInt( 0, 360 ); + pParticle->m_flRollDelta = 0; + } + } + + // + // Dump out drops + // + TrailParticle *tParticle; + + CSmartPtr<CTrailParticles> pTrailEmitter = CTrailParticles::Create( "blooddrops" ); + if ( !pTrailEmitter ) + return; + + pTrailEmitter->SetSortOrigin( origin ); + + // Partial gravity on blood drops + pTrailEmitter->SetGravity( 400.0 ); + + // Enable simple collisions with nearby surfaces + pTrailEmitter->Setup(origin, &normal, 1, 10, 100, 400, 0.2, 0 ); + + hMaterial = ParticleMgr()->GetPMaterial( "effects/blood_drop" ); + + // + // Shorter droplets + // + for ( i = 0; i < 32; i++ ) + { + // Originate from within a circle 'scale' inches in diameter + offset = origin; + + tParticle = (TrailParticle *) pTrailEmitter->AddParticle( sizeof(TrailParticle), hMaterial, offset ); + + if ( tParticle == NULL ) + break; + + tParticle->m_flLifetime = 0.0f; + + offDir = RandomVector( -1.0f, 1.0f ); + + tParticle->m_vecVelocity = offDir * random->RandomFloat( 32.0f, 128.0f ); + + tParticle->m_flWidth = scale * random->RandomFloat( 1.0f, 3.0f ); + tParticle->m_flLength = random->RandomFloat( 0.1f, 0.15f ); + tParticle->m_flDieTime = random->RandomFloat( 0.5f, 1.0f ); + + FloatToColor32( tParticle->m_color, color[0], color[1], color[2], 1.0f ); + } + + // Puff + float spread = 0.2f; + for ( i = 0; i < 4; i++ ) + { + pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), g_Mat_DustPuff[0], origin ); + + if ( pParticle != NULL ) + { + pParticle->m_flLifetime = 0.0f; + pParticle->m_flDieTime = random->RandomFloat( 0.5f, 1.0f ); + + pParticle->m_vecVelocity.Random( -spread, spread ); + pParticle->m_vecVelocity += ( normal * random->RandomFloat( 1.0f, 6.0f ) ); + + VectorNormalize( pParticle->m_vecVelocity ); + + float fForce = random->RandomFloat( 15, 30 ) * i; + + // scaled + pParticle->m_vecVelocity *= fForce; + + colorRamp = random->RandomFloat( 0.75f, 1.25f ); + + pParticle->m_uchColor[0] = MIN( 1.0f, color[0] * colorRamp ) * 255.0f; + pParticle->m_uchColor[1] = MIN( 1.0f, color[1] * colorRamp ) * 255.0f; + pParticle->m_uchColor[2] = MIN( 1.0f, color[2] * colorRamp ) * 255.0f; + + // scaled + pParticle->m_uchStartSize = random->RandomInt( 2, 3 ) * (i+1); + + // scaled + pParticle->m_uchEndSize = pParticle->m_uchStartSize * 4; + + pParticle->m_uchStartAlpha = random->RandomInt( 100, 200 ); + pParticle->m_uchEndAlpha = 0; + + pParticle->m_flRoll = random->RandomInt( 0, 360 ); + pParticle->m_flRollDelta = random->RandomFloat( -8.0f, 8.0f ); + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: Intercepts the blood spray message. +//----------------------------------------------------------------------------- +void DODBloodSprayCallback( const CEffectData &data ) +{ + FX_DOD_BloodSpray( data.m_vOrigin, data.m_vNormal, data.m_flMagnitude ); +} + +DECLARE_CLIENT_EFFECT( "dodblood", DODBloodSprayCallback ); diff --git a/game/client/dod/fx_dod_blood.h b/game/client/dod/fx_dod_blood.h new file mode 100644 index 0000000..83f76bd --- /dev/null +++ b/game/client/dod/fx_dod_blood.h @@ -0,0 +1,20 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef FX_DOD_BLOOD_H +#define FX_DOD_BLOOD_H +#ifdef _WIN32 +#pragma once +#endif + + +void FX_DOD_BloodSpray( + const Vector &origin, + const Vector &normal, + float flDamage ); + + +#endif // FX_DOD_BLOOD_H diff --git a/game/client/dod/fx_dod_ejectbrass.cpp b/game/client/dod/fx_dod_ejectbrass.cpp new file mode 100644 index 0000000..fac9096 --- /dev/null +++ b/game/client/dod/fx_dod_ejectbrass.cpp @@ -0,0 +1,100 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Game-specific impact effect hooks +// +//=============================================================================// +#include "cbase.h" +#include "c_te_effect_dispatch.h" +#include "tempent.h" +#include "c_te_legacytempents.h" +#include "dod_shareddefs.h" + +#define TE_RIFLE_SHELL 1024 +#define TE_PISTOL_SHELL 2048 + +//----------------------------------------------------------------------------- +// Purpose: DOD Eject Brass +//----------------------------------------------------------------------------- +void DOD_EjectBrassCallback( const CEffectData &data ) +{ + int shelltype = data.m_nHitBox; + + Vector vForward, vRight, vUp; + AngleVectors( data.m_vAngles, &vForward, &vRight, &vUp ); + + QAngle vecShellAngles; + VectorAngles( -vUp, vecShellAngles ); + + Vector vecVelocity = random->RandomFloat( 130, 180 ) * vForward + + random->RandomFloat( -30, 30 ) * vRight + + random->RandomFloat( -30, 30 ) * vUp; + + float flLifeTime = 10.0f; + + int hitsound = 0; + model_t *pModel = NULL; + + //should be precached .. oh well + static model_t *pSmallShell = (model_t *)engine->LoadModel( "models/shells/shell_small.mdl" ); + static model_t *pMediumShell = (model_t *)engine->LoadModel( "models/shells/shell_medium.mdl" ); + static model_t *pLargeShell = (model_t *)engine->LoadModel( "models/shells/shell_large.mdl" ); + static model_t *pGarandClip = (model_t *)engine->LoadModel( "models/shells/garand_clip.mdl" ); + + int flags = FTENT_FADEOUT | FTENT_GRAVITY | FTENT_COLLIDEALL | FTENT_HITSOUND | FTENT_ROTATE; + + switch( shelltype ) + { + case EJECTBRASS_PISTOL: + hitsound = TE_PISTOL_SHELL; + pModel = pSmallShell; + break; + case EJECTBRASS_RIFLE: + hitsound = TE_PISTOL_SHELL; + pModel = pMediumShell; + break; + case EJECTBRASS_MG: + case EJECTBRASS_MG_2: + hitsound = TE_RIFLE_SHELL; + pModel = pLargeShell; + break; + case EJECTBRASS_GARANDCLIP: + hitsound = TE_RIFLE_SHELL; + flags &= ~FTENT_COLLIDEALL; + flags |= FTENT_COLLIDEWORLD; + pModel = pGarandClip; + break; + default: + break; + } + + Assert( pModel ); + + C_LocalTempEntity *pTemp = tempents->SpawnTempModel( pModel, data.m_vOrigin, vecShellAngles, vecVelocity, flLifeTime, FTENT_NEVERDIE ); + if ( pTemp == NULL ) + return; + + pTemp->m_vecTempEntAngVelocity[0] = random->RandomFloat(-512,511); + pTemp->m_vecTempEntAngVelocity[1] = random->RandomFloat(-255,255); + pTemp->m_vecTempEntAngVelocity[2] = random->RandomFloat(-255,255); + + pTemp->hitSound = hitsound; + + pTemp->SetGravity( 0.4 ); + + pTemp->m_flSpriteScale = 10; + + pTemp->flags = flags; + + // don't collide with owner + pTemp->clientIndex = data.entindex(); + if ( pTemp->clientIndex < 0 ) + { + pTemp->clientIndex = 0; + } + + // ::ShouldCollide decides what this collides with + pTemp->flags |= FTENT_COLLISIONGROUP; + pTemp->SetCollisionGroup( DOD_COLLISIONGROUP_SHELLS ); +} + +DECLARE_CLIENT_EFFECT( "DOD_EjectBrass", DOD_EjectBrassCallback );
\ No newline at end of file diff --git a/game/client/dod/fx_dod_filmgrain.cpp b/game/client/dod/fx_dod_filmgrain.cpp new file mode 100644 index 0000000..d8b8bcb --- /dev/null +++ b/game/client/dod/fx_dod_filmgrain.cpp @@ -0,0 +1,482 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +#include "cbase.h" + +#include "KeyValues.h" +#include "cdll_client_int.h" +#include "view_scene.h" +#include "viewrender.h" +#include "tier0/icommandline.h" +#include "materialsystem/imesh.h" +#include "materialsystem/imaterial.h" +#include "materialsystem/imaterialsystemhardwareconfig.h" +#include "materialsystem/imaterialvar.h" + +#include "ScreenSpaceEffects.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + + +static float g_flDX7NoiseScale = 4.0f; + +//------------------------------------------------------------------------------ +// Film grain post-processing effect +//------------------------------------------------------------------------------ +struct FilmDustParticle_t +{ + int m_nChannel; + + float m_flPositionX; + float m_flPositionY; + + float m_flWidth; + float m_flHeight; + + int m_nSplotchIndex; + int m_nOrientation; +}; + +class CFilmGrainEffect : public IScreenSpaceEffect +{ +public: + + CFilmGrainEffect( ); + ~CFilmGrainEffect( ); + + void Init( ); + void Shutdown( ); + + void SetParameters( KeyValues *params ); + + void Render( int x, int y, int w, int h ); + + void Enable( bool bEnable ); + bool IsEnabled( ); + +private: + + void DrawSplotch( float x, float y, float width, float height, float u, float v, float uWidth, float vHeight, int orientation, int alpha=255 ); + + bool m_bEnable; + + CMaterialReference m_GrainMaterial; + CMaterialReference m_DustMaterial; + + Vector4D m_NoiseScale; + + int m_nMaxDustParticles; + + float m_flMinDustSize; + float m_flMaxDustSize; + + float m_flChanceOfDust; + + float m_flUpdateRate; + + bool m_bEnableFlicker; + int m_nFlickerAlpha; + + bool m_bSplitScreen; + + int m_nCachedParticleTime; + CUtlVector< FilmDustParticle_t > m_CachedParticles; + + float m_flEffectAlpha; + + IMaterial * m_pFlickerMaterial; +}; + +ADD_SCREENSPACE_EFFECT( CFilmGrainEffect, filmgrain ); + +//------------------------------------------------------------------------------ +// CFilmGrainEffect constructor +//------------------------------------------------------------------------------ +CFilmGrainEffect::CFilmGrainEffect( ) +{ + m_NoiseScale = Vector4D( 0.14f, 0.14f, 0.14f, 0.78f ); + + m_nMaxDustParticles = 3; + + m_flMinDustSize = 0.03f; + m_flMaxDustSize = 0.15f; + + m_flChanceOfDust = 0.75f; + + m_flUpdateRate = 24.0f; + + m_nCachedParticleTime = -1; + + m_bSplitScreen = false; + + m_bEnableFlicker = true; + m_nFlickerAlpha = 90; + + m_flEffectAlpha = 1.0; + + m_pFlickerMaterial = NULL; +} + + +//------------------------------------------------------------------------------ +// CFilmGrainEffect destructor +//------------------------------------------------------------------------------ +CFilmGrainEffect::~CFilmGrainEffect( ) +{ +} + + +//------------------------------------------------------------------------------ +// CFilmGrainEffect init +//------------------------------------------------------------------------------ +void CFilmGrainEffect::Init( ) +{ + KeyValues *pVMTKeyValues = new KeyValues( "filmgrain" ); + pVMTKeyValues->SetString( "$GRAIN_TEXTURE", "Effects/FilmScan256" ); + pVMTKeyValues->SetString( "$SCALEBIAS", "[0.0 0.0 0.0 0.0]" ); + pVMTKeyValues->SetString( "$NOISESCALE", "[0.0 1.0 0.5 1.0]" ); + + m_GrainMaterial.Init( "engine/filmgrain", pVMTKeyValues ); + m_GrainMaterial->Refresh( ); + + pVMTKeyValues = new KeyValues( "filmdust" ); + pVMTKeyValues->SetString( "$DUST_TEXTURE", "Effects/Splotches256" ); + pVMTKeyValues->SetString( "$SCALEBIAS", "[0.0 0.0 0.0 0.0]" ); + pVMTKeyValues->SetString( "$CHANNEL_SELECT", "[1.0 0.0 0.0 0.0]" ); + + m_DustMaterial.Init( "engine/filmdust", pVMTKeyValues ); + m_DustMaterial->Refresh( ); + + m_pFlickerMaterial = materials->FindMaterial( "effects/flicker_128", TEXTURE_GROUP_OTHER, false ); + if ( m_pFlickerMaterial ) + { + m_pFlickerMaterial->AddRef(); + } +} + + +//------------------------------------------------------------------------------ +// CFilmGrainEffect shutdown +//------------------------------------------------------------------------------ +void CFilmGrainEffect::Shutdown( ) +{ + m_DustMaterial.Shutdown(); + m_GrainMaterial.Shutdown(); + + if ( m_pFlickerMaterial ) + { + m_pFlickerMaterial->Release(); + } +} + + +//------------------------------------------------------------------------------ +// CFilmGrainEffect enable +//------------------------------------------------------------------------------ +void CFilmGrainEffect::Enable( bool bEnable ) +{ + m_bEnable = bEnable; +} + +bool CFilmGrainEffect::IsEnabled( ) +{ + return m_bEnable; +} + +//------------------------------------------------------------------------------ +// CFilmGrainEffect SetParameters +//------------------------------------------------------------------------------ +void CFilmGrainEffect::SetParameters( KeyValues *params ) +{ + if( params->FindKey( "split_screen" ) ) + { + int ival = params->GetInt( "split_screen" ); + m_bSplitScreen = ival?true:false; + + extern void EnableHUDFilmDemo( bool bEnable, const char *left_string_id, const char *right_string_id ); + EnableHUDFilmDemo( m_bSplitScreen, "#Valve_FilmDemo_FilmGrain_LeftTitle", "#Valve_FilmDemo_FilmGrain_RightTitle" ); + } + + if( params->FindKey( "noise_scale" ) ) + { + Color noise_color = params->GetColor( "noise_scale" ); + int r, g, b, a; + noise_color.GetColor( r, g, b, a ); + m_NoiseScale.x = r/255.0f;; + m_NoiseScale.y = g/255.0f;; + m_NoiseScale.z = b/255.0f;; + m_NoiseScale.w = a/255.0f;; + } + + if( params->FindKey( "max_dust_particles" ) ) + { + m_nMaxDustParticles = params->GetInt( "max_dust_particles" ); + } + + if( params->FindKey( "min_dust_size" ) ) + { + m_flMinDustSize = params->GetFloat( "min_dust_size" ); + } + + if( params->FindKey( "max_dust_size" ) ) + { + m_flMaxDustSize = params->GetFloat( "max_dust_size" ); + } + + if( params->FindKey( "dust_prob" ) ) + { + m_flChanceOfDust = params->GetFloat( "dust_prob" ); + } + + if( params->FindKey( "update_rate" ) ) + { + m_flUpdateRate = params->GetFloat( "update_rate" ); + } + + if( params->FindKey( "enable_flicker" ) ) + { + m_bEnableFlicker = params->GetInt( "enable_flicker" ); + } + + if( params->FindKey( "flicker_alpha" ) ) + { + m_nFlickerAlpha = params->GetInt( "flicker_alpha" ); + } + + if( params->FindKey( "effect_alpha" ) ) + { + m_flEffectAlpha = params->GetFloat( "effect_alpha" ); + } +} + + +//----------------------------------------------------------------------------- +// Draws a quad to resolve accumulation buffer samples as needed +//----------------------------------------------------------------------------- +void CFilmGrainEffect::DrawSplotch( float x, float y, float flWidth, float flHeight, float u, float v, float uWidth, float vWidth, int orientation, int alpha ) +{ + float flAlpha = ( alpha / 255.0f ) * m_flEffectAlpha; + + float tempU[4] = { u, u, u+uWidth, u+uWidth }; + float tempV[4] = { v, v+vWidth, v+vWidth, v }; + + float _u[4], _v[4]; + for( int i=0;i<4;i++ ) + { + _u[ (i + orientation)%4 ] = tempU[ i ]; + _v[ (i + orientation)%4 ] = tempV[ i ]; + } + + CMatRenderContextPtr pRenderContext( materials ); + IMesh *pMesh = pRenderContext->GetDynamicMesh(); + CMeshBuilder meshBuilder; + + pRenderContext->MatrixMode( MATERIAL_VIEW ); + pRenderContext->PushMatrix(); + pRenderContext->LoadIdentity(); + + pRenderContext->MatrixMode( MATERIAL_PROJECTION ); + pRenderContext->PushMatrix(); + pRenderContext->LoadIdentity(); + + meshBuilder.Begin( pMesh, MATERIAL_QUADS, 1 ); + + meshBuilder.Position3f( x, y, 0.0f ); // Upper left + meshBuilder.TexCoord2f( 0, _u[0], _v[0] ); + meshBuilder.Color4f( 1.0f, 1.0f, 1.0f, flAlpha ); + meshBuilder.AdvanceVertex(); + + meshBuilder.Position3f( x, y+flHeight, 0.0f ); // Lower left + meshBuilder.TexCoord2f( 0, _u[1], _v[1] ); + meshBuilder.Color4f( 1.0f, 1.0f, 1.0f, flAlpha ); + meshBuilder.AdvanceVertex(); + + meshBuilder.Position3f( x+flWidth, y+flHeight, 0.0 ); // Lower right + meshBuilder.TexCoord2f( 0, _u[2], _v[2] ); + meshBuilder.Color4f( 1.0f, 1.0f, 1.0f, flAlpha ); + meshBuilder.AdvanceVertex(); + + meshBuilder.Position3f( x+flWidth, y, 0.0 ); // Upper right + meshBuilder.TexCoord2f( 0, _u[3], _v[3] ); + meshBuilder.Color4f( 1.0f, 1.0f, 1.0f, flAlpha ); + meshBuilder.AdvanceVertex(); + + meshBuilder.End(); + pMesh->Draw(); + + pRenderContext->MatrixMode( MATERIAL_VIEW ); + pRenderContext->PopMatrix(); + + pRenderContext->MatrixMode( MATERIAL_PROJECTION ); + pRenderContext->PopMatrix(); +} + + +//------------------------------------------------------------------------------ +// CFilmGrainEffect render +//------------------------------------------------------------------------------ +void CFilmGrainEffect::Render( int x, int y, int w, int h ) +{ + if( !m_bEnable ) + return; + + int nTime = (int)(gpGlobals->curtime * m_flUpdateRate); + + // Set up random offsets for grain texture + float flBiasU = RandomFloat(); + float flBiasV = RandomFloat(); + float flScaleU = w / 256.0f; + float flScaleV = h / 256.0f; + + flBiasU *= w; + flBiasV *= h; + + int paramCount = m_GrainMaterial->ShaderParamCount(); + IMaterialVar **pParams = m_GrainMaterial->GetShaderParams(); + for( int i=0;i<paramCount;i++ ) + { + IMaterialVar *pVar = pParams[i]; + + // alpha operates from 1.0 -> m_NoiseScale.w + float alpha = 1.0 - ( 1.0 - m_NoiseScale.w ) * m_flEffectAlpha; + + if( !Q_stricmp( pVar->GetName(), "$noisescale" ) ) + { + if( g_pMaterialSystemHardwareConfig->GetDXSupportLevel()<=70 ) + { + pVar->SetVecValue( m_NoiseScale.x*g_flDX7NoiseScale * m_flEffectAlpha, + m_NoiseScale.y*g_flDX7NoiseScale * m_flEffectAlpha, + m_NoiseScale.z*g_flDX7NoiseScale * m_flEffectAlpha, + alpha ); + } + else + { + pVar->SetVecValue( m_NoiseScale.x * m_flEffectAlpha, + m_NoiseScale.y * m_flEffectAlpha, + m_NoiseScale.z * m_flEffectAlpha, + alpha ); + } + } + } + + // Render Effect + CMatRenderContextPtr pRenderContext( materials ); + + pRenderContext->Bind( m_GrainMaterial ); + if( m_bSplitScreen ) + { + DrawSplotch( 0.0f, -1.0f, 2.0f, 2.0f, flBiasU, flBiasV, flScaleU, flScaleV, 0 ); + } + else + { + DrawSplotch( -1.0f, -1.0f, 2.0f, 2.0f, flBiasU, flBiasV, flScaleU, flScaleV, 0 ); + } + + int screenWidth, screenHeight; + pRenderContext->GetRenderTargetDimensions( screenWidth, screenHeight ); + + // Now let's do the flicker + if( m_bEnableFlicker ) + { + if( !IsErrorMaterial( m_pFlickerMaterial ) ) + { + m_pFlickerMaterial->Refresh(); + m_pFlickerMaterial->SetMaterialVarFlag( MATERIAL_VAR_VERTEXALPHA, true ); + pRenderContext->Bind( m_pFlickerMaterial ); + + int nFlickerAlpha = (int)( m_nFlickerAlpha * m_flEffectAlpha ); + + if( !m_bSplitScreen ) + { + DrawSplotch( -1.0f, -1.0f, 2.0f, 2.0f, 0.0f, 1.0f, 1.0f, -1.0f, 0, nFlickerAlpha ); + } + else + { + DrawSplotch( 0.0f, -1.0f, 2.0f, 2.0f, 0.5f, 1.0f, 0.5f, -1.0f, 0, nFlickerAlpha ); + } + } + } + + // Now for some dust particles + if( nTime!=m_nCachedParticleTime ) + { + // Need to regenerate our dust particles + m_CachedParticles.RemoveAll(); + m_nCachedParticleTime = nTime; + + float flDustProb = RandomFloat( 0.0f, 1.0f ); + if( flDustProb < m_flChanceOfDust ) + { + int numDustParticles = RandomInt( 0, m_nMaxDustParticles ); + for( int i=0;i<numDustParticles;i++ ) + { + FilmDustParticle_t particle; + + particle.m_nChannel = RandomInt( 0, 2 ); + + particle.m_flPositionX = RandomFloat( -1.0f, 1.0f ); + particle.m_flPositionY = RandomFloat( -1.0f, 1.0f ); + + particle.m_nOrientation = RandomInt( 0, 3 ); + + particle.m_nSplotchIndex = RandomInt( 0, 15 ); + clamp( particle.m_nSplotchIndex, 0, 15 ); + + particle.m_flHeight = RandomFloat( m_flMinDustSize, m_flMaxDustSize ); + particle.m_flWidth = particle.m_flHeight * (float)screenHeight / (float)screenWidth; + + if( (!m_bSplitScreen) || (particle.m_flPositionX-particle.m_flWidth > 0.0f) ) + { + m_CachedParticles.AddToTail( particle ); + } + } + } + } + + for( int i=0;i<m_CachedParticles.Count();i++ ) + { + FilmDustParticle_t *particle = &m_CachedParticles[i]; + + float channelSelect[4] = { 0.0f, 0.0f, 0.0f, 0.0f }; + channelSelect[ particle->m_nChannel ] = 1.0f; + + paramCount = m_DustMaterial->ShaderParamCount(); + pParams = m_DustMaterial->GetShaderParams(); + for( int i=0;i<paramCount;i++ ) + { + IMaterialVar *pVar = pParams[i]; + + if( !Q_stricmp( pVar->GetName(), "$channel_select" ) ) + { + pVar->SetVecValue( channelSelect[0], channelSelect[1], channelSelect[2], channelSelect[3] ); + } + } + + float flUOffset = (particle->m_nSplotchIndex % 4) / 4.0f; + float flVOffset = (particle->m_nSplotchIndex / 4) / 4.0f; + + pRenderContext->Bind( m_DustMaterial ); + + DrawSplotch( particle->m_flPositionX, particle->m_flPositionY, particle->m_flWidth * m_flEffectAlpha, particle->m_flHeight * m_flEffectAlpha, + flUOffset, flVOffset, 0.25f, 0.25f, particle->m_nOrientation ); + } +} + + +//------------------------------------------------------------------------------ +// Console Interface +//------------------------------------------------------------------------------ +static void EnableFilmGrain( IConVar *pConVar, char const *pOldString, float flOldValue ) +{ + ConVarRef var( pConVar ); + if( var.GetBool() ) + { + g_pScreenSpaceEffects->EnableScreenSpaceEffect( "filmgrain" ); + } + else + { + g_pScreenSpaceEffects->DisableScreenSpaceEffect( "filmgrain" ); + } +} + +static ConVar mat_filmgrain( "mat_filmgrain", "0", FCVAR_CLIENTDLL, "Enable/disable film grain post effect", EnableFilmGrain ); + diff --git a/game/client/dod/fx_dod_impact.cpp b/game/client/dod/fx_dod_impact.cpp new file mode 100644 index 0000000..29de5cb --- /dev/null +++ b/game/client/dod/fx_dod_impact.cpp @@ -0,0 +1,185 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Game-specific impact effect hooks +// +//=============================================================================// +#include "cbase.h" +#include "fx_impact.h" +#include "engine/IEngineSound.h" + +#include "decals.h" +#include "IEffects.h" +#include "fx.h" +#include "c_impact_effects.h" +#include "fx_fleck.h" + +//----------------------------------------------------------------------------- +// This does the actual debris flecks +//----------------------------------------------------------------------------- +#define FLECK_MIN_SPEED 64.0f +#define FLECK_MAX_SPEED 128.0f +#define FLECK_GRAVITY 800.0f +#define FLECK_DAMPEN 0.3f +#define FLECK_ANGULAR_SPRAY 0.6f + +static void FX_Flecks( const Vector& origin, trace_t *trace, char materialType, int iScale ) +{ + Vector color; + GetColorForSurface( trace, &color ); + + Vector spawnOffset = trace->endpos + ( trace->plane.normal * 1.0f ); + + CSmartPtr<CFleckParticles> fleckEmitter = CFleckParticles::Create( "FX_DebrisFlecks", spawnOffset, Vector(5,5,5) ); + + if ( !fleckEmitter ) + return; + + // Handle increased scale + float flMaxSpeed = FLECK_MAX_SPEED * iScale; + float flAngularSpray = MAX( 0.2, FLECK_ANGULAR_SPRAY - ( (float)iScale * 0.2f) ); // More power makes the spray more controlled + + // Setup our collision information + fleckEmitter->m_ParticleCollision.Setup( spawnOffset, &trace->plane.normal, flAngularSpray, FLECK_MIN_SPEED, flMaxSpeed, FLECK_GRAVITY, FLECK_DAMPEN ); + + PMaterialHandle *hMaterial; + + switch ( materialType ) + { + case CHAR_TEX_WOOD: + hMaterial = g_Mat_Fleck_Wood; + break; + + case CHAR_TEX_CONCRETE: + case CHAR_TEX_TILE: + default: + hMaterial = g_Mat_Fleck_Cement; + break; + } + + Vector dir, end; + + float colorRamp; + + int numFlecks = random->RandomInt( 4, 16 ) * iScale; + + FleckParticle *pFleckParticle; + + //Dump out flecks + int i; + for ( i = 0; i < numFlecks; i++ ) + { + pFleckParticle = (FleckParticle *) fleckEmitter->AddParticle( sizeof(FleckParticle), hMaterial[random->RandomInt(0,1)], spawnOffset ); + + if ( pFleckParticle == NULL ) + break; + + pFleckParticle->m_flLifetime = 0.0f; + pFleckParticle->m_flDieTime = 3.0f; + + dir[0] = trace->plane.normal[0] + random->RandomFloat( -flAngularSpray, flAngularSpray ); + dir[1] = trace->plane.normal[1] + random->RandomFloat( -flAngularSpray, flAngularSpray ); + dir[2] = trace->plane.normal[2] + random->RandomFloat( -flAngularSpray, flAngularSpray ); + + pFleckParticle->m_uchSize = random->RandomInt( 1, 2 ); + + pFleckParticle->m_vecVelocity = dir * ( random->RandomFloat( FLECK_MIN_SPEED, flMaxSpeed) * ( 3 - pFleckParticle->m_uchSize ) ); + + pFleckParticle->m_flRoll = random->RandomFloat( 0, 360 ); + pFleckParticle->m_flRollDelta = random->RandomFloat( 0, 360 ); + + colorRamp = random->RandomFloat( 0.75f, 1.25f ); + + pFleckParticle->m_uchColor[0] = MIN( 1.0f, color[0]*colorRamp )*255.0f; + pFleckParticle->m_uchColor[1] = MIN( 1.0f, color[1]*colorRamp )*255.0f; + pFleckParticle->m_uchColor[2] = MIN( 1.0f, color[2]*colorRamp )*255.0f; + } +} + +//----------------------------------------------------------------------------- +// Purpose: Perform custom effects based on the Decal index +//----------------------------------------------------------------------------- +void DOD_PerformCustomEffects( const Vector &vecOrigin, trace_t &tr, const Vector &shotDir, int iMaterial, float flScale ) +{ + // Throw out the effect if any of these are true + if ( tr.surface.flags & (SURF_SKY|SURF_NODRAW|SURF_HINT|SURF_SKIP) ) + return; + + int iScale = (int)flScale; + if ( iScale < 1 ) + iScale = 1; + + // Cement and wood have dust and flecks + if ( ( iMaterial == CHAR_TEX_CONCRETE ) || + ( iMaterial == CHAR_TEX_TILE ) || + ( iMaterial == CHAR_TEX_WOOD ) ) + { + FX_Flecks( vecOrigin, &tr, iMaterial, iScale ); + FX_DustImpact( vecOrigin, &tr, flScale ); + } + else if ( ( iMaterial == CHAR_TEX_DIRT ) || ( iMaterial == CHAR_TEX_SAND ) ) + { + FX_DustImpact( vecOrigin, &tr, flScale ); + } + else if ( ( iMaterial == CHAR_TEX_METAL ) || ( iMaterial == CHAR_TEX_VENT ) ) + { + Vector reflect; + float dot = shotDir.Dot( tr.plane.normal ); + reflect = shotDir + ( tr.plane.normal * ( dot*-2.0f ) ); + + reflect[0] += random->RandomFloat( -0.2f, 0.2f ); + reflect[1] += random->RandomFloat( -0.2f, 0.2f ); + reflect[2] += random->RandomFloat( -0.2f, 0.2f ); + + FX_MetalSpark( vecOrigin, reflect, tr.plane.normal, iScale ); + } + else if ( iMaterial == CHAR_TEX_COMPUTER ) + { + Vector offset = vecOrigin + ( tr.plane.normal * 1.0f ); + + g_pEffects->Sparks( offset ); + } +} + + +//----------------------------------------------------------------------------- +// Purpose: Handle weapon impacts +//----------------------------------------------------------------------------- +void ImpactCallback( const CEffectData &data ) +{ + trace_t tr; + Vector vecOrigin, vecStart, vecShotDir; + int iMaterial, iDamageType, iHitbox; + short nSurfaceProp; + + C_BaseEntity *pEntity = ParseImpactData( data, &vecOrigin, &vecStart, &vecShotDir, nSurfaceProp, iMaterial, iDamageType, iHitbox ); + + if ( !pEntity ) + return; + + // If we hit, perform our custom effects and play the sound + if ( Impact( vecOrigin, vecStart, iMaterial, iDamageType, iHitbox, pEntity, tr ) ) + { + float flScale = 0.75f; + C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer(); + + if ( pPlayer ) + { + float flDistSqr = (vecOrigin - pPlayer->GetAbsOrigin()).LengthSqr(); + + flScale = RemapValClamped( flDistSqr, (400*400), (1000*1000), 0.8, 1.2 ); + } + + // Check for custom effects based on the Decal index + DOD_PerformCustomEffects( vecOrigin, tr, vecShotDir, iMaterial, flScale ); + PlayImpactSound( pEntity, tr, vecOrigin, nSurfaceProp ); + + //Play a ricochet sound some of the time + if( random->RandomInt(1,10) <= 3 && (iDamageType == DMG_BULLET) ) + { + CLocalPlayerFilter filter; + C_BaseEntity::EmitSound( filter, SOUND_FROM_WORLD, "Bounce.Shrapnel", &vecOrigin ); + } + } +} + +DECLARE_CLIENT_EFFECT( "Impact", ImpactCallback ); diff --git a/game/client/dod/fx_dod_knifeslash.cpp b/game/client/dod/fx_dod_knifeslash.cpp new file mode 100644 index 0000000..e08b11f --- /dev/null +++ b/game/client/dod/fx_dod_knifeslash.cpp @@ -0,0 +1,72 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Game-specific impact effect hooks +// +//============================================================================= +#include "cbase.h" +#include "decals.h" +#include "iefx.h" +#include "fx_impact.h" +#include "tempent.h" +#include "c_te_effect_dispatch.h" +#include "c_te_legacytempents.h" + +void KnifeSlash( const CEffectData &data ) +{ + trace_t tr; + Vector vecOrigin, vecStart, vecShotDir; + int iMaterial, iDamageType, iHitbox; + short nSurfaceProp; + + C_BaseEntity *pEntity = ParseImpactData( data, &vecOrigin, &vecStart, &vecShotDir, nSurfaceProp, iMaterial, iDamageType, iHitbox ); + + if( pEntity == NULL ) + return; + + int decalNumber = decalsystem->GetDecalIndexForName( GetImpactDecal( pEntity, iMaterial, iDamageType ) ); + if ( decalNumber == -1 ) + return; + + // vector perpendicular to the slash direction + // so we can align the slash decal to that + Vector vecPerp; + AngleVectors( data.m_vAngles, NULL, &vecPerp, NULL ); + + const ConVar *decals =cvar->FindVar( "r_decals" ); + + if ( decals && decals->GetInt() ) + { + if ( (pEntity->entindex() == 0) && (iHitbox != 0) ) + { + // Setup our shot information + Vector shotDir = vecOrigin - vecStart; + float flLength = VectorNormalize( shotDir ); + Vector traceExt; + VectorMA( vecStart, flLength + 8.0f, shotDir, traceExt ); + + // Special case for world entity with hitbox (that's a static prop): + // In this case, we've hit a static prop. Decal it! + staticpropmgr->AddDecalToStaticProp( vecStart, traceExt, iHitbox - 1, decalNumber, true, tr ); + } + else + { + effects->DecalShoot( decalNumber, + pEntity->entindex(), + pEntity->GetModel(), + pEntity->GetAbsOrigin(), + pEntity->GetAbsAngles(), + vecOrigin, + &vecPerp, + 0 ); + } + + } + + if( Impact( vecOrigin, vecStart, iMaterial, iDamageType, iHitbox, pEntity, tr, data.m_fFlags ) ) + { + // Check for custom effects based on the Decal index + PerformCustomEffects( vecOrigin, tr, vecShotDir, iMaterial, 1.0 ); + } +} + +DECLARE_CLIENT_EFFECT( "KnifeSlash", KnifeSlash ); diff --git a/game/client/dod/fx_dod_muzzleflash.cpp b/game/client/dod/fx_dod_muzzleflash.cpp new file mode 100644 index 0000000..1383642 --- /dev/null +++ b/game/client/dod/fx_dod_muzzleflash.cpp @@ -0,0 +1,135 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#include "cbase.h" +#include "particles_simple.h" +#include "particles_localspace.h" +#include "c_te_effect_dispatch.h" +#include "clienteffectprecachesystem.h" + +#include "fx.h" +#include "r_efx.h" +#include "dlight.h" +#include "dod_shareddefs.h" + +// Precache our effects +CLIENTEFFECT_REGISTER_BEGIN( PrecacheEffect_DOD_MuzzleFlash ) +CLIENTEFFECT_MATERIAL( "sprites/effects/muzzleflash1" ) +CLIENTEFFECT_MATERIAL( "sprites/effects/muzzleflash2" ) +CLIENTEFFECT_REGISTER_END() + +ConVar cl_muzzleflash_dlight_1st( "cl_muzzleflash_dlight_1st", "1" ); + +void TE_DynamicLight( IRecipientFilter& filter, float delay, + const Vector* org, int r, int g, int b, int exponent, float radius, float time, float decay, int nLightIndex = LIGHT_INDEX_TE_DYNAMIC ); + +void DOD_MuzzleFlashCallback( const CEffectData &data ) +{ + CSmartPtr<CLocalSpaceEmitter> pEmitter = + CLocalSpaceEmitter::Create( "DOD_MuzzleFlash", data.m_hEntity, data.m_nAttachmentIndex, 0 ); + + if ( !pEmitter ) + return; + + // SetBBox() manually on the particle system so it doesn't have to be recalculated more than once. + Vector vCenter( 0.0f, 0.0f, 0.0f ); + C_BaseEntity *pEnt = data.GetEntity(); + if ( pEnt ) + { + vCenter = pEnt->WorldSpaceCenter(); + } + else + { + IClientRenderable *pRenderable = data.GetRenderable( ); + if ( pRenderable ) + { + Vector vecMins, vecMaxs; + pRenderable->GetRenderBoundsWorldspace( vecMins, vecMaxs ); + VectorAdd( vecMins, vecMaxs, vCenter ); + vCenter *= 0.5f; + } + } + + Assert( pEmitter ); + pEmitter->GetBinding().SetBBox( vCenter - Vector( 10, 10, 10 ), vCenter + Vector( 10, 10, 10 ) ); + + // haxors - make the clip much shorter so the alpha is not + // changed based on large clip distances + pEmitter->SetNearClip( 0, 5 ); + + Vector vFlashOffset = vec3_origin; + Vector vForward(1,0,0); + int i; + + if( data.m_nHitBox == DOD_MUZZLEFLASH_MG ) //Machine gun + { + SimpleParticle *pParticle = (SimpleParticle *)pEmitter->AddParticle( sizeof( SimpleParticle ), + g_Mat_SMG_Muzzleflash[0], + vFlashOffset ); + Assert( pParticle ); + if( pParticle ) + { + pParticle->m_flLifetime = 0.0f; + pParticle->m_flDieTime = 0.1f; + + pParticle->m_vecVelocity = Vector(0,0,0); + + pParticle->m_uchColor[0] = 255; + pParticle->m_uchColor[1] = 255; + pParticle->m_uchColor[2] = 255; + + pParticle->m_uchStartAlpha = 210.0f; + pParticle->m_uchEndAlpha = 0; + + pParticle->m_uchStartSize = random->RandomFloat( 120, 130 ) * data.m_flMagnitude; + pParticle->m_uchEndSize = pParticle->m_uchStartSize; + pParticle->m_flRoll = 0; + pParticle->m_flRollDelta = 0.0f; + } + } + else + { + for( i=0;i<3;i++ ) + { + //move the three sprites around + + vFlashOffset = vForward * ( (2-i)*6 + 10 ); + + SimpleParticle *pParticle = (SimpleParticle *)pEmitter->AddParticle( sizeof( SimpleParticle ), + g_Mat_SMG_Muzzleflash[1], + vFlashOffset ); + Assert( pParticle ); + if( pParticle ) + { + pParticle->m_flLifetime = 0.0f; + pParticle->m_flDieTime = 0.1f; + + pParticle->m_vecVelocity = vec3_origin; + + pParticle->m_uchColor[0] = 255; + pParticle->m_uchColor[1] = 255; + pParticle->m_uchColor[2] = 255; + + pParticle->m_uchStartAlpha = 100.0f; + pParticle->m_uchEndAlpha = 30; + + pParticle->m_uchStartSize = ( 15.0 + 20.0*i ) * data.m_flMagnitude; + pParticle->m_uchEndSize = pParticle->m_uchStartSize; + pParticle->m_flRoll = random->RandomInt( 0, 360 ); + pParticle->m_flRollDelta = 0.0f; + } + } + } + + // dynamic light temporary entity for the muzzle flash + if ( cl_muzzleflash_dlight_1st.GetBool() ) + { + CPVSFilter filter(pEmitter->GetSortOrigin()); + TE_DynamicLight( filter, 0.0, &(pEmitter->GetSortOrigin()), 255, 192, 64, 5, 70, 0.05, 768 ); + } +} + +DECLARE_CLIENT_EFFECT( "DOD_MuzzleFlash", DOD_MuzzleFlashCallback );
\ No newline at end of file diff --git a/game/client/dod/fx_dod_muzzleflash.h b/game/client/dod/fx_dod_muzzleflash.h new file mode 100644 index 0000000..03275aa --- /dev/null +++ b/game/client/dod/fx_dod_muzzleflash.h @@ -0,0 +1,28 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#include "particles_simple.h" +#include "particles_localspace.h" +#include "fx.h" +#include "c_te_effect_dispatch.h" + +class CMuzzleFlashEmitter_1stPerson : public CLocalSpaceEmitter +{ +public: + DECLARE_CLASS( CMuzzleFlashEmitter_1stPerson, CLocalSpaceEmitter ); + + static CSmartPtr<CMuzzleFlashEmitter_1stPerson> Create( const char *pDebugName, int entIndex, int nAttachment, int fFlags = 0 ); + + virtual void Update( float t ) { BaseClass::Update(t); } + +protected: + CMuzzleFlashEmitter_1stPerson( const char *pDebugName ); + +private: + CMuzzleFlashEmitter_1stPerson( const CMuzzleFlashEmitter_1stPerson & ); + + int m_iMuzzleFlashType; +};
\ No newline at end of file diff --git a/game/client/dod/fx_dod_tracers.cpp b/game/client/dod/fx_dod_tracers.cpp new file mode 100644 index 0000000..1754c80 --- /dev/null +++ b/game/client/dod/fx_dod_tracers.cpp @@ -0,0 +1,152 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Game-specific impact effect hooks +// +//============================================================================= +#include "cbase.h" +#include "fx.h" +#include "c_te_effect_dispatch.h" +#include "tier0/vprof.h" +#include "clientsideeffects.h" +#include "clienteffectprecachesystem.h" +#include "view.h" +#include "collisionutils.h" +#include "SoundEmitterSystem/isoundemittersystembase.h" +#include "engine/IEngineSound.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +CLIENTEFFECT_REGISTER_BEGIN( PrecacheDodTracers ) +CLIENTEFFECT_MATERIAL( "effects/fainttracer" ) +CLIENTEFFECT_MATERIAL( "effects/spark" ) +CLIENTEFFECT_REGISTER_END() + +#define LISTENER_HEIGHT 24 + + +#define TRACER_TYPE_FAINT 4 + +void FX_DoDTracerSound( const Vector &start, const Vector &end, int iTracerType ) +{ + // don't play on very short hits + if ( ( start - end ).Length() < 200 ) + return; + + const char *pszSoundName = "Bullets.DefaultNearmiss"; + float flWhizDist = 64; + Vector vecListenOrigin = MainViewOrigin(); + + switch( iTracerType ) + { + case TRACER_TYPE_DEFAULT: + flWhizDist = 96; + // fall through ! + + default: + { + Ray_t bullet, listener; + bullet.Init( start, end ); + + Vector vecLower = vecListenOrigin; + vecLower.z -= LISTENER_HEIGHT; + listener.Init( vecListenOrigin, vecLower ); + + float s, t; + IntersectRayWithRay( bullet, listener, s, t ); + t = clamp( t, 0, 1 ); + vecListenOrigin.z -= t * LISTENER_HEIGHT; + } + break; + } + + static float flNextWhizTime = 0; + + // Is it time yet? + float dt = flNextWhizTime - gpGlobals->curtime; + if ( dt > 0 ) + return; + + // Did the thing pass close enough to our head? + float vDist = CalcDistanceSqrToLineSegment( vecListenOrigin, start, end ); + if ( vDist >= (flWhizDist * flWhizDist) ) + return; + + CSoundParameters params; + if( C_BaseEntity::GetParametersForSound( pszSoundName, params, NULL ) ) + { + // Get shot direction + Vector shotDir; + VectorSubtract( end, start, shotDir ); + VectorNormalize( shotDir ); + + CLocalPlayerFilter filter; + enginesound->EmitSound( filter, SOUND_FROM_WORLD, CHAN_STATIC, params.soundname, + params.volume, SNDLVL_TO_ATTN(params.soundlevel), 0, params.pitch, 0, &start, &shotDir, NULL); + } + + // Don't play another bullet whiz for this client until this time has run out + flNextWhizTime = gpGlobals->curtime + 0.1f; +} + +void FX_FaintTracer( Vector& start, Vector& end ) +{ + if ( random->RandomInt( 0, 2 ) == 0 ) + { + //Don't make small tracers + float dist; + Vector dir; + int velocity = 5000; + + VectorSubtract( end, start, dir ); + dist = VectorNormalize( dir ); + + float length = random->RandomFloat( 32.0f, 64.0f ); + float life = ( dist + length ) / velocity; //NOTENOTE: We want the tail to finish its run as well + + //Add it + FX_AddDiscreetLine( start, dir, velocity, length, dist, random->RandomFloat( 0.75f, 0.9f ), life, "effects/fainttracer" ); + } + + FX_DoDTracerSound( start, end, TRACER_TYPE_DEFAULT+1 ); //not default! +} + +void FX_BrightTracer( Vector& start, Vector& end ) +{ + //Don't make small tracers + float dist; + Vector dir; + int velocity = 5000; + + VectorSubtract( end, start, dir ); + dist = VectorNormalize( dir ); + + // Don't make short tracers. + float length = random->RandomFloat( 64.0f, 128.0f ); + float life = ( dist + length ) / velocity; //NOTENOTE: We want the tail to finish its run as well + + //Add it + FX_AddDiscreetLine( start, dir, velocity, length, dist, random->RandomFloat( 0.75f, 0.9f ), life, "effects/spark" ); + + FX_DoDTracerSound( start, end, TRACER_TYPE_DEFAULT ); +} + +//----------------------------------------------------------------------------- +// Purpose: Faint Tracer for most dod weapons +//----------------------------------------------------------------------------- +void FaintTracerCallback( const CEffectData &data ) +{ + FX_FaintTracer( (Vector&)data.m_vStart, (Vector&)data.m_vOrigin ); +} + + +//----------------------------------------------------------------------------- +// Purpose: Bright Tracer for Machine Guns +//----------------------------------------------------------------------------- +void BrightTracerCallback( const CEffectData &data ) +{ + FX_BrightTracer( (Vector&)data.m_vStart, (Vector&)data.m_vOrigin ); +} + +DECLARE_CLIENT_EFFECT( "FaintTracer", FaintTracerCallback ); +DECLARE_CLIENT_EFFECT( "BrightTracer", BrightTracerCallback );
\ No newline at end of file |