summaryrefslogtreecommitdiff
path: root/game/client/dod
diff options
context:
space:
mode:
Diffstat (limited to 'game/client/dod')
-rw-r--r--game/client/dod/VGUI/backgroundpanel.cpp677
-rw-r--r--game/client/dod/VGUI/backgroundpanel.h53
-rw-r--r--game/client/dod/VGUI/dodbutton.cpp99
-rw-r--r--game/client/dod/VGUI/dodbutton.h88
-rw-r--r--game/client/dod/VGUI/dodclassmenu.cpp353
-rw-r--r--game/client/dod/VGUI/dodclassmenu.h129
-rw-r--r--game/client/dod/VGUI/dodclientscoreboard.cpp621
-rw-r--r--game/client/dod/VGUI/dodclientscoreboard.h79
-rw-r--r--game/client/dod/VGUI/dodcornercutpanel.cpp245
-rw-r--r--game/client/dod/VGUI/dodcornercutpanel.h66
-rw-r--r--game/client/dod/VGUI/dodmenubackground.cpp89
-rw-r--r--game/client/dod/VGUI/dodmenubackground.h74
-rw-r--r--game/client/dod/VGUI/dodmouseoverpanelbutton.h72
-rw-r--r--game/client/dod/VGUI/dodoverview.cpp977
-rw-r--r--game/client/dod/VGUI/dodoverview.h81
-rw-r--r--game/client/dod/VGUI/dodrandombutton.h93
-rw-r--r--game/client/dod/VGUI/dodspectatorgui.cpp194
-rw-r--r--game/client/dod/VGUI/dodspectatorgui.h46
-rw-r--r--game/client/dod/VGUI/dodteammenu.cpp285
-rw-r--r--game/client/dod/VGUI/dodteammenu.h67
-rw-r--r--game/client/dod/VGUI/dodtextwindow.cpp162
-rw-r--r--game/client/dod/VGUI/dodtextwindow.h52
-rw-r--r--game/client/dod/VGUI/dodviewport.cpp195
-rw-r--r--game/client/dod/VGUI/dodviewport.h49
-rw-r--r--game/client/dod/VGUI/idodviewportmsgs.h25
-rw-r--r--game/client/dod/VGUI/vgui_rootpanel_dod.cpp106
-rw-r--r--game/client/dod/VGUI/vgui_rootpanel_dod.h56
-rw-r--r--game/client/dod/c_dod_basegrenade.cpp107
-rw-r--r--game/client/dod/c_dod_basegrenade.h72
-rw-r--r--game/client/dod/c_dod_baserocket.cpp110
-rw-r--r--game/client/dod/c_dod_bombdispenser.cpp43
-rw-r--r--game/client/dod/c_dod_bombtarget.cpp115
-rw-r--r--game/client/dod/c_dod_bombtarget.h38
-rw-r--r--game/client/dod/c_dod_objective_resource.cpp177
-rw-r--r--game/client/dod/c_dod_objective_resource.h239
-rw-r--r--game/client/dod/c_dod_player.cpp2780
-rw-r--r--game/client/dod/c_dod_player.h284
-rw-r--r--game/client/dod/c_dod_playerresource.cpp53
-rw-r--r--game/client/dod/c_dod_playerresource.h36
-rw-r--r--game/client/dod/c_dod_smokegrenade.cpp141
-rw-r--r--game/client/dod/c_dod_smokegrenade.h38
-rw-r--r--game/client/dod/c_dod_team.cpp143
-rw-r--r--game/client/dod/c_dod_team.h70
-rw-r--r--game/client/dod/c_grenadetrail.cpp301
-rw-r--r--game/client/dod/c_grenadetrail.h100
-rw-r--r--game/client/dod/c_te_firebullets.cpp63
-rw-r--r--game/client/dod/clientmode_dod.cpp556
-rw-r--r--game/client/dod/clientmode_dod.h60
-rw-r--r--game/client/dod/dod_fx_explosions.cpp106
-rw-r--r--game/client/dod/dod_headiconmanager.cpp215
-rw-r--r--game/client/dod/dod_headiconmanager.h45
-rw-r--r--game/client/dod/dod_hud_ammo.cpp508
-rw-r--r--game/client/dod/dod_hud_areacapicon.cpp89
-rw-r--r--game/client/dod/dod_hud_capturepanel.cpp629
-rw-r--r--game/client/dod/dod_hud_capturepanel.h91
-rw-r--r--game/client/dod/dod_hud_chat.cpp533
-rw-r--r--game/client/dod/dod_hud_chat.h74
-rw-r--r--game/client/dod/dod_hud_crosshair.cpp183
-rw-r--r--game/client/dod/dod_hud_crosshair.h58
-rw-r--r--game/client/dod/dod_hud_damageindicator.cpp425
-rw-r--r--game/client/dod/dod_hud_deathnotice.cpp942
-rw-r--r--game/client/dod/dod_hud_deathstats.cpp383
-rw-r--r--game/client/dod/dod_hud_deathstats.h90
-rw-r--r--game/client/dod/dod_hud_freezepanel.cpp667
-rw-r--r--game/client/dod/dod_hud_freezepanel.h122
-rw-r--r--game/client/dod/dod_hud_health.cpp191
-rw-r--r--game/client/dod/dod_hud_hintdisplay.cpp397
-rw-r--r--game/client/dod/dod_hud_history_resource.cpp113
-rw-r--r--game/client/dod/dod_hud_mgheaticon.cpp121
-rw-r--r--game/client/dod/dod_hud_objectiveicons.cpp903
-rw-r--r--game/client/dod/dod_hud_playerstatus_ammo.cpp700
-rw-r--r--game/client/dod/dod_hud_playerstatus_ammo.h79
-rw-r--r--game/client/dod/dod_hud_playerstatus_fireselect.cpp123
-rw-r--r--game/client/dod/dod_hud_playerstatus_fireselect.h45
-rw-r--r--game/client/dod/dod_hud_playerstatus_health.cpp255
-rw-r--r--game/client/dod/dod_hud_playerstatus_health.h78
-rw-r--r--game/client/dod/dod_hud_playerstatus_mgheat.cpp250
-rw-r--r--game/client/dod/dod_hud_playerstatus_mgheat.h95
-rw-r--r--game/client/dod/dod_hud_playerstatus_stamina.cpp172
-rw-r--r--game/client/dod/dod_hud_playerstatus_stamina.h91
-rw-r--r--game/client/dod/dod_hud_playerstatus_tnt.cpp133
-rw-r--r--game/client/dod/dod_hud_playerstatus_tnt.h49
-rw-r--r--game/client/dod/dod_hud_playerstatus_weapon.cpp62
-rw-r--r--game/client/dod/dod_hud_playerstatus_weapon.h28
-rw-r--r--game/client/dod/dod_hud_playerstatuspanel.cpp184
-rw-r--r--game/client/dod/dod_hud_readyrestart.cpp206
-rw-r--r--game/client/dod/dod_hud_restartround.cpp170
-rw-r--r--game/client/dod/dod_hud_scope.cpp225
-rw-r--r--game/client/dod/dod_hud_spec_crosshair.cpp87
-rw-r--r--game/client/dod/dod_hud_spec_crosshair.h49
-rw-r--r--game/client/dod/dod_hud_target_id.cpp193
-rw-r--r--game/client/dod/dod_hud_tnt_pickup.cpp152
-rw-r--r--game/client/dod/dod_hud_tnt_pickup.h45
-rw-r--r--game/client/dod/dod_hud_warmuplabel.cpp149
-rw-r--r--game/client/dod/dod_hud_weaponselection.cpp796
-rw-r--r--game/client/dod/dod_hud_winpanel.cpp526
-rw-r--r--game/client/dod/dod_hud_winpanel.h131
-rw-r--r--game/client/dod/dod_in_main.cpp23
-rw-r--r--game/client/dod/dod_playerstats.cpp344
-rw-r--r--game/client/dod/dod_playerstats.h53
-rw-r--r--game/client/dod/dod_prediction.cpp55
-rw-r--r--game/client/dod/dod_view_scene.cpp333
-rw-r--r--game/client/dod/dod_view_scene.h47
-rw-r--r--game/client/dod/fx_dod_blood.cpp518
-rw-r--r--game/client/dod/fx_dod_blood.h20
-rw-r--r--game/client/dod/fx_dod_ejectbrass.cpp100
-rw-r--r--game/client/dod/fx_dod_filmgrain.cpp482
-rw-r--r--game/client/dod/fx_dod_impact.cpp185
-rw-r--r--game/client/dod/fx_dod_knifeslash.cpp72
-rw-r--r--game/client/dod/fx_dod_muzzleflash.cpp135
-rw-r--r--game/client/dod/fx_dod_muzzleflash.h28
-rw-r--r--game/client/dod/fx_dod_tracers.cpp152
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, &currentdir, &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