summaryrefslogtreecommitdiff
path: root/game/client/tf2
diff options
context:
space:
mode:
Diffstat (limited to 'game/client/tf2')
-rw-r--r--game/client/tf2/ObjectBuildAlphaProxy.cpp117
-rw-r--r--game/client/tf2/ObjectControlPanel.cpp355
-rw-r--r--game/client/tf2/ObjectControlPanel.h135
-rw-r--r--game/client/tf2/ProxyTFPlayer.cpp198
-rw-r--r--game/client/tf2/RespawnWaveVGuiScreen.cpp101
-rw-r--r--game/client/tf2/VGuiScreenVehicleBay.cpp148
-rw-r--r--game/client/tf2/c_basecombatcharacter_tf2.cpp284
-rw-r--r--game/client/tf2/c_basefourwheelvehicle.cpp89
-rw-r--r--game/client/tf2/c_basefourwheelvehicle.h51
-rw-r--r--game/client/tf2/c_baseobject.cpp921
-rw-r--r--game/client/tf2/c_baseobject.h223
-rw-r--r--game/client/tf2/c_basetfplayer.cpp2705
-rw-r--r--game/client/tf2/c_basetfplayer.h386
-rw-r--r--game/client/tf2/c_controlzone.cpp67
-rw-r--r--game/client/tf2/c_controlzone.h39
-rw-r--r--game/client/tf2/c_demo_entities.cpp35
-rw-r--r--game/client/tf2/c_demo_entities.h36
-rw-r--r--game/client/tf2/c_effect_shootingstar.cpp179
-rw-r--r--game/client/tf2/c_effect_shootingstar.h72
-rw-r--r--game/client/tf2/c_entity_burn_effect.cpp85
-rw-r--r--game/client/tf2/c_entity_burn_effect.h44
-rw-r--r--game/client/tf2/c_env_meteor.cpp651
-rw-r--r--game/client/tf2/c_env_meteor.h189
-rw-r--r--game/client/tf2/c_func_construction_yard.cpp42
-rw-r--r--game/client/tf2/c_func_resource.cpp263
-rw-r--r--game/client/tf2/c_func_resource.h57
-rw-r--r--game/client/tf2/c_gasoline_blob.cpp350
-rw-r--r--game/client/tf2/c_gasoline_blob.h107
-rw-r--r--game/client/tf2/c_grenade_antipersonnel.cpp84
-rw-r--r--game/client/tf2/c_grenade_limpetmine.cpp109
-rw-r--r--game/client/tf2/c_grenade_objectsapper.cpp82
-rw-r--r--game/client/tf2/c_grenade_rocket.cpp83
-rw-r--r--game/client/tf2/c_harpoon.cpp95
-rw-r--r--game/client/tf2/c_hint_events.cpp49
-rw-r--r--game/client/tf2/c_hint_events.h62
-rw-r--r--game/client/tf2/c_info_act.cpp196
-rw-r--r--game/client/tf2/c_info_act.h56
-rw-r--r--game/client/tf2/c_info_customtech.cpp51
-rw-r--r--game/client/tf2/c_maker_bughole.cpp109
-rw-r--r--game/client/tf2/c_obj_barbed_wire.cpp110
-rw-r--r--game/client/tf2/c_obj_barbed_wire.h46
-rw-r--r--game/client/tf2/c_obj_base_manned_gun.cpp122
-rw-r--r--game/client/tf2/c_obj_base_manned_gun.h39
-rw-r--r--game/client/tf2/c_obj_buff_station.cpp272
-rw-r--r--game/client/tf2/c_obj_bunker.cpp70
-rw-r--r--game/client/tf2/c_obj_dragonsteeth.cpp44
-rw-r--r--game/client/tf2/c_obj_empgenerator.cpp99
-rw-r--r--game/client/tf2/c_obj_explosives.cpp36
-rw-r--r--game/client/tf2/c_obj_manned_missilelauncher.cpp28
-rw-r--r--game/client/tf2/c_obj_manned_plasmagun.cpp27
-rw-r--r--game/client/tf2/c_obj_manned_shield.cpp27
-rw-r--r--game/client/tf2/c_obj_mapdefined.cpp37
-rw-r--r--game/client/tf2/c_obj_mapdefined.h35
-rw-r--r--game/client/tf2/c_obj_mcv_selection_panel.cpp279
-rw-r--r--game/client/tf2/c_obj_mortar.cpp389
-rw-r--r--game/client/tf2/c_obj_powerpack.cpp340
-rw-r--r--game/client/tf2/c_obj_rallyflag.cpp35
-rw-r--r--game/client/tf2/c_obj_resourcepump.cpp164
-rw-r--r--game/client/tf2/c_obj_resourcepump.h44
-rw-r--r--game/client/tf2/c_obj_respawn_station.cpp38
-rw-r--r--game/client/tf2/c_obj_respawn_station.h39
-rw-r--r--game/client/tf2/c_obj_resupply.cpp151
-rw-r--r--game/client/tf2/c_obj_sandbag_bunker.cpp38
-rw-r--r--game/client/tf2/c_obj_selfheal.cpp36
-rw-r--r--game/client/tf2/c_obj_sentrygun.h106
-rw-r--r--game/client/tf2/c_obj_shieldwall.cpp111
-rw-r--r--game/client/tf2/c_obj_tower.cpp69
-rw-r--r--game/client/tf2/c_obj_tunnel.cpp143
-rw-r--r--game/client/tf2/c_obj_vehicleboost.cpp40
-rw-r--r--game/client/tf2/c_objectsentrygun.cpp558
-rw-r--r--game/client/tf2/c_order.cpp462
-rw-r--r--game/client/tf2/c_order.h73
-rw-r--r--game/client/tf2/c_order_assist.cpp22
-rw-r--r--game/client/tf2/c_order_assist.h32
-rw-r--r--game/client/tf2/c_order_buildsentrygun.cpp26
-rw-r--r--game/client/tf2/c_order_buildsentrygun.h34
-rw-r--r--game/client/tf2/c_order_buildshieldwall.cpp19
-rw-r--r--game/client/tf2/c_order_buildshieldwall.h32
-rw-r--r--game/client/tf2/c_order_heal.cpp22
-rw-r--r--game/client/tf2/c_order_heal.h32
-rw-r--r--game/client/tf2/c_order_killmortarguy.cpp22
-rw-r--r--game/client/tf2/c_order_killmortarguy.h32
-rw-r--r--game/client/tf2/c_order_mortar_attack.cpp22
-rw-r--r--game/client/tf2/c_order_mortar_attack.h32
-rw-r--r--game/client/tf2/c_order_player.cpp38
-rw-r--r--game/client/tf2/c_order_player.h33
-rw-r--r--game/client/tf2/c_order_repair.cpp19
-rw-r--r--game/client/tf2/c_order_repair.h32
-rw-r--r--game/client/tf2/c_order_resourcepump.cpp27
-rw-r--r--game/client/tf2/c_order_resourcepump.h34
-rw-r--r--game/client/tf2/c_order_respawnstation.cpp19
-rw-r--r--game/client/tf2/c_order_respawnstation.h32
-rw-r--r--game/client/tf2/c_order_resupply.cpp19
-rw-r--r--game/client/tf2/c_order_resupply.h32
-rw-r--r--game/client/tf2/c_ragdoll_shadow.cpp246
-rw-r--r--game/client/tf2/c_resource_chunk.cpp22
-rw-r--r--game/client/tf2/c_shield.cpp837
-rw-r--r--game/client/tf2/c_shield.h199
-rw-r--r--game/client/tf2/c_shield_flat.cpp350
-rw-r--r--game/client/tf2/c_shield_mobile.cpp274
-rw-r--r--game/client/tf2/c_tf2rootpanel.cpp194
-rw-r--r--game/client/tf2/c_tf2rootpanel.h63
-rw-r--r--game/client/tf2/c_tf_basecombatweapon.cpp310
-rw-r--r--game/client/tf2/c_tf_basecombatweapon.h47
-rw-r--r--game/client/tf2/c_tf_basehint.cpp691
-rw-r--r--game/client/tf2/c_tf_basehint.h147
-rw-r--r--game/client/tf2/c_tf_class_commando.cpp136
-rw-r--r--game/client/tf2/c_tf_class_commando.h50
-rw-r--r--game/client/tf2/c_tf_class_defender.cpp36
-rw-r--r--game/client/tf2/c_tf_class_defender.h38
-rw-r--r--game/client/tf2/c_tf_class_escort.cpp36
-rw-r--r--game/client/tf2/c_tf_class_escort.h37
-rw-r--r--game/client/tf2/c_tf_class_infiltrator.cpp36
-rw-r--r--game/client/tf2/c_tf_class_infiltrator.h38
-rw-r--r--game/client/tf2/c_tf_class_medic.cpp37
-rw-r--r--game/client/tf2/c_tf_class_medic.h38
-rw-r--r--game/client/tf2/c_tf_class_pyro.cpp44
-rw-r--r--game/client/tf2/c_tf_class_pyro.h41
-rw-r--r--game/client/tf2/c_tf_class_recon.cpp54
-rw-r--r--game/client/tf2/c_tf_class_recon.h37
-rw-r--r--game/client/tf2/c_tf_class_sapper.cpp53
-rw-r--r--game/client/tf2/c_tf_class_sapper.h45
-rw-r--r--game/client/tf2/c_tf_class_sniper.cpp36
-rw-r--r--game/client/tf2/c_tf_class_sniper.h38
-rw-r--r--game/client/tf2/c_tf_class_support.cpp36
-rw-r--r--game/client/tf2/c_tf_class_support.h38
-rw-r--r--game/client/tf2/c_tf_flare.cpp342
-rw-r--r--game/client/tf2/c_tf_hintmanager.cpp427
-rw-r--r--game/client/tf2/c_tf_hintmanager.h87
-rw-r--r--game/client/tf2/c_tf_hints.cpp1468
-rw-r--r--game/client/tf2/c_tf_hints.h38
-rw-r--r--game/client/tf2/c_tf_playerclass.cpp65
-rw-r--r--game/client/tf2/c_tf_playerclass.h50
-rw-r--r--game/client/tf2/c_tfcarrier.cpp30
-rw-r--r--game/client/tf2/c_tfcarrier.h43
-rw-r--r--game/client/tf2/c_tfplayerlocaldata.h50
-rw-r--r--game/client/tf2/c_tfplayerresource.cpp30
-rw-r--r--game/client/tf2/c_tfplayerresource.h30
-rw-r--r--game/client/tf2/c_tfteam.cpp217
-rw-r--r--game/client/tf2/c_tfteam.h62
-rw-r--r--game/client/tf2/c_vehicle_battering_ram.cpp208
-rw-r--r--game/client/tf2/c_vehicle_flatbed.cpp183
-rw-r--r--game/client/tf2/c_vehicle_mortar.cpp869
-rw-r--r--game/client/tf2/c_vehicle_motorcycle.cpp184
-rw-r--r--game/client/tf2/c_vehicle_siege_tower.cpp261
-rw-r--r--game/client/tf2/c_vehicle_tank.cpp150
-rw-r--r--game/client/tf2/c_vehicle_tank.h14
-rw-r--r--game/client/tf2/c_vehicle_teleport_station.cpp168
-rw-r--r--game/client/tf2/c_vehicle_teleport_station.h33
-rw-r--r--game/client/tf2/c_vehicle_wagon.cpp183
-rw-r--r--game/client/tf2/c_walker_base.cpp20
-rw-r--r--game/client/tf2/c_walker_base.h33
-rw-r--r--game/client/tf2/c_walker_ministrider.cpp38
-rw-r--r--game/client/tf2/c_walker_ministrider.h63
-rw-r--r--game/client/tf2/c_walker_strider.cpp218
-rw-r--r--game/client/tf2/c_walker_strider.h71
-rw-r--r--game/client/tf2/c_weapon__stubs_tf2.cpp32
-rw-r--r--game/client/tf2/c_weapon_builder.cpp380
-rw-r--r--game/client/tf2/c_weapon_builder.h63
-rw-r--r--game/client/tf2/c_weapon_chargeableplasma.cpp358
-rw-r--r--game/client/tf2/c_weapon_mortar.cpp634
-rw-r--r--game/client/tf2/c_weapon_twohandedcontainer.cpp166
-rw-r--r--game/client/tf2/clientmode_commander.cpp725
-rw-r--r--game/client/tf2/clientmode_commander.h146
-rw-r--r--game/client/tf2/clientmode_tfbase.cpp223
-rw-r--r--game/client/tf2/clientmode_tfbase.h68
-rw-r--r--game/client/tf2/clientmode_tfnormal.cpp173
-rw-r--r--game/client/tf2/clientmode_tfnormal.h64
-rw-r--r--game/client/tf2/commanderoverlay.cpp220
-rw-r--r--game/client/tf2/commanderoverlay.h153
-rw-r--r--game/client/tf2/commanderoverlaypanel.cpp1018
-rw-r--r--game/client/tf2/commanderoverlaypanel.h143
-rw-r--r--game/client/tf2/env_objecteffects.cpp137
-rw-r--r--game/client/tf2/env_objecteffects.h73
-rw-r--r--game/client/tf2/fx_tf2_blood.cpp347
-rw-r--r--game/client/tf2/fx_tf2_buildeffects.cpp737
-rw-r--r--game/client/tf2/fx_tf2_impacts.cpp453
-rw-r--r--game/client/tf2/fx_tf2_tracers.cpp105
-rw-r--r--game/client/tf2/ground_line.cpp418
-rw-r--r--game/client/tf2/ground_line.h80
-rw-r--r--game/client/tf2/hintitembase.cpp425
-rw-r--r--game/client/tf2/hintitembase.h113
-rw-r--r--game/client/tf2/hintitemobjectbase.cpp79
-rw-r--r--game/client/tf2/hintitemobjectbase.h43
-rw-r--r--game/client/tf2/hintitemorderbase.cpp71
-rw-r--r--game/client/tf2/hintitemorderbase.h37
-rw-r--r--game/client/tf2/hud_ammo.cpp265
-rw-r--r--game/client/tf2/hud_ammo.h52
-rw-r--r--game/client/tf2/hud_commander_statuspanel.cpp414
-rw-r--r--game/client/tf2/hud_commander_statuspanel.h93
-rw-r--r--game/client/tf2/hud_damageindicator.cpp322
-rw-r--r--game/client/tf2/hud_deathnotice.cpp378
-rw-r--r--game/client/tf2/hud_emp.cpp195
-rw-r--r--game/client/tf2/hud_health.cpp217
-rw-r--r--game/client/tf2/hud_minimap.cpp1367
-rw-r--r--game/client/tf2/hud_minimap.h272
-rw-r--r--game/client/tf2/hud_numeric.cpp978
-rw-r--r--game/client/tf2/hud_numeric.h140
-rw-r--r--game/client/tf2/hud_orders.cpp278
-rw-r--r--game/client/tf2/hud_orders.h87
-rw-r--r--game/client/tf2/hud_resources.cpp131
-rw-r--r--game/client/tf2/hud_target_id.cpp230
-rw-r--r--game/client/tf2/hud_targetreticle.cpp183
-rw-r--r--game/client/tf2/hud_targetreticle.h53
-rw-r--r--game/client/tf2/hud_technologytreedoc.cpp175
-rw-r--r--game/client/tf2/hud_technologytreedoc.h49
-rw-r--r--game/client/tf2/hud_timer.cpp298
-rw-r--r--game/client/tf2/hud_timer.h70
-rw-r--r--game/client/tf2/hud_vehicle_role.cpp80
-rw-r--r--game/client/tf2/hud_vehicle_role.h34
-rw-r--r--game/client/tf2/hud_weaponselection.cpp1671
-rw-r--r--game/client/tf2/infiltratorcamomaterialproxy.cpp84
-rw-r--r--game/client/tf2/itfhintitem.h58
-rw-r--r--game/client/tf2/iusesmortarpanel.h69
-rw-r--r--game/client/tf2/mapdata.cpp372
-rw-r--r--game/client/tf2/mapdata.h128
-rw-r--r--game/client/tf2/minimap_players.cpp250
-rw-r--r--game/client/tf2/minimap_resourcezone.cpp95
-rw-r--r--game/client/tf2/minimap_trace.cpp323
-rw-r--r--game/client/tf2/minimap_trace.h153
-rw-r--r--game/client/tf2/overlay_orders.cpp25
-rw-r--r--game/client/tf2/panel_effects.cpp1094
-rw-r--r--game/client/tf2/paneleffect.cpp414
-rw-r--r--game/client/tf2/paneleffect.h166
-rw-r--r--game/client/tf2/playerandobjectenumerator.cpp69
-rw-r--r--game/client/tf2/playerandobjectenumerator.h44
-rw-r--r--game/client/tf2/playeroverlay.cpp368
-rw-r--r--game/client/tf2/playeroverlay.h68
-rw-r--r--game/client/tf2/playeroverlayclass.cpp269
-rw-r--r--game/client/tf2/playeroverlayclass.h72
-rw-r--r--game/client/tf2/playeroverlayhealth.cpp123
-rw-r--r--game/client/tf2/playeroverlayhealth.h47
-rw-r--r--game/client/tf2/playeroverlayname.cpp183
-rw-r--r--game/client/tf2/playeroverlayname.h59
-rw-r--r--game/client/tf2/playeroverlayselected.cpp130
-rw-r--r--game/client/tf2/playeroverlayselected.h46
-rw-r--r--game/client/tf2/playeroverlaysquad.cpp187
-rw-r--r--game/client/tf2/playeroverlaysquad.h54
-rw-r--r--game/client/tf2/proxy_objpower.cpp56
-rw-r--r--game/client/tf2/proxy_shield.cpp313
-rw-r--r--game/client/tf2/proxy_sunroof.cpp72
-rw-r--r--game/client/tf2/resourcezoneoverlay.cpp249
-rw-r--r--game/client/tf2/teammaterialproxy.cpp71
-rw-r--r--game/client/tf2/tf_clientmode.cpp188
-rw-r--r--game/client/tf2/tf_in_main.cpp36
-rw-r--r--game/client/tf2/tf_prediction.cpp245
-rw-r--r--game/client/tf2/vgui_healthbar.cpp134
-rw-r--r--game/client/tf2/vgui_healthbar.h46
-rw-r--r--game/client/tf2/vgui_rootpanel_tf2.cpp41
-rw-r--r--game/client/tf2/vgui_rotation_slider.cpp74
-rw-r--r--game/client/tf2/vgui_rotation_slider.h43
-rw-r--r--game/client/tf2/ztestmaterialproxy.cpp64
252 files changed, 45841 insertions, 0 deletions
diff --git a/game/client/tf2/ObjectBuildAlphaProxy.cpp b/game/client/tf2/ObjectBuildAlphaProxy.cpp
new file mode 100644
index 0000000..a25add8
--- /dev/null
+++ b/game/client/tf2/ObjectBuildAlphaProxy.cpp
@@ -0,0 +1,117 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+#include "cbase.h"
+#include "proxyentity.h"
+#include "materialsystem/imaterial.h"
+#include "materialsystem/imaterialvar.h"
+#include "c_baseobject.h"
+#include <KeyValues.h>
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+class CObjectBuildAlphaProxy : public CEntityMaterialProxy
+{
+public:
+ CObjectBuildAlphaProxy();
+ virtual ~CObjectBuildAlphaProxy();
+ virtual bool Init( IMaterial *pMaterial, KeyValues* pKeyValues );
+ virtual void OnBind( C_BaseEntity *pC_BaseEntity );
+
+private:
+ IMaterialVar* m_pAlphaVar;
+
+ float buildstart;
+ float buildend;
+};
+
+
+//-----------------------------------------------------------------------------
+// Constructor, destructor
+//-----------------------------------------------------------------------------
+
+CObjectBuildAlphaProxy::CObjectBuildAlphaProxy()
+{
+ m_pAlphaVar = 0;
+}
+
+CObjectBuildAlphaProxy::~CObjectBuildAlphaProxy()
+{
+}
+
+//-----------------------------------------------------------------------------
+// Init baby...
+//-----------------------------------------------------------------------------
+bool CObjectBuildAlphaProxy::Init( IMaterial *pMaterial, KeyValues* pKeyValues )
+{
+
+ bool foundVar;
+ m_pAlphaVar = pMaterial->FindVar( "$alpha", &foundVar, false );
+ if( !foundVar )
+ {
+ m_pAlphaVar = 0;
+ }
+
+ buildstart = pKeyValues->GetFloat( "buildstart", 1.0f );
+ buildend = pKeyValues->GetFloat( "buildfinish", 1.0f );
+
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+// Set the appropriate texture...
+//-----------------------------------------------------------------------------
+void CObjectBuildAlphaProxy::OnBind( C_BaseEntity *pEntity )
+{
+ if( !m_pAlphaVar )
+ return;
+
+ // It needs to be a TF2 C_BaseObject to have this proxy applied
+ C_BaseObject *pObject = dynamic_cast< C_BaseObject * >( pEntity );
+ if ( !pObject )
+ return;
+
+ float build_amount = pObject->GetCycle(); //pObject->GetPercentageConstructed();
+ float frac;
+
+ if ( build_amount <= buildstart )
+ {
+ frac = 0.0f;
+ }
+ else if ( build_amount >= buildend )
+ {
+ frac = 1.0f;
+ }
+ else
+ {
+ // Avoid div by zero
+ if ( buildend == buildstart )
+ {
+ frac = 1.0f;
+ }
+ else
+ {
+ frac = ( build_amount - buildstart ) / ( buildend - buildstart );
+ frac = clamp( frac, 0.0f, 1.0f );
+ }
+ }
+
+ if ( !pObject->IsBuilding() )
+ {
+ frac = 1.0f;
+ }
+
+ m_pAlphaVar->SetFloatValue( frac );
+}
+
+EXPOSE_INTERFACE( CObjectBuildAlphaProxy, IMaterialProxy, "TFObjectBuildAlpha" IMATERIAL_PROXY_INTERFACE_VERSION );
+
+
diff --git a/game/client/tf2/ObjectControlPanel.cpp b/game/client/tf2/ObjectControlPanel.cpp
new file mode 100644
index 0000000..eef89b0
--- /dev/null
+++ b/game/client/tf2/ObjectControlPanel.cpp
@@ -0,0 +1,355 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+#include "cbase.h"
+#include "ObjectControlPanel.h"
+#include <vgui_controls/Controls.h>
+#include <vgui_controls/Label.h>
+#include "vgui_bitmapbutton.h"
+#include <vgui/ISurface.h>
+#include <vgui/IVGui.h>
+#include "C_BaseTFPlayer.h"
+#include "clientmode_tfbase.h"
+#include <vgui/IScheme.h>
+#include <vgui_controls/Slider.h>
+#include "vgui_rotation_slider.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+
+#define DISMANTLE_WAIT_TIME 5.0
+
+
+//-----------------------------------------------------------------------------
+// Standard VGUI panel for objects
+//-----------------------------------------------------------------------------
+DECLARE_VGUI_SCREEN_FACTORY( CObjectControlPanel, "object_control_panel" );
+
+
+//-----------------------------------------------------------------------------
+// Constructor:
+//-----------------------------------------------------------------------------
+CObjectControlPanel::CObjectControlPanel( vgui::Panel *parent, const char *panelName )
+ : BaseClass( parent, panelName, g_hVGuiObjectScheme )
+{
+ // Make some high-level panels to group stuff we want to activate/deactivate
+ m_pActivePanel = new CCommandChainingPanel( this, "ActivePanel" );
+ m_pDeterioratingPanel = new CCommandChainingPanel( this, "DeterioratingPanel" );
+ m_pDismantlingPanel = new CCommandChainingPanel( this, "DismantlingPanel" );
+
+ SetCursor( vgui::dc_none ); // don't draw a VGUI cursor for this panel, and for its children
+
+ // Make sure these are behind everything
+ m_pActivePanel->SetZPos( -1 );
+ m_pDeterioratingPanel->SetZPos( -1 );
+ m_pDismantlingPanel->SetZPos( -1 );
+}
+
+
+//-----------------------------------------------------------------------------
+// Initialization
+//-----------------------------------------------------------------------------
+bool CObjectControlPanel::Init( KeyValues* pKeyValues, VGuiScreenInitData_t* pInitData )
+{
+ // Grab ahold of certain well-known controls
+ m_pHealthLabel = new vgui::Label( this, "HealthReadout", "" );
+ m_pOwnerLabel = new vgui::Label( this, "OwnerReadout", "" );
+ m_pDismantleButton = new CBitmapButton( this, "DismantleButton", "Dismantle" );
+ m_pAssumeControlButton = new CBitmapButton( GetDeterioratingPanel(), "AssumeControl", "" );
+ m_pDismantleTimeLabel = new vgui::Label( GetDismantlingPanel(), "DismantleTime", "" );
+
+ m_flDismantleTime = -1;
+
+ // Make sure we get ticked...
+ vgui::ivgui()->AddTickSignal( GetVPanel() );
+
+ if (!BaseClass::Init(pKeyValues, pInitData))
+ return false;
+
+ SetCursor( vgui::dc_none ); // don't draw a VGUI cursor for this panel, and for its children
+
+ // Make the bounds of the sub-panels match
+ int x, y, w, h;
+ GetBounds( x, y, w, h );
+ m_pActivePanel->SetBounds( x, y, w, h );
+ m_pDeterioratingPanel->SetBounds( x, y, w, h );
+ m_pDismantlingPanel->SetBounds( x, y, w, h );
+
+ // Make em all invisible
+ m_pActivePanel->SetVisible( false );
+ m_pDeterioratingPanel->SetVisible( false );
+ m_pDismantlingPanel->SetVisible( false );
+ m_pCurrentPanel = m_pActivePanel;
+
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+// Returns the object it's attached to
+//-----------------------------------------------------------------------------
+C_BaseObject *CObjectControlPanel::GetOwningObject() const
+{
+ C_BaseEntity *pScreenEnt = GetEntity();
+ if (!pScreenEnt)
+ return NULL;
+
+ C_BaseEntity *pObj = pScreenEnt->GetOwnerEntity();
+ if (!pObj)
+ return NULL;
+
+ Assert( dynamic_cast<C_BaseObject*>(pObj) );
+ return static_cast<C_BaseObject*>(pObj);
+}
+
+
+//-----------------------------------------------------------------------------
+// Ticks the panel when its in its various states
+//-----------------------------------------------------------------------------
+
+void CObjectControlPanel::OnTickDeteriorating( C_BaseObject *pObj, C_BaseTFPlayer *pLocalPlayer )
+{
+ char buf[256];
+ if ( pLocalPlayer && ClassCanBuild( pLocalPlayer->PlayerClass(), pObj->GetType() ) )
+ {
+ int nCost = CalculateObjectCost( pObj->GetType(), pLocalPlayer->GetNumObjects( pObj->GetType() ), pLocalPlayer->GetTeamNumber() );
+ Q_snprintf( buf, sizeof( buf ), "Buy for %d", nCost );
+ m_pAssumeControlButton->SetText( buf );
+ m_pAssumeControlButton->SetVisible( true );
+
+ bool bHasEnoughResources = pLocalPlayer->GetBankResources() >= nCost;
+ m_pAssumeControlButton->SetEnabled( bHasEnoughResources );
+ }
+ else
+ {
+ m_pAssumeControlButton->SetVisible( false );
+ }
+
+ ShowDismantleButton( false );
+}
+
+void CObjectControlPanel::OnTickActive( C_BaseObject *pObj, C_BaseTFPlayer *pLocalPlayer )
+{
+ ShowDismantleButton( !(pObj->GetFlags() & OF_CANNOT_BE_DISMANTLED) && pObj->GetOwner() == pLocalPlayer );
+}
+
+void CObjectControlPanel::OnTickDismantling( C_BaseObject *pObj, C_BaseTFPlayer *pLocalPlayer )
+{
+ ShowDismantleButton( false );
+ if ( !m_bDismantled && (gpGlobals->curtime >= m_flDismantleTime))
+ {
+ Dismantle();
+ m_bDismantled = true;
+ }
+
+ int nSec = (int)(m_flDismantleTime - gpGlobals->curtime + 0.5f);
+ if (nSec < 0)
+ nSec = 0;
+
+ char buf[256];
+ int nLen = Q_snprintf( buf, sizeof( buf ), "%d second", nSec );
+ if (nSec != 1)
+ {
+ buf[nLen] = 's';
+ ++nLen;
+ buf[nLen] = 0;
+ }
+
+ m_pDismantleTimeLabel->SetText( buf );
+}
+
+
+vgui::Panel* CObjectControlPanel::TickCurrentPanel()
+{
+ C_BaseTFPlayer *pLocalPlayer = C_BaseTFPlayer::GetLocalPlayer();
+ C_BaseObject *pObj = GetOwningObject();
+
+ if (IsDismantling())
+ {
+ m_pCurrentPanel = GetDismantlingPanel();
+
+ OnTickDismantling(pObj, pLocalPlayer);
+ }
+ else if (pObj->IsDeteriorating())
+ {
+ m_pCurrentPanel = GetDeterioratingPanel();
+
+ OnTickDeteriorating(pObj, pLocalPlayer);
+ }
+ else
+ {
+ m_pCurrentPanel = GetActivePanel();
+
+ OnTickActive(pObj, pLocalPlayer);
+ }
+
+ return m_pCurrentPanel;
+}
+
+
+void CObjectControlPanel::ShowDismantleButton( bool bShow )
+{
+ m_pDismantleButton->SetVisible( bShow );
+}
+
+
+void CObjectControlPanel::ShowOwnerLabel( bool bShow )
+{
+ m_pOwnerLabel->SetVisible( bShow );
+}
+
+
+void CObjectControlPanel::ShowHealthLabel( bool bShow )
+{
+ m_pHealthLabel->SetVisible( bShow );
+}
+
+
+void CObjectControlPanel::SendToServerObject( const char *pMsg )
+{
+ C_BaseObject *pObj = GetOwningObject();
+ if (pObj)
+ {
+ pObj->SendClientCommand( pMsg );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Frame-based update
+//-----------------------------------------------------------------------------
+void CObjectControlPanel::OnTick()
+{
+ BaseClass::OnTick();
+
+ C_BaseObject *pObj = GetOwningObject();
+ if (!pObj)
+ return;
+
+ char buf[256];
+ Q_snprintf( buf, sizeof( buf ), "Health: %d%%", (int)(pObj->HealthFraction() * 100.0f) );
+ m_pHealthLabel->SetText( buf );
+
+ C_BaseTFPlayer *pPlayer = pObj->GetOwner();
+ if (pPlayer)
+ {
+ Q_snprintf( buf, sizeof( buf ), "Owner: %s", pPlayer->GetPlayerName() );
+ }
+ else
+ {
+ Q_snprintf( buf, sizeof( buf ), "No Owner" );
+ }
+
+ m_pOwnerLabel->SetText( buf );
+
+ // Update the current subpanel
+ m_pCurrentPanel->SetVisible( false );
+
+ m_pCurrentPanel = TickCurrentPanel();
+
+ m_pCurrentPanel->SetVisible( true );
+}
+
+
+//-----------------------------------------------------------------------------
+// Dismantles the object
+//-----------------------------------------------------------------------------
+void CObjectControlPanel::Dismantle()
+{
+ SendToServerObject( "dismantle" );
+}
+
+
+//-----------------------------------------------------------------------------
+// Starts/stops dismantling
+//-----------------------------------------------------------------------------
+void CObjectControlPanel::StartDismantling()
+{
+ m_flDismantleTime = gpGlobals->curtime + DISMANTLE_WAIT_TIME;
+ m_bDismantled = false;
+}
+
+void CObjectControlPanel::StopDismantling()
+{
+ m_flDismantleTime = -1.0f;
+}
+
+bool CObjectControlPanel::IsDismantling() const
+{
+ return m_flDismantleTime >= 0.0f;
+}
+
+
+//-----------------------------------------------------------------------------
+// Assumes control of the object
+//-----------------------------------------------------------------------------
+void CObjectControlPanel::AssumeControl()
+{
+ SendToServerObject( "takecontrol" );
+}
+
+
+//-----------------------------------------------------------------------------
+// Button click handlers
+//-----------------------------------------------------------------------------
+void CObjectControlPanel::OnCommand( const char *command )
+{
+ if (!Q_strnicmp(command, "Dismantle", 10))
+ {
+ StartDismantling();
+ return;
+ }
+
+ if (!Q_strnicmp(command, "CancelDismantle", 20))
+ {
+ StopDismantling();
+ return;
+ }
+
+ if (!Q_strnicmp(command, "AssumeControl", 15))
+ {
+ AssumeControl();
+ return;
+ }
+
+ BaseClass::OnCommand(command);
+}
+
+
+DECLARE_VGUI_SCREEN_FACTORY( CRotatingObjectControlPanel, "rotating_object_control_panel" );
+
+
+//-----------------------------------------------------------------------------
+// This is a panel for an object that has rotational controls
+//-----------------------------------------------------------------------------
+CRotatingObjectControlPanel::CRotatingObjectControlPanel( vgui::Panel *parent, const char *panelName )
+ : BaseClass( parent, panelName )
+{
+}
+
+bool CRotatingObjectControlPanel::Init( KeyValues* pKeyValues, VGuiScreenInitData_t* pInitData )
+{
+ // Grab ahold of certain well-known controls
+ m_pRotationSlider = new CRotationSlider( GetActivePanel(), "RotationSlider" );
+ m_pRotationLabel = new vgui::Label( GetActivePanel(), "RotationLabel", "Rotation Control" );
+
+ if (!BaseClass::Init(pKeyValues, pInitData))
+ return false;
+
+ m_pRotationSlider->SetControlledObject( GetOwningObject() );
+
+ return true;
+}
+
+void CRotatingObjectControlPanel::OnTickActive( C_BaseObject *pObj, C_BaseTFPlayer *pLocalPlayer )
+{
+ BaseClass::OnTickActive( pObj, pLocalPlayer );
+ bool bEnable = (pObj->GetOwner() == pLocalPlayer);
+ m_pRotationSlider->SetVisible( bEnable );
+ m_pRotationLabel->SetVisible( bEnable );
+}
+
diff --git a/game/client/tf2/ObjectControlPanel.h b/game/client/tf2/ObjectControlPanel.h
new file mode 100644
index 0000000..c1de4ec
--- /dev/null
+++ b/game/client/tf2/ObjectControlPanel.h
@@ -0,0 +1,135 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Clients CBaseObject
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef OBJECTCONTROLPANEL_H
+#define OBJECTCONTROLPANEL_H
+
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "c_vguiscreen.h"
+
+namespace vgui
+{
+ class Panel;
+ class Label;
+ class Button;
+}
+
+class C_BaseObject;
+class CRotationSlider;
+class C_BaseTFPlayer;
+
+//-----------------------------------------------------------------------------
+// Base class for all vgui screens on objects:
+//-----------------------------------------------------------------------------
+class CObjectControlPanel : public CVGuiScreenPanel
+{
+ DECLARE_CLASS( CObjectControlPanel, CVGuiScreenPanel );
+
+public:
+ CObjectControlPanel( vgui::Panel *parent, const char *panelName );
+
+ virtual bool Init( KeyValues* pKeyValues, VGuiScreenInitData_t* pInitData );
+ virtual void OnCommand( const char *command );
+ virtual void OnTick();
+
+protected:
+ // Method to add controls to particular panels
+ vgui::Panel *GetActivePanel() { return m_pActivePanel; }
+ vgui::Panel *GetDeterioratingPanel() { return m_pDeterioratingPanel; }
+ vgui::Panel *GetDismantlingPanel() { return m_pDismantlingPanel; }
+
+ // Override these to deal with various controls in various modes
+ virtual void OnTickDeteriorating( C_BaseObject *pObj, C_BaseTFPlayer *pLocalPlayer );
+ virtual void OnTickActive( C_BaseObject *pObj, C_BaseTFPlayer *pLocalPlayer );
+ virtual void OnTickDismantling( C_BaseObject *pObj, C_BaseTFPlayer *pLocalPlayer );
+
+ C_BaseObject *GetOwningObject() const;
+
+ // This should update the current panel and return that panel.
+ virtual vgui::Panel* TickCurrentPanel();
+
+ // The dismantle button has its own logic about whether or not to hide itself.
+ // Use this to make it go away.
+ void ShowDismantleButton( bool bShow );
+ void ShowOwnerLabel( bool bShow );
+ void ShowHealthLabel( bool bShow );
+
+ // Send a message to the owner.
+ void SendToServerObject( const char *pMsg );
+
+private:
+ // Operations performed through the controls
+ void AssumeControl();
+ void Dismantle();
+ void StartDismantling();
+ void StopDismantling();
+ bool IsDismantling() const;
+
+ vgui::EditablePanel *m_pActivePanel;
+ vgui::EditablePanel *m_pDeterioratingPanel;
+ vgui::EditablePanel *m_pDismantlingPanel;
+
+ vgui::Label *m_pHealthLabel;
+ vgui::Label *m_pOwnerLabel;
+ vgui::Button *m_pDismantleButton;
+ vgui::Button *m_pAssumeControlButton;
+ vgui::Label *m_pDismantleTimeLabel;
+
+ vgui::Panel *m_pCurrentPanel;
+
+ bool m_bDismantled;
+ float m_flDismantleTime;
+};
+
+
+// This is used for child panels. It forwards the messages to the parent panel.
+class CCommandChainingPanel : public vgui::EditablePanel
+{
+ typedef vgui::EditablePanel BaseClass;
+
+public:
+ CCommandChainingPanel( vgui::Panel *parent, const char *panelName ) :
+ BaseClass( parent, panelName )
+ {
+ SetPaintBackgroundEnabled( false );
+ }
+
+ void OnCommand( const char *command )
+ {
+ BaseClass::OnCommand( command );
+ if (GetParent())
+ {
+ GetParent()->OnCommand(command);
+ }
+ }
+};
+
+
+//-----------------------------------------------------------------------------
+// This is a panel for an object that has rotational controls
+//-----------------------------------------------------------------------------
+class CRotatingObjectControlPanel : public CObjectControlPanel
+{
+ DECLARE_CLASS( CRotatingObjectControlPanel, CObjectControlPanel );
+
+public:
+ CRotatingObjectControlPanel( vgui::Panel *parent, const char *panelName );
+
+ virtual bool Init( KeyValues* pKeyValues, VGuiScreenInitData_t* pInitData );
+
+protected:
+ virtual void OnTickActive( C_BaseObject *pObj, C_BaseTFPlayer *pLocalPlayer );
+
+private:
+ CRotationSlider *m_pRotationSlider;
+ vgui::Label *m_pRotationLabel;
+};
+
+#endif // OBJECTCONTROLPANEL_H
diff --git a/game/client/tf2/ProxyTFPlayer.cpp b/game/client/tf2/ProxyTFPlayer.cpp
new file mode 100644
index 0000000..9d14a34
--- /dev/null
+++ b/game/client/tf2/ProxyTFPlayer.cpp
@@ -0,0 +1,198 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+#include "cbase.h"
+#include "materialsystem/imaterial.h"
+#include "materialsystem/imaterialsystem.h"
+#include <KeyValues.h>
+#include "materialsystem/imaterialvar.h"
+#include "C_BaseTFPlayer.h"
+#include "functionproxy.h"
+#include "C_PlayerResource.h"
+
+
+//-----------------------------------------------------------------------------
+// Returns the player health (from 0 to 1)
+//-----------------------------------------------------------------------------
+class CPlayerHealthProxy : public CResultProxy
+{
+public:
+ bool Init( IMaterial *pMaterial, KeyValues *pKeyValues );
+ void OnBind( void *pEnt );
+
+private:
+ CFloatInput m_Factor;
+};
+
+bool CPlayerHealthProxy::Init( IMaterial *pMaterial, KeyValues *pKeyValues )
+{
+ if (!CResultProxy::Init( pMaterial, pKeyValues ))
+ return false;
+
+ if (!m_Factor.Init( pMaterial, pKeyValues, "scale", 1 ))
+ return false;
+
+ return true;
+}
+
+void CPlayerHealthProxy::OnBind( void *pArg )
+{
+ // NOTE: Player health max is not available on the server...
+ C_BaseEntity *pEntity = BindArgToEntity( pArg );
+ C_BaseTFPlayer* pPlayer = dynamic_cast<C_BaseTFPlayer*>(pEntity);
+ if (!pPlayer)
+ return;
+
+ Assert( m_pResult );
+ SetFloatResult( pPlayer->HealthFraction() * m_Factor.GetFloat() );
+
+ /*
+ // Should we draw their health?
+ // If he's not on our team we can't see it unless we're a command with "targetinginfo".
+ if ( GetLocalTeam() != GetTeam() && !(local->HasNamedTechnology("targetinginfo") && IsLocalPlayerClass(TFCLASS_COMMANDO) ))
+ return drawn;
+ // Don't draw health bars above myself
+ if ( local == this )
+ return drawn;
+ // Don't draw health bars over dead/dying player
+ if ( GetHealth() <= 0 )
+ return drawn;
+
+ return drawn;
+ */
+}
+
+EXPOSE_INTERFACE( CPlayerHealthProxy, IMaterialProxy, "PlayerHealth" IMATERIAL_PROXY_INTERFACE_VERSION );
+
+
+//-----------------------------------------------------------------------------
+// A function that returns the time since last being damaged
+//-----------------------------------------------------------------------------
+class CPlayerDamageTimeProxy : public CResultProxy
+{
+public:
+ bool Init( IMaterial *pMaterial, KeyValues *pKeyValues );
+ void OnBind( void *pEnt );
+
+private:
+ CFloatInput m_Factor;
+};
+
+bool CPlayerDamageTimeProxy::Init( IMaterial *pMaterial, KeyValues *pKeyValues )
+{
+ if (!CResultProxy::Init( pMaterial, pKeyValues ))
+ return false;
+
+ if (!m_Factor.Init( pMaterial, pKeyValues, "scale", 1.0f ))
+ return false;
+
+ return true;
+}
+
+void CPlayerDamageTimeProxy::OnBind( void *pArg )
+{
+ C_BaseEntity *pEntity = BindArgToEntity( pArg );
+
+ // NOTE: Player health max is not available on the server...
+ C_BaseTFPlayer* pPlayer = dynamic_cast<C_BaseTFPlayer*>(pEntity);
+ if (!pPlayer)
+ {
+ SetFloatResult( 10000 * m_Factor.GetFloat() );
+ return;
+ }
+
+ Assert( m_pResult );
+ float dt = gpGlobals->curtime - pPlayer->GetLastDamageTime();
+ SetFloatResult( dt * m_Factor.GetFloat() );
+}
+
+EXPOSE_INTERFACE( CPlayerDamageTimeProxy, IMaterialProxy, "PlayerDamageTime" IMATERIAL_PROXY_INTERFACE_VERSION );
+
+
+//-----------------------------------------------------------------------------
+// A function that returns the time since last being healed
+//-----------------------------------------------------------------------------
+class CPlayerHealTimeProxy : public CResultProxy
+{
+public:
+ bool Init( IMaterial *pMaterial, KeyValues *pKeyValues );
+ void OnBind( void *pEnt );
+
+private:
+ CFloatInput m_Factor;
+};
+
+bool CPlayerHealTimeProxy::Init( IMaterial *pMaterial, KeyValues *pKeyValues )
+{
+ if (!CResultProxy::Init( pMaterial, pKeyValues ))
+ return false;
+
+ if (!m_Factor.Init( pMaterial, pKeyValues, "scale", 1.0f ))
+ return false;
+
+ return true;
+}
+
+void CPlayerHealTimeProxy::OnBind( void *pArg )
+{
+ // NOTE: Player health max is not available on the server...
+ C_BaseEntity *pEntity = BindArgToEntity( pArg );
+ C_BaseTFPlayer* pPlayer = dynamic_cast<C_BaseTFPlayer*>(pEntity);
+ if (!pPlayer)
+ return;
+
+ Assert( m_pResult );
+ float dt = gpGlobals->curtime - pPlayer->GetLastGainHealthTime();
+ SetFloatResult( dt * m_Factor.GetFloat() );
+}
+
+EXPOSE_INTERFACE( CPlayerHealTimeProxy, IMaterialProxy, "PlayerHealTime" IMATERIAL_PROXY_INTERFACE_VERSION );
+
+
+//-----------------------------------------------------------------------------
+// Returns the player score
+//-----------------------------------------------------------------------------
+class CPlayerScoreProxy : public CResultProxy
+{
+public:
+ bool Init( IMaterial *pMaterial, KeyValues *pKeyValues );
+ void OnBind( void *pEntity );
+
+private:
+ CFloatInput m_Factor;
+};
+
+bool CPlayerScoreProxy::Init( IMaterial *pMaterial, KeyValues *pKeyValues )
+{
+ if (!CResultProxy::Init( pMaterial, pKeyValues ))
+ return false;
+
+ if (!m_Factor.Init( pMaterial, pKeyValues, "scale", 1 ))
+ return false;
+
+ return true;
+}
+
+void CPlayerScoreProxy::OnBind( void *pArg )
+{
+ // Find the view angle between the player and this entity....
+ C_BaseEntity *pEntity = BindArgToEntity( pArg );
+ C_BaseTFPlayer* pPlayer = dynamic_cast<C_BaseTFPlayer*>(pEntity);
+ if (!pPlayer)
+ return;
+
+ if ( !g_PR )
+ return;
+
+ int score = g_PR->GetPlayerScore(pPlayer->index);
+
+ Assert( m_pResult );
+ SetFloatResult( score * m_Factor.GetFloat() );
+}
+
+EXPOSE_INTERFACE( CPlayerScoreProxy, IMaterialProxy, "PlayerScore" IMATERIAL_PROXY_INTERFACE_VERSION );
+
+
diff --git a/game/client/tf2/RespawnWaveVGuiScreen.cpp b/game/client/tf2/RespawnWaveVGuiScreen.cpp
new file mode 100644
index 0000000..e9ba442
--- /dev/null
+++ b/game/client/tf2/RespawnWaveVGuiScreen.cpp
@@ -0,0 +1,101 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+#include "cbase.h"
+#include "c_vguiscreen.h"
+#include "clientmode_tfbase.h"
+#include <vgui/IVGui.h>
+#include <vgui_controls/Controls.h>
+#include <vgui_controls/Label.h>
+#include "c_info_act.h"
+
+
+//-----------------------------------------------------------------------------
+// Base class for all vgui screens on objects:
+//-----------------------------------------------------------------------------
+class CRespawnWaveVGuiScreen : public CVGuiScreenPanel
+{
+ DECLARE_CLASS( CRespawnWaveVGuiScreen, CVGuiScreenPanel );
+
+public:
+ CRespawnWaveVGuiScreen( vgui::Panel *parent, const char *panelName );
+
+ virtual bool Init( KeyValues* pKeyValues, VGuiScreenInitData_t* pInitData );
+ virtual void OnTick();
+
+private:
+ vgui::Label *m_pTime1RemainingLabel;
+ vgui::Label *m_pTime2RemainingLabel;
+};
+
+
+//-----------------------------------------------------------------------------
+// Standard VGUI panel for objects
+//-----------------------------------------------------------------------------
+DECLARE_VGUI_SCREEN_FACTORY( CRespawnWaveVGuiScreen, "respawn_wave_screen" );
+
+
+//-----------------------------------------------------------------------------
+// Constructor:
+//-----------------------------------------------------------------------------
+CRespawnWaveVGuiScreen::CRespawnWaveVGuiScreen( vgui::Panel *parent, const char *panelName )
+ : BaseClass( parent, panelName, g_hVGuiObjectScheme )
+{
+}
+
+
+//-----------------------------------------------------------------------------
+// Initialization
+//-----------------------------------------------------------------------------
+bool CRespawnWaveVGuiScreen::Init( KeyValues* pKeyValues, VGuiScreenInitData_t* pInitData )
+{
+ // Load all of the controls in
+ if (!BaseClass::Init(pKeyValues, pInitData))
+ return false;
+
+ // Make sure we get ticked...
+ vgui::ivgui()->AddTickSignal( GetVPanel() );
+
+ // Grab ahold of certain well-known controls
+ // NOTE: it is valid for these controls to not exist!
+ m_pTime1RemainingLabel = dynamic_cast<vgui::Label*>(FindChildByName( "RespawnTime1Remaining" ));
+ m_pTime2RemainingLabel = dynamic_cast<vgui::Label*>(FindChildByName( "RespawnTime2Remaining" ));
+
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+// Frame-based update
+//-----------------------------------------------------------------------------
+void CRespawnWaveVGuiScreen::OnTick()
+{
+ BaseClass::OnTick();
+
+ if (!GetEntity())
+ return;
+
+ int nTime1Remaining = 0;
+ int nTime2Remaining = 0;
+ if (g_hCurrentAct.Get())
+ {
+ nTime1Remaining = g_hCurrentAct->RespawnTimeRemaining( GetEntity()->GetTeamNumber(), 1 );
+ nTime2Remaining = g_hCurrentAct->RespawnTimeRemaining( GetEntity()->GetTeamNumber(), 2 );
+ }
+
+ char buf[32];
+ if (m_pTime1RemainingLabel)
+ {
+ Q_snprintf( buf, sizeof( buf ), "%d", nTime1Remaining );
+ m_pTime1RemainingLabel->SetText( buf );
+ }
+ if (m_pTime2RemainingLabel)
+ {
+ Q_snprintf( buf, sizeof( buf ), "%d", nTime2Remaining );
+ m_pTime2RemainingLabel->SetText( buf );
+ }
+}
+
diff --git a/game/client/tf2/VGuiScreenVehicleBay.cpp b/game/client/tf2/VGuiScreenVehicleBay.cpp
new file mode 100644
index 0000000..cf8cce9
--- /dev/null
+++ b/game/client/tf2/VGuiScreenVehicleBay.cpp
@@ -0,0 +1,148 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+#include "cbase.h"
+#include "c_vguiscreen.h"
+#include "clientmode_tfbase.h"
+#include <vgui/IVGui.h>
+#include <vgui_controls/Controls.h>
+#include <vgui_controls/Label.h>
+#include "vgui_bitmapbutton.h"
+#include "c_info_act.h"
+#include "tf_shareddefs.h"
+#include "c_basetfplayer.h"
+
+int g_ValidVehicles[] =
+{
+ OBJ_WAGON,
+ OBJ_BATTERING_RAM,
+ OBJ_VEHICLE_TANK,
+ OBJ_VEHICLE_TELEPORT_STATION,
+ OBJ_WALKER_STRIDER,
+ OBJ_WALKER_MINI_STRIDER
+
+ // If you add a new vehicle here, you have to add a button for it to the screen_vehicle_bay.res file.
+ // The button's name must be VehicleButton%d, where %d is it's index into this array.
+ // Then add the build%d command to OnCommand at the bottom of this file.
+};
+
+#define NUM_VEHICLES ARRAYSIZE(g_ValidVehicles)
+
+//-----------------------------------------------------------------------------
+// Vgui screen handling vehicle selection in vehicle bays
+//-----------------------------------------------------------------------------
+class CVehicleBayVGuiScreen : public CVGuiScreenPanel
+{
+ DECLARE_CLASS( CVehicleBayVGuiScreen, CVGuiScreenPanel );
+
+public:
+ CVehicleBayVGuiScreen( vgui::Panel *parent, const char *panelName );
+
+ virtual bool Init( KeyValues* pKeyValues, VGuiScreenInitData_t* pInitData );
+ virtual void OnTick();
+ virtual void OnCommand( const char *command );
+
+private:
+ vgui::Button *m_pVehicleButtons[ NUM_VEHICLES ];
+};
+
+
+//-----------------------------------------------------------------------------
+// Standard VGUI panel for objects
+//-----------------------------------------------------------------------------
+DECLARE_VGUI_SCREEN_FACTORY( CVehicleBayVGuiScreen, "vehicle_bay_screen" );
+
+
+//-----------------------------------------------------------------------------
+// Constructor:
+//-----------------------------------------------------------------------------
+CVehicleBayVGuiScreen::CVehicleBayVGuiScreen( vgui::Panel *parent, const char *panelName )
+ : BaseClass( parent, panelName, g_hVGuiObjectScheme )
+{
+}
+
+
+//-----------------------------------------------------------------------------
+// Initialization
+//-----------------------------------------------------------------------------
+bool CVehicleBayVGuiScreen::Init( KeyValues* pKeyValues, VGuiScreenInitData_t* pInitData )
+{
+ // Create our vehicle buttons
+ for ( int i = 0; i < NUM_VEHICLES; i++ )
+ {
+ char ch[128];
+ Q_snprintf( ch, sizeof(ch), "VehicleButton%d", i );
+ m_pVehicleButtons[i] = new CBitmapButton( this, ch, "Name" );
+ }
+
+ // Load all of the controls in
+ if (!BaseClass::Init(pKeyValues, pInitData))
+ return false;
+
+ // Make sure we get ticked...
+ vgui::ivgui()->AddTickSignal( GetVPanel() );
+
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// Frame-based update
+//-----------------------------------------------------------------------------
+void CVehicleBayVGuiScreen::OnTick()
+{
+ BaseClass::OnTick();
+
+ if (!GetEntity())
+ return;
+
+ C_BaseTFPlayer *pLocalPlayer = C_BaseTFPlayer::GetLocalPlayer();
+ if ( !pLocalPlayer )
+ return;
+
+ int nBankResources = pLocalPlayer ? pLocalPlayer->GetBankResources() : 0;
+
+ // Set the vehicles costs
+ for ( int i = 0; i < NUM_VEHICLES; i++ )
+ {
+ if ( !m_pVehicleButtons[i] )
+ continue;
+
+ char buf[128];
+ int iCost = CalculateObjectCost( g_ValidVehicles[i], pLocalPlayer->GetNumObjects( g_ValidVehicles[i] ), pLocalPlayer->GetTeamNumber() );
+ Q_snprintf( buf, sizeof( buf ), "%s : %d", GetObjectInfo( g_ValidVehicles[i] )->m_pStatusName, iCost );
+ m_pVehicleButtons[i]->SetText( buf );
+ // Can't build if the game hasn't started
+ if ( CurrentActIsAWaitingAct() )
+ {
+ m_pVehicleButtons[i]->SetEnabled( false );
+ }
+ else
+ {
+ m_pVehicleButtons[i]->SetEnabled( nBankResources >= iCost );
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Button click handlers
+//-----------------------------------------------------------------------------
+void CVehicleBayVGuiScreen::OnCommand( const char *command )
+{
+ if (!Q_strnicmp(command, "build", 5))
+ {
+ int iButton;
+ int nCount = sscanf( command, "build%d", &iButton );
+ if (nCount == 1)
+ {
+ char szbuf[64];
+ Q_snprintf( szbuf, sizeof( szbuf ), "buildvehicle %d %d", GetEntity()->entindex(), g_ValidVehicles[iButton] );
+ engine->ClientCmd(szbuf);
+ return;
+ }
+ }
+
+ BaseClass::OnCommand(command);
+}
diff --git a/game/client/tf2/c_basecombatcharacter_tf2.cpp b/game/client/tf2/c_basecombatcharacter_tf2.cpp
new file mode 100644
index 0000000..87df975
--- /dev/null
+++ b/game/client/tf2/c_basecombatcharacter_tf2.cpp
@@ -0,0 +1,284 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: TF2 Specific C_BaseCombatCharacter code.
+//
+//=============================================================================//
+#include "cbase.h"
+#include "c_basecombatcharacter.h"
+#include "tf_shareddefs.h"
+#include "particles_simple.h"
+#include "functionproxy.h"
+#include "IEffects.h"
+#include "weapon_combatshield.h"
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void C_BaseCombatCharacter::Release( void )
+{
+ RemoveAllPowerups();
+
+ BaseClass::Release();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void C_BaseCombatCharacter::SetDormant( bool bDormant )
+{
+ // If we're going dormant, stop all our powerup sounds
+ if ( bDormant )
+ {
+ RemoveAllPowerups();
+ }
+ else
+ {
+ // Restart any powerups on him
+ for ( int i = 0; i < MAX_POWERUPS; i++ )
+ {
+ if ( m_iPowerups & (1 << i) )
+ {
+ PowerupStart( i, false );
+ }
+ }
+ }
+
+ BaseClass::SetDormant( bDormant );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : updateType -
+//-----------------------------------------------------------------------------
+void C_BaseCombatCharacter::OnPreDataChanged( DataUpdateType_t updateType )
+{
+ BaseClass::OnPreDataChanged( updateType );
+
+ m_iPrevPowerups = m_iPowerups;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void C_BaseCombatCharacter::OnDataChanged( DataUpdateType_t updateType )
+{
+ BaseClass::OnDataChanged( updateType );
+
+ if ( updateType == DATA_UPDATE_CREATED )
+ {
+ SetNextClientThink( CLIENT_THINK_ALWAYS );
+ }
+
+ // Power state changed?
+ if ( m_iPowerups != m_iPrevPowerups )
+ {
+ for ( int i = 0; i < MAX_POWERUPS; i++ )
+ {
+ bool bPoweredNow = ( m_iPowerups & (1 << i) );
+ bool bPoweredThen = ( m_iPrevPowerups & (1 << i) );
+
+ if ( !bPoweredThen && bPoweredNow )
+ {
+ PowerupStart( i, true );
+ }
+ else if ( bPoweredThen && !bPoweredNow )
+ {
+ PowerupEnd( i );
+ }
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Powerup has just started
+// If bInitial is set, the server's just told us this powerup has come on.
+// If it's false, the entity had it on when it left PVS, and now it's re-entered
+//-----------------------------------------------------------------------------
+void C_BaseCombatCharacter::PowerupStart( int iPowerup, bool bInitial )
+{
+ Assert( iPowerup >= 0 && iPowerup < MAX_POWERUPS );
+
+ switch( iPowerup )
+ {
+ case POWERUP_BOOST:
+ break;
+
+ case POWERUP_EMP:
+ {
+ // Play the EMP sound
+ if ( !bInitial )
+ {
+ EmitSound( "BaseCombatCharacter.EMPPulse" );
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Powerup has just finished
+//-----------------------------------------------------------------------------
+void C_BaseCombatCharacter::PowerupEnd( int iPowerup )
+{
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void C_BaseCombatCharacter::RemoveAllPowerups( void )
+{
+ // Stop any powerups we have
+ if ( m_iPowerups )
+ {
+ for ( int i = 0; i < MAX_POWERUPS; i++ )
+ {
+ if ( m_iPowerups & (1 << i) )
+ {
+ PowerupEnd( i );
+ }
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void C_BaseCombatCharacter::ClientThink( void )
+{
+ BaseClass::ClientThink();
+
+ if ( !IsDormant() )
+ {
+ if ( HasPowerup(POWERUP_EMP) )
+ {
+ AddEMPEffect( WorldAlignSize().Length() * 0.15 );
+ }
+
+ if ( HasPowerup(POWERUP_BOOST) )
+ {
+ AddBuffEffect( WorldAlignSize().Length() * 0.15 );
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Draw an effect to show this entity has been EMPed
+//-----------------------------------------------------------------------------
+void C_BaseCombatCharacter::AddEMPEffect( float flSize )
+{
+ // Don't draw on the local player
+ if ( this == C_BasePlayer::GetLocalPlayer() )
+ return;
+
+ CSmartPtr<CSimpleEmitter> pEmitter;
+ PMaterialHandle hParticleMaterial;
+ TimedEvent pParticleEvent;
+
+ pParticleEvent.Init( 300 );
+ pEmitter = CSimpleEmitter::Create( "ObjectEMPEffect" );
+ hParticleMaterial = pEmitter->GetPMaterial( "sprites/chargeball" );
+
+ // Add particles
+ float flCur = gpGlobals->frametime;
+ Vector vCenter = WorldSpaceCenter( );
+
+ while ( pParticleEvent.NextEvent( flCur ) )
+ {
+ Vector vPos;
+ Vector vOffset = RandomVector( -1, 1 );
+ VectorNormalize( vOffset );
+ vPos = vCenter + (vOffset * RandomFloat( 0, flSize ));
+
+ pEmitter->SetSortOrigin( vPos );
+ SimpleParticle *pParticle = pEmitter->AddSimpleParticle( hParticleMaterial, vPos );
+ if ( pParticle )
+ {
+ // Move the points along the path.
+ pParticle->m_vecVelocity.Init();
+ pParticle->m_flRoll = 0;
+ pParticle->m_flRollDelta = 0;
+ pParticle->m_flDieTime = 0.4f;
+ pParticle->m_flLifetime = 0;
+ pParticle->m_uchColor[0] = 255;
+ pParticle->m_uchColor[1] = 255;
+ pParticle->m_uchColor[2] = 255;
+ pParticle->m_uchStartAlpha = 32;
+ pParticle->m_uchEndAlpha = 0;
+ pParticle->m_uchStartSize = 4;
+ pParticle->m_uchEndSize = 2;
+ pParticle->m_iFlags = 0;
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Draw an effect to show this entity is being buffed
+//-----------------------------------------------------------------------------
+void C_BaseCombatCharacter::AddBuffEffect( float flSize )
+{
+ // Don't draw on the local player
+ if ( this == C_BasePlayer::GetLocalPlayer() )
+ return;
+
+ CSmartPtr<CSimpleEmitter> pEmitter;
+ PMaterialHandle hParticleMaterial;
+ TimedEvent pParticleEvent;
+
+ pParticleEvent.Init( 300 );
+ pEmitter = CSimpleEmitter::Create( "ObjectBuffEffect" );
+ hParticleMaterial = pEmitter->GetPMaterial( "sprites/chargeball" );
+
+ // Add particles
+ float flCur = gpGlobals->frametime;
+ Vector vCenter = WorldSpaceCenter( );
+
+ while ( pParticleEvent.NextEvent( flCur ) )
+ {
+ Vector vPos;
+ Vector vOffset = RandomVector( -1, 1 );
+ VectorNormalize( vOffset );
+ vPos = vCenter + (vOffset * RandomFloat( 0, flSize ));
+
+ SimpleParticle *pParticle = pEmitter->AddSimpleParticle( hParticleMaterial, vPos );
+ if ( pParticle )
+ {
+ // Move the points along the path.
+ pParticle->m_vecVelocity.Init();
+ pParticle->m_flRoll = 0;
+ pParticle->m_flRollDelta = 0;
+ pParticle->m_flDieTime = 0.4f;
+ pParticle->m_flLifetime = 0;
+ pParticle->m_uchColor[1] = 255; pParticle->m_uchColor[0] = pParticle->m_uchColor[2] = 0;
+ pParticle->m_uchStartAlpha = 128;
+ pParticle->m_uchEndAlpha = 0;
+ pParticle->m_uchStartSize = 3;
+ pParticle->m_uchEndSize = 1;
+ pParticle->m_iFlags = 0;
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Returns shield if owned.
+//-----------------------------------------------------------------------------
+C_WeaponCombatShield *C_BaseCombatCharacter::GetShield( void )
+{
+ C_BaseCombatWeapon *pWeapon;
+ if ( GetTeamNumber() == TEAM_ALIENS )
+ {
+ pWeapon = Weapon_OwnsThisType( "weapon_combat_shield_alien" );
+ }
+ else
+ {
+ pWeapon = Weapon_OwnsThisType( "weapon_combat_shield" );
+ }
+
+ if ( !pWeapon )
+ return NULL;
+
+ return ( CWeaponCombatShield* )pWeapon;
+}
diff --git a/game/client/tf2/c_basefourwheelvehicle.cpp b/game/client/tf2/c_basefourwheelvehicle.cpp
new file mode 100644
index 0000000..88b98e3
--- /dev/null
+++ b/game/client/tf2/c_basefourwheelvehicle.cpp
@@ -0,0 +1,89 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+#include "cbase.h"
+#include "C_BaseFourWheelVehicle.h"
+
+IMPLEMENT_CLIENTCLASS_DT(C_BaseTFFourWheelVehicle, DT_BaseTFFourWheelVehicle, CBaseTFFourWheelVehicle)
+ RecvPropFloat( RECVINFO( m_flDeployFinishTime ) ),
+ RecvPropInt( RECVINFO( m_eDeployMode ) ),
+ RecvPropInt( RECVINFO( m_bBoostUpgrade ) ),
+ RecvPropInt( RECVINFO( m_nBoostTimeLeft ) ),
+END_RECV_TABLE()
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+C_BaseTFFourWheelVehicle::C_BaseTFFourWheelVehicle()
+{
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+float C_BaseTFFourWheelVehicle::GetDeployFinishTime() const
+{
+ return m_flDeployFinishTime;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+VehicleModeDeploy_e C_BaseTFFourWheelVehicle::GetVehicleModeDeploy() const
+{
+ return m_eDeployMode;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void C_BaseTFFourWheelVehicle::OnDataChanged( DataUpdateType_t updateType )
+{
+ BaseClass::OnDataChanged( updateType );
+
+ if ( updateType == DATA_UPDATE_CREATED )
+ {
+ // Start thinking (Baseclass stops it)
+ ClientThinkList()->SetNextClientThink( GetClientHandle(), CLIENT_THINK_ALWAYS );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Restricts the view within a range of the center...
+//-----------------------------------------------------------------------------
+void C_BaseTFFourWheelVehicle::RestrictView( int nRole, float flMinYaw, float flMaxYaw, QAngle &vecViewAngles )
+{
+ Assert( nRole >= 0 );
+ Vector vehicleEyeOrigin;
+ QAngle vehicleEyeAngles;
+ GetRoleViewPosition( nRole, &vehicleEyeOrigin, &vehicleEyeAngles );
+
+ // Confine the view to the appropriate yaw range...
+ float flCenterYaw = vehicleEyeAngles[YAW];
+
+ // View angles are dealt with in absolute terms here...
+ float flAngleDiff = AngleDiff( vecViewAngles[YAW], flCenterYaw );
+
+ // Here, we must clamp to the cone...
+ if (flAngleDiff < flMinYaw)
+ vecViewAngles[YAW] = anglemod(flCenterYaw + flMinYaw);
+ else if (flAngleDiff > flMaxYaw)
+ vecViewAngles[YAW] = anglemod(flCenterYaw + flMaxYaw);
+}
+
+
+//-----------------------------------------------------------------------------
+// Clamps the view angles while driving the vehicle
+//-----------------------------------------------------------------------------
+void C_BaseTFFourWheelVehicle::UpdateViewAngles( C_BasePlayer *pLocalPlayer, CUserCmd *pCmd )
+{
+ int nRole = GetPassengerRole( pLocalPlayer );
+ if ( nRole != VEHICLE_ROLE_DRIVER )
+ {
+ RestrictView( nRole, -90, 90, pCmd->viewangles );
+ }
+}
+
diff --git a/game/client/tf2/c_basefourwheelvehicle.h b/game/client/tf2/c_basefourwheelvehicle.h
new file mode 100644
index 0000000..5ccbcaf
--- /dev/null
+++ b/game/client/tf2/c_basefourwheelvehicle.h
@@ -0,0 +1,51 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef C_BASE_FOUR_WHEEL_VEHICLE_H
+#define C_BASE_FOUR_WHEEL_VEHICLE_H
+
+#include "basetfvehicle.h"
+
+class C_BasePlayer;
+
+class C_BaseTFFourWheelVehicle : public C_BaseTFVehicle
+{
+ DECLARE_CLASS( C_BaseTFFourWheelVehicle, C_BaseTFVehicle );
+ DECLARE_CLIENTCLASS();
+
+public:
+
+ C_BaseTFFourWheelVehicle();
+
+ float GetDeployFinishTime() const;
+ VehicleModeDeploy_e GetVehicleModeDeploy() const;
+
+ // TF2 vehicles are animated by the server
+ virtual bool IsSelfAnimating() { return false; };
+
+ virtual void OnDataChanged( DataUpdateType_t updateType );
+
+// IClientVehicle overrides.
+public:
+ virtual void UpdateViewAngles( C_BasePlayer *pLocalPlayer, CUserCmd *pCmd );
+
+protected:
+ // Restricts the view within a range of the center...
+ void RestrictView( int nRole, float flMinYaw, float flMaxYaw, QAngle &vecViewAngles );
+
+private:
+
+ C_BaseTFFourWheelVehicle( const C_BaseTFFourWheelVehicle & ); // not defined, not accessible
+
+private:
+
+ // Used to draw deploy timer on vgui screens.
+ float m_flDeployFinishTime;
+ VehicleModeDeploy_e m_eDeployMode;
+};
+
+#endif // C_BASE_FOUR_WHEEL_VEHICLE_H \ No newline at end of file
diff --git a/game/client/tf2/c_baseobject.cpp b/game/client/tf2/c_baseobject.cpp
new file mode 100644
index 0000000..491dba9
--- /dev/null
+++ b/game/client/tf2/c_baseobject.cpp
@@ -0,0 +1,921 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Clients CBaseObject
+//
+// $NoKeywords: $
+//=============================================================================//
+#include "cbase.h"
+#include "c_baseobject.h"
+#include "c_basetfplayer.h"
+#include "hud.h"
+#include "c_tfteam.h"
+#include "engine/IEngineSound.h"
+#include "particles_simple.h"
+#include "functionproxy.h"
+#include "IEffects.h"
+#include "c_hint_events.h"
+#include "model_types.h"
+#include "particlemgr.h"
+#include "particle_collision.h"
+#include "env_objecteffects.h"
+#include "basetfvehicle.h"
+#include "c_weapon_builder.h"
+#include "ivrenderview.h"
+#include "ObjectControlPanel.h"
+#include "engine/ivmodelinfo.h"
+#include "c_te_effect_dispatch.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+#define MAX_VISIBLE_BUILDPOINT_DISTANCE (400 * 400)
+
+// Remove aliasing of name due to shared code
+#undef CBaseObject
+
+IMPLEMENT_CLIENTCLASS_DT(C_BaseObject, DT_BaseObject, CBaseObject)
+ RecvPropInt(RECVINFO(m_iHealth)),
+ RecvPropInt(RECVINFO(m_iMaxHealth)),
+ RecvPropInt(RECVINFO(m_bHasSapper)),
+ RecvPropInt(RECVINFO(m_iObjectType)),
+ RecvPropInt(RECVINFO(m_bBuilding)),
+ RecvPropInt(RECVINFO(m_bPlacing)),
+ RecvPropFloat(RECVINFO(m_flPercentageConstructed)),
+ RecvPropInt(RECVINFO(m_fObjectFlags)),
+ RecvPropInt(RECVINFO(m_bDeteriorating)),
+ RecvPropEHandle(RECVINFO(m_hBuiltOnEntity)),
+ RecvPropInt(RECVINFO( m_takedamage ) ),
+ RecvPropInt( RECVINFO( m_bDisabled ) ),
+ RecvPropEHandle( RECVINFO( m_hBuilder ) ),
+END_RECV_TABLE()
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+C_BaseObject::C_BaseObject( )
+{
+ m_flDamageFlash = 0;
+ m_YawPreviewState = YAW_PREVIEW_OFF;
+ m_bBuilding = false;
+ m_bPlacing = false;
+ m_flPercentageConstructed = 0;
+ m_flNextEffect = 0;
+ m_bOldSapper = m_bHasSapper = false;
+ m_fObjectFlags = 0;
+ m_bDeteriorating = false;
+ m_ThermalMaterial.Init("player/thermal/thermal",TEXTURE_GROUP_CLIENT_EFFECTS);
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+C_BaseObject::~C_BaseObject( void )
+{
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void C_BaseObject::PreDataUpdate( DataUpdateType_t updateType )
+{
+ BaseClass::PreDataUpdate( updateType );
+
+ m_iOldHealth = m_iHealth;
+ m_bOldSapper = m_bHasSapper;
+ m_hOldOwner = GetOwner();
+ m_bWasActive = ShouldBeActive();
+ m_bWasBuilding = m_bBuilding;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void C_BaseObject::OnDataChanged( DataUpdateType_t updateType )
+{
+ if (updateType == DATA_UPDATE_CREATED)
+ {
+ if ( !IS_MINIMAP_PANEL_DEFINED( ) && !(m_fObjectFlags & OF_SUPPRESS_APPEAR_ON_MINIMAP) )
+ {
+ CONSTRUCT_MINIMAP_PANEL( "minimap_object", MINIMAP_OBJECTS );
+ }
+
+ CreateBuildPoints();
+ }
+
+ BaseClass::OnDataChanged( updateType );
+
+ // Did we just finish building?
+ if ( m_bWasBuilding && !m_bBuilding )
+ {
+ FinishedBuilding();
+ }
+
+ // Did we just go active?
+ bool bShouldBeActive = ShouldBeActive();
+ if ( !m_bWasActive && bShouldBeActive )
+ {
+ OnGoActive();
+ }
+ else if ( m_bWasActive && !bShouldBeActive )
+ {
+ OnGoInactive();
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void C_BaseObject::SetDormant( bool bDormant )
+{
+ BaseClass::SetDormant( bDormant );
+ //ENTITY_PANEL_ACTIVATE( "analyzed_object", !bDormant );
+}
+
+#define TF_OBJ_BODYGROUPTURNON 1
+#define TF_OBJ_BODYGROUPTURNOFF 0
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : origin -
+// angles -
+// event -
+// *options -
+//-----------------------------------------------------------------------------
+void C_BaseObject::FireEvent( const Vector& origin, const QAngle& angles, int event, const char *options )
+{
+ switch ( event )
+ {
+ default:
+ {
+ BaseClass::FireEvent( origin, angles, event, options );
+ }
+ break;
+ case TF_OBJ_PLAYBUILDSOUND:
+ {
+ EmitSound( options );
+ }
+ break;
+ case TF_OBJ_ENABLEBODYGROUP:
+ {
+ int index = FindBodygroupByName( options );
+ if ( index >= 0 )
+ {
+ SetBodygroup( index, TF_OBJ_BODYGROUPTURNON );
+ }
+ }
+ break;
+ case TF_OBJ_DISABLEBODYGROUP:
+ {
+ int index = FindBodygroupByName( options );
+ if ( index >= 0 )
+ {
+ SetBodygroup( index, TF_OBJ_BODYGROUPTURNOFF );
+ }
+ }
+ break;
+ case TF_OBJ_ENABLEALLBODYGROUPS:
+ case TF_OBJ_DISABLEALLBODYGROUPS:
+ {
+ // Start at 1, because body 0 is the main .mdl body...
+ // Is this the way we want to do this?
+ int count = GetNumBodyGroups();
+ for ( int i = 1; i < count; i++ )
+ {
+ int subpartcount = GetBodygroupCount( i );
+ if ( subpartcount == 2 )
+ {
+ SetBodygroup( i,
+ ( event == TF_OBJ_ENABLEALLBODYGROUPS ) ?
+ TF_OBJ_BODYGROUPTURNON : TF_OBJ_BODYGROUPTURNOFF );
+ }
+ else
+ {
+ DevMsg( "TF_OBJ_ENABLE/DISABLEBODY GROUP: %s has a group with %i subparts, should be exactly 2\n",
+ GetClassname(), subpartcount );
+ }
+ }
+ }
+ break;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+bool C_BaseObject::OffsetObjectOrigin( Vector& origin )
+{
+ if ( !m_bBuilding )
+ return false;
+
+ if ( inv_demo.GetBool() )
+ return false;
+
+ Vector vecWorldMins, vecWorldMaxs;
+ CollisionProp()->WorldSpaceAABB( &vecWorldMins, &vecWorldMaxs );
+ float flSize = vecWorldMaxs.z - vecWorldMins.z;
+ origin.z -= (flSize * (1 - m_flPercentageConstructed));
+
+ // If we're building, fake sliding the object out of the ground
+ return true;
+}
+
+
+const char* C_BaseObject::GetStatusName() const
+{
+ return GetObjectInfo( GetType() )->m_pStatusName;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+int C_BaseObject::DrawModel( int flags )
+{
+ Vector vRealOrigin = GetLocalOrigin();
+ Vector vOrigin = vRealOrigin;
+ bool needOriginReset = OffsetObjectOrigin( vOrigin );
+ if ( needOriginReset )
+ {
+ SetLocalOrigin( vOrigin );
+ InvalidateBoneCache();
+ }
+
+ int drawn;
+ C_BaseTFPlayer *pLocal = C_BaseTFPlayer::GetLocalPlayer();
+ if ( pLocal && pLocal->IsUsingThermalVision() )
+ {
+ modelrender->ForcedMaterialOverride( m_ThermalMaterial );
+ drawn = BaseClass::DrawModel(flags);
+ modelrender->ForcedMaterialOverride( NULL );
+ }
+ else
+ {
+ // If we're a brush-built, map-defined object chain up to baseentity draw
+ if ( modelinfo->GetModelType( GetModel() ) == mod_brush )
+ {
+ drawn = CBaseEntity::DrawModel(flags);
+ }
+ else
+ {
+ drawn = BaseClass::DrawModel(flags);
+ }
+ }
+
+ // Restore faked origin
+ if ( needOriginReset )
+ {
+ SetLocalOrigin( vRealOrigin );
+ }
+
+ // If we were drawn, draw building effects if we're building, or damage effects if we're damaged
+ if ( drawn && (m_flNextEffect < gpGlobals->curtime) )
+ {
+ // Haxory LOD
+ C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
+ if ( (GetAbsOrigin() - pPlayer->GetAbsOrigin()).LengthSqr() < lod_effect_distance.GetFloat() )
+ {
+ if ( IsBuilding() )
+ {
+ DrawBuildEffects();
+ }
+ if ( !m_bPlacing && !m_bBuilding )
+ {
+ if ( !HasPowerup( POWERUP_EMP ) )
+ {
+ DrawRunningEffects();
+ }
+
+ if ( GetHealth() < GetMaxHealth() )
+ {
+ DrawDamageEffects();
+ }
+ }
+ }
+ }
+
+ HighlightBuildPoints( flags );
+
+ return drawn;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void C_BaseObject::HighlightBuildPoints( int flags )
+{
+ C_BaseTFPlayer *pLocal = C_BaseTFPlayer::GetLocalPlayer();
+ if ( !pLocal )
+ return;
+
+ if ( !GetNumBuildPoints() || !InLocalTeam() )
+ return;
+
+ C_WeaponBuilder *pBuilderWpn = dynamic_cast< C_WeaponBuilder * >( pLocal->GetActiveWeaponForSelection() );
+ if ( !pBuilderWpn )
+ return;
+ if ( !pBuilderWpn->IsPlacingObject() )
+ return;
+ C_BaseObject *pPlacementObj = pBuilderWpn->GetPlacementModel();
+ if ( !pPlacementObj || pPlacementObj == this )
+ return;
+
+ // Near enough?
+ if ( (GetAbsOrigin() - pLocal->GetAbsOrigin()).LengthSqr() < MAX_VISIBLE_BUILDPOINT_DISTANCE )
+ {
+ bool bRestoreModel = false;
+ Vector vecPrevAbsOrigin = pPlacementObj->GetAbsOrigin();
+ QAngle vecPrevAbsAngles = pPlacementObj->GetAbsAngles();
+
+ Vector orgColor;
+ render->GetColorModulation( orgColor.Base() );
+ float orgBlend = render->GetBlend();
+
+ // Any empty buildpoints?
+ for ( int i = 0; i < GetNumBuildPoints(); i++ )
+ {
+ // Can this object build on this point?
+ if ( CanBuildObjectOnBuildPoint( i, pPlacementObj->GetType() ) )
+ {
+ Vector vecBPOrigin;
+ QAngle vecBPAngles;
+ if ( GetBuildPoint(i, vecBPOrigin, vecBPAngles) )
+ {
+ pPlacementObj->InvalidateBoneCaches();
+
+ Vector color( 0, 255, 0 );
+ render->SetColorModulation( color.Base() );
+ float frac = fmod( gpGlobals->curtime, 3 );
+ frac *= 2 * M_PI;
+ frac = cos( frac );
+ render->SetBlend( (175 + (int)( frac * 75.0f )) / 255.0 );
+
+ // HACK: Fixup angles on the HL2 model we're using
+ if ( !strcmp( modelinfo->GetModelName( pPlacementObj->GetModel() ), "models/items/HealthKit.mdl" ) )
+ {
+ vecBPAngles.x += 90;
+ }
+
+ // FIXME: This truly sucks! The bone cache should use
+ // render location for this computation instead of directly accessing AbsAngles
+ // Necessary for bone cache computations to work
+ pPlacementObj->SetAbsOrigin( vecBPOrigin );
+ pPlacementObj->SetAbsAngles( vecBPAngles );
+
+
+ modelrender->DrawModel(
+ flags,
+ pPlacementObj,
+ pPlacementObj->GetModelInstance(),
+ pPlacementObj->index,
+ pPlacementObj->GetModel(),
+ vecBPOrigin,
+ vecBPAngles,
+ pPlacementObj->m_nSkin,
+ pPlacementObj->m_nBody,
+ pPlacementObj->m_nHitboxSet
+ );
+
+ bRestoreModel = true;
+ }
+ }
+ }
+
+ if ( bRestoreModel )
+ {
+ pPlacementObj->SetAbsOrigin(vecPrevAbsOrigin);
+ pPlacementObj->SetAbsAngles(vecPrevAbsAngles);
+ pPlacementObj->InvalidateBoneCaches();
+
+ render->SetColorModulation( orgColor.Base() );
+ render->SetBlend( orgBlend );
+ }
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Exit points for mounted vehicles....
+//-----------------------------------------------------------------------------
+void C_BaseObject::GetExitPoint( CBaseEntity *pPlayer, int nBuildPoint, Vector *pAbsPosition, QAngle *pAbsAngles )
+{
+ Assert(0);
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Overridden to allow for brush-built map defined objects
+//-----------------------------------------------------------------------------
+bool C_BaseObject::IsIdentityBrush( void )
+{
+ return false;
+}
+
+//-----------------------------------------------------------------------------
+// Builder preview...
+//-----------------------------------------------------------------------------
+void C_BaseObject::ActivateYawPreview( bool enable )
+{
+ m_YawPreviewState = enable ? YAW_PREVIEW_ON : YAW_PREVIEW_WAITING_FOR_UPDATE;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void C_BaseObject::PreviewYaw( float yaw )
+{
+ m_fYawPreview = yaw;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+bool C_BaseObject::IsPreviewingYaw() const
+{
+ return m_YawPreviewState != YAW_PREVIEW_OFF;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: This is called to get the initial builder yaw...
+//-----------------------------------------------------------------------------
+float C_BaseObject::GetInitialBuilderYaw()
+{
+ return GetAbsAngles().y;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void C_BaseObject::PostDataUpdate( DataUpdateType_t updateType )
+{
+ BaseClass::PostDataUpdate( updateType );
+
+ bool bNewEntity = (updateType == DATA_UPDATE_CREATED);
+ if ( bNewEntity )
+ {
+ m_flAttackTime = -1000;
+ }
+
+ // Determine if we're under attack
+ if ( !bNewEntity )
+ {
+ if ( m_iHealth < m_iOldHealth )
+ {
+ // Deteriorating objects don't play sounds
+ if ( !IsDeteriorating() )
+ {
+ m_flAttackTime = gpGlobals->curtime;
+ }
+ }
+ else if ( m_iHealth > m_iOldHealth && m_iHealth == m_iMaxHealth )
+ {
+ // If we were just fully healed, remove all decals
+ RemoveAllDecals();
+ }
+ }
+
+ if ( m_bHasSapper )
+ {
+ // Play a specific sound for a sapper...
+ if ( m_bOldSapper != m_bHasSapper )
+ {
+ // Don't create these for dragonsteeth
+ if ( InLocalTeam() && GetType() != OBJ_DRAGONSTEETH )
+ {
+ // Play a sound.
+ CLocalPlayerFilter filter;
+ EmitSound( filter, SOUND_FROM_LOCAL_PLAYER, "BaseObject.SapperDestroyingTeamBuilding" );
+
+ MinimapCreateTempTrace( "minimap_under_attack", MINIMAP_PERSONAL_ORDERS, GetAbsOrigin() );
+ }
+ }
+ }
+
+ // Notify the hint system of the object being built.
+ if ( bNewEntity && GetOwner() && ( GetOwner() == C_BasePlayer::GetLocalPlayer() ) )
+ {
+ C_HintEvent_ObjectBuiltByLocalPlayer event( this );
+ GlobalHintEvent( &event );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void C_BaseObject::Release( void )
+{
+ // Remove any reticles on this entity
+ C_BaseTFPlayer *pPlayer = C_BaseTFPlayer::GetLocalPlayer();
+ if ( pPlayer )
+ {
+ pPlayer->Remove_Target( this );
+ }
+
+ BaseClass::Release();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+bool C_BaseObject::IsUnderAttack( )
+{
+ // It's under attack for the 3 seconds after the last attack time
+ return (gpGlobals->curtime - m_flAttackTime) < 5.0f;
+}
+
+//-----------------------------------------------------------------------------
+// Ownership:
+//-----------------------------------------------------------------------------
+C_BaseTFPlayer *C_BaseObject::GetOwner()
+{
+ return m_hBuilder;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+bool C_BaseObject::IsOwnedByLocalPlayer() const
+{
+ if ( !m_hBuilder )
+ return false;
+
+ return ( m_hBuilder == C_BaseTFPlayer::GetLocalPlayer() );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Add entity to visibile entities list
+//-----------------------------------------------------------------------------
+void C_BaseObject::AddEntity( void )
+{
+ // If set to invisible, skip. Do this before resetting the entity pointer so it has
+ // valid data to decide whether it's visible.
+ if ( !ShouldDraw() )
+ {
+ return;
+ }
+
+ // Update the entity position
+ UpdatePosition();
+
+ // Yaw preview
+ if (m_YawPreviewState != YAW_PREVIEW_OFF)
+ {
+ // This piece of code makes it so we keep using the preview
+ // until we get a network update which matches the update value
+ if (m_YawPreviewState == YAW_PREVIEW_WAITING_FOR_UPDATE)
+ {
+ if (fmod( fabs(GetLocalAngles().y - m_fYawPreview), 360.0f) < 1.0f)
+ {
+ m_YawPreviewState = YAW_PREVIEW_OFF;
+ }
+ }
+
+ if (GetLocalOrigin().y != m_fYawPreview)
+ {
+ SetLocalAnglesDim( Y_INDEX, m_fYawPreview );
+ InvalidateBoneCache();
+ }
+ }
+
+ // Create flashlight effects, etc.
+ CreateLightEffects();
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void C_BaseObject::Select( void )
+{
+ C_BaseTFPlayer *pPlayer = C_BaseTFPlayer::GetLocalPlayer();
+ pPlayer->SetSelectedObject( this );
+}
+
+//-----------------------------------------------------------------------------
+// Sends client commands back to the server:
+//-----------------------------------------------------------------------------
+void C_BaseObject::SendClientCommand( const char *pCmd )
+{
+ char szbuf[128];
+ Q_snprintf( szbuf, sizeof( szbuf ), "objcmd %d %s", entindex(), pCmd );
+ engine->ClientCmd(szbuf);
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Get a text description for the object target
+//-----------------------------------------------------------------------------
+const char *C_BaseObject::GetTargetDescription( void ) const
+{
+ return GetStatusName();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Get a text description for the object target (more verbose)
+//-----------------------------------------------------------------------------
+char *C_BaseObject::GetIDString( void )
+{
+ m_szIDString[0] = 0;
+ RecalculateIDString();
+ return m_szIDString;
+}
+
+
+//-----------------------------------------------------------------------------
+// It's a valid ID target when it's building
+//-----------------------------------------------------------------------------
+bool C_BaseObject::IsValidIDTarget( void )
+{
+ return InSameTeam( C_BaseTFPlayer::GetLocalPlayer() ) && m_bBuilding;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void C_BaseObject::RecalculateIDString( void )
+{
+ // Subclasses may have filled this out with a string
+ if ( !m_szIDString[0] )
+ {
+ Q_strncpy( m_szIDString, GetTargetDescription(), sizeof(m_szIDString) );
+ }
+
+ // Have I taken damage?
+ if ( m_iHealth < m_iMaxHealth )
+ {
+ char szHealth[ MAX_ID_STRING ];
+ if ( IsDeteriorating() )
+ {
+ Q_snprintf( szHealth, sizeof(szHealth), "\nBUILDER LOST, DETERIORATING... %.0f percent", ceil(((float)m_iHealth / (float)m_iMaxHealth) * 100) );
+ }
+ else if ( m_bBuilding )
+ {
+ Q_snprintf( szHealth, sizeof(szHealth), "\nConstruction at %.0f percent\nHealth at %.0f percent", (m_flPercentageConstructed * 100), ceil(((float)m_iHealth / (float)m_iMaxHealth) * 100) );
+ }
+ else
+ {
+ Q_snprintf( szHealth, sizeof(szHealth), "\nHealth at %.0f percent", ceil(((float)m_iHealth / (float)m_iMaxHealth) * 100) );
+ }
+ Q_strncat( m_szIDString, szHealth, sizeof(m_szIDString), COPY_ALL_CHARACTERS );
+ }
+
+ if ( m_bHasSapper )
+ {
+ Q_strncat( m_szIDString, "\nUse it to remove the attached enemy object", sizeof(m_szIDString), COPY_ALL_CHARACTERS );
+ }
+
+ // If it's deteriorating, and I can buy it, tell me
+ C_BaseTFPlayer *pLocalPlayer = C_BaseTFPlayer::GetLocalPlayer();
+ if ( IsDeteriorating() && pLocalPlayer && ClassCanBuild( pLocalPlayer->PlayerClass(), GetType() ) )
+ {
+ char szBuy[ MAX_ID_STRING ];
+ int iCost = CalculateObjectCost( GetType(), pLocalPlayer->GetNumObjects( GetType() ), pLocalPlayer->GetTeamNumber() );
+ Q_snprintf( szBuy, sizeof(szBuy), "\nBUY THIS OBJECT FOR %d RESOURCES", iCost );
+ Q_strncat( m_szIDString, szBuy, sizeof(m_szIDString), COPY_ALL_CHARACTERS );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Effects created when the object's running
+//-----------------------------------------------------------------------------
+void C_BaseObject::DrawRunningEffects( void )
+{
+ if ( !GetMaxHealth() )
+ return;
+
+ // Get the overall damage percentage
+ float flDamaged = 1.0 - ((float)GetHealth() / (float)GetMaxHealth());
+
+ // Damage attachment points
+ int iSmokeAttachment, iSparkAttachment;
+ Vector vecSmoke, vecSpark, vecSmokeDir, dir;
+ QAngle angSmoke, angSpark;
+
+ // Look for damage points
+ iSmokeAttachment = LookupRandomAttachment( "r_smoke" );
+
+ // Get the points
+ if ( GetAttachment( iSmokeAttachment, vecSmoke, angSmoke ) )
+ {
+ AngleVectors( angSmoke, &vecSmokeDir);
+
+ float r, g, b;
+ r = g = b = random->RandomFloat( 16, 92 );
+
+ // Smoke
+ CSmartPtr<CObjectSmokeParticles> pSmokeEmitter = CObjectSmokeParticles::Create( "DrawRunningEffects 1" );
+ pSmokeEmitter->SetSortOrigin( vecSmoke );
+ ObjectSmokeParticle *pParticle = (ObjectSmokeParticle *) pSmokeEmitter->AddParticle( sizeof(ObjectSmokeParticle), g_Mat_DustPuff[1], vecSmoke );
+ if ( pParticle )
+ {
+ pParticle->m_flLifetime = 0.0f;
+ pParticle->m_flDieTime = random->RandomFloat( 2.0f, 3.0f );
+ pParticle->m_uchStartSize = random->RandomFloat( 2, 3 );
+ pParticle->m_uchEndSize = random->RandomFloat( 5, 10 );
+ dir[0] = vecSmokeDir[0] + random->RandomFloat( -0.1f, 0.1f );
+ dir[1] = vecSmokeDir[1] + random->RandomFloat( -0.1f, 0.1f );
+ dir[2] = vecSmokeDir[2] + random->RandomFloat( -0.1f, 0.1f );
+ pParticle->m_vecVelocity = dir * random->RandomFloat( 30.0f, 40.0f );
+ pParticle->m_uchStartAlpha = random->RandomFloat( 128,255 );
+ pParticle->m_uchEndAlpha = 0;
+ pParticle->m_flRoll = random->RandomFloat( 180, 360 );
+ pParticle->m_flRollDelta = random->RandomFloat( -1, 1 );
+ pParticle->m_uchColor[0] = r;
+ pParticle->m_uchColor[1] = g;
+ pParticle->m_uchColor[2] = b;
+ pParticle->m_vecAcceleration = Vector(0,0,10);
+ }
+ }
+
+ // Sparks
+ for ( float flSparks = flDamaged - 0.3; flSparks > 0; flSparks -= 0.3 )
+ {
+ // Get random spark attachment point
+ iSparkAttachment = LookupRandomAttachment( "r_spark" );
+ if ( GetAttachment( iSparkAttachment, vecSpark, angSpark ) )
+ {
+ g_pEffects->Sparks( vecSpark );
+ }
+ }
+
+ m_flNextEffect = gpGlobals->curtime + random->RandomFloat( 0.05, 0.1 );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Effects created while the object's building itself
+//-----------------------------------------------------------------------------
+void C_BaseObject::DrawBuildEffects( void )
+{
+ m_flNextEffect = gpGlobals->curtime + 10;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Effects created when the object's damaged
+//-----------------------------------------------------------------------------
+void C_BaseObject::DrawDamageEffects( void )
+{
+ if ( !GetMaxHealth() )
+ return;
+
+ // Get the overall damage percentage
+ float flDamaged = 1.0 - ((float)GetHealth() / (float)GetMaxHealth());
+
+ // Damage attachment points
+ int iSmokeAttachment, iFireAttachment, iSparkAttachment;
+ Vector vecSmoke, vecFire, vecSpark, vecSmokeDir, dir;
+ QAngle angSmoke, angFire, angSpark;
+
+ // HACK: Calculate a random origin
+ // This can go away when we require all objects to have damage attachment points
+ Vector vecOrigin;
+ CollisionProp()->RandomPointInBounds( vec3_origin, Vector( 1, 1, 1 ), &vecOrigin );
+
+ // Look for damage points
+ iSmokeAttachment = LookupRandomAttachment( "d_smoke" );
+ iFireAttachment = LookupRandomAttachment( "d_fire" );
+
+ // Get the points, and if we can't find 'em, use the random origin
+ if ( GetAttachment( iSmokeAttachment, vecSmoke, angSmoke ) )
+ {
+ AngleVectors( angSmoke, &vecSmokeDir );
+ }
+ else
+ {
+ vecSmoke = vecOrigin;
+ vecSmokeDir = Vector(0,0,1);
+ }
+ if ( !GetAttachment( iFireAttachment, vecFire, angFire ) )
+ {
+ vecFire = vecOrigin;
+ angFire = QAngle(0,0,0);
+ }
+
+ float r, g, b;
+ r = g = b = random->RandomFloat( 16, 92 );
+
+ // Smoke
+ CSmartPtr<CSimpleEmitter> pSmokeEmitter = CSimpleEmitter::Create( "DrawDamageEffects 1" );
+ pSmokeEmitter->SetSortOrigin( vecSmoke );
+ SimpleParticle *pParticle = (SimpleParticle *) pSmokeEmitter->AddParticle( sizeof(SimpleParticle), g_Mat_DustPuff[1], vecSmoke );
+ if ( pParticle )
+ {
+ pParticle->m_flLifetime = 0.0f;
+ pParticle->m_flDieTime = random->RandomFloat( 2.0f, 3.0f );
+ pParticle->m_uchStartSize = MAX( 1, 20 * flDamaged );
+ pParticle->m_uchEndSize = MAX( 10, 80 * flDamaged );
+ dir[0] = vecSmokeDir[0] + random->RandomFloat( -0.2f, 0.2f );
+ dir[1] = vecSmokeDir[1] + random->RandomFloat( -0.2f, 0.2f );
+ dir[2] = vecSmokeDir[2] + random->RandomFloat( -0.2f, 0.2f );
+ pParticle->m_vecVelocity = dir * random->RandomFloat( 60.0f, 80.0f );
+ pParticle->m_uchStartAlpha = 255;
+ pParticle->m_uchEndAlpha = 0;
+ pParticle->m_flRoll = random->RandomFloat( 180, 360 );
+ pParticle->m_flRollDelta = random->RandomFloat( -1, 1 );
+ pParticle->m_uchColor[0] = r;
+ pParticle->m_uchColor[1] = g;
+ pParticle->m_uchColor[2] = b;
+ }
+
+ // If we're really hurt, start burning
+ if ( flDamaged > 0.25 )
+ {
+ CSmartPtr<CObjectFireParticles> pFireEmitter = CObjectFireParticles::Create( "DrawDamageEffects 1" );
+ pFireEmitter->SetSortOrigin( vecFire );
+ PMaterialHandle hSphereMaterial = pFireEmitter->GetPMaterial( "sprites/floorflame" );
+ ObjectFireParticle *pParticle = (ObjectFireParticle *) pFireEmitter->AddParticle( sizeof(ObjectFireParticle), hSphereMaterial, vecFire );
+ if ( pParticle )
+ {
+ pParticle->m_hParent = this;
+ pParticle->m_iAttachmentPoint = iFireAttachment;
+
+ pParticle->m_flLifetime = 0.0f;
+ pParticle->m_flDieTime = 1.0;
+ pParticle->m_uchStartSize = MAX( 5, 30 * (flDamaged - 0.25) );
+ pParticle->m_uchEndSize = pParticle->m_uchStartSize;
+ pParticle->m_vecVelocity = Vector(0,0,1);
+ pParticle->m_uchStartAlpha = 255;
+ pParticle->m_uchEndAlpha = 255;
+ pParticle->m_flRoll = 0;
+ pParticle->m_flRollDelta = 0;
+ }
+ }
+
+ // Sparks
+ for ( float flSparks = flDamaged - 0.3; flSparks > 0; flSparks -= 0.3 )
+ {
+ // Get random spark attachment point
+ iSparkAttachment = LookupRandomAttachment( "d_spark" );
+ if ( !GetAttachment( iSparkAttachment, vecSpark, angSpark ) )
+ {
+ vecSpark = vecOrigin;
+ angSpark = QAngle(0,0,0);
+ }
+
+ g_pEffects->Sparks( vecSpark );
+ }
+
+ m_flNextEffect = gpGlobals->curtime + random->RandomFloat( 0.2, 0.5 );
+}
+
+//============================================================================================================
+// POWER PROXY
+//============================================================================================================
+class CObjectPowerProxy : public CResultProxy
+{
+public:
+ bool Init( IMaterial *pMaterial, KeyValues *pKeyValues );
+ void OnBind( void *pC_BaseEntity );
+
+private:
+ CFloatInput m_Factor;
+};
+
+bool CObjectPowerProxy::Init( IMaterial *pMaterial, KeyValues *pKeyValues )
+{
+ if (!CResultProxy::Init( pMaterial, pKeyValues ))
+ return false;
+
+ if (!m_Factor.Init( pMaterial, pKeyValues, "scale", 1 ))
+ return false;
+
+ return true;
+}
+
+void CObjectPowerProxy::OnBind( void *pRenderable )
+{
+ // Find the view angle between the player and this entity....
+ IClientRenderable *pRend = (IClientRenderable *)pRenderable;
+ C_BaseEntity *pEntity = pRend->GetIClientUnknown()->GetBaseEntity();
+ C_BaseObject *pObject = dynamic_cast<C_BaseObject*>(pEntity);
+ if (!pObject)
+ return;
+
+ int iPowered = pObject->IsPowered();
+
+ SetFloatResult( iPowered * m_Factor.GetFloat() );
+}
+
+EXPOSE_INTERFACE( CObjectPowerProxy, IMaterialProxy, "ObjectPower" IMATERIAL_PROXY_INTERFACE_VERSION );
+
+//-----------------------------------------------------------------------------
+// Control screen
+//-----------------------------------------------------------------------------
+class CBasicControlPanel : public CObjectControlPanel
+{
+ DECLARE_CLASS( CBasicControlPanel, CObjectControlPanel );
+
+public:
+ CBasicControlPanel( vgui::Panel *parent, const char *panelName );
+};
+
+
+DECLARE_VGUI_SCREEN_FACTORY( CBasicControlPanel, "basic_control_panel" );
+
+
+//-----------------------------------------------------------------------------
+// Constructor:
+//-----------------------------------------------------------------------------
+CBasicControlPanel::CBasicControlPanel( vgui::Panel *parent, const char *panelName )
+ : BaseClass( parent, "CBasicControlPanel" )
+{
+}
diff --git a/game/client/tf2/c_baseobject.h b/game/client/tf2/c_baseobject.h
new file mode 100644
index 0000000..a26ade8
--- /dev/null
+++ b/game/client/tf2/c_baseobject.h
@@ -0,0 +1,223 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Clients CBaseObject
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef C_BASEOBJECT_H
+#define C_BASEOBJECT_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "baseobject_shared.h"
+#include <vgui_controls/Panel.h>
+#include <vgui_controls/Label.h>
+#include "vgui_healthbar.h"
+#include "commanderoverlay.h"
+#include "hud_minimap.h"
+#include "particlemgr.h"
+#include "particle_prototype.h"
+#include "particle_util.h"
+#include "c_basecombatcharacter.h"
+#include "ihasbuildpoints.h"
+
+class C_BaseTFPlayer;
+
+// Max Length of ID Strings
+#define MAX_ID_STRING 256
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+class C_BaseObject : public C_BaseCombatCharacter, public IHasBuildPoints
+{
+ DECLARE_CLASS( C_BaseObject, C_BaseCombatCharacter );
+public:
+ DECLARE_CLIENTCLASS();
+ DECLARE_ENTITY_PANEL();
+ DECLARE_MINIMAP_PANEL();
+
+ C_BaseObject();
+ ~C_BaseObject( void );
+
+ virtual bool IsBaseObject( void ) const { return true; }
+ virtual bool IsAnUpgrade(void ) const { return false; }
+ virtual bool IsAVehicle( void ) const { return false; }
+
+ virtual void SetType( int iObjectType );
+
+ virtual void AddEntity();
+ virtual void Select( void );
+
+ void SetActivity( Activity act );
+ Activity GetActivity( ) const;
+ void SetObjectSequence( int sequence );
+ virtual void OnActivityChanged( Activity act );
+
+ virtual void PreDataUpdate( DataUpdateType_t updateType );
+ virtual void PostDataUpdate( DataUpdateType_t updateType );
+ virtual void OnDataChanged( DataUpdateType_t updateType );
+ virtual void Release( void );
+
+ virtual int GetHealth() const { return m_iHealth; }
+ void SetHealth( int health ) { m_iHealth = health; }
+ virtual int GetMaxHealth() const { return m_iMaxHealth; }
+ int GetObjectFlags( void ) { return m_fObjectFlags; }
+ void SetObjectFlags( int flags ) { m_fObjectFlags = flags; }
+
+ // Derive to customize an object's attached version
+ virtual void SetupAttachedVersion( void ) { return; }
+ virtual void SetupUnattachedVersion( void ) { return; }
+ virtual void OnLostPower( void ) { return; };
+
+ virtual const char *GetTargetDescription( void ) const;
+ virtual char *GetIDString( void );
+ virtual bool IsValidIDTarget( void );
+
+ void AttemptToGoActive( void );
+ virtual bool ShouldBeActive( void );
+ virtual void OnGoActive( void );
+ virtual void OnGoInactive( void );
+
+ virtual void SetDormant( bool bDormant );
+
+ void SendClientCommand( const char *pCmd );
+
+ virtual void FireEvent( const Vector& origin, const QAngle& angles, int event, const char *options );
+
+ // Builder preview...
+ void ActivateYawPreview( bool enable );
+ void PreviewYaw( float yaw );
+ bool IsPreviewingYaw() const;
+
+ // This is called to get the initial builder yaw...
+ virtual float GetInitialBuilderYaw();
+
+ virtual void RecalculateIDString( void );
+
+ int GetType() const { return m_iObjectType; }
+ bool IsOwnedByLocalPlayer() const;
+ C_BaseTFPlayer *GetOwner();
+
+ // Are we under attack?
+ bool IsUnderAttack( );
+
+ virtual int DrawModel( int flags );
+ virtual bool IsIdentityBrush( void );
+
+ // Effects
+ void DrawRunningEffects( void );
+ void DrawBuildEffects( void );
+ void DrawDamageEffects( void );
+
+ // Deterioration
+ bool IsDeteriorating( void ) { return m_bDeteriorating; };
+
+ float GetPercentageConstructed( void ) { return m_flPercentageConstructed; }
+
+ bool IsPlacing( void ) const { return m_bPlacing; }
+ bool IsBuilding( void ) const { return m_bBuilding; }
+
+ virtual void FinishedBuilding( void ) { return; }
+
+ virtual bool OffsetObjectOrigin( Vector& origin );
+
+ virtual const char* GetStatusName() const;
+
+ // Object Previews
+ void HighlightBuildPoints( int flags );
+
+public:
+ // Client/Server shared build point code
+ void CreateBuildPoints( void );
+ void AddAndParseBuildPoint( int iAttachmentNumber, KeyValues *pkvBuildPoint );
+ virtual int AddBuildPoint( int iAttachmentNum );
+ virtual void AddValidObjectToBuildPoint( int iPoint, int iObjectType );
+ virtual CBaseObject *GetBuildPointObject( int iPoint );
+ bool IsBuiltOnAttachment( void ) { return (m_hBuiltOnEntity != NULL); }
+ void AttachObjectToObject( CBaseEntity *pEntity, int iPoint, Vector &vecOrigin );
+ CBaseObject *GetParentObject( void );
+ void SetBuildPointPassenger( int iPoint, int iPassenger );
+ int GetBuildPointPassenger( int iPoint ) const;
+
+ // Build points
+ CUtlVector<BuildPoint_t> m_BuildPoints;
+
+ // Power
+ bool IsPowered( void );
+ virtual bool CanPowerupEver( int iPowerup );
+ virtual bool CanPowerupNow( int iPowerup );
+
+ bool IsDisabled( void ) { return m_bDisabled; }
+
+ virtual float GetSapperAttachTime( void );
+
+// IHasBuildPoints
+public:
+ virtual int GetNumBuildPoints( void ) const;
+ virtual bool GetBuildPoint( int iPoint, Vector &vecOrigin, QAngle &vecAngles );
+ virtual int GetBuildPointAttachmentIndex( int iPoint ) const;
+ virtual bool CanBuildObjectOnBuildPoint( int iPoint, int iObjectType );
+ virtual void SetObjectOnBuildPoint( int iPoint, CBaseObject *pObject );
+ virtual float GetMaxSnapDistance( int iBuildPoint );
+ virtual bool ShouldCheckForMovement( void ) { return true; }
+ virtual int GetNumObjectsOnMe( void );
+ virtual CBaseEntity *GetFirstObjectOnMe( void );
+ virtual CBaseObject *GetObjectOfTypeOnMe( int iObjectType );
+ virtual void RemoveAllObjects( void );
+ virtual int FindObjectOnBuildPoint( CBaseObject *pObject );
+ virtual void GetExitPoint( CBaseEntity *pPlayer, int iPoint, Vector *pAbsOrigin, QAngle *pAbsAngles );
+
+ virtual bool TestHitboxes( const Ray_t &ray, unsigned int fContentsMask, trace_t& tr );
+
+protected:
+ char m_szIDString[ MAX_ID_STRING ];
+
+private:
+ enum
+ {
+ YAW_PREVIEW_OFF = 0,
+ YAW_PREVIEW_ON,
+ YAW_PREVIEW_WAITING_FOR_UPDATE
+ };
+
+ Activity m_Activity;
+
+ int m_fObjectFlags;
+ float m_fYawPreview;
+ char m_YawPreviewState;
+ CHandle< C_BaseTFPlayer > m_hOldOwner;
+ CHandle< C_BaseTFPlayer > m_hBuilder;
+ bool m_bWasActive;
+ int m_iOldHealth;
+ bool m_bHasSapper;
+ bool m_bOldSapper;
+ int m_iObjectType;
+ int m_iHealth;
+ int m_iMaxHealth;
+ bool m_bWasBuilding;
+ bool m_bBuilding;
+ bool m_bPlacing;
+ bool m_bDeteriorating;
+ bool m_bDisabled;
+ float m_flPercentageConstructed;
+ EHANDLE m_hBuiltOnEntity;
+
+ CHealthBarPanel *m_pHealthBar;
+ vgui::Label *m_pNameLabel;
+ float m_flDamageFlash; // Used to flash the panel when the object takes damage
+ int m_iFlashes;
+
+ float m_flAttackTime;
+ CMaterialReference m_ThermalMaterial;
+
+ // Effects
+ float m_flNextEffect;
+
+private:
+ C_BaseObject( const C_BaseObject & ); // not defined, not accessible
+};
+
+#endif // C_BASEOBJECT_H
diff --git a/game/client/tf2/c_basetfplayer.cpp b/game/client/tf2/c_basetfplayer.cpp
new file mode 100644
index 0000000..a85c2ed
--- /dev/null
+++ b/game/client/tf2/c_basetfplayer.cpp
@@ -0,0 +1,2705 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+#include "cbase.h"
+#include "c_basetfplayer.h"
+#include "beamdraw.h"
+#include <stdarg.h>
+#include "ivmodemanager.h"
+#include "shake.h"
+#include "ivieweffects.h"
+#include "c_tfteam.h"
+#include "view.h"
+#include "UserCmd.h"
+#include "ivrenderview.h"
+#include "model_types.h"
+#include "view_shared.h"
+#include "hud_orders.h"
+#include "weapon_twohandedcontainer.h"
+#include "particles_simple.h"
+#include "playerandobjectenumerator.h"
+#include "iclientvehicle.h"
+#include "input.h"
+#include "basetfvehicle.h"
+#include "c_vehicle_teleport_station.h"
+#include "weapon_combatshield.h"
+#include "hud_vehicle_role.h"
+#include "hud_technologytreedoc.h"
+#include "iclientmode.h"
+#include "weapon_selection.h"
+#include "clienteffectprecachesystem.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+
+// Don't alias here
+#if defined( CBaseTFPlayer )
+#undef CBaseTFPlayer
+#endif
+
+void CAM_ToThirdPerson(void);
+void CAM_ToFirstPerson(void);
+void FX_ReconParticle( const Vector &vecOrigin, bool bBlue );
+
+static ConVar tf2_showstate( "tf2_showstate", "0", 0, "Print state name\n" );
+extern ConVar mannedgun_usethirdperson;
+ConVar damageboost_modeloffset( "damageboost_modeloffset", "1" );
+ConVar damageboost_modelphasespeed_min( "damageboost_modelphasespeed_min", "99" );
+ConVar damageboost_modelphasespeed_max( "damageboost_modelphasespeed_max", "170" );
+
+
+CLIENTEFFECT_REGISTER_BEGIN( PrecacheBaseTFPlayer )
+CLIENTEFFECT_MATERIAL( "sprites/physbeam" )
+CLIENTEFFECT_MATERIAL( "player/infiltratorcamo/infiltratorcamo" )
+CLIENTEFFECT_REGISTER_END()
+
+
+class CPersonalShieldEffect
+{
+public:
+
+ static CPersonalShieldEffect* Create( C_BaseTFPlayer *pEnt, const Vector &vOffsetFromEnt, const Vector &vIncomingDirection, int iDamage );
+
+ ~CPersonalShieldEffect();
+
+ // Returns false if the effect is done and should be deleted.
+ bool Update( float dt );
+
+ void Render(); // Draw the effect.
+
+private:
+
+ CPersonalShieldEffect();
+
+private:
+
+ CHandle<C_BaseTFPlayer> m_hEnt;
+ Vector m_vOffsetFromEnt;
+ Vector m_vIncomingDirection;
+ float m_flDamage;
+
+ enum
+ {
+ NUM_TRACERS = 10
+ };
+
+ Vector m_vTracerEndPoints[NUM_TRACERS]; // These are relative to the model's origin.
+ float m_flLifetimeRemaining;
+ float m_flTotalLifetime;
+};
+
+
+CPersonalShieldEffect* CPersonalShieldEffect::Create(
+ C_BaseTFPlayer *pEnt,
+ const Vector &vOffsetFromEnt,
+ const Vector &vIncomingDirection,
+ int iDamage )
+{
+ CPersonalShieldEffect *pRet = new CPersonalShieldEffect;
+ if ( pRet )
+ {
+ pRet->m_hEnt = pEnt;
+ pRet->m_vOffsetFromEnt = vOffsetFromEnt;
+ pRet->m_flDamage = iDamage;
+
+ Vector vNormal = vIncomingDirection;
+ VectorNormalize( vNormal );
+
+ for ( int i=0; i < CPersonalShieldEffect::NUM_TRACERS; i++ )
+ {
+ pRet->m_vTracerEndPoints[i] = pRet->m_vOffsetFromEnt;
+
+ Vector vOffset = RandomVector( -1, 1 );
+
+ // Make it tangent to a sphere enclosing the player.
+ float flDot = vNormal.Dot( vOffset );
+ vOffset -= vNormal * flDot;
+
+ VectorNormalize( vOffset );
+ vOffset *= 10;
+
+ pRet->m_vTracerEndPoints[i] += vOffset;
+ }
+
+ pRet->m_flLifetimeRemaining = pRet->m_flTotalLifetime = 0.15;
+ pRet->m_vIncomingDirection = vIncomingDirection;
+ }
+ return pRet;
+}
+
+CPersonalShieldEffect::CPersonalShieldEffect()
+{
+}
+
+
+CPersonalShieldEffect::~CPersonalShieldEffect()
+{
+}
+
+
+bool CPersonalShieldEffect::Update( float dt )
+{
+ if ( !m_hEnt.Get() )
+ return false;
+
+ m_flLifetimeRemaining -= dt;
+ if ( m_flLifetimeRemaining >= 0 )
+ {
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+
+void CPersonalShieldEffect::Render()
+{
+ if ( !m_hEnt.Get() )
+ return;
+
+ Vector vCenter = m_hEnt->WorldSpaceCenter( );
+
+ const Vector vBasePos = vCenter + m_vOffsetFromEnt;
+ IMaterial *pMat = materials->FindMaterial( "sprites/physbeam", TEXTURE_GROUP_CLIENT_EFFECTS );
+
+ CBeamSeg seg;
+
+ // Get redder as their health goes down.
+ float flColor = (float)m_hEnt->GetHealth() / m_hEnt->GetMaxHealth();
+ flColor = clamp(flColor, 0, 1);
+ seg.m_vColor.Init( 0.5 + 0.5*flColor, flColor, flColor );
+
+ seg.m_flAlpha = 1;
+ seg.m_flTexCoord = 0;
+ seg.m_flWidth = 2;
+
+ for ( int i=0; i < CPersonalShieldEffect::NUM_TRACERS; i++ )
+ {
+ const Vector vEndPos = vCenter + m_vTracerEndPoints[i];
+
+ static int nSegs = 5;
+
+ CBeamSegDraw beamDraw;
+ beamDraw.Start( nSegs, pMat );
+
+ for ( int iSeg=0; iSeg < nSegs; iSeg++ )
+ {
+ float t = (float)iSeg / (nSegs-1);
+ VectorLerp( vBasePos, vEndPos, t, seg.m_vPos );
+
+ // Add a random offset.
+ seg.m_vPos += RandomVector( -3, 3 );
+ seg.m_flTexCoord += 0.1f;
+
+ beamDraw.NextSeg( &seg );
+ }
+
+ beamDraw.End();
+ }
+
+/*
+ Vector vEggBounds[2];
+ m_hEnt->GetBounds( vEggBounds[0], vEggBounds[1] );
+ vEggBounds[0] += m_hEnt->GetAbsOrigin();
+ vEggBounds[1] += m_hEnt->GetAbsOrigin();
+ Vector vEggCenter = (vEggBounds[0] + vEggBounds[1]) * 0.5f;
+ Vector vEggDims = (vEggBounds[1] - vEggBounds[0]) * 0.5f;
+
+ Vector vUp( 0, 0, 1 );
+ Vector vForward = m_vIncomingDirection;
+ vForward.z = 0;
+ VectorNormalize( vForward );
+ Vector vRight = vUp.Cross( vForward );
+
+ // Now draw an eggshell around the player showing their health.
+ seg.m_vColor.Init( 1, flColor, flColor );
+ seg.m_flAlpha = 0.3f;
+ seg.m_flWidth = 1;
+
+ static int nSamples = 30;
+ CBeamSegDraw beamDraw;
+ beamDraw.Start( nSamples, pMat );
+
+ for ( int iSeg=0; iSeg < nSamples; iSeg++ )
+ {
+ float t = (float)iSeg / (nSamples-1);
+ float angle = M_PI * 2.0f * t;
+ seg.m_vPos = vEggCenter + vUp*vEggDims.z*sin( angle ) + vRight*vEggDims.x*cos( angle );
+ beamDraw.NextSeg( &seg );
+ }
+
+ beamDraw.End();
+*/
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Helper for animation state machine
+// Input : clear -
+// destination -
+// *pFormat -
+// ... -
+//-----------------------------------------------------------------------------
+void StatusPrintf( bool clear, int destination, char *pFormat, ... )
+{
+ if ( destination != 4 && destination != 5 )
+ return;
+ char data[ 2048 ];
+ va_list argptr;
+
+ va_start( argptr, pFormat );
+ Q_vsnprintf( data, sizeof( data ), pFormat, argptr );
+ va_end( argptr );
+
+ char *out = data;
+ if ( destination == 5 )
+ out += 2;
+
+ if ( destination == 5 )
+ {
+ char slot[3];
+ Q_strncpy( slot, data, 3 );
+
+ slot[2] = 0;
+
+ int s = atoi( slot );
+ s &= 31;
+
+ engine->Con_NPrintf( s, "%s", out );
+ }
+ else
+ {
+ Msg( "%s", out );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: RecvProxy that converts the Player's object UtlVector to entindexes
+//-----------------------------------------------------------------------------
+void RecvProxy_PlayerObjectList( const CRecvProxyData *pData, void *pStruct, void *pOut )
+{
+ CTFPlayerLocalData *pLocalData = (CTFPlayerLocalData*)pStruct;
+ CBaseHandle *pHandle = (CBaseHandle*)(&(pLocalData->m_aObjects[pData->m_iElement]));
+ RecvProxy_IntToEHandle( pData, pStruct, pHandle );
+}
+
+
+void RecvProxyArrayLength_PlayerObjects( void *pStruct, int objectID, int currentArrayLength )
+{
+ CTFPlayerLocalData *pLocalData = (CTFPlayerLocalData*)pStruct;
+
+ if ( pLocalData->m_aObjects.Count() != currentArrayLength )
+ {
+ pLocalData->m_aObjects.SetSize( currentArrayLength );
+ }
+}
+
+BEGIN_RECV_TABLE_NOBASE( CTFPlayerLocalData, DT_TFLocal )
+ RecvPropInt( RECVINFO(m_nInTacticalView) ),
+ RecvPropInt( RECVINFO( m_bKnockedDown )),
+ RecvPropVector( RECVINFO( m_vecKnockDownDir )),
+ RecvPropInt( RECVINFO( m_bThermalVision )),
+ RecvPropInt( RECVINFO( m_iIDEntIndex )),
+ RecvPropArray( RecvPropInt( RECVINFO(m_iResourceAmmo[0])), m_iResourceAmmo),
+ RecvPropInt( RECVINFO(m_iBankResources) ),
+ RecvPropArray2(
+ RecvProxyArrayLength_PlayerObjects,
+ RecvPropInt( "player_object_array_element", 0, SIZEOF_IGNORE, 0, RecvProxy_PlayerObjectList ),
+ MAX_OBJECTS_PER_PLAYER,
+ 0,
+ "player_object_array" ),
+ RecvPropInt( RECVINFO( m_bAttachingSapper ) ),
+ RecvPropFloat( RECVINFO( m_flSapperAttachmentFrac ) ),
+ RecvPropInt( RECVINFO( m_bForceMapOverview ) ),
+END_RECV_TABLE()
+
+IMPLEMENT_CLIENTCLASS_DT(C_BaseTFPlayer, DT_BaseTFPlayer, CBaseTFPlayer)
+ RecvPropDataTable(RECVINFO_DT(m_TFLocal),0, &REFERENCE_RECV_TABLE(DT_TFLocal), DataTableRecvProxy_StaticDataTable),
+
+ // Class Data Tables
+ RecvPropInt( RECVINFO(m_iPlayerClass)),
+ RecvPropDataTable( RECVINFO_DT( m_PlayerClasses ), 0, &REFERENCE_RECV_TABLE( DT_AllPlayerClasses ), DataTableRecvProxy_StaticDataTable ),
+
+ RecvPropEHandle( RECVINFO( m_hSelectedMCV ) ),
+ RecvPropInt( RECVINFO(m_iCurrentZoneState ) ),
+ RecvPropInt( RECVINFO(m_iMaxHealth ) ),
+ RecvPropInt( RECVINFO(m_TFPlayerFlags) ),
+ RecvPropInt( RECVINFO( m_bUnderAttack )),
+ RecvPropInt( RECVINFO( m_bIsBlocking )),
+
+ // Sniper - will get moved to a class data table
+ RecvPropVector( RECVINFO(m_vecDeployedAngles) ),
+ RecvPropInt( RECVINFO( m_bDeployed )),
+ RecvPropInt( RECVINFO( m_bDeploying )),
+ RecvPropInt( RECVINFO( m_bUnDeploying )),
+
+ // Infiltrator - will get moved to a class data table
+ RecvPropFloat( RECVINFO( m_flCamouflageAmount )),
+ RecvPropEHandle(RECVINFO(m_hSpawnPoint)),
+END_RECV_TABLE()
+
+BEGIN_PREDICTION_DATA_NO_BASE( CTFPlayerLocalData )
+
+ DEFINE_PRED_FIELD( m_nInTacticalView, FIELD_INTEGER, FTYPEDESC_INSENDTABLE ),
+ DEFINE_PRED_FIELD( m_bKnockedDown, FIELD_BOOLEAN, FTYPEDESC_INSENDTABLE ),
+ DEFINE_PRED_FIELD( m_vecKnockDownDir, FIELD_VECTOR, FTYPEDESC_INSENDTABLE ),
+ DEFINE_PRED_FIELD( m_bThermalVision, FIELD_BOOLEAN, FTYPEDESC_INSENDTABLE ),
+// DEFINE_PRED_FIELD( m_iIDEntIndex, FIELD_INTEGER, FTYPEDESC_INSENDTABLE ),
+ DEFINE_PRED_FIELD( m_iBankResources, FIELD_INTEGER, FTYPEDESC_INSENDTABLE ),
+ DEFINE_PRED_ARRAY( m_iResourceAmmo, FIELD_INTEGER, RESOURCE_TYPES, FTYPEDESC_INSENDTABLE ),
+ //DEFINE_PRED_ARRAY( m_aObjects, FIELD_EHANDLE, MAX_OBJECTS_PER_PLAYER, FTYPEDESC_INSENDTABLE ),
+ DEFINE_PRED_FIELD( m_bAttachingSapper, FIELD_BOOLEAN, FTYPEDESC_INSENDTABLE ),
+ DEFINE_PRED_FIELD( m_flSapperAttachmentFrac, FIELD_FLOAT, FTYPEDESC_INSENDTABLE ),
+ DEFINE_PRED_FIELD( m_bForceMapOverview, FIELD_BOOLEAN, FTYPEDESC_INSENDTABLE ),
+
+END_PREDICTION_DATA()
+
+
+// TODO: consolidate all these includes and the DEFINE_PRED... for each class type
+// into tf_shareddefs.h.
+#include "c_tf_class_commando.h"
+#include "c_tf_class_defender.h"
+#include "c_tf_class_escort.h"
+#include "c_tf_class_infiltrator.h"
+#include "c_tf_class_medic.h"
+#include "c_tf_class_recon.h"
+#include "c_tf_class_sniper.h"
+#include "c_tf_class_support.h"
+#include "c_tf_class_sapper.h"
+#include "c_tf_class_pyro.h"
+
+
+BEGIN_PREDICTION_DATA( C_BaseTFPlayer )
+
+ DEFINE_PRED_TYPEDESCRIPTION( m_TFLocal, CTFPlayerLocalData ),
+
+ DEFINE_PRED_FIELD( m_flCycle, FIELD_FLOAT, FTYPEDESC_INSENDTABLE | FTYPEDESC_PRIVATE | FTYPEDESC_OVERRIDE ),
+ DEFINE_PRED_FIELD( m_flPlaybackRate, FIELD_FLOAT, FTYPEDESC_INSENDTABLE | FTYPEDESC_PRIVATE | FTYPEDESC_OVERRIDE ),
+
+ DEFINE_PRED_TYPEDESCRIPTION_PTR( m_PlayerClasses.m_pClasses[TFCLASS_COMMANDO], C_PlayerClassCommando ),
+ DEFINE_PRED_TYPEDESCRIPTION_PTR( m_PlayerClasses.m_pClasses[TFCLASS_DEFENDER], C_PlayerClassDefender ),
+ DEFINE_PRED_TYPEDESCRIPTION_PTR( m_PlayerClasses.m_pClasses[TFCLASS_ESCORT], C_PlayerClassEscort ),
+ DEFINE_PRED_TYPEDESCRIPTION_PTR( m_PlayerClasses.m_pClasses[TFCLASS_INFILTRATOR], C_PlayerClassInfiltrator ),
+ DEFINE_PRED_TYPEDESCRIPTION_PTR( m_PlayerClasses.m_pClasses[TFCLASS_MEDIC], C_PlayerClassMedic ),
+ DEFINE_PRED_TYPEDESCRIPTION_PTR( m_PlayerClasses.m_pClasses[TFCLASS_RECON], C_PlayerClassRecon ),
+ DEFINE_PRED_TYPEDESCRIPTION_PTR( m_PlayerClasses.m_pClasses[TFCLASS_SNIPER], C_PlayerClassSniper ),
+ DEFINE_PRED_TYPEDESCRIPTION_PTR( m_PlayerClasses.m_pClasses[TFCLASS_SUPPORT], C_PlayerClassSupport ),
+ DEFINE_PRED_TYPEDESCRIPTION_PTR( m_PlayerClasses.m_pClasses[TFCLASS_SAPPER], C_PlayerClassSapper ),
+
+ DEFINE_PRED_FIELD( m_iPlayerClass, FIELD_INTEGER, FTYPEDESC_INSENDTABLE ),
+ DEFINE_PRED_FIELD( m_flCamouflageAmount, FIELD_FLOAT, FTYPEDESC_INSENDTABLE ),
+ DEFINE_PRED_FIELD( m_hSpawnPoint, FIELD_EHANDLE, FTYPEDESC_INSENDTABLE ),
+ DEFINE_PRED_FIELD( m_iMaxHealth, FIELD_INTEGER, FTYPEDESC_INSENDTABLE ),
+ DEFINE_PRED_FIELD( m_bDeployed, FIELD_BOOLEAN, FTYPEDESC_INSENDTABLE ),
+ DEFINE_PRED_FIELD( m_bDeploying, FIELD_BOOLEAN, FTYPEDESC_INSENDTABLE ),
+ DEFINE_PRED_FIELD( m_bUnDeploying, FIELD_BOOLEAN, FTYPEDESC_INSENDTABLE ),
+ DEFINE_PRED_FIELD( m_vecDeployedAngles, FIELD_VECTOR, FTYPEDESC_INSENDTABLE ),
+ DEFINE_PRED_FIELD( m_iCurrentZoneState, FIELD_INTEGER, FTYPEDESC_INSENDTABLE ),
+ DEFINE_PRED_FIELD( m_TFPlayerFlags, FIELD_INTEGER, FTYPEDESC_INSENDTABLE ),
+ DEFINE_PRED_FIELD( m_bUnderAttack, FIELD_BOOLEAN, FTYPEDESC_INSENDTABLE ),
+
+ DEFINE_PRED_FIELD( m_vecConstraintCenter, FIELD_VECTOR, FTYPEDESC_INSENDTABLE ),
+ DEFINE_PRED_FIELD( m_flConstraintRadius, FIELD_FLOAT, FTYPEDESC_INSENDTABLE ),
+ DEFINE_PRED_FIELD( m_flConstraintWidth, FIELD_FLOAT, FTYPEDESC_INSENDTABLE ),
+ DEFINE_PRED_FIELD( m_flConstraintSpeedFactor, FIELD_FLOAT, FTYPEDESC_INSENDTABLE ),
+
+ DEFINE_FIELD( m_vecPosDelta, FIELD_VECTOR ),
+ DEFINE_ARRAY( m_aMomentum, FIELD_FLOAT, C_BaseTFPlayer::MOMENTUM_MAXSIZE ),
+ DEFINE_FIELD( m_iMomentumHead, FIELD_INTEGER ),
+ //DEFINE_FIELD( m_iSelectedTarget, FIELD_INTEGER ),
+ //DEFINE_FIELD( m_iPersonalTarget, FIELD_INTEGER ),
+ //DEFINE_FIELD( m_iLastHealth, FIELD_INTEGER ),
+ //DEFINE_FIELD( m_nOldTacticalView, FIELD_INTEGER ),
+ //DEFINE_FIELD( m_nOldPlayerClass, FIELD_INTEGER ),
+ //DEFINE_FIELD( m_bOldThermalVision, FIELD_BOOLEAN ),
+ //DEFINE_FIELD( m_bOldKnockDownState, FIELD_BOOLEAN ),
+ //DEFINE_FIELD( m_flStartKnockdown, FIELD_FLOAT ),
+ //DEFINE_FIELD( m_flEndKnockdown, FIELD_FLOAT ),
+ //DEFINE_FIELD( m_vecOriginalViewAngles, FIELD_VECTOR ),
+ //DEFINE_FIELD( m_vecCurrentKnockdownAngles, FIELD_VECTOR ),
+ //DEFINE_FIELD( m_vecKnockDownGoalAngles, FIELD_VECTOR ),
+ //DEFINE_FIELD( m_bKnockdownOverrideAngles, FIELD_BOOLEAN ),
+ //DEFINE_FIELD( m_flKnockdownViewheightAdjust, FIELD_FLOAT ),
+ //DEFINE_FIELD( m_flLastMoveTime, FIELD_FLOAT ),
+ //DEFINE_FIELD( m_vecLastOrigin, FIELD_VECTOR ),
+ //DEFINE_FIELD( m_flLastDamageTime, FIELD_FLOAT ),
+ //DEFINE_FIELD( m_flLastGainHealthTime, FIELD_FLOAT ),
+ //DEFINE_FIELD( m_flDampeningAmount, FIELD_FLOAT ),
+ //DEFINE_FIELD( m_flGoalDampeningAmount, FIELD_FLOAT ),
+ //DEFINE_FIELD( m_flDampeningStayoutTime, FIELD_FLOAT ),
+ //DEFINE_FIELD( m_flMovementCamoSuppression, FIELD_FLOAT ),
+ //DEFINE_FIELD( m_flGoalMovementCamoSuppressionAmount, FIELD_FLOAT ),
+ //DEFINE_FIELD( m_flMovementCamoSuppressionStayoutTime, FIELD_FLOAT ),
+ //DEFINE_FIELD( m_flNextAdrenalinEffect, FIELD_FLOAT ),
+ //DEFINE_FIELD( m_bFadingIn, FIELD_BOOLEAN ),
+ //DEFINE_FIELD( m_iIDEntIndex, FIELD_INTEGER ),
+ //DEFINE_ARRAY( m_BoostModelAngles, FIELD_FLOAT, 3 ),
+
+ // DEFINE_PRED_TYPEDESCRIPTION( m_RideVehicle, CRideVehicle ),
+ // DEFINE_FIELD( m_aTargetReticles, CUtlVector < CTargetReticle * > ),
+ // DEFINE_FIELD( m_aSpyCameras, CUtlVector < C_SpyCamera * > ),
+ // DEFINE_FIELD( m_ParticleEffect, CParticleEffectBinding ),
+ // DEFINE_FIELD( m_ParticleTimer, TimedEvent ),
+ // DEFINE_FIELD( m_MaterialHandle, PMaterialHandle ),
+ // DEFINE_FIELD( m_pParticleMgr, CParticleMgr ),
+ // DEFINE_FIELD( m_pThermalMaterial, IMaterial ),
+ // DEFINE_FIELD( m_pCamoEffectMaterial, IMaterial ),
+ // DEFINE_FIELD( m_BoostMaterial, CMaterialReference ),
+ // DEFINE_FIELD( m_EMPMaterial, CMaterialReference ),
+ // DEFINE_FIELD( m_PersonalShieldEffects, CUtlLinkedList < CPersonalShieldEffect* , int > ),
+ // DEFINE_FIELD( m_hSelectedOrder, CHandle < C_Order > ),
+ // DEFINE_FIELD( m_hPersonalOrder, FIELD_EHANDLE ),
+ // DEFINE_FIELD( m_hSelectedObject, CHandle < C_BaseObject > ),
+
+END_PREDICTION_DATA()
+
+LINK_ENTITY_TO_CLASS( player, C_BaseTFPlayer );
+
+ConVar cl_TargetInfoFadeDist("cl_TargetInfoFadeDist", "800", 0, "Distance at which TF player targetting info fades out.");
+
+//-----------------------------------------------------------------------------
+// Purpose: Return true if the local player is the specified class
+//-----------------------------------------------------------------------------
+bool IsLocalPlayerClass( int iClass )
+{
+ C_BaseTFPlayer *pPlayer = C_BaseTFPlayer::GetLocalPlayer();
+ if ( pPlayer )
+ {
+ return ( pPlayer->PlayerClass() == iClass );
+ }
+ return false;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Return the local player's class
+//-----------------------------------------------------------------------------
+int GetLocalPlayerClass( void )
+{
+ C_BaseTFPlayer *pPlayer = C_BaseTFPlayer::GetLocalPlayer();
+ if ( pPlayer )
+ {
+ return pPlayer->PlayerClass();
+ }
+ return TFCLASS_UNDECIDED;
+}
+
+//-----------------------------------------------------------------------------
+// returns true if the local player is in tactical view
+//-----------------------------------------------------------------------------
+bool IsLocalPlayerInTactical( void )
+{
+ C_BaseTFPlayer *pPlayer = C_BaseTFPlayer::GetLocalPlayer();
+ if (!pPlayer)
+ return false;
+
+ return !!pPlayer->m_TFLocal.m_nInTacticalView;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+C_BaseTFPlayer::C_BaseTFPlayer() :
+ m_PlayerClasses( this ), m_PlayerAnimState( this )
+{
+ Clear();
+}
+
+void C_BaseTFPlayer::Clear()
+{
+ m_iPlayerClass = TFCLASS_UNDECIDED;
+ m_iCurrentZoneState = 0;
+ m_TFPlayerFlags = 0;
+ m_hSelectedOrder = NULL;
+ m_hPersonalOrder = NULL;
+ m_hSelectedObject = NULL;
+ m_iSelectedTarget = 0;
+ m_iPersonalTarget = 0;
+ m_iIDEntIndex = 0;
+ m_bStoreRagdollInfo = true;
+ m_flNextUseCheck = 0;
+ m_pSapperAttachmentStatus = NULL;
+
+ int i;
+ for ( i=0; i < ARRAYSIZE( m_BoostModelAngles ); i++ )
+ {
+ m_BoostModelAngles[i] = RandomFloat( 0, 360 );
+ }
+
+
+ for ( i = 0; i < MOMENTUM_MAXSIZE; i++ )
+ {
+ m_aMomentum[ i ] = 1.0f;
+ }
+}
+
+
+bool C_BaseTFPlayer::IsHidden() const
+{
+ return (m_TFPlayerFlags & TF_PLAYER_HIDDEN) != 0;
+}
+
+
+bool C_BaseTFPlayer::IsDamageBoosted() const
+{
+ return (m_TFPlayerFlags & TF_PLAYER_DAMAGE_BOOST) != 0;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+C_BaseTFPlayer::~C_BaseTFPlayer()
+{
+ int iSize = m_aTargetReticles.Size();
+ for (int i = iSize-1; i >= 0; i-- )
+ {
+ delete m_aTargetReticles[i];
+ }
+ m_aTargetReticles.Purge();
+
+ if ( m_pThermalMaterial )
+ {
+ m_pThermalMaterial->DecrementReferenceCount();
+ }
+ if ( m_pCamoEffectMaterial )
+ {
+ m_pCamoEffectMaterial->DecrementReferenceCount();
+ }
+
+ m_PersonalShieldEffects.PurgeAndDeleteElements();
+
+ if ( m_pSapperAttachmentStatus )
+ {
+ delete m_pSapperAttachmentStatus;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Add, remove object from the panel
+//-----------------------------------------------------------------------------
+void C_BaseTFPlayer::SetDormant( bool bDormant )
+{
+ BaseClass::SetDormant( bDormant );
+ ENTITY_PANEL_ACTIVATE( "player", !bDormant );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+bool C_BaseTFPlayer::HasNamedTechnology( const char *name )
+{
+ CTechnologyTree *pTree = GetTechnologyTreeDoc().GetTechnologyTree();
+ if ( !pTree )
+ return false;
+
+ CBaseTechnology *pItem = pTree->GetTechnology(name);
+ // If the tech doesn't exist, everyone has it by default
+ if ( !pItem )
+ return true;
+
+ return pItem->GetActive();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+bool C_BaseTFPlayer::ShouldDraw()
+{
+ if ( IsHidden() )
+ return false;
+
+ C_BaseTFPlayer *local = C_BaseTFPlayer::GetLocalPlayer();
+ if ( local && local->IsUsingThermalVision() )
+ return true;
+
+ // Draw the local player if he's the driver of a vehicle.
+ // We can safely return true here because vehicles will hide drivers that shouldn't be visible.
+ if ( mannedgun_usethirdperson.GetInt() && IsVehicleMounted() && IsLocalPlayer() )
+ {
+ IClientVehicle *pVehicle = GetVehicle();
+ int nRole = pVehicle->GetPassengerRole( this );
+ if ( nRole == VEHICLE_ROLE_DRIVER )
+ return !IsEffectActive(EF_NODRAW);
+ }
+
+ return BaseClass::ShouldDraw();
+}
+
+
+//-----------------------------------------------------------------------------
+// Should this object cast shadows?
+//-----------------------------------------------------------------------------
+ShadowType_t C_BaseTFPlayer::ShadowCastType()
+{
+ // FIXME: This check can be removed once we've dealt with the interpolation problem
+ C_BaseTFPlayer *local = C_BaseTFPlayer::GetLocalPlayer();
+ if (local == this)
+ return SHADOWS_NONE;
+
+ if (IsCamouflaged())
+ return SHADOWS_NONE;
+
+ return SHADOWS_RENDER_TO_TEXTURE_DYNAMIC;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Called once per frame for the local player only.
+// Called after rendering ( called in PostRender() ) the 3d objects ( i.e., other players )
+// but before vgui paints 2d overlays so that we can update the positions of all world
+// targets before rendering
+//-----------------------------------------------------------------------------
+void C_BaseTFPlayer::UpdateTargetReticles( void )
+{
+ // Update all the target reticles
+ for ( int i = 0; i < m_aTargetReticles.Size(); i++ )
+ {
+ m_aTargetReticles[i]->Update();
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Called to update hud elements contained in the player
+//-----------------------------------------------------------------------------
+void C_BaseTFPlayer::ClientThink( void )
+{
+ BaseClass::ClientThink();
+
+ SetNextClientThink( CLIENT_THINK_ALWAYS );
+
+ CheckKnockdownState();
+ CheckMovementCamoSuppression();
+ CheckCamoDampening();
+ CheckLastMovement();
+ CheckAdrenalin();
+ UpdateIDTarget();
+
+ // update personal shield effects.
+ int iNext;
+ for ( int i=m_PersonalShieldEffects.Head(); i != m_PersonalShieldEffects.InvalidIndex(); i = iNext )
+ {
+ iNext = m_PersonalShieldEffects.Next( i );
+ CPersonalShieldEffect *pEffect = m_PersonalShieldEffects[i];
+
+ if ( !pEffect->Update( gpGlobals->frametime ) )
+ {
+ delete pEffect;
+ m_PersonalShieldEffects.Remove( i );
+ }
+ }
+
+ // Let the classes think as well.
+ if ( GetPlayerClass() )
+ {
+ GetPlayerClass()->ClassThink();
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Store off old movetype ( commander or not )
+// Input : bnewentity -
+//-----------------------------------------------------------------------------
+void C_BaseTFPlayer::OnPreDataChanged( DataUpdateType_t updateType )
+{
+ BaseClass::OnPreDataChanged( updateType );
+
+ m_nOldTacticalView = m_TFLocal.m_nInTacticalView;
+
+ m_iLastHealth = GetHealth();
+ m_bOldKnockDownState = m_TFLocal.m_bKnockedDown;
+
+ m_bOldThermalVision = m_TFLocal.m_bThermalVision;
+
+ m_nOldPlayerClass = m_iPlayerClass;
+
+ // Chain.
+ if ( GetPlayerClass() )
+ {
+ GetPlayerClass()->ClassPreDataUpdate();
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Switch to/from commander mode if necessary
+// Input : bnewentity -
+//-----------------------------------------------------------------------------
+void C_BaseTFPlayer::OnDataChanged( DataUpdateType_t updateType )
+{
+ bool bnewentity = (updateType == DATA_UPDATE_CREATED);
+ if ( bnewentity )
+ {
+ // Do the minimap panel thing here because we don't
+ // want predicted players to have traces
+ CONSTRUCT_MINIMAP_PANEL( "minimap_player", MINIMAP_PLAYERS );
+
+ SetNextClientThink( CLIENT_THINK_ALWAYS );
+ m_BoostMaterial.Init( "player/damageboost/thermal", TEXTURE_GROUP_CLIENT_EFFECTS );
+ m_EMPMaterial.Init( "player/empeffect", TEXTURE_GROUP_CLIENT_EFFECTS );
+ }
+
+ BaseClass::OnDataChanged( updateType );
+
+ // Only care about this stuff for the local player
+ if ( IsLocalPlayer() )
+ {
+ // Check to see if we switched into/out of the commander mode.
+ if ( m_TFLocal.m_nInTacticalView != m_nOldTacticalView )
+ {
+ // Is this the local player
+ C_BasePlayer *player = C_BasePlayer::GetLocalPlayer();
+ if ( player == this )
+ {
+ // Tell mode switcher that server changed our mode
+ modemanager->SwitchMode( m_TFLocal.m_nInTacticalView ? true : false, false );
+ }
+ }
+
+ // Knockdown
+ if ( m_bOldKnockDownState != m_TFLocal.m_bKnockedDown )
+ {
+ if ( IsKnockedDown() )
+ {
+ m_flStartKnockdown = gpGlobals->curtime;
+ m_vecOriginalViewAngles = GetAbsAngles();
+
+ m_vecKnockDownGoalAngles = m_TFLocal.m_vecKnockDownDir;
+ }
+ else
+ {
+ m_flEndKnockdown = gpGlobals->curtime;
+ }
+ }
+
+ // Thermal Vision
+ if ( m_bOldThermalVision != m_TFLocal.m_bThermalVision )
+ {
+ if ( m_TFLocal.m_bThermalVision )
+ {
+ ScreenFade_t sf;
+ memset( &sf, 0, sizeof( sf ) );
+ sf.a = 128;
+ sf.r = 0;
+ sf.g = 0;
+ sf.b = 255;
+ sf.duration = 0; // not used
+ sf.holdTime = (float)(1<<SCREENFADE_FRACBITS) * 30.0f;
+ sf.fadeFlags = FFADE_STAYOUT;
+ vieweffects->Fade( sf );
+ }
+ else
+ {
+ vieweffects->ClearPermanentFades();
+ }
+ }
+
+ if ( m_nOldPlayerClass != m_iPlayerClass )
+ {
+ engine->ClientCmd( "cancelselect\n" );
+ }
+ }
+
+ if ( bnewentity )
+ {
+ m_iLastHealth = GetHealth();
+ m_flLastDamageTime = -10000;
+ m_flLastGainHealthTime = -10000;
+ }
+
+ if (m_iLastHealth != GetHealth())
+ {
+ if (m_iLastHealth > GetHealth())
+ {
+ if (GetHealth() < GetMaxHealth())
+ {
+ m_flLastDamageTime = gpGlobals->curtime;
+
+ C_TFTeam *pTeam = static_cast<C_TFTeam*>(GetTeam());
+ if (pTeam && !IsLocalPlayer() && m_bUnderAttack )
+ pTeam->NotifyBaseUnderAttack( GetAbsOrigin(), false );
+ }
+ }
+ else
+ {
+ m_flLastGainHealthTime = gpGlobals->curtime;
+
+ // If we were just fully healed, remove all decals
+ if ( GetHealth() >= GetMaxHealth() )
+ {
+ RemoveAllDecals();
+ }
+ }
+ }
+
+ // Snap to 100 % since we round down
+ if ( m_flCamouflageAmount > 99.0f )
+ {
+ m_flCamouflageAmount = 100.0f;
+ }
+
+ // Chain.
+ if ( GetPlayerClass() )
+ {
+ GetPlayerClass()->ClassOnDataChanged();
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void C_BaseTFPlayer::PreDataUpdate( DataUpdateType_t updateType )
+{
+ BaseClass::PreDataUpdate( updateType );
+
+ m_bOldAttachingSapper = m_TFLocal.m_bAttachingSapper;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void C_BaseTFPlayer::PostDataUpdate( DataUpdateType_t updateType )
+{
+ BaseClass::PostDataUpdate( updateType );
+
+ // Only care about this stuff for the local player
+ if ( IsLocalPlayer() )
+ {
+ // Sapper attachment
+ if ( m_bOldAttachingSapper != m_TFLocal.m_bAttachingSapper || m_TFLocal.m_bAttachingSapper )
+ {
+ if ( !m_pSapperAttachmentStatus )
+ {
+ // Create the attachment status
+ m_pSapperAttachmentStatus = new CHealthBarPanel();
+ vgui::Panel *pParent = g_pClientMode->GetViewport();
+ m_pSapperAttachmentStatus->SetParent( pParent );
+ m_pSapperAttachmentStatus->SetAutoDelete( false );
+ m_pSapperAttachmentStatus->SetPos( XRES(320) - XRES(40), YRES(250) );
+ m_pSapperAttachmentStatus->SetSize( XRES(80), YRES(8) );
+ m_pSapperAttachmentStatus->SetGoodColor( 240, 180, 63, 192 );
+ m_pSapperAttachmentStatus->SetBadColor( 0, 0, 0, 192 );
+ }
+
+ m_pSapperAttachmentStatus->SetVisible( m_TFLocal.m_bAttachingSapper );
+ if ( m_TFLocal.m_bAttachingSapper )
+ {
+ m_pSapperAttachmentStatus->SetHealth( m_TFLocal.m_flSapperAttachmentFrac );
+ }
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void C_BaseTFPlayer::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 BASEENTITY_MSG_REMOVE_DECALS:
+ {
+ RemoveAllDecals();
+ }
+ break;
+ case PLAYER_MSG_PERSONAL_SHIELD:
+ {
+ Vector vOffsetFromEnt;
+ msg.ReadBitVec3Coord( vOffsetFromEnt );
+
+ // Show a personal shield effect.
+ Vector vIncomingDirection;
+ msg.ReadBitVec3Normal( vIncomingDirection );
+
+ short iDamage = msg.ReadShort();
+
+ // Show the effect.
+ CPersonalShieldEffect *pEffect = CPersonalShieldEffect::Create( this, vOffsetFromEnt, vIncomingDirection, iDamage );
+ if ( pEffect )
+ m_PersonalShieldEffects.AddToTail( pEffect );
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Free this entity
+//-----------------------------------------------------------------------------
+void C_BaseTFPlayer::Release( void )
+{
+ // Remove any reticles on this entity
+ C_BaseTFPlayer *pPlayer = C_BaseTFPlayer::GetLocalPlayer();
+ if ( pPlayer )
+ {
+ pPlayer->Remove_Target( this );
+ }
+
+ BaseClass::Release();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void C_BaseTFPlayer::ItemPostFrame( void )
+{
+ if ( m_flNextUseCheck < gpGlobals->curtime )
+ {
+ m_flNextUseCheck = gpGlobals->curtime + 0.3;
+
+ CVehicleRoleHudElement *pElement = GET_HUDELEMENT( CVehicleRoleHudElement );
+ Assert( pElement );
+ pElement->ShowVehicleRole( -1 );
+
+ // See if there's an entity we can +use
+ if ( IsAlive() && !GetVehicle() && ( gpGlobals->curtime > m_flNextAttack ) )
+ {
+ CBaseEntity *pUseEntity = FindUseEntity();
+ if ( pUseEntity )
+ {
+ // Vehicles need to show we're going to get in them
+ C_BaseTFVehicle *pVehicle = dynamic_cast<C_BaseTFVehicle*>( pUseEntity );
+ if ( pVehicle && InSameTeam(pVehicle) && !pVehicle->IsPlacing() && !pVehicle->IsBuilding() && pVehicle->GetMaxPassengerCount() >= 2 )
+ {
+ pElement->ShowVehicleRole( pVehicle->LocateEntryPoint( this ) );
+ }
+ }
+ }
+ }
+
+ // Don't process items while in a vehicle.
+ if ( IsInAVehicle() )
+ {
+ IClientVehicle *pVehicle = GetVehicle();
+ Assert( pVehicle );
+
+ // NOTE: We *have* to do this before ItemPostFrame because ItemPostFrame
+ // may dump us out of the vehicle
+ int nRole = pVehicle->GetPassengerRole( this );
+ bool bUsingStandardWeapons = pVehicle->IsPassengerUsingStandardWeapons( nRole );
+
+ pVehicle->ItemPostFrame( this );
+
+ // Fall through and check weapons, etc. if we're using them
+ if (!bUsingStandardWeapons || !IsInAVehicle())
+ return;
+ }
+
+ // If we're attaching a sapper, handle player use only
+ if ( m_TFLocal.m_bAttachingSapper )
+ {
+ PlayerUse();
+ return;
+ }
+
+ BaseClass::ItemPostFrame();
+
+#if 0
+ if ( GetPlayerClass() )
+ {
+ GetPlayerClass()->ItemPostFrame(); // Let the player class handle it.
+ }
+#endif
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Return true if I'm in a vehicle that's mounted on another vehicle
+//-----------------------------------------------------------------------------
+bool C_BaseTFPlayer::IsVehicleMounted() const
+{
+ CBaseTFVehicle *pVehicle = dynamic_cast< CBaseTFVehicle* >( GetMoveParent() );
+ if ( pVehicle )
+ return dynamic_cast< CBaseTFVehicle* >( pVehicle->GetMoveParent() ) != NULL;
+
+ return false;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+int C_BaseTFPlayer::DrawModel( int flags )
+{
+ int drawn = 0;
+
+ if ( !m_bReadyToDraw )
+ return 0;
+
+ QAngle saveAngles(0,0,0);
+ Vector saveLocalOrigin(0,0,0);
+ bool angleschanged = false;
+ bool originchanged = false;
+
+ // If we're in a vehicle, use the vehicle's angles for the local player
+ if ( IsInAVehicle() && !IsInAVehicle() )
+ {
+ IClientVehicle *pVehicle = GetVehicle();
+ int nRole = pVehicle->GetPassengerRole( this );
+ if ( nRole == VEHICLE_ROLE_DRIVER )
+ {
+ C_BaseTFVehicle *pVehicleEntity = (CBaseTFVehicle*)pVehicle->GetVehicleEnt();
+ angleschanged = true;
+ SetLocalAngles( pVehicleEntity->GetPassengerAngles( saveAngles, VEHICLE_ROLE_DRIVER ) );
+
+ // HACK: Stomp the origin
+ originchanged = true;
+ SetLocalOrigin( vec3_origin );
+ }
+ }
+ else
+ {
+ angleschanged = true;
+ SetLocalAngles( m_PlayerAnimState.GetRenderAngles() );
+ }
+
+ drawn = BaseClass::DrawModel(flags);
+
+ if ( angleschanged )
+ {
+ SetLocalAngles( saveAngles );
+ }
+ if ( originchanged )
+ {
+ SetLocalOrigin( saveLocalOrigin );
+ }
+
+ // Draw all personal shield effects.
+ FOR_EACH_LL( m_PersonalShieldEffects, i )
+ {
+ m_PersonalShieldEffects[i]->Render();
+ }
+
+ return drawn;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+int C_BaseTFPlayer::GetClass( void )
+{
+ if ( !GetPlayerClass() )
+ return TFCLASS_UNDECIDED;
+
+ return m_iPlayerClass;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void C_BaseTFPlayer::OverrideView( CViewSetup *pSetup )
+{
+ if ( CheckKnockdownAngleOverride() )
+ {
+ float adj = GetKnockdownViewheightAdjust();
+
+ pSetup->origin.z -= adj;
+
+ return;
+ }
+
+ BaseClass::OverrideView( pSetup );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+bool C_BaseTFPlayer::ShouldDrawViewModel()
+{
+ if ( CheckKnockdownAngleOverride() )
+ return false;
+
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Hack to search up the hierarchy looking for bones whose ultimate parent is 1 ( i.e., the pelvis ) since
+// these are the lower body bones
+//-----------------------------------------------------------------------------
+bool ParentIsPelvis( mstudiobone_t *bones, int start, int pelvis, int spine )
+{
+ int current = start;
+
+ while ( bones[ current ].parent )
+ {
+ // Root?
+ if ( bones[ current ].parent <= 0 )
+ {
+ return false;
+ }
+
+ if ( bones[ current ].parent == pelvis )
+ return true;
+
+ if ( bones[ current ].parent == spine )
+ return false;
+
+ current = bones[ current ].parent;
+ }
+
+ return false;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Hack to find the bone indices of the pelvis and the spine so we can
+// more quickly determine if a bones parent is the pelvis so we can merge bones correctly
+//-----------------------------------------------------------------------------
+static void FindPelvisAndSpine( int numbones, mstudiobone_t *bones, int *pelvis, int *spine )
+{
+ *pelvis = *spine = -1;
+
+ mstudiobone_t *bone = bones;
+ for ( int i = 0; i < numbones; i++, bone++ )
+ {
+ if ( !stricmp( bone->pszName(), "Bip01 Pelvis" ) )
+ {
+ *pelvis = i;
+ }
+ else if ( !stricmp( bone->pszName(), "Bip01 Spine" ) )
+ {
+ *spine = i;
+ }
+
+ if ( *spine >= 0 && *pelvis >= 0 )
+ break;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Another hack, the TFC 1.5 v. 2 models expect controllers at the midpoint
+// Input : controllers[MAXSTUDIOBONECTRLS] -
+//-----------------------------------------------------------------------------
+void C_BaseTFPlayer::GetBoneControllers(float controllers[MAXSTUDIOBONECTRLS])
+{
+ // Set controllers to a their zero value.
+ for(int i=0; i < MAXSTUDIOBONECTRLS; i++)
+ {
+ controllers[i] = 0.5;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Get a text description for the object target
+//-----------------------------------------------------------------------------
+void C_BaseTFPlayer::GetTargetDescription( char *pDest, int bufferSize )
+{
+ const char *pStr = GetPlayerName();
+ if ( pStr )
+ {
+ Q_strncpy( pDest, pStr, bufferSize );
+ }
+ else
+ {
+ pDest[0] = 0;
+ }
+}
+
+//=====================================================================================================
+// ORDERS
+//=====================================================================================================
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Player has received a new personal order
+//-----------------------------------------------------------------------------
+void C_BaseTFPlayer::SetPersonalOrder( C_Order *pOrder )
+{
+ // Do we have an order already?
+ RemoveOrderTarget();
+
+ m_hPersonalOrder = pOrder;
+ m_iPersonalTarget = pOrder->GetTarget();
+
+ // Add a new target to our list
+ if ( pOrder->ShouldDrawReticle() )
+ {
+ int iTargetIndex = pOrder->GetTarget();
+ if ( iTargetIndex )
+ {
+ C_BaseEntity *pTarget = cl_entitylist->GetBaseEntity( iTargetIndex );
+ if ( pTarget )
+ {
+ char desc[512];
+ pOrder->GetTargetDescription( desc, sizeof( desc ) );
+ Add_Target( pTarget, desc );
+ }
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Remove the target reticle for the specified order
+//-----------------------------------------------------------------------------
+void C_BaseTFPlayer::RemoveOrderTarget()
+{
+ if ( m_iPersonalTarget )
+ {
+ C_BaseEntity *pTarget = cl_entitylist->GetBaseEntity( m_iPersonalTarget );
+ if ( pTarget )
+ {
+ Remove_Target( pTarget );
+ }
+
+ m_iPersonalTarget = 0;
+ }
+}
+
+//====================================================================================================
+// RESOURCES
+//====================================================================================================
+// Purpose:
+//-----------------------------------------------------------------------------
+int C_BaseTFPlayer::GetBankResources( void )
+{
+ return m_TFLocal.m_iBankResources;
+}
+
+
+//====================================================================================================
+// OBJECTS
+//====================================================================================================
+// Purpose: Player has selected an Object
+//-----------------------------------------------------------------------------
+void C_BaseTFPlayer::SetSelectedObject( C_BaseObject *pObject )
+{
+ // Do we have an order already?
+ if ( m_hSelectedObject )
+ {
+ Remove_Target( m_hSelectedObject );
+
+ // If we selected our existing one, we just wanted to deselect
+ if ( pObject == m_hSelectedObject )
+ {
+ m_hSelectedObject = NULL;
+ return;
+ }
+ }
+
+ m_hSelectedObject = pObject;
+
+ // Add a new target to our list
+ if ( pObject )
+ {
+ Add_Target( pObject, pObject->GetTargetDescription() );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Get the currently selected object
+//-----------------------------------------------------------------------------
+C_BaseObject *C_BaseTFPlayer::GetSelectedObject( void )
+{
+ return m_hSelectedObject;
+}
+
+//====================================================================================================
+// TARGET RETICLES
+//====================================================================================================
+// Purpose: Add a new entity to the list of targets
+//-----------------------------------------------------------------------------
+void C_BaseTFPlayer::Add_Target( C_BaseEntity *pTarget, const char *sName )
+{
+ CTargetReticle *pTargetReticle = new CTargetReticle();
+ pTargetReticle->Init( pTarget, sName );
+
+ m_aTargetReticles.AddToTail( pTargetReticle );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Remove an entity from the list of targets
+//-----------------------------------------------------------------------------
+void C_BaseTFPlayer::Remove_Target( C_BaseEntity *pTarget )
+{
+ for (int i = 0; i < m_aTargetReticles.Size(); i++ )
+ {
+ CTargetReticle *pTargetReticle = m_aTargetReticles[i];
+ if ( pTargetReticle->GetTarget() == pTarget )
+ {
+ Remove_Target( pTargetReticle );
+ return;
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Remove a specific reticle from our list
+//-----------------------------------------------------------------------------
+void C_BaseTFPlayer::Remove_Target( CTargetReticle *pTargetReticle )
+{
+ m_aTargetReticles.FindAndRemove( pTargetReticle );
+ delete pTargetReticle;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Output : Returns true on success, false on failure.
+//-----------------------------------------------------------------------------
+bool C_BaseTFPlayer::IsUsingThermalVision( void ) const
+{
+ return m_TFLocal.m_bThermalVision;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+int C_BaseTFPlayer::GetIDTarget( void ) const
+{
+ return m_iIDEntIndex;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Output : Returns true on success, false on failure.
+//-----------------------------------------------------------------------------
+bool C_BaseTFPlayer::IsKnockedDown( void ) const
+{
+ return m_TFLocal.m_bKnockedDown;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : ang -
+//-----------------------------------------------------------------------------
+void C_BaseTFPlayer::SetKnockdownAngles( const QAngle& ang )
+{
+ m_bKnockdownOverrideAngles = true;
+ QAngle fixedAngles = ang;
+ NormalizeAngles( fixedAngles );
+ m_vecCurrentKnockdownAngles = fixedAngles;
+ engine->SetViewAngles( fixedAngles );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : outAngles -
+//-----------------------------------------------------------------------------
+void C_BaseTFPlayer::GetKnockdownAngles( QAngle& outAngles )
+{
+ outAngles = m_vecCurrentKnockdownAngles;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void C_BaseTFPlayer::CheckKnockdownState( void )
+{
+ m_bKnockdownOverrideAngles = false;
+
+ if ( m_flStartKnockdown == 0.0f &&
+ m_flEndKnockdown == 0.0f &&
+ !IsKnockedDown() )
+ {
+ m_flKnockdownViewheightAdjust = 0.0f;
+ return;
+ }
+
+ float frac = 0.0f;
+ float dt;
+ if ( IsKnockedDown() )
+ {
+ if ( m_flStartKnockdown != 0.0f )
+ {
+
+ dt = gpGlobals->curtime - m_flStartKnockdown;
+ if ( dt >= 0.0f && dt < KNOCKDOWN_BLEND_IN )
+ {
+ frac = ( dt / KNOCKDOWN_BLEND_IN );
+ frac = MAX( 0.0f, frac );
+ frac = MIN( 1.0f, frac );
+ }
+ else if ( dt >= KNOCKDOWN_BLEND_IN)
+ {
+ m_flStartKnockdown = 0.0f;
+ frac = 1.0f;
+ }
+ }
+ else
+ {
+ frac = 1.0f;
+ }
+ }
+ else
+ {
+ if ( m_flEndKnockdown != 0.0f )
+ {
+ frac = 0.0f;
+ dt = gpGlobals->curtime - m_flEndKnockdown;
+ if ( dt >= 0 && dt < KNOCKDOWN_BLEND_OUT )
+ {
+ frac = ( dt / KNOCKDOWN_BLEND_OUT );
+ frac = 1.0f - frac;
+ }
+ else if ( dt >= KNOCKDOWN_BLEND_OUT )
+ {
+ m_flEndKnockdown = 0.0f;
+ }
+ else
+ {
+ frac = 1.0f;
+ }
+ }
+ }
+
+ if ( frac == 0.0f )
+ {
+ SetKnockdownAngles( m_vecOriginalViewAngles );
+ }
+ else if ( frac == 1.0f )
+ {
+ SetKnockdownAngles( m_vecKnockDownGoalAngles );
+ }
+ else
+ {
+ QAngle current;
+ InterpolateAngles( m_vecOriginalViewAngles, m_vecKnockDownGoalAngles, current, frac );
+ SetKnockdownAngles( current );
+ }
+
+ Vector eyeZOffset;
+ VectorSubtract( EyePosition(), GetAbsOrigin(), eyeZOffset );
+ float zsize = eyeZOffset.z;
+
+ m_flKnockdownViewheightAdjust = frac * ( zsize - 12 );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Output : Returns true on success, false on failure.
+//-----------------------------------------------------------------------------
+bool C_BaseTFPlayer::CheckKnockdownAngleOverride( void ) const
+{
+ return m_bKnockdownOverrideAngles;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Output : float
+//-----------------------------------------------------------------------------
+float C_BaseTFPlayer::GetKnockdownViewheightAdjust( void ) const
+{
+ return m_flKnockdownViewheightAdjust;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Player has changed to a new team
+//-----------------------------------------------------------------------------
+void C_BaseTFPlayer::TeamChange( int iNewTeam )
+{
+ BaseClass::TeamChange( iNewTeam );
+
+ // Did we change team? or did we just join our first team?
+ if ( iNewTeam != GetTeamNumber() )
+ {
+ // Tell the tech tree to reload itself
+ GetTechnologyTreeDoc().ReloadTechTree();
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: // Override so infiltrator's disguised as other team will work
+// Output : int
+//-----------------------------------------------------------------------------
+int C_BaseTFPlayer::GetRenderTeamNumber( void )
+{
+ return GetTeamNumber();
+}
+
+
+// 50 % per second
+#define CAMO_DAMPENING_CHANGERATE 300.0f
+#define CAMO_MOVESUPPRESSION_CHANGERATE 100.0f
+#define CAMO_DAMPENINGVELOCITY_CUTOFF 50.0f
+#define CAMO_DAMPENINGVELOCITY_MAX 400.0f
+#define CAMO_DAMPENINGAVEL_CUTOFF 1.0f
+#define CAMO_DAMPENINGAVEL_MAX 5.0f
+#define CAMO_STAYOUT_TIME 1.0f
+#define CAMO_MOVEMENT_PENALTYTIME 1.0f
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Output : Returns true on success, false on failure.
+//-----------------------------------------------------------------------------
+bool C_BaseTFPlayer::IsCamouflaged( void )
+{
+ return ( m_flCamouflageAmount > 0.0f ) ? true : false;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Output : float
+//-----------------------------------------------------------------------------
+float C_BaseTFPlayer::GetCamouflageAmount( void )
+{
+ return m_flCamouflageAmount;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: 0 to 1, where 1 means hardly visible and 0 means pretty noticeable
+// Output : float
+//-----------------------------------------------------------------------------
+
+#define DISTANCE_CAMO_EFFECT_AMOUNT 0.1f
+#define LOCAL_MOTION_CAMO_EFFECT_AMOUNT 0.3f
+#define MOVEMENT_CAMO_EFFECT_AMOUNT 0.2f
+
+float C_BaseTFPlayer::ComputeCamoEffectAmount( void )
+{
+ if ( !IsCamouflaged() )
+ return 1.0f;
+
+ // Start with the amount from the server....
+ float effect_amount = m_flCamouflageAmount / 100.0f;
+
+ // If this player has moved recently, camo will not be as effective for him
+ effect_amount -= MOVEMENT_CAMO_EFFECT_AMOUNT * GetMovementCamoSuppression() / 100.0f;
+ if (effect_amount < 0)
+ effect_amount = 0;
+
+ // Determine distance to render origin
+ Vector delta = GetAbsOrigin() - CurrentViewOrigin();
+ float distance = delta.Length();
+
+ // At the max distance, make it n% less likely to see the camoed dude...
+ // At min distance, we're no less likely to see the dude
+ if ( distance >= CAMO_INNER_RADIUS )
+ effect_amount *= 1 + DISTANCE_CAMO_EFFECT_AMOUNT;
+ else
+ {
+ float frac = distance / CAMO_INNER_RADIUS;
+ effect_amount *= 1 - frac + (1 + DISTANCE_CAMO_EFFECT_AMOUNT) * frac;
+ }
+
+ // Local viewer movements make it n% less likely to see the camoed dude...
+ // No movement means we're no less likely to see the dude
+ // Dampening is based on the local viewer's movements
+ float dampening = 0.0f;
+ C_BaseTFPlayer *local = GetLocalPlayer();
+ if ( local )
+ {
+ dampening = local->GetDampeningAmount() / 100.0f;
+ }
+
+ // Now apply suppression (i.e., less visible) based on camera and viewer movement
+ effect_amount *= 1 + LOCAL_MOTION_CAMO_EFFECT_AMOUNT * dampening;
+
+ // Clamp to valid range
+ effect_amount = MAX( 0.0f, effect_amount );
+ effect_amount = MIN( 0.99f, effect_amount );
+
+ return effect_amount;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Output : int
+//-----------------------------------------------------------------------------
+int C_BaseTFPlayer::ComputeCamoAlpha( void )
+{
+ Assert( IsCamouflaged() );
+
+ // Determine distance to render origin
+ Vector delta = GetAbsOrigin() - CurrentViewOrigin();
+ float distance = delta.Length();
+
+ int baseline = 0;
+
+ // Too far, just blend out completely
+ if ( distance >= CAMO_OUTER_RADIUS )
+ {
+ baseline = 0;
+ }
+ else if ( distance >= CAMO_INNER_RADIUS )
+ {
+ float frac = ( distance - CAMO_INNER_RADIUS ) / ( CAMO_OUTER_RADIUS - CAMO_INNER_RADIUS );
+ frac = 1 - frac;
+ baseline = (int)( (float)( 255 - CAMO_INNER_ALPHA ) * frac );
+ }
+ else if ( distance >= CAMO_INVIS_RADIUS )
+ {
+ // We'll also render with the special effect
+ float frac = ( distance - CAMO_INVIS_RADIUS ) / ( CAMO_INNER_RADIUS - CAMO_INVIS_RADIUS );
+ baseline = (int)( (float)( CAMO_INNER_ALPHA ) * frac );
+ }
+ else
+ {
+ // NOTE: return 1 or else the renderer will skip drawing and we won't be
+ // able to draw the up close effect
+ baseline = 1;
+ }
+
+ // Suppress everything based on server ramp
+ return baseline + (int)( (float)( 255 - baseline ) * ( m_flCamouflageAmount / 100.0f ) );
+
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Output : int
+//-----------------------------------------------------------------------------
+void C_BaseTFPlayer::ComputeFxBlend( void )
+{
+ if ( !IsCamouflaged() )
+ {
+ BaseClass::ComputeFxBlend();
+ return;
+ }
+
+ m_nRenderFXBlend = ComputeCamoAlpha();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Output : Returns true on success, false on failure.
+//-----------------------------------------------------------------------------
+bool C_BaseTFPlayer::IsTransparent( void )
+{
+ if ( IsCamouflaged() )
+ {
+ return true;
+ }
+
+ return BaseClass::IsTransparent();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Output : Returns true on success, false on failure.
+//-----------------------------------------------------------------------------
+bool C_BaseTFPlayer::ViewModel_IsTransparent( void )
+{
+ if ( IsCamouflaged() )
+ {
+ return true;
+ }
+
+ return BaseClass::ViewModel_IsTransparent();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Return true if the player's viewmodel should match the player's model data
+//-----------------------------------------------------------------------------
+bool C_BaseTFPlayer::IsOverridingViewmodel( void )
+{
+ // Don't override medic weapons since we have effects for them
+ if ( PlayerClass() == TFCLASS_MEDIC )
+ return BaseClass::IsOverridingViewmodel();
+
+ if ( IsDamageBoosted() || IsCamouflaged() || HasPowerup(POWERUP_EMP) )
+ return true;
+
+ return BaseClass::IsOverridingViewmodel();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Draw my viewmodel in some special way
+//-----------------------------------------------------------------------------
+int C_BaseTFPlayer::DrawOverriddenViewmodel( C_BaseViewModel *pViewmodel, int flags )
+{
+ int ret = 0;
+
+ if ( IsCamouflaged() && ( ComputeCamoEffectAmount() != 1.0f ) )
+ {
+ if ( GetCamoMaterial() )
+ {
+ modelrender->ForcedMaterialOverride( GetCamoMaterial() );
+ ret = pViewmodel->DrawOverriddenViewmodel( flags );
+ modelrender->ForcedMaterialOverride( NULL );
+ }
+ }
+
+ if ( IsDamageBoosted() || HasPowerup(POWERUP_EMP) )
+ {
+
+ // First draw the model once normally.
+ pViewmodel->DrawOverriddenViewmodel( flags );
+
+ // NOTE: for the demo we do a different "BOOST" effect. What do we want to do here?
+ if ( !inv_demo.GetInt() )
+ {
+ if ( IsDamageBoosted() &&
+ pViewmodel->ViewModelIndex() != 0 )
+ {
+ return ret;
+ }
+
+ // Now overlay some shimmering ones.
+ render->SetBlend( 0.3 );
+
+ if ( IsDamageBoosted() )
+ {
+ // Radeon 9700 having a problem with this guy:
+ modelrender->ForcedMaterialOverride( m_BoostMaterial );
+ }
+ else
+ {
+ modelrender->ForcedMaterialOverride( m_EMPMaterial );
+ }
+
+ Vector vStart = pViewmodel->GetAbsOrigin();
+
+ float flOffset = damageboost_modeloffset.GetFloat();
+ for ( int i=0; i < 3; i++ )
+ {
+ // Place the model at a slight offset.
+ vStart[i] += flOffset * sin( m_BoostModelAngles[i] );
+ pViewmodel->SetLocalOrigin( vStart );
+ m_BoostModelAngles[i] += RandomFloat( damageboost_modelphasespeed_min.GetFloat(), damageboost_modelphasespeed_max.GetFloat() ) * gpGlobals->frametime;
+
+ // Invalidate the bones because they've been setup with our original position and cached,
+ // and we want to render it in a new spot with different bone transforms.
+ pViewmodel->InvalidateBoneCache();
+ ret = pViewmodel->DrawOverriddenViewmodel( flags );
+ }
+
+ // Reset the position and bone info.
+ pViewmodel->SetLocalOrigin( vStart );
+ pViewmodel->InvalidateBoneCache();
+
+ modelrender->ForcedMaterialOverride( NULL );
+ render->SetBlend( 1 );
+ }
+ }
+
+ return ret;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Players under adrenalin animate faster
+//-----------------------------------------------------------------------------
+float C_BaseTFPlayer::GetDefaultAnimSpeed( void )
+{
+ if ( HasPowerup( POWERUP_RUSH ) )
+ return ADRENALIN_ANIM_SPEED;
+
+ // Weapons may modify animation times
+ if ( GetActiveWeapon() )
+ return GetActiveWeapon()->GetDefaultAnimSpeed();
+
+ return 1.0;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: This is used to penalize the local viewer for moving around or rotating
+// the camera, it causes camo'd guys who are close to fade out their "white" effect
+// for a bit of time
+//-----------------------------------------------------------------------------
+void C_BaseTFPlayer::CheckCameraMovement( void )
+{
+ float dt = gpGlobals->frametime;
+
+ float vel = GetAbsVelocity().Length();
+ float avel = fabs( GetLocalAngles().y - GetPrevLocalAngles().y );
+ if ( dt > 0.0f )
+ {
+ avel *= 1.0f / dt;
+ }
+
+ float frac1 = 0.0f;
+ if ( vel > CAMO_DAMPENINGVELOCITY_CUTOFF )
+ {
+ frac1 = ( vel - CAMO_DAMPENINGVELOCITY_CUTOFF ) / ( CAMO_DAMPENINGVELOCITY_MAX - CAMO_DAMPENINGVELOCITY_CUTOFF );
+ frac1 = MIN( 0.0f, frac1 );
+ frac1 = MAX( 1.0f, frac1 );
+
+ frac1 *= 50.0f;
+
+ m_flDampeningStayoutTime = gpGlobals->curtime + CAMO_STAYOUT_TIME;
+
+ }
+
+ float frac2 = 0.0f;
+ if ( avel > CAMO_DAMPENINGAVEL_CUTOFF )
+ {
+ frac2 = ( avel - CAMO_DAMPENINGAVEL_CUTOFF ) / ( CAMO_DAMPENINGAVEL_MAX - CAMO_DAMPENINGAVEL_CUTOFF );
+ frac2 = MIN( 0.0f, frac2 );
+ frac2 = MAX( 1.0f, frac2 );
+
+ frac2 *= 50.0f;
+
+ m_flDampeningStayoutTime = gpGlobals->curtime + CAMO_STAYOUT_TIME;
+
+ }
+
+ // Pick the greater
+ float amount = MAX( frac1, frac2 );
+
+ SetCamoDampening( amount );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Decay suppression camo amount
+//-----------------------------------------------------------------------------
+void C_BaseTFPlayer::CheckCamoDampening( void )
+{
+ CheckCameraMovement();
+
+ if ( m_flGoalDampeningAmount == m_flDampeningAmount )
+ return;
+
+ // Camouflage
+ float dt = gpGlobals->frametime;
+ float changeamount = ( dt * CAMO_DAMPENING_CHANGERATE );
+
+ // Move but don't overshoot
+ if ( m_flGoalDampeningAmount > m_flDampeningAmount )
+ {
+ m_flDampeningAmount += changeamount;
+ m_flDampeningAmount = MIN( m_flDampeningAmount, m_flGoalDampeningAmount );
+ }
+ else
+ {
+ if ( gpGlobals->curtime < m_flDampeningStayoutTime )
+ return;
+
+ m_flDampeningAmount -= changeamount;
+ m_flDampeningAmount = MAX( m_flDampeningAmount, m_flGoalDampeningAmount );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Force amount, decay happens in CheckCamoDampening
+// Input : amount -
+//-----------------------------------------------------------------------------
+void C_BaseTFPlayer::SetCamoDampening( float amount )
+{
+ m_flGoalDampeningAmount = amount;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: For camera movement by local player
+// Output : float
+//-----------------------------------------------------------------------------
+float C_BaseTFPlayer::GetDampeningAmount( void )
+{
+ return m_flDampeningAmount;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: This is used so that if you are watching a camo'd guy who is moving
+// he becomes more visible for a bit of time, before fading back out.
+// Input : amount -
+//-----------------------------------------------------------------------------
+void C_BaseTFPlayer::SetMovementCamoSuppression( float amount )
+{
+ m_flGoalMovementCamoSuppressionAmount = amount;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: This is used so that if you are watching a camo'd guy who is moving
+// he becomes more visible for a bit of time, before fading back out.
+//-----------------------------------------------------------------------------
+void C_BaseTFPlayer::CheckMovementCamoSuppression( void )
+{
+ // FIXME: Don't bother with suppression during deployment...
+ if ( m_bDeployed )
+ {
+ m_flMovementCamoSuppression = 0;
+ return;
+ }
+
+ float flSuppression = 0;
+
+ // Rotation blends them in a bit too
+ float avel = fabs( GetLocalAngles().y - GetPrevLocalAngles().y ) + fabs( GetLocalAngles().x - GetPrevLocalAngles().x );
+ if ( avel > CAMO_DAMPENINGAVEL_CUTOFF )
+ {
+ float frac2 = ( avel - CAMO_DAMPENINGAVEL_CUTOFF ) / ( CAMO_DAMPENINGAVEL_MAX - CAMO_DAMPENINGAVEL_CUTOFF );
+ frac2 = MIN( 0.0f, frac2 );
+ frac2 = MAX( 1.0f, frac2 );
+ flSuppression = 50.0f * frac2;
+ }
+
+ // Add in velocity blend
+ float vel = GetAbsVelocity().Length();
+ if ( vel > CAMO_DAMPENINGVELOCITY_CUTOFF )
+ {
+ float frac = ( vel- CAMO_DAMPENINGVELOCITY_CUTOFF ) / ( CAMO_DAMPENINGVELOCITY_MAX - CAMO_DAMPENINGVELOCITY_CUTOFF );
+ frac = MIN( 1.0f, frac );
+ flSuppression = MIN( 100.f, flSuppression + (100.0f * frac) );
+ }
+
+ // Set the camo aount
+ SetMovementCamoSuppression( flSuppression );
+ if ( flSuppression )
+ {
+ m_flMovementCamoSuppressionStayoutTime = gpGlobals->curtime + CAMO_MOVEMENT_PENALTYTIME;
+ }
+
+ if ( m_flGoalMovementCamoSuppressionAmount == m_flMovementCamoSuppression )
+ return;
+
+ // Camouflage
+ float dt = gpGlobals->frametime;
+ float changeamount = ( dt * CAMO_MOVESUPPRESSION_CHANGERATE );
+
+ // Move but don't overshoot
+ if ( m_flGoalMovementCamoSuppressionAmount > m_flMovementCamoSuppression )
+ {
+ m_flMovementCamoSuppression += changeamount;
+ m_flMovementCamoSuppression = MIN( m_flMovementCamoSuppression, m_flGoalMovementCamoSuppressionAmount );
+ }
+ else
+ {
+ if ( gpGlobals->curtime < m_flMovementCamoSuppressionStayoutTime )
+ return;
+
+ m_flMovementCamoSuppression -= changeamount;
+ m_flMovementCamoSuppression = MAX( m_flMovementCamoSuppression, m_flGoalMovementCamoSuppressionAmount );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Get the material used for this player's camo
+//-----------------------------------------------------------------------------
+IMaterial *C_BaseTFPlayer::GetCamoMaterial( void )
+{
+ if ( !m_pCamoEffectMaterial )
+ {
+ m_pCamoEffectMaterial = materials->FindMaterial("player/infiltratorcamo/infiltratorcamo", TEXTURE_GROUP_CLIENT_EFFECTS);
+ if ( m_pCamoEffectMaterial )
+ {
+ m_pCamoEffectMaterial->IncrementReferenceCount();
+ }
+ }
+
+ return m_pCamoEffectMaterial;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Percentage suppression of camo effect up close based on velocity
+// Output : float
+//-----------------------------------------------------------------------------
+float C_BaseTFPlayer::GetMovementCamoSuppression( void )
+{
+ return m_flMovementCamoSuppression;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void C_BaseTFPlayer::CheckLastMovement( void )
+{
+ if ( GetAbsOrigin() != m_vecLastOrigin )
+ {
+ m_vecLastOrigin = GetAbsOrigin();
+ m_flLastMoveTime = gpGlobals->curtime;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Output : float
+//-----------------------------------------------------------------------------
+float C_BaseTFPlayer::GetLastMoveTime( void )
+{
+ return m_flLastMoveTime;
+}
+
+float C_BaseTFPlayer::GetLastDamageTime( void ) const
+{
+ return m_flLastDamageTime;
+}
+
+float C_BaseTFPlayer::GetLastGainHealthTime( void ) const
+{
+ return m_flLastGainHealthTime;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Output : float
+//-----------------------------------------------------------------------------
+float C_BaseTFPlayer::GetOverlayAlpha( void )
+{
+ float alpha = 1.0f;
+
+ C_BaseTFPlayer *local = GetLocalPlayer();
+ if ( local && local != this )
+ {
+ if ( local && GetTeamNumber() != local->GetTeamNumber() )
+ {
+ if ( IsCamouflaged() )
+ {
+ float frac = ( GetCamouflageAmount() / 100.0f );
+ alpha *= ( 1.0f - frac );
+ }
+
+ // Only applies to sniper right now
+ if ( m_iPlayerClass == TFCLASS_SNIPER )
+ {
+ float dt = gpGlobals->curtime - GetLastMoveTime();
+ if ( dt > SNIPER_STATIONARY_FADESTART )
+ {
+ if ( dt > SNIPER_STATIONARY_FADEFINISH )
+ {
+ alpha = 0.0;
+ }
+ else
+ {
+ float frac = ( dt - SNIPER_STATIONARY_FADESTART ) / ( SNIPER_STATIONARY_FADEFINISH - SNIPER_STATIONARY_FADESTART );
+ alpha *= ( 1.0f - frac );
+ }
+ }
+ }
+ }
+ }
+
+ alpha = MIN( 1.0f, alpha );
+ alpha = MAX( 0.0f, alpha );
+
+ return alpha;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+bool C_BaseTFPlayer::IsDeployed( void )
+{
+ return m_bDeployed;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+bool C_BaseTFPlayer::IsDeploying( void )
+{
+ return m_bDeploying;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+bool C_BaseTFPlayer::IsUnDeploying( void )
+{
+ return m_bUnDeploying;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Return true if the player's allowed to switch weapons in his current state
+//-----------------------------------------------------------------------------
+bool C_BaseTFPlayer::IsAllowedToSwitchWeapons( void )
+{
+ // Can't switch while deployed
+ if ( IsDeployed() || IsDeploying() || IsUnDeploying() )
+ return false;
+
+ if ( IsInAVehicle() && GetVehicle() )
+ {
+ IClientVehicle *pVehicle = GetVehicle();
+ int nRole = pVehicle->GetPassengerRole( this );
+ if (!pVehicle->IsPassengerUsingStandardWeapons(nRole))
+ {
+ return false;
+ }
+ }
+
+ // See if the weapon will allow us to switch
+ if ( GetActiveWeapon() && GetActiveWeapon()->IsAllowedToSwitch() == false )
+ return false;
+
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Get the number of objects of the specified type that this player has
+//-----------------------------------------------------------------------------
+int C_BaseTFPlayer::GetNumObjects( int iObjectType )
+{
+ int iCount = 0;
+ for (int i = 0; i < GetObjectCount(); i++)
+ {
+ if ( !GetObject(i) )
+ continue;
+
+ if ( GetObject(i)->GetType() == iObjectType )
+ {
+ iCount++;
+ }
+ }
+
+ return iCount;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+int C_BaseTFPlayer::GetObjectCount( void )
+{
+ return m_TFLocal.m_aObjects.Count();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+C_BaseObject *C_BaseTFPlayer::GetObject( int index )
+{
+ return m_TFLocal.m_aObjects[index].Get();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void C_BaseTFPlayer::AddEntity( void )
+{
+ BaseClass::AddEntity();
+
+ // Zero out model pitch, blending takes care of all of it.
+ SetLocalAnglesDim( X_INDEX, 0 );
+
+ m_PlayerAnimState.Update();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: See if it's time to start another adrenalin effect
+//-----------------------------------------------------------------------------
+void C_BaseTFPlayer::CheckAdrenalin( void )
+{
+ if ( m_flNextAdrenalinEffect && gpGlobals->curtime > m_flNextAdrenalinEffect )
+ {
+ ScreenFade_t sf;
+ memset( &sf, 0, sizeof( sf ) );
+ sf.a = 128;
+ sf.r = 0;
+ sf.g = 128;
+ sf.b = 0;
+ // One second
+ sf.duration = (unsigned short)((float)(1<<SCREENFADE_FRACBITS) * 1.0f );
+ if ( m_bFadingIn )
+ {
+ sf.fadeFlags = FFADE_IN;
+ }
+ else
+ {
+ sf.fadeFlags = FFADE_OUT;
+ }
+ vieweffects->Fade( sf );
+
+ m_bFadingIn = !m_bFadingIn;
+ m_flNextAdrenalinEffect = gpGlobals->curtime + 1.0;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Update this client's target entity
+//-----------------------------------------------------------------------------
+void C_BaseTFPlayer::UpdateIDTarget( void )
+{
+ if ( !IsLocalPlayer() )
+ return;
+
+ // If the server's forcing us to a specific ID target, use it instead
+ if ( m_TFLocal.m_iIDEntIndex )
+ {
+ m_iIDEntIndex = m_TFLocal.m_iIDEntIndex;
+ return;
+ }
+
+ // Clear old target and find a new one
+ m_iIDEntIndex = 0;
+
+ trace_t tr;
+ Vector vecStart, vecEnd;
+ VectorMA( MainViewOrigin(), 1500, MainViewForward(), vecEnd );
+ VectorMA( MainViewOrigin(), 48, MainViewForward(), vecStart );
+ UTIL_TraceLine( vecStart, vecEnd, MASK_SOLID, NULL, COLLISION_GROUP_NONE, &tr );
+ if ( tr.DidHitNonWorldEntity() )
+ {
+ C_BaseEntity *pEntity = tr.m_pEnt;
+ IClientVehicle *vehicle = GetVehicle();
+ C_BaseEntity *pVehicleEntity = vehicle ? vehicle->GetVehicleEnt() : NULL;
+
+ if ( pEntity && (pEntity != this) && (pEntity != pVehicleEntity) )
+ {
+ // Make sure it's not an object
+ if ( !dynamic_cast<C_BaseObject*>( pEntity ) )
+ {
+ m_iIDEntIndex = pEntity->entindex();
+ }
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Return the weapon to have open the weapon selection on, based upon our currently active weapon
+// If the currently active weapon is a two handed weapon, returns it's primary weapon.
+//-----------------------------------------------------------------------------
+C_BaseCombatWeapon *C_BaseTFPlayer::GetActiveWeaponForSelection( void )
+{
+ C_WeaponTwoHandedContainer *pTwoHandedWeapon = dynamic_cast<C_WeaponTwoHandedContainer*>( GetActiveWeapon() );
+ if ( pTwoHandedWeapon )
+ return pTwoHandedWeapon->m_hLeftWeapon;
+
+ return BaseClass::GetActiveWeaponForSelection();
+}
+
+//-----------------------------------------------------------------------------
+// HACK: Until we get a recon model, trail recon particles
+//-----------------------------------------------------------------------------
+void FX_ReconParticle( const Vector &vecOrigin, bool bBlue )
+{
+ CSmartPtr<CSimpleEmitter> pSimple = CSimpleEmitter::Create( "reconparticle" );
+ pSimple->SetSortOrigin( vecOrigin );
+ pSimple->SetNearClip( 32, 64 );
+
+ SimpleParticle *pParticle;
+
+ Vector offset;
+
+ for ( int i = 0; i < 1; i++ )
+ {
+ pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof(SimpleParticle), g_Mat_DustPuff[0], vecOrigin );
+
+ if ( pParticle != NULL )
+ {
+ pParticle->m_flLifetime = 0.0f;
+ pParticle->m_flDieTime = random->RandomFloat( 1.0f, 1.5f );
+
+ pParticle->m_vecVelocity = vec3_origin;
+
+ int color = random->RandomInt( 128, 192 );
+
+ if ( bBlue )
+ {
+ pParticle->m_uchColor[0] = color;
+ pParticle->m_uchColor[1] = color;
+ pParticle->m_uchColor[2] = 255;
+ }
+ else
+ {
+ pParticle->m_uchColor[0] = 255;
+ pParticle->m_uchColor[1] = color;
+ pParticle->m_uchColor[2] = color;
+ }
+ pParticle->m_uchStartAlpha = random->RandomInt( 192, 255 );
+ pParticle->m_uchEndAlpha = 0;
+ pParticle->m_uchStartSize = random->RandomInt( 12, 16 );
+ pParticle->m_uchEndSize = 0;
+ pParticle->m_flRoll = random->RandomInt( 0, 360 );
+ pParticle->m_flRollDelta = random->RandomFloat( -1.0f, 1.0f );
+ }
+ }
+}
+
+// Prediction stuff
+void C_BaseTFPlayer::PreThink( void )
+{
+ BaseClass::PreThink();
+
+ // Chain pre-think to player class.
+ if ( GetPlayerClass() )
+ {
+ GetPlayerClass()->PreClassThink();
+ }
+}
+
+void C_BaseTFPlayer::PostThink( void )
+{
+ BaseClass::PostThink();
+
+ // Chain post-think to player class.
+ if ( GetPlayerClass() )
+ {
+ GetPlayerClass()->PostClassThink();
+ }
+}
+
+C_PlayerClass *C_BaseTFPlayer::GetPlayerClass( void )
+{
+ return m_PlayerClasses.GetPlayerClass( PlayerClass() );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void C_BaseTFPlayer::SetVehicleRole( int nRole )
+{
+ if ( IsInAVehicle() )
+ {
+ C_BaseTFVehicle *pVehicle = ( C_BaseTFVehicle* )GetVehicle();
+ if ( pVehicle )
+ {
+ if ( nRole >= pVehicle->GetMaxPassengerCount() )
+ return;
+ }
+ }
+
+ char szCmd[64];
+ Q_snprintf( szCmd, sizeof( szCmd ), "vehicleRole %i\n", nRole );
+ engine->ServerCmd( szCmd );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+bool C_BaseTFPlayer::CanGetInVehicle( void )
+{
+ if ( GetPlayerClass() )
+ {
+ return GetPlayerClass()->CanGetInVehicle();
+ }
+
+ return true;
+}
+
+
+// How fast to avoid collisions with center of other object, in units per second
+#define AVOID_SPEED 1000.0f
+extern ConVar cl_forwardspeed;
+extern ConVar cl_backspeed;
+extern ConVar cl_sidespeed;
+
+static ConVar tf2_solidplayers( "tf2_solidplayers", "1", 0, "Treat players and objects as solid." );
+
+//-----------------------------------------------------------------------------
+// Client-side obstacle avoidance
+//-----------------------------------------------------------------------------
+void C_BaseTFPlayer::PerformClientSideObstacleAvoidance( float flFrameTime, CUserCmd *pCmd )
+{
+ if ( !tf2_solidplayers.GetBool() )
+ {
+ return;
+ }
+
+ // Don't avoid if noclipping or in movetype none
+ switch ( GetMoveType() )
+ {
+ case MOVETYPE_NOCLIP:
+ case MOVETYPE_NONE:
+ return;
+ default:
+ break;
+ }
+
+ // Try to steer away from any objects/players we might interpenetrate
+ Vector size = WorldAlignSize();
+
+ float radius = 0.5f * sqrt( size.x * size.x + size.y * size.y );
+ float curspeed = GetAbsVelocity().Length2D();
+
+ // int slot = 1;
+
+ //engine->Con_NPrintf( slot++, "speed %f\n", curspeed );
+ //engine->Con_NPrintf( slot++, "radius %f\n", radius );
+
+ // If running, use a larger radius
+ if ( curspeed > 100.0f )
+ {
+ float factor = ( 1.0f + ( curspeed - 100.0f ) / 100.0f );
+
+ // engine->Con_NPrintf( slot++, "scaleup (%f) to radius %f\n", factor, radius * factor );
+
+ radius = radius * factor;
+ }
+
+ CPlayerAndObjectEnumerator avoid( radius );
+ partition->EnumerateElementsInSphere( PARTITION_CLIENT_SOLID_EDICTS, GetAbsOrigin(), radius, false, &avoid );
+
+ // Okay, decide how to avoid if there's anything close by
+ int c = avoid.GetObjectCount();
+ if ( c <= 0 )
+ return;
+
+ Vector currentdir;
+ Vector rightdir;
+ AngleVectors( pCmd->viewangles, &currentdir, &rightdir, NULL );
+
+ bool istryingtomove = false;
+ bool ismovingforward = false;
+ if ( fabs( pCmd->forwardmove ) > 0.0f ||
+ fabs( pCmd->sidemove ) > 0.0f )
+ {
+ istryingtomove = true;
+ if ( pCmd->forwardmove > 1.0f )
+ {
+ ismovingforward = true;
+ }
+ }
+
+ //engine->Con_NPrintf( slot++, "moving %s forward %s\n", istryingtomove ? "true" : "false", ismovingforward ? "true" : "false" );
+
+ float adjustforwardmove = 0.0f;
+ float adjustsidemove = 0.0f;
+
+ int i;
+ for ( i = 0; i < c; i++ )
+ {
+ C_BaseEntity *obj = avoid.GetObject( i );
+ if( !obj )
+ continue;
+
+ float flHit1, flHit2;
+
+ // Figure out a 2D radius for the object
+ Vector vecWorldMins, vecWorldMaxs;
+ obj->CollisionProp()->WorldSpaceAABB( &vecWorldMins, &vecWorldMaxs );
+ Vector objSize = vecWorldMaxs - vecWorldMins;
+
+ float objectradius = /*0.5f **/ 1.0 * sqrt( objSize.x * objSize.x + objSize.y * objSize.y );
+
+ if ( !IntersectInfiniteRayWithSphere(
+ GetAbsOrigin(),
+ currentdir,
+ obj->GetAbsOrigin(),
+ objectradius,
+ &flHit1,
+ &flHit2 ) )
+ continue;
+
+ float force = 0.0f;
+
+ float forward = 0.0f, side = 0.0f;
+
+ Vector vecToObject = obj->GetAbsOrigin() - GetAbsOrigin();
+ Vector cross = vecToObject.Cross( currentdir );
+
+ //engine->Con_NPrintf( slot++, "object side %s\n", sign > 0.0f ? "right" : "left" );
+
+ if ( 0 && istryingtomove )
+ {
+/*
+ // Okay, line hits sphere in two points
+ // Determine how close line is to center of sphere and move sideways to avoid if we are
+ // actually trying to move forward
+ Vector deltaHit = vHit2 - vHit1;
+ float leg1 = ( deltaHit.Length() ) / 2.0f;
+
+ float distfromcenter = sqrt( leg1 * leg1 + objectradius * objectradius );
+
+ force = distfromcenter / radius;
+ force = clamp( force, 0.0f, 1.0f );
+ force = 1.0f - force;
+
+ if ( force <= 0.5f )
+ continue;
+
+ side = force * AVOID_SPEED;
+
+ // Move to right or left of object
+ side *= sign;
+*/
+ }
+ else
+ {
+ Vector deltaObject = vecToObject;
+ float dist = deltaObject.Length2D();
+
+ force = dist / radius;
+ force = clamp( force, 0.0f, 1.0f );
+ force = 1.0f - force;
+
+ //engine->Con_NPrintf( slot++, "dist %f/radius %f == %f\n", dist, radius, force );
+
+ if ( force <= 0.3f )
+ continue;
+
+ force = sqrt( force );
+
+ //engine->Con_NPrintf( slot++, "sqrt(force) == %f\n", force );
+
+ Vector moveDir = -vecToObject;
+ VectorNormalize( moveDir );
+
+ float fwd = currentdir.Dot( moveDir );
+ float rt = rightdir.Dot( moveDir );
+
+ //engine->Con_NPrintf( slot++, "fwd %f right %f\n", fwd, rt );
+
+ float sidescale = 2.0f;
+ float forwardscale = 1.0f;
+
+ if ( istryingtomove )
+ {
+ // If running, then do a lot more sideways veer since we're not going to do anything to
+ // forward velocity
+ sidescale = 4.0f;
+ forwardscale = 2.0f;
+ }
+
+ forward = forwardscale * fwd * force * AVOID_SPEED;
+ side = sidescale * rt * force * AVOID_SPEED;
+
+ //engine->Con_NPrintf( slot++, "forward %f side %f\n", forward, side );
+ }
+
+ adjustforwardmove += forward;
+ adjustsidemove += side;
+ }
+
+ pCmd->forwardmove += adjustforwardmove;
+ pCmd->sidemove += adjustsidemove;
+
+ if ( pCmd->forwardmove > 0.0f )
+ {
+ pCmd->forwardmove = clamp( pCmd->forwardmove, -cl_forwardspeed.GetFloat(), cl_forwardspeed.GetFloat() );
+ }
+ else
+ {
+ pCmd->forwardmove = clamp( pCmd->forwardmove, -cl_backspeed.GetFloat(), cl_backspeed.GetFloat() );
+ }
+ pCmd->sidemove = clamp( pCmd->sidemove, -cl_sidespeed.GetFloat(), cl_sidespeed.GetFloat() );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Input handling
+//-----------------------------------------------------------------------------
+void C_BaseTFPlayer::CreateMove( float flInputSampleTime, CUserCmd *pCmd )
+{
+ BaseClass::CreateMove( flInputSampleTime, pCmd );
+
+ // If the frozen flag is set, prevent view movement (server prevents the rest of the movement)
+ if ( GetFlags() & FL_FROZEN )
+ {
+ return;
+ }
+
+ if (!IsInVGuiInputMode() && !IsInAVehicle())
+ {
+ PerformClientSideObstacleAvoidance( TICK_INTERVAL, pCmd );
+ }
+}
+
+
+C_BaseAnimating* C_BaseTFPlayer::GetRenderedWeaponModel()
+{
+ // Attach to either their weapon model or their view model.
+ if ( C_BasePlayer::ShouldDrawLocalPlayer() || !IsLocalPlayer() )
+ {
+ // Hook it to their external weapon model.
+ C_BaseCombatWeapon *pWeapon = GetActiveWeapon();
+ if ( !pWeapon )
+ return NULL;
+
+ // If this a two-handed container (shield + weapon), return the left weapon.
+ C_WeaponTwoHandedContainer *pContainer = dynamic_cast< C_WeaponTwoHandedContainer* >( pWeapon );
+ if ( pContainer )
+ {
+ return pContainer->GetLeftWeapon();
+ }
+ else
+ {
+ return pWeapon;
+ }
+ }
+ else
+ {
+ return GetViewModel();
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void C_BaseTFPlayer::SetIDEnt( C_BaseEntity *pEntity )
+{
+ if ( pEntity )
+ m_TFLocal.m_iIDEntIndex = pEntity->entindex();
+ else
+ m_TFLocal.m_iIDEntIndex = 0;
+}
+
+
+C_VehicleTeleportStation* C_BaseTFPlayer::GetSelectedMCV() const
+{
+ return dynamic_cast< C_VehicleTeleportStation* >( m_hSelectedMCV.Get() );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Return true if this object can be +used by the player
+//-----------------------------------------------------------------------------
+bool C_BaseTFPlayer::IsUseableEntity( CBaseEntity *pEntity )
+{
+ // I can use vehicles
+ return dynamic_cast<C_BaseTFVehicle*>( pEntity );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Powerup has just started
+//-----------------------------------------------------------------------------
+void C_BaseTFPlayer::PowerupStart( int iPowerup, bool bInitial )
+{
+ Assert( iPowerup >= 0 && iPowerup < MAX_POWERUPS );
+
+ switch( iPowerup )
+ {
+ case POWERUP_RUSH:
+ {
+ // Play the rage start
+ if ( bInitial )
+ {
+ EmitSound( "BaseTFPlayer.Rage" );
+ }
+
+ // Start the looping breathing
+ CPASAttenuationFilter filter( this, "BaseTFPlayer.HeavyBreathing" );
+ EmitSound( filter, entindex(), "BaseTFPlayer.HeavyBreathing" );
+
+ if ( IsLocalPlayer() )
+ {
+ // Start the visual effects
+ if ( !m_flNextAdrenalinEffect )
+ {
+ m_flNextAdrenalinEffect = gpGlobals->curtime;
+ m_bFadingIn = false;
+ }
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ BaseClass::PowerupStart( iPowerup, bInitial );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Powerup has just finished
+//-----------------------------------------------------------------------------
+void C_BaseTFPlayer::PowerupEnd( int iPowerup )
+{
+ Assert( iPowerup >= 0 && iPowerup < MAX_POWERUPS );
+
+ switch( iPowerup )
+ {
+ case POWERUP_RUSH:
+ {
+ // Stop the looping breathing
+ StopSound( "BaseTFPlayer.HeavyBreathing" );
+
+ if ( IsLocalPlayer() )
+ {
+ // Stop the visual effects
+ if ( m_flNextAdrenalinEffect )
+ {
+ vieweffects->ClearAllFades();
+ }
+
+ m_flNextAdrenalinEffect = 0;
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ BaseClass::PowerupEnd( iPowerup );
+}
diff --git a/game/client/tf2/c_basetfplayer.h b/game/client/tf2/c_basetfplayer.h
new file mode 100644
index 0000000..b2fc64c
--- /dev/null
+++ b/game/client/tf2/c_basetfplayer.h
@@ -0,0 +1,386 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#if !defined( C_BASETFPLAYER_H )
+#define C_BASETFPLAYER_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "tf_vehicleshared.h"
+#include "c_baseplayer.h"
+#include "CommanderOverlay.h"
+#include "hud_minimap.h"
+#include "hud_targetreticle.h"
+#include "c_tfplayerlocaldata.h"
+#include "particlemgr.h"
+#include "particle_prototype.h"
+#include "particle_util.h"
+#include "tf_playeranimstate.h"
+
+class C_VehicleTeleportStation;
+class CViewSetup;
+class IMaterial;
+class C_Order;
+class C_BaseObject;
+class C_PlayerClass;
+class CPersonalShieldEffect;
+class CBasePredictedWeapon;
+class C_BaseViewModel;
+class CUserCmd;
+class C_WeaponCombatShield;
+
+//-----------------------------------------------------------------------------
+// Purpose: Client Side TF Player entity
+//-----------------------------------------------------------------------------
+class C_BaseTFPlayer : public C_BasePlayer
+{
+public:
+ DECLARE_CLASS( C_BaseTFPlayer, C_BasePlayer );
+ DECLARE_CLIENTCLASS();
+ DECLARE_ENTITY_PANEL();
+ DECLARE_MINIMAP_PANEL();
+ DECLARE_PREDICTABLE();
+
+ C_BaseTFPlayer();
+ virtual ~C_BaseTFPlayer();
+
+private:
+ void Clear(); // Clear all elements.
+
+public:
+ bool IsHidden() const;
+ bool IsDamageBoosted() const;
+
+ bool HasNamedTechnology( const char *name );
+
+ float LastAttackTime() const { return m_flLastAttackTime; }
+ void SetLastAttackTime( float flTime ) { m_flLastAttackTime = flTime; }
+
+ // Return this client's C_BaseTFPlayer pointer
+ static C_BaseTFPlayer* GetLocalPlayer( void )
+ {
+ return ( static_cast< C_BaseTFPlayer * >( C_BasePlayer::GetLocalPlayer() ) );
+ }
+
+ virtual void ClientThink( void );
+ virtual void OnPreDataChanged( DataUpdateType_t updateType );
+ virtual void OnDataChanged( DataUpdateType_t updateType );
+ virtual void PreDataUpdate( DataUpdateType_t updateType );
+ virtual void PostDataUpdate( DataUpdateType_t updateType );
+ virtual void ReceiveMessage( int classID, bf_read &msg );
+ virtual void Release( void );
+
+ virtual void ItemPostFrame( void );
+
+ virtual bool ShouldDraw();
+ virtual int DrawModel( int flags );
+
+ virtual void SetDormant( bool bDormant );
+
+ virtual void GetBoneControllers(float controllers[MAXSTUDIOBONES]);
+
+ virtual int GetRenderTeamNumber( void );
+ virtual void ComputeFxBlend( void );
+ virtual bool IsTransparent( void );
+
+ // Called by the view model if its rendering is being overridden.
+ virtual bool ViewModel_IsTransparent( void );
+
+ virtual bool IsOverridingViewmodel( void );
+ virtual int DrawOverriddenViewmodel( C_BaseViewModel *pViewmodel, int flags );
+ virtual void CreateMove( float flInputSampleTime, CUserCmd *pCmd );
+ virtual float GetDefaultAnimSpeed( void );
+
+ int GetClass( void );
+
+ // Called when not in tactical mode. Allows view to be overriden for things like driving a tank.
+ void OverrideView( CViewSetup *pSetup );
+
+ // Called when not in tactical mode. Allows view model drawing to be disabled for things like driving a tank.
+ bool ShouldDrawViewModel();
+
+ void GetTargetDescription( char *pDest, int bufferSize );
+
+ // Orders
+ void SetPersonalOrder( C_Order *pOrder );
+ void RemoveOrderTarget();
+
+ // Resources
+ int GetBankResources( void );
+
+ // Objects
+ void SetSelectedObject( C_BaseObject *pObject );
+ C_BaseObject *GetSelectedObject( void );
+ int GetNumObjects( int iObjectType );
+ int GetObjectCount( void );
+ C_BaseObject *GetObject( int index );
+
+ // Targets
+ void Add_Target( C_BaseEntity *pTarget, const char *sName );
+ void Remove_Target( C_BaseEntity *pTarget );
+ void Remove_Target( CTargetReticle *pTargetReticle );
+
+ void UpdateTargetReticles( void );
+
+ bool IsUsingThermalVision( void ) const;
+
+ // Weapon handling
+ virtual bool IsAllowedToSwitchWeapons( void );
+ virtual bool Weapon_ShouldSetLast( CBaseCombatWeapon *pOldWeapon, CBaseCombatWeapon *pNewWeapon );
+ virtual bool Weapon_ShouldSelectItem( CBaseCombatWeapon *pWeapon );
+ virtual C_BaseCombatWeapon *GetActiveWeaponForSelection( void );
+ virtual C_BaseCombatWeapon *GetLastWeaponBeforeObject( void ) { return m_hLastWeaponBeforeObject; }
+
+ virtual C_BaseAnimating* GetRenderedWeaponModel();
+
+ // ID Target
+ void SetIDEnt( C_BaseEntity *pEntity );
+ int GetIDTarget( void ) const;
+ void UpdateIDTarget( void );
+
+ bool IsKnockedDown( void ) const;
+ void CheckKnockdownState( void );
+ bool CheckKnockdownAngleOverride( void ) const;
+ void SetKnockdownAngles( const QAngle& ang );
+ void GetKnockdownAngles( QAngle& outAngles );
+ float GetKnockdownViewheightAdjust( void ) const;
+
+ // Team handling
+ virtual void TeamChange( int iNewTeam );
+
+ // Camouflage effect
+ virtual bool IsCamouflaged( void );
+ virtual float GetCamouflageAmount( void );
+ virtual float ComputeCamoEffectAmount( void ); // 0 - visible, 1 = invisible
+ virtual int ComputeCamoAlpha( void );
+ virtual void CheckCamoDampening( void );
+ virtual void SetCamoDampening( float amount );
+ virtual float GetDampeningAmount( void );
+ virtual void CheckCameraMovement( void );
+
+ IMaterial *GetCamoMaterial( void );
+ virtual float GetMovementCamoSuppression( void );
+ virtual void CheckMovementCamoSuppression( void );
+ virtual void SetMovementCamoSuppression( float amount );
+
+ // Adrenalin
+ void CheckAdrenalin( void );
+
+ void CheckLastMovement( void );
+ float GetLastMoveTime( void );
+ float GetOverlayAlpha( void );
+
+ float GetLastDamageTime( void ) const;
+ float GetLastGainHealthTime( void ) const;
+
+ // Powerups
+ virtual void PowerupStart( int iPowerup, bool bInitial );
+ virtual void PowerupEnd( int iPowerup );
+
+ // Sniper
+ bool IsDeployed( void );
+ bool IsDeploying( void );
+ bool IsUnDeploying( void );
+
+ virtual void AddEntity( void );
+
+ // Vertification
+ inline bool HasClass( void ) { return GetPlayerClass() != NULL; }
+
+ bool IsClass( TFClass iClass );
+
+
+ virtual int GetMaxHealth() const { return m_iMaxHealth; }
+
+ bool ClassProxyUpdate( int nClassID );
+
+ // Should this object cast shadows?
+ virtual ShadowType_t ShadowCastType();
+
+ // Prediction stuff
+ virtual void PreThink( void );
+ virtual void PostThink( void );
+
+ // Combat prototyping
+ bool IsBlocking( void ) const { return m_bIsBlocking; }
+ bool IsParrying( void ) const { return m_bIsParrying; }
+ void SetBlocking( bool bBlocking ) { m_bIsBlocking = bBlocking; }
+ void SetParrying( bool bParrying ) { m_bIsParrying = bParrying; }
+
+ // Vehicles
+ void SetVehicleRole( int nRole );
+ bool CanGetInVehicle( void );
+
+ // Returns true if we're in a vehicle and it's mounted on another vehicle
+ // (ie: are we in a manned gun that's mounted on a tank).
+ bool IsVehicleMounted() const;
+
+ virtual bool IsUseableEntity( CBaseEntity *pEntity );
+
+// Shared Client / Server code
+public:
+ bool IsHittingShield( const Vector &vecVelocity, float *flDamage );
+ C_WeaponCombatShield *GetCombatShield( void );
+ virtual void PainSound( void );
+
+public:
+ // Data for only the local player
+ CTFPlayerLocalData m_TFLocal;
+
+ // Accessors...
+ const QAngle& DeployedAngles() const { return m_vecDeployedAngles; }
+ int ZoneState() const { return m_iCurrentZoneState; }
+ float CamouflageAmount() const { return m_flCamouflageAmount; }
+ int PlayerClass() const { return m_iPlayerClass; }
+ C_PlayerClass *GetPlayerClass();
+ C_Order *PersonalOrder() { return m_hPersonalOrder; }
+ C_BaseEntity *SpawnPoint() { return m_hSpawnPoint.Get(); }
+
+ C_VehicleTeleportStation* GetSelectedMCV() const;
+
+ // Object sapper placement handling
+ //float m_flSapperAttachmentFinishTime;
+ //float m_flSapperAttachmentStartTime;
+ //CHandle< CGrenadeObjectSapper > m_hSapper;
+ //CHandle< CBaseObject > m_hSappedObject;
+ CHealthBarPanel *m_pSapperAttachmentStatus;
+
+private:
+ C_BaseTFPlayer( const C_BaseTFPlayer & );
+
+ // Client-side obstacle avoidance
+ void PerformClientSideObstacleAvoidance( float flFrameTime, CUserCmd *pCmd );
+
+ float m_flLastAttackTime;
+
+ EHANDLE m_hSelectedMCV;
+
+ // Weapon used before switching to an object placement
+ CHandle<C_BaseCombatWeapon> m_hLastWeaponBeforeObject;
+
+ float m_flCamouflageAmount;
+
+ // Movement.
+ Vector m_vecPosDelta;
+
+ enum { MOMENTUM_MAXSIZE = 10 };
+ float m_aMomentum[MOMENTUM_MAXSIZE];
+ int m_iMomentumHead;
+
+ // Player Class
+ int m_iPlayerClass;
+ C_AllPlayerClasses m_PlayerClasses;
+
+ // Spawn location...
+ EHANDLE m_hSpawnPoint;
+
+ // Orders
+ CHandle< C_Order > m_hSelectedOrder;
+ CHandle< C_Order > m_hPersonalOrder;
+ int m_iSelectedTarget;
+ int m_iPersonalTarget;
+ CUtlVector< CTargetReticle * > m_aTargetReticles; // A list of entities to show target reticles for
+
+ // Objects
+ CHandle< C_BaseObject > m_hSelectedObject;
+
+ int m_iLastHealth;
+
+ bool m_bIsBlocking;
+ bool m_bIsParrying;
+
+ bool m_bUnderAttack;
+ int m_iMaxHealth;
+ bool m_bDeployed;
+ bool m_bDeploying;
+ bool m_bUnDeploying;
+ QAngle m_vecDeployedAngles;
+ int m_iCurrentZoneState;
+ int m_TFPlayerFlags;
+
+ int m_nOldTacticalView;
+ int m_nOldPlayerClass;
+
+ float m_flNextUseCheck;
+
+ bool m_bOldThermalVision;
+ bool m_bOldAttachingSapper;
+
+ bool m_bOldKnockDownState;
+ float m_flStartKnockdown;
+ float m_flEndKnockdown;
+ QAngle m_vecOriginalViewAngles;
+ QAngle m_vecCurrentKnockdownAngles;
+ QAngle m_vecKnockDownGoalAngles;
+ bool m_bKnockdownOverrideAngles;
+ float m_flKnockdownViewheightAdjust;
+
+ CPlayerAnimState m_PlayerAnimState;
+
+ // For sniper hiding
+ float m_flLastMoveTime;
+ Vector m_vecLastOrigin;
+
+ // For material proxies
+ float m_flLastDamageTime;
+ float m_flLastGainHealthTime;
+
+ IMaterial *m_pThermalMaterial;
+ IMaterial *m_pCamoEffectMaterial;
+
+ // Camouflage
+ float m_flDampeningAmount;
+ float m_flGoalDampeningAmount;
+ float m_flDampeningStayoutTime;
+
+ // Suppression of camo based on movement
+ float m_flMovementCamoSuppression;
+ float m_flGoalMovementCamoSuppressionAmount;
+ float m_flMovementCamoSuppressionStayoutTime;
+
+ // Adrenalin
+ float m_flNextAdrenalinEffect;
+ bool m_bFadingIn;
+
+ // ID Target
+ int m_iIDEntIndex;
+
+ CMaterialReference m_BoostMaterial;
+ CMaterialReference m_EMPMaterial;
+ float m_BoostModelAngles[3];
+
+ // Personal shield effects.
+ CUtlLinkedList<CPersonalShieldEffect*, int> m_PersonalShieldEffects;
+
+ CHandle< C_WeaponCombatShield > m_hWeaponCombatShield;
+
+ // No one should call this
+ C_BaseTFPlayer& operator=( const C_BaseTFPlayer& src );
+
+ friend void RecvProxy_PlayerClass( const CRecvProxyData *pData, void *pStruct, void *pOut );
+
+
+ friend class CTFPrediction;
+};
+
+int GetLocalPlayerClass( void );
+bool IsLocalPlayerClass( int iClass );
+bool IsLocalPlayerInTactical( );
+inline C_BaseTFPlayer *ToBaseTFPlayer( C_BaseEntity *pEntity )
+{
+ if ( !pEntity || !pEntity->IsPlayer() )
+ return NULL;
+
+#if _DEBUG
+ return dynamic_cast<C_BaseTFPlayer *>( pEntity );
+#else
+ return static_cast<C_BaseTFPlayer *>( pEntity );
+#endif
+}
+
+#endif // C_BASETFPLAYER_H
diff --git a/game/client/tf2/c_controlzone.cpp b/game/client/tf2/c_controlzone.cpp
new file mode 100644
index 0000000..be220b4
--- /dev/null
+++ b/game/client/tf2/c_controlzone.cpp
@@ -0,0 +1,67 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $Workfile: $
+// $Date: $
+//
+//-----------------------------------------------------------------------------
+// $Log: $
+//
+// $NoKeywords: $
+//=============================================================================//
+#include "cbase.h"
+#include "c_controlzone.h"
+#include "mapdata.h"
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+C_ControlZone::C_ControlZone()
+{
+ m_nZoneNumber = 0;
+
+ m_pShowTriggers = cvar->FindVar("showtriggers");
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+C_ControlZone::~C_ControlZone()
+{
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Are we using showtriggers?
+// Output : Returns true on success, false on failure.
+//-----------------------------------------------------------------------------
+bool C_ControlZone::ShouldDraw()
+{
+ if ( !m_pShowTriggers )
+ return false;
+
+ return m_pShowTriggers->GetInt() != 0 ? true : false;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Update global map state based on data received
+// Input : bnewentity -
+//-----------------------------------------------------------------------------
+void C_ControlZone::OnDataChanged( DataUpdateType_t updateType )
+{
+ BaseClass::OnDataChanged( updateType );
+
+ CMapZones *zone;
+ if ( m_nZoneNumber < 1 ||
+ m_nZoneNumber > MAX_ZONES )
+ return;
+
+ zone = &MapData().m_Zones[ m_nZoneNumber -1 ];
+ zone->m_nControllingTeam = GetTeamNumber();
+}
+
+IMPLEMENT_CLIENTCLASS_DT(C_ControlZone, DT_ControlZone, CControlZone)
+ RecvPropInt( RECVINFO(m_nZoneNumber )),
+END_RECV_TABLE()
+
+
diff --git a/game/client/tf2/c_controlzone.h b/game/client/tf2/c_controlzone.h
new file mode 100644
index 0000000..8d0af26
--- /dev/null
+++ b/game/client/tf2/c_controlzone.h
@@ -0,0 +1,39 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $Workfile: $
+// $Date: $
+// $NoKeywords: $
+//=============================================================================//
+
+#if !defined( C_CONTROLZONE_H )
+#define C_CONTROLZONE_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+class ConVar;
+//-----------------------------------------------------------------------------
+// Purpose: Client side rep of control zone entity ( trigger, so not usually visible )
+//-----------------------------------------------------------------------------
+class C_ControlZone : public C_BaseEntity
+{
+public:
+ DECLARE_CLASS( C_ControlZone, C_BaseEntity );
+ DECLARE_CLIENTCLASS();
+
+ C_ControlZone();
+ virtual ~C_ControlZone();
+
+ virtual bool ShouldDraw();
+ virtual void OnDataChanged( DataUpdateType_t updateType );
+
+public:
+ int m_nZoneNumber;
+
+private:
+ const ConVar *m_pShowTriggers;
+};
+
+#endif // C_CONTROLZONE_H \ No newline at end of file
diff --git a/game/client/tf2/c_demo_entities.cpp b/game/client/tf2/c_demo_entities.cpp
new file mode 100644
index 0000000..e186ebb
--- /dev/null
+++ b/game/client/tf2/c_demo_entities.cpp
@@ -0,0 +1,35 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+#include "cbase.h"
+#include "c_demo_entities.h"
+
+
+IMPLEMENT_CLIENTCLASS_DT(C_Cycler_TF2Commando, DT_Cycler_TF2Commando, CCycler_TF2Commando)
+ RecvPropInt( RECVINFO(m_bShieldActive) ),
+ RecvPropFloat( RECVINFO(m_flShieldRaiseTime) ),
+ RecvPropFloat( RECVINFO(m_flShieldLowerTime) ),
+END_RECV_TABLE()
+
+C_Cycler_TF2Commando::C_Cycler_TF2Commando()
+{
+}
+
+float C_Cycler_TF2Commando::GetShieldRaiseTime() const
+{
+ return m_bShieldActive ? gpGlobals->curtime - m_flShieldRaiseTime : 0.0f;
+}
+
+float C_Cycler_TF2Commando::GetShieldLowerTime() const
+{
+ return !m_bShieldActive ? gpGlobals->curtime - m_flShieldLowerTime : 0.0f;
+}
+
+bool C_Cycler_TF2Commando::IsShieldActive() const
+{
+ return m_bShieldActive;
+}
+
diff --git a/game/client/tf2/c_demo_entities.h b/game/client/tf2/c_demo_entities.h
new file mode 100644
index 0000000..3966aad
--- /dev/null
+++ b/game/client/tf2/c_demo_entities.h
@@ -0,0 +1,36 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef C_DEMO_ENTITIES_H
+#define C_DEMO_ENTITIES_H
+
+#include "c_ai_basenpc.h"
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+class C_Cycler_TF2Commando : public C_AI_BaseNPC
+{
+ DECLARE_CLASS( C_Cycler_TF2Commando, C_AI_BaseNPC );
+public:
+ DECLARE_CLIENTCLASS();
+
+ C_Cycler_TF2Commando();
+
+ float GetShieldRaiseTime() const;
+ float GetShieldLowerTime() const;
+ bool IsShieldActive() const;
+
+private:
+ C_Cycler_TF2Commando( const C_Cycler_TF2Commando& );
+
+ bool m_bShieldActive;
+ float m_flShieldRaiseTime;
+ float m_flShieldLowerTime;
+};
+
+#endif // C_DEMO_ENTITIES_H
diff --git a/game/client/tf2/c_effect_shootingstar.cpp b/game/client/tf2/c_effect_shootingstar.cpp
new file mode 100644
index 0000000..98a4ecc
--- /dev/null
+++ b/game/client/tf2/c_effect_shootingstar.cpp
@@ -0,0 +1,179 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Client's Meteor
+//
+// $NoKeywords: $
+//=============================================================================//
+#include "cbase.h"
+#include "c_effect_shootingstar.h"
+#include "clienteffectprecachesystem.h"
+
+//=============================================================================
+//
+// Shooting Star Spawner Functionality
+//
+
+IMPLEMENT_CLIENTCLASS_DT( C_ShootingStarSpawner, DT_ShootingStarSpawner, CShootingStarSpawner )
+ RecvPropFloat( RECVINFO( m_flSpawnInterval ) ),
+END_RECV_TABLE()
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+C_ShootingStarSpawner::C_ShootingStarSpawner( void )
+{
+ SetNextClientThink( gpGlobals->curtime + m_flSpawnInterval );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void C_ShootingStarSpawner::ClientThink( void )
+{
+ // Spawn a number of shooting stars.
+ SpawnShootingStars();
+
+ // Randomly generate a next think time.
+ SetNextClientThink( gpGlobals->curtime + random->RandomFloat( 0.25, m_flSpawnInterval ) );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void C_ShootingStarSpawner::SpawnShootingStars( void )
+{
+ C_ShootingStar *pShootingStar = new C_ShootingStar;
+ if ( pShootingStar )
+ {
+ // In Space.
+ pShootingStar->SetFriction( 1.0f );
+ pShootingStar->SetGravity( 0.0f );
+
+ // Randomize the velocity. -- This isn't right, but works for the test!
+ Vector vecVelocity;
+ vecVelocity.x = ( GetAbsAngles().x ) * random->RandomFloat( 1.0f, 10.0f );
+ vecVelocity.y = ( GetAbsAngles().y ) * random->RandomFloat( 1.0f, 10.0f );
+ vecVelocity.z = ( GetAbsAngles().z ) * random->RandomFloat( 1.0f, 10.0f );
+
+ pShootingStar->Init( GetAbsOrigin(), vecVelocity, random->RandomFloat( 10.0f, 100.0f ), random->RandomFloat( 10.0f, 30.0f ) );
+ }
+}
+
+//=============================================================================
+//
+// Shooting Star Functionality
+//
+
+//Precahce the effects
+CLIENTEFFECT_REGISTER_BEGIN( PrecacheEffectShootingStars )
+CLIENTEFFECT_MATERIAL( "effects/redflare" )
+CLIENTEFFECT_REGISTER_END()
+
+//-----------------------------------------------------------------------------
+// Constructor
+//-----------------------------------------------------------------------------
+C_ShootingStar::C_ShootingStar( void ) : CSimpleEmitter( "ShootingStar" )
+{
+ m_flScale = 1.0f;
+ SetDynamicallyAllocated( false );
+}
+
+
+//-----------------------------------------------------------------------------
+// Destructor
+//-----------------------------------------------------------------------------
+C_ShootingStar::~C_ShootingStar( void )
+{
+}
+
+//-----------------------------------------------------------------------------
+// Destructor
+//-----------------------------------------------------------------------------
+void C_ShootingStar::Init( const Vector vecOrigin, const Vector vecVelocity, int nSize,
+ float flLifeTime )
+{
+ // Set the sort origin.
+ SetSortOrigin( vecOrigin );
+
+ // Create the initial particle and set the data.
+ SimpleParticle *pParticle = ( SimpleParticle* )AddParticle( sizeof( SimpleParticle ), GetPMaterial( "effects/redflare" ), vecOrigin );
+ if ( pParticle )
+ {
+ pParticle->m_vecVelocity = vecVelocity;
+
+ pParticle->m_uchColor[0] = pParticle->m_uchColor[1] = pParticle->m_uchColor[2] = 255;
+
+ pParticle->m_flRoll = random->RandomInt( 0, 360 );
+ pParticle->m_flRollDelta = random->RandomFloat( 1.0f, 4.0f );
+
+ pParticle->m_flLifetime = 0.0f;
+ pParticle->m_flDieTime = flLifeTime;
+
+ pParticle->m_uchStartAlpha = 255;
+ pParticle->m_uchEndAlpha = 0;
+ pParticle->m_uchStartSize = nSize;
+ pParticle->m_uchEndSize = ( nSize / 3 );
+ }
+
+ int iParticle = m_aParticles.AddToTail();
+ m_aParticles[iParticle] = pParticle;
+}
+
+//-----------------------------------------------------------------------------
+// Destructor
+//-----------------------------------------------------------------------------
+void C_ShootingStar::Destroy( void )
+{
+ // Destroy shooting star particles.
+ int nParticleCount = m_aParticles.Count();
+ for ( int iParticle = ( nParticleCount - 1 ); iParticle >= 0; iParticle-- )
+ {
+ SimpleParticle *pParticle = m_aParticles[iParticle];
+ m_aParticles.Remove( iParticle );
+ CSimpleEmitter::NotifyDestroyParticle( pParticle );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void C_ShootingStar::SetSortOrigin( const Vector &vSortOrigin )
+{
+ CSimpleEmitter::SetSortOrigin( vSortOrigin );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : timeDelta -
+//-----------------------------------------------------------------------------
+void C_ShootingStar::Update( float timeDelta )
+{
+ // Parent update.
+ CSimpleEmitter::Update( timeDelta );
+
+ // Don't update if the console is down.
+ if ( timeDelta <= 0.0f )
+ return;
+
+ // Are we still alive? Get the tail of the shooting star (last valid index)
+ // and test.
+ int nParticleCount = m_aParticles.Count();
+ if ( nParticleCount <= 0 )
+ return;
+
+ SimpleParticle *pParticle = m_aParticles[nParticleCount-1];
+ if ( pParticle->m_flLifetime >= pParticle->m_flDieTime )
+ {
+ Destroy();
+ return;
+ }
+
+ // Update the particles lifetime.
+ pParticle->m_flLifetime += timeDelta;
+
+ // Update the particle position.
+ pParticle->m_Pos += ( pParticle->m_vecVelocity * timeDelta );
+
+ SetLocalOrigin( pParticle->m_Pos );
+ SetSortOrigin( GetAbsOrigin() );
+}
diff --git a/game/client/tf2/c_effect_shootingstar.h b/game/client/tf2/c_effect_shootingstar.h
new file mode 100644
index 0000000..a0f5671
--- /dev/null
+++ b/game/client/tf2/c_effect_shootingstar.h
@@ -0,0 +1,72 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Client's Meteor
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef C_EFFECT_SHOOTINGSTAR_H
+#define C_EFFECT_SHOOTINGSTAR_H
+#pragma once
+
+#include "c_baseanimating.h"
+#include "particles_simple.h"
+
+class C_ShootingStar;
+
+//=============================================================================
+//
+// Client-side shooting star spawner.
+//
+class C_ShootingStarSpawner : public C_BaseEntity
+{
+ DECLARE_CLASS( C_ShootingStarSpawner, C_BaseEntity );
+
+public:
+
+ DECLARE_CLIENTCLASS();
+
+ C_ShootingStarSpawner();
+
+ void ClientThink( void );
+ void SpawnShootingStars( void );
+
+public:
+
+ float m_flSpawnInterval; // How often do I spawn meteors?
+};
+
+
+//=============================================================================
+//
+// Shooting Star Effect
+//
+class C_ShootingStar : public C_BaseAnimating, CSimpleEmitter
+{
+ DECLARE_CLASS( C_ShootingStar, C_BaseAnimating );
+
+public:
+
+ C_ShootingStar( );
+ ~C_ShootingStar( void );
+
+ void Init( const Vector vecOrigin, const Vector vecVelocity, int nSize, float flLifeTime );
+ void Destroy( void );
+
+ void Update( float timeDelta );
+
+public:
+
+ float m_flScale;
+
+private:
+
+ void SetSortOrigin( const Vector &vSortOrigin );
+
+private:
+ C_ShootingStar( const C_ShootingStar & );
+
+ CUtlVector<SimpleParticle*> m_aParticles;
+};
+
+#endif // C_EFFECT_SHOOTINGSTAR_H \ No newline at end of file
diff --git a/game/client/tf2/c_entity_burn_effect.cpp b/game/client/tf2/c_entity_burn_effect.cpp
new file mode 100644
index 0000000..08c4f89
--- /dev/null
+++ b/game/client/tf2/c_entity_burn_effect.cpp
@@ -0,0 +1,85 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+#include "cbase.h"
+#include "c_entity_burn_effect.h"
+
+
+#define NUM_BURN_PARTICLES_PER_SEC 50
+
+
+
+IMPLEMENT_CLIENTCLASS_DT( C_EntityBurnEffect, DT_EntityBurnEffect, CEntityBurnEffect )
+ RecvPropInt( RECVINFO( m_hBurningEntity ) )
+END_RECV_TABLE()
+
+
+
+C_EntityBurnEffect::C_EntityBurnEffect()
+{
+ m_pEmitter = CSimpleEmitter::Create( "Entity burn effect" );
+ if ( m_pEmitter.IsValid() )
+ {
+ m_hFireMaterial = m_pEmitter->GetPMaterial( "particle/fire" );
+ }
+ else
+ {
+ m_hFireMaterial = INVALID_MATERIAL_HANDLE;
+ }
+ m_Timer.Init( NUM_BURN_PARTICLES_PER_SEC );
+}
+
+
+void C_EntityBurnEffect::OnDataChanged( DataUpdateType_t updateType )
+{
+ if ( updateType == DATA_UPDATE_CREATED )
+ {
+ SetNextClientThink( CLIENT_THINK_ALWAYS );
+ }
+}
+
+
+void C_EntityBurnEffect::ClientThink()
+{
+ if ( !m_pEmitter.IsValid() || IsDormant() )
+ return;
+
+ // Add some burning particles to our target entity.
+ C_BaseEntity *pEnt = ClientEntityList().GetBaseEntity( m_hBurningEntity );
+ if ( !pEnt )
+ return;
+
+ float dt = gpGlobals->frametime;
+ while ( m_Timer.NextEvent( dt ) )
+ {
+ Vector vDims = (pEnt->WorldAlignMaxs() - pEnt->WorldAlignMins()) * 0.5f;
+ Vector vCenter = pEnt->GetAbsOrigin() + pEnt->WorldAlignMins() + vDims;
+ Vector vPos = vCenter + vDims * RandomVector( -0.7, 0.7 );
+
+ float flLifetime = 1;
+ float flRadius = 3;
+ unsigned char uchColor[4] = { 255, 100, 0, 100 };
+
+ SimpleParticle *pParticle = m_pEmitter->AddSimpleParticle( m_hFireMaterial, vPos, flLifetime, flRadius );
+ if ( pParticle )
+ {
+ pParticle->m_uchColor[0] = uchColor[0];
+ pParticle->m_uchColor[1] = uchColor[1];
+ pParticle->m_uchColor[2] = uchColor[2];
+
+ pParticle->m_uchEndAlpha = 0;
+ pParticle->m_uchStartAlpha = uchColor[3];
+
+ pParticle->m_vecVelocity.x = RandomFloat( -2, 2 );
+ pParticle->m_vecVelocity.y = RandomFloat( -2, 2 );
+ pParticle->m_vecVelocity.z = RandomFloat( 3, 29 );
+
+ // Pick up some velocity from the burning guy running around.
+ pParticle->m_vecVelocity += pEnt->GetAbsVelocity() * 0.6;
+ }
+ }
+}
+
diff --git a/game/client/tf2/c_entity_burn_effect.h b/game/client/tf2/c_entity_burn_effect.h
new file mode 100644
index 0000000..9a5d7d3
--- /dev/null
+++ b/game/client/tf2/c_entity_burn_effect.h
@@ -0,0 +1,44 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef C_ENTITY_BURN_EFFECT_H
+#define C_ENTITY_BURN_EFFECT_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "c_baseentity.h"
+#include "particle_util.h"
+#include "particles_simple.h"
+
+class C_EntityBurnEffect : public C_BaseEntity
+{
+public:
+
+ DECLARE_CLASS( C_EntityBurnEffect, C_BaseEntity );
+ DECLARE_CLIENTCLASS();
+
+ C_EntityBurnEffect();
+
+
+// Overrides.
+public:
+
+ virtual void OnDataChanged( DataUpdateType_t updateType );
+ virtual void ClientThink();
+
+
+private:
+ int m_hBurningEntity; // todo: this should be an ehandle but base networkables aren't setup for ehandles yet.
+
+ TimedEvent m_Timer;
+ CSmartPtr<CSimpleEmitter> m_pEmitter;
+ PMaterialHandle m_hFireMaterial;
+};
+
+
+#endif // C_ENTITY_BURN_EFFECT_H
diff --git a/game/client/tf2/c_env_meteor.cpp b/game/client/tf2/c_env_meteor.cpp
new file mode 100644
index 0000000..e2ccf53
--- /dev/null
+++ b/game/client/tf2/c_env_meteor.cpp
@@ -0,0 +1,651 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+#include "cbase.h"
+#include "C_Env_Meteor.h"
+#include "fx_explosion.h"
+#include "tempentity.h"
+#include "c_tracer.h"
+
+//=============================================================================
+//
+// Meteor Factory Functions
+//
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void C_MeteorFactory::CreateMeteor( int nID, int iType,
+ const Vector &vecPosition, const Vector &vecDirection,
+ float flSpeed, float flStartTime, float flDamageRadius,
+ const Vector &vecTriggerMins, const Vector &vecTriggerMaxs )
+{
+ C_EnvMeteor::Create( nID, iType, vecPosition, vecDirection, flSpeed, flStartTime, flDamageRadius,
+ vecTriggerMins, vecTriggerMaxs );
+}
+
+
+//=============================================================================
+//
+// Meteor Spawner Functions
+//
+
+void RecvProxy_MeteorTargetPositions( const CRecvProxyData *pData, void *pStruct, void *pOut )
+{
+ CEnvMeteorSpawnerShared *pSpawner = ( CEnvMeteorSpawnerShared* )pStruct;
+ pSpawner->m_aTargets[pData->m_iElement].m_vecPosition.x = pData->m_Value.m_Vector[0];
+ pSpawner->m_aTargets[pData->m_iElement].m_vecPosition.y = pData->m_Value.m_Vector[1];
+ pSpawner->m_aTargets[pData->m_iElement].m_vecPosition.z = pData->m_Value.m_Vector[2];
+}
+
+void RecvProxy_MeteorTargetRadii( const CRecvProxyData *pData, void *pStruct, void *pOut )
+{
+ CEnvMeteorSpawnerShared *pSpawner = ( CEnvMeteorSpawnerShared* )pStruct;
+ pSpawner->m_aTargets[pData->m_iElement].m_flRadius = pData->m_Value.m_Float;
+}
+
+void RecvProxyArrayLength_MeteorTargets( void *pStruct, int objectID, int currentArrayLength )
+{
+ CEnvMeteorSpawnerShared *pSpawner = ( CEnvMeteorSpawnerShared* )pStruct;
+ if ( pSpawner->m_aTargets.Count() < currentArrayLength )
+ {
+ pSpawner->m_aTargets.SetSize( currentArrayLength );
+ }
+}
+
+
+BEGIN_RECV_TABLE_NOBASE( CEnvMeteorSpawnerShared, DT_EnvMeteorSpawnerShared )
+ // Setup (read from) Worldcraft.
+ RecvPropInt ( RECVINFO( m_iMeteorType ) ),
+ RecvPropInt ( RECVINFO( m_bSkybox ) ),
+ RecvPropFloat ( RECVINFO( m_flMinSpawnTime ) ),
+ RecvPropFloat ( RECVINFO( m_flMaxSpawnTime ) ),
+ RecvPropInt ( RECVINFO( m_nMinSpawnCount ) ),
+ RecvPropInt ( RECVINFO( m_nMaxSpawnCount ) ),
+ RecvPropFloat ( RECVINFO( m_flMinSpeed ) ),
+ RecvPropFloat ( RECVINFO( m_flMaxSpeed ) ),
+
+ // Setup through Init.
+ RecvPropFloat ( RECVINFO( m_flStartTime ) ),
+ RecvPropInt ( RECVINFO( m_nRandomSeed ) ),
+ RecvPropVector ( RECVINFO( m_vecMinBounds ) ),
+ RecvPropVector ( RECVINFO( m_vecMaxBounds ) ),
+ RecvPropVector ( RECVINFO( m_vecTriggerMins ) ),
+ RecvPropVector ( RECVINFO( m_vecTriggerMaxs ) ),
+
+ // Target List
+ RecvPropArray2( RecvProxyArrayLength_MeteorTargets,
+ RecvPropVector( "meteortargetposition_array_element", 0, 0, 0, RecvProxy_MeteorTargetPositions ),
+ 16, 0, "meteortargetposition_array" ),
+
+ RecvPropArray2( RecvProxyArrayLength_MeteorTargets,
+ RecvPropFloat( "meteortargetradius_array_element", 0, 0, 0, RecvProxy_MeteorTargetRadii ),
+ 16, 0, "meteortargetradius_array" )
+END_RECV_TABLE()
+
+// This table encodes the CBaseEntity data.
+IMPLEMENT_CLIENTCLASS_DT( C_EnvMeteorSpawner, DT_EnvMeteorSpawner, CEnvMeteorSpawner )
+ RecvPropDataTable ( RECVINFO_DT( m_SpawnerShared ), 0, &REFERENCE_RECV_TABLE( DT_EnvMeteorSpawnerShared ) ),
+ RecvPropInt ( RECVINFO( m_fDisabled ) ),
+END_RECV_TABLE()
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+C_EnvMeteorSpawner::C_EnvMeteorSpawner()
+{
+}
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void C_EnvMeteorSpawner::OnDataChanged( DataUpdateType_t updateType )
+{
+ // Initialize the client side spawner.
+ m_SpawnerShared.Init( &m_Factory, m_SpawnerShared.m_nRandomSeed, m_SpawnerShared.m_flStartTime,
+ m_SpawnerShared.m_vecMinBounds, m_SpawnerShared.m_vecMaxBounds,
+ m_SpawnerShared.m_vecTriggerMins, m_SpawnerShared.m_vecTriggerMaxs );
+
+ // Set the next think to be the next spawn interval.
+ if ( !m_fDisabled )
+ {
+ SetNextClientThink( m_SpawnerShared.m_flNextSpawnTime );
+ }
+}
+
+#if 0
+// Will probably be used later!!
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void C_EnvMeteorSpawner::ReceiveMessage( int classID, bf_read &msg )
+{
+ if ( classID != GetClientClass()->m_ClassID )
+ {
+ // message is for subclass
+ BaseClass::ReceiveMessage( classID, msg );
+ return;
+ }
+
+ m_SpawnerShared.m_flStartTime = msg.ReadLong();
+ m_SpawnerShared.m_flNextSpawnTime = msg.ReadLong();
+ SetNextClientThink( m_SpawnerShared.m_flNextSpawnTime );
+}
+#endif
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void C_EnvMeteorSpawner::ClientThink( void )
+{
+ SetNextClientThink( m_SpawnerShared.MeteorThink( gpGlobals->curtime ) );
+}
+
+//=============================================================================
+//
+// Meteor Tail Functions
+//
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+C_EnvMeteorHead::C_EnvMeteorHead()
+{
+ m_vecPos.Init();
+ m_vecPrevPos.Init();
+
+ m_flParticleScale = 1.0f;
+
+ m_pSmokeEmitter = NULL;
+ m_flSmokeSpawnInterval = 0.0f;
+ m_hSmokeMaterial = INVALID_MATERIAL_HANDLE;
+ m_flSmokeLifetime = 2.5f;
+ m_bEmitSmoke = true;
+
+ m_hFlareMaterial = INVALID_MATERIAL_HANDLE;
+}
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+C_EnvMeteorHead::~C_EnvMeteorHead()
+{
+ Destroy();
+}
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void C_EnvMeteorHead::Start( const Vector &vecOrigin, const Vector &vecDirection )
+{
+ // Emitters.
+ m_pSmokeEmitter = CSimpleEmitter::Create( "MeteorTrail" );
+// m_pFireEmitter = CSimpleEmitter::Create( "MeteorFire" );
+ if ( !m_pSmokeEmitter /*|| !m_pFireEmitter*/ )
+ return;
+
+ // Smoke
+ m_pSmokeEmitter->SetSortOrigin( vecOrigin );
+ m_hSmokeMaterial = m_pSmokeEmitter->GetPMaterial( "particle/SmokeStack" );
+ Assert( m_hSmokeMaterial != INVALID_MATERIAL_HANDLE );
+
+ // Fire
+// m_pFireEmitter->SetSortOrigin( vecOrigin );
+// m_hFireMaterial = m_pFireEmitter->GetPMaterial( "particle/particle_fire" );
+// Assert( m_hFireMaterial != INVALID_MATERIAL_HANDLE );
+
+ // Flare
+// m_hFlareMaterial = m_ParticleEffect.FindOrAddMaterial( "effects/redflare" );
+
+ VectorCopy( vecDirection, m_vecDirection );
+ VectorCopy( vecOrigin, m_vecPos );
+
+ m_bInitThink = true;
+}
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void C_EnvMeteorHead::Destroy( void )
+{
+ m_pSmokeEmitter = NULL;
+}
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void C_EnvMeteorHead::MeteorHeadThink( const Vector &vecOrigin, float flTime )
+{
+ if ( m_bInitThink )
+ {
+ VectorCopy( vecOrigin, m_vecPrevPos );
+ m_bInitThink = false;
+ }
+
+ // Update the position of the emitters.
+ VectorCopy( vecOrigin, m_vecPos );
+
+ // Update Smoke
+ if ( m_pSmokeEmitter.IsValid() && m_bEmitSmoke )
+ {
+ m_pSmokeEmitter->SetSortOrigin( m_vecPos );
+
+ // Get distance covered
+ Vector vecDelta;
+ VectorSubtract( m_vecPos, m_vecPrevPos, vecDelta );
+ float flLength = vecDelta.Length();
+
+ int nParticleCount = flLength / 35.0f;
+ if ( nParticleCount < 1 )
+ {
+ nParticleCount = 1;
+ }
+
+ flLength /= nParticleCount;
+
+ Vector vecPos;
+ for( int iParticle = 0; iParticle < nParticleCount; ++iParticle )
+ {
+ vecPos = m_vecPrevPos + ( m_vecDirection * ( flLength * iParticle ) );
+
+ // Add some noise to the position.
+ Vector vecPosOffset;
+ vecPosOffset.Random( -m_flSmokeSpawnRadius, m_flSmokeSpawnRadius );
+ VectorAdd( vecPosOffset, vecPos, vecPosOffset );
+
+
+ SimpleParticle *pParticle = ( SimpleParticle* )m_pSmokeEmitter->AddParticle( sizeof( SimpleParticle ),
+ m_hSmokeMaterial,
+ vecPosOffset );
+ if ( pParticle )
+ {
+ pParticle->m_flLifetime = 0.0f;
+ pParticle->m_flDieTime = m_flSmokeLifetime;
+
+ // Add just a little movement.
+ pParticle->m_vecVelocity.Random( -5.0f, 5.0f );
+
+ pParticle->m_uchColor[0] = 255.0f;
+ pParticle->m_uchColor[1] = 255.0f;
+ pParticle->m_uchColor[2] = 255.0f;
+
+
+ pParticle->m_uchStartSize = 70 * m_flParticleScale;
+ pParticle->m_uchEndSize = 25 * m_flParticleScale;
+
+ float flAlpha = random->RandomFloat( 0.5f, 1.0f );
+ pParticle->m_uchStartAlpha = flAlpha * 255;
+ pParticle->m_uchEndAlpha = 0;
+
+ pParticle->m_flRoll = random->RandomInt( 0, 360 );
+ pParticle->m_flRollDelta = random->RandomFloat( -1.0f, 1.0f );
+ }
+ }
+ }
+
+ // Update Fire
+// if ( m_pFireEmitter && m_bEmitFire )
+// {
+// }
+
+ // Flare
+
+ // Save off position.
+ VectorCopy( m_vecPos, m_vecPrevPos );
+}
+
+//=============================================================================
+//
+// Meteor Tail Functions
+//
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+C_EnvMeteorTail::C_EnvMeteorTail()
+{
+ m_TailMaterialHandle = INVALID_MATERIAL_HANDLE;
+
+ m_pParticleMgr = NULL;
+ m_pParticle = NULL;
+
+ m_flFadeTime = 0.5f;
+ m_flWidth = 3.0f;
+}
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+C_EnvMeteorTail::~C_EnvMeteorTail()
+{
+ Destroy();
+}
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void C_EnvMeteorTail::Start( const Vector &vecOrigin, const Vector &vecDirection,
+ float flSpeed )
+{
+ // Set the particle manager.
+ m_pParticleMgr = ParticleMgr();
+ m_pParticleMgr->AddEffect( &m_ParticleEffect, this );
+ m_TailMaterialHandle = m_ParticleEffect.FindOrAddMaterial( "particle/guidedplasmaprojectile" );
+ m_pParticle = m_ParticleEffect.AddParticle( sizeof( StandardParticle_t ), m_TailMaterialHandle );
+ if ( m_pParticle )
+ {
+ m_pParticle->m_Pos = vecOrigin;
+ }
+
+ VectorCopy( vecDirection, m_vecDirection );
+ m_flSpeed = flSpeed;
+}
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void C_EnvMeteorTail::Destroy( void )
+{
+ if ( m_pParticleMgr )
+ {
+ m_pParticleMgr->RemoveEffect( &m_ParticleEffect );
+ m_pParticleMgr = NULL;
+ }
+}
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void C_EnvMeteorTail::DrawFragment( ParticleDraw* pDraw,
+ const Vector &vecStart, const Vector &vecDelta,
+ const Vector4D &vecStartColor, const Vector4D &vecEndColor,
+ float flStartV, float flEndV )
+{
+ if( !pDraw->GetMeshBuilder() )
+ return;
+
+ // Clip the fragment.
+ Vector vecVerts[4];
+ if ( !Tracer_ComputeVerts( vecStart, vecDelta, m_flWidth, vecVerts ) )
+ return;
+
+ // NOTE: Gotta get the winding right so it's not backface culled
+ // (we need to turn of backface culling for these bad boys)
+ CMeshBuilder* pMeshBuilder = pDraw->GetMeshBuilder();
+
+ pMeshBuilder->Position3f( vecVerts[0].x, vecVerts[0].y, vecVerts[0].z );
+ pMeshBuilder->TexCoord2f( 0, 0.0f, flStartV );
+ pMeshBuilder->Color4fv( vecStartColor.Base() );
+ pMeshBuilder->AdvanceVertex();
+
+ pMeshBuilder->Position3f( vecVerts[1].x, vecVerts[1].y, vecVerts[1].z );
+ pMeshBuilder->TexCoord2f( 0, 1.0f, flStartV );
+ pMeshBuilder->Color4fv( vecStartColor.Base() );
+ pMeshBuilder->AdvanceVertex();
+
+ pMeshBuilder->Position3f( vecVerts[3].x, vecVerts[3].y, vecVerts[3].z );
+ pMeshBuilder->TexCoord2f( 0, 1.0f, flEndV );
+ pMeshBuilder->Color4fv( vecEndColor.Base() );
+ pMeshBuilder->AdvanceVertex();
+
+ pMeshBuilder->Position3f( vecVerts[2].x, vecVerts[2].y, vecVerts[2].z );
+ pMeshBuilder->TexCoord2f( 0, 0.0f, flEndV );
+ pMeshBuilder->Color4fv( vecEndColor.Base() );
+ pMeshBuilder->AdvanceVertex();
+}
+
+void C_EnvMeteorTail::SimulateParticles( CParticleSimulateIterator *pIterator )
+{
+ Particle *pParticle = (Particle*)pIterator->GetFirst();
+ while ( pParticle )
+ {
+ // Update the particle position.
+ pParticle->m_Pos = GetLocalOrigin();
+
+ pParticle = (Particle*)pIterator->GetNext();
+ }
+}
+
+
+void C_EnvMeteorTail::RenderParticles( CParticleRenderIterator *pIterator )
+{
+ const Particle *pParticle = (const Particle *)pIterator->GetFirst();
+ while ( pParticle )
+ {
+ // Now draw the tail fragments...
+ Vector4D vecStartColor( 1.0f, 1.0f, 1.0f, 1.0f );
+ Vector4D vecEndColor( 1.0f, 1.0f, 1.0f, 0.0f );
+ Vector vecDelta, vecStartPos, vecEndPos;
+
+ // Calculate the tail.
+ Vector vecTailEnd;
+ vecTailEnd = GetLocalOrigin() + ( m_vecDirection * -m_flSpeed );
+
+ // Transform particles into camera space.
+ TransformParticle( m_pParticleMgr->GetModelView(), GetLocalOrigin(), vecStartPos );
+ TransformParticle( m_pParticleMgr->GetModelView(), vecTailEnd, vecEndPos );
+ float sortKey = vecStartPos.z;
+
+ // Draw the tail fragment.
+ VectorSubtract( vecStartPos, vecEndPos, vecDelta );
+ DrawFragment( pIterator->GetParticleDraw(), vecEndPos, vecDelta, vecEndColor, vecStartColor,
+ 1.0f - vecEndColor[3], 1.0f - vecStartColor[3] );
+
+ pParticle = (const Particle *)pIterator->GetNext( sortKey );
+ }
+}
+
+
+//=============================================================================
+//
+// Meteor Functions
+//
+
+static g_MeteorCounter = 0;
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+C_EnvMeteor::C_EnvMeteor()
+{
+}
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+C_EnvMeteor::~C_EnvMeteor()
+{
+}
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void C_EnvMeteor::ClientThink( void )
+{
+ // Get the current time.
+ float flTime = gpGlobals->curtime;
+
+ // Update the meteor.
+ if ( m_Meteor.IsInSkybox( flTime ) )
+ {
+ if ( m_Meteor.m_nLocation == METEOR_LOCATION_WORLD )
+ {
+ WorldToSkyboxThink( flTime );
+ }
+ else
+ {
+ SkyboxThink( flTime );
+ }
+ }
+ else
+ {
+ if ( m_Meteor.m_nLocation == METEOR_LOCATION_SKYBOX )
+ {
+ SkyboxToWorldThink( flTime );
+ }
+ else
+ {
+ WorldThink( flTime );
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void C_EnvMeteor::SkyboxThink( float flTime )
+{
+ float flDeltaTime = flTime - m_Meteor.m_flStartTime;
+ if ( flDeltaTime > METEOR_MAX_LIFETIME )
+ {
+ Destroy( this );
+ return;
+ }
+
+ // Check to see if the object is passive or not - act accordingly!
+ if ( !m_Meteor.IsPassive( flTime ) )
+ {
+ // Update meteor position.
+ Vector origin;
+ m_Meteor.GetPositionAtTime( flTime, origin );
+ SetLocalOrigin( origin );
+
+ // Update the position of the tail effect.
+ m_TailEffect.SetLocalOrigin( GetLocalOrigin() );
+ m_HeadEffect.MeteorHeadThink( GetLocalOrigin(), flTime );
+ }
+
+ // Add the entity to the active list - update!
+ AddEntity();
+}
+
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void C_EnvMeteor::WorldToSkyboxThink( float flTime )
+{
+ // Move the meteor from the world into the skybox.
+ m_Meteor.ConvertFromWorldToSkybox();
+
+ // Destroy the head effect. Recreate it.
+ m_HeadEffect.Destroy();
+ m_HeadEffect.Start( m_Meteor.m_vecStartPosition, m_vecTravelDir );
+ m_HeadEffect.SetSmokeEmission( true );
+ m_HeadEffect.SetParticleScale( 1.0f / 16.0f );
+ m_HeadEffect.m_bInitThink = true;
+
+ // Update to world model.
+ SetModel( "models/props/common/meteorites/meteor05.mdl" );
+
+ // Update the meteor position (move into the skybox!)
+ SetLocalOrigin( m_Meteor.m_vecStartPosition );
+
+ // Update (think).
+ SkyboxThink( flTime );
+}
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void C_EnvMeteor::SkyboxToWorldThink( float flTime )
+{
+ // Move the meteor from the skybox into the world.
+ m_Meteor.ConvertFromSkyboxToWorld();
+
+ // Destroy the head effect. Recreate it.
+ m_HeadEffect.Destroy();
+ m_HeadEffect.Start( m_Meteor.m_vecStartPosition, m_vecTravelDir );
+ m_HeadEffect.SetSmokeEmission( true );
+ m_HeadEffect.SetParticleScale( 1.0f );
+ m_HeadEffect.m_bInitThink = true;
+
+ // Update to world model.
+ SetModel( "models/props/common/meteorites/meteor04.mdl" );
+
+ SetLocalOrigin( m_Meteor.m_vecStartPosition );
+
+ // Update (think).
+ WorldThink( flTime );
+}
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void C_EnvMeteor::WorldThink( float flTime )
+{
+ // Update meteor position.
+ Vector vecEndPosition;
+ m_Meteor.GetPositionAtTime( flTime, vecEndPosition );
+
+ // m_Meteor must return the end position in world space for the trace to work.
+ Assert( GetMoveParent() == NULL );
+
+// Msg( "Client: Time = %lf, Position: %4.2f %4.2f %4.2f\n", flTime, vecEndPosition.x, vecEndPosition.y, vecEndPosition.z );
+
+ // Check to see if we struck the world. If so, cause an explosion.
+ trace_t trace;
+
+ Vector vecMin, vecMax;
+ GetRenderBounds( vecMin, vecMax );
+
+ // NOTE: This code works only if we aren't in hierarchy!!!
+ Assert( !GetMoveParent() );
+
+ CTraceFilterWorldOnly traceFilter;
+ UTIL_TraceHull( GetAbsOrigin(), vecEndPosition, vecMin, vecMax,
+ MASK_SOLID_BRUSHONLY, &traceFilter, &trace );
+
+ // Collision.
+ if ( ( trace.fraction < 1.0f ) && !( trace.surface.flags & SURF_SKY ) )
+ {
+ // Move up to the end.
+ Vector vecEnd = GetAbsOrigin() + ( ( vecEndPosition - GetAbsOrigin() ) * trace.fraction );
+
+ // Create an explosion effect!
+ BaseExplosionEffect().Create( vecEnd, 10, 32, TE_EXPLFLAG_NONE );
+
+ // Debugging Info!!!!
+// debugoverlay->AddBoxOverlay( vecEnd, Vector( -10, -10, -10 ), Vector( 10, 10, 10 ), QAngle( 0.0f, 0.0f, 0.0f ), 255, 0, 0, 0, 100 );
+
+ Destroy( this );
+ return;
+ }
+ else
+ {
+ // Move to the end.
+ SetLocalOrigin( vecEndPosition );
+ }
+
+ m_TailEffect.SetLocalOrigin( GetLocalOrigin() );
+ m_HeadEffect.MeteorHeadThink( GetLocalOrigin(), flTime );
+
+ // Add the entity to the active list - update!
+ AddEntity();
+}
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+C_EnvMeteor *C_EnvMeteor::Create( int nID, int iMeteorType, const Vector &vecOrigin,
+ const Vector &vecDirection, float flSpeed, float flStartTime,
+ float flDamageRadius,
+ const Vector &vecTriggerMins, const Vector &vecTriggerMaxs )
+{
+ C_EnvMeteor *pMeteor = new C_EnvMeteor;
+ if ( pMeteor )
+ {
+ pMeteor->m_Meteor.Init( nID, flStartTime, METEOR_PASSIVE_TIME, vecOrigin, vecDirection, flSpeed, flDamageRadius,
+ vecTriggerMins, vecTriggerMaxs );
+
+ // Initialize the meteor.
+ pMeteor->InitializeAsClientEntity( "models/props/common/meteorites/meteor05.mdl", RENDER_GROUP_OPAQUE_ENTITY );
+
+ // Handle forward simulation.
+ if ( ( pMeteor->m_Meteor.m_flStartTime + METEOR_MAX_LIFETIME ) < gpGlobals->curtime )
+ {
+ Destroy( pMeteor );
+ }
+
+ // Meteor Head and Tail
+ pMeteor->SetTravelDirection( vecDirection );
+
+ pMeteor->m_HeadEffect.SetSmokeEmission( true );
+ pMeteor->m_HeadEffect.Start( vecOrigin, vecDirection );
+ pMeteor->m_HeadEffect.SetParticleScale( 1.0f / 16.0f );
+
+ pMeteor->m_TailEffect.Start( vecOrigin, vecDirection, flSpeed );
+
+ pMeteor->SetNextClientThink( CLIENT_THINK_ALWAYS );
+ }
+
+ return pMeteor;
+}
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void C_EnvMeteor::Destroy( C_EnvMeteor *pMeteor )
+{
+ Assert( pMeteor->GetClientHandle() != INVALID_CLIENTENTITY_HANDLE );
+ ClientThinkList()->AddToDeleteList( pMeteor->GetClientHandle() );
+}
diff --git a/game/client/tf2/c_env_meteor.h b/game/client/tf2/c_env_meteor.h
new file mode 100644
index 0000000..77e4d52
--- /dev/null
+++ b/game/client/tf2/c_env_meteor.h
@@ -0,0 +1,189 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef C_ENV_METEOR_H
+#define C_ENV_METEOR_H
+#pragma once
+
+#include "utlvector.h"
+#include "env_meteor_shared.h"
+#include "baseparticleentity.h"
+#include "c_effect_shootingstar.h"
+
+//=============================================================================
+//
+// Client-side Meteor Factory Class
+//
+class C_MeteorFactory : public IMeteorFactory
+{
+public:
+
+ void CreateMeteor( int nID, int iType, const Vector &vecPosition,
+ const Vector &vecDirection, float flSpeed, float flStartTime,
+ float flDamageRadius,
+ const Vector &vecTriggerMins, const Vector &vecTriggerMaxs );
+};
+
+//=============================================================================
+//
+// Meteor Spawner Class
+//
+class C_EnvMeteorSpawner : public C_BaseEntity
+{
+public:
+
+ DECLARE_CLASS( C_EnvMeteorSpawner, C_BaseEntity );
+
+ DECLARE_CLIENTCLASS();
+
+ C_EnvMeteorSpawner();
+
+ // Will more than likely be used for meteor input(s) later!
+// void ReceiveMessage( const char *msgname, int length, void *data );
+
+ //-------------------------------------------------------------------------
+ // Networking
+ //-------------------------------------------------------------------------
+ void OnDataChanged( DataUpdateType_t updateType );
+
+ //-------------------------------------------------------------------------
+ // Think
+ //-------------------------------------------------------------------------
+ void ClientThink( void );
+
+private:
+
+ C_MeteorFactory m_Factory;
+ CEnvMeteorSpawnerShared m_SpawnerShared;
+ bool m_fDisabled;
+};
+
+
+//=============================================================================
+//
+// Meteor Tail Class - Effect
+//
+class C_EnvMeteorHead
+{
+public:
+
+ C_EnvMeteorHead();
+ ~C_EnvMeteorHead();
+
+ void Start( const Vector &vecOrigin, const Vector &vecDirection );
+ void Destroy( void );
+
+ void MeteorHeadThink( const Vector &vecOrigin, float flTime );
+
+ void SetSmokeEmission( bool bEmit ) { m_bEmitSmoke = bEmit; }
+ bool EmitSmoke( void ) { return m_bEmitSmoke; }
+
+ void SetParticleScale( float flScale ) { m_flParticleScale = flScale; }
+
+ bool m_bInitThink;
+
+private:
+
+ Vector m_vecPos;
+ Vector m_vecPrevPos;
+ Vector m_vecDirection;
+
+ float m_flParticleScale;
+
+ CSmartPtr<CSimpleEmitter> m_pSmokeEmitter;
+ float m_flSmokeSpawnInterval;
+ float m_flSmokeSpawnRadius;
+ PMaterialHandle m_hSmokeMaterial;
+ float m_flSmokeLifetime; // How long do the particles live?
+ bool m_bEmitSmoke;
+
+ PMaterialHandle m_hFlareMaterial;
+};
+
+//=============================================================================
+//
+// Meteor Tail Class - Effect
+//
+class C_EnvMeteorTail : public C_BaseParticleEntity
+{
+public:
+
+ DECLARE_CLASS( C_EnvMeteorTail, C_BaseParticleEntity );
+
+ C_EnvMeteorTail();
+ ~C_EnvMeteorTail();
+
+ void Start( const Vector &vecOrigin, const Vector &vecDirection, float flSpeed );
+ void Destroy( void );
+ virtual void RenderParticles( CParticleRenderIterator *pIterator );
+ virtual void SimulateParticles( CParticleSimulateIterator *pIterator );
+
+//protected:
+
+ void DrawFragment( ParticleDraw* pDraw, const Vector &vecStart, const Vector &vecDelta,
+ const Vector4D &vecStartColor, const Vector4D &vecEndColor,
+ float flStartV, float flEndV );
+
+ CParticleMgr *m_pParticleMgr;
+ Particle *m_pParticle;
+
+ PMaterialHandle m_TailMaterialHandle;
+
+ // Properties.
+ float m_flFadeTime;
+ float m_flWidth;
+ float m_flSpeed;
+ Vector m_vecDirection;
+
+private:
+ C_EnvMeteorTail( const C_EnvMeteorTail & );
+};
+
+//=============================================================================
+//
+// Meteor Class (Client-side only!)
+//
+class C_EnvMeteor : public C_BaseAnimating
+{
+public:
+
+ DECLARE_CLASS( C_EnvMeteor, C_BaseAnimating );
+
+ //-------------------------------------------------------------------------
+ // Initialization/Destruction
+ //-------------------------------------------------------------------------
+ C_EnvMeteor();
+ ~C_EnvMeteor();
+ static C_EnvMeteor *Create( int nID, int iMeteorType, const Vector &vecOrigin,
+ const Vector &vecDirection, float flSpeed, float flStartTime,
+ float flDamageRadius,
+ const Vector &vecTriggerMins, const Vector &vecTriggerMaxs );
+ static void Destroy( C_EnvMeteor *pMeteor );
+
+ //-------------------------------------------------------------------------
+ // Think
+ //-------------------------------------------------------------------------
+ void ClientThink( void );
+ void SkyboxThink( float flTime );
+ void WorldThink( float flTime );
+ void WorldToSkyboxThink( float flTime );
+ void SkyboxToWorldThink( float flTime );
+
+ void SetTravelDirection( const Vector &vecDir ) { m_vecTravelDir = vecDir; }
+
+private:
+ C_EnvMeteor( const C_EnvMeteor & );
+
+ CEnvMeteorShared m_Meteor;
+
+ // Effects
+ Vector m_vecTravelDir;
+ C_EnvMeteorHead m_HeadEffect;
+ C_EnvMeteorTail m_TailEffect;
+};
+
+#endif // C_ENV_METEOR_H
diff --git a/game/client/tf2/c_func_construction_yard.cpp b/game/client/tf2/c_func_construction_yard.cpp
new file mode 100644
index 0000000..200f8fd
--- /dev/null
+++ b/game/client/tf2/c_func_construction_yard.cpp
@@ -0,0 +1,42 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: A place where vehicles can be built
+//
+// $NoKeywords: $
+//=============================================================================//
+#include "cbase.h"
+
+//-----------------------------------------------------------------------------
+// Purpose: A place where vehicles can be built
+//-----------------------------------------------------------------------------
+class C_FuncConstructionYard : public C_BaseEntity
+{
+ DECLARE_CLASS( C_FuncConstructionYard, C_BaseEntity );
+public:
+ DECLARE_CLIENTCLASS();
+// DECLARE_MINIMAP_PANEL();
+
+ C_FuncConstructionYard();
+ const char *GetTargetDescription( void ) const;
+};
+
+
+IMPLEMENT_CLIENTCLASS_DT(C_FuncConstructionYard, DT_FuncConstructionYard, CFuncConstructionYard)
+END_RECV_TABLE()
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+C_FuncConstructionYard::C_FuncConstructionYard()
+{
+// CONSTRUCT_MINIMAP_PANEL( "minimap_construction_yard", MINIMAP_RESOURCE_ZONES );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+const char *C_FuncConstructionYard::GetTargetDescription( void ) const
+{
+ return "Construction Yard";
+}
+
diff --git a/game/client/tf2/c_func_resource.cpp b/game/client/tf2/c_func_resource.cpp
new file mode 100644
index 0000000..ac9dc5b
--- /dev/null
+++ b/game/client/tf2/c_func_resource.cpp
@@ -0,0 +1,263 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Client's CResourceZone.
+//
+// $NoKeywords: $
+//=============================================================================//
+#include "cbase.h"
+#include "engine/IEngineSound.h"
+#include "c_func_resource.h"
+#include "techtree.h"
+#include "fx.h"
+#include "fx_sparks.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+// Chunk movement
+#define CHUNK_FLECK_MIN_SPEED 25.0f
+#define CHUNK_FLECK_MAX_SPEED 100.0f
+#define CHUNK_FLECK_GRAVITY 800.0f
+#define CHUNK_FLECK_DAMPEN 0.3f
+#define CHUNK_FLECK_ANGULAR_SPRAY 0.8f
+
+IMPLEMENT_CLIENTCLASS_DT(C_ResourceZone, DT_ResourceZone, CResourceZone)
+ RecvPropFloat(RECVINFO(m_flClientResources)),
+ RecvPropInt(RECVINFO(m_nResourcesLeft)),
+END_RECV_TABLE()
+
+LINK_ENTITY_TO_CLASS( trigger_resourcezone, C_ResourceZone );
+BEGIN_PREDICTION_DATA( C_ResourceZone )
+END_PREDICTION_DATA();
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+C_ResourceZone::C_ResourceZone()
+{
+ CONSTRUCT_MINIMAP_PANEL( "minimap_resource_zone", MINIMAP_RESOURCE_ZONES );
+}
+
+//-----------------------------------------------------------------------------
+// Add, remove object from the panel
+//-----------------------------------------------------------------------------
+void C_ResourceZone::SetDormant( bool bDormant )
+{
+ BaseClass::SetDormant( bDormant );
+ ENTITY_PANEL_ACTIVATE( "resourcezone", (!bDormant && m_flClientResources > 0) );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void C_ResourceZone::OnDataChanged( DataUpdateType_t updateType )
+{
+ BaseClass::OnDataChanged( updateType );
+
+ if ( updateType == DATA_UPDATE_CREATED )
+ {
+ SetNextClientThink( gpGlobals->curtime + 1.0 );
+ }
+
+ // If I've just dried up, remove me from the minimap
+ if ( m_flClientResources <= 0 )
+ {
+ ENTITY_PANEL_ACTIVATE( "resourcezone", false );
+ DESTRUCT_MINIMAP_PANEL();
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+const char *C_ResourceZone::GetTargetDescription( void ) const
+{
+ return "Resource Zone";
+}
+
+
+//==========================================================================================================
+// Resource Spawner
+//==========================================================================================================
+IMPLEMENT_CLIENTCLASS_DT(C_ResourceSpawner, DT_ResourceSpawner, CResourceSpawner)
+ RecvPropInt(RECVINFO(m_bActive)),
+END_RECV_TABLE()
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+C_ResourceSpawner::C_ResourceSpawner( void )
+{
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void C_ResourceSpawner::OnDataChanged( DataUpdateType_t updateType )
+{
+ BaseClass::OnDataChanged( updateType );
+
+ if ( updateType == DATA_UPDATE_CREATED )
+ {
+ SetNextClientThink( gpGlobals->curtime + random->RandomFloat( 2.0, 4.0 ) );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Receive a spawn message from the server
+//-----------------------------------------------------------------------------
+void C_ResourceSpawner::ReceiveMessage( int classID, bf_read &msg )
+{
+ if ( classID != GetClientClass()->m_ClassID )
+ {
+ // message is for subclass
+ BaseClass::ReceiveMessage( classID, msg );
+ return;
+ }
+
+ // Make some particles
+ SpawnEffect( true );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void C_ResourceSpawner::ClientThink( void )
+{
+ SetNextClientThink( gpGlobals->curtime + random->RandomFloat( 2.0, 10.0 ) );
+
+ // Don't do random puffs if I'm not active
+ if ( !m_bActive )
+ return;
+
+ // Occasionally spurt as if I was making a chunk
+ if ( random->RandomInt(0, 20) == 5 )
+ {
+ SpawnEffect( true );
+ }
+ else
+ {
+ SpawnEffect( false );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Particle effects created when we spawn a chunk
+//-----------------------------------------------------------------------------
+void C_ResourceSpawner::SpawnEffect( bool bSpawningChunk )
+{
+ Vector normal = Vector(0,0,1);
+ Vector offset = GetAbsOrigin() + (normal * 16);
+ Vector dir;
+
+ float r = sResourceColor.r;
+ float g = sResourceColor.g;
+ float b = sResourceColor.b;
+
+ // Play a random puff sound
+ if ( bSpawningChunk )
+ {
+ EmitSound( "ResourceSpawner.BigPuff" );
+ }
+ else
+ {
+ EmitSound( "ResourceSpawner.Puff" );
+ }
+
+ // Chunks o'dirt
+ CSmartPtr<CFleckParticles> fleckEmitter = CFleckParticles::Create( "SpawnEffect 1", offset, Vector(5,5,5) );
+ if ( !fleckEmitter )
+ return;
+
+ // Setup our collision information
+ fleckEmitter->m_ParticleCollision.Setup( offset, &normal, CHUNK_FLECK_ANGULAR_SPRAY, CHUNK_FLECK_MIN_SPEED, CHUNK_FLECK_MAX_SPEED, CHUNK_FLECK_GRAVITY, CHUNK_FLECK_DAMPEN );
+
+ int numFlecks;
+ if ( bSpawningChunk )
+ numFlecks = random->RandomInt( 48, 64 );
+ else
+ numFlecks = random->RandomInt( 1, 3 );
+
+ // Dump out flecks
+ int i;
+ for ( i = 0; i < numFlecks; i++ )
+ {
+ FleckParticle *pParticle = (FleckParticle *) fleckEmitter->AddParticle( sizeof(FleckParticle), g_Mat_Fleck_Cement[random->RandomInt(0,1)], offset );
+
+ if ( pParticle == NULL )
+ break;
+
+ pParticle->m_flLifetime = 0.0f;
+ pParticle->m_flDieTime = random->RandomFloat(3.0f,5.0f);
+
+ if ( bSpawningChunk )
+ {
+ pParticle->m_uchSize = random->RandomInt( 4, 8 );
+ dir[0] = normal[0] + random->RandomFloat( -CHUNK_FLECK_ANGULAR_SPRAY, CHUNK_FLECK_ANGULAR_SPRAY );
+ dir[1] = normal[1] + random->RandomFloat( -CHUNK_FLECK_ANGULAR_SPRAY, CHUNK_FLECK_ANGULAR_SPRAY );
+ dir[2] = normal[2] + random->RandomFloat( -CHUNK_FLECK_ANGULAR_SPRAY, CHUNK_FLECK_ANGULAR_SPRAY );
+ pParticle->m_vecVelocity = dir * ( random->RandomFloat( CHUNK_FLECK_MIN_SPEED, CHUNK_FLECK_MAX_SPEED ) * ( 9 - pParticle->m_uchSize ) );
+ }
+ else
+ {
+ pParticle->m_uchSize = random->RandomInt( 2, 4 );
+ dir[0] = normal[0] + (random->RandomFloat( -CHUNK_FLECK_ANGULAR_SPRAY, CHUNK_FLECK_ANGULAR_SPRAY ) * 0.5);
+ dir[1] = normal[1] + (random->RandomFloat( -CHUNK_FLECK_ANGULAR_SPRAY, CHUNK_FLECK_ANGULAR_SPRAY ) * 0.5);
+ dir[2] = normal[2] + (random->RandomFloat( -CHUNK_FLECK_ANGULAR_SPRAY, CHUNK_FLECK_ANGULAR_SPRAY ) * 0.5);
+ pParticle->m_vecVelocity = dir * ( random->RandomFloat( CHUNK_FLECK_MIN_SPEED, CHUNK_FLECK_MAX_SPEED ) * 3);
+ }
+
+ pParticle->m_flRoll = random->RandomFloat( 0, 360 );
+ pParticle->m_flRollDelta = random->RandomFloat( 0, 360 );
+
+ pParticle->m_uchColor[0] = r;
+ pParticle->m_uchColor[1] = g;
+ pParticle->m_uchColor[2] = b;
+ }
+
+
+ // Create a couple of big, floating smoke clouds
+ if ( bSpawningChunk || random->RandomInt(0,10) == 0 )
+ {
+ CSmartPtr<CSimpleEmitter> pSmokeEmitter = CSimpleEmitter::Create( "SpawnEffect 2" );
+ pSmokeEmitter->SetSortOrigin( offset );
+ int iSmokeClouds = 2;
+ if ( !bSpawningChunk )
+ iSmokeClouds = 1;
+ for ( i = 0; i < iSmokeClouds; i++ )
+ {
+ SimpleParticle *pParticle = (SimpleParticle *) pSmokeEmitter->AddParticle( sizeof(SimpleParticle), g_Mat_DustPuff[1], offset );
+ if ( pParticle == NULL )
+ break;
+
+ pParticle->m_flLifetime = 0.0f;
+ pParticle->m_flDieTime = random->RandomFloat( 2.0f, 3.0f );
+
+ if ( bSpawningChunk )
+ {
+ pParticle->m_uchStartSize = 32;
+ pParticle->m_uchEndSize = 128;
+ }
+ else
+ {
+ pParticle->m_uchStartSize = 16;
+ pParticle->m_uchEndSize = 64;
+ }
+
+ dir[0] = normal[0] + random->RandomFloat( -0.4f, 0.4f );
+ dir[1] = normal[1] + random->RandomFloat( -0.4f, 0.4f );
+ dir[2] = normal[2] + random->RandomFloat( 0, 0.6f );
+ pParticle->m_vecVelocity = dir * random->RandomFloat( 2.0f, 24.0f )*(i+1);
+ pParticle->m_uchStartAlpha = 160;
+ pParticle->m_uchEndAlpha = 0;
+ pParticle->m_flRoll = random->RandomFloat( 180, 360 );
+ pParticle->m_flRollDelta = random->RandomFloat( -1, 1 );
+
+ pParticle->m_uchColor[0] = r;
+ pParticle->m_uchColor[1] = g;
+ pParticle->m_uchColor[2] = b;
+ }
+ }
+}
diff --git a/game/client/tf2/c_func_resource.h b/game/client/tf2/c_func_resource.h
new file mode 100644
index 0000000..fd22b28
--- /dev/null
+++ b/game/client/tf2/c_func_resource.h
@@ -0,0 +1,57 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Client's CObjectSentrygun
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef C_FUNC_RESOURCE_H
+#define C_FUNC_RESOURCE_H
+
+#include "commanderoverlay.h"
+#include "hud_minimap.h"
+
+
+//-----------------------------------------------------------------------------
+// Purpose: A resource zone
+//-----------------------------------------------------------------------------
+class C_ResourceZone : public C_BaseEntity
+{
+ DECLARE_CLASS( C_ResourceZone, C_BaseEntity );
+public:
+ DECLARE_PREDICTABLE();
+ DECLARE_CLIENTCLASS();
+ DECLARE_ENTITY_PANEL();
+ DECLARE_MINIMAP_PANEL();
+
+ C_ResourceZone();
+ virtual void SetDormant( bool bDormant );
+ virtual void OnDataChanged( DataUpdateType_t updateType );
+ const char *GetTargetDescription( void ) const;
+
+public:
+ float m_flClientResources; // Amount of resources left
+ int m_nResourcesLeft;
+};
+
+//-----------------------------------------------------------------------------
+// Purpose: A resource chunk spawning point in a resource zone
+//-----------------------------------------------------------------------------
+class C_ResourceSpawner : public C_BaseAnimating
+{
+ DECLARE_CLASS( C_ResourceSpawner, C_BaseAnimating );
+public:
+ DECLARE_CLIENTCLASS();
+
+ C_ResourceSpawner();
+ virtual void OnDataChanged( DataUpdateType_t updateType );
+ virtual void ReceiveMessage( int classID, bf_read &msg );
+ virtual void SpawnEffect( bool bSpawningChunk );
+ virtual void ClientThink( void );
+
+public:
+ bool m_bActive;
+};
+
+#endif // C_FUNC_RESOURCE_H
+
diff --git a/game/client/tf2/c_gasoline_blob.cpp b/game/client/tf2/c_gasoline_blob.cpp
new file mode 100644
index 0000000..800ee89
--- /dev/null
+++ b/game/client/tf2/c_gasoline_blob.cpp
@@ -0,0 +1,350 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+#include "cbase.h"
+#include "c_gasoline_blob.h"
+#include "gasoline_shared.h"
+#include "engine/IEngineSound.h"
+#include "clienteffectprecachesystem.h"
+
+static CUtlLinkedList<C_GasolineBlob*, int> g_GasolineBlobs;
+
+// If multiple blobs are within this distance to each other, then only one will
+// play a sound.
+#define BLOB_SOUND_RELATED_DISTANCE 600
+
+
+#define PUDDLE_START_SIZE 35
+#define PUDDLE_END_SIZE 65
+#define PUDDLE_GROW_TIME 0.5
+
+#define PUDDLE_FADE_TIME 1.0
+
+
+CLIENTEFFECT_REGISTER_BEGIN( PrecacheGasolineBlob )
+CLIENTEFFECT_MATERIAL( "decals/puddle" )
+CLIENTEFFECT_REGISTER_END()
+
+// ------------------------------------------------------------------------------------------------ //
+// CGasolineEmitter.
+// ------------------------------------------------------------------------------------------------ //
+
+CSmartPtr<CGasolineEmitter> CGasolineEmitter::Create( C_GasolineBlob *pBlob )
+{
+ CGasolineEmitter *pEmitter = new CGasolineEmitter;
+
+ pEmitter->m_pBlob = pBlob;
+
+ pEmitter->m_hFireMaterial = pEmitter->GetPMaterial( "particle/fire" );
+ pEmitter->m_hUnlitMaterial = pEmitter->GetPMaterial( "sprites/env_particles" );
+
+ pEmitter->m_Timer.Init( 40 );
+
+ return pEmitter;
+}
+
+
+void CGasolineEmitter::UpdateFire( float frametime )
+{
+ float flLifetime = gpGlobals->curtime - m_pBlob->m_flCreateTime;
+
+ float litPercent = 1;
+ if ( m_pBlob->IsLit() )
+ {
+ litPercent = 1 - (flLifetime / m_pBlob->m_flMaxLifetime);
+ if ( litPercent <= 0 )
+ return;
+ }
+ else
+ {
+ return;
+ }
+
+ // Don't show a burn effect for a blob that hasn't hit anything yet.
+ // If you do, it tends to make the flamethrower effect look weird.
+ if ( !m_pBlob->IsStopped() )
+ return;
+
+ // Make a coordinate system in which to spawn the particles. It
+ Vector vUp, vRight;
+ vUp.Init();
+ vRight.Init();
+ if ( m_pBlob->IsStopped() )
+ {
+ QAngle angles;
+ VectorAngles( m_pBlob->GetSurfaceNormal(), angles );
+ AngleVectors( angles, NULL, &vRight, &vUp );
+ }
+
+ PMaterialHandle hMaterial = m_hFireMaterial;
+ float flParticleLifetime = 1;
+ float flRadius = 7;
+ unsigned char uchColor[4] = { 255, 128, 0, 128 };
+ float flMaxZVel = 29;
+
+
+ float curDelta = frametime;
+ while ( m_Timer.NextEvent( curDelta ) )
+ {
+ // Based on how close we are to expiring, show less particles.
+ if ( RandomFloat( 0, 1 ) > litPercent )
+ continue;
+
+ Vector vPos = m_pBlob->GetAbsOrigin();
+ if ( m_pBlob->IsStopped() )
+ {
+ float flAngle = RandomFloat( 0, M_PI * 2 );
+ float flDist = RandomFloat( 0, GASOLINE_BLOB_RADIUS );
+ vPos += vRight * (cos( flAngle ) * flDist);
+ vPos += vUp * ( sin( flAngle ) * flDist );
+ }
+ else
+ {
+ vPos += RandomVector( -GASOLINE_BLOB_RADIUS, GASOLINE_BLOB_RADIUS );
+ }
+
+ SimpleParticle *pParticle = AddSimpleParticle( hMaterial, vPos, flParticleLifetime, flRadius );
+ if ( pParticle )
+ {
+ pParticle->m_uchColor[0] = uchColor[0];
+ pParticle->m_uchColor[1] = uchColor[1];
+ pParticle->m_uchColor[2] = uchColor[2];
+
+ pParticle->m_uchEndAlpha = 0;
+ pParticle->m_uchStartAlpha = uchColor[3];
+
+ pParticle->m_vecVelocity.x = RandomFloat( -2, 2 );
+ pParticle->m_vecVelocity.y = RandomFloat( -2, 2 );
+ pParticle->m_vecVelocity.z = RandomFloat( 3, flMaxZVel );
+ }
+ }
+}
+
+
+// ------------------------------------------------------------------------------------------------ //
+// C_GasolineBlob.
+// ------------------------------------------------------------------------------------------------ //
+
+IMPLEMENT_CLIENTCLASS_DT_NOBASE( C_GasolineBlob, DT_GasolineBlob, CGasolineBlob )
+ RecvPropInt( RECVINFO( m_BlobFlags ) ),
+ RecvPropVector( RECVINFO_NAME( m_vecNetworkOrigin, m_vecOrigin ) ),
+ RecvPropInt( RECVINFO_NAME(m_hNetworkMoveParent, moveparent), 0, RecvProxy_IntToMoveParent ),
+ RecvPropFloat( RECVINFO( m_flLitStartTime ) ),
+ RecvPropFloat( RECVINFO( m_flCreateTime ) ),
+ RecvPropFloat( RECVINFO( m_flMaxLifetime ) ),
+ RecvPropInt( RECVINFO( m_iTeamNum ) ),
+ RecvPropVector( RECVINFO( m_vSurfaceNormal ) )
+END_RECV_TABLE()
+
+
+C_GasolineBlob::C_GasolineBlob()
+{
+ m_pEmitter = CGasolineEmitter::Create( this );
+ m_vSurfaceNormal.Init();
+ m_flLitStartTime = 0;
+ m_bSoundOn = false;
+ g_GasolineBlobs.AddToTail( this );
+ m_flPuddleSize = PUDDLE_START_SIZE;
+ m_flPuddleFade = 1;
+}
+
+
+C_GasolineBlob::~C_GasolineBlob()
+{
+ g_GasolineBlobs.FindAndRemove( this );
+ StopSound();
+
+ // If a bunch of nearby blobs weren't playing a sound because we were, have them start their sound now.
+ FOR_EACH_LL( g_GasolineBlobs, i )
+ {
+ C_GasolineBlob *pBlob = g_GasolineBlobs[i];
+
+ if ( pBlob->IsSoundRelatedTo( this ) )
+ pBlob->CheckStartSound();
+ }
+}
+
+
+bool C_GasolineBlob::IsLit() const
+{
+ return (m_BlobFlags & BLOBFLAG_LIT) != 0;
+}
+
+
+bool C_GasolineBlob::IsStopped() const
+{
+ return (m_BlobFlags & BLOBFLAG_STOPPED) != 0;
+}
+
+
+const Vector& C_GasolineBlob::GetSurfaceNormal() const
+{
+ return m_vSurfaceNormal;
+}
+
+
+float C_GasolineBlob::GetLitStartTime() const
+{
+ return m_flLitStartTime;
+}
+
+
+void C_GasolineBlob::OnDataChanged( DataUpdateType_t type )
+{
+ BaseClass::OnDataChanged( type );
+
+ if ( type == DATA_UPDATE_CREATED )
+ {
+ SetNextClientThink( CLIENT_THINK_ALWAYS );
+ }
+
+ CheckStartSound();
+}
+
+
+void C_GasolineBlob::ClientThink()
+{
+ if ( m_pEmitter.IsValid() )
+ m_pEmitter->UpdateFire( gpGlobals->frametime );
+
+ // Grow the puddle a little.
+ if ( IsStopped() )
+ {
+ if ( IsLit() )
+ {
+ // Fade out after we get lit.
+ m_flPuddleFade -= gpGlobals->frametime / PUDDLE_FADE_TIME;
+ m_flPuddleFade = MAX( m_flPuddleFade, 0 );
+ }
+ else
+ {
+ // Grow the puddle until it's at its max size.
+ m_flPuddleSize += gpGlobals->frametime * ( PUDDLE_END_SIZE - PUDDLE_START_SIZE ) / PUDDLE_GROW_TIME;
+ m_flPuddleSize = MIN( m_flPuddleSize, PUDDLE_END_SIZE );
+ }
+ }
+}
+
+
+bool C_GasolineBlob::ShouldDraw()
+{
+ return IsStopped() && (m_flPuddleFade > 0);
+}
+
+
+int C_GasolineBlob::DrawModel( int flags )
+{
+ // Generate a basis.
+ QAngle angles;
+ VectorAngles( m_vSurfaceNormal, angles );
+
+ Vector vRight, vUp;
+ AngleVectors( angles, NULL, &vRight, &vUp );
+
+
+ float flAlpha = m_flPuddleFade * RemapVal( m_flPuddleSize, PUDDLE_START_SIZE, PUDDLE_END_SIZE, 0, 1 );
+ if ( flAlpha <= 0 )
+ return 0;
+
+
+ // Draw the puddle.
+ IMaterial *pMat = materials->FindMaterial( "decals/puddle", TEXTURE_GROUP_DECAL );
+ IMesh *pMesh = materials->GetDynamicMesh( true, NULL, NULL, pMat );
+ CMeshBuilder mb;
+ mb.Begin( pMesh, MATERIAL_QUADS, 1 );
+
+ Vector v;
+
+ v = GetAbsOrigin() + m_vSurfaceNormal + vRight*m_flPuddleSize - vUp*m_flPuddleSize;
+ mb.Position3f( v.x, v.y, v.z );
+ mb.Color4f( 1, 1, 1, flAlpha );
+ mb.Normal3f( VectorExpand( m_vSurfaceNormal ) );
+ mb.TexCoord2f( 0, 1, 0 );
+ mb.AdvanceVertex();
+
+ v = GetAbsOrigin() + m_vSurfaceNormal + vRight*m_flPuddleSize + vUp*m_flPuddleSize;
+ mb.Position3f( v.x, v.y, v.z );
+ mb.Color4f( 1, 1, 1, flAlpha );
+ mb.Normal3f( VectorExpand( m_vSurfaceNormal ) );
+ mb.TexCoord2f( 0, 1, 1 );
+ mb.AdvanceVertex();
+
+ v = GetAbsOrigin() + m_vSurfaceNormal - vRight*m_flPuddleSize + vUp*m_flPuddleSize;
+ mb.Position3f( v.x, v.y, v.z );
+ mb.Color4f( 1, 1, 1, flAlpha );
+ mb.Normal3f( VectorExpand( m_vSurfaceNormal ) );
+ mb.TexCoord2f( 0, 0, 1 );
+ mb.AdvanceVertex();
+
+ v = GetAbsOrigin() + m_vSurfaceNormal - vRight*m_flPuddleSize - vUp*m_flPuddleSize;
+ mb.Position3f( v.x, v.y, v.z );
+ mb.Color4f( 1, 1, 1, flAlpha );
+ mb.Normal3f( VectorExpand( m_vSurfaceNormal ) );
+ mb.TexCoord2f( 0, 0, 0 );
+ mb.AdvanceVertex();
+
+ mb.End( false, true );
+
+ return 0;
+}
+
+
+bool C_GasolineBlob::IsSoundRelatedTo( const C_GasolineBlob *pBlob ) const
+{
+ return pBlob->GetAbsOrigin().DistTo( GetAbsOrigin() ) < BLOB_SOUND_RELATED_DISTANCE;
+}
+
+
+bool C_GasolineBlob::IsPlayingBurningSound() const
+{
+ return m_bSoundOn;
+}
+
+
+void C_GasolineBlob::CheckStartSound()
+{
+ if ( IsPlayingBurningSound() || (m_BlobFlags & BLOBFLAG_STOPPED) == 0 || !IsLit() )
+ return;
+
+
+ // First, make sure no nearby blob is playing the sound.
+ FOR_EACH_LL( g_GasolineBlobs, i )
+ {
+ C_GasolineBlob *pBlob = g_GasolineBlobs[i];
+
+ if ( pBlob != this && pBlob->IsSoundRelatedTo( this ) )
+ {
+ // If it's already playing a sound, then don't start our sound.
+ if ( pBlob->IsPlayingBurningSound() )
+ return;
+ }
+ }
+
+
+ StartSound();
+}
+
+
+void C_GasolineBlob::StartSound()
+{
+ if ( !m_bSoundOn )
+ {
+ EmitSound( "GasolineBlob.FlameSound" );
+
+ m_bSoundOn = true;
+ }
+}
+
+
+void C_GasolineBlob::StopSound()
+{
+ if ( m_bSoundOn )
+ {
+ BaseClass::StopSound( "GasolineBlob.FlameSound" );
+ m_bSoundOn = false;
+ }
+}
+
diff --git a/game/client/tf2/c_gasoline_blob.h b/game/client/tf2/c_gasoline_blob.h
new file mode 100644
index 0000000..101dfca
--- /dev/null
+++ b/game/client/tf2/c_gasoline_blob.h
@@ -0,0 +1,107 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef C_GASOLINE_BLOB_H
+#define C_GASOLINE_BLOB_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+
+#include "c_baseentity.h"
+#include "particles_simple.h"
+#include "particle_util.h"
+
+
+class C_GasolineBlob;
+
+class CGasolineEmitter : public CSimpleEmitter
+{
+public:
+
+ static CSmartPtr<CGasolineEmitter> Create( C_GasolineBlob *pBlob );
+
+ void UpdateFire( float frametime );
+
+
+private:
+
+ CGasolineEmitter() : CSimpleEmitter( "Gasoline" ){}
+ CGasolineEmitter( const CGasolineEmitter & );
+
+
+ C_GasolineBlob *m_pBlob;
+
+ PMaterialHandle m_hFireMaterial;
+ PMaterialHandle m_hUnlitMaterial;
+ TimedEvent m_Timer;
+};
+
+
+class C_GasolineBlob : public C_BaseEntity
+{
+friend class CGasolineEmitter;
+
+public:
+ DECLARE_CLASS( C_GasolineBlob, C_BaseEntity );
+ DECLARE_CLIENTCLASS();
+
+
+ C_GasolineBlob();
+ virtual ~C_GasolineBlob();
+
+ bool IsLit() const;
+ bool IsStopped() const;
+ const Vector& GetSurfaceNormal() const;
+ float GetLitStartTime() const;
+
+
+// Overrides.
+public:
+
+ virtual void OnDataChanged( DataUpdateType_t type );
+ virtual void ClientThink();
+ virtual int DrawModel( int flags );
+ virtual bool ShouldDraw();
+
+
+private:
+
+ // Returns true if the two blobs relate their sound, meaning one blob won't play
+ // its sound if the other one is playing it.
+ bool IsSoundRelatedTo( const C_GasolineBlob *pBlob ) const;
+
+ bool IsPlayingBurningSound() const;
+
+ // Starts the burning sound if no other flames are playing the sound nearby.
+ void CheckStartSound();
+
+ // Make the burning sound.
+ void StartSound();
+ void StopSound();
+
+
+private:
+
+ bool m_bSoundOn;
+ float m_flPuddleSize;
+ float m_flPuddleFade;
+
+ CSmartPtr<CGasolineEmitter> m_pEmitter;
+
+ float m_flLitStartTime;
+
+ float m_flCreateTime;
+ float m_flMaxLifetime;
+
+ Vector m_vSurfaceNormal;
+
+ int m_BlobFlags; // Combination of BLOBFLAG_ defines.
+};
+
+
+#endif // C_GASOLINE_BLOB_H
diff --git a/game/client/tf2/c_grenade_antipersonnel.cpp b/game/client/tf2/c_grenade_antipersonnel.cpp
new file mode 100644
index 0000000..ee4d60e
--- /dev/null
+++ b/game/client/tf2/c_grenade_antipersonnel.cpp
@@ -0,0 +1,84 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+#include "cbase.h"
+#include "hud.h"
+#include "grenade_base_empable.h"
+#include "particles_simple.h"
+
+//-----------------------------------------------------------------------------
+// Purpose: Client side entity for the antipersonnel grenades
+//-----------------------------------------------------------------------------
+class C_GrenadeAntiPersonnel : public C_BaseEMPableGrenade
+{
+ DECLARE_CLASS( C_GrenadeAntiPersonnel, C_BaseEMPableGrenade );
+public:
+ DECLARE_CLIENTCLASS();
+
+ C_GrenadeAntiPersonnel();
+
+ virtual void OnDataChanged( DataUpdateType_t updateType );
+ virtual void ClientThink( void );
+
+public:
+ C_GrenadeAntiPersonnel( const C_GrenadeAntiPersonnel & );
+};
+
+IMPLEMENT_CLIENTCLASS_DT(C_GrenadeAntiPersonnel, DT_GrenadeAntiPersonnel, CGrenadeAntiPersonnel)
+END_RECV_TABLE()
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+C_GrenadeAntiPersonnel::C_GrenadeAntiPersonnel( void )
+{
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void C_GrenadeAntiPersonnel::OnDataChanged( DataUpdateType_t updateType )
+{
+ BaseClass::OnDataChanged( updateType );
+
+ // Only think when sapping
+ SetNextClientThink( CLIENT_THINK_ALWAYS );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Spawn effects if I'm sapping
+//-----------------------------------------------------------------------------
+void C_GrenadeAntiPersonnel::ClientThink( void )
+{
+ // Fire smoke puffs out the side
+ CSmartPtr<CSimpleEmitter> pSmokeEmitter = CSimpleEmitter::Create( "AntipersonnelGrenade::Effect" );
+ pSmokeEmitter->SetSortOrigin( GetAbsOrigin() );
+ int iSmokeClouds = random->RandomInt(1,2);
+ for ( int i = 0; i < iSmokeClouds; i++ )
+ {
+ SimpleParticle *pParticle = (SimpleParticle *) pSmokeEmitter->AddParticle( sizeof(SimpleParticle), g_Mat_DustPuff[1], GetAbsOrigin() );
+ if ( pParticle == NULL )
+ return;
+
+ pParticle->m_flLifetime = 0.0f;
+ pParticle->m_flDieTime = random->RandomFloat( 0.1f, 0.3f );
+
+ pParticle->m_uchStartSize = random->RandomFloat(2,5);
+ pParticle->m_uchEndSize = pParticle->m_uchStartSize + 2;
+
+ pParticle->m_vecVelocity = vec3_origin;
+ pParticle->m_uchStartAlpha = 255;
+ pParticle->m_uchEndAlpha = 64;
+ pParticle->m_flRoll = random->RandomFloat( 180, 360 );
+ pParticle->m_flRollDelta = random->RandomFloat( -1, 1 );
+
+ pParticle->m_uchColor[0] = 50;
+ pParticle->m_uchColor[1] = 250;
+ pParticle->m_uchColor[2] = 50;
+ }
+}
+
+
diff --git a/game/client/tf2/c_grenade_limpetmine.cpp b/game/client/tf2/c_grenade_limpetmine.cpp
new file mode 100644
index 0000000..2f9754e
--- /dev/null
+++ b/game/client/tf2/c_grenade_limpetmine.cpp
@@ -0,0 +1,109 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+#include "cbase.h"
+#include "basegrenade_shared.h"
+#include "minimap_trace.h"
+#include "particles_simple.h"
+
+//-----------------------------------------------------------------------------
+// Purpose: Client side entity for the ferry target items
+//-----------------------------------------------------------------------------
+class C_LimpetMine : public C_BaseGrenade
+{
+ DECLARE_CLASS( C_LimpetMine, C_BaseGrenade );
+public:
+ DECLARE_CLIENTCLASS();
+ DECLARE_MINIMAP_PANEL();
+
+ C_LimpetMine();
+
+ virtual void OnDataChanged( DataUpdateType_t updateType );
+ virtual void ClientThink( void );
+
+public:
+ C_LimpetMine( const C_LimpetMine & );
+
+private:
+ bool m_bLive;
+};
+
+IMPLEMENT_CLIENTCLASS_DT(C_LimpetMine, DT_LimpetMine, CLimpetMine)
+ RecvPropInt(RECVINFO(m_bLive)),
+END_RECV_TABLE()
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+C_LimpetMine::C_LimpetMine( void )
+{
+ CONSTRUCT_MINIMAP_PANEL( "minimap_limpet", MINIMAP_OBJECTS );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void C_LimpetMine::OnDataChanged( DataUpdateType_t updateType )
+{
+ BaseClass::OnDataChanged( updateType );
+
+ // Only think when live
+ if ( m_bLive )
+ {
+ SetNextClientThink( CLIENT_THINK_ALWAYS );
+ }
+ else
+ {
+ SetNextClientThink( CLIENT_THINK_NEVER );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Spawn effects if I'm live
+//-----------------------------------------------------------------------------
+void C_LimpetMine::ClientThink( void )
+{
+ if ( !InLocalTeam() )
+ return;
+
+ Vector up;
+ GetVectors( NULL, NULL, &up );
+ up *= 8.0f;
+ Vector vecOrg = GetAbsOrigin() + up;
+
+ // Make a single sprite
+ CSmartPtr<CSimpleEmitter> pSmokeEmitter = CSimpleEmitter::Create( "C_LimpetMine::Effect" );
+ pSmokeEmitter->SetSortOrigin( vecOrg );
+ PMaterialHandle hSphereMaterial = g_Mat_DustPuff[0];
+ SimpleParticle *pParticle = (SimpleParticle *) pSmokeEmitter->AddParticle( sizeof(SimpleParticle), hSphereMaterial, vecOrg );
+ if ( pParticle == NULL )
+ return;
+
+ pParticle->m_flLifetime = 0.0f;
+ pParticle->m_flDieTime = 0.1f;
+ pParticle->m_uchStartSize = RandomInt(4,6);
+ pParticle->m_uchEndSize = pParticle->m_uchStartSize;
+ pParticle->m_vecVelocity = vec3_origin;
+ pParticle->m_uchStartAlpha = 255;
+ pParticle->m_uchEndAlpha = 255;
+ pParticle->m_flRoll = random->RandomFloat( 180, 360 );
+ pParticle->m_flRollDelta = random->RandomFloat( -1, 1 );
+
+ if ( InLocalTeam() )
+ {
+ pParticle->m_uchColor[0] = 0;
+ pParticle->m_uchColor[1] = 255;
+ pParticle->m_uchColor[2] = 0;
+ }
+ else
+ {
+ pParticle->m_uchColor[0] = 255;
+ pParticle->m_uchColor[1] = 50;
+ pParticle->m_uchColor[2] = 50;
+ }
+}
+
+
diff --git a/game/client/tf2/c_grenade_objectsapper.cpp b/game/client/tf2/c_grenade_objectsapper.cpp
new file mode 100644
index 0000000..5b40dae
--- /dev/null
+++ b/game/client/tf2/c_grenade_objectsapper.cpp
@@ -0,0 +1,82 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+#include "cbase.h"
+#include "hud.h"
+#include "basegrenade_shared.h"
+#include "IEffects.h"
+#include "c_baseplayer.h"
+
+extern ConVar lod_effect_distance;
+
+//-----------------------------------------------------------------------------
+// Purpose: Client side entity for the ferry target items
+//-----------------------------------------------------------------------------
+class C_GrenadeObjectSapper : public C_BaseGrenade
+{
+ DECLARE_CLASS( C_GrenadeObjectSapper, C_BaseGrenade );
+public:
+ DECLARE_CLIENTCLASS();
+
+ C_GrenadeObjectSapper();
+
+ virtual void OnDataChanged( DataUpdateType_t updateType );
+ virtual void ClientThink( void );
+
+public:
+ C_GrenadeObjectSapper( const C_GrenadeObjectSapper & );
+
+ bool m_bSapping;
+ float m_flNextEffectTime;
+};
+
+IMPLEMENT_CLIENTCLASS_DT(C_GrenadeObjectSapper, DT_GrenadeObjectSapper, CGrenadeObjectSapper)
+ RecvPropInt(RECVINFO(m_bSapping)),
+END_RECV_TABLE()
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+C_GrenadeObjectSapper::C_GrenadeObjectSapper( void )
+{
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void C_GrenadeObjectSapper::OnDataChanged( DataUpdateType_t updateType )
+{
+ BaseClass::OnDataChanged( updateType );
+
+ // Only think when sapping
+ if ( m_bSapping )
+ {
+ SetNextClientThink( CLIENT_THINK_ALWAYS );
+ m_flNextEffectTime = gpGlobals->curtime;
+ }
+ else
+ {
+ SetNextClientThink( CLIENT_THINK_NEVER );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Spawn effects if I'm sapping
+//-----------------------------------------------------------------------------
+void C_GrenadeObjectSapper::ClientThink( void )
+{
+ if ( m_flNextEffectTime < gpGlobals->curtime )
+ {
+ // Haxory LOD
+ C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
+ if ( (GetAbsOrigin() - pPlayer->GetAbsOrigin()).LengthSqr() < lod_effect_distance.GetFloat() )
+ {
+ g_pEffects->Sparks( GetAbsOrigin() );
+ }
+
+ m_flNextEffectTime = gpGlobals->curtime + 0.3;
+ }
+}
diff --git a/game/client/tf2/c_grenade_rocket.cpp b/game/client/tf2/c_grenade_rocket.cpp
new file mode 100644
index 0000000..3db4497
--- /dev/null
+++ b/game/client/tf2/c_grenade_rocket.cpp
@@ -0,0 +1,83 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+#include "cbase.h"
+#include "hud.h"
+#include "particles_simple.h"
+
+//-----------------------------------------------------------------------------
+// Purpose: Client side entity for the antipersonnel grenades
+//-----------------------------------------------------------------------------
+class C_GrenadeRocket : public C_BaseAnimating
+{
+ DECLARE_CLASS( C_GrenadeRocket, C_BaseAnimating );
+public:
+ DECLARE_CLIENTCLASS();
+
+ C_GrenadeRocket();
+
+ virtual void OnDataChanged( DataUpdateType_t updateType );
+ virtual void ClientThink( void );
+
+public:
+ C_GrenadeRocket( const C_GrenadeRocket & );
+};
+
+IMPLEMENT_CLIENTCLASS_DT(C_GrenadeRocket, DT_GrenadeRocket, CGrenadeRocket)
+END_RECV_TABLE()
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+C_GrenadeRocket::C_GrenadeRocket( void )
+{
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void C_GrenadeRocket::OnDataChanged( DataUpdateType_t updateType )
+{
+ BaseClass::OnDataChanged( updateType );
+
+ // Only think when sapping
+ SetNextClientThink( CLIENT_THINK_ALWAYS );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Spawn effects if I'm sapping
+//-----------------------------------------------------------------------------
+void C_GrenadeRocket::ClientThink( void )
+{
+ // Fire smoke puffs out the side
+ CSmartPtr<CSimpleEmitter> pSmokeEmitter = CSimpleEmitter::Create( "C_GrenadeRocket::Effect" );
+ pSmokeEmitter->SetSortOrigin( GetAbsOrigin() );
+ int iSmokeClouds = random->RandomInt(1,2);
+ for ( int i = 0; i < iSmokeClouds; i++ )
+ {
+ SimpleParticle *pParticle = (SimpleParticle *) pSmokeEmitter->AddParticle( sizeof(SimpleParticle), g_Mat_DustPuff[1], GetAbsOrigin() );
+ if ( pParticle == NULL )
+ return;
+
+ pParticle->m_flLifetime = 0.0f;
+ pParticle->m_flDieTime = random->RandomFloat( 0.1f, 0.3f );
+
+ pParticle->m_uchStartSize = 10;
+ pParticle->m_uchEndSize = pParticle->m_uchStartSize + 2;
+
+ pParticle->m_vecVelocity = GetAbsVelocity();
+ pParticle->m_uchStartAlpha = 255;
+ pParticle->m_uchEndAlpha = 64;
+ pParticle->m_flRoll = random->RandomFloat( 180, 360 );
+ pParticle->m_flRollDelta = random->RandomFloat( -1, 1 );
+
+ pParticle->m_uchColor[0] = 50;
+ pParticle->m_uchColor[1] = 250;
+ pParticle->m_uchColor[2] = 50;
+ }
+}
+
+
diff --git a/game/client/tf2/c_harpoon.cpp b/game/client/tf2/c_harpoon.cpp
new file mode 100644
index 0000000..1ea93e6
--- /dev/null
+++ b/game/client/tf2/c_harpoon.cpp
@@ -0,0 +1,95 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+#include "cbase.h"
+#include "hud.h"
+#include "particles_simple.h"
+
+//-----------------------------------------------------------------------------
+// Purpose: Client side entity for the harpoon
+//-----------------------------------------------------------------------------
+class C_Harpoon : public C_BaseAnimating
+{
+ DECLARE_CLASS( C_Harpoon, C_BaseAnimating );
+public:
+ DECLARE_CLIENTCLASS();
+
+ C_Harpoon();
+
+ virtual void OnDataChanged( DataUpdateType_t updateType );
+ virtual void GetAimEntOrigin( IClientEntity *pAttachedTo, Vector *pOrigin, QAngle *pAngles );
+
+public:
+ C_Harpoon( const C_Harpoon & );
+
+private:
+ // Impaling
+ Vector m_vecOffset;
+ QAngle m_angOffset;
+};
+
+IMPLEMENT_CLIENTCLASS_DT(C_Harpoon, DT_Harpoon, CHarpoon)
+ RecvPropVector( RECVINFO(m_vecOffset) ),
+ RecvPropVector( RECVINFO(m_angOffset) ),
+END_RECV_TABLE()
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+C_Harpoon::C_Harpoon( void )
+{
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void C_Harpoon::OnDataChanged( DataUpdateType_t updateType )
+{
+ BaseClass::OnDataChanged( updateType );
+}
+
+
+//-----------------------------------------------------------------------------
+// Returns the attachment render origin + origin
+//-----------------------------------------------------------------------------
+void C_Harpoon::GetAimEntOrigin( IClientEntity *pAttachedTo, Vector *pOrigin, QAngle *pAngles )
+{
+ C_BaseAnimating *pEnt = dynamic_cast< C_BaseAnimating * >( pAttachedTo->GetBaseEntity() );
+ if (!pEnt)
+ return;
+
+ float controllers[MAXSTUDIOBONES];
+ pEnt->GetBoneControllers(controllers);
+
+ float headcontroller = controllers[ 0 ];
+
+ // Compute angles as well, since parent uses bone controller for rotation
+
+ // Convert 0 - 1 to angles
+ float renderYaw = -180.0f + 360.0f * headcontroller;
+
+ matrix3x4_t matrix;
+
+ // Convert roll/pitch only to matrix
+ AngleMatrix( pEnt->GetAbsAngles(), matrix );
+
+ // Convert desired yaw to vector
+ QAngle anglesRotated( 0, renderYaw, 0 );
+ Vector forward;
+ AngleVectors( anglesRotated, &forward );
+
+ Vector rotatedForward;
+
+ // Rotate desired yaw vector by roll/pitch matrix
+ VectorRotate( forward, matrix, rotatedForward );
+
+ // Convert rotated vector back to orientation
+ VectorAngles( rotatedForward, *pAngles );
+ //*pAngles -= m_angOffset;
+
+ // HACK: Until we have a proper bone solution, hack the origin for all moving objects
+ *pOrigin = pEnt->WorldSpaceCenter( );
+} \ No newline at end of file
diff --git a/game/client/tf2/c_hint_events.cpp b/game/client/tf2/c_hint_events.cpp
new file mode 100644
index 0000000..71b29e4
--- /dev/null
+++ b/game/client/tf2/c_hint_events.cpp
@@ -0,0 +1,49 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+#include "cbase.h"
+#include "c_hint_events.h"
+#include "c_tf_hints.h"
+#include "c_tf_hintmanager.h"
+#include <KeyValues.h>
+#include "c_baseobject.h"
+
+
+void GlobalHintEvent( C_HintEvent_Base *pEvent )
+{
+ // Call the static registered functions for each hint type.
+ for ( int i=0; i < GetNumHintDatas(); i++ )
+ {
+ CHintData *pData = GetHintData( i );
+ if ( pData && pData->m_pEventFn )
+ pData->m_pEventFn( pData, pEvent );
+ }
+}
+
+
+void HintEventFn_BuildObject( CHintData *pData, C_HintEvent_Base *pEvent )
+{
+ if ( pEvent->GetType() == HINTEVENT_OBJECT_BUILT_BY_LOCAL_PLAYER )
+ {
+ C_BaseObject *pObj = ((C_HintEvent_ObjectBuiltByLocalPlayer*)pEvent)->m_pObject;
+
+ if ( pObj->GetType() == pData->m_ObjectType )
+ {
+ // Ok, they just built the object that any hints of this type are referring to, so disable
+ // all further hints of this type.
+ KeyValues *pkvStats = GetHintDisplayStats();
+ if ( pkvStats )
+ {
+ KeyValues *pkvStatSection = pkvStats->FindKey( pData->name, true );
+ if ( pkvStatSection )
+ {
+ pkvStatSection->SetString( "times_shown", VarArgs( "%i", 100 ) );
+ }
+ }
+ }
+ }
+}
+
diff --git a/game/client/tf2/c_hint_events.h b/game/client/tf2/c_hint_events.h
new file mode 100644
index 0000000..89dc0db
--- /dev/null
+++ b/game/client/tf2/c_hint_events.h
@@ -0,0 +1,62 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef C_HINT_EVENTS_H
+#define C_HINT_EVENTS_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+
+class CHintData;
+
+
+typedef enum
+{
+ HINTEVENT_OBJECT_BUILT_BY_LOCAL_PLAYER=0 // C_HintEvent_ObjectBuiltByLocalPlayer
+} HintEventType;
+
+
+// All hint events derive from this.
+class C_HintEvent_Base
+{
+public:
+ // Find out what kind of event this is.
+ virtual HintEventType GetType() = 0;
+};
+
+
+// Fire a global hint event. It goes to all hint types so they can determine if
+// they want to react.
+void GlobalHintEvent( C_HintEvent_Base *pEvent );
+
+
+// Hint callbacks for each type of hint.
+void HintEventFn_BuildObject( CHintData *pData, C_HintEvent_Base *pEvent );
+
+
+
+// This notifies the hint system that an object has been built by the local player so
+// it can disable all further hints referring to objects of this type.
+class C_BaseObject;
+
+class C_HintEvent_ObjectBuiltByLocalPlayer : public C_HintEvent_Base
+{
+public:
+ C_HintEvent_ObjectBuiltByLocalPlayer( C_BaseObject *pObj )
+ {
+ m_pObject = pObj;
+ }
+
+ virtual HintEventType GetType() { return HINTEVENT_OBJECT_BUILT_BY_LOCAL_PLAYER; }
+
+public:
+ C_BaseObject *m_pObject; // The object just built.
+};
+
+
+#endif // C_HINT_EVENTS_H
diff --git a/game/client/tf2/c_info_act.cpp b/game/client/tf2/c_info_act.cpp
new file mode 100644
index 0000000..71941dc
--- /dev/null
+++ b/game/client/tf2/c_info_act.cpp
@@ -0,0 +1,196 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+#include "cbase.h"
+#include "tf_shareddefs.h"
+#include "c_info_act.h"
+#include "hud_timer.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+// We may get act begin messages for acts we haven't yet received entities for (usually during connection)
+// We store the current act in this, and if an act arrives matching it, we start that act.
+static int g_iCurrentActNumber = -1;
+static float g_flActStartTime;
+
+CHandle<C_InfoAct> g_hCurrentAct;
+
+IMPLEMENT_CLIENTCLASS_DT(C_InfoAct, DT_InfoAct, CInfoAct)
+ RecvPropInt( RECVINFO(m_iActNumber) ),
+ RecvPropInt( RECVINFO(m_spawnflags) ),
+ RecvPropFloat( RECVINFO(m_flActTimeLimit) ),
+ RecvPropInt(RECVINFO(m_nRespawn1Team1Time) ),
+ RecvPropInt(RECVINFO(m_nRespawn1Team2Time) ),
+ RecvPropInt(RECVINFO(m_nRespawn2Team1Time) ),
+ RecvPropInt(RECVINFO(m_nRespawn2Team2Time) ),
+ RecvPropInt(RECVINFO(m_nRespawnTeam1Delay) ),
+ RecvPropInt(RECVINFO(m_nRespawnTeam2Delay) ),
+END_RECV_TABLE()
+
+typedef CHandle<C_InfoAct> ActHandle_t;
+CUtlVector< ActHandle_t > g_hActs;
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+C_InfoAct::C_InfoAct()
+{
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+C_InfoAct::~C_InfoAct()
+{
+ ActHandle_t hAct;
+ hAct = this;
+ g_hActs.FindAndRemove( hAct );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void C_InfoAct::OnPreDataChanged( DataUpdateType_t updateType )
+{
+ BaseClass::OnPreDataChanged( updateType );
+ m_flPreviousTimeLimit = m_flActTimeLimit;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void C_InfoAct::OnDataChanged( DataUpdateType_t updateType )
+{
+ ActHandle_t hAct;
+ hAct = this;
+ if ( g_hActs.Find( hAct ) == g_hActs.InvalidIndex() )
+ {
+ g_hActs.AddToTail( hAct );
+
+ // Is this act the one that's supposed to be going?
+ if ( GetActNumber() == g_iCurrentActNumber )
+ {
+ StartAct( g_flActStartTime );
+ return;
+ }
+ }
+
+ // Timer changed?
+ if ( g_hCurrentAct == this )
+ {
+ if ( m_flPreviousTimeLimit != m_flActTimeLimit )
+ {
+ CHudTimer *timer = GET_HUDELEMENT( CHudTimer );
+ if ( timer )
+ {
+ timer->SetFixedTimer( m_flStartTime, m_flActTimeLimit );
+ }
+ }
+ }
+
+ BaseClass::OnDataChanged( updateType );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void C_InfoAct::StartAct( float flStartTime )
+{
+ g_hCurrentAct = this;
+ m_flStartTime = flStartTime;
+
+ CHudTimer *timer = GET_HUDELEMENT( CHudTimer );
+ if ( timer )
+ {
+ timer->SetFixedTimer( m_flStartTime, m_flActTimeLimit );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+bool C_InfoAct::IsAWaitingAct( void )
+{
+ return (m_spawnflags & SF_ACT_WAITINGFORGAMESTART) != 0;
+}
+
+
+//-----------------------------------------------------------------------------
+// PReturns the respawn time remaining
+//-----------------------------------------------------------------------------
+float C_InfoAct::RespawnTimeRemaining( int nTeam, int nTimer ) const
+{
+ if ((g_hCurrentAct != this) || (nTeam == 0))
+ return 0;
+
+ int nTimerTime;
+ float flTimeDelta = gpGlobals->curtime - m_flStartTime;
+ if (flTimeDelta <= 0)
+ return 0;
+
+ if (nTeam == 1)
+ {
+ nTimerTime = (nTimer == 1) ? m_nRespawn1Team1Time : m_nRespawn2Team1Time;
+ flTimeDelta -= m_nRespawnTeam1Delay;
+ }
+ else
+ {
+ nTimerTime = (nTimer == 1) ? m_nRespawn1Team2Time : m_nRespawn2Team2Time;
+ flTimeDelta -= m_nRespawnTeam2Delay;
+ }
+
+ if (nTimerTime <= 0)
+ return 0.0f;
+
+ // This case takes care of the initial spawn delay time...
+ if (flTimeDelta < 0)
+ {
+ return nTimerTime - flTimeDelta;
+ }
+
+ int nFactor = flTimeDelta / nTimerTime;
+ return nTimerTime - (flTimeDelta - nFactor * nTimerTime);
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Server's told us to start an act
+//-----------------------------------------------------------------------------
+void StartAct( int iActNumber, float flStartTime )
+{
+ g_iCurrentActNumber = iActNumber;
+ g_flActStartTime = flStartTime;
+
+ // Find the act
+ for ( int i = 0; i < g_hActs.Size(); i++ )
+ {
+ if ( g_hActs[i] && g_hActs[i]->GetActNumber() == iActNumber )
+ {
+ g_hActs[i]->StartAct( flStartTime );
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+int GetCurrentActNumber( void )
+{
+ if ( g_hCurrentAct )
+ return g_hCurrentAct->GetActNumber();
+ return ACT_NONE_SPECIFIED;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Return true if the current act (if any) is a waiting act.
+//-----------------------------------------------------------------------------
+bool CurrentActIsAWaitingAct( void )
+{
+ if ( g_hCurrentAct )
+ return g_hCurrentAct->IsAWaitingAct();
+
+ return false;
+} \ No newline at end of file
diff --git a/game/client/tf2/c_info_act.h b/game/client/tf2/c_info_act.h
new file mode 100644
index 0000000..ad97248
--- /dev/null
+++ b/game/client/tf2/c_info_act.h
@@ -0,0 +1,56 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#ifndef C_INFO_ACT_H
+#define C_INFO_ACT_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#define ACT_NONE_SPECIFIED -1
+
+//-----------------------------------------------------------------------------
+// Purpose: Map entity that defines an act
+//-----------------------------------------------------------------------------
+class C_InfoAct : public C_BaseEntity
+{
+ DECLARE_CLASS( C_InfoAct, C_BaseEntity );
+public:
+ C_InfoAct();
+ ~C_InfoAct();
+
+ DECLARE_CLIENTCLASS();
+
+ virtual void OnPreDataChanged( DataUpdateType_t updateType );
+ virtual void OnDataChanged( DataUpdateType_t updateType );
+
+ void StartAct( float flStartTime );
+
+ int GetActNumber( void ) { return m_iActNumber; }
+ bool IsAWaitingAct( void );
+
+ float RespawnTimeRemaining( int nTeam, int nTimer ) const;
+
+private:
+ int m_iActNumber;
+ int m_spawnflags;
+ float m_flActTimeLimit;
+ int m_nRespawn1Team1Time;
+ int m_nRespawn1Team2Time;
+ int m_nRespawn2Team1Time;
+ int m_nRespawn2Team2Time;
+ int m_nRespawnTeam1Delay;
+ int m_nRespawnTeam2Delay;
+ float m_flStartTime;
+ float m_flPreviousTimeLimit;
+};
+
+extern CHandle<C_InfoAct> g_hCurrentAct;
+void StartAct( int iActNumber, float flStartTime );
+int GetCurrentActNumber( void );
+bool CurrentActIsAWaitingAct( void );
+
+#endif // C_INFO_ACT_H
diff --git a/game/client/tf2/c_info_customtech.cpp b/game/client/tf2/c_info_customtech.cpp
new file mode 100644
index 0000000..d5ae027
--- /dev/null
+++ b/game/client/tf2/c_info_customtech.cpp
@@ -0,0 +1,51 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+#include "cbase.h"
+#include "hud_technologytreedoc.h"
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+class C_InfoCustomTechnology : public C_BaseEntity
+{
+ DECLARE_CLASS( C_InfoCustomTechnology, C_BaseEntity );
+public:
+ DECLARE_CLIENTCLASS();
+
+ C_InfoCustomTechnology( void );
+ virtual void SetDormant( bool bDormant );
+
+public:
+ // Sent via datatable
+ char m_szTechTreeFile[128];
+};
+
+IMPLEMENT_CLIENTCLASS_DT(C_InfoCustomTechnology, DT_InfoCustomTechnology, CInfoCustomTechnology)
+ RecvPropString(RECVINFO(m_szTechTreeFile)),
+END_RECV_TABLE()
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+C_InfoCustomTechnology::C_InfoCustomTechnology( void )
+{
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Whenever we enter the PVS, add ourselves to the tech tree. This will
+// only happen when the player joins a new team.
+//-----------------------------------------------------------------------------
+void C_InfoCustomTechnology::SetDormant( bool bDormant )
+{
+ if ( IsDormant() && !bDormant )
+ {
+ // Tell the techtree to add the file to it's list of technologies
+ GetTechnologyTreeDoc().AddTechnologyFile( m_szTechTreeFile );
+ }
+
+ BaseClass::SetDormant( bDormant );
+} \ No newline at end of file
diff --git a/game/client/tf2/c_maker_bughole.cpp b/game/client/tf2/c_maker_bughole.cpp
new file mode 100644
index 0000000..a789e05
--- /dev/null
+++ b/game/client/tf2/c_maker_bughole.cpp
@@ -0,0 +1,109 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+#include "cbase.h"
+#include "hud.h"
+#include "c_ai_basenpc.h"
+#include "IEffects.h"
+#include "particles_simple.h"
+
+//-----------------------------------------------------------------------------
+// Purpose: Client side entity for the NPC Bug hole
+//-----------------------------------------------------------------------------
+class C_Maker_Bughole : public C_BaseEntity
+{
+ DECLARE_CLASS( C_Maker_Bughole, C_BaseEntity );
+public:
+ DECLARE_CLIENTCLASS();
+
+ C_Maker_Bughole();
+
+ virtual void OnDataChanged( DataUpdateType_t updateType );
+ virtual void ClientThink( void );
+ void SpawnEffect( void );
+
+public:
+ C_Maker_Bughole( const C_Maker_Bughole & );
+
+ float m_flNextEffectTime;
+};
+
+IMPLEMENT_CLIENTCLASS_DT(C_Maker_Bughole, DT_Maker_Bughole, CMaker_Bughole)
+END_RECV_TABLE()
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+C_Maker_Bughole::C_Maker_Bughole( void )
+{
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void C_Maker_Bughole::OnDataChanged( DataUpdateType_t updateType )
+{
+ BaseClass::OnDataChanged( updateType );
+
+ if ( updateType == DATA_UPDATE_CREATED )
+ {
+ SetNextClientThink( CLIENT_THINK_ALWAYS );
+ m_flNextEffectTime = gpGlobals->curtime;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Spawn effects if I'm sapping
+//-----------------------------------------------------------------------------
+void C_Maker_Bughole::ClientThink( void )
+{
+ if ( m_flNextEffectTime < gpGlobals->curtime )
+ {
+ SpawnEffect();
+ m_flNextEffectTime = gpGlobals->curtime + random->RandomFloat( 0.5, 1.0 );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Particle effects created when we spawn a chunk
+//-----------------------------------------------------------------------------
+void C_Maker_Bughole::SpawnEffect( void )
+{
+ Vector normal = Vector(0,0,-1);
+ Vector offset = GetAbsOrigin() + (normal * 16);
+ Vector dir;
+
+ // Create a couple of big, floating smoke clouds
+ CSmartPtr<CSimpleEmitter> pSmokeEmitter = CSimpleEmitter::Create( "C_Maker_Bughole::SpawnEffect" );
+ pSmokeEmitter->SetSortOrigin( offset );
+ int iSmokeClouds = random->RandomInt(2,5);
+ for ( int i = 0; i < iSmokeClouds; i++ )
+ {
+ SimpleParticle *pParticle = (SimpleParticle *) pSmokeEmitter->AddParticle( sizeof(SimpleParticle), g_Mat_DustPuff[1], offset );
+ if ( pParticle == NULL )
+ return;
+
+ pParticle->m_flLifetime = 0.0f;
+ pParticle->m_flDieTime = random->RandomFloat( 2.0f, 3.0f );
+
+ pParticle->m_uchStartSize = 8;
+ pParticle->m_uchEndSize = 48;
+
+ dir[0] = normal[0] + random->RandomFloat( -0.4f, 0.4f );
+ dir[1] = normal[1] + random->RandomFloat( -0.4f, 0.4f );
+ dir[2] = normal[2] + random->RandomFloat( 0, 0.6f );
+ pParticle->m_vecVelocity = dir * random->RandomFloat( 8.0f, 20.0f )*(i+1);
+ pParticle->m_uchStartAlpha = 255;
+ pParticle->m_uchEndAlpha = 0;
+ pParticle->m_flRoll = random->RandomFloat( 180, 360 );
+ pParticle->m_flRollDelta = random->RandomFloat( -1, 1 );
+
+ float flColor = random->RandomFloat( 0,64 );
+ pParticle->m_uchColor[0] = 100 + flColor;
+ pParticle->m_uchColor[1] = 50 + flColor;
+ pParticle->m_uchColor[2] = flColor;
+ }
+}
diff --git a/game/client/tf2/c_obj_barbed_wire.cpp b/game/client/tf2/c_obj_barbed_wire.cpp
new file mode 100644
index 0000000..fdf74bd
--- /dev/null
+++ b/game/client/tf2/c_obj_barbed_wire.cpp
@@ -0,0 +1,110 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#include "cbase.h"
+#include "c_obj_barbed_wire.h"
+
+
+IMPLEMENT_CLIENTCLASS_DT( C_ObjectBarbedWire, DT_ObjectBarbedWire, CObjectBarbedWire )
+ RecvPropEHandle( RECVINFO( m_hConnectedTo ) )
+END_RECV_TABLE()
+
+
+ConVar obj_barbed_wire_hang_dist( "obj_barbed_wire_hang_dist", "20" );
+
+
+C_ObjectBarbedWire::C_ObjectBarbedWire()
+{
+ m_vLastConnectedOrigin.Init( -999999999, -999999999, -999999999 );
+ m_vLastOrigin = m_vLastConnectedOrigin;
+}
+
+
+C_ObjectBarbedWire::~C_ObjectBarbedWire()
+{
+ // Get rid of our rope if necessary.
+ if ( m_hRope )
+ {
+ m_hRope->Release();
+ }
+}
+
+
+void C_ObjectBarbedWire::OnDataChanged( DataUpdateType_t type )
+{
+ if ( m_hConnectedTo != m_hLastConnectedTo )
+ {
+ m_hLastConnectedTo = m_hConnectedTo;
+
+ // Get rid of any old rope we had.
+ int iAttachment = LookupAttachment( "wire_attachment" );
+
+ // Create or delete our rope?
+ if ( m_hConnectedTo )
+ {
+ if ( !m_hRope )
+ {
+
+ m_hRope = C_RopeKeyframe::Create(
+ this,
+ m_hConnectedTo,
+ iAttachment,
+ iAttachment,
+ 3,
+ "sprites/physbeam"
+ );
+ }
+ }
+ else
+ {
+ if ( m_hRope )
+ {
+ m_hRope->Release();
+ m_hRope = NULL;
+ }
+ }
+
+ // Update rope parameters.
+ if ( m_hRope )
+ {
+ int r, g, b, a;
+ CMapTeamColors *team = &MapData().m_TeamColors[ GetTeamNumber() ];
+ team->m_clrTeam.GetColor( r, g, b, a );
+ m_hRope->SetColorMod( Vector( r / 255.0f, g / 255.0f, b / 255.0f ) );
+
+ m_hRope->SetEndEntity( m_hConnectedTo );
+ m_hRope->SetRopeFlags( ROPE_SIMULATE | ROPE_BARBED );
+ }
+ }
+
+ BaseClass::OnDataChanged( type );
+}
+
+
+void C_ObjectBarbedWire::Spawn()
+{
+}
+
+
+void C_ObjectBarbedWire::ClientThink()
+{
+ if ( m_hConnectedTo && m_hRope )
+ {
+ if ( m_vLastOrigin != GetAbsOrigin() || m_vLastConnectedOrigin != m_hConnectedTo->GetAbsOrigin() )
+ {
+ m_hRope->SetupHangDistance( obj_barbed_wire_hang_dist.GetFloat() );
+
+ m_vLastOrigin = GetAbsOrigin();
+ m_vLastConnectedOrigin = m_hConnectedTo->GetAbsOrigin();
+ }
+ }
+
+ SetNextClientThink( gpGlobals->curtime + 0.1f );
+}
+
+
+
+
diff --git a/game/client/tf2/c_obj_barbed_wire.h b/game/client/tf2/c_obj_barbed_wire.h
new file mode 100644
index 0000000..b242640
--- /dev/null
+++ b/game/client/tf2/c_obj_barbed_wire.h
@@ -0,0 +1,46 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#ifndef C_OBJ_BARBED_WIRE_H
+#define C_OBJ_BARBED_WIRE_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+
+#include "c_baseobject.h"
+#include "c_rope.h"
+
+
+class C_ObjectBarbedWire : public C_BaseObject
+{
+public:
+ DECLARE_CLASS( C_ObjectBarbedWire, C_BaseObject );
+ DECLARE_CLIENTCLASS();
+
+ C_ObjectBarbedWire();
+ ~C_ObjectBarbedWire();
+
+ virtual void OnDataChanged( DataUpdateType_t type );
+
+ virtual void Spawn();
+ virtual void ClientThink();
+
+
+private:
+ C_ObjectBarbedWire( C_ObjectBarbedWire& ) {}
+
+ CHandle<C_ObjectBarbedWire> m_hConnectedTo;
+ CHandle<C_ObjectBarbedWire> m_hLastConnectedTo;
+ CHandle<C_RopeKeyframe> m_hRope;
+
+ // Used to determine when to recalculate the hang distance.
+ Vector m_vLastOrigin;
+ Vector m_vLastConnectedOrigin;
+};
+
+
+#endif // C_OBJ_BARBED_WIRE_H
diff --git a/game/client/tf2/c_obj_base_manned_gun.cpp b/game/client/tf2/c_obj_base_manned_gun.cpp
new file mode 100644
index 0000000..b7d7582
--- /dev/null
+++ b/game/client/tf2/c_obj_base_manned_gun.cpp
@@ -0,0 +1,122 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+#include "cbase.h"
+#include "c_obj_base_manned_gun.h"
+#include "hudelement.h"
+#include "tf_movedata.h"
+#include "bone_setup.h"
+#include "hud_ammo.h"
+#include "vgui_bitmapbutton.h"
+
+extern ConVar mannedgun_usethirdperson;
+
+//=================================================================================================
+// Control Screen
+//=================================================================================================
+
+DECLARE_VGUI_SCREEN_FACTORY( CMannedPlasmagunControlPanel, "manned_plasmagun_control_panel" );
+
+//-----------------------------------------------------------------------------
+// Constructor:
+//-----------------------------------------------------------------------------
+CMannedPlasmagunControlPanel::CMannedPlasmagunControlPanel( vgui::Panel *parent, const char *panelName )
+ : BaseClass( parent, "CMannedPlasmagunControlPanel" )
+{
+}
+
+
+//-----------------------------------------------------------------------------
+// Initialization
+//-----------------------------------------------------------------------------
+bool CMannedPlasmagunControlPanel::Init( KeyValues* pKeyValues, VGuiScreenInitData_t* pInitData )
+{
+ m_pMannedLabel = new vgui::Label( this, "MannedReadout", "" );
+ m_pOccupyButton = new CBitmapButton( this, "OccupyButton", "Occupy" );
+
+ if (!BaseClass::Init(pKeyValues, pInitData))
+ return false;
+
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+// Frame-based update
+//-----------------------------------------------------------------------------
+void CMannedPlasmagunControlPanel::OnTick()
+{
+ BaseClass::OnTick();
+
+ C_BaseObject *pObj = GetOwningObject();
+ if (!pObj)
+ return;
+
+ Assert( dynamic_cast<C_ObjectBaseMannedGun*>(pObj) );
+ C_ObjectBaseMannedGun *pGun = static_cast<C_ObjectBaseMannedGun*>(pObj);
+
+ char buf[256];
+ // Update the currently manned player label
+ if ( pGun->GetDriverPlayer() )
+ {
+ Q_snprintf( buf, sizeof( buf ), "Manned by %s", pGun->GetDriverPlayer()->GetPlayerName() );
+ m_pMannedLabel->SetText( buf );
+ m_pMannedLabel->SetVisible( true );
+ }
+ else
+ {
+ m_pMannedLabel->SetVisible( false );
+ }
+
+ // Update the get in button
+ if ( pGun->GetDriverPlayer() )
+ {
+ // Owners can boot other players to get in
+ if ( pGun->GetOwner() == C_BaseTFPlayer::GetLocalPlayer() && C_BaseTFPlayer::GetLocalPlayer() != pGun->GetDriverPlayer() )
+ {
+ Q_snprintf( buf, sizeof( buf ), "Get In (Ejecting %s)", pGun->GetDriverPlayer()->GetPlayerName() );
+ m_pMannedLabel->SetText( buf );
+ m_pOccupyButton->SetEnabled( true );
+ }
+ else
+ {
+ // Disable the button
+ m_pOccupyButton->SetEnabled( false );
+ }
+ }
+ else
+ {
+ m_pOccupyButton->SetText( "Get In" );
+ m_pOccupyButton->SetEnabled( true );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Handle clicking on the Occupy button
+//-----------------------------------------------------------------------------
+void CMannedPlasmagunControlPanel::GetInGun( void )
+{
+ C_BaseObject *pObj = GetOwningObject();
+ if (pObj)
+ {
+ pObj->SendClientCommand( "toggle_use" );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Button click handlers
+//-----------------------------------------------------------------------------
+void CMannedPlasmagunControlPanel::OnCommand( const char *command )
+{
+ if (!Q_strnicmp(command, "Occupy", 7))
+ {
+ GetInGun();
+ return;
+ }
+
+ BaseClass::OnCommand(command);
+}
+
diff --git a/game/client/tf2/c_obj_base_manned_gun.h b/game/client/tf2/c_obj_base_manned_gun.h
new file mode 100644
index 0000000..94b2c74
--- /dev/null
+++ b/game/client/tf2/c_obj_base_manned_gun.h
@@ -0,0 +1,39 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#ifndef C_OBJ_BASE_MANNED_GUN_H
+#define C_OBJ_BASE_MANNED_GUN_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "basetfvehicle.h"
+#include "tf_obj_manned_plasmagun_shared.h"
+#include "ObjectControlPanel.h"
+#include "tf_obj_base_manned_gun.h"
+
+
+//-----------------------------------------------------------------------------
+// Control screen
+//-----------------------------------------------------------------------------
+class CMannedPlasmagunControlPanel : public CRotatingObjectControlPanel
+{
+ DECLARE_CLASS( CMannedPlasmagunControlPanel, CRotatingObjectControlPanel );
+
+public:
+ CMannedPlasmagunControlPanel( vgui::Panel *parent, const char *panelName );
+ virtual bool Init( KeyValues* pKeyValues, VGuiScreenInitData_t* pInitData );
+ virtual void OnTick();
+ virtual void OnCommand( const char *command );
+
+ void GetInGun( void );
+
+private:
+ vgui::Label *m_pMannedLabel;
+ vgui::Button *m_pOccupyButton;
+};
+
+#endif // C_OBJ_BASE_MANNED_GUN_H
diff --git a/game/client/tf2/c_obj_buff_station.cpp b/game/client/tf2/c_obj_buff_station.cpp
new file mode 100644
index 0000000..350862a
--- /dev/null
+++ b/game/client/tf2/c_obj_buff_station.cpp
@@ -0,0 +1,272 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: The client-side version of the portable power generator
+//
+// $NoKeywords: $
+//=============================================================================//
+#include "cbase.h"
+#include "c_baseobject.h"
+#include "tf_shareddefs.h"
+#include "C_BaseTFPlayer.h"
+#include "ObjectControlPanel.h"
+#include "vgui_bitmapbutton.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+//=============================================================================
+//
+// Portable Power Generator Class
+//
+class C_ObjectBuffStation : public C_BaseObject
+{
+ DECLARE_CLASS( C_ObjectBuffStation, C_BaseObject );
+
+public:
+
+ DECLARE_CLIENTCLASS();
+
+ C_ObjectBuffStation( void );
+
+ virtual void Release( void );
+ virtual void OnPreDataChanged( DataUpdateType_t updateType );
+ virtual void OnDataChanged( DataUpdateType_t updateType );
+
+ // Since we have material proxies to show building amount, don't offset origin
+ virtual bool OffsetObjectOrigin( Vector& origin )
+ {
+ return false;
+ }
+
+ int PlayerSocketsLeft() const { return ( BUFF_STATION_MAX_PLAYERS - m_nPlayerCount ); }
+ int ObjectSocketsLeft() const { return ( BUFF_STATION_MAX_OBJECTS - m_nObjectCount ); }
+
+ // Check if the local player is attached
+ bool IsLocalPlayerAttached( void );
+
+private:
+ typedef CHandle<C_BaseTFPlayer> CPlayerHandle;
+ int m_nPlayerCount;
+ CPlayerHandle m_hPlayers[BUFF_STATION_MAX_PLAYERS];
+ CPlayerHandle m_hOldPlayers[BUFF_STATION_MAX_PLAYERS];
+
+ typedef CHandle<C_BaseObject> CObjectHandle;
+ int m_nObjectCount;
+ CObjectHandle m_hObjects[BUFF_STATION_MAX_OBJECTS];
+
+private:
+ C_ObjectBuffStation( const C_ObjectBuffStation & ); // not defined, not accessible
+};
+
+
+IMPLEMENT_CLIENTCLASS_DT( C_ObjectBuffStation, DT_ObjectBuffStation, CObjectBuffStation )
+ RecvPropInt( RECVINFO( m_nPlayerCount ) ),
+ RecvPropArray( RecvPropEHandle( RECVINFO( m_hPlayers[0]) ), m_hPlayers ),
+ RecvPropInt( RECVINFO( m_nObjectCount ) ),
+ RecvPropArray( RecvPropEHandle( RECVINFO( m_hObjects[0]) ), m_hObjects ),
+END_RECV_TABLE()
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+C_ObjectBuffStation::C_ObjectBuffStation( void )
+{
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Check if the local player is attached
+//-----------------------------------------------------------------------------
+bool C_ObjectBuffStation::IsLocalPlayerAttached( void )
+{
+ C_BaseTFPlayer *pLocalPlayer = C_BaseTFPlayer::GetLocalPlayer();
+ for ( int iPlayer = 0; iPlayer < m_nPlayerCount; ++iPlayer )
+ {
+ if ( m_hPlayers[iPlayer].Get() == pLocalPlayer )
+ return true;
+ }
+
+ return false;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void C_ObjectBuffStation::Release( void )
+{
+ // Remove any sounds for players attached
+ for ( int i = 0; i < BUFF_STATION_MAX_PLAYERS; i++ )
+ {
+ if ( m_hPlayers[i] )
+ {
+ // Stop the startup, in case it's still going
+ StopSound( m_hPlayers[i]->entindex(), "ObjectPortablePowerGenerator.Startup" );
+
+ // Start the shutdown sound
+ CPASAttenuationFilter filter( m_hPlayers[i], "ObjectPortablePowerGenerator.Shutdown" );
+ EmitSound( filter, m_hPlayers[i]->entindex(), "ObjectPortablePowerGenerator.Shutdown" );
+ }
+ }
+
+ BaseClass::Release();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void C_ObjectBuffStation::OnPreDataChanged( DataUpdateType_t updateType )
+{
+ BaseClass::OnPreDataChanged( updateType );
+
+ for ( int i = 0; i < BUFF_STATION_MAX_PLAYERS; i++ )
+ {
+ m_hOldPlayers[i] = m_hPlayers[i];
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void C_ObjectBuffStation::OnDataChanged( DataUpdateType_t updateType )
+{
+ BaseClass::OnDataChanged( updateType );
+
+ // Did a player connect / disconnect?
+ for ( int i = 0; i < BUFF_STATION_MAX_PLAYERS; i++ )
+ {
+ // Something's changed
+ if ( m_hOldPlayers[i] != m_hPlayers[i] )
+ {
+ // Disconnected?
+ if ( m_hOldPlayers[i] )
+ {
+ // Stop the startup, in case it's still going
+ StopSound( m_hOldPlayers[i]->entindex(), "ObjectPortablePowerGenerator.Startup" );
+
+ // Start the shutdown sound
+ CPASAttenuationFilter filter( m_hOldPlayers[i], "ObjectPortablePowerGenerator.Shutdown" );
+ EmitSound( filter, m_hOldPlayers[i]->entindex(), "ObjectPortablePowerGenerator.Shutdown" );
+ }
+
+ if ( m_hPlayers[i] )
+ {
+ // Start "buff" sound.
+ CPASAttenuationFilter filter( m_hPlayers[i], "ObjectPortablePowerGenerator.Startup" );
+ EmitSound( filter, m_hPlayers[i]->entindex(), "ObjectPortablePowerGenerator.Startup" );
+ }
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Control screen
+//-----------------------------------------------------------------------------
+class CBuffStationControlPanel : public CObjectControlPanel
+{
+ DECLARE_CLASS( CBuffStationControlPanel, CObjectControlPanel );
+
+public:
+
+ CBuffStationControlPanel( vgui::Panel *parent, const char *panelName );
+ virtual bool Init( KeyValues* pKeyValues, VGuiScreenInitData_t* pInitData );
+ virtual void OnTick();
+ virtual void OnCommand( const char *command );
+
+ void ConnectToStation( void );
+
+private:
+ vgui::Label *m_pSocketsLabel;
+ vgui::Button *m_pConnectButton;
+};
+
+
+DECLARE_VGUI_SCREEN_FACTORY( CBuffStationControlPanel, "buffstation_control_panel" );
+
+
+//-----------------------------------------------------------------------------
+// Constructor:
+//-----------------------------------------------------------------------------
+CBuffStationControlPanel::CBuffStationControlPanel( vgui::Panel *parent, const char *panelName )
+ : BaseClass( parent, "CBuffStationControlPanel" )
+{
+}
+
+
+//-----------------------------------------------------------------------------
+// Initialization
+//-----------------------------------------------------------------------------
+bool CBuffStationControlPanel::Init( KeyValues* pKeyValues, VGuiScreenInitData_t* pInitData )
+{
+ m_pSocketsLabel = new vgui::Label( this, "SocketReadout", "" );
+ m_pConnectButton = new CBitmapButton( this, "ConnectButton", "Connect" );
+
+ if (!BaseClass::Init(pKeyValues, pInitData))
+ return false;
+
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+// Frame-based update
+//-----------------------------------------------------------------------------
+void CBuffStationControlPanel::OnTick()
+{
+ BaseClass::OnTick();
+
+ C_BaseObject *pObj = GetOwningObject();
+ if (!pObj)
+ return;
+
+ Assert( dynamic_cast<C_ObjectBuffStation*>(pObj) );
+ C_ObjectBuffStation *pStation = static_cast<C_ObjectBuffStation*>(pObj);
+
+ char buf[256];
+ int nSocketsLeft = pStation->PlayerSocketsLeft();
+ if (nSocketsLeft > 0)
+ {
+ Q_snprintf( buf, sizeof( buf ), "%d sockets left", pStation->PlayerSocketsLeft() );
+ }
+ else
+ {
+ Q_strncpy( buf, "No sockets left", sizeof( buf ) );
+ }
+
+ m_pSocketsLabel->SetText( buf );
+
+ // Make sure the connect/disconnect button is correct
+ if ( pStation->IsLocalPlayerAttached() )
+ {
+ m_pConnectButton->SetText( "Disconnect from Station" );
+ }
+ else
+ {
+ m_pConnectButton->SetText( "Connect To Station" );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Handle clicking on the Connect/Disconnect button
+//-----------------------------------------------------------------------------
+void CBuffStationControlPanel::ConnectToStation( void )
+{
+ C_BaseObject *pObj = GetOwningObject();
+ if (pObj)
+ {
+ pObj->SendClientCommand( "toggle_connect" );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Button click handlers
+//-----------------------------------------------------------------------------
+void CBuffStationControlPanel::OnCommand( const char *command )
+{
+ if (!Q_strnicmp(command, "Connect", 7))
+ {
+ ConnectToStation();
+ return;
+ }
+
+ BaseClass::OnCommand(command);
+}
+
diff --git a/game/client/tf2/c_obj_bunker.cpp b/game/client/tf2/c_obj_bunker.cpp
new file mode 100644
index 0000000..bc590a1
--- /dev/null
+++ b/game/client/tf2/c_obj_bunker.cpp
@@ -0,0 +1,70 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#include "cbase.h"
+#include "hud.h"
+#include "commanderoverlay.h"
+#include "c_baseobject.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+class C_ObjectBunker : public C_BaseObject
+{
+ DECLARE_CLASS( C_ObjectBunker, C_BaseObject );
+public:
+ DECLARE_CLIENTCLASS();
+
+ C_ObjectBunker();
+
+private:
+ C_ObjectBunker( const C_ObjectBunker & ); // not defined, not accessible
+};
+
+IMPLEMENT_CLIENTCLASS_DT(C_ObjectBunker, DT_ObjectBunker, CObjectBunker)
+END_RECV_TABLE()
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+C_ObjectBunker::C_ObjectBunker()
+{
+}
+
+
+//=============================================================================
+// Bunker Ladder
+//=============================================================================
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+class C_ObjectBunkerLadder : public C_BaseAnimating
+{
+ DECLARE_CLASS( C_ObjectBunkerLadder, C_BaseAnimating );
+public:
+
+ DECLARE_CLIENTCLASS();
+
+ C_ObjectBunkerLadder();
+
+private:
+ C_ObjectBunkerLadder( const C_ObjectBunkerLadder& ); // not defined, not accessible
+};
+
+IMPLEMENT_CLIENTCLASS_DT( C_ObjectBunkerLadder, DT_ObjectBunkerLadder, CObjectBunkerLadder )
+END_RECV_TABLE()
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+C_ObjectBunkerLadder::C_ObjectBunkerLadder()
+{
+}
+
diff --git a/game/client/tf2/c_obj_dragonsteeth.cpp b/game/client/tf2/c_obj_dragonsteeth.cpp
new file mode 100644
index 0000000..3f690bf
--- /dev/null
+++ b/game/client/tf2/c_obj_dragonsteeth.cpp
@@ -0,0 +1,44 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#include "cbase.h"
+#include "hud.h"
+#include "commanderoverlay.h"
+#include "c_baseobject.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+class C_ObjectDragonsTeeth : public C_BaseObject
+{
+ DECLARE_CLASS( C_ObjectDragonsTeeth, C_BaseObject );
+public:
+ DECLARE_CLIENTCLASS();
+
+ C_ObjectDragonsTeeth();
+
+ // Since we have material proxies to show building amount, don't offset origin
+ virtual bool OffsetObjectOrigin( Vector& origin )
+ {
+ return false;
+ }
+
+private:
+ C_ObjectDragonsTeeth( const C_ObjectDragonsTeeth & ); // not defined, not accessible
+};
+
+IMPLEMENT_CLIENTCLASS_DT(C_ObjectDragonsTeeth, DT_ObjectDragonsTeeth, CObjectDragonsTeeth)
+END_RECV_TABLE()
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+C_ObjectDragonsTeeth::C_ObjectDragonsTeeth()
+{
+}
diff --git a/game/client/tf2/c_obj_empgenerator.cpp b/game/client/tf2/c_obj_empgenerator.cpp
new file mode 100644
index 0000000..2782bc4
--- /dev/null
+++ b/game/client/tf2/c_obj_empgenerator.cpp
@@ -0,0 +1,99 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+#include "cbase.h"
+#include "hud.h"
+#include "c_baseobject.h"
+#include "particles_simple.h"
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+class C_ObjectEMPGenerator : public C_BaseObject
+{
+ DECLARE_CLASS( C_ObjectEMPGenerator, C_BaseObject );
+public:
+ DECLARE_CLIENTCLASS();
+
+ C_ObjectEMPGenerator();
+
+ virtual void OnDataChanged( DataUpdateType_t updateType );
+ virtual void ClientThink( void );
+
+private:
+ CSmartPtr<CSimpleEmitter> m_pEmitter;
+ PMaterialHandle m_hParticleMaterial;
+ TimedEvent m_ParticleEvent;
+
+private:
+ C_ObjectEMPGenerator( const C_ObjectEMPGenerator & ); // not defined, not accessible
+};
+
+IMPLEMENT_CLIENTCLASS_DT(C_ObjectEMPGenerator, DT_ObjectEMPGenerator, CObjectEMPGenerator)
+END_RECV_TABLE()
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+C_ObjectEMPGenerator::C_ObjectEMPGenerator()
+{
+ m_ParticleEvent.Init( 300 );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void C_ObjectEMPGenerator::OnDataChanged( DataUpdateType_t updateType )
+{
+ BaseClass::OnDataChanged( updateType );
+
+ if ( updateType == DATA_UPDATE_CREATED )
+ {
+ m_pEmitter = CSimpleEmitter::Create( "C_ObjectEMPGenerator" );
+ m_hParticleMaterial = m_pEmitter->GetPMaterial( "sprites/chargeball" );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void C_ObjectEMPGenerator::ClientThink( void )
+{
+ // Add particles at the target.
+ float flCur = gpGlobals->frametime;
+ while ( m_ParticleEvent.NextEvent( flCur ) )
+ {
+ Vector vPos = WorldSpaceCenter( );
+ Vector vOffset = RandomVector( -1, 1 );
+ VectorNormalize( vOffset );
+ vPos += vOffset * RandomFloat( 0, 50 );
+
+ SimpleParticle *pParticle = m_pEmitter->AddSimpleParticle( m_hParticleMaterial, vPos );
+ if ( pParticle )
+ {
+ // Move the points along the path.
+ pParticle->m_vecVelocity.Init();
+ pParticle->m_flRoll = 0;
+ pParticle->m_flRollDelta = 0;
+ pParticle->m_flDieTime = 0.4f;
+ pParticle->m_flLifetime = 0;
+ pParticle->m_uchColor[0] = 255;
+ pParticle->m_uchColor[1] = 255;
+ pParticle->m_uchColor[2] = 255;
+ pParticle->m_uchStartAlpha = 32;
+ pParticle->m_uchEndAlpha = 0;
+ pParticle->m_uchStartSize = 6;
+ pParticle->m_uchEndSize = 4;
+ pParticle->m_iFlags = 0;
+ }
+ }
+}
+
+
+
+
+
diff --git a/game/client/tf2/c_obj_explosives.cpp b/game/client/tf2/c_obj_explosives.cpp
new file mode 100644
index 0000000..ed32caf
--- /dev/null
+++ b/game/client/tf2/c_obj_explosives.cpp
@@ -0,0 +1,36 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#include "cbase.h"
+#include "hud.h"
+#include "commanderoverlay.h"
+#include "tf_obj_baseupgrade_shared.h"
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+class C_ObjectExplosives : public C_BaseObjectUpgrade
+{
+ DECLARE_CLASS( C_ObjectExplosives, C_BaseObjectUpgrade );
+public:
+ DECLARE_CLIENTCLASS();
+
+ C_ObjectExplosives();
+
+private:
+ C_ObjectExplosives( const C_ObjectExplosives & ); // not defined, not accessible
+};
+
+IMPLEMENT_CLIENTCLASS_DT(C_ObjectExplosives, DT_ObjectExplosives, CObjectExplosives)
+END_RECV_TABLE()
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+C_ObjectExplosives::C_ObjectExplosives()
+{
+}
+
diff --git a/game/client/tf2/c_obj_manned_missilelauncher.cpp b/game/client/tf2/c_obj_manned_missilelauncher.cpp
new file mode 100644
index 0000000..d1f67ad
--- /dev/null
+++ b/game/client/tf2/c_obj_manned_missilelauncher.cpp
@@ -0,0 +1,28 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#include "cbase.h"
+#include "c_obj_base_manned_gun.h"
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+class C_ObjectMannedMissileLauncher : public C_ObjectBaseMannedGun
+{
+ DECLARE_CLASS( C_ObjectMannedMissileLauncher, C_ObjectBaseMannedGun );
+public:
+ DECLARE_CLIENTCLASS();
+
+ C_ObjectMannedMissileLauncher() {}
+
+private:
+ C_ObjectMannedMissileLauncher( const C_ObjectMannedMissileLauncher & ); // not defined, not accessible
+};
+
+IMPLEMENT_CLIENTCLASS_DT(C_ObjectMannedMissileLauncher, DT_ObjectMannedMissileLauncher, CObjectMannedMissileLauncher)
+END_RECV_TABLE()
+
diff --git a/game/client/tf2/c_obj_manned_plasmagun.cpp b/game/client/tf2/c_obj_manned_plasmagun.cpp
new file mode 100644
index 0000000..0603671
--- /dev/null
+++ b/game/client/tf2/c_obj_manned_plasmagun.cpp
@@ -0,0 +1,27 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+#include "cbase.h"
+#include "c_obj_base_manned_gun.h"
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+class C_ObjectMannedPlasmagun : public C_ObjectBaseMannedGun
+{
+ DECLARE_CLASS( C_ObjectMannedPlasmagun, C_ObjectBaseMannedGun );
+public:
+ DECLARE_CLIENTCLASS();
+
+ C_ObjectMannedPlasmagun() {}
+
+private:
+ C_ObjectMannedPlasmagun( const C_ObjectMannedPlasmagun & ); // not defined, not accessible
+};
+
+IMPLEMENT_CLIENTCLASS_DT(C_ObjectMannedPlasmagun, DT_ObjectMannedPlasmagun, CObjectMannedPlasmagun)
+END_RECV_TABLE()
+
diff --git a/game/client/tf2/c_obj_manned_shield.cpp b/game/client/tf2/c_obj_manned_shield.cpp
new file mode 100644
index 0000000..61dd995
--- /dev/null
+++ b/game/client/tf2/c_obj_manned_shield.cpp
@@ -0,0 +1,27 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#include "cbase.h"
+#include "c_obj_base_manned_gun.h"
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+class C_ObjectMannedShield : public C_ObjectBaseMannedGun
+{
+ DECLARE_CLASS( C_ObjectMannedShield, C_ObjectBaseMannedGun );
+public:
+ DECLARE_CLIENTCLASS();
+
+ C_ObjectMannedShield() {}
+
+private:
+ C_ObjectMannedShield( const C_ObjectMannedShield & ); // not defined, not accessible
+};
+
+IMPLEMENT_CLIENTCLASS_DT( C_ObjectMannedShield, DT_ObjectMannedShield, CObjectMannedShield )
+END_RECV_TABLE()
diff --git a/game/client/tf2/c_obj_mapdefined.cpp b/game/client/tf2/c_obj_mapdefined.cpp
new file mode 100644
index 0000000..8cd5ce9
--- /dev/null
+++ b/game/client/tf2/c_obj_mapdefined.cpp
@@ -0,0 +1,37 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+#include "cbase.h"
+#include "hud.h"
+#include "tf_shareddefs.h"
+#include "c_obj_mapdefined.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+IMPLEMENT_CLIENTCLASS_DT(C_ObjectMapDefined, DT_ObjectMapDefined, CObjectMapDefined)
+ RecvPropString( RECVINFO(m_szCustomName) ),
+END_RECV_TABLE()
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+C_ObjectMapDefined::C_ObjectMapDefined()
+{
+ memset( m_szCustomName, 0, sizeof(m_szCustomName) );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Get a text description for the object target
+//-----------------------------------------------------------------------------
+const char *C_ObjectMapDefined::GetTargetDescription( void ) const
+{
+ if ( m_szCustomName && m_szCustomName[0] )
+ return m_szCustomName;
+
+ return BaseClass::GetTargetDescription();
+} \ No newline at end of file
diff --git a/game/client/tf2/c_obj_mapdefined.h b/game/client/tf2/c_obj_mapdefined.h
new file mode 100644
index 0000000..610f1d9
--- /dev/null
+++ b/game/client/tf2/c_obj_mapdefined.h
@@ -0,0 +1,35 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef C_OBJ_MAPDEFINED_H
+#define C_OBJ_MAPDEFINED_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "c_baseobject.h"
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+class C_ObjectMapDefined : public C_BaseObject
+{
+ DECLARE_CLASS( C_ObjectMapDefined, C_BaseObject );
+public:
+ DECLARE_CLIENTCLASS();
+
+ C_ObjectMapDefined();
+
+ virtual const char *GetTargetDescription( void ) const;
+
+private:
+ C_ObjectMapDefined( const C_ObjectMapDefined & ); // not defined, not accessible
+
+ char m_szCustomName[ MAX_OBJ_CUSTOMNAME_SIZE ];
+};
+
+#endif // C_OBJ_MAPDEFINED_H
diff --git a/game/client/tf2/c_obj_mcv_selection_panel.cpp b/game/client/tf2/c_obj_mcv_selection_panel.cpp
new file mode 100644
index 0000000..1e57f0b
--- /dev/null
+++ b/game/client/tf2/c_obj_mcv_selection_panel.cpp
@@ -0,0 +1,279 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#include "cbase.h"
+#include "c_baseobject.h"
+#include "ObjectControlPanel.h"
+#include "hud_minimap.h"
+#include "vgui_bitmapimage.h"
+#include "c_vehicle_teleport_station.h"
+#include <vgui/MouseCode.h>
+
+
+class C_ObjMCVSelectionPanel;
+CUtlLinkedList<C_ObjMCVSelectionPanel*,int> g_SelectionPanels;
+
+
+// ------------------------------------------------------------------------------------------------ //
+// C_ObjMCVSelectionPanel
+// ------------------------------------------------------------------------------------------------ //
+
+class C_ObjMCVSelectionPanel : public C_BaseObject
+{
+public:
+
+ DECLARE_CLASS( C_ObjMCVSelectionPanel, C_BaseObject );
+ DECLARE_CLIENTCLASS();
+
+ C_ObjMCVSelectionPanel();
+ ~C_ObjMCVSelectionPanel();
+
+ typedef CHandle<C_VehicleTeleportStation> VehicleTeleportStationHandle;
+ CUtlVector<VehicleTeleportStationHandle> m_DeployedTeleportStations;
+
+
+private:
+ static C_ObjMCVSelectionPanel *s_pSelectionPanel;
+
+ friend void RecvProxy_TeleportStationCount( void *pStruct, int objectID, int currentArrayLength );
+ friend void RecvProxy_TeleportStationElement( const CRecvProxyData *pData, void *pStruct, void *pOut );
+
+ C_ObjMCVSelectionPanel( const C_ObjMCVSelectionPanel & );
+};
+
+
+void RecvProxy_TeleportStationCount( void *pStruct, int objectID, int currentArrayLength )
+{
+ C_ObjMCVSelectionPanel *pPanel = (C_ObjMCVSelectionPanel*)pStruct;
+ if ( pPanel->m_DeployedTeleportStations.Count() != currentArrayLength )
+ {
+ pPanel->m_DeployedTeleportStations.SetSize( currentArrayLength );
+ }
+}
+
+
+void RecvProxy_TeleportStationElement( const CRecvProxyData *pData, void *pStruct, void *pOut )
+{
+ C_ObjMCVSelectionPanel *pPanel = (C_ObjMCVSelectionPanel*)pStruct;
+
+ Assert( pData->m_iElement < pPanel->m_DeployedTeleportStations.Count() );
+
+ RecvProxy_IntToEHandle( pData, pStruct, &pPanel->m_DeployedTeleportStations[pData->m_iElement] );
+}
+
+
+IMPLEMENT_CLIENTCLASS_DT( C_ObjMCVSelectionPanel, DT_MCVSelectionPanel, CObjMCVSelectionPanel )
+ RecvPropVirtualArray(
+ RecvProxy_TeleportStationCount,
+ 32,
+ RecvPropEHandle( "teleport_station_element", 0, 0, RecvProxy_TeleportStationElement ),
+ "teleport_stations" )
+END_RECV_TABLE()
+
+
+C_ObjMCVSelectionPanel::C_ObjMCVSelectionPanel()
+{
+ g_SelectionPanels.AddToTail( this );
+}
+
+C_ObjMCVSelectionPanel::~C_ObjMCVSelectionPanel()
+{
+ g_SelectionPanels.FindAndRemove( this );
+}
+
+
+
+//-----------------------------------------------------------------------------
+// CMCVMinimapPanel
+//-----------------------------------------------------------------------------
+
+class CMCVMinimapPanel : public CMinimapPanel
+{
+public:
+
+ DECLARE_CLASS( CMCVMinimapPanel, CMinimapPanel );
+
+ CMCVMinimapPanel( vgui::Panel *pParent, const char *pElementName );
+ virtual ~CMCVMinimapPanel();
+
+ virtual void Paint();
+ virtual void OnMousePressed( vgui::MouseCode code );
+ virtual void OnCursorMoved( int x, int y );
+
+
+private:
+ BitmapImage m_MCVImage;
+ BitmapImage m_SelectedMCVImage;
+ int m_LastX, m_LastY;
+};
+
+
+CMCVMinimapPanel::CMCVMinimapPanel( vgui::Panel *pParent, const char *pElementName )
+ : CMinimapPanel( pElementName )
+{
+ SetParent( pParent );
+ m_MCVImage.Init( GetVPanel(), "hud/minimap/icon_mcv_unselected" );
+ m_SelectedMCVImage.Init( GetVPanel(), "hud/minimap/icon_mcv_selected" );
+ m_LastX = m_LastY = 0;
+}
+
+
+CMCVMinimapPanel::~CMCVMinimapPanel()
+{
+}
+
+
+void CMCVMinimapPanel::Paint()
+{
+ // Draw the minimap.
+ BaseClass::Paint();
+
+ // Now draw the MCVs.
+ if ( g_SelectionPanels.Count() > 0 )
+ {
+ C_ObjMCVSelectionPanel *pPanel = g_SelectionPanels[ g_SelectionPanels.Head() ];
+ C_BaseEntity *pSelectedMCV = C_BaseTFPlayer::GetLocalPlayer()->GetSelectedMCV();
+
+ for ( int i=0; i < pPanel->m_DeployedTeleportStations.Count(); i++ )
+ {
+ C_VehicleTeleportStation *pStation = pPanel->m_DeployedTeleportStations[i];
+ if ( pStation )
+ {
+ float x, y;
+ if ( WorldToMinimap( MINIMAP_CLAMP, pStation->GetAbsOrigin(), x, y ) )
+ {
+ int size = 20;
+
+ if ( pStation == pSelectedMCV )
+ m_SelectedMCVImage.DoPaint( x-size/2, y-size/2, size, size );
+ else
+ m_MCVImage.DoPaint( x-size/2, y-size/2, size, size );
+ }
+ }
+ }
+ }
+}
+
+
+
+void CMCVMinimapPanel::OnMousePressed( vgui::MouseCode code )
+{
+ BaseClass::OnMousePressed( code );
+
+ if ( code != vgui::MOUSE_LEFT )
+ return;
+
+ // Now draw the MCVs.
+ if ( g_SelectionPanels.Count() > 0 )
+ {
+ C_ObjMCVSelectionPanel *pPanel = g_SelectionPanels[ g_SelectionPanels.Head() ];
+
+ // Find the closest MCV to their mouse press.
+ int iClosest = -1;
+ float flClosest = 1e24;
+ Vector2D curMousePos( m_LastX, m_LastY );
+
+ for ( int i=0; i < pPanel->m_DeployedTeleportStations.Count(); i++ )
+ {
+ C_VehicleTeleportStation *pStation = pPanel->m_DeployedTeleportStations[i];
+ if ( pStation )
+ {
+ Vector2D mcvPos;
+ if ( WorldToMinimap( MINIMAP_CLAMP, pStation->GetAbsOrigin(), mcvPos.x, mcvPos.y ) )
+ {
+ float flTestDist = mcvPos.DistTo( curMousePos );
+ if ( flTestDist < flClosest )
+ {
+ flClosest = flTestDist;
+ iClosest = i;
+ }
+ }
+ }
+ }
+
+ if ( iClosest != -1 && flClosest < 10 )
+ {
+ C_VehicleTeleportStation *pClosest = pPanel->m_DeployedTeleportStations[iClosest];
+
+ char str[512];
+ Q_snprintf( str, sizeof( str ), "SelectMCV %d", pClosest->entindex() );
+ pPanel->SendClientCommand( str );
+ }
+ }
+}
+
+
+void CMCVMinimapPanel::OnCursorMoved( int x, int y )
+{
+ BaseClass::OnCursorMoved( x, y );
+
+ m_LastX = x;
+ m_LastY = y;
+}
+
+
+
+// ------------------------------------------------------------------------------------------------ //
+// CMCVSelectionPanel
+// ------------------------------------------------------------------------------------------------ //
+
+class CMCVSelectionPanel : public CObjectControlPanel
+{
+ DECLARE_CLASS( CMCVSelectionPanel, CObjectControlPanel );
+
+
+public:
+
+ CMCVSelectionPanel( vgui::Panel *parent, const char *panelName );
+ virtual ~CMCVSelectionPanel();
+
+ virtual bool Init( KeyValues* pKeyValues, VGuiScreenInitData_t* pInitData );
+ virtual void OnCommand( const char *command );
+
+
+private:
+
+ CMCVMinimapPanel *m_pMinimapPanel;
+};
+
+
+DECLARE_VGUI_SCREEN_FACTORY( CMCVSelectionPanel, "mcv_selection_panel" );
+
+
+CMCVSelectionPanel::CMCVSelectionPanel( vgui::Panel *parent, const char *panelName )
+ : BaseClass( parent, "CMCVSelectionPanel" )
+{
+ m_pMinimapPanel = new CMCVMinimapPanel( this, "MinimapPanel" );
+ m_pMinimapPanel->SetZPos( 10 );
+ m_pMinimapPanel->Init( NULL );
+}
+
+
+CMCVSelectionPanel::~CMCVSelectionPanel()
+{
+ delete m_pMinimapPanel;
+}
+
+
+bool CMCVSelectionPanel::Init( KeyValues* pKeyValues, VGuiScreenInitData_t* pInitData )
+{
+ if ( !BaseClass::Init( pKeyValues, pInitData ) )
+ return false;
+
+ m_pMinimapPanel->LevelInit( engine->GetLevelName() );
+ m_pMinimapPanel->SetVisible( true );
+
+ return true;
+}
+
+
+void CMCVSelectionPanel::OnCommand( const char *command )
+{
+ BaseClass::OnCommand( command );
+}
+
+
+
diff --git a/game/client/tf2/c_obj_mortar.cpp b/game/client/tf2/c_obj_mortar.cpp
new file mode 100644
index 0000000..ea4e79b
--- /dev/null
+++ b/game/client/tf2/c_obj_mortar.cpp
@@ -0,0 +1,389 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Client version of CObjectMortar
+//
+// $NoKeywords: $
+//=============================================================================//
+#include "cbase.h"
+#include "hud.h"
+#include "CommanderOverlay.h"
+#include "c_baseobject.h"
+#include "tf_shareddefs.h"
+#include "c_basetfplayer.h"
+#include "ObjectControlPanel.h"
+#include <vgui_controls/Label.h>
+#include <vgui_controls/Button.h>
+#include "vgui_rotation_slider.h"
+#include <vgui/ISurface.h>
+#include "vgui_basepanel.h"
+#include "vgui_bitmapimage.h"
+#include "iusesmortarpanel.h"
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+class C_ObjectMortar : public C_BaseObject, public IUsesMortarPanel
+{
+ DECLARE_CLASS( C_ObjectMortar, C_BaseObject );
+public:
+ DECLARE_CLIENTCLASS();
+ DECLARE_ENTITY_PANEL();
+
+ C_ObjectMortar();
+
+ virtual void SetDormant( bool bDormant );
+ virtual void Select( void );
+ virtual void RecalculateIDString( void );
+
+ void FireMortar( void );
+
+// IUsesMortarPanel
+public:
+ // Get the data from this mortar needed by the panel
+ virtual void GetMortarData( float *flClientMortarYaw, bool *bAllowedToFire, float *flPower, float *flFiringPower, float *flFiringAccuracy, int *iFiringState );
+ virtual void SendYawCommand( void );
+ virtual void ForceClientYawCountdown( float flTime );
+ virtual void ClickFire( void );
+
+public:
+ int m_iRoundType;
+ int m_iMortarRounds[ MA_LASTAMMOTYPE ];
+
+ // Mortar firing info.
+ int m_iFiringState; // One of the MORTAR_ defines.
+ bool m_bMortarReloading;
+ float m_flPower;
+ bool m_bAllowedToFire;
+
+ // Parameters for the next shot.
+ float m_flFiringPower;
+ float m_flFiringAccuracy;
+
+ float m_flMortarYaw; // What direction the mortar is aimed in.
+ float m_flMortarPitch;
+
+ // This is what is used on the client to draw the ground line and orient the mortar.
+ // It is usually copied right over from m_flClientMortarYaw (which comes from the server),
+ // but this is also used when rotating the mortar so you can see the line move smoothly.
+ float m_flClientMortarYaw;
+
+ // This is set to about 1/4 seconds when you rotate the mortar line so you use the client's
+ // (smooth, non-lagged) yaw changes instead of the server's.
+ float m_flForceClientYawCountdown;
+
+private:
+ C_ObjectMortar( const C_ObjectMortar & ); // not defined, not accessible
+};
+
+IMPLEMENT_CLIENTCLASS_DT(C_ObjectMortar, DT_ObjectMortar, CObjectMortar)
+ RecvPropInt( RECVINFO(m_iRoundType) ),
+ RecvPropArray( RecvPropInt( RECVINFO(m_iMortarRounds[0]) ), m_iMortarRounds )
+END_RECV_TABLE()
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+C_ObjectMortar::C_ObjectMortar( void )
+{
+ memset( m_iMortarRounds, 0, sizeof( m_iMortarRounds ) );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void C_ObjectMortar::SetDormant( bool bDormant )
+{
+ BaseClass::SetDormant( bDormant );
+ ENTITY_PANEL_ACTIVATE( "mortar", !bDormant );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Cycle ammo types on the mortar
+//-----------------------------------------------------------------------------
+void C_ObjectMortar::Select( void )
+{
+ C_BaseTFPlayer *pPlayer = C_BaseTFPlayer::GetLocalPlayer();
+ if ( pPlayer == NULL )
+ return;
+
+ int iOldType = m_iRoundType++;
+
+ // Cycle to the next ammo type
+ while ( m_iRoundType != iOldType )
+ {
+ // Hit the end of the round types?
+ if ( m_iRoundType == MA_LASTAMMOTYPE )
+ {
+ m_iRoundType = MA_SHELL;
+ break;
+ }
+
+ // Does this round type need a technology?
+ if ( MortarAmmoTechs[ m_iRoundType ] && MortarAmmoTechs[ m_iRoundType ][0] )
+ {
+ // Does the player have the technology?
+ if ( pPlayer->HasNamedTechnology( MortarAmmoTechs[ m_iRoundType ] ) )
+ {
+ // Do we have ammo?
+ if ( m_iMortarRounds[ m_iRoundType ] > 0 )
+ break;
+ }
+ }
+
+ // Go to the next round type
+ m_iRoundType++;
+ }
+
+ engine->ClientCmd( VarArgs("mortarround %d", m_iRoundType) );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void C_ObjectMortar::RecalculateIDString( void )
+{
+ // Only owners get full data
+ if ( IsOwnedByLocalPlayer() )
+ {
+ if ( m_iRoundType >= 0 )
+ {
+ // -1 means we have infinite rounds of this type
+ if ( m_iMortarRounds[ m_iRoundType ] == -1 )
+ {
+ Q_snprintf( m_szIDString, sizeof(m_szIDString), "%s - %s", GetTargetDescription(), MortarAmmoNames[ m_iRoundType ] );
+ }
+ else
+ {
+ Q_snprintf( m_szIDString, sizeof(m_szIDString), "%s - %d %s", GetTargetDescription(), m_iMortarRounds[ m_iRoundType ], MortarAmmoNames[ m_iRoundType ] );
+ }
+ Q_strncat( m_szIDString, "\nUse it to change ammo types.", sizeof(m_szIDString), COPY_ALL_CHARACTERS );
+ }
+ }
+
+ BaseClass::RecalculateIDString();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void C_ObjectMortar::ClickFire( void )
+{
+ switch( m_iFiringState )
+ {
+ case MORTAR_IDLE:
+ m_iFiringState = MORTAR_CHARGING_POWER;
+ break;
+
+ case MORTAR_CHARGING_POWER:
+ m_flFiringPower = m_flPower;
+ m_iFiringState = MORTAR_CHARGING_ACCURACY;
+ break;
+
+ case MORTAR_CHARGING_ACCURACY:
+ m_flFiringAccuracy = m_flPower;
+ m_iFiringState = MORTAR_IDLE;
+
+ FireMortar();
+ break;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void C_ObjectMortar::GetMortarData( float *flClientMortarYaw, bool *bAllowedToFire, float *flPower, float *flFiringPower, float *flFiringAccuracy, int *iFiringState )
+{
+ *flClientMortarYaw = m_flClientMortarYaw;
+ *bAllowedToFire = m_bAllowedToFire;
+ *flPower = m_flPower;
+ *flFiringPower = m_flFiringPower;
+ *flFiringAccuracy = m_flFiringAccuracy;
+ *iFiringState = m_iFiringState;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void C_ObjectMortar::SendYawCommand( void )
+{
+ char szbuf[48];
+ Q_snprintf( szbuf, sizeof( szbuf ), "MortarYaw %0.2f\n", m_flClientMortarYaw );
+ SendClientCommand( szbuf );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void C_ObjectMortar::ForceClientYawCountdown( float flTime )
+{
+ m_flForceClientYawCountdown = flTime;
+}
+
+
+//-----------------------------------------------------------------------------
+// Control screen
+//-----------------------------------------------------------------------------
+class CMortarControlPanel : public CObjectControlPanel
+{
+ DECLARE_CLASS( CMortarControlPanel, CObjectControlPanel );
+public:
+ CMortarControlPanel( vgui::Panel *parent, const char *panelName );
+ virtual ~CMortarControlPanel();
+
+ virtual bool Init( KeyValues* pKeyValues, VGuiScreenInitData_t* pInitData );
+ virtual void OnCommand( const char *command );
+ C_ObjectMortar* GetMortar() const;
+
+protected:
+ virtual vgui::Panel* TickCurrentPanel();
+
+private:
+ CMortarMinimapPanel *m_pMinimapPanel;
+};
+
+
+DECLARE_VGUI_SCREEN_FACTORY( CMortarControlPanel, "mortar_control_panel" );
+
+
+//-----------------------------------------------------------------------------
+// Constructor:
+//-----------------------------------------------------------------------------
+CMortarControlPanel::CMortarControlPanel( vgui::Panel *parent, const char *panelName )
+ : BaseClass( parent, "CMortarControlPanel" )
+{
+ m_pMinimapPanel = new CMortarMinimapPanel( this, "MinimapPanel" );
+ m_pMinimapPanel->Init( NULL );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+CMortarControlPanel::~CMortarControlPanel()
+{
+ delete m_pMinimapPanel;
+}
+
+//-----------------------------------------------------------------------------
+// Initialization
+//-----------------------------------------------------------------------------
+bool CMortarControlPanel::Init( KeyValues* pKeyValues, VGuiScreenInitData_t* pInitData )
+{
+ // Make sure all named panels are created up above because BaseClass::Init initializes them
+ // all from their keyvalues.
+ if ( !BaseClass::Init( pKeyValues, pInitData ) )
+ return false;
+
+ // Init subpanels.
+ int x, y, w, h;
+ GetBounds( x, y, w, h );
+
+ m_pMinimapPanel->LevelInit( engine->GetLevelName() );
+ m_pMinimapPanel->SetVisible( true );
+ m_pMinimapPanel->InitMortarMinimap( GetMortar() );
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+C_ObjectMortar* CMortarControlPanel::GetMortar() const
+{
+ return dynamic_cast< C_ObjectMortar* >( GetOwningObject() );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void C_ObjectMortar::FireMortar( void )
+{
+ char cmd[512];
+ Q_snprintf( cmd, sizeof( cmd ), "FireMortar %.2f %.2f", m_flFiringPower, m_flFiringAccuracy );
+ SendClientCommand( cmd );
+}
+
+//-----------------------------------------------------------------------------
+// Frame-based update
+//-----------------------------------------------------------------------------
+vgui::Panel* CMortarControlPanel::TickCurrentPanel()
+{
+ C_BaseObject *pObj = GetOwningObject();
+ if (!pObj)
+ return BaseClass::TickCurrentPanel();;
+
+ ShowOwnerLabel( true );
+ ShowHealthLabel( true );
+
+ C_ObjectMortar *pMortar = GetMortar();
+ if ( !pMortar )
+ return BaseClass::TickCurrentPanel();;
+
+ ShowOwnerLabel( false );
+ ShowHealthLabel( false );
+
+ m_pMinimapPanel->Repaint();
+
+ float flAccuracySpeed = (1.0 / MORTAR_CHARGE_ACCURACY_RATE);
+
+ // Handle power charging
+ switch( pMortar->m_iFiringState )
+ {
+ case MORTAR_IDLE:
+ pMortar->m_flPower = 0;
+ break;
+
+ case MORTAR_CHARGING_POWER:
+ pMortar->m_flPower = MIN( pMortar->m_flPower + ( (1.0 / MORTAR_CHARGE_POWER_RATE) * gpGlobals->frametime), 1 );
+ pMortar->m_flFiringPower = 0;
+ pMortar->m_flFiringAccuracy = 0;
+ if ( pMortar->m_flPower >= 1.0 )
+ {
+ // Hit Max, start going down
+ pMortar->m_flFiringPower = pMortar->m_flPower;
+ pMortar->m_iFiringState = MORTAR_CHARGING_ACCURACY;
+ }
+ break;
+
+ case MORTAR_CHARGING_ACCURACY:
+ // Calculate accuracy speed
+ if ( pMortar->m_flFiringPower > 0.5 )
+ {
+ // Shots over halfway suffer an increased speed to the accuracy power, making accurate shots harder
+ float flAdjustedPower = (pMortar->m_flFiringPower - 0.5) * 3.0;
+ flAccuracySpeed += (pMortar->m_flFiringPower * flAdjustedPower);
+ }
+
+ pMortar->m_flPower = MAX( pMortar->m_flPower - ( flAccuracySpeed * gpGlobals->frametime), -0.25f);
+ if ( pMortar->m_flPower <= -0.25 )
+ {
+ // Hit Min, fire mortar
+ pMortar->m_flFiringAccuracy = pMortar->m_flPower;
+ pMortar->m_iFiringState = MORTAR_IDLE;
+
+ pMortar->FireMortar();
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return BaseClass::TickCurrentPanel();
+}
+
+//-----------------------------------------------------------------------------
+// Button click handlers
+//-----------------------------------------------------------------------------
+void CMortarControlPanel::OnCommand( const char *command )
+{
+ C_ObjectMortar *pMortar = GetMortar();
+ if ( !pMortar )
+ return;
+
+ if ( !Q_stricmp( command, "FireMortar" ) )
+ {
+ pMortar->ClickFire();
+ }
+
+ BaseClass::OnCommand(command);
+}
+
diff --git a/game/client/tf2/c_obj_powerpack.cpp b/game/client/tf2/c_obj_powerpack.cpp
new file mode 100644
index 0000000..edbfcfd
--- /dev/null
+++ b/game/client/tf2/c_obj_powerpack.cpp
@@ -0,0 +1,340 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+#include "cbase.h"
+#include "c_baseobject.h"
+#include "ObjectControlPanel.h"
+#include "tf_shareddefs.h"
+#include "tempent.h"
+#include "c_te_legacytempents.h"
+#include "iviewrender_beams.h"
+#include "beamdraw.h"
+#include "view.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+#define NUM_POWERPACK_GLOWS 6
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+class C_ObjectPowerPack : public C_BaseObject
+{
+ DECLARE_CLASS( C_ObjectPowerPack, C_BaseObject );
+public:
+ DECLARE_CLIENTCLASS();
+
+ C_ObjectPowerPack();
+ ~C_ObjectPowerPack();
+ int SocketsLeft() const { return (MAX_OBJECTS_PER_PACK - m_iObjectsAttached); }
+
+ // Since we have material proxies to show building amount, don't offset origin
+ virtual bool OffsetObjectOrigin( Vector& origin )
+ {
+ return false;
+ }
+
+ virtual void OnGoActive( void );
+ virtual void OnGoInactive( void );
+ void RemoveGlows( void );
+ virtual void ClientThink( void );
+ virtual int DrawModel( int flags );
+
+private:
+ int m_iObjectsAttached;
+ int m_iGlowModelIndex;
+ C_LocalTempEntity *m_pGlowSprites[ NUM_POWERPACK_GLOWS ];
+
+ // Jacob's laddder
+ Beam_t *m_pJacobsLadderBeam;
+ float m_flJacobsLeftPoint;
+ float m_flJacobsRightPoint;
+ Vector m_vecJacobsStart;
+ Vector m_vecJacobsEnd;
+ CMaterialReference m_hJacobsPointMaterial;
+
+private:
+ C_ObjectPowerPack( const C_ObjectPowerPack & ); // not defined, not accessible
+};
+
+IMPLEMENT_CLIENTCLASS_DT(C_ObjectPowerPack, DT_ObjectPowerPack, CObjectPowerPack)
+ RecvPropInt( RECVINFO(m_iObjectsAttached) ),
+END_RECV_TABLE()
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+C_ObjectPowerPack::C_ObjectPowerPack()
+{
+ for ( int i = 0; i < NUM_POWERPACK_GLOWS; i++ )
+ {
+ m_pGlowSprites[i] = NULL;
+ }
+
+ m_iGlowModelIndex = PrecacheModel( "effects/human_object_glow.vmt" );
+ m_pJacobsLadderBeam = NULL;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+C_ObjectPowerPack::~C_ObjectPowerPack( void )
+{
+ RemoveGlows();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: We've just gone active
+//-----------------------------------------------------------------------------
+void C_ObjectPowerPack::OnGoActive( void )
+{
+ // Turn on our glows
+ for ( int i = 0; i < NUM_POWERPACK_GLOWS; i++ )
+ {
+ // Find the attachment point
+ int iAttachment = LookupAttachment( VarArgs("glow_%d",(i+1)) );
+ Vector vecOrigin;
+ QAngle vecAngles;
+ if ( GetAttachment( iAttachment, vecOrigin, vecAngles ) )
+ {
+ Vector vecForward;
+ AngleVectors( vecAngles, &vecForward );
+ m_pGlowSprites[i] = tempents->TempSprite( vecOrigin, vec3_origin, 0.35, m_iGlowModelIndex, kRenderTransAdd, 0, 0.5, 1, FTENT_PERSIST | FTENT_NEVERDIE | FTENT_BEOCCLUDED, vecForward );
+ }
+ }
+
+ m_flJacobsLeftPoint = 0;
+ m_flJacobsRightPoint = 0;
+ m_hJacobsPointMaterial.Init( "sprites/blueflare2", TEXTURE_GROUP_CLIENT_EFFECTS );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: We've just gone inactive
+//-----------------------------------------------------------------------------
+void C_ObjectPowerPack::OnGoInactive( void )
+{
+ // Turn off our glows
+ RemoveGlows();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void C_ObjectPowerPack::RemoveGlows( void )
+{
+ for ( int i = 0; i < NUM_POWERPACK_GLOWS; i++ )
+ {
+ if ( m_pGlowSprites[i] )
+ {
+ m_pGlowSprites[i]->die = 0;
+ m_pGlowSprites[i] = NULL;
+ }
+ }
+
+ // Stop the jacob's ladder
+ if ( m_pJacobsLadderBeam )
+ {
+ m_pJacobsLadderBeam->flags &= ~FBEAM_FOREVER;
+ m_pJacobsLadderBeam->die = gpGlobals->curtime;
+ m_pJacobsLadderBeam = NULL;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void C_ObjectPowerPack::ClientThink( void )
+{
+ // Create the jacob's ladder
+ if ( !m_pJacobsLadderBeam )
+ {
+ BeamInfo_t beamInfo;
+ beamInfo.m_vecStart.Init();
+ beamInfo.m_vecEnd.Init();
+ beamInfo.m_pszModelName = "sprites/physbeam.vmt";
+ beamInfo.m_flHaloScale = 0.0f;
+ beamInfo.m_flLife = 0.0f;
+ beamInfo.m_flWidth = 8.0f;
+ beamInfo.m_flEndWidth = 4.0f;
+ beamInfo.m_flFadeLength = 0.0f;
+ beamInfo.m_flAmplitude = 20.0f;
+ beamInfo.m_flBrightness = 255.0f;
+ beamInfo.m_flSpeed = 0.0f;
+ beamInfo.m_nStartFrame = 0;
+ beamInfo.m_flFrameRate = 0.0f;
+ beamInfo.m_flRed = 206.0f;
+ beamInfo.m_flGreen = 181.0f;
+ beamInfo.m_flBlue = 127.0f;
+ beamInfo.m_nSegments = 5;
+ beamInfo.m_bRenderable = true;
+ m_pJacobsLadderBeam = beams->CreateBeamPoints( beamInfo );
+ }
+
+ // Update the position of the jacob's ladder
+ BeamInfo_t beamInfo;
+ QAngle vecAngle;
+ int iAttachment;
+
+ // Setup a color reflecting the amount of power being used
+ color32 color;
+ color.r = 206;
+ color.g = 182;
+ color.b = 127;
+ color.a = 255;
+
+ // Tesla Effect
+ Vector vecRightTop, vecRightBottom;
+ Vector vecLeftTop, vecLeftBottom;
+ iAttachment = LookupAttachment( "Tesla_ll" );
+ GetAttachment( iAttachment, vecLeftBottom, vecAngle );
+ iAttachment = LookupAttachment( "Tesla_ul" );
+ GetAttachment( iAttachment, vecLeftTop, vecAngle );
+ iAttachment = LookupAttachment( "Tesla_lr" );
+ GetAttachment( iAttachment, vecRightBottom, vecAngle );
+ iAttachment = LookupAttachment( "Tesla_ur" );
+ GetAttachment( iAttachment, vecRightTop, vecAngle );
+
+ float flSpeed = 0.02;
+
+ m_flJacobsLeftPoint += random->RandomFloat( flSpeed * 0.25, flSpeed * 2);
+ m_flJacobsRightPoint += random->RandomFloat( flSpeed * 0.25, flSpeed * 2);
+
+ // If they've both hit the end, break the ladder
+ if ( m_flJacobsLeftPoint >= 1.0f && m_flJacobsRightPoint >= 1.0f )
+ {
+ // Snap!
+ m_flJacobsLeftPoint = 0.0f;
+ m_flJacobsRightPoint = 0.0f;
+ }
+ else if ( m_flJacobsLeftPoint > 1.0f )
+ {
+ // Only the left point's made it
+ m_flJacobsLeftPoint = 1.0f;
+ }
+ else if ( m_flJacobsRightPoint > 1.0f )
+ {
+ // Only the right point's made it
+ m_flJacobsRightPoint = 1.0f;
+ }
+
+ Vector vecLeft = vecLeftTop - vecLeftBottom;
+ Vector vecRight = vecRightTop - vecRightBottom;
+ m_vecJacobsStart = vecLeftBottom + ( m_flJacobsLeftPoint * vecLeft );
+ m_vecJacobsEnd = vecRightBottom + ( m_flJacobsRightPoint * vecRight );
+
+ beamInfo.m_vecStart = m_vecJacobsStart;
+ beamInfo.m_vecEnd = m_vecJacobsEnd;
+ beamInfo.m_flRed = color.r;
+ beamInfo.m_flGreen = color.g;
+ beamInfo.m_flBlue = color.b;
+ beams->UpdateBeamInfo( m_pJacobsLadderBeam, beamInfo );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+int C_ObjectPowerPack::DrawModel( int flags )
+{
+ if ( BaseClass::DrawModel( flags ) )
+ {
+ if ( ShouldBeActive() )
+ {
+ // Get the distance to the view
+ float flDistance = (GetAbsOrigin() - MainViewOrigin()).LengthSqr();
+ if ( flDistance < (1024 * 1024) )
+ {
+ // Draw a sprite at the tips.
+ color32 color;
+ color.r = 255;
+ color.g = 255;
+ color.b = 255;
+ color.a = 255;
+ float flSize = 25.0f;
+ materials->Bind( m_hJacobsPointMaterial, this );
+ DrawSprite( m_vecJacobsStart, flSize, flSize, color );
+ DrawSprite( m_vecJacobsEnd, flSize, flSize, color );
+ }
+ }
+
+ return true;
+ }
+
+ return false;
+}
+
+//-----------------------------------------------------------------------------
+// Control screen
+//-----------------------------------------------------------------------------
+class CPowerPackControlPanel : public CObjectControlPanel
+{
+ DECLARE_CLASS( CPowerPackControlPanel, CObjectControlPanel );
+
+public:
+ CPowerPackControlPanel( vgui::Panel *parent, const char *panelName );
+ virtual bool Init( KeyValues* pKeyValues, VGuiScreenInitData_t* pInitData );
+ virtual void OnTick();
+
+private:
+ vgui::Label *m_pSocketsLabel;
+};
+
+
+DECLARE_VGUI_SCREEN_FACTORY( CPowerPackControlPanel, "powerpack_control_panel" );
+
+
+//-----------------------------------------------------------------------------
+// Constructor:
+//-----------------------------------------------------------------------------
+CPowerPackControlPanel::CPowerPackControlPanel( vgui::Panel *parent, const char *panelName )
+ : BaseClass( parent, "CPowerPackControlPanel" )
+{
+}
+
+
+//-----------------------------------------------------------------------------
+// Initialization
+//-----------------------------------------------------------------------------
+bool CPowerPackControlPanel::Init( KeyValues* pKeyValues, VGuiScreenInitData_t* pInitData )
+{
+ m_pSocketsLabel = new vgui::Label( GetActivePanel(), "SocketReadout", "" );
+
+ if (!BaseClass::Init(pKeyValues, pInitData))
+ return false;
+
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+// Frame-based update
+//-----------------------------------------------------------------------------
+void CPowerPackControlPanel::OnTick()
+{
+ BaseClass::OnTick();
+
+ C_BaseObject *pObj = GetOwningObject();
+ if (!pObj)
+ return;
+
+ Assert( dynamic_cast<C_ObjectPowerPack*>(pObj) );
+ C_ObjectPowerPack *pPowerPack = static_cast<C_ObjectPowerPack*>(pObj);
+
+ char buf[256];
+ int nSocketsLeft = pPowerPack->SocketsLeft();
+ if (nSocketsLeft > 0)
+ {
+ Q_snprintf( buf, sizeof( buf ), "%d sockets left", pPowerPack->SocketsLeft() );
+ }
+ else
+ {
+ Q_strncpy( buf, "No sockets left", sizeof( buf ) );
+ }
+
+ m_pSocketsLabel->SetText( buf );
+}
+
+
diff --git a/game/client/tf2/c_obj_rallyflag.cpp b/game/client/tf2/c_obj_rallyflag.cpp
new file mode 100644
index 0000000..76a1ee5
--- /dev/null
+++ b/game/client/tf2/c_obj_rallyflag.cpp
@@ -0,0 +1,35 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+#include "cbase.h"
+#include "hud.h"
+#include "c_baseobject.h"
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+class C_ObjectRallyFlag : public C_BaseObject
+{
+ DECLARE_CLASS( C_ObjectRallyFlag, C_BaseObject );
+public:
+ DECLARE_CLIENTCLASS();
+
+ C_ObjectRallyFlag();
+
+private:
+ C_ObjectRallyFlag( const C_ObjectRallyFlag & ); // not defined, not accessible
+};
+
+IMPLEMENT_CLIENTCLASS_DT(C_ObjectRallyFlag, DT_ObjectRallyFlag, CObjectRallyFlag)
+END_RECV_TABLE()
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+C_ObjectRallyFlag::C_ObjectRallyFlag()
+{
+}
+
diff --git a/game/client/tf2/c_obj_resourcepump.cpp b/game/client/tf2/c_obj_resourcepump.cpp
new file mode 100644
index 0000000..13858ce
--- /dev/null
+++ b/game/client/tf2/c_obj_resourcepump.cpp
@@ -0,0 +1,164 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+#include "cbase.h"
+#include "hud.h"
+#include "c_obj_resourcepump.h"
+#include "commanderoverlay.h"
+#include "vgui_healthbar.h"
+#include "ObjectControlPanel.h"
+#include "tf_shareddefs.h"
+#include "vgui_bitmapbutton.h"
+#include "C_Func_Resource.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+BEGIN_RECV_TABLE_NOBASE( C_ObjectResourcePump, DT_ResourcePumpTeamOnlyVars )
+ RecvPropInt( RECVINFO(m_iPumpLevel) ),
+ RecvPropEHandle( RECVINFO(m_hResourceZone) ),
+END_RECV_TABLE()
+
+
+IMPLEMENT_CLIENTCLASS_DT(C_ObjectResourcePump, DT_ResourcePump, CObjectResourcePump)
+ RecvPropDataTable( "teamonly", 0, 0, &REFERENCE_RECV_TABLE( DT_ResourcePumpTeamOnlyVars ) )
+END_RECV_TABLE()
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+C_ObjectResourcePump::C_ObjectResourcePump()
+{
+ m_iPumpLevel = 1;
+ m_pResourceBar = NULL;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void C_ObjectResourcePump::SetDormant( bool bDormant )
+{
+ BaseClass::SetDormant( bDormant );
+ ENTITY_PANEL_ACTIVATE( "resource_pump", !bDormant );
+}
+
+
+//-----------------------------------------------------------------------------
+// Control screen
+//-----------------------------------------------------------------------------
+class CResourcePumpControlPanel : public CObjectControlPanel
+{
+ DECLARE_CLASS( CResourcePumpControlPanel, CObjectControlPanel );
+
+public:
+ CResourcePumpControlPanel( vgui::Panel *parent, const char *panelName );
+ virtual bool Init( KeyValues* pKeyValues, VGuiScreenInitData_t* pInitData );
+ virtual void OnTick();
+ virtual void OnCommand( const char *command );
+
+ void Upgrade( void );
+
+private:
+ vgui::Button *m_pUpgradeButton;
+ vgui::Label *m_pResourcesLabel;
+};
+
+
+DECLARE_VGUI_SCREEN_FACTORY( CResourcePumpControlPanel, "resourcepump_control_panel" );
+
+
+//-----------------------------------------------------------------------------
+// Constructor:
+//-----------------------------------------------------------------------------
+CResourcePumpControlPanel::CResourcePumpControlPanel( vgui::Panel *parent, const char *panelName )
+ : BaseClass( parent, "CResourcePumpControlPanel" )
+{
+}
+
+//-----------------------------------------------------------------------------
+// Initialization
+//-----------------------------------------------------------------------------
+bool CResourcePumpControlPanel::Init( KeyValues* pKeyValues, VGuiScreenInitData_t* pInitData )
+{
+ m_pUpgradeButton = new CBitmapButton( this, "UpgradeButton", "Upgrade" );
+ m_pResourcesLabel = new vgui::Label( this, "ResourcesLabel", "Resources: 0" );
+
+ if (!BaseClass::Init(pKeyValues, pInitData))
+ return false;
+
+ // ROBIN: Removed upgrading for now
+ m_pUpgradeButton->SetVisible( false );
+
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+// Frame-based update
+//-----------------------------------------------------------------------------
+void CResourcePumpControlPanel::OnTick()
+{
+ BaseClass::OnTick();
+
+ C_BaseObject *pObj = GetOwningObject();
+ if (!pObj)
+ return;
+
+ Assert( dynamic_cast<C_ObjectResourcePump*>(pObj) );
+ C_ObjectResourcePump *pPump = static_cast<C_ObjectResourcePump*>(pObj);
+
+ char buf[256];
+ int iPumpLevel = pPump->GetLevel();
+ int iCost = CalculateObjectUpgrade( OBJ_RESOURCEPUMP, iPumpLevel );
+ if ( iCost )
+ {
+ Q_snprintf( buf, sizeof( buf ), "Upgrade to Level %d\nCost: %d", iPumpLevel+1, iCost );
+ }
+ else
+ {
+ Q_snprintf( buf, sizeof( buf ), "Level %d", iPumpLevel );
+ }
+
+ m_pUpgradeButton->SetText( buf );
+
+ C_ResourceZone *pResourceZone = pPump->GetResourceZone();
+ if (pResourceZone)
+ {
+ Q_snprintf( buf, sizeof( buf ), "Resources: %d", pResourceZone->m_nResourcesLeft );
+ m_pResourcesLabel->SetText( buf );
+ }
+ else
+ {
+ m_pResourcesLabel->SetText( "Resources: 0" );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Dismantles the object
+//-----------------------------------------------------------------------------
+void CResourcePumpControlPanel::Upgrade( void )
+{
+ C_BaseObject *pObj = GetOwningObject();
+ if (pObj)
+ {
+ pObj->SendClientCommand( "upgrade" );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Button click handlers
+//-----------------------------------------------------------------------------
+void CResourcePumpControlPanel::OnCommand( const char *command )
+{
+ if (!Q_strnicmp(command, "Upgrade", 7))
+ {
+ Upgrade();
+ return;
+ }
+
+ BaseClass::OnCommand(command);
+}
+
diff --git a/game/client/tf2/c_obj_resourcepump.h b/game/client/tf2/c_obj_resourcepump.h
new file mode 100644
index 0000000..3cab0e9
--- /dev/null
+++ b/game/client/tf2/c_obj_resourcepump.h
@@ -0,0 +1,44 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef C_OBJ_RESOURCEPUMP_H
+#define C_OBJ_RESOURCEPUMP_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "CommanderOverlay.h"
+#include "c_baseobject.h"
+
+class C_ResourceZone;
+
+class C_ObjectResourcePump : public C_BaseObject
+{
+ DECLARE_CLASS( C_ObjectResourcePump, C_BaseObject );
+public:
+ DECLARE_CLIENTCLASS();
+ DECLARE_ENTITY_PANEL();
+
+ C_ObjectResourcePump();
+
+ virtual void SetDormant( bool bDormant );
+ int GetLevel( void ) { return m_iPumpLevel; }
+
+ C_ResourceZone* GetResourceZone() { return m_hResourceZone.Get(); }
+
+private:
+ CHealthBarPanel *m_pResourceBar;
+ int m_iPumpLevel;
+ CHandle<C_ResourceZone> m_hResourceZone;
+
+private:
+ C_ObjectResourcePump( const C_ObjectResourcePump & ); // not defined, not accessible
+};
+
+
+
+#endif // C_OBJ_RESOURCEPUMP_H
diff --git a/game/client/tf2/c_obj_respawn_station.cpp b/game/client/tf2/c_obj_respawn_station.cpp
new file mode 100644
index 0000000..65af05f
--- /dev/null
+++ b/game/client/tf2/c_obj_respawn_station.cpp
@@ -0,0 +1,38 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Client's CObjectSentrygun
+//
+// $NoKeywords: $
+//=============================================================================//
+#include "cbase.h"
+#include "hud.h"
+#include "CommanderOverlay.h"
+#include "c_baseobject.h"
+#include "vgui_healthbar.h"
+#include "c_obj_respawn_station.h"
+#include "C_BaseTFPlayer.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+
+IMPLEMENT_CLIENTCLASS_DT(C_ObjectRespawnStation, DT_ObjectRespawnStation, CObjectRespawnStation)
+END_RECV_TABLE()
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+C_ObjectRespawnStation::C_ObjectRespawnStation( void )
+{
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void C_ObjectRespawnStation::SetDormant( bool bDormant )
+{
+ BaseClass::SetDormant( bDormant );
+ ENTITY_PANEL_ACTIVATE( "respawn_station", !bDormant );
+}
+
diff --git a/game/client/tf2/c_obj_respawn_station.h b/game/client/tf2/c_obj_respawn_station.h
new file mode 100644
index 0000000..8b766f1
--- /dev/null
+++ b/game/client/tf2/c_obj_respawn_station.h
@@ -0,0 +1,39 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef C_OBJ_RESPAWN_STATION_H
+#define C_OBJ_RESPAWN_STATION_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+//-----------------------------------------------------------------------------
+// Purpose: Respawn Station object
+//-----------------------------------------------------------------------------
+class C_ObjectRespawnStation : public C_BaseObject
+{
+ DECLARE_CLASS( C_ObjectRespawnStation, C_BaseObject );
+
+public:
+ DECLARE_CLIENTCLASS();
+ DECLARE_ENTITY_PANEL();
+
+ C_ObjectRespawnStation();
+
+ // Status
+ virtual void SetDormant( bool bDormant );
+
+protected:
+ // A special panel to indicate which one's the respawn station
+ CPanelRegistration m_SelectedRespawnPanel;
+
+private:
+ C_ObjectRespawnStation( const C_ObjectRespawnStation & ); // not defined, not accessible
+};
+
+
+#endif // C_OBJ_RESPAWN_STATION_H
diff --git a/game/client/tf2/c_obj_resupply.cpp b/game/client/tf2/c_obj_resupply.cpp
new file mode 100644
index 0000000..c0134dd
--- /dev/null
+++ b/game/client/tf2/c_obj_resupply.cpp
@@ -0,0 +1,151 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Client's CObjectSentrygun
+//
+// $NoKeywords: $
+//=============================================================================//
+#include "cbase.h"
+#include "c_baseobject.h"
+#include "c_basetfplayer.h"
+#include "ObjectControlPanel.h"
+#include "vgui_bitmapbutton.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Resupply Station object
+//-----------------------------------------------------------------------------
+class C_ObjectResupply : public C_BaseObject
+{
+ DECLARE_CLASS( C_ObjectResupply, C_BaseObject );
+public:
+ DECLARE_CLIENTCLASS();
+
+ C_ObjectResupply();
+
+private:
+ C_ObjectResupply( const C_ObjectResupply & ); // not defined, not accessible
+};
+
+
+IMPLEMENT_CLIENTCLASS_DT(C_ObjectResupply, DT_ObjectResupply, CObjectResupply)
+END_RECV_TABLE()
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+C_ObjectResupply::C_ObjectResupply()
+{
+}
+
+
+//-----------------------------------------------------------------------------
+// Control screen
+//-----------------------------------------------------------------------------
+class CResupplyControlPanel : public CObjectControlPanel
+{
+ DECLARE_CLASS( CResupplyControlPanel, CObjectControlPanel );
+
+public:
+ CResupplyControlPanel( vgui::Panel *parent, const char *panelName );
+ virtual bool Init( KeyValues* pKeyValues, VGuiScreenInitData_t* pInitData );
+ virtual void OnCommand( const char *command );
+
+protected:
+ virtual void OnTickActive( C_BaseObject *pObj, C_BaseTFPlayer *pLocalPlayer );
+
+private:
+ void Buy( ResupplyBuyType_t type );
+
+ vgui::Button *m_pBuyAmmoButton;
+ vgui::Button *m_pBuyGrenadesButton;
+ vgui::Button *m_pBuyHealthButton;
+ vgui::Button *m_pBuyAllButton;
+};
+
+
+DECLARE_VGUI_SCREEN_FACTORY( CResupplyControlPanel, "resupply_control_panel" );
+
+
+//-----------------------------------------------------------------------------
+// Constructor:
+//-----------------------------------------------------------------------------
+CResupplyControlPanel::CResupplyControlPanel( vgui::Panel *parent, const char *panelName )
+ : BaseClass( parent, "CResupplyControlPanel" )
+{
+}
+
+
+//-----------------------------------------------------------------------------
+// Initialization
+//-----------------------------------------------------------------------------
+bool CResupplyControlPanel::Init( KeyValues* pKeyValues, VGuiScreenInitData_t* pInitData )
+{
+ // Grab ahold of certain well-known controls
+ m_pBuyAmmoButton = new CBitmapButton( GetActivePanel(), "BuyAmmoButton", "" );
+ m_pBuyGrenadesButton = new CBitmapButton( GetActivePanel(), "BuyGrenadesButton", "" );
+ m_pBuyHealthButton = new CBitmapButton( GetActivePanel(), "BuyHealthButton", "" );
+ m_pBuyAllButton = new CBitmapButton( GetActivePanel(), "BuyAllButton", "" );
+
+ return BaseClass::Init( pKeyValues, pInitData );
+}
+
+
+//-----------------------------------------------------------------------------
+// Deactivates buttons we can't afford
+//-----------------------------------------------------------------------------
+void CResupplyControlPanel::OnTickActive( C_BaseObject *pObj, C_BaseTFPlayer *pLocalPlayer )
+{
+ BaseClass::OnTickActive( pObj, pLocalPlayer );
+
+ int nBankResources = pLocalPlayer ? pLocalPlayer->GetBankResources() : 0;
+ m_pBuyAmmoButton->SetEnabled( nBankResources >= RESUPPLY_AMMO_COST );
+ m_pBuyGrenadesButton->SetEnabled( nBankResources >= RESUPPLY_GRENADES_COST );
+ m_pBuyHealthButton->SetEnabled( nBankResources >= RESUPPLY_HEALTH_COST );
+ m_pBuyAllButton->SetEnabled( nBankResources >= RESUPPLY_ALL_COST );
+}
+
+
+//-----------------------------------------------------------------------------
+// Buys stuff
+//-----------------------------------------------------------------------------
+void CResupplyControlPanel::Buy( ResupplyBuyType_t type )
+{
+ C_BaseObject *pObj = GetOwningObject();
+ if (pObj)
+ {
+ char szbuf[48];
+ Q_snprintf( szbuf, sizeof( szbuf ), "buy %d", type );
+ pObj->SendClientCommand( szbuf );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Button click handlers
+//-----------------------------------------------------------------------------
+void CResupplyControlPanel::OnCommand( const char *command )
+{
+ if (!Q_strnicmp(command, "BuyAmmo", 8))
+ {
+ Buy(RESUPPLY_BUY_AMMO);
+ }
+ else if (!Q_strnicmp(command, "BuyHealth", 10))
+ {
+ Buy(RESUPPLY_BUY_HEALTH);
+ }
+ else if (!Q_strnicmp(command, "BuyGrenades", 12))
+ {
+ Buy(RESUPPLY_BUY_GRENADES);
+ }
+ else if (!Q_strnicmp(command, "BuyAll", 7))
+ {
+ Buy(RESUPPLY_BUY_ALL);
+ }
+ else
+ {
+ BaseClass::OnCommand(command);
+ }
+}
diff --git a/game/client/tf2/c_obj_sandbag_bunker.cpp b/game/client/tf2/c_obj_sandbag_bunker.cpp
new file mode 100644
index 0000000..4ae7a92
--- /dev/null
+++ b/game/client/tf2/c_obj_sandbag_bunker.cpp
@@ -0,0 +1,38 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#include "cbase.h"
+#include "hud.h"
+#include "commanderoverlay.h"
+#include "c_baseobject.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+class C_ObjectSandbagBunker : public C_BaseObject
+{
+ DECLARE_CLASS( C_ObjectSandbagBunker, C_BaseObject );
+public:
+ DECLARE_CLIENTCLASS();
+
+ C_ObjectSandbagBunker();
+
+private:
+ C_ObjectSandbagBunker( const C_ObjectSandbagBunker & ); // not defined, not accessible
+};
+
+IMPLEMENT_CLIENTCLASS_DT(C_ObjectSandbagBunker, DT_ObjectSandbagBunker, CObjectSandbagBunker)
+END_RECV_TABLE()
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+C_ObjectSandbagBunker::C_ObjectSandbagBunker()
+{
+}
diff --git a/game/client/tf2/c_obj_selfheal.cpp b/game/client/tf2/c_obj_selfheal.cpp
new file mode 100644
index 0000000..5fec4e9
--- /dev/null
+++ b/game/client/tf2/c_obj_selfheal.cpp
@@ -0,0 +1,36 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#include "cbase.h"
+#include "hud.h"
+#include "commanderoverlay.h"
+#include "tf_obj_baseupgrade_shared.h"
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+class C_ObjectSelfHeal : public C_BaseObjectUpgrade
+{
+ DECLARE_CLASS( C_ObjectSelfHeal, C_BaseObjectUpgrade );
+public:
+ DECLARE_CLIENTCLASS();
+
+ C_ObjectSelfHeal();
+
+private:
+ C_ObjectSelfHeal( const C_ObjectSelfHeal & ); // not defined, not accessible
+};
+
+IMPLEMENT_CLIENTCLASS_DT(C_ObjectSelfHeal, DT_ObjectSelfHeal, CObjectSelfHeal)
+END_RECV_TABLE()
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+C_ObjectSelfHeal::C_ObjectSelfHeal()
+{
+}
+
diff --git a/game/client/tf2/c_obj_sentrygun.h b/game/client/tf2/c_obj_sentrygun.h
new file mode 100644
index 0000000..c66fd81
--- /dev/null
+++ b/game/client/tf2/c_obj_sentrygun.h
@@ -0,0 +1,106 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef C_OBJ_SENTRYGUN_H
+#define C_OBJ_SENTRYGUN_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+//-----------------------------------------------------------------------------
+// Purpose: Base Sentrygun
+//-----------------------------------------------------------------------------
+class C_ObjectSentrygun : public C_BaseObject
+{
+ DECLARE_CLASS( C_ObjectSentrygun, C_BaseObject );
+public:
+ DECLARE_CLIENTCLASS();
+ DECLARE_ENTITY_PANEL();
+
+ C_ObjectSentrygun();
+ virtual void GetBoneControllers(float controllers[MAXSTUDIOBONES]);
+ virtual int DrawModel( int flags );
+ virtual void SetDormant( bool bDormant );
+ virtual void PreDataUpdate( DataUpdateType_t updateType );
+ virtual void PostDataUpdate( DataUpdateType_t updateType );
+ virtual void OnDataChanged( DataUpdateType_t updateType );
+ virtual float GetInitialBuilderYaw();
+ int GetAmmoLeft( void ) { return m_iAmmo; }
+ virtual void FinishedBuilding( void );
+
+ virtual void ClientThink( void );
+
+private:
+ bool IsTurtled( void ) { return m_bTurtled; }
+
+ // Turret Functions
+ bool MoveTurret( void );
+
+ // Recompute sentrygun orientation...
+ void RecomputeOrientation();
+
+public:
+
+ int m_iRightBound;
+ int m_iLeftBound;
+ bool m_bTurningRight;
+
+ // Movement
+ int m_iBaseTurnRate;
+ float m_fTurnRate;
+ QAngle m_vecCurAngles;
+ QAngle m_vecGoalAngles;
+ Vector m_vecCurDishAngles;
+
+ float m_fBoneXRotator;
+ float m_fBoneYRotator;
+ int m_iAmmo;
+
+ // Turtling
+ bool m_bTurtled;
+ bool m_bLastTurtled;
+ float m_flStartedTurtlingAt;
+ float m_flStartedUnTurtlingAt;
+
+ int m_nAnimationParity;
+ int m_nLastAnimationParity;
+
+ // Networked from server
+ EHANDLE m_hEnemy;
+
+
+ QAngle m_angPrevLocalAngles;
+ int m_nOrientationParity;
+ int m_nPrevOrientationParity;
+
+private:
+ C_ObjectSentrygun( const C_ObjectSentrygun & ); // not defined, not accessible
+};
+
+class C_ObjectSentrygunPlasma : public C_ObjectSentrygun
+{
+ DECLARE_CLASS( C_ObjectSentrygunPlasma, C_ObjectSentrygun );
+public:
+ C_ObjectSentrygunPlasma();
+ DECLARE_CLIENTCLASS();
+
+private:
+ C_ObjectSentrygunPlasma( const C_ObjectSentrygunPlasma & ); // not defined, not accessible
+};
+
+class C_ObjectSentrygunRocketlauncher : public C_ObjectSentrygun
+{
+ DECLARE_CLASS( C_ObjectSentrygunRocketlauncher, C_ObjectSentrygun );
+public:
+ C_ObjectSentrygunRocketlauncher();
+ DECLARE_CLIENTCLASS();
+
+private:
+ C_ObjectSentrygunRocketlauncher( const C_ObjectSentrygunRocketlauncher & ); // not defined, not accessible
+};
+
+#endif // C_OBJ_SENTRYGUN_H
diff --git a/game/client/tf2/c_obj_shieldwall.cpp b/game/client/tf2/c_obj_shieldwall.cpp
new file mode 100644
index 0000000..b094502
--- /dev/null
+++ b/game/client/tf2/c_obj_shieldwall.cpp
@@ -0,0 +1,111 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Client's CObjectSentrygun
+//
+// $NoKeywords: $
+//=============================================================================//
+#include "cbase.h"
+#include "hud.h"
+#include "CommanderOverlay.h"
+#include "c_baseobject.h"
+#include "vgui_healthbar.h"
+#include "ObjectControlPanel.h"
+#include "c_shield.h"
+
+//-----------------------------------------------------------------------------
+// Purpose: Resupply Station object
+//-----------------------------------------------------------------------------
+class C_ObjectShieldWallBase : public C_BaseObject
+{
+ DECLARE_CLASS( C_ObjectShieldWallBase, C_BaseObject );
+
+public:
+ C_ObjectShieldWallBase() {}
+
+public:
+ CHandle<C_Shield> m_hDeployedShield;
+
+private:
+ C_ObjectShieldWallBase( const C_ObjectShieldWallBase & ); // not defined, not accessible
+};
+
+
+//-----------------------------------------------------------------------------
+//
+// Projected shield wall
+//
+//-----------------------------------------------------------------------------
+class C_ObjectShieldWall : public C_ObjectShieldWallBase
+{
+ DECLARE_CLASS( C_ObjectShieldWall, C_ObjectShieldWallBase );
+public:
+ DECLARE_CLIENTCLASS();
+ DECLARE_ENTITY_PANEL();
+
+ C_ObjectShieldWall( void );
+
+ virtual void SetDormant( bool bDormant );
+ virtual void RecalculateIDString( void );
+
+private:
+ C_ObjectShieldWall( const C_ObjectShieldWall & ); // not defined, not accessible
+};
+
+IMPLEMENT_CLIENTCLASS_DT(C_ObjectShieldWall, DT_ObjectShieldWall, CObjectShieldWall)
+ RecvPropEHandle(RECVINFO(m_hDeployedShield)),
+END_RECV_TABLE()
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+C_ObjectShieldWall::C_ObjectShieldWall( void )
+{
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void C_ObjectShieldWall::SetDormant( bool bDormant )
+{
+ BaseClass::SetDormant( bDormant );
+ ENTITY_PANEL_ACTIVATE( "shield_wall", !bDormant );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void C_ObjectShieldWall::RecalculateIDString( void )
+{
+ if ( m_hDeployedShield )
+ {
+ // Report shield strength
+ Q_snprintf( m_szIDString, sizeof(m_szIDString), "Shield Strength: %.0f percent", m_hDeployedShield->GetPowerLevel() * 100 );
+ }
+
+ BaseClass::RecalculateIDString();
+}
+
+//-----------------------------------------------------------------------------
+// Control screen
+//-----------------------------------------------------------------------------
+class CShieldWallControlPanel : public CRotatingObjectControlPanel
+{
+ DECLARE_CLASS( CShieldWallControlPanel, CRotatingObjectControlPanel );
+
+public:
+ CShieldWallControlPanel( vgui::Panel *parent, const char *panelName );
+};
+
+
+DECLARE_VGUI_SCREEN_FACTORY( CShieldWallControlPanel, "shieldwall_control_panel" );
+
+
+//-----------------------------------------------------------------------------
+// Constructor:
+//-----------------------------------------------------------------------------
+CShieldWallControlPanel::CShieldWallControlPanel( vgui::Panel *parent, const char *panelName )
+ : BaseClass( parent, "CShieldWallControlPanel" )
+{
+}
+
+
diff --git a/game/client/tf2/c_obj_tower.cpp b/game/client/tf2/c_obj_tower.cpp
new file mode 100644
index 0000000..14a0473
--- /dev/null
+++ b/game/client/tf2/c_obj_tower.cpp
@@ -0,0 +1,69 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#include "cbase.h"
+#include "hud.h"
+#include "commanderoverlay.h"
+#include "c_baseobject.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+class C_ObjectTower : public C_BaseObject
+{
+ DECLARE_CLASS( C_ObjectTower, C_BaseObject );
+public:
+ DECLARE_CLIENTCLASS();
+
+ C_ObjectTower();
+
+private:
+ C_ObjectTower( const C_ObjectTower & ); // not defined, not accessible
+};
+
+IMPLEMENT_CLIENTCLASS_DT(C_ObjectTower, DT_ObjectTower, CObjectTower)
+END_RECV_TABLE()
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+C_ObjectTower::C_ObjectTower()
+{
+}
+
+//=============================================================================
+// Tower Ladder
+//=============================================================================
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+class C_ObjectTowerLadder : public C_BaseAnimating
+{
+ DECLARE_CLASS( C_ObjectTowerLadder, C_BaseAnimating );
+public:
+
+ DECLARE_CLIENTCLASS();
+
+ C_ObjectTowerLadder();
+
+private:
+ C_ObjectTowerLadder( const C_ObjectTowerLadder& ); // not defined, not accessible
+};
+
+IMPLEMENT_CLIENTCLASS_DT( C_ObjectTowerLadder, DT_ObjectTowerLadder, CObjectTowerLadder )
+END_RECV_TABLE()
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+C_ObjectTowerLadder::C_ObjectTowerLadder()
+{
+}
+
diff --git a/game/client/tf2/c_obj_tunnel.cpp b/game/client/tf2/c_obj_tunnel.cpp
new file mode 100644
index 0000000..7794571
--- /dev/null
+++ b/game/client/tf2/c_obj_tunnel.cpp
@@ -0,0 +1,143 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#include "cbase.h"
+#include "hud.h"
+#include "c_obj_mapdefined.h"
+#include "minimap_trace.h"
+#include <KeyValues.h>
+#include "VGuiMatSurface/IMatSystemSurface.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+class C_ObjectTunnel : public C_ObjectMapDefined
+{
+ DECLARE_CLASS( C_ObjectTunnel, C_ObjectMapDefined );
+public:
+ DECLARE_PREDICTABLE();
+ DECLARE_CLIENTCLASS();
+
+ C_ObjectTunnel();
+
+private:
+ C_ObjectTunnel( const C_ObjectTunnel& src );
+};
+
+LINK_ENTITY_TO_CLASS( obj_tunnel, C_ObjectTunnel );
+BEGIN_PREDICTION_DATA( C_ObjectTunnel )
+END_PREDICTION_DATA();
+
+
+IMPLEMENT_CLIENTCLASS_DT(C_ObjectTunnel, DT_ObjectTunnel, CObjectTunnel)
+END_RECV_TABLE()
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+C_ObjectTunnel::C_ObjectTunnel()
+{
+ CONSTRUCT_MINIMAP_PANEL( "obj_tunnel", MINIMAP_OBJECTS );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+class CMinimapObjectTunnelPanel : public CMinimapTraceTeamBitmapPanel
+{
+ DECLARE_CLASS( CMinimapObjectTunnelPanel, CMinimapTraceTeamBitmapPanel );
+
+public:
+ CMinimapObjectTunnelPanel( vgui::Panel *parent, const char *panelName )
+ : BaseClass( parent, "CMinimapObjectTunnelPanel" )
+ {
+ }
+
+ virtual bool Init( KeyValues* pKeyValues, MinimapInitData_t* pInitData );
+ virtual void Paint();
+
+private:
+ enum
+ {
+ STATE_ENABLED = 0,
+ STATE_DISABLED,
+
+ NUM_STATES
+ };
+
+ CTeamBitmapImage m_TeamImage[ NUM_STATES ];
+};
+
+//-----------------------------------------------------------------------------
+//
+// A standard minimap renderable that displays a bitmap that changes when team changes
+//
+//-----------------------------------------------------------------------------
+DECLARE_MINIMAP_FACTORY( CMinimapObjectTunnelPanel, "minimap_obj_tunnel_panel" );
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : pKeyValues -
+// pInitData -
+// Output : Returns true on success, false on failure.
+//-----------------------------------------------------------------------------
+bool CMinimapObjectTunnelPanel::Init( KeyValues* pKeyValues, MinimapInitData_t* pInitData )
+{
+ if (!BaseClass::Init(pKeyValues, pInitData))
+ return false;
+
+ // Load viewcone material
+ KeyValues *enabled = pKeyValues->FindKey( "EnabledImage" );
+ if ( enabled )
+ {
+ if ( !m_TeamImage[ STATE_ENABLED ].Init( this, enabled, pInitData->m_pEntity ) )
+ return false;
+ }
+
+ KeyValues *disabled = pKeyValues->FindKey( "DisabledImage" );
+ if ( disabled )
+ {
+ if ( !m_TeamImage[ STATE_DISABLED ].Init( this, disabled, pInitData->m_pEntity ) )
+ return false;
+ }
+
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CMinimapObjectTunnelPanel::Paint()
+{
+ // Draw the view cone
+ C_BaseEntity *pEntity = GetEntity();
+ Assert( pEntity );
+
+ if ( gHUD.IsHidden( HIDEHUD_MISCSTATUS ) )
+ return;
+
+ if ( !pEntity->IsBaseObject() )
+ return;
+
+ C_BaseObject *obj = static_cast< C_BaseObject * >( pEntity );
+ Assert( obj );
+
+ bool enabled = !obj->IsDisabled();
+ int image = enabled ? STATE_ENABLED : STATE_DISABLED;
+
+ if (!m_bClipToMap)
+ {
+ g_pMatSystemSurface->DisableClipping( true );
+ }
+ m_TeamImage[ image ].SetAlpha( ComputePanelAlpha() );
+ m_TeamImage[ image ].Paint();
+ g_pMatSystemSurface->DisableClipping( false );
+} \ No newline at end of file
diff --git a/game/client/tf2/c_obj_vehicleboost.cpp b/game/client/tf2/c_obj_vehicleboost.cpp
new file mode 100644
index 0000000..652015b
--- /dev/null
+++ b/game/client/tf2/c_obj_vehicleboost.cpp
@@ -0,0 +1,40 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#include "cbase.h"
+#include "hud.h"
+#include "commanderoverlay.h"
+#include "tf_obj_baseupgrade_shared.h"
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+class C_ObjectVehicleBoost : public C_BaseObjectUpgrade
+{
+
+ DECLARE_CLASS( C_ObjectVehicleBoost, C_BaseObjectUpgrade );
+
+public:
+
+ DECLARE_CLIENTCLASS();
+
+ C_ObjectVehicleBoost();
+
+private:
+
+ C_ObjectVehicleBoost( const C_ObjectVehicleBoost& ); // not defined, not accessible
+};
+
+IMPLEMENT_CLIENTCLASS_DT( C_ObjectVehicleBoost, DT_ObjectVehicleBoost, CObjectVehicleBoost )
+END_RECV_TABLE()
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+C_ObjectVehicleBoost::C_ObjectVehicleBoost()
+{
+}
+
diff --git a/game/client/tf2/c_objectsentrygun.cpp b/game/client/tf2/c_objectsentrygun.cpp
new file mode 100644
index 0000000..9d47a76
--- /dev/null
+++ b/game/client/tf2/c_objectsentrygun.cpp
@@ -0,0 +1,558 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Client's CObjectSentrygun
+//
+// $NoKeywords: $
+//=============================================================================//
+#include "cbase.h"
+#include "bone_setup.h"
+#include "CommanderOverlay.h"
+#include "c_baseobject.h"
+#include "C_Obj_SentryGun.h"
+#include "tf_shareddefs.h"
+#include "c_basetfplayer.h"
+#include "ObjectControlPanel.h"
+#include <vgui_controls/Button.h>
+
+inline float UTIL_AngleMod(float a)
+{
+ return anglemod(a);
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Base Sentrygun
+//-----------------------------------------------------------------------------
+BEGIN_RECV_TABLE_NOBASE(C_ObjectSentrygun, DT_SentrygunTeamOnlyVars)
+ RecvPropInt(RECVINFO( m_iAmmo )),
+END_RECV_TABLE()
+
+IMPLEMENT_CLIENTCLASS_DT(C_ObjectSentrygun, DT_ObjectSentrygun, CObjectSentrygun)
+ RecvPropInt( RECVINFO( m_iBaseTurnRate ) ),
+ RecvPropEHandle(RECVINFO(m_hEnemy)),
+ RecvPropDataTable( "teamonly", 0, 0, &REFERENCE_RECV_TABLE( DT_SentrygunTeamOnlyVars )),
+ RecvPropInt(RECVINFO(m_bTurtled)),
+ RecvPropInt( RECVINFO( m_nAnimationParity ) ),
+ RecvPropInt( RECVINFO( m_nOrientationParity ) ),
+END_RECV_TABLE()
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+C_ObjectSentrygun::C_ObjectSentrygun()
+{
+ m_fBoneXRotator = 0;
+ m_fBoneYRotator = 0;
+ m_iAmmo = 0;
+ m_bTurtled = false;
+ m_flStartedTurtlingAt = 0;
+ m_flStartedUnTurtlingAt = 0;
+
+ SetViewOffset( Vector(0,0,22) );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void C_ObjectSentrygun::SetDormant( bool bDormant )
+{
+ BaseClass::SetDormant( bDormant );
+ ENTITY_PANEL_ACTIVATE( "sentrygun", !bDormant );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+int C_ObjectSentrygun::DrawModel( int flags )
+{
+ float flRealOriginZ = GetLocalOrigin().z;
+
+ // If we're turtling, slide the model into the ground
+ if ( m_bTurtled )
+ {
+ // How far down are we?
+ float flTime = MIN( gpGlobals->curtime - m_flStartedTurtlingAt, SENTRY_TURTLE_TIME );
+ float flPercent = 1 - (SENTRY_TURTLE_TIME - flTime) / SENTRY_TURTLE_TIME;
+
+ // FIXME: This is totally wrong!!!
+ Vector vNewOrigin = GetLocalOrigin();
+ vNewOrigin.z -= (CollisionProp()->OBBSize().z * flPercent);
+ SetLocalOrigin( vNewOrigin );
+ InvalidateBoneCache();
+ }
+ else if ( !m_bTurtled )
+ {
+ if ( m_flStartedUnTurtlingAt )
+ {
+ float flTime = MIN( gpGlobals->curtime - m_flStartedUnTurtlingAt, SENTRY_TURTLE_TIME );
+ float flPercent = (SENTRY_TURTLE_TIME - flTime) / SENTRY_TURTLE_TIME;
+
+ // FIXME: This is totally wrong!!!
+ Vector vNewOrigin = GetLocalOrigin();
+ vNewOrigin.z -= (CollisionProp()->OBBSize().z * flPercent);
+ SetLocalOrigin( vNewOrigin );
+ InvalidateBoneCache();
+
+ // Fully unturtled?
+ if ( flTime >= SENTRY_TURTLE_TIME )
+ {
+ m_flStartedUnTurtlingAt = 0;
+ }
+ }
+ }
+
+ int drawn = BaseClass::DrawModel( flags );
+ SetLocalOriginDim( Z_INDEX, flRealOriginZ );
+
+ return drawn;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void C_ObjectSentrygun::PreDataUpdate( DataUpdateType_t updateType )
+{
+ BaseClass::PreDataUpdate( updateType );
+
+ m_bLastTurtled = m_bTurtled;
+ m_nLastAnimationParity = m_nAnimationParity;
+ m_angPrevLocalAngles = GetLocalAngles();
+ m_nPrevOrientationParity = m_nOrientationParity;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void C_ObjectSentrygun::PostDataUpdate( DataUpdateType_t updateType )
+{
+ BaseClass::PostDataUpdate( updateType );
+
+ if ( m_bLastTurtled != m_bTurtled )
+ {
+ if ( m_bTurtled )
+ {
+ m_flStartedTurtlingAt = gpGlobals->curtime;
+ m_flStartedUnTurtlingAt = 0;
+ }
+ else
+ {
+ m_flStartedUnTurtlingAt = gpGlobals->curtime;
+ m_flStartedTurtlingAt = 0;
+ }
+ }
+
+ if ( m_nLastAnimationParity != m_nAnimationParity )
+ {
+ SetCycle( 0.0f );
+ }
+
+ bool changed = false;
+ QAngle angleDiff;
+ angleDiff = ( GetAbsAngles() - m_angPrevLocalAngles );
+ for (int i = 0;i < 3; i++ )
+ {
+ angleDiff[i] = UTIL_AngleMod( angleDiff[ i ] );
+ }
+
+ if ( angleDiff.Length() > 0.1f )
+ {
+ changed = true;
+ }
+ if ( updateType == DATA_UPDATE_CREATED || changed )
+ {
+ // Orient it
+ m_vecCurAngles.y = UTIL_AngleMod( GetLocalAngles().y );
+ RecomputeOrientation();
+ }
+ else if ( m_nPrevOrientationParity != m_nOrientationParity )
+ {
+ if ( changed )
+ {
+ RecomputeOrientation();
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void C_ObjectSentrygun::OnDataChanged( DataUpdateType_t updateType )
+{
+ BaseClass::OnDataChanged( updateType );
+
+ if ( updateType == DATA_UPDATE_CREATED )
+ {
+ // Start thinking (Baseclass stops it)
+ SetNextClientThink( CLIENT_THINK_ALWAYS );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void C_ObjectSentrygun::FinishedBuilding( void )
+{
+ BaseClass::FinishedBuilding();
+
+ EmitSound( "ObjectSentrygun.Activate" );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void C_ObjectSentrygun::GetBoneControllers(float controllers[MAXSTUDIOBONECTRLS])
+{
+ studiohdr_t *pModel = modelinfo->GetStudiomodel( GetModel() );
+
+ // When yaw preview is on,
+ if (!IsPreviewingYaw())
+ {
+ Studio_SetController(pModel, 0, m_fBoneXRotator, controllers[0]);
+ }
+ else
+ {
+ // Bone rotation == 0 here to make it exactly match the preview
+ Studio_SetController(pModel, 0, 0, controllers[0]);
+ }
+
+ Studio_SetController(pModel, 1, m_fBoneYRotator, controllers[1]);
+ Studio_SetController(pModel, 2, m_fBoneYRotator, controllers[2]);
+ Studio_SetController(pModel, 3, m_fBoneYRotator, controllers[3]);
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: This is called to get the initial builder yaw...
+//-----------------------------------------------------------------------------
+float C_ObjectSentrygun::GetInitialBuilderYaw()
+{
+ // Take the current rotation into account
+ return GetAbsAngles().y + m_fBoneXRotator;
+}
+
+//-----------------------------------------------------------------------------
+// Called when a rotation happens
+//-----------------------------------------------------------------------------
+void C_ObjectSentrygun::RecomputeOrientation( )
+{
+ m_iRightBound = UTIL_AngleMod( m_vecCurAngles.y - 50);
+ m_iLeftBound = UTIL_AngleMod( m_vecCurAngles.y + 50);
+ if ( m_iRightBound > m_iLeftBound )
+ {
+ m_iRightBound = m_iLeftBound;
+ m_iLeftBound = UTIL_AngleMod( m_vecCurAngles.y - 50);
+ }
+
+ // Start it rotating
+ m_vecGoalAngles.y = m_iRightBound;;
+ m_vecGoalAngles.x = m_vecCurAngles.x = 0;
+
+ m_fBoneXRotator = 0.0f;
+ m_fBoneYRotator = 0.0f;
+
+ m_bTurningRight = true;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Handle movement of the turret
+//-----------------------------------------------------------------------------
+bool C_ObjectSentrygun::MoveTurret(void)
+{
+ bool bMoved = 0;
+
+ float turnrate = (float)(m_iBaseTurnRate) * 10.0f;
+ turnrate *= gpGlobals->frametime;
+
+ // any x movement?
+ if ( m_vecCurAngles.x != m_vecGoalAngles.x )
+ {
+ float flDir = m_vecGoalAngles.x > m_vecCurAngles.x ? 1 : -1 ;
+
+ m_vecCurAngles.x += 0.1 * (turnrate * 5) * flDir;
+
+ // if we started below the goal, and now we're past, peg to goal
+ if (flDir == 1)
+ {
+ if (m_vecCurAngles.x > m_vecGoalAngles.x)
+ m_vecCurAngles.x = m_vecGoalAngles.x;
+ }
+ else
+ {
+ if (m_vecCurAngles.x < m_vecGoalAngles.x)
+ m_vecCurAngles.x = m_vecGoalAngles.x;
+ }
+
+ m_fBoneYRotator = m_vecCurAngles.x;
+
+ bMoved = 1;
+ }
+
+ if ( m_vecCurAngles.y != m_vecGoalAngles.y )
+ {
+ float flDir = m_vecGoalAngles.y > m_vecCurAngles.y ? 1 : -1 ;
+ float flDist = fabs(m_vecGoalAngles.y - m_vecCurAngles.y);
+ bool bReversed = false;
+
+ if (flDist > 180)
+ {
+ flDist = 360 - flDist;
+ flDir = -flDir;
+ bReversed = true;
+ }
+
+ if (m_hEnemy == NULL )
+ {
+ if (flDist > 30)
+ {
+ if (m_fTurnRate < turnrate * 20)
+ {
+ m_fTurnRate += turnrate;
+ }
+ }
+ else
+ {
+ // Slow down
+ if ( m_fTurnRate > (turnrate * 5) )
+ m_fTurnRate -= turnrate;
+ }
+ }
+ else
+ {
+ // When tracking enemies, move faster and don't slow
+ if (flDist > 30)
+ {
+ if (m_fTurnRate < turnrate * 30)
+ {
+ m_fTurnRate += turnrate * 3;
+ }
+ }
+ }
+
+ m_vecCurAngles.y += 0.1 * m_fTurnRate * flDir;
+
+ // if we passed over the goal, peg right to it now
+ if (flDir == -1)
+ {
+ if ( (bReversed == false && m_vecGoalAngles.y > m_vecCurAngles.y) || (bReversed == true && m_vecGoalAngles.y < m_vecCurAngles.y) )
+ m_vecCurAngles.y = m_vecGoalAngles.y;
+ }
+ else
+ {
+ if ( (bReversed == false && m_vecGoalAngles.y < m_vecCurAngles.y) || (bReversed == true && m_vecGoalAngles.y > m_vecCurAngles.y) )
+ m_vecCurAngles.y = m_vecGoalAngles.y;
+ }
+
+ if (m_vecCurAngles.y < 0)
+ m_vecCurAngles.y += 360;
+ else if (m_vecCurAngles.y >= 360)
+ m_vecCurAngles.y -= 360;
+
+ if (flDist < (0.05 * turnrate))
+ m_vecCurAngles.y = m_vecGoalAngles.y;
+
+ m_fBoneXRotator = m_vecCurAngles.y - UTIL_AngleMod( GetAbsAngles().y );
+
+ bMoved = 1;
+ }
+
+ if ( !bMoved || !m_fTurnRate )
+ m_fTurnRate = turnrate;
+
+ if ( bMoved )
+ {
+ NetworkStateChanged();
+ }
+
+ return bMoved;
+}
+
+void C_ObjectSentrygun::ClientThink( void )
+{
+ // Turtling sentryguns don't think
+ if ( IsTurtled() )
+ return;
+
+ if ( IsPlacing() || IsBuilding() )
+ return;
+
+
+ if ( m_hEnemy != NULL )
+ {
+ // Figure out where we're firing at
+ Vector vecMid = EyePosition();
+ Vector vecFireTarget = m_hEnemy->WorldSpaceCenter(); // + vecMid; // BodyTarget( vecMid );
+ Vector vecDirToEnemy = vecFireTarget - vecMid;
+ QAngle angToTarget;
+ VectorAngles(vecDirToEnemy, angToTarget);
+
+ angToTarget.y = UTIL_AngleMod( angToTarget.y );
+ if (angToTarget.x < -180)
+ angToTarget.x += 360;
+ if (angToTarget.x > 180)
+ angToTarget.x -= 360;
+
+ // now all numbers should be in [1...360]
+ // pin to turret limitations to [-50...50]
+ if (angToTarget.x > 50)
+ angToTarget.x = 50;
+ else if (angToTarget.x < -50)
+ angToTarget.x = -50;
+
+ m_vecGoalAngles.y = angToTarget.y;
+ m_vecGoalAngles.x = angToTarget.x;
+
+ MoveTurret();
+ return;
+ }
+
+ // Rotate
+ if ( !MoveTurret() )
+ {
+ // Play a sound occasionally
+ if ( random->RandomFloat(0, 1) < 0.02 )
+ {
+ EmitSound( "ObjectSentrygun.Idle" );
+ }
+
+ // Switch rotation direction
+ if (m_bTurningRight)
+ {
+ m_bTurningRight = false;
+ m_vecGoalAngles.y = m_iLeftBound;
+ }
+ else
+ {
+ m_bTurningRight = true;
+ m_vecGoalAngles.y = m_iRightBound;
+ }
+
+ // Randomly look up and down a bit
+ if ( random->RandomFloat(0, 1) < 0.3 )
+ {
+ m_vecGoalAngles.x = (int)random->RandomFloat(-10,10);
+ }
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Control screen
+//-----------------------------------------------------------------------------
+class CSentrygunControlPanel : public CRotatingObjectControlPanel
+{
+ DECLARE_CLASS( CSentrygunControlPanel, CRotatingObjectControlPanel );
+
+public:
+ CSentrygunControlPanel( vgui::Panel *parent, const char *panelName );
+ virtual bool Init( KeyValues* pKeyValues, VGuiScreenInitData_t* pInitData );
+ virtual void OnTick();
+ virtual void OnCommand( const char *command );
+
+ void AddAmmo( void );
+
+private:
+ vgui::Label *m_pAmmoLabel;
+};
+
+
+DECLARE_VGUI_SCREEN_FACTORY( CSentrygunControlPanel, "sentrygun_control_panel" );
+
+
+//-----------------------------------------------------------------------------
+// Constructor:
+//-----------------------------------------------------------------------------
+CSentrygunControlPanel::CSentrygunControlPanel( vgui::Panel *parent, const char *panelName )
+ : BaseClass( parent, "CSentrygunControlPanel" )
+{
+}
+
+//-----------------------------------------------------------------------------
+// Initialization
+//-----------------------------------------------------------------------------
+bool CSentrygunControlPanel::Init( KeyValues* pKeyValues, VGuiScreenInitData_t* pInitData )
+{
+ m_pAmmoLabel = new vgui::Label( this, "AmmoReadout", "" );
+
+ if (!BaseClass::Init(pKeyValues, pInitData))
+ return false;
+
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// Frame-based update
+//-----------------------------------------------------------------------------
+void CSentrygunControlPanel::OnTick()
+{
+ BaseClass::OnTick();
+
+ C_BaseObject *pObj = GetOwningObject();
+ if (!pObj)
+ return;
+
+ Assert( dynamic_cast<C_ObjectSentrygun*>(pObj) );
+ C_ObjectSentrygun *pSentrygun = static_cast<C_ObjectSentrygun*>(pObj);
+
+ char buf[256];
+ int iAmmo = pSentrygun->GetAmmoLeft();
+ if (iAmmo > 0)
+ {
+ Q_snprintf( buf, sizeof( buf ), "%d rounds left", iAmmo );
+ }
+ else
+ {
+ Q_snprintf( buf, sizeof( buf ), "OUT OF AMMO" );
+ }
+ m_pAmmoLabel->SetText( buf );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Handle ammo input to the sentrygun
+//-----------------------------------------------------------------------------
+void CSentrygunControlPanel::AddAmmo( void )
+{
+ C_BaseObject *pObj = GetOwningObject();
+ if (pObj)
+ {
+ pObj->SendClientCommand( "addammo" );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Button click handlers
+//-----------------------------------------------------------------------------
+void CSentrygunControlPanel::OnCommand( const char *command )
+{
+ if (!Q_strnicmp(command, "AddAmmo", 7))
+ {
+ AddAmmo();
+ return;
+ }
+
+ BaseClass::OnCommand(command);
+}
+
+
+
+//======================================================================================================
+// SENTRYGUN TYPES
+//======================================================================================================
+// Purpose: Plasma sentrygun
+//-----------------------------------------------------------------------------
+IMPLEMENT_CLIENTCLASS_DT(C_ObjectSentrygunPlasma, DT_ObjectSentrygunPlasma, CObjectSentrygunPlasma)
+END_RECV_TABLE()
+
+C_ObjectSentrygunPlasma::C_ObjectSentrygunPlasma()
+{
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Rocket launcher sentrygun
+//-----------------------------------------------------------------------------
+IMPLEMENT_CLIENTCLASS_DT(C_ObjectSentrygunRocketlauncher, DT_ObjectSentrygunRocketlauncher, CObjectSentrygunRocketlauncher)
+END_RECV_TABLE()
+
+C_ObjectSentrygunRocketlauncher::C_ObjectSentrygunRocketlauncher()
+{
+}
+
+
diff --git a/game/client/tf2/c_order.cpp b/game/client/tf2/c_order.cpp
new file mode 100644
index 0000000..4309e63
--- /dev/null
+++ b/game/client/tf2/c_order.cpp
@@ -0,0 +1,462 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Client Side COrder class
+//
+// $NoKeywords: $
+//=============================================================================//
+#include "cbase.h"
+#include "hud_orders.h"
+#include "c_order.h"
+#include <vgui_controls/Controls.h>
+#include <vgui/ISurface.h>
+#include "minimap_trace.h"
+#include "VGuiMatSurface/IMatSystemSurface.h"
+#include "c_func_resource.h"
+#include "tf_shareddefs.h"
+#include "c_baseobject.h"
+#include "tf_hints.h"
+#include "hud.h"
+#include "c_basetfplayer.h"
+#include "c_tf_hintmanager.h"
+#include "clientmode_tfnormal.h"
+
+#define NEW_ORDER_ANIM_DURATION 1.0f
+#define NEW_ORDERS_RIGHT XRES(640-8)
+#define NEW_ORDERS_LEFT XRES(8)
+#define NEW_ORDERS_WIDTH (ORDERS_RIGHT - NEW_ORDERS_LEFT) //(NEW_ORDERS_RIGHT - ORDERS_LEFT)
+
+
+class COrderLabel : public vgui::Label
+{
+public:
+ COrderLabel( vgui::Panel *pParent, const char *pPanelName, const char *pText )
+ : vgui::Label( pParent, pPanelName, pText )
+ {
+ }
+
+ virtual void OnThink()
+ {
+ BaseClass::OnThink();
+
+ // Resize?
+ int x, y, w, h;
+ if( m_flAnimCounter < NEW_ORDER_ANIM_DURATION )
+ {
+ int wantedWidth, dummy;
+ GetContentSize( wantedWidth, dummy );
+ wantedWidth += 10;
+
+ float flPercent = m_flAnimCounter / NEW_ORDER_ANIM_DURATION;
+ int newWidth = (int)(NEW_ORDERS_WIDTH + (wantedWidth - NEW_ORDERS_WIDTH) * flPercent);
+
+ GetBounds( x, y, w, h );
+
+ m_flAnimCounter += gpGlobals->frametime;
+ if( m_flAnimCounter >= NEW_ORDER_ANIM_DURATION )
+ {
+ SetBounds( ORDERS_RIGHT - wantedWidth, y, wantedWidth, h );
+ }
+ else
+ {
+ SetBounds( ORDERS_RIGHT - newWidth, y, newWidth, h );
+ }
+ }
+ }
+
+ virtual void PaintBackground()
+ {
+ // BaseClass::PaintBackground();
+
+ // Draw our background.
+ int x, y, w, h;
+ GetBounds( x, y, w, h );
+
+ vgui::surface()->DrawSetColor( Color( 0, 0, 0, 160 ) );
+ vgui::surface()->DrawFilledRect( 0, 0, w, h );
+
+ vgui::surface()->DrawSetColor( Color( 63, 63, 63, 255 ) );
+ vgui::surface()->DrawOutlinedRect( 0, 0, w, h );
+ }
+
+public:
+ float m_flAnimCounter;
+};
+
+
+class CMinimapOrderPanel : public CMinimapTraceBitmapPanel
+{
+ DECLARE_CLASS( CMinimapOrderPanel, CMinimapTraceBitmapPanel );
+
+public:
+ CMinimapOrderPanel( vgui::Panel *parent, const char *panelName )
+ : BaseClass( parent, "CMinimapOrderPanel" )
+ {
+ }
+ virtual bool Init( KeyValues* pKeyValues, MinimapInitData_t* pInitData );
+ virtual void OnTick();
+ virtual void Paint( );
+
+private:
+ C_Order *m_pOrder;
+};
+
+
+DECLARE_MINIMAP_FACTORY( CMinimapOrderPanel, "minimap_order_panel" );
+
+bool CMinimapOrderPanel::Init( KeyValues* pKeyValues, MinimapInitData_t* pInitData )
+{
+ m_pOrder = dynamic_cast<C_Order*>(pInitData->m_pEntity);
+ if (!m_pOrder)
+ return false;
+
+ if (!BaseClass::Init( pKeyValues, pInitData ))
+ return false;
+
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// called when we're ticked...
+//-----------------------------------------------------------------------------
+void CMinimapOrderPanel::OnTick()
+{
+ // NOTE: Do *not* chain down the the base OnTick; it's going to do
+ // a totally different computation that will conflict with ours
+ Assert( m_pOrder );
+ if( m_pOrder->GetTarget() <= 0 )
+ {
+ SetVisible(false);
+ return;
+ }
+
+ C_BaseEntity *pTarget = ClientEntityList().GetEnt( m_pOrder->GetTarget() );
+ if( !pTarget )
+ {
+ SetVisible(false);
+ return;
+ }
+
+ SetEntity( pTarget );
+
+ // Now that we're attached to the correct target, compute position!
+ BaseClass::OnTick();
+}
+
+
+void CMinimapOrderPanel::Paint( )
+{
+ Assert( m_pOrder );
+
+ if( m_pOrder->GetTarget() <= 0 )
+ return;
+
+ C_BaseEntity *pTarget = ClientEntityList().GetEnt( m_pOrder->GetTarget() );
+ if( !pTarget )
+ return;
+
+ g_pMatSystemSurface->DisableClipping( true );
+
+ static float flStrobeDuration = 0.5;
+ float flShade = sin( gpGlobals->curtime * M_PI / flStrobeDuration ) * 0.5f + 0.5f;
+
+ Color color(255*flShade, 0, 0, 255);
+ m_Image.SetColor( color );
+ m_Image.Paint();
+
+ g_pMatSystemSurface->DisableClipping( false );
+}
+
+
+
+enum GetTargetDescriptionType_t
+{
+ GETDESC_RESOURCEZONE=0,
+ GETDESC_OBJECT
+};
+
+char* GetTargetDescription( int entindex, GetTargetDescriptionType_t type )
+{
+ static char szDesc[128];
+ szDesc[0]=0;
+
+ // Order target
+ if ( entindex )
+ {
+ C_BaseEntity *pEnt = cl_entitylist->GetEnt( entindex );
+ if ( pEnt )
+ {
+ if( type == GETDESC_RESOURCEZONE )
+ {
+ C_ResourceZone *pZone = dynamic_cast<C_ResourceZone*>(pEnt);
+ if ( pZone )
+ Q_strncpy( szDesc, pZone->GetTargetDescription(), sizeof( szDesc ) );
+ }
+ else if( type == GETDESC_OBJECT )
+ {
+ C_BaseObject *pObj = dynamic_cast<C_BaseObject*>( pEnt );
+ if( pObj )
+ Q_strncpy( szDesc, pObj->GetTargetDescription(), sizeof( szDesc ) );
+ }
+ }
+ }
+
+ return szDesc;
+}
+
+
+IMPLEMENT_CLIENTCLASS_DT(C_Order, DT_Order, COrder)
+ RecvPropInt( RECVINFO(m_iPriority) ),
+ RecvPropInt( RECVINFO(m_iOrderType) ),
+ RecvPropInt( RECVINFO(m_iTargetEntIndex) ),
+END_RECV_TABLE()
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+C_Order::C_Order( void )
+{
+ m_nHintID = TF_HINT_UNDEFINED;
+
+ m_pNameLabel = NULL;
+
+ CONSTRUCT_MINIMAP_PANEL( "minimap_order", MINIMAP_PERSONAL_ORDERS );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+C_Order::~C_Order( void )
+{
+ RemoveOrder();
+
+ if( C_BaseTFPlayer::GetLocalPlayer() )
+ C_BaseTFPlayer::GetLocalPlayer()->RemoveOrderTarget();
+
+
+ if ( m_nHintID != TF_HINT_UNDEFINED )
+ {
+ DestroyGlobalHint( m_nHintID );
+ }
+}
+
+void C_Order::ClientThink( void )
+{
+ BaseClass::ClientThink();
+
+ if ( m_nHintID != TF_HINT_UNDEFINED )
+ {
+ switch ( m_iOrderType )
+ {
+ case ORDER_REPAIR:
+ m_nHintID = TF_HINT_REPAIROBJECT;
+ break;
+ default:
+ break;
+ }
+ }
+
+ if ( m_nHintID != TF_HINT_UNDEFINED )
+ {
+ CreateGlobalHint_Panel( m_pNameLabel, m_nHintID, NULL, index );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void C_Order::OnDataChanged( DataUpdateType_t updateType )
+{
+ BaseClass::OnDataChanged( updateType );
+
+ C_BaseTFPlayer *pPlayer = C_BaseTFPlayer::GetLocalPlayer();
+ pPlayer->SetPersonalOrder( this );
+
+ // Update us if we've changed
+ if( updateType == DATA_UPDATE_CREATED )
+ {
+ CreateStatus( GetClientModeNormal()->GetViewport() );
+ }
+ else
+ {
+ GetHudOrderList()->RecalculateOrderList();
+ UpdateStatus();
+ }
+
+ if( m_iTargetEntIndex > 0 )
+ {
+ C_BaseEntity *pTarget = ClientEntityList().GetEnt( m_iTargetEntIndex );
+ m_OverlayPanel.Activate( pTarget, "personal_order", true );
+ }
+
+ if ( (updateType == DATA_UPDATE_CREATED) && ( m_nHintID != TF_HINT_UNDEFINED ) )
+ {
+ // Wait for animation to fly all the way in
+ SetNextClientThink( gpGlobals->curtime + NEW_ORDER_ANIM_DURATION + 0.25f );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Clean up a removed order
+//-----------------------------------------------------------------------------
+void C_Order::RemoveOrder( void )
+{
+ m_OverlayPanel.RemoveOverlay();
+
+ DestroyStatus();
+
+ if ( m_pNameLabel )
+ {
+ delete m_pNameLabel;
+ m_pNameLabel = NULL;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Get a text description of this order
+//-----------------------------------------------------------------------------
+void C_Order::GetDescription( char *pDest, int bufferSize )
+{
+ char targetDesc[512];
+ GetTargetDescription( targetDesc, sizeof( targetDesc ) );
+
+ switch ( m_iOrderType )
+ {
+ case ORDER_ATTACK:
+ Q_snprintf( pDest, bufferSize, "Attack %s", targetDesc );
+ break;
+
+ case ORDER_DEFEND:
+ Q_snprintf( pDest, bufferSize, "Defend %s", targetDesc );
+ break;
+
+ case ORDER_CAPTURE:
+ Q_snprintf( pDest, bufferSize, "Capture %s", targetDesc );
+ break;
+
+ default:
+ Q_snprintf( pDest, bufferSize, "INVALID" );
+ break;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Get a text description for the target of this order
+//-----------------------------------------------------------------------------
+void C_Order::GetTargetDescription( char *pDest, int bufferSize )
+{
+ pDest[0] = 0;
+
+ if ( !m_iTargetEntIndex )
+ return;
+
+ C_BaseEntity *pEnt = cl_entitylist->GetEnt( m_iTargetEntIndex );
+ if ( !pEnt )
+ return;
+
+ C_ResourceZone *pZone = dynamic_cast<C_ResourceZone*>(pEnt);
+ if ( pZone )
+ {
+ Q_strncpy( pDest, pZone->GetTargetDescription(), bufferSize );
+ }
+ else
+ {
+ C_BaseObject *pObj = dynamic_cast<C_BaseObject*>( pEnt );
+ if( pObj )
+ Q_strncpy( pDest, pObj->GetTargetDescription(), bufferSize );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Create all elements needed in a status panel for this order
+//-----------------------------------------------------------------------------
+void C_Order::CreateStatus( vgui::Panel *pParent )
+{
+ // If we already have our elements, we're just moving.
+ if ( m_pNameLabel )
+ {
+ m_pNameLabel->SetParent( pParent );
+ }
+ else
+ {
+ m_pNameLabel = new COrderLabel( pParent, "NameLabel", "Temp" );
+ m_pNameLabel->SetBounds( ORDERS_LEFT, ORDERS_TOP, NEW_ORDERS_WIDTH, ORDERS_ELEMENT_HEIGHT );
+ m_pNameLabel->SetAutoDelete( false );
+ m_pNameLabel->SetPaintBackgroundEnabled( true );
+ m_pNameLabel->SetFgColor( Color( 0, 0, 0, 255 ) );
+ m_pNameLabel->SetContentAlignment( vgui::Label::a_east );
+ m_pNameLabel->SetTextInset( -2, 0 );
+ }
+
+ UpdateStatus();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Destroy all elements in the status panel for this order
+//-----------------------------------------------------------------------------
+void C_Order::DestroyStatus( void )
+{
+ if ( m_pNameLabel )
+ {
+ delete m_pNameLabel;
+ m_pNameLabel = NULL;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Update all elements in the status panel for this order
+//-----------------------------------------------------------------------------
+void C_Order::UpdateStatus( void )
+{
+ if ( m_pNameLabel )
+ {
+ char desc[512];
+ GetDescription( desc, sizeof( desc ) );
+
+ m_pNameLabel->SetText( desc );
+ m_pNameLabel->m_flAnimCounter = 0;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Return true if this order wants a target reticle created around it's target
+//-----------------------------------------------------------------------------
+bool C_Order::ShouldDrawReticle( void )
+{
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+int C_Order::GetPriority( void )
+{
+ return m_iPriority;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+int C_Order::GetType( void )
+{
+ return m_iOrderType;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+int C_Order::GetTarget( void )
+{
+ return m_iTargetEntIndex;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Return true if this order is a personal one for this player
+//-----------------------------------------------------------------------------
+bool C_Order::IsPersonalOrder( void )
+{
+ return (GetPriority() == 0);
+}
+
diff --git a/game/client/tf2/c_order.h b/game/client/tf2/c_order.h
new file mode 100644
index 0000000..b1623c8
--- /dev/null
+++ b/game/client/tf2/c_order.h
@@ -0,0 +1,73 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Client Side COrder class
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef C_ORDER_H
+#define C_ORDER_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include <vgui_controls/Label.h>
+#include <vgui_controls/Panel.h>
+#include "CommanderOverlay.h"
+#include "hud_minimap.h"
+
+class COrderLabel;
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Datatable container class for orders
+//-----------------------------------------------------------------------------
+class C_Order : public C_BaseEntity
+{
+ DECLARE_CLASS( C_Order, C_BaseEntity );
+public:
+ DECLARE_CLIENTCLASS();
+
+ C_Order( void );
+ ~C_Order( void );
+
+ virtual void ClientThink( void );
+ virtual void OnDataChanged( DataUpdateType_t updateType );
+ virtual void RemoveOrder( void );
+ virtual void GetDescription( char *pDest, int bufferSize );
+ virtual void GetTargetDescription( char *pDest, int bufferSize );
+
+ // Status drawing
+ virtual void CreateStatus( vgui::Panel *pParent );
+ virtual void DestroyStatus( void );
+ virtual void UpdateStatus( void );
+ virtual bool ShouldDrawReticle( void );
+
+ // Data access
+ int GetPriority( void );
+ int GetTarget( void );
+ int GetType( void );
+ bool IsPersonalOrder( void );
+
+protected:
+ // Received via datatable
+ int m_iPriority;
+ int m_iOrderType;
+ int m_iTargetEntIndex;
+
+ // Used in status drawing
+ COrderLabel *m_pNameLabel;
+
+ // Animating panel to show the new order.
+ float m_flNewOrderHighlightTimer;
+
+ // Hook up the overlay on the tactical map.
+ DECLARE_ENTITY_PANEL();
+ DECLARE_MINIMAP_PANEL();
+
+protected:
+ int m_nHintID;
+};
+
+
+#endif // C_ORDER_H
diff --git a/game/client/tf2/c_order_assist.cpp b/game/client/tf2/c_order_assist.cpp
new file mode 100644
index 0000000..ab18247
--- /dev/null
+++ b/game/client/tf2/c_order_assist.cpp
@@ -0,0 +1,22 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+#include "cbase.h"
+#include "c_order_assist.h"
+
+
+IMPLEMENT_CLIENTCLASS_DT( C_OrderAssist, DT_OrderAssist, COrderAssist )
+END_RECV_TABLE()
+
+
+void C_OrderAssist::GetDescription( char *pDest, int bufferSize )
+{
+ char targetDesc[512];
+ GetTargetDescription( targetDesc, sizeof( targetDesc ) );
+
+ Q_snprintf( pDest, bufferSize, "Assist %s", targetDesc );
+}
+
diff --git a/game/client/tf2/c_order_assist.h b/game/client/tf2/c_order_assist.h
new file mode 100644
index 0000000..4457c3e
--- /dev/null
+++ b/game/client/tf2/c_order_assist.h
@@ -0,0 +1,32 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef C_ORDER_ASSIST_H
+#define C_ORDER_ASSIST_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+
+#include "c_order_player.h"
+
+
+class C_OrderAssist : public C_OrderPlayer
+{
+public:
+ DECLARE_CLASS( C_OrderAssist, C_OrderPlayer );
+ DECLARE_CLIENTCLASS();
+
+
+// C_Order overrides.
+public:
+
+ virtual void GetDescription( char *pDest, int bufferSize );
+};
+
+
+#endif // C_ORDER_ASSIST_H
diff --git a/game/client/tf2/c_order_buildsentrygun.cpp b/game/client/tf2/c_order_buildsentrygun.cpp
new file mode 100644
index 0000000..0a536d8
--- /dev/null
+++ b/game/client/tf2/c_order_buildsentrygun.cpp
@@ -0,0 +1,26 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+#include "cbase.h"
+#include "c_order_buildsentrygun.h"
+#include "tf_hints.h"
+
+
+IMPLEMENT_CLIENTCLASS_DT( C_OrderBuildSentryGun, DT_OrderBuildSentryGun, COrderBuildSentryGun )
+END_RECV_TABLE()
+
+
+C_OrderBuildSentryGun::C_OrderBuildSentryGun()
+{
+ m_nHintID = TF_HINT_BUILDSENTRYGUN_PLASMA;
+}
+
+
+void C_OrderBuildSentryGun::GetDescription( char *pDest, int bufferSize )
+{
+ Q_strncpy( pDest, "Build Sentry Gun To Protect Object", bufferSize );
+}
+
diff --git a/game/client/tf2/c_order_buildsentrygun.h b/game/client/tf2/c_order_buildsentrygun.h
new file mode 100644
index 0000000..04c7ffa
--- /dev/null
+++ b/game/client/tf2/c_order_buildsentrygun.h
@@ -0,0 +1,34 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef C_ORDER_BUILDSENTRYGUN_H
+#define C_ORDER_BUILDSENTRYGUN_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+
+#include "c_order.h"
+
+
+class C_OrderBuildSentryGun : public C_Order
+{
+public:
+ DECLARE_CLASS( C_OrderBuildSentryGun, C_Order );
+ DECLARE_CLIENTCLASS();
+
+ C_OrderBuildSentryGun();
+
+
+// C_Order overrides.
+public:
+
+ virtual void GetDescription( char *pDest, int bufferSize );
+};
+
+
+#endif // C_ORDER_BUILDSENTRYGUN_H
diff --git a/game/client/tf2/c_order_buildshieldwall.cpp b/game/client/tf2/c_order_buildshieldwall.cpp
new file mode 100644
index 0000000..1139917
--- /dev/null
+++ b/game/client/tf2/c_order_buildshieldwall.cpp
@@ -0,0 +1,19 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+#include "cbase.h"
+#include "c_order_buildshieldwall.h"
+
+
+IMPLEMENT_CLIENTCLASS_DT( C_OrderBuildShieldWall, DT_OrderBuildShieldWall, COrderBuildShieldWall )
+END_RECV_TABLE()
+
+
+void C_OrderBuildShieldWall::GetDescription( char *pDest, int bufferSize )
+{
+ Q_strncpy( pDest, "Build Shield Wall To Protect Object", bufferSize );
+}
+
diff --git a/game/client/tf2/c_order_buildshieldwall.h b/game/client/tf2/c_order_buildshieldwall.h
new file mode 100644
index 0000000..b22f3b9
--- /dev/null
+++ b/game/client/tf2/c_order_buildshieldwall.h
@@ -0,0 +1,32 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef C_ORDER_BUILDSHIELDWALL_H
+#define C_ORDER_BUILDSHIELDWALL_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+
+#include "c_order.h"
+
+
+class C_OrderBuildShieldWall : public C_Order
+{
+public:
+ DECLARE_CLASS( C_OrderBuildShieldWall, C_Order );
+ DECLARE_CLIENTCLASS();
+
+
+// C_Order overrides.
+public:
+
+ virtual void GetDescription( char *pDest, int bufferSize );
+};
+
+
+#endif // C_ORDER_BUILDSHIELDWALL_H
diff --git a/game/client/tf2/c_order_heal.cpp b/game/client/tf2/c_order_heal.cpp
new file mode 100644
index 0000000..555fb47
--- /dev/null
+++ b/game/client/tf2/c_order_heal.cpp
@@ -0,0 +1,22 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+#include "cbase.h"
+#include "c_order_heal.h"
+
+
+IMPLEMENT_CLIENTCLASS_DT( C_OrderHeal, DT_OrderHeal, COrderHeal )
+END_RECV_TABLE()
+
+
+void C_OrderHeal::GetDescription( char *pDest, int bufferSize )
+{
+ char targetDesc[512];
+ GetTargetDescription( targetDesc, sizeof( targetDesc ) );
+
+ Q_snprintf( pDest, bufferSize, "Heal %s", targetDesc );
+}
+
diff --git a/game/client/tf2/c_order_heal.h b/game/client/tf2/c_order_heal.h
new file mode 100644
index 0000000..a1addc6
--- /dev/null
+++ b/game/client/tf2/c_order_heal.h
@@ -0,0 +1,32 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef C_ORDER_HEAL_H
+#define C_ORDER_HEAL_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+
+#include "c_order_player.h"
+
+
+class C_OrderHeal : public C_OrderPlayer
+{
+public:
+ DECLARE_CLASS( C_OrderHeal, C_OrderPlayer );
+ DECLARE_CLIENTCLASS();
+
+
+// C_Order overrides.
+public:
+
+ virtual void GetDescription( char *pDest, int bufferSize );
+};
+
+
+#endif // C_ORDER_HEAL_H
diff --git a/game/client/tf2/c_order_killmortarguy.cpp b/game/client/tf2/c_order_killmortarguy.cpp
new file mode 100644
index 0000000..682a2f2
--- /dev/null
+++ b/game/client/tf2/c_order_killmortarguy.cpp
@@ -0,0 +1,22 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+#include "cbase.h"
+#include "c_order_killmortarguy.h"
+
+
+IMPLEMENT_CLIENTCLASS_DT( C_OrderKillMortarGuy, DT_OrderKillMortarGuy, COrderKillMortarGuy )
+END_RECV_TABLE()
+
+
+void C_OrderKillMortarGuy::GetDescription( char *pDest, int bufferSize )
+{
+ char targetDesc[512];
+ GetTargetDescription( targetDesc, sizeof( targetDesc ) );
+
+ Q_snprintf( pDest, bufferSize, "Kill Mortar Guy: %s", targetDesc );
+}
+
diff --git a/game/client/tf2/c_order_killmortarguy.h b/game/client/tf2/c_order_killmortarguy.h
new file mode 100644
index 0000000..c3932ce
--- /dev/null
+++ b/game/client/tf2/c_order_killmortarguy.h
@@ -0,0 +1,32 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef C_ORDER_KILLMORTARGUY_H
+#define C_ORDER_KILLMORTARGUY_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+
+#include "c_order_player.h"
+
+
+class C_OrderKillMortarGuy : public C_OrderPlayer
+{
+public:
+ DECLARE_CLASS( C_OrderKillMortarGuy, C_OrderPlayer );
+ DECLARE_CLIENTCLASS();
+
+
+// C_Order overrides.
+public:
+
+ virtual void GetDescription( char *pDest, int bufferSize );
+};
+
+
+#endif // C_ORDER_KILLMORTARGUY_H
diff --git a/game/client/tf2/c_order_mortar_attack.cpp b/game/client/tf2/c_order_mortar_attack.cpp
new file mode 100644
index 0000000..67795a7
--- /dev/null
+++ b/game/client/tf2/c_order_mortar_attack.cpp
@@ -0,0 +1,22 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+#include "cbase.h"
+#include "c_order_mortar_attack.h"
+
+
+IMPLEMENT_CLIENTCLASS_DT( C_OrderMortarAttack, DT_OrderMortarAttack, COrderMortarAttack )
+END_RECV_TABLE()
+
+
+void C_OrderMortarAttack::GetDescription( char *pDest, int bufferSize )
+{
+ char targetDesc[512];
+ GetTargetDescription( targetDesc, sizeof( targetDesc ) );
+
+ Q_snprintf( pDest, bufferSize, "Attack %s with mortar", targetDesc );
+}
+
diff --git a/game/client/tf2/c_order_mortar_attack.h b/game/client/tf2/c_order_mortar_attack.h
new file mode 100644
index 0000000..9502d6a
--- /dev/null
+++ b/game/client/tf2/c_order_mortar_attack.h
@@ -0,0 +1,32 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef C_ORDER_MORTAR_ATTACK_H
+#define C_ORDER_MORTAR_ATTACK_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+
+#include "c_order.h"
+
+
+class C_OrderMortarAttack : public C_Order
+{
+public:
+ DECLARE_CLASS( C_OrderMortarAttack, C_Order );
+ DECLARE_CLIENTCLASS();
+
+
+// C_Order overrides.
+public:
+
+ virtual void GetDescription( char *pDest, int bufferSize );
+};
+
+
+#endif // C_ORDER_MORTAR_ATTACK_H
diff --git a/game/client/tf2/c_order_player.cpp b/game/client/tf2/c_order_player.cpp
new file mode 100644
index 0000000..180c390
--- /dev/null
+++ b/game/client/tf2/c_order_player.cpp
@@ -0,0 +1,38 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+#include "cbase.h"
+#include "c_order_player.h"
+#include "cliententitylist.h"
+#include "c_basetfplayer.h"
+
+
+IMPLEMENT_CLIENTCLASS_DT( C_OrderPlayer, DT_OrderPlayer, COrderPlayer )
+END_RECV_TABLE()
+
+
+void C_OrderPlayer::GetTargetDescription( char *pDest, int bufferSize )
+{
+ pDest[0] = 0;
+
+ // Order target
+ if ( !m_iTargetEntIndex )
+ return;
+
+ C_BaseEntity *pEnt = cl_entitylist->GetEnt(m_iTargetEntIndex);
+ if ( !pEnt )
+ return;
+
+ C_BaseTFPlayer *pPlayer = dynamic_cast<C_BaseTFPlayer*>(pEnt);
+ if ( pPlayer )
+ {
+ pPlayer->GetTargetDescription( pDest, bufferSize );
+ }
+}
+
+
+
+
diff --git a/game/client/tf2/c_order_player.h b/game/client/tf2/c_order_player.h
new file mode 100644
index 0000000..54b8961
--- /dev/null
+++ b/game/client/tf2/c_order_player.h
@@ -0,0 +1,33 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef C_ORDER_PLAYER_H
+#define C_ORDER_PLAYER_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+
+#include "c_order.h"
+
+
+// Orders that point at players.
+class C_OrderPlayer : public C_Order
+{
+public:
+ DECLARE_CLASS( C_OrderPlayer, C_Order );
+ DECLARE_CLIENTCLASS();
+
+
+// C_Order overrides.
+public:
+
+ virtual void GetTargetDescription( char *pDest, int bufferSize );
+};
+
+
+#endif // C_ORDER_PLAYER_H
diff --git a/game/client/tf2/c_order_repair.cpp b/game/client/tf2/c_order_repair.cpp
new file mode 100644
index 0000000..3ad2af7
--- /dev/null
+++ b/game/client/tf2/c_order_repair.cpp
@@ -0,0 +1,19 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+#include "cbase.h"
+#include "c_order_repair.h"
+
+
+IMPLEMENT_CLIENTCLASS_DT( C_OrderRepair, DT_OrderRepair, COrderRepair )
+END_RECV_TABLE()
+
+
+void C_OrderRepair::GetDescription( char *pDest, int bufferSize )
+{
+ Q_strncpy( pDest, "Repair Structure", bufferSize );
+}
+
diff --git a/game/client/tf2/c_order_repair.h b/game/client/tf2/c_order_repair.h
new file mode 100644
index 0000000..ffb9d8c
--- /dev/null
+++ b/game/client/tf2/c_order_repair.h
@@ -0,0 +1,32 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef C_ORDER_REPAIR_H
+#define C_ORDER_REPAIR_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+
+#include "c_order.h"
+
+
+class C_OrderRepair : public C_Order
+{
+public:
+ DECLARE_CLASS( C_OrderRepair, C_Order );
+ DECLARE_CLIENTCLASS();
+
+
+// C_Order overrides.
+public:
+
+ virtual void GetDescription( char *pDest, int bufferSize );
+};
+
+
+#endif // C_ORDER_REPAIR_H
diff --git a/game/client/tf2/c_order_resourcepump.cpp b/game/client/tf2/c_order_resourcepump.cpp
new file mode 100644
index 0000000..5e2e90d
--- /dev/null
+++ b/game/client/tf2/c_order_resourcepump.cpp
@@ -0,0 +1,27 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#include "cbase.h"
+#include "c_order_resourcepump.h"
+#include "tf_hints.h"
+
+
+IMPLEMENT_CLIENTCLASS_DT( C_OrderResourcePump, DT_OrderResourcePump, COrderResourcePump )
+END_RECV_TABLE()
+
+
+C_OrderResourcePump::C_OrderResourcePump()
+{
+ m_nHintID = TF_HINT_BUILDRESOURCEPUMP;
+}
+
+
+void C_OrderResourcePump::GetDescription( char *pDest, int bufferSize )
+{
+ Q_strncpy( pDest, "Build Resource Pump", bufferSize );
+}
+
diff --git a/game/client/tf2/c_order_resourcepump.h b/game/client/tf2/c_order_resourcepump.h
new file mode 100644
index 0000000..11a24d8
--- /dev/null
+++ b/game/client/tf2/c_order_resourcepump.h
@@ -0,0 +1,34 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef C_ORDER_RESOURCEPUMP_H
+#define C_ORDER_RESOURCEPUMP_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+
+#include "c_order.h"
+
+
+class C_OrderResourcePump : public C_Order
+{
+public:
+ DECLARE_CLASS( C_OrderResourcePump, C_Order );
+ DECLARE_CLIENTCLASS();
+
+ C_OrderResourcePump();
+
+
+// C_Order overrides.
+public:
+
+ virtual void GetDescription( char *pDest, int bufferSize );
+};
+
+
+#endif // C_ORDER_RESOURCEPUMP_H
diff --git a/game/client/tf2/c_order_respawnstation.cpp b/game/client/tf2/c_order_respawnstation.cpp
new file mode 100644
index 0000000..757f218
--- /dev/null
+++ b/game/client/tf2/c_order_respawnstation.cpp
@@ -0,0 +1,19 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+#include "cbase.h"
+#include "c_order_respawnstation.h"
+
+
+IMPLEMENT_CLIENTCLASS_DT( C_OrderRespawnStation, DT_OrderRespawnStation, COrderRespawnStation )
+END_RECV_TABLE()
+
+
+void C_OrderRespawnStation::GetDescription( char *pDest, int bufferSize )
+{
+ Q_strncpy( pDest, "Build Respawn Station Near Object", bufferSize );
+}
+
diff --git a/game/client/tf2/c_order_respawnstation.h b/game/client/tf2/c_order_respawnstation.h
new file mode 100644
index 0000000..f28e72c
--- /dev/null
+++ b/game/client/tf2/c_order_respawnstation.h
@@ -0,0 +1,32 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef C_ORDER_RESPAWNSTATION_H
+#define C_ORDER_RESPAWNSTATION_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+
+#include "c_order_player.h"
+
+
+class C_OrderRespawnStation : public C_Order
+{
+public:
+ DECLARE_CLASS( C_OrderRespawnStation, C_Order );
+ DECLARE_CLIENTCLASS();
+
+
+// C_Order overrides.
+public:
+
+ virtual void GetDescription( char *pDest, int bufferSize );
+};
+
+
+#endif // C_ORDER_RESPAWNSTATION_H
diff --git a/game/client/tf2/c_order_resupply.cpp b/game/client/tf2/c_order_resupply.cpp
new file mode 100644
index 0000000..ca71b93
--- /dev/null
+++ b/game/client/tf2/c_order_resupply.cpp
@@ -0,0 +1,19 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+#include "cbase.h"
+#include "c_order_resupply.h"
+
+
+IMPLEMENT_CLIENTCLASS_DT( C_OrderResupply, DT_OrderResupply, COrderResupply )
+END_RECV_TABLE()
+
+
+void C_OrderResupply::GetDescription( char *pDest, int bufferSize )
+{
+ Q_strncpy( pDest, "Build Resupply Station Near Object", bufferSize );
+}
+
diff --git a/game/client/tf2/c_order_resupply.h b/game/client/tf2/c_order_resupply.h
new file mode 100644
index 0000000..0db297a
--- /dev/null
+++ b/game/client/tf2/c_order_resupply.h
@@ -0,0 +1,32 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef C_ORDER_RESUPPLY_H
+#define C_ORDER_RESUPPLY_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+
+#include "c_order.h"
+
+
+class C_OrderResupply : public C_Order
+{
+public:
+ DECLARE_CLASS( C_OrderResupply, C_Order );
+ DECLARE_CLIENTCLASS();
+
+
+// C_Order overrides.
+public:
+
+ virtual void GetDescription( char *pDest, int bufferSize );
+};
+
+
+#endif // C_ORDER_RESUPPLY_H
diff --git a/game/client/tf2/c_ragdoll_shadow.cpp b/game/client/tf2/c_ragdoll_shadow.cpp
new file mode 100644
index 0000000..efb705b
--- /dev/null
+++ b/game/client/tf2/c_ragdoll_shadow.cpp
@@ -0,0 +1,246 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+#include "cbase.h"
+#include "model_types.h"
+#include "vcollide.h"
+#include "vcollide_parse.h"
+#include "solidsetdefaults.h"
+#include "c_basetfplayer.h"
+#include "bone_setup.h"
+#include "engine/ivmodelinfo.h"
+
+CPhysCollide *PhysCreateBbox( const Vector &mins, const Vector &maxs );
+extern CSolidSetDefaults g_SolidSetup;
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+class C_RagdollShadow : public C_BaseAnimating
+{
+ DECLARE_CLASS( C_RagdollShadow, C_BaseAnimating );
+public:
+ DECLARE_CLIENTCLASS();
+
+ C_RagdollShadow( void );
+ ~C_RagdollShadow( void );
+
+ virtual void OnDataChanged( DataUpdateType_t updateType );
+
+ virtual void ClientThink( void );
+ virtual int DrawModel( int flags );
+
+public:
+ IPhysicsObject *VPhysicsInitShadow( bool allowPhysicsMovement, bool allowPhysicsRotation );
+ void VPhysicsSetObject( IPhysicsObject *pPhysics );
+ void VPhysicsDestroyObject( void );
+
+ int m_nPlayer;
+ EHANDLE m_hPlayer;
+
+ IPhysicsObject *m_pPhysicsObject;
+ IPhysicsSpring *m_pSpring;
+};
+
+IMPLEMENT_CLIENTCLASS_DT( C_RagdollShadow, DT_RagdollShadow, CRagdollShadow )
+ RecvPropInt( RECVINFO( m_nPlayer ) ),
+END_RECV_TABLE()
+
+C_RagdollShadow::C_RagdollShadow( void )
+{
+ m_nPlayer = -1;
+ m_hPlayer = NULL;
+
+ m_pPhysicsObject = NULL;
+ m_pSpring = NULL;
+}
+
+C_RagdollShadow::~C_RagdollShadow( void )
+{
+ VPhysicsDestroyObject();
+
+ delete m_pSpring;
+}
+
+void C_RagdollShadow::VPhysicsDestroyObject( void )
+{
+ if ( m_pPhysicsObject )
+ {
+ physenv->DestroyObject( m_pPhysicsObject );
+ m_pPhysicsObject = NULL;
+ }
+}
+
+// Create a physics thingy based on an existing collision model
+IPhysicsObject *PhysModelCreateCustom( C_BaseEntity *pEntity, const CPhysCollide *pModel, const Vector &origin, const QAngle &angles, const char *props )
+{
+ solid_t solid;
+ solid.params = g_PhysDefaultObjectParams;
+ solid.params.mass = 85.0f;
+ solid.params.inertia = 1e24f;
+ int surfaceProp = -1;
+ if ( props && props[0] )
+ {
+ surfaceProp = physprops->GetSurfaceIndex( props );
+ }
+ solid.params.pGameData = static_cast<void *>(pEntity);
+ IPhysicsObject *pObject = physenv->CreatePolyObject( pModel, surfaceProp, origin, angles, &solid.params );
+ return pObject;
+}
+
+IPhysicsObject *PhysModelCreateRagdoll( C_BaseEntity *pEntity, int modelIndex, const Vector &origin, const QAngle &angles )
+{
+ vcollide_t *pCollide = modelinfo->GetVCollide( modelIndex );
+ if ( !pCollide )
+ return NULL;
+
+ solid_t solid;
+ memset( &solid, 0, sizeof(solid) );
+ solid.params = g_PhysDefaultObjectParams;
+
+ IVPhysicsKeyParser *pParse = physcollision->VPhysicsKeyParserCreate( pCollide->pKeyValues );
+ while ( !pParse->Finished() )
+ {
+ const char *pBlock = pParse->GetCurrentBlockName();
+ if ( !strcmpi( pBlock, "solid" ) )
+ {
+ pParse->ParseSolid( &solid, &g_SolidSetup );
+ break;
+ }
+ else
+ {
+ pParse->SkipBlock();
+ }
+ }
+ physcollision->VPhysicsKeyParserDestroy( pParse );
+
+ // collisions are off by default
+ solid.params.enableCollisions = true;
+
+ int surfaceProp = -1;
+ if ( solid.surfaceprop[0] )
+ {
+ surfaceProp = physprops->GetSurfaceIndex( solid.surfaceprop );
+ }
+ solid.params.pGameData = static_cast<void *>(pEntity);
+ solid.params.pName = "ragdoll_player";
+ IPhysicsObject *pObject = physenv->CreatePolyObject( pCollide->solids[0], surfaceProp, origin, angles, &solid.params );
+ //PhysCheckAdd( pObject, STRING(pEntity->m_iClassname) );
+ return pObject;
+}
+
+void C_RagdollShadow::VPhysicsSetObject( IPhysicsObject *pPhysics )
+{
+ if ( m_pPhysicsObject && pPhysics )
+ {
+ Warning( "C_RagdollShadow::Overwriting physics object!\n" );
+ }
+ m_pPhysicsObject = pPhysics;
+}
+
+
+// This creates a vphysics object with a shadow controller that follows the AI
+IPhysicsObject *C_RagdollShadow::VPhysicsInitShadow( bool allowPhysicsMovement, bool allowPhysicsRotation )
+{
+ CStudioHdr *hdr = GetModelPtr();
+ if ( !hdr )
+ {
+ return NULL;
+ }
+
+ // If this entity already has a physics object, then it should have been deleted prior to making this call.
+ Assert(!m_pPhysicsObject);
+
+ // make sure m_vecOrigin / m_vecAngles are correct
+ const Vector &origin = GetAbsOrigin();
+ QAngle angles = GetAbsAngles();
+ IPhysicsObject *pPhysicsObject = NULL;
+
+ if ( GetSolid() == SOLID_BBOX )
+ {
+ const char *pSurfaceProps = "flesh";
+ if ( GetModelIndex() && modelinfo->GetModelType( GetModel() ) == mod_studio )
+ {
+ pSurfaceProps = Studio_GetDefaultSurfaceProps( hdr );
+ }
+ angles = vec3_angle;
+ CPhysCollide *pCollide = PhysCreateBbox( WorldAlignMins(), WorldAlignMaxs() );
+ if ( !pCollide )
+ return NULL;
+ pPhysicsObject = PhysModelCreateCustom( this, pCollide, origin, angles, pSurfaceProps );
+ }
+ else
+ {
+ pPhysicsObject = PhysModelCreateRagdoll( this, GetModelIndex(), origin, angles );
+ }
+ VPhysicsSetObject( pPhysicsObject );
+ pPhysicsObject->SetShadow( 1e4, 1e4, allowPhysicsMovement, allowPhysicsRotation );
+ pPhysicsObject->UpdateShadow( GetAbsOrigin(), GetAbsAngles(), false, 0 );
+// PhysAddShadow( this );
+ return pPhysicsObject;
+}
+
+void C_RagdollShadow::OnDataChanged( DataUpdateType_t updateType )
+{
+ BaseClass::OnDataChanged( updateType );
+
+ // Has to happen *after* the client handle is set
+ SetNextClientThink( CLIENT_THINK_ALWAYS );
+
+ bool bnewentity = (updateType == DATA_UPDATE_CREATED);
+ if ( bnewentity && ( m_nPlayer != 0 ) )
+ {
+ SetNextClientThink( CLIENT_THINK_ALWAYS );
+
+ Assert( !m_pPhysicsObject );
+
+ C_BaseEntity *pl = static_cast< C_BaseEntity * >( cl_entitylist->GetEnt( m_nPlayer ) );
+ if ( pl )
+ {
+ m_hPlayer = pl;
+ }
+
+ m_pPhysicsObject = VPhysicsInitShadow( true, false );
+ }
+
+ if ( m_pPhysicsObject )
+ {
+ // Create the spring if we don't have one yet
+ if ( !m_pSpring )
+ {
+ C_BaseTFPlayer *pl = static_cast< C_BaseTFPlayer * >( (C_BaseEntity *)m_hPlayer );
+ if ( pl && pl->VPhysicsGetObject() )
+ {
+ springparams_t spring;
+ spring.constant = 15000;
+ spring.damping = 1.0;
+ spring.naturalLength = 0.0f;
+ spring.relativeDamping = 100.0f;
+ VectorCopy( vec3_origin, spring.startPosition );
+ VectorCopy( vec3_origin, spring.endPosition );
+ spring.useLocalPositions = true;
+
+ m_pSpring = physenv->CreateSpring( m_pPhysicsObject, pl->VPhysicsGetObject(), &spring );
+
+ PhysDisableObjectCollisions( m_pPhysicsObject, pl->VPhysicsGetObject() );
+ }
+ }
+
+ m_pPhysicsObject->UpdateShadow( GetAbsOrigin(), GetAbsAngles(), false, 0 );
+ }
+
+}
+
+void C_RagdollShadow::ClientThink( void )
+{
+ BaseClass::ClientThink();
+}
+
+int C_RagdollShadow::DrawModel( int flags )
+{
+// int drawn = BaseClass::DrawModel( flags );
+// return drawn;
+ return 0;
+}
diff --git a/game/client/tf2/c_resource_chunk.cpp b/game/client/tf2/c_resource_chunk.cpp
new file mode 100644
index 0000000..ab4acf8
--- /dev/null
+++ b/game/client/tf2/c_resource_chunk.cpp
@@ -0,0 +1,22 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+#include "cbase.h"
+#include "particles_simple.h"
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+class C_ResourceChunk : public C_BaseAnimating
+{
+ DECLARE_CLASS( C_ResourceChunk, C_BaseAnimating );
+public:
+ DECLARE_CLIENTCLASS();
+};
+
+IMPLEMENT_CLIENTCLASS_DT( C_ResourceChunk, DT_ResourceChunk, CResourceChunk )
+END_RECV_TABLE()
+
diff --git a/game/client/tf2/c_shield.cpp b/game/client/tf2/c_shield.cpp
new file mode 100644
index 0000000..b404a92
--- /dev/null
+++ b/game/client/tf2/c_shield.cpp
@@ -0,0 +1,837 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Client's sheild entity
+//
+// $Workfile: $
+// $NoKeywords: $
+//=============================================================================//
+#include "cbase.h"
+#include "C_Shield.h"
+#include "clienteffectprecachesystem.h"
+#include "clientmode.h"
+#include "materialsystem/imesh.h"
+#include "mapdata.h"
+#include "ivrenderview.h"
+#include "tf_shareddefs.h"
+#include "collisionutils.h"
+#include "functionproxy.h"
+
+// Precache the effects
+CLIENTEFFECT_REGISTER_BEGIN( Shield )
+CLIENTEFFECT_MATERIAL( "shadertest/wireframevertexcolor" )
+CLIENTEFFECT_MATERIAL( "effects/shield/shield" )
+CLIENTEFFECT_MATERIAL( "effects/shieldhit" )
+CLIENTEFFECT_MATERIAL( "effects/shieldpass" )
+CLIENTEFFECT_MATERIAL( "effects/shieldpass2" )
+CLIENTEFFECT_REGISTER_END()
+
+//-----------------------------------------------------------------------------
+// Stores a list of all active shields
+//-----------------------------------------------------------------------------
+CUtlVector< C_Shield* > C_Shield::s_Shields;
+
+
+//-----------------------------------------------------------------------------
+// Various important constants:
+//-----------------------------------------------------------------------------
+
+#define SHIELD_DAMAGE_CHANGE_FIRST_PASS_TIME 0.3f
+#define SHIELD_DAMAGE_CHANGE_TRANSITION_TIME 0.5f
+#define SHIELD_DAMAGE_CHANGE_TRANSITION_START_TIME (SHIELD_DAMAGE_CHANGE_TIME - SHIELD_DAMAGE_CHANGE_TRANSITION_TIME)
+#define SHIELD_DAMAGE_CHANGE_TOTAL_TIME (SHIELD_DAMAGE_CHANGE_TRANSITION_START_TIME + SHIELD_DAMAGE_CHANGE_TRANSITION_TIME)
+#define SHIELD_TRANSITION_MAX_BLEND_AMT 0.2f
+
+
+//-----------------------------------------------------------------------------
+// Data table
+//-----------------------------------------------------------------------------
+//EXTERN_RECV_TABLE(DT_BaseEntity);
+
+IMPLEMENT_CLIENTCLASS_DT(C_Shield, DT_Shield, CShield)
+ RecvPropInt( RECVINFO(m_nOwningPlayerIndex) ),
+ RecvPropFloat( RECVINFO(m_flPowerLevel) ),
+ RecvPropInt( RECVINFO(m_bIsEMPed) ),
+END_RECV_TABLE()
+
+
+//-----------------------------------------------------------------------------
+// Shield color for the various protection types
+//-----------------------------------------------------------------------------
+static unsigned char s_ImpactDecalColor[3] = { 0, 0, 255 };
+
+
+// ----------------------------------------------------------------------------
+// Functions.
+// ----------------------------------------------------------------------------
+C_Shield::C_Shield()
+{
+ m_pWireframe.Init( "shadertest/wireframevertexcolor", TEXTURE_GROUP_OTHER );
+ m_pShield.Init( "effects/shield/shield", TEXTURE_GROUP_CLIENT_EFFECTS );
+ m_pHitDecal.Init( "effects/shieldhit", TEXTURE_GROUP_CLIENT_EFFECTS );
+ m_pPassDecal.Init( "effects/shieldpass", TEXTURE_GROUP_CLIENT_EFFECTS );
+ m_pPassDecal2.Init( "effects/shieldpass2", TEXTURE_GROUP_CLIENT_EFFECTS );
+ m_FadeValue = 1.0f;
+ m_CurveValue = 1.0f;
+ m_bCollisionsActive = true;
+
+ s_Shields.AddToTail(this);
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+C_Shield::~C_Shield()
+{
+ int i = s_Shields.Find(this);
+ if ( i >= 0 )
+ {
+ s_Shields.FastRemove(i);
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Inherited classes should call this in their constructor to indicate size...
+//-----------------------------------------------------------------------------
+void C_Shield::InitShield( int w, int h, int subdivisions )
+{
+ m_SplinePatch.Init( w, h, 2 );
+
+ m_SubdivisionCount = subdivisions;
+ Assert( m_SubdivisionCount > 1 );
+ m_InvSubdivisionCount = 1.0f / (m_SubdivisionCount - 1);
+}
+
+//-----------------------------------------------------------------------------
+// This is called after a network update
+//-----------------------------------------------------------------------------
+void C_Shield::OnDataChanged( DataUpdateType_t updateType )
+{
+ if (updateType == DATA_UPDATE_CREATED)
+ {
+ m_StartTime = engine->GetLastTimeStamp();
+ }
+
+ BaseClass::OnDataChanged( updateType );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : collisionGroup -
+// Output : Returns true on success, false on failure.
+//-----------------------------------------------------------------------------
+bool C_Shield::ShouldCollide( int collisionGroup, int contentsMask ) const
+{
+ return m_bCollisionsActive && ((collisionGroup == TFCOLLISION_GROUP_WEAPON) || (collisionGroup == TFCOLLISION_GROUP_GRENADE));
+}
+
+//-----------------------------------------------------------------------------
+// Should I draw?
+//-----------------------------------------------------------------------------
+bool C_Shield::ShouldDraw()
+{
+ // Let the client mode (like commander mode) reject drawing entities.
+ if (g_pClientMode && !g_pClientMode->ShouldDrawEntity(this) )
+ return false;
+
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// Activates/deactivates a shield for collision purposes
+//-----------------------------------------------------------------------------
+void C_Shield::ActivateCollisions( bool activate )
+{
+ m_bCollisionsActive = activate;
+}
+
+//-----------------------------------------------------------------------------
+// Activates all shields
+//-----------------------------------------------------------------------------
+void C_Shield::ActivateShields( bool activate, int team )
+{
+ for (int i = s_Shields.Count(); --i >= 0; )
+ {
+ // Activate all shields on the same team
+ if ( (team == -1) || (team == s_Shields[i]->GetTeamNumber()) )
+ {
+ s_Shields[i]->ActivateCollisions( activate );
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Helper method for collision testing
+//-----------------------------------------------------------------------------
+#pragma warning ( disable : 4701 )
+
+bool C_Shield::TestCollision( const Ray_t& ray, unsigned int mask, trace_t& trace )
+{
+ // Can't block anything if we're EMPed, or we've got no power left to block
+ if ( m_bIsEMPed )
+ return false;
+ if ( m_flPowerLevel <= 0 )
+ return false;
+
+ // Here, we're gonna test for collision.
+ // If we don't stop this kind of bullet, we'll generate an effect here
+ // but we won't change the trace to indicate a collision.
+
+ // It's just polygon soup...
+ int hitgroup;
+ bool firstTri;
+ int v1[2], v2[2], v3[2];
+ float ihit, jhit;
+ float mint = FLT_MAX;
+ float t;
+
+ int h = Height();
+ int w = Width();
+
+ for (int i = 0; i < h - 1; ++i)
+ {
+ for (int j = 0; j < w - 1; ++j)
+ {
+ // Don't test if this panel ain't active...
+ if (!IsPanelActive( j, i ))
+ continue;
+
+ // NOTE: Structure order of points so that our barycentric
+ // axes for each triangle are along the (u,v) directions of the mesh
+ // The barycentric coords we'll need below
+
+ // Two triangles per quad...
+ t = IntersectRayWithTriangle( ray,
+ GetPoint( j, i + 1 ),
+ GetPoint( j + 1, i + 1 ),
+ GetPoint( j, i ), true );
+ if ((t >= 0.0f) && (t < mint))
+ {
+ mint = t;
+ v1[0] = j; v1[1] = i + 1;
+ v2[0] = j + 1; v2[1] = i + 1;
+ v3[0] = j; v3[1] = i;
+ ihit = i; jhit = j;
+ firstTri = true;
+ }
+
+ t = IntersectRayWithTriangle( ray,
+ GetPoint( j + 1, i ),
+ GetPoint( j, i ),
+ GetPoint( j + 1, i + 1 ), true );
+ if ((t >= 0.0f) && (t < mint))
+ {
+ mint = t;
+ v1[0] = j + 1; v1[1] = i;
+ v2[0] = j; v2[1] = i;
+ v3[0] = j + 1; v3[1] = i + 1;
+ ihit = i; jhit = j;
+ firstTri = false;
+ }
+ }
+ }
+
+ if (mint == FLT_MAX)
+ return false;
+
+ // Stuff the barycentric coordinates of the triangle hit into the hit group
+ // For the first triangle, the first edge goes along u, the second edge goes
+ // along -v. For the second triangle, the first edge goes along -u,
+ // the second edge goes along v.
+ const Vector& v1vec = GetPoint(v1[0], v1[1]);
+ const Vector& v2vec = GetPoint(v2[0], v2[1]);
+ const Vector& v3vec = GetPoint(v3[0], v3[1]);
+ float u, v;
+ bool ok = ComputeIntersectionBarycentricCoordinates( ray,
+ v1vec, v2vec, v3vec, u, v );
+ Assert( ok );
+ if ( !ok )
+ {
+ return false;
+ }
+
+ if (firstTri)
+ v = 1.0 - v;
+ else
+ u = 1.0 - u;
+ v += ihit; u += jhit;
+ v /= (h - 1);
+ u /= (w - 1);
+
+ // Compress (u,v) into 1 dot 15, v in top bits
+ hitgroup = (((int)(v * (1 << 15))) << 16) + (int)(u * (1 << 15));
+
+ Vector normal;
+ float intercept;
+ ComputeTrianglePlane( v1vec, v2vec, v3vec, normal, intercept );
+
+ UTIL_SetTrace( trace, ray, this, mint, hitgroup, CONTENTS_SOLID, normal, intercept );
+ return true;
+}
+
+#pragma warning ( default : 4701 )
+
+//-----------------------------------------------------------------------------
+// Called when we hit something that we deflect...
+//-----------------------------------------------------------------------------
+void C_Shield::RegisterDeflection(const Vector& vecDir, int bitsDamageType, trace_t *ptr)
+{
+ Vector normalDir;
+ VectorCopy( vecDir, normalDir );
+ VectorNormalize( normalDir );
+
+ CreateShieldDeflection( ptr->hitgroup, normalDir, false );
+}
+
+//-----------------------------------------------------------------------------
+// This is required to get all the decals to animate correctly
+//-----------------------------------------------------------------------------
+void C_Shield::SetCurrentDecal( int idx )
+{
+ m_CurrentDecal = idx;
+}
+
+//-----------------------------------------------------------------------------
+// returns the address of a variable that stores the material animation frame
+//-----------------------------------------------------------------------------
+float C_Shield::GetTextureAnimationStartTime()
+{
+ if( m_CurrentDecal == -1 )
+ return m_StartTime;
+ return m_Decals[m_CurrentDecal].m_StartTime;
+}
+
+//-----------------------------------------------------------------------------
+// Indicates that a texture animation has wrapped
+//-----------------------------------------------------------------------------
+void C_Shield::TextureAnimationWrapped()
+{
+ if( m_CurrentDecal != -1 )
+ {
+ m_Decals[m_CurrentDecal].m_StartTime = -1.0f;
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Indicates a collision occurred:
+//-----------------------------------------------------------------------------
+void C_Shield::ReceiveMessage( int classID, bf_read &msg )
+{
+ if ( classID != GetClientClass()->m_ClassID )
+ {
+ // message is for subclass
+ BaseClass::ReceiveMessage( classID, msg );
+ return;
+ }
+
+ int hitgroup;
+ Vector dir;
+ unsigned char partialBlock;
+
+ hitgroup = msg.ReadLong( );
+ msg.ReadBitVec3Normal( dir );
+ partialBlock = msg.ReadByte( );
+
+ CreateShieldDeflection( hitgroup, dir, partialBlock );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void C_Shield::CreateShieldDeflection( int hitgroup, const Vector &dir, bool partialBlock )
+{
+ float hitU = (float)(hitgroup & 0xFFFF) / (float)(1 << 15);
+ float hitV = (float)(hitgroup >> 16) / (float)(1 << 15);
+
+ Ripple_t ripple;
+ ripple.m_RippleU = hitU;
+ ripple.m_RippleV = hitV;
+ ripple.m_Amplitude = partialBlock ? 4 : 30;
+ ripple.m_Radius = 0.08f;
+ ripple.m_StartTime = engine->GetLastTimeStamp();
+ ripple.m_Direction = dir;
+ m_Ripples.AddToTail(ripple);
+
+ Decal_t decal;
+ decal.m_RippleU = hitU;
+ decal.m_RippleV = hitV;
+ decal.m_Radius = partialBlock ? 0.03f : 0.08f;
+ decal.m_StartTime = engine->GetLastTimeStamp();
+ m_Decals.AddToTail(decal);
+}
+
+
+//-----------------------------------------------------------------------------
+// Draws the control points in wireframe
+//-----------------------------------------------------------------------------
+void C_Shield::DrawWireframeModel( Vector const** ppPositions )
+{
+ IMesh* pMesh = materials->GetDynamicMesh( true, NULL, NULL, m_pWireframe );
+
+ int numLines = (Height() - 1) * Width() + Height() * (Width() - 1);
+
+ CMeshBuilder meshBuilder;
+ meshBuilder.Begin( pMesh, MATERIAL_LINES, numLines );
+
+ Vector const* tmp;
+ for (int i = 0; i < Height(); ++i)
+ {
+ for (int j = 0; j < Width(); ++j)
+ {
+ if ( i > 0 )
+ {
+ tmp = ppPositions[j + Width() * i];
+ meshBuilder.Position3fv( tmp->Base() );
+ meshBuilder.Color4ub( 255, 255, 255, 128 );
+ meshBuilder.AdvanceVertex();
+
+ tmp = ppPositions[j + Width() * (i-1)];
+ meshBuilder.Position3fv( tmp->Base() );
+ meshBuilder.Color4ub( 255, 255, 255, 128 );
+ meshBuilder.AdvanceVertex();
+ }
+
+ if (j > 0)
+ {
+ tmp = ppPositions[j + Width() * i];
+ meshBuilder.Position3fv( tmp->Base() );
+ meshBuilder.Color4ub( 255, 255, 255, 128 );
+ meshBuilder.AdvanceVertex();
+
+ tmp = ppPositions[j - 1 + Width() * i];
+ meshBuilder.Position3fv( tmp->Base() );
+ meshBuilder.Color4ub( 255, 255, 255, 128 );
+ meshBuilder.AdvanceVertex();
+ }
+ }
+ }
+
+ meshBuilder.End();
+ pMesh->Draw();
+}
+
+//-----------------------------------------------------------------------------
+// Draws the base shield
+//-----------------------------------------------------------------------------
+#define TRANSITION_REGION_WIDTH 0.5f
+
+extern ConVar mat_wireframe;
+
+void C_Shield::DrawShieldPoints(Vector* pt, Vector* normal, float* opacity)
+{
+ SetCurrentDecal( -1 );
+
+ if (mat_wireframe.GetInt() == 0)
+ materials->Bind( m_pShield, (IClientRenderable*)this );
+ else
+ materials->Bind( m_pWireframe, (IClientRenderable*)this );
+ IMesh* pMesh = materials->GetDynamicMesh( true, NULL, NULL );
+
+ int numTriangles = (m_SubdivisionCount - 1) * (m_SubdivisionCount - 1) * 2;
+
+ CMeshBuilder meshBuilder;
+ meshBuilder.Begin( pMesh, MATERIAL_TRIANGLES, numTriangles );
+
+ float du = 1.0f * m_InvSubdivisionCount;
+ float dv = du;
+
+ unsigned char color[3];
+ color[0] = 255;
+ color[1] = 255;
+ color[2] = 255;
+
+ for ( int i = 0; i < m_SubdivisionCount - 1; ++i)
+ {
+ float v = i * dv;
+
+ for (int j = 0; j < m_SubdivisionCount - 1; ++j)
+ {
+ int idx = i * m_SubdivisionCount + j;
+ float u = j * du;
+
+ meshBuilder.Position3fv( pt[idx].Base() );
+ meshBuilder.Color4ub( color[0], color[1], color[2], opacity[idx] );
+ meshBuilder.Normal3fv( normal[idx].Base() );
+ meshBuilder.TexCoord2f( 0, u, v );
+ meshBuilder.AdvanceVertex();
+
+ meshBuilder.Position3fv( pt[idx + m_SubdivisionCount].Base() );
+ meshBuilder.Color4ub( color[0], color[1], color[2], opacity[idx+m_SubdivisionCount] );
+ meshBuilder.Normal3fv( normal[idx + m_SubdivisionCount].Base() );
+ meshBuilder.TexCoord2f( 0, u, v + dv );
+ meshBuilder.AdvanceVertex();
+
+ meshBuilder.Position3fv( pt[idx + 1].Base() );
+ meshBuilder.Color4ub( color[0], color[1], color[2], opacity[idx+1] );
+ meshBuilder.Normal3fv( normal[idx+1].Base() );
+ meshBuilder.TexCoord2f( 0, u + du, v );
+ meshBuilder.AdvanceVertex();
+
+ meshBuilder.Position3fv( pt[idx + 1].Base() );
+ meshBuilder.Color4ub( color[0], color[1], color[2], opacity[idx+1] );
+ meshBuilder.Normal3fv( normal[idx+1].Base() );
+ meshBuilder.TexCoord2f( 0, u + du, v );
+ meshBuilder.AdvanceVertex();
+
+ meshBuilder.Position3fv( pt[idx + m_SubdivisionCount].Base() );
+ meshBuilder.Color4ub( color[0], color[1], color[2], opacity[idx+m_SubdivisionCount] );
+ meshBuilder.Normal3fv( normal[idx + m_SubdivisionCount].Base() );
+ meshBuilder.TexCoord2f( 0, u, v + dv );
+ meshBuilder.AdvanceVertex();
+
+ meshBuilder.Position3fv( pt[idx + m_SubdivisionCount + 1].Base() );
+ meshBuilder.Color4ub( color[0], color[1], color[2], opacity[idx+m_SubdivisionCount+1] );
+ meshBuilder.Normal3fv( normal[idx + m_SubdivisionCount + 1].Base() );
+ meshBuilder.TexCoord2f( 0, u + du, v + dv );
+ meshBuilder.AdvanceVertex();
+ }
+ }
+
+ meshBuilder.End();
+ pMesh->Draw();
+}
+
+
+
+//-----------------------------------------------------------------------------
+// Draws shield decals
+//-----------------------------------------------------------------------------
+void C_Shield::DrawShieldDecals( Vector* pt, bool hitDecals )
+{
+ if (m_Decals.Size() == 0)
+ return;
+
+ // Compute ripples:
+ for ( int r = m_Decals.Size(); --r >= 0; )
+ {
+ // At the moment, nothing passes!
+ bool passDecal = false;
+ if ((!hitDecals) && (passDecal == hitDecals))
+ continue;
+
+ SetCurrentDecal( r );
+
+ // We have to force a flush here because we're changing the proxy state
+ if (!hitDecals)
+ materials->Bind( m_pPassDecal, (IClientRenderable*)this );
+ else
+ materials->Bind( passDecal ? m_pPassDecal2 : m_pHitDecal, (IClientRenderable*)this );
+
+ float dtime = gpGlobals->curtime - m_Decals[r].m_StartTime;
+ float decay = exp( -( 2 * dtime) );
+
+ // Retire the animation if it wraps
+ // This gets set by TextureAnimatedWrapped above
+ if ((m_Decals[r].m_StartTime < 0.0f) || (decay < 1e-3))
+ {
+ m_Decals.Remove(r);
+ continue;
+ }
+
+ IMesh* pMesh = materials->GetDynamicMesh();
+
+ // Figure out the quads we must mod2x....
+ float u0 = m_Decals[r].m_RippleU - m_Decals[r].m_Radius;
+ float u1 = m_Decals[r].m_RippleU + m_Decals[r].m_Radius;
+ float v0 = m_Decals[r].m_RippleV - m_Decals[r].m_Radius;
+ float v1 = m_Decals[r].m_RippleV + m_Decals[r].m_Radius;
+ float du = u1 - u0;
+ float dv = v1 - v0;
+
+ int i0 = Floor2Int( v0 * (m_SubdivisionCount - 1) );
+ int i1 = Ceil2Int( v1 * (m_SubdivisionCount - 1) );
+ int j0 = Floor2Int( u0 * (m_SubdivisionCount - 1) );
+ int j1 = Ceil2Int( u1 * (m_SubdivisionCount - 1) );
+ if (i0 < 0)
+ i0 = 0;
+ if (i1 >= m_SubdivisionCount)
+ i1 = m_SubdivisionCount - 1;
+ if (j0 < 0)
+ j0 = 0;
+ if (j1 >= m_SubdivisionCount)
+ j1 = m_SubdivisionCount - 1;
+
+ int numTriangles = (i1 - i0) * (j1 - j0) * 2;
+
+ CMeshBuilder meshBuilder;
+ meshBuilder.Begin( pMesh, MATERIAL_TRIANGLES, numTriangles );
+
+ float decalDu = m_InvSubdivisionCount / du;
+ float decalDv = m_InvSubdivisionCount / dv;
+
+ unsigned char color[3];
+ color[0] = s_ImpactDecalColor[0] * decay;
+ color[1] = s_ImpactDecalColor[1] * decay;
+ color[2] = s_ImpactDecalColor[2] * decay;
+
+ for ( int i = i0; i < i1; ++i)
+ {
+ float t = (float)i * m_InvSubdivisionCount;
+ for (int j = j0; j < j1; ++j)
+ {
+ float s = (float)j * m_InvSubdivisionCount;
+ int idx = i * m_SubdivisionCount + j;
+
+ // Compute (u,v) into the decal
+ float decalU = (s - u0) / du;
+ float decalV = (t - v0) / dv;
+
+ meshBuilder.Position3fv( pt[idx].Base() );
+ meshBuilder.Color3ubv( color );
+ meshBuilder.TexCoord2f( 0, decalU, decalV );
+ meshBuilder.AdvanceVertex();
+
+ meshBuilder.Position3fv( pt[idx + m_SubdivisionCount].Base() );
+ meshBuilder.Color3ubv( color );
+ meshBuilder.TexCoord2f( 0, decalU, decalV + decalDv );
+ meshBuilder.AdvanceVertex();
+
+ meshBuilder.Position3fv( pt[idx + 1].Base() );
+ meshBuilder.Color3ubv( color );
+ meshBuilder.TexCoord2f( 0, decalU + decalDu, decalV );
+ meshBuilder.AdvanceVertex();
+
+ meshBuilder.Position3fv( pt[idx + 1].Base() );
+ meshBuilder.Color3ubv( color );
+ meshBuilder.TexCoord2f( 0, decalU + decalDu, decalV );
+ meshBuilder.AdvanceVertex();
+
+ meshBuilder.Position3fv( pt[idx + m_SubdivisionCount].Base() );
+ meshBuilder.Color3ubv( color );
+ meshBuilder.TexCoord2f( 0, decalU, decalV + decalDv );
+ meshBuilder.AdvanceVertex();
+
+ meshBuilder.Position3fv( pt[idx + m_SubdivisionCount + 1].Base() );
+ meshBuilder.Color3ubv( color );
+ meshBuilder.TexCoord2f( 0, decalU + decalDu, decalV + decalDv );
+ meshBuilder.AdvanceVertex();
+ }
+ }
+
+ meshBuilder.End();
+ pMesh->Draw();
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Computes a single point
+//-----------------------------------------------------------------------------
+void C_Shield::ComputePoint( float s, float t, Vector& pt, Vector& normal, float& opacity )
+{
+ // Precache some computations for the point on the spline at (s, t).
+ m_SplinePatch.SetupPatchQuery( s, t );
+
+ // Get the position + normal
+ m_SplinePatch.GetPointAndNormal( pt, normal );
+
+ // From here on down is all futzing with opacity
+
+ // Check neighbors for activity...
+ bool active = IsPanelActive(m_SplinePatch.m_is, m_SplinePatch.m_it);
+ if (m_SplinePatch.m_fs == 0.0f)
+ active = active || IsPanelActive(m_SplinePatch.m_is - 1, m_SplinePatch.m_it);
+ if (m_SplinePatch.m_ft == 0.0f)
+ active = active || IsPanelActive(m_SplinePatch.m_is, m_SplinePatch.m_it - 1);
+
+ if (!active)
+ {
+ // If the panel's not active, it's transparent.
+ opacity = 0.0f;
+ }
+ else
+ {
+ if ((s == 0.0f) || (t == 0.0f) ||
+ (s == (Width() - 1.0f)) || (t == (Height() - 1.0f)) )
+ {
+ // If it's on the edge, it's max opacity
+ opacity = 192.0f;
+ }
+ else
+ {
+ // Channel zero is the opacity data
+ opacity = m_SplinePatch.GetChannel( 0 );
+
+ // Make the shield translucent if the owner is the local player...
+ // Also don't mess with the edges..
+ if (m_ShieldOwnedByLocalPlayer)
+ {
+ // Channel 1 is the opacity blend
+ float blendFactor = m_SplinePatch.GetChannel( 1 );
+ blendFactor = clamp( blendFactor, 0.0f, 1.0f );
+
+ float blendValue = 1.0f;
+ Vector delta;
+ VectorSubtract( pt, GetAbsOrigin(), delta );
+ float dist = VectorLength( delta );
+ if (dist != 0.0f)
+ {
+ delta *= 1.0f / dist;
+ float dot = DotProduct( m_ViewDir, delta );
+ float angle = acos( dot );
+ float fov = M_PI * render->GetFieldOfView() / 180.0f;
+ if (angle < fov * .2f)
+ blendValue = 0.1f;
+ else if (angle < fov * 0.4f)
+ {
+ // Want a cos falloff between .2 and .4
+ // 0.1 at .2 and 1.0 at .4
+ angle -= fov * 0.2f;
+ blendValue = 1.0f - 0.9f * 0.5f * (cos ( M_PI * angle / (fov * 0.2f) ) + 1.0f);
+ }
+ }
+
+ // Interpolate between 1 and the blend value based on the blend factor...
+ opacity *= (1.0f - blendFactor) + blendFactor * blendValue;
+ }
+
+ opacity = clamp( opacity, 0.0f, 192.0f );
+ }
+ }
+ opacity *= m_FadeValue;
+}
+
+
+//-----------------------------------------------------------------------------
+// Compute the shield points using catmull-rom
+//-----------------------------------------------------------------------------
+void C_Shield::ComputeShieldPoints( Vector* pt, Vector* normal, float* opacity )
+{
+ int i;
+ for ( i = 0; i < m_SubdivisionCount; ++i)
+ {
+ float t = (Height() - 1) * (float)i * m_InvSubdivisionCount;
+ for (int j = 0; j < m_SubdivisionCount; ++j)
+ {
+ float s = (Width() - 1) * (float)j * m_InvSubdivisionCount;
+ int idx = i * m_SubdivisionCount + j;
+
+ ComputePoint( s, t, pt[idx], normal[idx], opacity[idx] );
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Compute the shield ripples from being hit
+//-----------------------------------------------------------------------------
+void C_Shield::RippleShieldPoints( Vector* pt, float* opacity )
+{
+ // Compute ripples:
+ for ( int r = m_Ripples.Size(); --r >= 0; )
+ {
+ float dtime = gpGlobals->curtime - m_Ripples[r].m_StartTime;
+ float decay = exp( -( 2 * dtime) );
+ float amplitude = m_Ripples[r].m_Amplitude * decay;
+
+ for ( int i = 0; i < m_SubdivisionCount; ++i)
+ {
+ float t = i * m_InvSubdivisionCount;
+ for (int j = 0; j < m_SubdivisionCount; ++j)
+ {
+ float s = j * m_InvSubdivisionCount;
+ int idx = i * m_SubdivisionCount + j;
+
+ float ds = s - m_Ripples[r].m_RippleU;
+ float dt = t - m_Ripples[r].m_RippleV;
+ float dr = sqrt( ds * ds + dt * dt );
+ if (dr < m_Ripples[r].m_Radius)
+ {
+ // need to apply ripple
+ float diff = amplitude * cos( 0.5f * M_PI * dr / m_Ripples[r].m_Radius );
+ VectorMA( pt[idx], diff, m_Ripples[r].m_Direction, pt[idx] );
+
+ // Compute opacity at this point...
+ float impactopacity = 192.0f * decay * dr / m_Ripples[r].m_Radius;
+ if (impactopacity > opacity[idx])
+ opacity[idx] = impactopacity;
+ }
+ }
+ }
+
+ if (amplitude < 0.1)
+ m_Ripples.Remove(r);
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Main draw entry point
+//-----------------------------------------------------------------------------
+int C_Shield::DrawModel( int flags )
+{
+ if ( !m_bReadyToDraw )
+ return 0;
+
+ if (m_FadeValue == 0.0f)
+ return 1;
+
+ // If I have no power, don't draw
+ if ( m_flPowerLevel <= 0 )
+ return 1;
+
+ // Make it curvy or not!!
+ m_SplinePatch.SetLinearBlend( m_CurveValue );
+
+ // Set up the patch with all the data it's going to need
+ int count = Width() * Height();
+ Vector const** pControlPoints = (Vector const**)stackalloc(count * sizeof(Vector*));
+ float* pControlOpacity = (float*)stackalloc(count * sizeof(float));
+ float* pControlBlend = (float*)stackalloc(count * sizeof(float));
+
+ GetShieldData( pControlPoints, pControlOpacity, pControlBlend );
+ m_SplinePatch.SetControlPositions( pControlPoints );
+ m_SplinePatch.SetChannelData( 0, pControlOpacity );
+ m_SplinePatch.SetChannelData( 1, pControlBlend );
+
+// DrawWireframeModel( pControlPoints );
+
+ // Allocate space for temporary data
+ int numSubdivisions = m_SubdivisionCount * m_SubdivisionCount;
+ Vector* pt = (Vector*)stackalloc(numSubdivisions * sizeof(Vector));
+ Vector* normal = (Vector*)stackalloc(numSubdivisions * sizeof(Vector));
+ float* opacity = (float*)stackalloc(numSubdivisions * sizeof(float));
+
+ // Do something a little special if this shield is owned by the local player
+ C_BasePlayer *player = C_BasePlayer::GetLocalPlayer();
+ m_ShieldOwnedByLocalPlayer = (player->entindex() == m_nOwningPlayerIndex);
+ if (m_ShieldOwnedByLocalPlayer)
+ {
+ QAngle viewAngles;
+ engine->GetViewAngles(viewAngles);
+ AngleVectors( viewAngles, &m_ViewDir );
+ }
+
+ ComputeShieldPoints( pt, normal, opacity );
+ RippleShieldPoints( pt, opacity );
+
+ // Commented out because it causes things to not be drawn behind it
+// DrawShieldDecals( pt, false );
+
+ DrawShieldPoints( pt, normal, opacity );
+ DrawShieldDecals( pt, true );
+
+ return 1;
+}
+
+
+
+//============================================================================================================
+// SHIELD POWERLEVEL PROXY
+//============================================================================================================
+class CShieldPowerLevelProxy : public CResultProxy
+{
+public:
+ void OnBind( void *pC_BaseEntity );
+};
+
+void CShieldPowerLevelProxy::OnBind( void *pRenderable )
+{
+ IClientRenderable *pRend = (IClientRenderable *)pRenderable;
+ C_BaseEntity *pEntity = pRend->GetIClientUnknown()->GetBaseEntity();
+ C_Shield *pShield = dynamic_cast<C_Shield*>(pEntity);
+ if (!pShield)
+ return;
+
+ SetFloatResult( pShield->GetPowerLevel() );
+}
+
+EXPOSE_INTERFACE( CShieldPowerLevelProxy, IMaterialProxy, "ShieldPowerLevel" IMATERIAL_PROXY_INTERFACE_VERSION );
diff --git a/game/client/tf2/c_shield.h b/game/client/tf2/c_shield.h
new file mode 100644
index 0000000..2b92cb1
--- /dev/null
+++ b/game/client/tf2/c_shield.h
@@ -0,0 +1,199 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Client's sheild entity
+//
+// $Workfile: $
+// $Date: $
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef C_SHIELD_H
+#define C_SHIELD_H
+
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "SplinePatch.h"
+
+//-----------------------------------------------------------------------------
+// Shield:
+//-----------------------------------------------------------------------------
+class C_Shield : public C_BaseEntity
+{
+public:
+ DECLARE_CLASS( C_Shield, C_BaseEntity );
+ DECLARE_CLIENTCLASS();
+
+ // constructor, destructor
+ C_Shield();
+ ~C_Shield();
+
+ // Inherited classes should call this in their constructor to indicate size...
+ void InitShield( int w, int h, int subdivisions );
+
+ void OnDataChanged( DataUpdateType_t updateType );
+ int DrawModel( int flags );
+ void ReceiveMessage( int classID, bf_read &msg );
+
+ void CreateShieldDeflection( int hitgroup, const Vector &dir, bool partialBlock );
+
+ virtual bool ShouldDraw();
+ virtual bool IsTransparent() { return true; }
+ virtual void SetAlwaysOrient( bool bOrient ) {}
+ virtual bool IsAlwaysOrienting( ) { return false; }
+ virtual void SetCenterAngles( const QAngle & ) {}
+ virtual void SetAttachmentIndex( int nAttachmentIndex ) {}
+
+ // returns the address of a variable that stores the material animation frame
+ float GetTextureAnimationStartTime();
+
+ // Indicates that a texture animation has wrapped
+ void TextureAnimationWrapped();
+
+ virtual bool ShouldCollide( int collisionGroup, int contentsMask ) const;
+
+ // Collision detection
+ // Activates/deactivates a shield for collision purposes
+ void ActivateCollisions( bool activate );
+
+ // Deactivates all shields of players on a particular team
+ // If you don't specify a team, it'll affect all shields
+ static void ActivateShields( bool activate, int team = -1 );
+ virtual const Vector& GetPoint( int x, int y ) { return vec3_origin; }
+
+ // For collision testing
+ bool TestCollision( const Ray_t& ray, unsigned int mask, trace_t& trace );
+
+ // Called when we hit something that we deflect...
+ void RegisterDeflection(const Vector& vecDir, int bitsDamageType, trace_t *ptr);
+
+ float GetPowerLevel( void ) { return m_flPowerLevel; }
+
+ bool IsEMPed() const;
+ void SetEMPed( bool bIsEmped );
+
+protected:
+ //
+ // Inheriting classes must implement these methods!!!
+ //
+
+ // Return true if the panel is active
+ virtual bool IsPanelActive( int x, int y ) { assert(0); return false; }
+
+ // Gets at the control point data; who knows how it was made?
+ virtual void GetShieldData( Vector const** ppVerts, float* pOpacity, float* pBlend ) { assert(0); }
+
+private:
+ void DrawWireframeModel( Vector const** pPositions );
+ void ComputePoint( float s, float t, Vector& pt, Vector& normal, float& opacity );
+ void ComputeShieldPoints( Vector* pt, Vector* normal, float* opacity );
+ void RippleShieldPoints( Vector* pt, float* opacity );
+ void DrawShieldPoints(Vector* pt, Vector* normal, float* opacity);
+ void DrawShieldDecals(Vector* pt, bool hitDecals );
+ void SetCurrentDecal( int idx );
+
+ int Width() const;
+ int Height() const;
+
+protected:
+ // Used to fade out the shield
+ float m_FadeValue;
+
+ // Used to make the shield more or less curvy
+ float m_CurveValue;
+
+private:
+ // no copy constructor
+ C_Shield( const C_Shield& );
+
+ // Data needs to ripple the shield control points
+ struct Ripple_t
+ {
+ float m_RippleU;
+ float m_RippleV;
+ float m_Amplitude;
+ float m_Radius;
+ float m_StartTime;
+ Vector m_Direction;
+ };
+
+ struct Decal_t
+ {
+ float m_RippleU;
+ float m_RippleV;
+ float m_Radius;
+ float m_StartTime;
+ };
+
+ // Owner entity
+ int m_nOwningPlayerIndex;
+
+ // number of subdivisions
+ int m_SubdivisionCount;
+ float m_InvSubdivisionCount;
+
+ // Shield powerlevel
+ float m_flPowerLevel;
+
+ // Texture animation
+ float m_StartTime;
+
+ bool m_bCollisionsActive;
+ bool m_bIsEMPed;
+
+ // Used to do spline queries
+ CSplinePatch m_SplinePatch;
+
+ // List of all ripples + decals
+ int m_CurrentDecal;
+ CUtlVector< Ripple_t > m_Ripples;
+ CUtlVector< Decal_t > m_Decals;
+
+ // All the various materials we use
+ CMaterialReference m_pWireframe;
+ CMaterialReference m_pShield;
+ CMaterialReference m_pHitDecal;
+ CMaterialReference m_pPassDecal;
+ CMaterialReference m_pPassDecal2;
+
+ // A little state used only during rendering, but I didn't want
+ // to pass these as arguments to a bunch of functions
+ bool m_ShieldOwnedByLocalPlayer;
+ Vector m_ViewDir;
+
+ // List of all active shields
+ static CUtlVector< C_Shield* > s_Shields;
+};
+
+
+//-----------------------------------------------------------------------------
+// Inline methods
+//-----------------------------------------------------------------------------
+inline int C_Shield::Width() const
+{
+ return m_SplinePatch.Width();
+}
+
+inline int C_Shield::Height() const
+{
+ return m_SplinePatch.Height();
+}
+
+inline bool C_Shield::IsEMPed() const
+{
+ return m_bIsEMPed;
+}
+
+inline void C_Shield::SetEMPed( bool bIsEmped )
+{
+ m_bIsEMPed = bIsEmped;
+}
+
+
+//-----------------------------------------------------------------------------
+// Class factory methods to create the various versions of the shield
+//-----------------------------------------------------------------------------
+C_Shield* CreateMobileShield( C_BaseEntity *owner, float flFrontDistance = 0 );
+
+#endif // C_SHIELD_H \ No newline at end of file
diff --git a/game/client/tf2/c_shield_flat.cpp b/game/client/tf2/c_shield_flat.cpp
new file mode 100644
index 0000000..0d8316c
--- /dev/null
+++ b/game/client/tf2/c_shield_flat.cpp
@@ -0,0 +1,350 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Client's sheild entity
+//
+// $Workfile: $
+// $Date: $
+// $NoKeywords: $
+//=============================================================================//
+#include "cbase.h"
+#include "C_Shield.h"
+#include "tf_shieldshared.h"
+#include "c_basetfplayer.h"
+
+enum
+{
+ NUM_SUBDIVISIONS = 21,
+};
+
+#define EMP_WAVE_AMPLITUDE 6.0f
+#define EMP_GROW_WIDTH_DELAY 0.2f
+#define EMP_GROW_TIME 0.6f
+#define EMP_GROW_ATTEN 0.5f
+#define EMP_MIN_WIDTH 5.0f
+
+//-----------------------------------------------------------------------------
+// Flat version of the shield
+//-----------------------------------------------------------------------------
+
+class C_ShieldFlat : public C_Shield
+{
+public:
+ DECLARE_CLASS( C_ShieldFlat, C_Shield );
+ DECLARE_CLIENTCLASS();
+
+ C_ShieldFlat();
+ ~C_ShieldFlat();
+
+ virtual void GetBounds( Vector& mins, Vector& maxs );
+
+ virtual void AddEntity( );
+
+ virtual void SetDormant( bool bDormant );
+
+ // Return true if the panel is active
+ virtual bool IsPanelActive( int x, int y );
+
+ // Gets at the control point data; who knows how it was made?
+ virtual void GetShieldData( Vector const** ppVerts, float* pOpacity, float* pBlend );
+ virtual const Vector& GetPoint( int x, int y );
+
+ // Draws the model
+ virtual int DrawModel( int flags );
+
+public:
+ // networked data
+ unsigned char m_ShieldState;
+ float m_Width;
+ float m_Height;
+
+ float m_DeathFade;
+ float m_EMPFade;
+
+private:
+ void ShieldMoved( void );
+
+private:
+ C_ShieldFlat( const C_ShieldFlat& );
+ void ComputeEMPFade();
+ void ComputeDeathFade();
+ void ComputeSize( float& w, float& h );
+ void PreRender( );
+
+ Vector m_pPositions[4];
+ Vector m_Forward;
+ float m_EnterPVSTime;
+
+ QAngle m_LastAngles;
+ Vector m_LastPosition;
+ Vector m_Pos[4];
+};
+
+
+//-----------------------------------------------------------------------------
+// Data table
+//-----------------------------------------------------------------------------
+
+IMPLEMENT_CLIENTCLASS_DT(C_ShieldFlat, DT_Shield_Flat, CShieldFlat)
+
+ RecvPropInt( RECVINFO(m_ShieldState) ),
+ RecvPropFloat( RECVINFO(m_Width) ),
+ RecvPropFloat( RECVINFO(m_Height) ),
+
+END_RECV_TABLE()
+
+
+//-----------------------------------------------------------------------------
+// Constructor, destructor
+//-----------------------------------------------------------------------------
+
+C_ShieldFlat::C_ShieldFlat()
+{
+ m_DeathFade = 1.0f;
+ m_EMPFade = 1.0f;
+
+ InitShield( 2, 2, 6 );
+}
+
+C_ShieldFlat::~C_ShieldFlat()
+{
+}
+
+//-----------------------------------------------------------------------------
+// Leaving/entering the PVS on the server.
+//-----------------------------------------------------------------------------
+
+void C_ShieldFlat::SetDormant( bool bDormant )
+{
+ if (!bDormant)
+ {
+ if (m_ShieldState & SHIELD_FLAT_EMP)
+ {
+ m_EMPFade = 0.0f;
+ }
+ else
+ {
+ m_EMPFade = 1.0f;
+ }
+
+ m_EnterPVSTime = 0.0f;
+ if (m_ShieldState & SHIELD_FLAT_INACTIVE)
+ {
+ m_DeathFade = 0.0f;
+ }
+ else
+ {
+ m_EnterPVSTime = gpGlobals->curtime;
+ m_DeathFade = 1.0f;
+ }
+ }
+
+ BaseClass::SetDormant(bDormant);
+}
+
+//-----------------------------------------------------------------------------
+// Figures the EMP fade factor
+//-----------------------------------------------------------------------------
+
+void C_ShieldFlat::ComputeEMPFade()
+{
+ if (m_ShieldState & SHIELD_FLAT_EMP)
+ {
+ // Decay fade if we've been EMPed or if we're inactive
+ if (m_EMPFade > 0.0f)
+ {
+ m_EMPFade -= gpGlobals->frametime / SHIELD_EMP_FADE_TIME;
+ if (m_EMPFade < 0.0f)
+ {
+ m_EMPFade = 0.0f;
+ }
+ else
+ {
+ Vector dir;
+
+ // Futz with the control points if we've been EMPed
+ for (int i = 0; i < 4; ++i)
+ {
+ float dist = -EMP_WAVE_AMPLITUDE * sin( i * M_PI * 0.5f + gpGlobals->curtime * M_PI / SHIELD_EMP_WOBBLE_TIME );
+ VectorMA( m_pPositions[i], dist, m_Forward, m_pPositions[i] );
+ }
+ }
+ }
+ }
+ else
+ {
+ // Fade back in, no longer EMPed
+ if (m_EMPFade < 1.0f)
+ {
+ m_EMPFade += gpGlobals->frametime / SHIELD_EMP_FADE_TIME;
+ if (m_EMPFade >= 1.0f)
+ {
+ m_EMPFade = 1.0f;
+ }
+ }
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Figures the networked fade factor
+//-----------------------------------------------------------------------------
+
+void C_ShieldFlat::ComputeDeathFade()
+{
+ if (m_ShieldState & SHIELD_FLAT_INACTIVE)
+ {
+ // Fade out when we become inactive
+ if (m_DeathFade > 0.0f)
+ {
+ m_DeathFade -= gpGlobals->frametime / SHIELD_FLAT_SHUTDOWN_TIME;
+ if (m_DeathFade < 0.0f)
+ {
+ m_DeathFade = 0.0f;
+ }
+ }
+ }
+ else
+ {
+ // Active? We should be visible
+ m_DeathFade = 1.0f;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// A little pre-render processing
+//-----------------------------------------------------------------------------
+
+void C_ShieldFlat::ComputeSize( float& w, float& h )
+{
+ w = m_Width;
+ h = m_Height;
+
+ float dt = gpGlobals->curtime - m_EnterPVSTime;
+ if (dt > EMP_GROW_TIME)
+ {
+ return;
+ }
+
+ if (dt < 0)
+ dt = 0.0f;
+
+ // Attenuate it up
+ w *= 1.0f - pow ( EMP_GROW_ATTEN, 10 * (dt / EMP_GROW_TIME ));
+
+ if (w < EMP_MIN_WIDTH)
+ w = EMP_MIN_WIDTH;
+}
+
+//-----------------------------------------------------------------------------
+// A little pre-render processing
+//-----------------------------------------------------------------------------
+
+void C_ShieldFlat::PreRender( )
+{
+ // Compute the shield positions...
+ Vector right, up;
+ AngleVectors( GetRenderAngles(), &m_Forward, &right, &up );
+
+ float w, h;
+ ComputeSize( w, h );
+
+ VectorMA( GetRenderOrigin(), -w * 0.5, right, m_pPositions[0] );
+ VectorMA( m_pPositions[0], -h * 0.5, up, m_pPositions[0] );
+ VectorMA( m_pPositions[0], w, right, m_pPositions[1] );
+ VectorMA( m_pPositions[0], h, up, m_pPositions[2] );
+ VectorMA( m_pPositions[2], w, right, m_pPositions[3] );
+
+ ComputeEMPFade();
+ ComputeDeathFade();
+
+ m_FadeValue = m_DeathFade * m_EMPFade;
+}
+
+void C_ShieldFlat::AddEntity( )
+{
+ BaseClass::AddEntity( );
+ PreRender();
+}
+
+//-----------------------------------------------------------------------------
+// Bounds computation
+//-----------------------------------------------------------------------------
+
+void C_ShieldFlat::GetBounds( Vector& mins, Vector& maxs )
+{
+ mins.Init( -1.0/16.0f, -m_Width * 0.5f, -m_Height * 0.5f );
+ maxs.Init( 1.0/16.0f, m_Width * 0.5f, m_Height * 0.5f );
+}
+
+//-----------------------------------------------------------------------------
+// Return true if the panel is active
+//-----------------------------------------------------------------------------
+
+bool C_ShieldFlat::IsPanelActive( int x, int y )
+{
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// Gets at the control point data; who knows how it was made?
+//-----------------------------------------------------------------------------
+
+void C_ShieldFlat::GetShieldData( Vector const** ppVerts, float* pOpacity, float* pBlend )
+{
+ for ( int i = 0; i < 4; ++i )
+ {
+ ppVerts[i] = &m_pPositions[i];
+ pOpacity[i] = 32.0f;
+ pBlend[i] = 0.0f;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Shield points
+//-----------------------------------------------------------------------------
+const Vector& C_ShieldFlat::GetPoint( int x, int y )
+{
+ if ((m_LastAngles != GetAbsAngles()) || (m_LastPosition != GetAbsOrigin() ))
+ {
+ ShieldMoved();
+ }
+
+ int i = (x >= 1);
+ i += (y >= 1) * 2;
+ return m_Pos[i];
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Computes the shield bounding box
+//-----------------------------------------------------------------------------
+void C_ShieldFlat::ShieldMoved( void )
+{
+ Vector forward, right, up;
+ AngleVectors( GetAbsAngles(), &forward, &right, &up );
+
+ VectorMA( GetAbsOrigin(), -m_Width * 0.5, right, m_Pos[0] );
+ VectorMA( m_Pos[0], -m_Height * 0.5, up, m_Pos[0] );
+ VectorMA( m_Pos[0], m_Width, right, m_Pos[1] );
+ VectorMA( m_Pos[0], m_Height, up, m_Pos[2] );
+ VectorMA( m_Pos[2], m_Width, right, m_Pos[3] );
+
+ m_LastAngles = GetAbsAngles();
+ m_LastPosition = GetAbsOrigin();
+}
+
+//-----------------------------------------------------------------------------
+// Suppress rendering if the player owns it
+//-----------------------------------------------------------------------------
+
+int C_ShieldFlat::DrawModel( int flags )
+{
+ if ( !m_bReadyToDraw )
+ return 0;
+
+ // Don't draw it if the owner is the local player
+// if ( m_OwnerEntity == C_BasePlayer::GetLocalPlayer()->index )
+// return 0;
+
+ return BaseClass::DrawModel( flags );
+}
+
diff --git a/game/client/tf2/c_shield_mobile.cpp b/game/client/tf2/c_shield_mobile.cpp
new file mode 100644
index 0000000..1de8592
--- /dev/null
+++ b/game/client/tf2/c_shield_mobile.cpp
@@ -0,0 +1,274 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Client's sheild entity
+//
+// $Workfile: $
+// $NoKeywords: $
+//=============================================================================//
+#include "cbase.h"
+#include "C_Shield.h"
+#include "tf_shieldshared.h"
+
+enum
+{
+ NUM_SUBDIVISIONS = 21,
+};
+
+#define EMP_WAVE_AMPLITUDE 8.0f
+
+//-----------------------------------------------------------------------------
+// Mobile version of the shield
+//-----------------------------------------------------------------------------
+
+class C_ShieldMobile;
+class C_ShieldMobileActiveVertList : public IActiveVertList
+{
+public:
+ void Init( C_ShieldMobile *pShield, unsigned char *pVertList );
+
+// IActiveVertList overrides.
+public:
+
+ virtual int GetActiveVertState( int iVert );
+ virtual void SetActiveVertState( int iVert, int bOn );
+
+private:
+ C_ShieldMobile *m_pShield;
+ unsigned char *m_pVertsActive;
+};
+
+
+class C_ShieldMobile : public C_Shield
+{
+ DECLARE_CLASS( C_ShieldMobile, C_Shield );
+public:
+ DECLARE_CLIENTCLASS();
+
+ C_ShieldMobile();
+ ~C_ShieldMobile();
+
+ void OnDataChanged( DataUpdateType_t updateType );
+ virtual void GetBounds( Vector& mins, Vector& maxs );
+
+ virtual void AddEntity( );
+
+ // Return true if the panel is active
+ virtual bool IsPanelActive( int x, int y );
+
+ // Gets at the control point data; who knows how it was made?
+ virtual void GetShieldData( Vector const** ppVerts, float* pOpacity, float* pBlend );
+ virtual const Vector& GetPoint( int x, int y ) { return m_ShieldEffect.GetPoint( x, y ); }
+
+ virtual void SetThetaPhi( float flTheta, float flPhi ) { m_ShieldEffect.SetThetaPhi(flTheta,flPhi); }
+
+public:
+ // networked data
+ unsigned char m_pVertsActive[SHIELD_VERTEX_BYTES];
+ unsigned char m_ShieldState;
+
+private:
+ C_ShieldMobile( const C_ShieldMobile& );
+
+ // Is a particular panel an edge?
+ bool IsVertexValid( float s, float t ) const;
+ void PreRender( );
+
+private:
+ CShieldEffect m_ShieldEffect;
+ C_ShieldMobileActiveVertList m_VertList;
+ float m_flTheta;
+ float m_flPhi;
+};
+
+
+//-----------------------------------------------------------------------------
+// C_ShieldMobileActiveVertList functions
+//-----------------------------------------------------------------------------
+
+void C_ShieldMobileActiveVertList::Init( C_ShieldMobile *pShield, unsigned char *pVertList )
+{
+ m_pShield = pShield;
+ m_pVertsActive = pVertList;
+}
+
+
+int C_ShieldMobileActiveVertList::GetActiveVertState( int iVert )
+{
+ return m_pVertsActive[iVert>>3] & (1 << (iVert & 7));
+}
+
+
+void C_ShieldMobileActiveVertList::SetActiveVertState( int iVert, int bOn )
+{
+ if ( bOn )
+ m_pVertsActive[iVert>>3] |= (1 << (iVert & 7));
+ else
+ m_pVertsActive[iVert>>3] &= ~(1 << (iVert & 7));
+}
+
+
+//-----------------------------------------------------------------------------
+// Data table
+//-----------------------------------------------------------------------------
+
+IMPLEMENT_CLIENTCLASS_DT(C_ShieldMobile, DT_Shield_Mobile, CShieldMobile)
+
+ RecvPropInt( RECVINFO(m_ShieldState) ),
+ RecvPropArray(
+ RecvPropInt( RECVINFO(m_pVertsActive[0])),
+ m_pVertsActive
+ ),
+ RecvPropFloat( RECVINFO(m_flTheta) ),
+ RecvPropFloat( RECVINFO(m_flPhi) ),
+
+END_RECV_TABLE()
+
+
+//-----------------------------------------------------------------------------
+// Various raycasting routines
+//-----------------------------------------------------------------------------
+
+
+void ShieldTraceLine(const Vector &vecStart, const Vector &vecEnd,
+ unsigned int mask, int collisionGroup, trace_t *ptr)
+{
+ UTIL_TraceLine(vecStart, vecEnd, mask, NULL, collisionGroup, ptr );
+}
+
+void ShieldTraceHull(const Vector &vecStart, const Vector &vecEnd,
+ const Vector &hullMin, const Vector &hullMax,
+ unsigned int mask, int collisionGroup, trace_t *ptr)
+{
+ CTraceFilterWorldOnly traceFilter;
+ enginetrace->TraceHull( vecStart, vecEnd, hullMin, hullMax, mask, &traceFilter, ptr );
+}
+
+
+//-----------------------------------------------------------------------------
+// Constructor, destructor
+//-----------------------------------------------------------------------------
+
+C_ShieldMobile::C_ShieldMobile() : m_ShieldEffect(ShieldTraceLine, ShieldTraceHull)
+{
+ m_VertList.Init( this, m_pVertsActive );
+ m_ShieldEffect.SetActiveVertexList( &m_VertList );
+ m_ShieldEffect.Spawn(vec3_origin, vec3_angle);
+ InitShield( SHIELD_NUM_HORIZONTAL_POINTS, SHIELD_NUM_VERTICAL_POINTS, NUM_SUBDIVISIONS );
+}
+
+C_ShieldMobile::~C_ShieldMobile()
+{
+}
+
+//-----------------------------------------------------------------------------
+// Get this after the data changes
+//-----------------------------------------------------------------------------
+
+void C_ShieldMobile::OnDataChanged( DataUpdateType_t updateType )
+{
+ BaseClass::OnDataChanged( updateType );
+
+ m_ShieldEffect.SetCurrentPosition( GetAbsOrigin() );
+ m_ShieldEffect.SetCurrentAngles( GetAbsAngles() );
+ m_ShieldEffect.SetThetaPhi( m_flTheta, m_flPhi );
+
+ // No need to simulate, just compute active panels from network data
+ m_ShieldEffect.ComputeControlPoints();
+ m_ShieldEffect.ComputePanelActivity();
+}
+
+//-----------------------------------------------------------------------------
+// A little pre-render processing
+//-----------------------------------------------------------------------------
+
+void C_ShieldMobile::PreRender( )
+{
+ if (m_ShieldState & SHIELD_MOBILE_EMP)
+ {
+ // Decay fade if we've been EMPed or if we're inactive
+ if (m_FadeValue > 0.0f)
+ {
+ m_FadeValue -= gpGlobals->frametime / SHIELD_EMP_FADE_TIME;
+ if (m_FadeValue < 0.0f)
+ {
+ m_FadeValue = 0.0f;
+
+ // Reset the shield to un-wobbled state
+ m_ShieldEffect.ComputeControlPoints();
+ }
+ else
+ {
+ Vector dir;
+ AngleVectors( m_ShieldEffect.GetCurrentAngles(), & dir );
+
+ // Futz with the control points if we've been EMPed
+ for (int i = 0; i < SHIELD_NUM_CONTROL_POINTS; ++i)
+ {
+ // Get the direction for the point
+ float factor = -EMP_WAVE_AMPLITUDE * sin( i * M_PI * 0.5f + gpGlobals->curtime * M_PI / SHIELD_EMP_WOBBLE_TIME );
+ m_ShieldEffect.GetPoint(i) += dir * factor;
+ }
+ }
+ }
+ }
+ else
+ {
+ // Fade back in, no longer EMPed
+ if (m_FadeValue < 1.0f)
+ {
+ m_FadeValue += gpGlobals->frametime / SHIELD_EMP_FADE_TIME;
+ if (m_FadeValue >= 1.0f)
+ {
+ m_FadeValue = 1.0f;
+ }
+ }
+ }
+}
+
+void C_ShieldMobile::AddEntity( )
+{
+ BaseClass::AddEntity( );
+ PreRender();
+}
+
+//-----------------------------------------------------------------------------
+// Bounds computation
+//-----------------------------------------------------------------------------
+
+void C_ShieldMobile::GetBounds( Vector& mins, Vector& maxs )
+{
+ m_ShieldEffect.ComputeBounds( mins, maxs );
+}
+
+//-----------------------------------------------------------------------------
+// Return true if the panel is active
+//-----------------------------------------------------------------------------
+
+bool C_ShieldMobile::IsPanelActive( int x, int y )
+{
+ return m_ShieldEffect.IsPanelActive(x, y);
+}
+
+//-----------------------------------------------------------------------------
+// Gets at the control point data; who knows how it was made?
+//-----------------------------------------------------------------------------
+
+void C_ShieldMobile::GetShieldData( Vector const** ppVerts, float* pOpacity, float* pBlend )
+{
+ for ( int i = 0; i < SHIELD_NUM_CONTROL_POINTS; ++i )
+ {
+ ppVerts[i] = &m_ShieldEffect.GetControlPoint(i);
+
+ if ( m_pVertsActive[i >> 3] & (1 << (i & 0x7)) )
+ {
+ pOpacity[i] = m_ShieldEffect.ComputeOpacity( *ppVerts[i], GetAbsOrigin() );
+ pBlend[i] = 1.0f;
+ }
+ else
+ {
+ pOpacity[i] = 192.0f;
+ pBlend[i] = 0.0f;
+ }
+ }
+}
+
diff --git a/game/client/tf2/c_tf2rootpanel.cpp b/game/client/tf2/c_tf2rootpanel.cpp
new file mode 100644
index 0000000..7e01f6f
--- /dev/null
+++ b/game/client/tf2/c_tf2rootpanel.cpp
@@ -0,0 +1,194 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#include "cbase.h"
+#include "c_tf2rootpanel.h"
+#include <vgui_controls/Controls.h>
+#include <vgui/IVGui.h>
+#include "paneleffect.h"
+#include "itfhintitem.h"
+#include "clientmode_commander.h"
+#include "commanderoverlaypanel.h"
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *parent -
+//-----------------------------------------------------------------------------
+C_TF2RootPanel::C_TF2RootPanel( vgui::VPANEL parent )
+ : BaseClass( NULL, "TF2 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_TF2RootPanel::~C_TF2RootPanel( void )
+{
+ ClearAllEffects();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void C_TF2RootPanel::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_TF2RootPanel::RenderPanelEffects( void )
+{
+ for ( int i = 0; i < m_Effects.Size(); i++ )
+ {
+ CPanelEffect *e = m_Effects[ i ];
+ Assert( e );
+ ITFHintItem *owner = e->GetOwner();
+ if ( owner && !owner->ShouldRenderPanelEffects() )
+ continue;
+ if ( e->GetVisible() )
+ {
+ e->doPaint( this );
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Add effect to list
+// Input : *effect -
+//-----------------------------------------------------------------------------
+EFFECT_HANDLE C_TF2RootPanel::AddEffect( CPanelEffect *effect )
+{
+ Assert( effect );
+
+ m_Effects.AddToTail( effect );
+
+ return effect->GetHandle();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Remove effect from list
+// Input : *effect -
+//-----------------------------------------------------------------------------
+void C_TF2RootPanel::RemoveEffect( EFFECT_HANDLE handle )
+{
+ for ( int i = m_Effects.Size() - 1; i >= 0; i-- )
+ {
+ CPanelEffect *e = m_Effects[ i ];
+ if ( e->GetHandle() == handle )
+ {
+ m_Effects.Remove( i );
+ delete e;
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Find effect by handle
+// Input : handle -
+// Output : CPanelEffect
+//-----------------------------------------------------------------------------
+CPanelEffect *C_TF2RootPanel::FindEffect( EFFECT_HANDLE handle )
+{
+ for ( int i = 0; i < m_Effects.Size(); i++ )
+ {
+ CPanelEffect *e = m_Effects[ i ];
+ if ( e->GetHandle() == handle )
+ {
+ return e;
+ }
+ }
+ return NULL;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Delete all effects
+//-----------------------------------------------------------------------------
+void C_TF2RootPanel::ClearAllEffects( void )
+{
+ while ( m_Effects.Size() > 0 )
+ {
+ CPanelEffect *e = m_Effects[ 0 ];
+ m_Effects.Remove( 0 );
+ delete e;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void C_TF2RootPanel::OnTick( void )
+{
+ // Go backards
+ for ( int i = m_Effects.Size() - 1; i >= 0; i-- )
+ {
+ CPanelEffect *e = m_Effects[ i ];
+ Assert( e );
+
+ // Allow panel to think
+ e->Think();
+
+ // See if panel should disappear
+ if ( e->ShouldRemove() )
+ {
+ m_Effects.Remove( i );
+ delete e;
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Reset effects on level load/shutdown
+//-----------------------------------------------------------------------------
+void C_TF2RootPanel::LevelInit( void )
+{
+ ClearAllEffects();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void C_TF2RootPanel::LevelShutdown( void )
+{
+ ClearAllEffects();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Delete any panel effects owned by owner
+// Input : *owner -
+//-----------------------------------------------------------------------------
+void C_TF2RootPanel::DestroyPanelEffects( ITFHintItem *owner )
+{
+ for ( int i = m_Effects.Size() - 1; i >= 0; i-- )
+ {
+ CPanelEffect *e = m_Effects[ i ];
+ if ( e->GetOwner() == owner )
+ {
+ m_Effects.Remove( i );
+ delete e;
+ }
+ }
+}
+
diff --git a/game/client/tf2/c_tf2rootpanel.h b/game/client/tf2/c_tf2rootpanel.h
new file mode 100644
index 0000000..264475e
--- /dev/null
+++ b/game/client/tf2/c_tf2rootpanel.h
@@ -0,0 +1,63 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef C_TF2ROOTPANEL_H
+#define C_TF2ROOTPANEL_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include <vgui_controls/Panel.h>
+#include <vgui_controls/EditablePanel.h>
+#include "utlvector.h"
+
+class CPanelEffect;
+class ITFHintItem;
+
+// 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_TF2RootPanel : public vgui::Panel
+{
+ typedef vgui::Panel BaseClass;
+public:
+ C_TF2RootPanel( vgui::VPANEL parent );
+ virtual ~C_TF2RootPanel( void );
+
+ // Draw Panel effects here
+ virtual void PostChildPaint();
+
+ // Clear list of Panel Effects
+ virtual void LevelInit( void );
+ virtual void LevelShutdown( void );
+
+ // Panel Effect handlers
+ EFFECT_HANDLE AddEffect( CPanelEffect *effect );
+ void RemoveEffect( EFFECT_HANDLE handle );
+ CPanelEffect *FindEffect( EFFECT_HANDLE handle );
+ void DestroyPanelEffects( ITFHintItem *owner );
+ void ClearAllEffects( 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;
+};
+
+extern C_TF2RootPanel *g_pTF2RootPanel;
+
+#endif // C_TF2ROOTPANEL_H
diff --git a/game/client/tf2/c_tf_basecombatweapon.cpp b/game/client/tf2/c_tf_basecombatweapon.cpp
new file mode 100644
index 0000000..6408570
--- /dev/null
+++ b/game/client/tf2/c_tf_basecombatweapon.cpp
@@ -0,0 +1,310 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Client's CBaseTFCombatWeapon
+//
+// $NoKeywords: $
+//=============================================================================//
+#include "cbase.h"
+#include "c_tf_basecombatweapon.h"
+#include "hud.h"
+#include "iclientmode.h"
+#include "tf_hints.h"
+#include "itfhintitem.h"
+#include "c_tf_basehint.h"
+#include "hud_technologytreedoc.h"
+#include "c_tf_hintmanager.h"
+#include "hud_ammo.h"
+#include "c_weapon__stubs.h"
+#include "c_tf_class_sapper.h"
+#include <vgui/ISurface.h>
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+STUB_WEAPON_CLASS_IMPLEMENT( foo_tf_machine_gun, C_TFMachineGun );
+
+IMPLEMENT_CLIENTCLASS_DT( C_TFMachineGun, DT_TFMachineGun, CTFMachineGun )
+END_RECV_TABLE()
+
+// Share crosshair stuff among all weapons
+bool C_BaseTFCombatWeapon::m_bCrosshairInitialized = false;
+vgui::Label *C_BaseTFCombatWeapon::m_pCrosshairAmmo = NULL;
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+int C_BaseTFCombatWeapon::DrawModel( int flags )
+{
+ int iDrawn = 0;
+
+ // If my carrier is camouflaged, apply the camo to me too
+ if ( IsBeingCarried() )
+ {
+ C_BaseTFPlayer *pPlayer = (C_BaseTFPlayer *)GetOwner();
+ if ( pPlayer )
+ {
+ if ( pPlayer->IsCamouflaged())
+ {
+ if ( pPlayer->GetCamoMaterial() && ( pPlayer->ComputeCamoEffectAmount() != 1.0f ) )
+ {
+ modelrender->ForcedMaterialOverride( pPlayer->GetCamoMaterial() );
+ iDrawn = BaseClass::DrawModel(flags);
+ modelrender->ForcedMaterialOverride( NULL );
+ }
+ return iDrawn;
+ }
+ }
+ }
+
+ return BaseClass::DrawModel(flags);
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Output : int
+//-----------------------------------------------------------------------------
+int C_BaseTFCombatWeapon::GetFxBlend( void )
+{
+ if ( !IsCamouflaged() )
+ return BaseClass::GetFxBlend();
+
+ return ((C_BaseTFPlayer *)GetOwner())->GetFxBlend();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Output : Returns true on success, false on failure.
+//-----------------------------------------------------------------------------
+bool C_BaseTFCombatWeapon::IsTransparent( void )
+{
+ if ( IsCamouflaged() )
+ return true;
+
+ return BaseClass::IsTransparent();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Output : static void
+//-----------------------------------------------------------------------------
+void C_BaseTFCombatWeapon::CreateCrosshairPanels( void )
+{
+ m_pCrosshairAmmo = new vgui::Label( (vgui::Panel *)NULL, "crosshairammo", "100" );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void C_BaseTFCombatWeapon::DestroyCrosshairPanels( void )
+{
+ delete m_pCrosshairAmmo;
+ m_pCrosshairAmmo = NULL;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void C_BaseTFCombatWeapon::InitializeCrosshairPanels( void )
+{
+ // Init the crosshair labels if they haven't been
+ if ( m_bCrosshairInitialized )
+ return;
+
+ m_bCrosshairInitialized = true;
+
+ vgui::Panel *pParent = g_pClientMode->GetViewport();
+ m_pCrosshairAmmo->SetContentAlignment( vgui::Label::a_northeast );
+ m_pCrosshairAmmo->SetFgColor( Color( 255, 170, 0, 255 ) );
+ m_pCrosshairAmmo->SetPaintBackgroundEnabled( false );
+ m_pCrosshairAmmo->SetPos( CROSSHAIR_AMMO_LEFT, CROSSHAIR_AMMO_TOP );
+ m_pCrosshairAmmo->SetSize( CROSSHAIR_HEALTH_OFFSET / 2, m_pCrosshairAmmo->GetTall() );
+ m_pCrosshairAmmo->SetParent( pParent );
+ m_pCrosshairAmmo->SetAutoDelete( false );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Draw the ammo counts
+//-----------------------------------------------------------------------------
+void C_BaseTFCombatWeapon::DrawAmmo()
+{
+ // Get the local player
+ C_BaseTFPlayer *player = C_BaseTFPlayer::GetLocalPlayer();
+ if ( player == NULL )
+ return;
+
+ GetHudAmmo()->SetPrimaryAmmo(
+ m_iPrimaryAmmoType,
+ GetPrimaryAmmo(),
+ Clip1(),
+ GetMaxClip1() );
+ GetHudAmmo()->SetSecondaryAmmo(
+ m_iSecondaryAmmoType,
+ GetSecondaryAmmo(),
+ Clip2(),
+ GetMaxClip2() );
+
+ // ROBIN: Disabled mini ammo count for now
+ /*
+ InitializeCrosshairPanels();
+ DrawMiniAmmo();
+ */
+
+ // HACK: Draw technician's drain level
+ if ( IsLocalPlayerClass( TFCLASS_SAPPER ) )
+ {
+ C_PlayerClassSapper *pSapper = (C_PlayerClassSapper *)player->GetPlayerClass();
+
+ int r, g, b, a;
+ int x, y;
+
+ // Get the drained energy
+ float flPowerLevel = pSapper->m_flDrainedEnergy;
+ float flInverseFactor = 1.0 - flPowerLevel;
+
+ gHUD.m_clrNormal.GetColor( r, g, b, a );
+
+ int iWidth = XRES(12);
+ int iHeight = YRES(64);
+
+ x = XRES(64);
+ y = ( ScreenHeight() - YRES(2) - iHeight );
+
+ // draw the exhausted portion of the bar.
+ vgui::surface()->DrawSetColor( Color( r, g * flPowerLevel, b * flPowerLevel, 100 ) );
+ vgui::surface()->DrawFilledRect( x, y, x + iWidth, y + iHeight * flInverseFactor );
+
+ // draw the powerered portion of the bar
+ vgui::surface()->DrawSetColor( Color( r, g * flPowerLevel, b * flPowerLevel, 190 ) );
+ vgui::surface()->DrawFilledRect( x, y + iHeight * flInverseFactor, x + iWidth, y + iHeight * flInverseFactor + iHeight * flPowerLevel );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Draw the mini ammo/health counts around the health
+//-----------------------------------------------------------------------------
+void C_BaseTFCombatWeapon::DrawMiniAmmo()
+{
+ // Get the local player
+ C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
+ if ( pPlayer == NULL )
+ return;
+
+ // Draw the ammo to the right of the crosshair
+ if ( m_iClip1 >= 0 )
+ m_pCrosshairAmmo->SetText( VarArgs("%.3d", m_iClip1 < 999 ? m_iClip1 : 999) );
+ else
+ m_pCrosshairAmmo->SetText( VarArgs("%.3d", GetPrimaryAmmo() < 999 ? GetPrimaryAmmo() : 999) );
+
+ // BUG: This shouldn't need to be reset, since it's set in the section above, on initialization
+ m_pCrosshairAmmo->SetSize( CROSSHAIR_HEALTH_OFFSET / 2, m_pCrosshairAmmo->GetTall() );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Return true if a weapon-pickup icon should be displayed when this weapon is received
+//-----------------------------------------------------------------------------
+bool C_BaseTFCombatWeapon::ShouldDrawPickup( void )
+{
+ return false;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Output : char const
+//-----------------------------------------------------------------------------
+const char *C_BaseTFCombatWeapon::GetPrintName( void )
+{
+ return GetWpnData().szPrintName;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Output : Returns true on success, false on failure.
+//-----------------------------------------------------------------------------
+bool C_BaseTFCombatWeapon::ShouldShowUsageHint( void )
+{
+ return GetWpnData().bShowUsageHint;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : bnewentity -
+//-----------------------------------------------------------------------------
+void C_BaseTFCombatWeapon::OnDataChanged( DataUpdateType_t updateType )
+{
+ BaseClass::OnDataChanged( updateType );
+
+ if ( updateType != DATA_UPDATE_CREATED )
+ return;
+
+ if ( !ShouldShowUsageHint() )
+ return;
+
+ // See if the weapon is given as an associated weapon of a technology that
+ // is of level 1 or greater
+ CTechnologyTree *tree = GetTechnologyTreeDoc().GetTechnologyTree();
+ if ( !tree )
+ return;
+
+ bool done = false;
+ for ( int i = 0; !done && ( i < tree->GetNumberTechnologies() ); i++ )
+ {
+ CBaseTechnology *t = tree->GetTechnology( i );
+ Assert( t );
+ if ( !t )
+ continue;
+
+ // Must be associated with a tech >= level 1
+ if ( t->GetLevel() < 1 )
+ continue;
+
+ for ( int j = 0; j < t->GetNumWeaponAssociations(); j++ )
+ {
+ const char *associated_weapon = t->GetAssociatedWeapon( j );
+ if ( !associated_weapon )
+ continue;
+
+ if ( !GetName() )
+ continue;
+
+ // Is this tech associating the weapon
+ if ( stricmp( GetName(), associated_weapon ) )
+ continue;
+
+ if ( t->GetHintsGiven( TF_HINT_WEAPONRECEIVED ) )
+ continue;
+
+ t->SetHintsGiven( TF_HINT_WEAPONRECEIVED, true );
+
+ // Fill in hint data for this weapon
+ // Only show a max of 3 or 4 weapon received hints at a time
+ C_TFBaseHint *hint = CreateGlobalHint( TF_HINT_WEAPONRECEIVED, GetPrintName(), -1, 3 );
+ if ( hint )
+ {
+ ITFHintItem *item = hint->GetHintItem( 0 );
+ if ( item )
+ {
+ item->SetKeyValue( "weapon", GetPrintName() );
+ item->SetKeyValue( "weapontype", GetName() );
+ }
+ }
+
+ done = true;
+ break;
+ }
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+int C_BaseTFCombatWeapon ::GetSecondaryAmmo( void )
+{
+ // Get the local player
+ C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
+ if ( pPlayer == NULL )
+ return 0;
+
+ return pPlayer->GetAmmoCount( m_iSecondaryAmmoType );
+}
diff --git a/game/client/tf2/c_tf_basecombatweapon.h b/game/client/tf2/c_tf_basecombatweapon.h
new file mode 100644
index 0000000..9ed6f52
--- /dev/null
+++ b/game/client/tf2/c_tf_basecombatweapon.h
@@ -0,0 +1,47 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Clients TF Base combat weapon
+//
+// $NoKeywords: $
+//=============================================================================//
+#ifndef C_TF_BASECOMBATWEAPON_H
+#define C_TF_BASECOMBATWEAPON_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "c_baseanimating.h"
+
+class CViewSetup;
+class C_BaseTFPlayer;
+
+// Crosshair info positions
+#define CROSSHAIR_HEALTH_TOP YRES(266)
+#define CROSSHAIR_HEALTH_OFFSET XRES(80)
+#define CROSSHAIR_HEALTH_LEFT ((ScreenWidth() - CROSSHAIR_HEALTH_OFFSET) / 2)
+#define CROSSHAIR_AMMO_TOP CROSSHAIR_HEALTH_TOP
+#define CROSSHAIR_AMMO_LEFT (ScreenWidth() / 2)
+
+namespace vgui
+{
+ class Label;
+};
+
+#include "basetfcombatweapon_shared.h"
+
+class C_TFMachineGun : public C_BaseTFCombatWeapon
+{
+private:
+ DECLARE_CLASS( C_TFMachineGun, C_BaseTFCombatWeapon );
+
+public:
+ C_TFMachineGun() {}
+
+ DECLARE_CLIENTCLASS();
+ DECLARE_PREDICTABLE();
+
+private:
+ C_TFMachineGun( const C_TFMachineGun & );
+};
+
+#endif // C_TF_BASECOMBATWEAPON_H
diff --git a/game/client/tf2/c_tf_basehint.cpp b/game/client/tf2/c_tf_basehint.cpp
new file mode 100644
index 0000000..61c16c1
--- /dev/null
+++ b/game/client/tf2/c_tf_basehint.cpp
@@ -0,0 +1,691 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+#include "cbase.h"
+#include "c_tf_basehint.h"
+#include "tf_hints.h"
+#include "itfhintitem.h"
+#include <vgui_controls/Controls.h>
+#include <vgui/IVGui.h>
+#include <vgui/Cursor.h>
+#include <vgui_controls/Label.h>
+#include <vgui/ISurface.h>
+#include <vgui/IScheme.h>
+#include "vgui_int.h"
+#include "hintitembase.h"
+#include <KeyValues.h>
+
+HINTCOMPLETIONFUNCTION LookupCompletionFunction( const char *name );
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : id -
+// priority -
+// player -
+// entity -
+//-----------------------------------------------------------------------------
+C_TFBaseHint::C_TFBaseHint( int id, int priority, int entity, HINTCOMPLETIONFUNCTION pfn /*=NULL*/ )
+ : vgui::Panel( NULL, "TFBaseHint" ), m_CursorNone( vgui::dc_none )
+{
+ m_pObject = NULL;
+ m_pClearLabel = NULL;
+ m_pCaption = NULL;
+ m_pfnCompletion = pfn;
+
+ // Child of main panel
+ SetParent( VGui_GetClientDLLRootPanel() );
+
+ // Put at top of z-order (happens in Think, too)
+// MoveToFront();
+
+ // No cursor
+ SetCursor( m_CursorNone );
+ // Set to default size
+ SetSize( TFBASEHINT_DEFAULT_WIDTH, TFBASEHINT_DEFAULT_HEIGHT );
+ // We'll expressly delete it
+ SetAutoDelete( false );
+
+ // Set up default values
+ SetID( id );
+ SetPriority( priority );
+ SetEntity( entity );
+ SetCompleted( false );
+ // Target panel
+ m_hTarget = NULL;
+
+ m_bMoving = false;
+ m_flMoveRemaining = 0.0f;
+ m_flMoveTotal = 0.0f;
+
+ for ( int pt = 0; pt < 2; pt++ )
+ {
+ m_nMoveStart[ pt ] = 0;
+ m_nMoveEnd[ pt ] = 0;
+ }
+
+ vgui::ivgui()->AddTickSignal( GetVPanel() );
+
+ // Create clear label
+ m_pClearLabel = new vgui::Label( this, "CLEAR", "[Enter] to remove, [Enter] twice quickly to remove all..." );
+ m_pClearLabel->SetContentAlignment( vgui::Label::a_west );
+ m_pClearLabel->SetTextInset( 3, 2 );
+
+ // Create window caption
+ m_pCaption = new vgui::Label( this, "CAPTION", "" );
+ m_pCaption->SetContentAlignment( vgui::Label::a_west );
+ m_pCaption->SetTextInset( 3, 0 );
+
+ // See if the hint started out complete!
+ CheckForCompletion();
+
+ // Always start out hidden
+ SetVisible( false );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+C_TFBaseHint::~C_TFBaseHint( void )
+{
+ RemoveAllHintItems( true );
+}
+
+
+//-----------------------------------------------------------------------------
+// Applying scheme settings
+//-----------------------------------------------------------------------------
+void C_TFBaseHint::ApplySchemeSettings(vgui::IScheme *pScheme)
+{
+ BaseClass::ApplySchemeSettings(pScheme);
+
+ vgui::HFont hSmallFont = pScheme->GetFont( "DefaultVerySmall" );
+ vgui::HFont hCaptionFont = pScheme->GetFont( "DefaultSmall" );
+ m_pClearLabel->SetFont( hSmallFont );
+ m_pCaption->SetFont( hCaptionFont );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *pkv -
+//-----------------------------------------------------------------------------
+void C_TFBaseHint::ParseFromData( KeyValues *pkv )
+{
+ int priority = pkv->GetInt( "priority", 100 );
+ SetPriority( priority );
+ int width = pkv->GetInt( "width", TFBASEHINT_DEFAULT_WIDTH );
+ if ( !width && !stricmp( pkv->GetString( "width" ), "default" ) )
+ {
+ width = TFBASEHINT_DEFAULT_WIDTH;
+ }
+ SetSize( width, TFBASEHINT_DEFAULT_HEIGHT );
+ const char *title = pkv->GetString( "title" );
+ if ( title )
+ {
+ SetTitle( title );
+ }
+
+ const char *completionfunction = pkv->GetString( "completionfunction" );
+ if ( completionfunction && strlen( completionfunction ) > 0 )
+ {
+ SetCompletionFunction( LookupCompletionFunction( completionfunction ) );
+ }
+
+ KeyValues *items = pkv->FindKey( "items" );
+ if ( items )
+ {
+ KeyValues *pkvItem = items->GetFirstSubKey();
+ for( ; pkvItem ; pkvItem = pkvItem->GetNextKey() )
+ {
+ CHintItemBase *item = CreateHintItem( this, pkvItem->GetName() );
+ if ( item )
+ {
+ item->ParseItem( pkvItem );
+ item->ComputeTitle();
+
+ item->SetSize( GetWide(), 20 );
+
+ AddHintItem( item );
+ }
+ else
+ {
+ Msg( "C_TFBaseHint::ParseFromData: Failed to create hint item %s\n", pkvItem->GetName() );
+ }
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : int&x -
+// y -
+// w -
+// &h -
+//-----------------------------------------------------------------------------
+void C_TFBaseHint::GetClientArea( int&x, int& y, int& w, int &h )
+{
+ GetSize( w, h );
+
+ x = BORDER;
+ y = BORDER + CAPTION;
+
+ w -= 2 * BORDER;
+ h -= 2 * BORDER;
+
+ h -= CAPTION;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *title -
+//-----------------------------------------------------------------------------
+void C_TFBaseHint::SetTitle( const char *title )
+{
+ if ( m_pCaption )
+ {
+ m_pCaption->SetText( title );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void C_TFBaseHint::PaintBackground()
+{
+ SetBgColor( Color( 240, 240, 220, 255 ) );
+ if ( m_pCaption )
+ {
+ m_pCaption->SetBgColor( Color( 163, 180, 200, 255 ) );
+
+ m_pCaption->SetFgColor( Color( 0, 0, 0, 255 ) );
+ }
+ if ( m_pClearLabel )
+ {
+ m_pClearLabel->SetBgColor( Color( 230, 230, 210, 255 ) );
+ m_pClearLabel->SetFgColor( Color( 100, 127, 160, 255 ) );
+ }
+
+ BaseClass::PaintBackground();
+
+ int w, h;
+ GetSize( w, h );
+
+ vgui::surface()->DrawSetColor( 0, 0, 0, 255 );
+ vgui::surface()->DrawOutlinedRect( 0, 0, w, h );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void C_TFBaseHint::PerformLayout()
+{
+ BaseClass::PerformLayout();
+
+ int x, y, w, h;
+ GetClientArea( x, y, w, h );
+
+ int itemh;
+
+ int needY = 4;
+
+ for ( int i = 0; i < GetNumHintItems(); i++ )
+ {
+ ITFHintItem *item = GetHintItem( i );
+ if ( item )
+ {
+ itemh = item->GetHeight();
+
+ item->SetPosition( x, y + 2 );
+ item->SetItemNumber( i + 1 );
+
+ if ( i == 0 )
+ {
+ item->SetVisible( true );
+ needY += itemh + 2;
+ }
+ else
+ {
+ item->SetVisible( false );
+ }
+ }
+ }
+
+ needY += 8;
+
+ if ( m_pClearLabel )
+ {
+ m_pClearLabel->SetBounds( x, y + needY + 2, w, 14 );
+ }
+
+ if ( m_pCaption )
+ {
+ m_pCaption->SetBounds( x, BORDER, w, CAPTION );
+ }
+
+ needY += 14 + BORDER;
+
+ int needPixels = needY - h;
+
+ int trueW, trueH;
+ GetSize( trueW, trueH );
+
+ SetSize( trueW, trueH + needPixels );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Install completion function
+// Input : pfn -
+//-----------------------------------------------------------------------------
+void C_TFBaseHint::SetCompletionFunction( HINTCOMPLETIONFUNCTION pfn )
+{
+ m_pfnCompletion = pfn;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void C_TFBaseHint::CheckForCompletion( void )
+{
+ if ( m_pfnCompletion )
+ {
+ bool complete = (*m_pfnCompletion)( this );
+ if ( complete )
+ {
+ SetCompleted( true );
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void C_TFBaseHint::OnTick()
+{
+ if ( !IsVisible() )
+ return;
+
+// MoveToFront();
+
+ // Check for completion of entire hint
+ CheckForCompletion();
+
+ bool setactive = false;
+ int numactive = 0;
+ // Remove obsolete items
+ int i;
+ for ( i = m_Hints.Size() - 1; i >= 0; i-- )
+ {
+ ITFHintItem *item = m_Hints[ i ];
+ if ( !item )
+ continue;
+
+ if ( item->GetCompleted() )
+ {
+ RemoveHintItem( i );
+ }
+ else
+ {
+ numactive++;
+ }
+ }
+
+ // Mark first one as active
+ // Perform think
+ for ( i = 0; i < m_Hints.Size(); i++ )
+ {
+ ITFHintItem *item = m_Hints[ i ];
+ if ( !item )
+ continue;
+
+ if ( !setactive )
+ {
+ item->SetActive( true );
+ setactive = true;
+ }
+ else
+ {
+ item->SetActive( false );
+ }
+
+ // Think, too
+ if ( item->GetActive() )
+ {
+ item->Think();
+ }
+ }
+
+ // No more active items
+ if ( !numactive )
+ {
+ SetCompleted( true );
+ }
+
+ // Keep moving window to correct position
+ AnimatePosition();
+
+/*
+ static float nextchange = 0.0f;
+
+ if ( gpGlobals->curtime < nextchange )
+ return;
+
+ nextchange = gpGlobals->curtime + 1.0f;
+
+ int w, h;
+ GetSize( w, h );
+
+ int x = random->RandomInt( 0, ScreenWidth() - w );
+ int y = random->RandomInt( 0, ScreenHeight() - h );
+
+ SetDesiredPosition( x, y, 0.9f );
+*/
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Output : int
+//-----------------------------------------------------------------------------
+int C_TFBaseHint::GetID( void )
+{
+ return m_nID;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : id -
+//-----------------------------------------------------------------------------
+void C_TFBaseHint::SetID( int id )
+{
+ m_nID = id;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Output : int
+//-----------------------------------------------------------------------------
+int C_TFBaseHint::GetPriority( void )
+{
+ return m_nPriority;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : priority -
+//-----------------------------------------------------------------------------
+void C_TFBaseHint::SetPriority( int priority )
+{
+ m_nPriority = priority;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Output : int
+//-----------------------------------------------------------------------------
+int C_TFBaseHint::GetEntity( void )
+{
+ return m_nEntity;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Output : C_BaseEntity
+//-----------------------------------------------------------------------------
+C_BaseEntity *C_TFBaseHint::GetBaseEntity( void )
+{
+ return m_nEntity != -1 ? cl_entitylist->GetEnt( m_nEntity ) : NULL;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : entity -
+//-----------------------------------------------------------------------------
+void C_TFBaseHint::SetEntity( int entity )
+{
+ m_nEntity = entity;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *entity -
+//-----------------------------------------------------------------------------
+void C_TFBaseHint::SetBaseEntity( C_BaseEntity *entity )
+{
+ m_nEntity = entity ? entity->index : -1;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Output : Returns true on success, false on failure.
+//-----------------------------------------------------------------------------
+bool C_TFBaseHint::GetCompleted( void )
+{
+ return m_bCompleted;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : completed -
+//-----------------------------------------------------------------------------
+void C_TFBaseHint::SetCompleted( bool completed )
+{
+ m_bCompleted = completed;
+ // Hide the window right away if it's finished
+ SetVisible( !completed );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *item -
+//-----------------------------------------------------------------------------
+void C_TFBaseHint::AddHintItem( ITFHintItem *item )
+{
+ m_Hints.AddToTail( item );
+ InvalidateLayout();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : index -
+//-----------------------------------------------------------------------------
+void C_TFBaseHint::RemoveHintItem( int index )
+{
+ ITFHintItem *item = GetHintItem( index );
+ if ( item )
+ {
+ m_Hints.Remove( index );
+ item->DeleteThis();
+ InvalidateLayout();
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Output : int
+//-----------------------------------------------------------------------------
+int C_TFBaseHint::GetNumHintItems( void )
+{
+ return m_Hints.Size();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : deleteitems -
+//-----------------------------------------------------------------------------
+void C_TFBaseHint::RemoveAllHintItems( bool deleteitems )
+{
+ while ( m_Hints.Size() > 0 )
+ {
+ ITFHintItem *item = m_Hints[ 0 ];
+ m_Hints.Remove( 0 );
+ if ( deleteitems )
+ {
+ item->DeleteThis();
+ }
+ }
+
+ InvalidateLayout();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : index -
+//-----------------------------------------------------------------------------
+ITFHintItem *C_TFBaseHint::GetHintItem( int index )
+{
+ if ( index < 0 || index >= m_Hints.Size() )
+ {
+ return NULL;
+ }
+
+ return m_Hints[ index ];
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : x -
+// y -
+// movementtime -
+//-----------------------------------------------------------------------------
+void C_TFBaseHint::SetDesiredPosition( int x, int y, float movementtime /*=0.3f*/ )
+{
+ m_bMoving = true;
+
+ m_flMoveRemaining = movementtime;
+ m_flMoveTotal = movementtime;
+
+ int ox, oy;
+ GetPos( ox, oy );
+
+ m_nMoveStart[ 0 ] = ox;
+ m_nMoveStart[ 1 ] = oy;
+
+ m_nMoveEnd[ 0 ] = x;
+ m_nMoveEnd[ 1 ] = y;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Output : float
+//-----------------------------------------------------------------------------
+float C_TFBaseHint::GetMovementFraction( void )
+{
+ float frac = 0.0f;
+
+ if ( m_flMoveTotal > 0.0f )
+ {
+ frac = 1.0f - ( m_flMoveRemaining / m_flMoveTotal );
+ }
+
+ float squared = frac * frac;
+
+ frac = 3 * squared - 2 * frac * squared;
+
+ // Simple spline
+ frac = clamp( frac, 0.0f, 1.0f );
+
+ return frac;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void C_TFBaseHint::AnimatePosition( void )
+{
+ if ( !m_bMoving )
+ return;
+
+ m_flMoveRemaining -= gpGlobals->frametime;
+ if ( m_flMoveRemaining <= 0.0f )
+ {
+ m_bMoving = false;
+ SetPos( m_nMoveEnd[ 0 ], m_nMoveEnd[ 1 ] );
+ return;
+ }
+
+ float frac = GetMovementFraction();
+
+ int dx = m_nMoveEnd[ 0 ] - m_nMoveStart[ 0 ];
+ int dy = m_nMoveEnd[ 1 ] - m_nMoveStart[ 1 ];
+
+ int x, y;
+
+ x = m_nMoveStart[ 0 ] + ( int )( frac * dx );
+ y = m_nMoveStart[ 1 ] + ( int )( frac * dy );
+
+ SetPos( x, y );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Helper to center a panel
+// Input : *panel -
+// Output : static void
+//-----------------------------------------------------------------------------
+static void PositionHintNoTarget( C_TFBaseHint *panel )
+{
+ int w, h;
+ panel->GetSize( w, h );
+ int y = ( ScreenHeight() - h ) / 2;
+
+ panel->SetDesiredPosition( ScreenWidth() - w - 10, y );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *panel -
+//-----------------------------------------------------------------------------
+void C_TFBaseHint::SetHintTarget( vgui::Panel *panel )
+{
+ m_hTarget = panel;
+
+ if ( panel )
+ {
+ int hintW, hintH;
+
+ GetSize( hintW, hintH );
+
+ int x, y, w, h;
+ panel->GetBounds( x, y, w, h );
+
+ // Try and position ourselves up and to left of target item?
+ x = x - ( hintW - w );
+ y = y - ( hintH ) - 40;
+
+ // Don't let it hang off screen
+ if ( x < 3 )
+ {
+ x = 3;
+ }
+ else if ( x + hintW + 3 >= ScreenWidth() )
+ {
+ int over = ( x + hintW + 3 - ScreenWidth() );
+
+ x -= over;
+ }
+
+ if ( y < 3 )
+ {
+ y = 3;
+ }
+ else if ( y + hintH >= ScreenHeight() )
+ {
+ int over = ( y + hintH + 3 - ScreenHeight() );
+
+ y -= over;
+ }
+
+ SetDesiredPosition( x, y );
+ }
+ else
+ {
+ PositionHintNoTarget( this );
+ }
+
+ // Tell hint items that there is a new target
+ for ( int i = 0 ; i < GetNumHintItems(); i++ )
+ {
+ ITFHintItem *item = GetHintItem( i );
+ item->SetHintTarget( panel );
+ }
+}
diff --git a/game/client/tf2/c_tf_basehint.h b/game/client/tf2/c_tf_basehint.h
new file mode 100644
index 0000000..3263673
--- /dev/null
+++ b/game/client/tf2/c_tf_basehint.h
@@ -0,0 +1,147 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef C_TF_BASEHINT_H
+#define C_TF_BASEHINT_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include <vgui_controls/Panel.h>
+#include <vgui_controls/PHandle.h>
+#include "utlvector.h"
+
+class C_BaseTFPlayer;
+class C_BaseEntity;
+class ITFHintItem;
+class KeyValues;
+namespace vgui
+{
+ class Label;
+}
+
+class C_TFBaseHint;
+
+typedef bool (*HINTCOMPLETIONFUNCTION)( C_TFBaseHint *hint );
+
+#define TFBASEHINT_DEFAULT_WIDTH 400
+#define TFBASEHINT_DEFAULT_HEIGHT 300
+
+//-----------------------------------------------------------------------------
+// Purpose: Base TF Hint UI Element
+// hints must position themselves and are responsible for any "sub objects"
+//-----------------------------------------------------------------------------
+class C_TFBaseHint : public vgui::Panel
+{
+ typedef vgui::Panel BaseClass;
+public:
+ enum
+ {
+ BORDER = 2,
+ CAPTION = 17
+ };
+
+ // Factory for hints
+ static C_TFBaseHint *CreateHint( int id, const char *subsection, int entity );
+
+ // Construction
+ C_TFBaseHint( int id, int priority, int entity, HINTCOMPLETIONFUNCTION pfn = NULL );
+ virtual ~C_TFBaseHint( void );
+
+ // Initialization
+ virtual void ParseFromData( KeyValues *pkv );
+
+ // Redraw self
+ virtual void PaintBackground();
+ virtual void PerformLayout();
+ virtual void GetClientArea( int&x, int& y, int& w, int &h );
+ virtual void SetTitle( const char *title );
+
+ // Panel will move itself to spot over movementtime
+ virtual void SetDesiredPosition( int x, int y, float movementtime = 0.3f );
+
+ // Target element for hint
+ virtual void SetHintTarget( vgui::Panel *panel );
+
+ // Scheme
+ virtual void ApplySchemeSettings(vgui::IScheme *pScheme);
+
+ // Think
+ virtual void OnTick();
+ // Derived classes should set m_bCompleted here for entire hint
+ virtual void CheckForCompletion( void );
+
+ // Data access
+ virtual int GetID( void );
+ virtual void SetID( int id );
+
+ virtual int GetPriority( void );
+ virtual void SetPriority( int priority );
+
+ virtual int GetEntity( void );
+ virtual C_BaseEntity *GetBaseEntity( void );
+ virtual void SetEntity( int entity );
+ virtual void SetBaseEntity( C_BaseEntity *entity );
+
+ // Install a function used to determine if the global hint requirements have
+ // been met
+ virtual bool GetCompleted( void );
+ virtual void SetCompleted( bool completed );
+ virtual void SetCompletionFunction( HINTCOMPLETIONFUNCTION pfn );
+
+ // Accessors for hint items themselves
+ virtual void AddHintItem( ITFHintItem *item );
+ virtual void RemoveHintItem( int index );
+ virtual int GetNumHintItems( void );
+ virtual void RemoveAllHintItems( bool deleteitems );
+ virtual ITFHintItem *GetHintItem( int index );
+
+protected:
+ // Move current position toward desirec position
+ virtual void AnimatePosition( void );
+ virtual float GetMovementFraction( void );
+
+ // In the process of moving
+ bool m_bMoving;
+
+ // Amount of move time remaining
+ float m_flMoveRemaining;
+ // Total move time
+ float m_flMoveTotal;
+ // Start/end positions for panel movement
+ int m_nMoveStart[2];
+ int m_nMoveEnd[2];
+
+private:
+ // ID of the hint
+ int m_nID;
+ // Priority of the hint
+ int m_nPriority;
+ // Associated entity
+ int m_nEntity;
+ // Has the hint been completed
+ bool m_bCompleted;
+ // Object hint is associated with
+ void *m_pObject;
+ // No mouse
+ vgui::HCursor m_CursorNone;
+ // "Press [Esc]..."
+ vgui::Label *m_pClearLabel;
+ // Window caption
+ vgui::Label *m_pCaption;
+
+ // Safe handle to target object
+ vgui::PHandle m_hTarget;
+
+ // Completion function
+ HINTCOMPLETIONFUNCTION m_pfnCompletion;
+
+ // List of items
+ CUtlVector< ITFHintItem * > m_Hints;
+};
+
+#endif // C_TF_BASEHINT_H
diff --git a/game/client/tf2/c_tf_class_commando.cpp b/game/client/tf2/c_tf_class_commando.cpp
new file mode 100644
index 0000000..4d5e78c
--- /dev/null
+++ b/game/client/tf2/c_tf_class_commando.cpp
@@ -0,0 +1,136 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+#include "cbase.h"
+#include "c_tf_class_commando.h"
+#include "usercmd.h"
+
+//=============================================================================
+//
+// Commando Data Table
+//
+BEGIN_RECV_TABLE_NOBASE( C_PlayerClassCommando, DT_PlayerClassCommandoData )
+ RecvPropInt ( RECVINFO( m_ClassData.m_bCanBullRush ) ),
+ RecvPropInt ( RECVINFO( m_ClassData.m_bBullRush ) ),
+ RecvPropVector ( RECVINFO( m_ClassData.m_vecBullRushDir ) ),
+ RecvPropVector ( RECVINFO( m_ClassData.m_vecBullRushViewDir ) ),
+ RecvPropVector ( RECVINFO( m_ClassData.m_vecBullRushViewGoalDir ) ),
+ RecvPropFloat ( RECVINFO( m_ClassData.m_flBullRushTime ) ),
+ RecvPropFloat ( RECVINFO( m_ClassData.m_flDoubleTapForwardTime ) ),
+END_RECV_TABLE()
+
+BEGIN_PREDICTION_DATA_NO_BASE( C_PlayerClassCommando )
+
+ DEFINE_PRED_TYPEDESCRIPTION( m_ClassData, PlayerClassCommandoData_t ),
+
+END_PREDICTION_DATA()
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+C_PlayerClassCommando::C_PlayerClassCommando( C_BaseTFPlayer *pPlayer ) :
+ C_PlayerClass( pPlayer )
+{
+ m_ClassData.m_bCanBullRush = false;
+ m_ClassData.m_bBullRush = false;
+ m_ClassData.m_vecBullRushDir.Init();
+ m_ClassData.m_vecBullRushViewDir.Init();
+ m_ClassData.m_vecBullRushViewGoalDir.Init();
+ m_ClassData.m_flBullRushTime = COMMANDO_TIME_INVALID;
+ m_ClassData.m_flDoubleTapForwardTime = COMMANDO_TIME_INVALID;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+C_PlayerClassCommando::~C_PlayerClassCommando()
+{
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void C_PlayerClassCommando::ClassThink( void )
+{
+ CheckBullRushState();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void C_PlayerClassCommando::PostClassThink( void )
+{
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void C_PlayerClassCommando::ClassPreDataUpdate( void )
+{
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void C_PlayerClassCommando::ClassOnDataChanged( void )
+{
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void C_PlayerClassCommando::CreateMove( float flInputSampleTime, CUserCmd *pCmd )
+{
+ if ( m_ClassData.m_bBullRush )
+ {
+ pCmd->viewangles = m_ClassData.m_vecBullRushViewDir;
+ QAngle angles = m_ClassData.m_vecBullRushViewDir;
+ engine->SetViewAngles( angles );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+bool C_PlayerClassCommando::CanGetInVehicle( void )
+{
+ if ( m_ClassData.m_bBullRush )
+ return false;
+
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void C_PlayerClassCommando::CheckBullRushState( void )
+{
+ if ( m_ClassData.m_bBullRush )
+ {
+ InterpolateBullRushViewAngles();
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void C_PlayerClassCommando::InterpolateBullRushViewAngles( void )
+{
+ // Determine the fraction.
+ if ( m_ClassData.m_flBullRushTime < COMMANDO_BULLRUSH_VIEWDELTA_TEST )
+ {
+ m_ClassData.m_vecBullRushViewDir = m_ClassData.m_vecBullRushViewGoalDir;
+ return;
+ }
+
+ float flFraction = 1.0f - ( ( m_ClassData.m_flBullRushTime - COMMANDO_BULLRUSH_VIEWDELTA_TEST ) / COMMANDO_BULLRUSH_VIEWDELTA_TIME );
+
+ QAngle angCurrent;
+ InterpolateAngles( m_ClassData.m_vecBullRushViewDir, m_ClassData.m_vecBullRushViewGoalDir, angCurrent, flFraction );
+
+ NormalizeAngles( angCurrent );
+ m_ClassData.m_vecBullRushViewDir = angCurrent;
+}
diff --git a/game/client/tf2/c_tf_class_commando.h b/game/client/tf2/c_tf_class_commando.h
new file mode 100644
index 0000000..9ce42de
--- /dev/null
+++ b/game/client/tf2/c_tf_class_commando.h
@@ -0,0 +1,50 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef C_TF_CLASS_COMMANDO_H
+#define C_TF_CLASS_COMMANDO_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "c_tf_playerclass.h"
+#include "dt_recv.h"
+
+class C_PlayerClassCommando : public C_PlayerClass
+{
+public:
+
+ DECLARE_CLASS( C_PlayerClassCommando, C_PlayerClass );
+
+ DECLARE_PREDICTABLE();
+
+ C_PlayerClassCommando( C_BaseTFPlayer *pPlayer );
+ virtual ~C_PlayerClassCommando();
+
+ PlayerClassCommandoData_t *GetClassData( void ) { return &m_ClassData; }
+
+ void ClassThink( void );
+ void PostClassThink( void );
+ void ClassPreDataUpdate( void );
+ void ClassOnDataChanged( void );
+
+ void CreateMove( float flInputSampleTime, CUserCmd *pCmd );
+
+ // Vehicles
+ bool CanGetInVehicle( void );
+
+ PlayerClassCommandoData_t m_ClassData;
+
+private:
+
+ void CheckBullRushState( void );
+ void InterpolateBullRushViewAngles( void );
+};
+
+EXTERN_RECV_TABLE( DT_PlayerClassCommandoData )
+
+#endif // C_TF_CLASS_COMMANDO_H \ No newline at end of file
diff --git a/game/client/tf2/c_tf_class_defender.cpp b/game/client/tf2/c_tf_class_defender.cpp
new file mode 100644
index 0000000..e375aaf
--- /dev/null
+++ b/game/client/tf2/c_tf_class_defender.cpp
@@ -0,0 +1,36 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+#include "cbase.h"
+#include "c_tf_class_defender.h"
+
+//=============================================================================
+//
+// Defender Data Table
+//
+BEGIN_RECV_TABLE_NOBASE( C_PlayerClassDefender, DT_PlayerClassDefenderData )
+END_RECV_TABLE()
+
+BEGIN_PREDICTION_DATA_NO_BASE( C_PlayerClassDefender )
+
+ DEFINE_PRED_TYPEDESCRIPTION( m_ClassData, PlayerClassDefenderData_t ),
+
+END_PREDICTION_DATA()
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+C_PlayerClassDefender::C_PlayerClassDefender( C_BaseTFPlayer *pPlayer ) :
+ C_PlayerClass( pPlayer )
+{
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+C_PlayerClassDefender::~C_PlayerClassDefender()
+{
+}
diff --git a/game/client/tf2/c_tf_class_defender.h b/game/client/tf2/c_tf_class_defender.h
new file mode 100644
index 0000000..a6cb73a
--- /dev/null
+++ b/game/client/tf2/c_tf_class_defender.h
@@ -0,0 +1,38 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef C_TF_CLASS_DEFENDER_H
+#define C_TF_CLASS_DEFENDER_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "c_tf_playerclass.h"
+#include "dt_recv.h"
+
+class C_PlayerClassDefender : public C_PlayerClass
+{
+
+ DECLARE_CLASS( C_PlayerClassDefender, C_PlayerClass );
+
+public:
+
+ DECLARE_PREDICTABLE();
+
+ C_PlayerClassDefender( C_BaseTFPlayer *pPlayer );
+ virtual ~C_PlayerClassDefender();
+
+ PlayerClassDefenderData_t *GetClassData( void ) { return &m_ClassData; }
+
+protected:
+
+ PlayerClassDefenderData_t m_ClassData;
+};
+
+EXTERN_RECV_TABLE( DT_PlayerClassDefenderData )
+
+#endif // C_TF_CLASS_DEFENDER_H \ No newline at end of file
diff --git a/game/client/tf2/c_tf_class_escort.cpp b/game/client/tf2/c_tf_class_escort.cpp
new file mode 100644
index 0000000..84e7907
--- /dev/null
+++ b/game/client/tf2/c_tf_class_escort.cpp
@@ -0,0 +1,36 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+#include "cbase.h"
+#include "c_tf_class_escort.h"
+
+//=============================================================================
+//
+// Escort Data Table
+//
+BEGIN_RECV_TABLE_NOBASE( C_PlayerClassEscort, DT_PlayerClassEscortData )
+END_RECV_TABLE()
+
+BEGIN_PREDICTION_DATA_NO_BASE( C_PlayerClassEscort )
+
+ DEFINE_PRED_TYPEDESCRIPTION( m_ClassData, PlayerClassEscortData_t ),
+
+END_PREDICTION_DATA()
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+C_PlayerClassEscort::C_PlayerClassEscort( C_BaseTFPlayer *pPlayer ) :
+ C_PlayerClass( pPlayer )
+{
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+C_PlayerClassEscort::~C_PlayerClassEscort()
+{
+} \ No newline at end of file
diff --git a/game/client/tf2/c_tf_class_escort.h b/game/client/tf2/c_tf_class_escort.h
new file mode 100644
index 0000000..c906764
--- /dev/null
+++ b/game/client/tf2/c_tf_class_escort.h
@@ -0,0 +1,37 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef C_TF_CLASS_ESCORT_H
+#define C_TF_CLASS_ESCORT_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "c_tf_playerclass.h"
+#include "dt_recv.h"
+
+class C_PlayerClassEscort : public C_PlayerClass
+{
+
+ DECLARE_CLASS( C_PlayerClassEscort, C_PlayerClass );
+
+public:
+
+ C_PlayerClassEscort( C_BaseTFPlayer *pPlayer );
+ virtual ~C_PlayerClassEscort();
+
+ DECLARE_PREDICTABLE();
+ PlayerClassEscortData_t *GetClassData( void ) { return &m_ClassData; }
+
+protected:
+
+ PlayerClassEscortData_t m_ClassData;
+};
+
+EXTERN_RECV_TABLE( DT_PlayerClassEscortData )
+
+#endif // C_TF_CLASS_ESCORT_H \ No newline at end of file
diff --git a/game/client/tf2/c_tf_class_infiltrator.cpp b/game/client/tf2/c_tf_class_infiltrator.cpp
new file mode 100644
index 0000000..129cdcc
--- /dev/null
+++ b/game/client/tf2/c_tf_class_infiltrator.cpp
@@ -0,0 +1,36 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+#include "cbase.h"
+#include "c_tf_class_infiltrator.h"
+
+//=============================================================================
+//
+// Infiltrator Data Table
+//
+BEGIN_RECV_TABLE_NOBASE( C_PlayerClassInfiltrator, DT_PlayerClassInfiltratorData )
+END_RECV_TABLE()
+
+BEGIN_PREDICTION_DATA_NO_BASE( C_PlayerClassInfiltrator )
+
+ DEFINE_PRED_TYPEDESCRIPTION( m_ClassData, PlayerClassInfiltratorData_t ),
+
+END_PREDICTION_DATA()
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+C_PlayerClassInfiltrator::C_PlayerClassInfiltrator( C_BaseTFPlayer *pPlayer ) :
+ C_PlayerClass( pPlayer )
+{
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+C_PlayerClassInfiltrator::~C_PlayerClassInfiltrator()
+{
+} \ No newline at end of file
diff --git a/game/client/tf2/c_tf_class_infiltrator.h b/game/client/tf2/c_tf_class_infiltrator.h
new file mode 100644
index 0000000..d91f0cc
--- /dev/null
+++ b/game/client/tf2/c_tf_class_infiltrator.h
@@ -0,0 +1,38 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef C_TF_CLASS_INFILTRATOR_H
+#define C_TF_CLASS_INFILTRATOR_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "c_tf_playerclass.h"
+#include "dt_recv.h"
+
+class C_PlayerClassInfiltrator : public C_PlayerClass
+{
+
+ DECLARE_CLASS( C_PlayerClassInfiltrator, C_PlayerClass );
+
+public:
+
+ C_PlayerClassInfiltrator( C_BaseTFPlayer *pPlayer );
+ virtual ~C_PlayerClassInfiltrator();
+
+ DECLARE_PREDICTABLE();
+
+ PlayerClassInfiltratorData_t *GetClassData( void ) { return &m_ClassData; }
+
+protected:
+
+ PlayerClassInfiltratorData_t m_ClassData;
+};
+
+EXTERN_RECV_TABLE( DT_PlayerClassInfiltratorData )
+
+#endif // C_TF_CLASS_INFILTRATOR_H \ No newline at end of file
diff --git a/game/client/tf2/c_tf_class_medic.cpp b/game/client/tf2/c_tf_class_medic.cpp
new file mode 100644
index 0000000..3015929
--- /dev/null
+++ b/game/client/tf2/c_tf_class_medic.cpp
@@ -0,0 +1,37 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+#include "cbase.h"
+#include "c_tf_class_medic.h"
+
+//=============================================================================
+//
+// Medic Data Table
+//
+BEGIN_RECV_TABLE_NOBASE( C_PlayerClassMedic, DT_PlayerClassMedicData )
+END_RECV_TABLE()
+
+BEGIN_PREDICTION_DATA_NO_BASE( C_PlayerClassMedic )
+
+ DEFINE_PRED_TYPEDESCRIPTION( m_ClassData, PlayerClassMedicData_t ),
+
+END_PREDICTION_DATA()
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+C_PlayerClassMedic::C_PlayerClassMedic( C_BaseTFPlayer *pPlayer ) :
+ C_PlayerClass( pPlayer )
+{
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+C_PlayerClassMedic::~C_PlayerClassMedic()
+{
+} \ No newline at end of file
diff --git a/game/client/tf2/c_tf_class_medic.h b/game/client/tf2/c_tf_class_medic.h
new file mode 100644
index 0000000..dffaa02
--- /dev/null
+++ b/game/client/tf2/c_tf_class_medic.h
@@ -0,0 +1,38 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef C_TF_CLASS_MEDIC_H
+#define C_TF_CLASS_MEDIC_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "c_tf_playerclass.h"
+#include "dt_recv.h"
+
+class C_PlayerClassMedic : public C_PlayerClass
+{
+
+ DECLARE_CLASS( C_PlayerClassMedic, C_PlayerClass );
+
+public:
+
+ C_PlayerClassMedic( C_BaseTFPlayer *pPlayer );
+ virtual ~C_PlayerClassMedic();
+
+ DECLARE_PREDICTABLE();
+
+ PlayerClassMedicData_t *GetClassData( void ) { return &m_ClassData; }
+
+protected:
+
+ PlayerClassMedicData_t m_ClassData;
+};
+
+EXTERN_RECV_TABLE( DT_PlayerClassMedicData )
+
+#endif // C_TF_CLASS_MEDIC_H \ No newline at end of file
diff --git a/game/client/tf2/c_tf_class_pyro.cpp b/game/client/tf2/c_tf_class_pyro.cpp
new file mode 100644
index 0000000..c8600db
--- /dev/null
+++ b/game/client/tf2/c_tf_class_pyro.cpp
@@ -0,0 +1,44 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+#include "cbase.h"
+#include "c_tf_class_pyro.h"
+
+//=============================================================================
+//
+// Medic Data Table
+//
+BEGIN_RECV_TABLE_NOBASE( C_PlayerClassPyro, DT_PlayerClassPyroData )
+END_RECV_TABLE()
+
+BEGIN_PREDICTION_DATA_NO_BASE( C_PlayerClassPyro )
+
+ DEFINE_PRED_TYPEDESCRIPTION( m_ClassData, PlayerClassPyroData_t ),
+
+END_PREDICTION_DATA()
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+C_PlayerClassPyro::C_PlayerClassPyro( C_BaseTFPlayer *pPlayer ) :
+ C_PlayerClass( pPlayer )
+{
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+C_PlayerClassPyro::~C_PlayerClassPyro()
+{
+}
+
+
+PlayerClassPyroData_t* C_PlayerClassPyro::GetClassData()
+{
+ return &m_ClassData;
+}
+
diff --git a/game/client/tf2/c_tf_class_pyro.h b/game/client/tf2/c_tf_class_pyro.h
new file mode 100644
index 0000000..64365f4
--- /dev/null
+++ b/game/client/tf2/c_tf_class_pyro.h
@@ -0,0 +1,41 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef C_TF_CLASS_PYRO_H
+#define C_TF_CLASS_PYRO_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+
+#include "c_tf_playerclass.h"
+#include "dt_recv.h"
+
+
+class C_PlayerClassPyro : public C_PlayerClass
+{
+public:
+
+ DECLARE_CLASS( C_PlayerClassPyro, C_PlayerClass );
+ DECLARE_PREDICTABLE();
+
+
+ C_PlayerClassPyro( C_BaseTFPlayer *pPlayer );
+ virtual ~C_PlayerClassPyro();
+
+ PlayerClassPyroData_t *GetClassData();
+
+
+protected:
+
+ PlayerClassPyroData_t m_ClassData;
+};
+
+EXTERN_RECV_TABLE( DT_PlayerClassPyroData )
+
+
+#endif // C_TF_CLASS_PYRO_H
diff --git a/game/client/tf2/c_tf_class_recon.cpp b/game/client/tf2/c_tf_class_recon.cpp
new file mode 100644
index 0000000..0a615ce
--- /dev/null
+++ b/game/client/tf2/c_tf_class_recon.cpp
@@ -0,0 +1,54 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+#include "cbase.h"
+#include "c_tf_class_recon.h"
+
+//=============================================================================
+//
+// Recon Data Table
+//
+BEGIN_RECV_TABLE_NOBASE( C_PlayerClassRecon, DT_PlayerClassReconData )
+ RecvPropInt ( RECVINFO( m_ClassData.m_nJumpCount ) ),
+ RecvPropFloat ( RECVINFO( m_ClassData.m_flSuppressionJumpTime ) ),
+ RecvPropFloat ( RECVINFO( m_ClassData.m_flSuppressionImpactTime ) ),
+ RecvPropFloat ( RECVINFO( m_ClassData.m_flStickTime ) ),
+ RecvPropFloat ( RECVINFO( m_ClassData.m_flActiveJumpTime ) ),
+ RecvPropFloat ( RECVINFO( m_ClassData.m_flImpactDist ) ),
+ RecvPropVector ( RECVINFO( m_ClassData.m_vecImpactNormal ) ),
+ RecvPropVector ( RECVINFO( m_ClassData.m_vecUnstickVelocity ) ),
+ RecvPropInt ( RECVINFO( m_ClassData.m_bTrailParticles ) ),
+END_RECV_TABLE()
+
+BEGIN_PREDICTION_DATA_NO_BASE( C_PlayerClassRecon )
+
+ DEFINE_PRED_TYPEDESCRIPTION( m_ClassData, PlayerClassReconData_t ),
+
+END_PREDICTION_DATA()
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+C_PlayerClassRecon::C_PlayerClassRecon( C_BaseTFPlayer *pPlayer ) :
+ C_PlayerClass( pPlayer )
+{
+ m_ClassData.m_nJumpCount = 0;
+ m_ClassData.m_flSuppressionJumpTime = -99999;
+ m_ClassData.m_flSuppressionImpactTime = -99999;
+ m_ClassData.m_flActiveJumpTime = -99999;
+ m_ClassData.m_flStickTime = -99999;
+ m_ClassData.m_flImpactDist = -99999;
+ m_ClassData.m_vecImpactNormal.Init();
+ m_ClassData.m_vecUnstickVelocity.Init();
+ m_ClassData.m_bTrailParticles = false;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+C_PlayerClassRecon::~C_PlayerClassRecon()
+{
+}
diff --git a/game/client/tf2/c_tf_class_recon.h b/game/client/tf2/c_tf_class_recon.h
new file mode 100644
index 0000000..46d8438
--- /dev/null
+++ b/game/client/tf2/c_tf_class_recon.h
@@ -0,0 +1,37 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef C_TF_CLASS_RECON_H
+#define C_TF_CLASS_RECON_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "c_tf_playerclass.h"
+#include "TFClassData_Shared.h"
+#include "dt_recv.h"
+
+class C_PlayerClassRecon : public C_PlayerClass
+{
+
+ DECLARE_CLASS( C_PlayerClassRecon, C_PlayerClass );
+
+public:
+
+ C_PlayerClassRecon( C_BaseTFPlayer *pPlayer );
+ virtual ~C_PlayerClassRecon();
+
+ DECLARE_PREDICTABLE();
+
+ PlayerClassReconData_t *GetClassData( void ) { return &m_ClassData; }
+
+ PlayerClassReconData_t m_ClassData;
+};
+
+EXTERN_RECV_TABLE( DT_PlayerClassReconData )
+
+#endif // C_TF_CLASS_RECON_H \ No newline at end of file
diff --git a/game/client/tf2/c_tf_class_sapper.cpp b/game/client/tf2/c_tf_class_sapper.cpp
new file mode 100644
index 0000000..cc84859
--- /dev/null
+++ b/game/client/tf2/c_tf_class_sapper.cpp
@@ -0,0 +1,53 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+#include "cbase.h"
+#include "c_tf_class_sapper.h"
+
+//=============================================================================
+//
+// Sapper Data Table
+//
+BEGIN_RECV_TABLE_NOBASE( C_PlayerClassSapper, DT_PlayerClassSapperData )
+ RecvPropFloat( RECVINFO(m_flDrainedEnergy) ),
+END_RECV_TABLE()
+
+BEGIN_PREDICTION_DATA_NO_BASE( C_PlayerClassSapper )
+
+ DEFINE_PRED_TYPEDESCRIPTION( m_ClassData, PlayerClassSapperData_t ),
+
+END_PREDICTION_DATA()
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+C_PlayerClassSapper::C_PlayerClassSapper( C_BaseTFPlayer *pPlayer ) :
+ C_PlayerClass( pPlayer )
+{
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+C_PlayerClassSapper::~C_PlayerClassSapper()
+{
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+float C_PlayerClassSapper::GetDrainedEnergy( void )
+{
+ return m_flDrainedEnergy;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void C_PlayerClassSapper::DeductDrainedEnergy( float flEnergy )
+{
+ m_flDrainedEnergy = MAX( 0, m_flDrainedEnergy - flEnergy );
+}
diff --git a/game/client/tf2/c_tf_class_sapper.h b/game/client/tf2/c_tf_class_sapper.h
new file mode 100644
index 0000000..a3f7287
--- /dev/null
+++ b/game/client/tf2/c_tf_class_sapper.h
@@ -0,0 +1,45 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef C_TF_CLASS_TECHNICIAN_H
+#define C_TF_CLASS_TECHNICIAN_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "c_tf_playerclass.h"
+#include "dt_recv.h"
+
+class C_PlayerClassSapper : public C_PlayerClass
+{
+
+ DECLARE_CLASS( C_PlayerClassSapper, C_PlayerClass );
+
+public:
+
+ C_PlayerClassSapper( C_BaseTFPlayer *pPlayer );
+ virtual ~C_PlayerClassSapper();
+
+ DECLARE_PREDICTABLE();
+
+ PlayerClassSapperData_t* GetClassData( void ) { return &m_ClassData; }
+
+ // Energy handling
+ float GetDrainedEnergy( void );
+ void DeductDrainedEnergy( float flEnergy );
+
+protected:
+
+ PlayerClassSapperData_t m_ClassData;
+
+public:
+ float m_flDrainedEnergy;
+};
+
+EXTERN_RECV_TABLE( DT_PlayerClassSapperData )
+
+#endif // C_TF_CLASS_TECHNICIAN_H \ No newline at end of file
diff --git a/game/client/tf2/c_tf_class_sniper.cpp b/game/client/tf2/c_tf_class_sniper.cpp
new file mode 100644
index 0000000..e2a0449
--- /dev/null
+++ b/game/client/tf2/c_tf_class_sniper.cpp
@@ -0,0 +1,36 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+#include "cbase.h"
+#include "c_tf_class_sniper.h"
+
+//=============================================================================
+//
+// Sniper Data Table
+//
+BEGIN_RECV_TABLE_NOBASE( C_PlayerClassSniper, DT_PlayerClassSniperData )
+END_RECV_TABLE()
+
+BEGIN_PREDICTION_DATA_NO_BASE( C_PlayerClassSniper )
+
+ DEFINE_PRED_TYPEDESCRIPTION( m_ClassData, PlayerClassSniperData_t ),
+
+END_PREDICTION_DATA()
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+C_PlayerClassSniper::C_PlayerClassSniper( C_BaseTFPlayer *pPlayer ) :
+ C_PlayerClass( pPlayer )
+{
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+C_PlayerClassSniper::~C_PlayerClassSniper()
+{
+} \ No newline at end of file
diff --git a/game/client/tf2/c_tf_class_sniper.h b/game/client/tf2/c_tf_class_sniper.h
new file mode 100644
index 0000000..078624d
--- /dev/null
+++ b/game/client/tf2/c_tf_class_sniper.h
@@ -0,0 +1,38 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef C_TF_CLASS_SNIPER_H
+#define C_TF_CLASS_SNIPER_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "c_tf_playerclass.h"
+#include "dt_recv.h"
+
+class C_PlayerClassSniper : public C_PlayerClass
+{
+
+ DECLARE_CLASS( C_PlayerClassSniper, C_PlayerClass );
+
+public:
+
+ C_PlayerClassSniper( C_BaseTFPlayer *pPlayer );
+ virtual ~C_PlayerClassSniper();
+
+ DECLARE_PREDICTABLE();
+
+ PlayerClassSniperData_t *GetClassData( void ) { return &m_ClassData; }
+
+protected:
+
+ PlayerClassSniperData_t m_ClassData;
+};
+
+EXTERN_RECV_TABLE( DT_PlayerClassSniperData )
+
+#endif // C_TF_CLASS_SNIPER_H \ No newline at end of file
diff --git a/game/client/tf2/c_tf_class_support.cpp b/game/client/tf2/c_tf_class_support.cpp
new file mode 100644
index 0000000..ea85891
--- /dev/null
+++ b/game/client/tf2/c_tf_class_support.cpp
@@ -0,0 +1,36 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+#include "cbase.h"
+#include "c_tf_class_support.h"
+
+//=============================================================================
+//
+// Support Data Table
+//
+BEGIN_RECV_TABLE_NOBASE( C_PlayerClassSupport, DT_PlayerClassSupportData )
+END_RECV_TABLE()
+
+BEGIN_PREDICTION_DATA_NO_BASE( C_PlayerClassSupport )
+
+ DEFINE_PRED_TYPEDESCRIPTION( m_ClassData, PlayerClassSupportData_t ),
+
+END_PREDICTION_DATA()
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+C_PlayerClassSupport::C_PlayerClassSupport( C_BaseTFPlayer *pPlayer ) :
+ C_PlayerClass( pPlayer )
+{
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+C_PlayerClassSupport::~C_PlayerClassSupport()
+{
+} \ No newline at end of file
diff --git a/game/client/tf2/c_tf_class_support.h b/game/client/tf2/c_tf_class_support.h
new file mode 100644
index 0000000..27817cb
--- /dev/null
+++ b/game/client/tf2/c_tf_class_support.h
@@ -0,0 +1,38 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef C_TF_CLASS_SUPPORT_H
+#define C_TF_CLASS_SUPPORT_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "c_tf_playerclass.h"
+#include "dt_recv.h"
+
+class C_PlayerClassSupport : public C_PlayerClass
+{
+
+ DECLARE_CLASS( C_PlayerClassSupport, C_PlayerClass );
+
+public:
+
+ C_PlayerClassSupport( C_BaseTFPlayer *pPlayer );
+ virtual ~C_PlayerClassSupport();
+
+ DECLARE_PREDICTABLE();
+
+ PlayerClassSupportData_t *GetClassData( void ) { return &m_ClassData; }
+
+protected:
+
+ PlayerClassSupportData_t m_ClassData;
+};
+
+EXTERN_RECV_TABLE( DT_PlayerClassSupportData )
+
+#endif // C_TF_CLASS_SUPPORT_H \ No newline at end of file
diff --git a/game/client/tf2/c_tf_flare.cpp b/game/client/tf2/c_tf_flare.cpp
new file mode 100644
index 0000000..7b8b806
--- /dev/null
+++ b/game/client/tf2/c_tf_flare.cpp
@@ -0,0 +1,342 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Flare effects
+//
+// $NoKeywords: $
+//=============================================================================//
+#include "cbase.h"
+#include "dlight.h"
+#include "cmodel.h"
+#include "view.h"
+#include "clientsideeffects.h"
+#include "clienteffectprecachesystem.h"
+#include "particles_simple.h"
+#include "particlemgr.h"
+#include "IEFx.h"
+#include "fx.h"
+
+//Precahce the effects
+CLIENTEFFECT_REGISTER_BEGIN( PrecacheEffectFlares )
+CLIENTEFFECT_MATERIAL( "effects/redflare" )
+CLIENTEFFECT_MATERIAL( "effects/yellowflare" )
+CLIENTEFFECT_MATERIAL( "effects/yellowflare_noz" )
+CLIENTEFFECT_REGISTER_END()
+
+class C_SignalFlare : public C_BaseAnimating, CSimpleEmitter
+{
+
+ DECLARE_CLASS( C_SignalFlare, C_BaseAnimating );
+
+public:
+
+ DECLARE_CLIENTCLASS();
+
+ C_SignalFlare( void );
+ ~C_SignalFlare( void );
+
+ void OnDataChanged( DataUpdateType_t updateType );
+ void Update( float timeDelta );
+ void NotifyDestroyParticle( Particle* pParticle );
+ void RestoreResources( void );
+
+ float m_flDuration;
+ float m_flScale;
+ bool m_bLight;
+ bool m_bSmoke;
+
+private:
+ C_SignalFlare( const C_SignalFlare & );
+
+ SimpleParticle *m_pParticle[2];
+};
+
+IMPLEMENT_CLIENTCLASS_DT( C_SignalFlare, DT_SignalFlare, CSignalFlare )
+ RecvPropFloat( RECVINFO( m_flDuration ) ),
+ RecvPropFloat( RECVINFO( m_flScale ) ),
+ RecvPropInt( RECVINFO( m_bLight ) ),
+ RecvPropInt( RECVINFO( m_bSmoke ) ),
+END_RECV_TABLE()
+
+//-----------------------------------------------------------------------------
+// Constructor
+//-----------------------------------------------------------------------------
+C_SignalFlare::C_SignalFlare( void ) : CSimpleEmitter( "C_SignalFlare" )
+{
+ m_pParticle[0] = NULL;
+ m_pParticle[1] = NULL;
+ m_flDuration = 0.0f;
+
+ m_bLight = true;
+ m_bSmoke = true;
+
+ SetDynamicallyAllocated( false );
+}
+
+
+//-----------------------------------------------------------------------------
+// Destructor
+//-----------------------------------------------------------------------------
+C_SignalFlare::~C_SignalFlare( void )
+{
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : bool -
+//-----------------------------------------------------------------------------
+void C_SignalFlare::OnDataChanged( DataUpdateType_t updateType )
+{
+ if ( updateType == DATA_UPDATE_CREATED )
+ {
+ SetSortOrigin( GetAbsOrigin() );
+ }
+
+ BaseClass::OnDataChanged( updateType );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void C_SignalFlare::RestoreResources( void )
+{
+ if ( m_pParticle[0] == NULL )
+ {
+ m_pParticle[0] = (SimpleParticle *) AddParticle( sizeof( SimpleParticle ), GetPMaterial( "effects/redflare" ), GetAbsOrigin() );
+
+ if ( m_pParticle[0] != NULL )
+ {
+ m_pParticle[0]->m_uchColor[0] = m_pParticle[0]->m_uchColor[1] = m_pParticle[0]->m_uchColor[2] = 0;
+ m_pParticle[0]->m_flRoll = random->RandomInt( 0, 360 );
+ m_pParticle[0]->m_flRollDelta = random->RandomFloat( 1.0f, 4.0f );
+ m_pParticle[0]->m_flLifetime = 0.0f;
+ m_pParticle[0]->m_flDieTime = 10.0f;
+ }
+ else
+ {
+ assert(0);
+ }
+ }
+
+ if ( m_pParticle[1] == NULL )
+ {
+ m_pParticle[1] = (SimpleParticle *) AddParticle( sizeof( SimpleParticle ), GetPMaterial( "effects/yellowflare_noz" ), GetAbsOrigin() );
+
+ if ( m_pParticle[1] != NULL )
+ {
+ m_pParticle[1]->m_uchColor[0] = m_pParticle[1]->m_uchColor[1] = m_pParticle[1]->m_uchColor[2] = 0;
+ m_pParticle[1]->m_flRoll = random->RandomInt( 0, 360 );
+ m_pParticle[1]->m_flRollDelta = random->RandomFloat( 1.0f, 4.0f );
+ m_pParticle[1]->m_flLifetime = 0.0f;
+ m_pParticle[1]->m_flDieTime = 10.0f;
+ }
+ else
+ {
+ assert(0);
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : pParticle -
+//-----------------------------------------------------------------------------
+void C_SignalFlare::NotifyDestroyParticle( Particle *pParticle )
+{
+ if ( pParticle == m_pParticle[0] )
+ {
+ m_pParticle[0] = NULL;
+ }
+
+ if ( pParticle == m_pParticle[1] )
+ {
+ m_pParticle[1] = NULL;
+ }
+
+ CSimpleEmitter::NotifyDestroyParticle( pParticle );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : timeDelta -
+//-----------------------------------------------------------------------------
+void C_SignalFlare::Update( float timeDelta )
+{
+ CSimpleEmitter::Update( timeDelta );
+
+ //Make sure our stored resources are up to date
+ RestoreResources();
+
+ //Don't do this if the console is down
+ if ( timeDelta <= 0.0f )
+ return;
+
+ float fColor;
+ float baseScale = m_flScale;
+
+ //Account for fading out
+ if ( ( m_flDuration != -1.0f ) && ( ( m_flDuration - gpGlobals->curtime ) <= 10.0f ) )
+ {
+ baseScale *= ( ( m_flDuration - gpGlobals->curtime ) / 10.0f );
+ }
+
+ //Clamp the scale if vanished
+ if ( baseScale < 0.01f )
+ {
+ baseScale = 0.0f;
+
+ if ( m_pParticle[0] != NULL )
+ {
+ m_pParticle[0]->m_flDieTime = gpGlobals->curtime;
+ m_pParticle[0]->m_uchStartSize = m_pParticle[0]->m_uchEndSize = 0;
+ m_pParticle[0]->m_uchColor[0] = 0;
+ m_pParticle[0]->m_uchColor[1] = 0;
+ m_pParticle[0]->m_uchColor[2] = 0;
+ }
+
+ if ( m_pParticle[1] != NULL )
+ {
+ m_pParticle[1]->m_flDieTime = gpGlobals->curtime;
+ m_pParticle[1]->m_uchStartSize = m_pParticle[1]->m_uchEndSize = 0;
+ m_pParticle[1]->m_uchColor[0] = 0;
+ m_pParticle[1]->m_uchColor[1] = 0;
+ m_pParticle[1]->m_uchColor[2] = 0;
+ }
+
+ return;
+ }
+
+ //
+ // Dynamic light
+ //
+
+ if ( m_bLight )
+ {
+ dlight_t *dl= effects->CL_AllocDlight( index );
+
+ dl->origin = GetAbsOrigin();
+ dl->color.r = 255;
+ dl->color.g = dl->color.b = random->RandomInt( 32, 64 );
+ dl->radius = baseScale * random->RandomFloat( 110.0f, 128.0f );
+ dl->die = gpGlobals->curtime;
+ }
+
+ //
+ // Smoke
+ //
+
+ if ( m_bSmoke )
+ {
+ Vector smokeOrg = GetAbsOrigin();
+
+ Vector flareScreenDir = ( smokeOrg - CurrentViewOrigin() );
+ VectorNormalize( flareScreenDir );
+
+ smokeOrg = smokeOrg + ( flareScreenDir * 2.0f );
+ smokeOrg[2] += baseScale * 4.0f;
+
+ SimpleParticle *sParticle = (SimpleParticle *) AddParticle( sizeof( SimpleParticle ), g_Mat_DustPuff[1], smokeOrg );
+
+ if ( sParticle == NULL )
+ return;
+
+ sParticle->m_flLifetime = 0.0f;
+ sParticle->m_flDieTime = 1.0f;
+
+ sParticle->m_vecVelocity = Vector( random->RandomFloat( -16.0f, 16.0f ), random->RandomFloat( -16.0f, 16.0f ), random->RandomFloat( 8.0f, 16.0f ) + 32.0f );
+
+ fColor = random->RandomInt( 64, 128 );
+
+ sParticle->m_uchColor[0] = fColor+64;
+ sParticle->m_uchColor[1] = fColor;
+ sParticle->m_uchColor[2] = fColor;
+ sParticle->m_uchStartAlpha = random->RandomInt( 16, 32 );
+ sParticle->m_uchEndAlpha = 0;
+ sParticle->m_uchStartSize = random->RandomInt( 2, 4 );
+ sParticle->m_uchEndSize = sParticle->m_uchStartSize * 6.0f;
+ sParticle->m_flRoll = random->RandomInt( 0, 360 );
+ sParticle->m_flRollDelta = random->RandomFloat( -2.0f, 2.0f );
+ }
+
+ //Check for LOS
+ if ( EffectOccluded( GetAbsOrigin() ) )
+ {
+ if ( m_pParticle[0] != NULL )
+ {
+ m_pParticle[0]->m_uchColor[0] *= 0.5f;
+ m_pParticle[0]->m_uchColor[1] *= 0.5f;
+ m_pParticle[0]->m_uchColor[2] *= 0.5f;
+ }
+
+ if ( m_pParticle[1] != NULL )
+ {
+ m_pParticle[1]->m_uchColor[0] *= 0.25f;
+ m_pParticle[1]->m_uchColor[1] *= 0.25f;
+ m_pParticle[1]->m_uchColor[2] *= 0.25f;
+ }
+
+ return;
+ }
+
+ //
+ // Outer glow
+ //
+
+ Vector offset;
+
+ //Cause the base of the effect to shake
+ offset.Random( -0.5f * baseScale, 0.5f * baseScale );
+ offset += GetAbsOrigin();
+
+ if ( m_pParticle[0] != NULL )
+ {
+ m_pParticle[0]->m_Pos = offset;
+ m_pParticle[0]->m_flLifetime = 0.0f;
+ m_pParticle[0]->m_flDieTime = 2.0f;
+
+ m_pParticle[0]->m_vecVelocity.Init();
+
+ fColor = random->RandomInt( 100.0f, 128.0f );
+
+ m_pParticle[0]->m_uchColor[0] = fColor;
+ m_pParticle[0]->m_uchColor[1] = fColor;
+ m_pParticle[0]->m_uchColor[2] = fColor;
+ m_pParticle[0]->m_uchStartAlpha = fColor;
+ m_pParticle[0]->m_uchEndAlpha = fColor;
+ m_pParticle[0]->m_uchStartSize = baseScale * (float) random->RandomInt( 32, 48 );
+ m_pParticle[0]->m_uchEndSize = m_pParticle[0]->m_uchStartSize;
+ m_pParticle[0]->m_flRollDelta = 0.0f;
+
+ if ( random->RandomInt( 0, 4 ) == 3 )
+ {
+ m_pParticle[0]->m_flRoll += random->RandomInt( 2, 8 );
+ }
+ }
+
+ //
+ // Inner core
+ //
+
+ //Cause the base of the effect to shake
+ offset.Random( -1.0f * baseScale, 1.0f * baseScale );
+ offset += GetAbsOrigin();
+
+ if ( m_pParticle[1] != NULL )
+ {
+ m_pParticle[1]->m_Pos = offset;
+ m_pParticle[1]->m_flLifetime = 0.0f;
+ m_pParticle[1]->m_flDieTime = 2.0f;
+
+ m_pParticle[1]->m_vecVelocity.Init();
+
+ fColor = 255;
+
+ m_pParticle[1]->m_uchColor[0] = fColor;
+ m_pParticle[1]->m_uchColor[1] = fColor;
+ m_pParticle[1]->m_uchColor[2] = fColor;
+ m_pParticle[1]->m_uchStartAlpha = fColor;
+ m_pParticle[1]->m_uchEndAlpha = fColor;
+ m_pParticle[1]->m_uchStartSize = baseScale * (float) random->RandomInt( 2, 4 );
+ m_pParticle[1]->m_uchEndSize = m_pParticle[0]->m_uchStartSize;
+ m_pParticle[1]->m_flRoll = random->RandomInt( 0, 360 );
+ }
+}
diff --git a/game/client/tf2/c_tf_hintmanager.cpp b/game/client/tf2/c_tf_hintmanager.cpp
new file mode 100644
index 0000000..6aeec17
--- /dev/null
+++ b/game/client/tf2/c_tf_hintmanager.cpp
@@ -0,0 +1,427 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+#include "cbase.h"
+#include "c_tf_hintmanager.h"
+#include "c_tf_basehint.h"
+#include <KeyValues.h>
+#include "filesystem.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+
+// Global off switch for hint system
+static ConVar tf2_hintsystem( "tf2_hintsystem", "0", 0, "Enable interface hints in TF2." );
+static C_TFHintManager *g_pHintManager = NULL;
+
+#define HINT_DISPLAY_STATS_FILE "scripts/hintdisplaystats.txt"
+
+static float g_flLastEscapeKeyTime = -1.0f;
+//-----------------------------------------------------------------------------
+// Purpose: Helper to create panel in center and then shift toward right edge of screen
+// Input : *panel -
+// Output : static void
+//-----------------------------------------------------------------------------
+static void PositionPanel( C_TFBaseHint *panel )
+{
+ int w, h;
+ panel->GetSize( w, h );
+
+ int x = ( ScreenWidth() - w ) / 2;
+ int y = ( ScreenHeight() - h ) / 2;
+
+ panel->SetPos( x, y );
+
+ panel->SetDesiredPosition( ScreenWidth() - w - 10, y - 75 );
+}
+
+IMPLEMENT_CLIENTCLASS_DT_NOBASE(C_TFHintManager, DT_TFHintManager, CTFHintManager)
+END_RECV_TABLE()
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+C_TFHintManager::C_TFHintManager( void )
+{
+ g_pHintManager = this;
+
+ m_pkvHintSystem = new KeyValues( "HintSystem" );
+ if ( m_pkvHintSystem )
+ {
+ bool valid = m_pkvHintSystem->LoadFromFile( filesystem, "scripts//hintsystem.txt" );
+ if ( !valid )
+ {
+ m_pkvHintSystem->deleteThis();
+ m_pkvHintSystem = NULL;
+ }
+ }
+
+ m_pkvHintDisplayStats = new KeyValues( "HintDisplayStats" );
+ if ( m_pkvHintDisplayStats )
+ {
+ m_pkvHintDisplayStats->LoadFromFile( filesystem, HINT_DISPLAY_STATS_FILE );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Output : KeyValues
+//-----------------------------------------------------------------------------
+KeyValues *C_TFHintManager::GetHintKeyValues( void )
+{
+ return m_pkvHintSystem;
+}
+
+KeyValues *C_TFHintManager::GetHintDisplayStats( void )
+{
+ return m_pkvHintDisplayStats;
+}
+
+void C_TFHintManager::OnDataChanged( DataUpdateType_t updateType )
+{
+ BaseClass::OnDataChanged( updateType );
+
+ // Think right away
+ if ( updateType == DATA_UPDATE_CREATED )
+ SetNextClientThink( 0.0f );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Remove complete hints, and activate next highest priority hint
+//-----------------------------------------------------------------------------
+void C_TFHintManager::ClientThink( void )
+{
+ SetNextClientThink( gpGlobals->curtime + 1.0 );
+
+ int i;
+ int highestPriority = -1;
+ C_TFBaseHint *best = NULL;
+ bool anyVisible = false;
+
+ // See if any of the hints are completed, otherwise, store off the highest priority one
+ for ( i = m_aHints.Size() - 1; i >= 0; i-- )
+ {
+ C_TFBaseHint *hint = m_aHints[ i ];
+
+ // See if it should just be deleted
+ if ( hint && hint->GetCompleted() )
+ {
+ m_aHints.Remove( i );
+ delete hint;
+ continue;
+ }
+
+ if ( hint->IsVisible() )
+ {
+ anyVisible = true;
+ }
+
+ if ( !best || ( hint->GetPriority() > highestPriority ) )
+ {
+ highestPriority = hint->GetPriority();
+ best = hint;
+ }
+ }
+
+ // Last hint finished, show next best one
+ if ( !anyVisible )
+ {
+ // Now hide all but best one
+ for ( i = 0; i < m_aHints.Size(); i++ )
+ {
+ C_TFBaseHint *hint = m_aHints[ i ];
+ hint->SetVisible( hint == best );
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : playerIndex -
+// hintID -
+// priority -
+// entityIndex -
+//-----------------------------------------------------------------------------
+C_TFBaseHint *C_TFHintManager::AddHint( int hintID, const char *subsection, int entityIndex, int maxduplicates )
+{
+ if ( !tf2_hintsystem.GetBool() )
+ return NULL;
+
+ // Don't add the same hint more than once unless maxduplicates >= 1 has been specifically requested
+ int count = CountInstancesOfHintID( hintID );
+ if ( count > maxduplicates )
+ {
+ return NULL;
+ }
+
+ C_TFBaseHint *hint = C_TFBaseHint::CreateHint( hintID, subsection, entityIndex );
+ if ( hint )
+ {
+ // Force it to compute it's exact size
+ hint->PerformLayout();
+
+ PositionPanel( hint );
+
+ m_aHints.AddToTail( hint );
+ }
+
+ return hint;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void C_TFHintManager::ClearHints( void )
+{
+ for ( int i = 0; i < m_aHints.Size(); i++ )
+ {
+ C_TFBaseHint *hint = m_aHints[ i ];
+ delete hint;
+ }
+
+ m_aHints.RemoveAll();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : playerIndex -
+// hintID -
+//-----------------------------------------------------------------------------
+void C_TFHintManager::CompleteHint( int hintID, bool visibleOnly )
+{
+ for ( int i = m_aHints.Size() - 1; i >= 0; i-- )
+ {
+ C_TFBaseHint *hint = m_aHints[ i ];
+ if ( !hint )
+ continue;
+
+ if ( hint->GetID() != hintID )
+ continue;
+
+ if ( visibleOnly && !hint->IsVisible() )
+ continue;
+
+ delete hint;
+ m_aHints.Remove( i );
+ return;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : playerIndex -
+// hintID -
+// Output : Number of instances in list
+//-----------------------------------------------------------------------------
+int C_TFHintManager::CountInstancesOfHintID( int hintID )
+{
+ int c = 0;
+ for ( int i = m_aHints.Size() - 1; i >= 0; i-- )
+ {
+ C_TFBaseHint *hint = m_aHints[ i ];
+ if ( hint && hint->GetID() == hintID )
+ {
+ c++;
+ }
+ }
+
+ return c;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : playerIndex -
+// Output : int
+//-----------------------------------------------------------------------------
+int C_TFHintManager::GetCurrentHintID( void )
+{
+ for ( int i = m_aHints.Size() - 1; i >= 0; i-- )
+ {
+ C_TFBaseHint *hint = m_aHints[ i ];
+ if ( hint && hint->IsVisible() )
+ {
+ return hint->GetID();
+ }
+ }
+
+ return TF_HINT_UNDEFINED;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void C_TFHintManager::ResetDisplayStats( void )
+{
+ if ( !m_pkvHintDisplayStats )
+ {
+ Assert( 0 );
+ return;
+ }
+
+ KeyValues *kv = m_pkvHintDisplayStats->GetFirstSubKey();
+ while ( kv )
+ {
+ KeyValues *subKey = kv->GetFirstSubKey();
+ if ( subKey && stricmp( subKey->GetName(), "times_shown") )
+ {
+ while ( subKey )
+ {
+ subKey->SetString( "times_shown", "0" );
+ subKey = subKey->GetNextKey();
+ }
+ }
+ else
+ {
+ kv->SetString( "times_shown", "0" );
+ }
+
+ kv = kv->GetNextKey();
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : hintid -
+// 100 -
+// 1 -
+// -1 -
+//-----------------------------------------------------------------------------
+C_TFBaseHint *CreateGlobalHint( int hintid, const char *subsection /*=NULL*/, int entity /*= -1*/, int maxduplicates /*=0*/ )
+{
+ if ( !g_pHintManager )
+ {
+ return NULL;
+ }
+
+ return g_pHintManager->AddHint( hintid, subsection, entity, maxduplicates );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : hintid -
+// 100 -
+// 1 -
+// -1 -
+//-----------------------------------------------------------------------------
+C_TFBaseHint *CreateGlobalHint_Panel( vgui::Panel *targetPanel, int hintid, const char *subsection /*=NULL*/, int entity /*= -1*/, int maxduplicates /*=0*/ )
+{
+ C_TFBaseHint *hint = CreateGlobalHint( hintid, subsection, entity, maxduplicates );
+ if ( hint )
+ {
+ // Find an appropriate position near the panel
+ hint->SetHintTarget( targetPanel );
+ }
+ return hint;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Trap the escape key when a hint is showing
+// Output : Returns true if the escape key was swallowed by the hint system
+//-----------------------------------------------------------------------------
+
+// Hitting escape twice withing this amount of seconds will clear all hints pending
+#define ENTER_DOUBLETAP_TIME 1.0f
+
+bool HintSystemEscapeKey( void )
+{
+ if ( !g_pHintManager )
+ return false;
+
+ int hintID = g_pHintManager->GetCurrentHintID();
+ if ( hintID != TF_HINT_UNDEFINED )
+ {
+ bool killall = false;
+
+ float curtime = gpGlobals->curtime;
+ float dt = curtime - g_flLastEscapeKeyTime;
+
+ if ( dt < ENTER_DOUBLETAP_TIME )
+ {
+ killall = true;
+ }
+
+ g_flLastEscapeKeyTime = curtime;
+
+ if ( killall )
+ {
+ g_pHintManager->ClearHints();
+ }
+ else
+ {
+ g_pHintManager->CompleteHint( hintID, true );
+ }
+ // Swallow the escape key
+ return true;
+ }
+
+ return false;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : hindid -
+//-----------------------------------------------------------------------------
+void DestroyGlobalHint( int hintid )
+{
+ if ( !g_pHintManager )
+ return;
+
+ g_pHintManager->CompleteHint( hintid, false );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Output : KeyValues
+//-----------------------------------------------------------------------------
+KeyValues *GetHintKeyValues( void )
+{
+ if ( !g_pHintManager )
+ return NULL;
+
+ return g_pHintManager->GetHintKeyValues();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Output : KeyValues
+//-----------------------------------------------------------------------------
+KeyValues *GetHintDisplayStats( void )
+{
+ if ( !g_pHintManager )
+ return NULL;
+
+ return g_pHintManager->GetHintDisplayStats();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void ResetDisplayStats( void )
+{
+ if ( g_pHintManager )
+ {
+ g_pHintManager->ResetDisplayStats();
+ }
+}
+
+static ConCommand tf2_hintreset( "tf2_hintreset", ResetDisplayStats, 0, FCVAR_CHEAT );
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+C_TFHintManager::~C_TFHintManager( void )
+{
+ ClearHints();
+ g_pHintManager = NULL;
+ m_pkvHintSystem->deleteThis();
+ if ( m_pkvHintDisplayStats )
+ {
+ m_pkvHintDisplayStats->SaveToFile( filesystem, HINT_DISPLAY_STATS_FILE );
+ }
+ m_pkvHintDisplayStats->deleteThis();
+} \ No newline at end of file
diff --git a/game/client/tf2/c_tf_hintmanager.h b/game/client/tf2/c_tf_hintmanager.h
new file mode 100644
index 0000000..d96d80b
--- /dev/null
+++ b/game/client/tf2/c_tf_hintmanager.h
@@ -0,0 +1,87 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef C_TF_HINTMANAGER_H
+#define C_TF_HINTMANAGER_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "shareddefs.h"
+
+class C_TFBaseHint;
+class KeyValues;
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+class C_TFHintManager : public C_BaseEntity
+{
+ DECLARE_CLASS( C_TFHintManager, C_BaseEntity );
+public:
+ DECLARE_CLIENTCLASS();
+
+ C_TFHintManager( void );
+ ~C_TFHintManager( void );
+
+ virtual void OnDataChanged( DataUpdateType_t updateType );
+
+ // Override think method
+ virtual void ClientThink( void );
+
+ // Add hint to list
+ C_TFBaseHint *AddHint( int hintID, const char *subsection, int entityIndex, int maxduplicates );
+
+ // Clear hints
+ void ClearHints( void );
+ // Complete specified hint
+ void CompleteHint( int hintID, bool visibleOnly );
+ // Determine ID of hint currently being shown to player
+ int GetCurrentHintID( void );
+
+ KeyValues *GetHintKeyValues( void );
+ KeyValues *GetHintDisplayStats( void );
+
+ // Zero out all counters
+ void ResetDisplayStats( void );
+
+private:
+ // See how many of the type of hint are already being shown
+ int CountInstancesOfHintID( int hintID );
+
+ // Hint list
+ CUtlVector< C_TFBaseHint * > m_aHints;
+
+ KeyValues *m_pkvHintSystem;
+ KeyValues *m_pkvHintDisplayStats;
+};
+
+
+#include "tf_hints.h"
+
+class C_TFBaseHint;
+namespace vgui
+{
+ class Panel;
+}
+class KeyValues;
+
+// Use this when you want to allow an unlimited number of a certain type of hint
+// Just a huge number of simultaneous duplicates allowed
+#define HINTTYPE_NOLIMIT 5000
+
+C_TFBaseHint *CreateGlobalHint( int hintid, const char *subsection = NULL, int entity = -1, int maxduplicates = 0 );
+C_TFBaseHint *CreateGlobalHint_Panel( vgui::Panel *targetPanel, int hintid, const char *subsection = NULL, int entity = -1, int maxduplicates = 0 );
+void DestroyGlobalHint( int hintid );
+KeyValues *GetHintKeyValues( void );
+KeyValues *GetHintDisplayStats( void );
+
+// Returns true if hint system swallowed escape key
+bool HintSystemEscapeKey( void );
+
+
+#endif // C_TF_HINTMANAGER_H
diff --git a/game/client/tf2/c_tf_hints.cpp b/game/client/tf2/c_tf_hints.cpp
new file mode 100644
index 0000000..b12ff20
--- /dev/null
+++ b/game/client/tf2/c_tf_hints.cpp
@@ -0,0 +1,1468 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+#include "cbase.h"
+#include "c_tf_basehint.h"
+#include "tf_hints.h"
+#include "hintitemorderbase.h"
+#include "iclientmode.h"
+#include "clientmode_commander.h"
+#include "hud_technologytreedoc.h"
+#include "paneleffect.h"
+#include "techtree.h"
+#include "hintitemobjectbase.h"
+#include "c_order.h"
+#include "c_basetfplayer.h"
+#include "weapon_selection.h"
+#include <KeyValues.h>
+#include "c_weapon_builder.h"
+#include "VGuiMatSurface/IMatSystemSurface.h"
+#include "c_tf_hints.h"
+#include "c_hint_events.h"
+#include "c_tf_hintmanager.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+
+// Class Hierarchy
+// CHintItemBase -- base class for hint items
+// CHintItemOrderBase -- base class for hints derived from orders ( know how to draw
+// a white line from the hint to the order panel )
+// CHintItemObjectBase -- base class for hints that care about another object ( stores the object type name )
+// CHintGotoObject -- Contains logic that relates to the other object
+// CHintWaitBuilding
+// CHintChangeToCommander -- first level hint, doesn't rely on object, but does rely on UI manipulation
+// CHintChooseAnyTechnology -- doesn't try to draw line to order since it's in tactical view?
+//
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Change to commander view hint
+//-----------------------------------------------------------------------------
+class CHintChangeToCommander : public CHintItemOrderBase
+{
+ DECLARE_CLASS( CHintChangeToCommander, CHintItemOrderBase );
+
+public:
+ CHintChangeToCommander( vgui::Panel *parent, const char *panelName );
+ virtual void Think( void );
+};
+
+DECLARE_HINTITEMFACTORY( CHintChangeToCommander )
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *parent -
+// *panelName -
+// *text -
+// itemwidth -
+//-----------------------------------------------------------------------------
+CHintChangeToCommander::CHintChangeToCommander( vgui::Panel *parent, const char *panelName )
+: BaseClass( parent, panelName )
+{
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Set completed flag if we've made it to commander mode
+// Output : virtual void
+//-----------------------------------------------------------------------------
+void CHintChangeToCommander::Think( void )
+{
+ BaseClass::Think();
+
+ if ( g_pClientMode == ClientModeCommander() )
+ {
+ m_bCompleted = true;
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+class CHintGotoObject : public CHintItemObjectBase
+{
+ DECLARE_CLASS( CHintGotoObject, CHintItemObjectBase );
+
+public:
+ CHintGotoObject( vgui::Panel *parent, const char *panelName );
+ virtual void Think( void );
+
+private:
+ enum
+ {
+ MAX_OBJECT_TYPE = 128,
+ };
+
+ EFFECT_HANDLE m_ArrowEffect;
+
+ float m_flNextDistanceCheck;
+ IClientMode *m_pPreviousMode;
+};
+
+DECLARE_HINTITEMFACTORY( CHintGotoObject )
+
+#define ZONE_DISTANCE_CHECK_INTERVAL 0.5f
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *parent -
+// *panelName -
+//-----------------------------------------------------------------------------
+CHintGotoObject::CHintGotoObject( vgui::Panel *parent, const char *panelName )
+ : BaseClass( parent, panelName )
+{
+ m_ArrowEffect = CreateArrowEffect( this, parent, NULL );
+
+ m_flNextDistanceCheck = 0.0f;
+
+ m_pPreviousMode = NULL;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CHintGotoObject::Think( void )
+{
+ BaseClass::Think();
+
+ ClientModeTFBase *basemode = ( ClientModeTFBase * )g_pClientMode;
+ CMinimapPanel *minimap = basemode->GetMinimap();
+
+ CPanelEffect *e = g_pTF2RootPanel->FindEffect( m_ArrowEffect );
+ if ( e && minimap )
+ {
+ e->SetPanelOther( minimap );
+ }
+
+ // Check right away if we switch modes
+ if ( g_pClientMode != m_pPreviousMode )
+ {
+ m_flNextDistanceCheck = 0.0f;
+ m_pPreviousMode = g_pClientMode;
+ }
+
+ if ( gpGlobals->curtime < m_flNextDistanceCheck )
+ {
+ return;
+ }
+
+ m_flNextDistanceCheck = gpGlobals->curtime + ZONE_DISTANCE_CHECK_INTERVAL;
+
+ // The order contains the resource zone target
+ C_TFBaseHint *hint = static_cast< C_TFBaseHint * >( GetParent() );
+ if ( hint )
+ {
+ C_Order *order = dynamic_cast< C_Order * >( ClientEntityList().GetEnt( hint->GetEntity() ) );
+ if ( order )
+ {
+ C_BaseEntity *pTarget = ClientEntityList().GetEnt( order->GetTarget() );
+ if ( IsObjectOfType( pTarget ) )
+ {
+ Vector zonecenter = pTarget->WorldSpaceCenter( );
+
+ if ( e && minimap )
+ {
+ float mapx, mapy;
+
+ // Convert target center to map position
+ CMinimapPanel::MinimapPanel()->WorldToMinimap( MINIMAP_CLIP, zonecenter, mapx, mapy );
+
+ e->SetUsingOffset( true, (int)mapx, (int)mapy );
+ }
+
+ Vector delta;
+
+ C_BaseTFPlayer *local = C_BaseTFPlayer::GetLocalPlayer();
+ if ( local )
+ {
+ delta = local->GetAbsOrigin() - zonecenter;
+ if ( delta.Length() < 256.0f )
+ {
+ m_bCompleted = true;
+ }
+ }
+ }
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+class CHintDeployWeapon : public CHintItemOrderBase
+{
+ DECLARE_CLASS( CHintDeployWeapon, CHintItemOrderBase );
+
+public:
+ CHintDeployWeapon( vgui::Panel *parent, const char *panelName );
+
+ virtual void Think( void );
+
+ virtual void SetWeaponType( const char *type );
+ virtual char const *GetWeaponType( void );
+
+ virtual char const *GetKeyName( void );
+
+ virtual void SetPrintName( const char *name );
+ virtual char const *GetPrintName( void );
+
+ virtual void ParseItem( KeyValues *pKeyValues );
+
+ virtual bool CheckKeyAndValue( const char *instring, int* keylength, const char **ppOutstring );
+
+private:
+ enum
+ {
+ MAX_WEAPON_TYPE = 128,
+ MAX_WEAPON_NAME = 128,
+ };
+
+ char m_szWeaponType[ MAX_WEAPON_TYPE ];
+ char m_szPrintName[ MAX_WEAPON_NAME ];
+};
+
+DECLARE_HINTITEMFACTORY( CHintDeployWeapon )
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *parent -
+// *panelName -
+//-----------------------------------------------------------------------------
+CHintDeployWeapon::CHintDeployWeapon( vgui::Panel *parent, const char *panelName )
+: BaseClass( parent, panelName )
+{
+ SetWeaponType( "" );
+ SetPrintName( "" );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *instring -
+// keylength -
+// **ppOutstring -
+// Output : Returns true on success, false on failure.
+//-----------------------------------------------------------------------------
+bool CHintDeployWeapon::CheckKeyAndValue( const char *instring, int* keylength, const char **ppOutstring )
+{
+ if ( !Q_strnicmp( instring, "keyname", strlen( "keyname" ) ) )
+ {
+ *keylength = strlen( "keyname" );
+ *ppOutstring = GetKeyName();
+ return true;
+ }
+ else if ( !Q_strnicmp( instring, "printname", strlen( "printname" ) ) )
+ {
+ *keylength = strlen( "printname" );
+ *ppOutstring = GetPrintName();
+ return true;
+ }
+
+ return false;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *type -
+//-----------------------------------------------------------------------------
+void CHintDeployWeapon::SetWeaponType( const char *type )
+{
+ Q_strncpy( m_szWeaponType, type, MAX_WEAPON_TYPE );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Output : char const
+//-----------------------------------------------------------------------------
+const char *CHintDeployWeapon::GetWeaponType( void )
+{
+ return m_szWeaponType;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *name -
+//-----------------------------------------------------------------------------
+void CHintDeployWeapon::SetPrintName( const char *name )
+{
+ Q_strncpy( m_szPrintName, name, MAX_WEAPON_NAME );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Output : char const
+//-----------------------------------------------------------------------------
+const char *CHintDeployWeapon::GetPrintName( void )
+{
+ return m_szPrintName;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Output : char const
+//-----------------------------------------------------------------------------
+const char *CHintDeployWeapon::GetKeyName( void )
+{
+ static char keyname[ 128 ];
+
+ keyname[ 0 ] = 0;
+
+ CBaseHudWeaponSelection *pHudSelection = GetHudWeaponSelection();
+ if ( pHudSelection )
+ {
+ C_BasePlayer *player = C_BasePlayer::GetLocalPlayer();
+ if ( player )
+ {
+ for ( int slot = 0; slot < MAX_WEAPON_SLOTS; slot++ )
+ {
+ C_BaseCombatWeapon *weapon = pHudSelection->GetFirstPos( slot );
+ if ( !weapon )
+ continue;
+
+ if ( !stricmp( weapon->GetName(), GetWeaponType() ) )
+ {
+ Q_snprintf( keyname, sizeof( keyname ), GetKeyNameForBinding( VarArgs( "slot%i", slot + 1 ) ) );
+ break;
+ }
+ }
+ }
+ }
+
+ return keyname;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *pKeyValues -
+//-----------------------------------------------------------------------------
+void CHintDeployWeapon::ParseItem( KeyValues *pKeyValues )
+{
+ BaseClass::ParseItem( pKeyValues );
+
+ const char *type = pKeyValues->GetString( "weapon", "" );
+ if ( type )
+ {
+ SetWeaponType( type );
+ }
+
+ const char *printname = pKeyValues->GetString( "printname", "" );
+ if ( printname )
+ {
+ SetPrintName( printname );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CHintDeployWeapon::Think( void )
+{
+ BaseClass::Think();
+
+ C_BaseTFPlayer *player = C_BaseTFPlayer::GetLocalPlayer();
+ if ( !player )
+ return;
+
+ // Get the weapon selection Hud Element
+ CBaseHudWeaponSelection *pHudSelection = GetHudWeaponSelection();
+ // Make sure it's not still active
+ if ( pHudSelection->IsActive() )
+ return;
+
+ C_BaseCombatWeapon *weapon = GetActiveWeapon();
+ if ( !weapon )
+ return;
+
+ if ( !stricmp( weapon->GetClientClass()->m_pNetworkName, "CWeaponBuilder" ) )
+ {
+ m_bCompleted = true;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+class CHintStartPlacing : public CHintItemOrderBase
+{
+ DECLARE_CLASS( CHintStartPlacing, CHintItemOrderBase );
+
+public:
+ CHintStartPlacing( vgui::Panel *parent, const char *panelName );
+
+ virtual void Think( void );
+private:
+};
+
+DECLARE_HINTITEMFACTORY( CHintStartPlacing )
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *parent -
+// *panelName -
+//-----------------------------------------------------------------------------
+CHintStartPlacing::CHintStartPlacing( vgui::Panel *parent, const char *panelName )
+: BaseClass( parent, panelName )
+{
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CHintStartPlacing::Think( void )
+{
+ BaseClass::Think();
+
+ C_WeaponBuilder *builder = dynamic_cast< C_WeaponBuilder * >( GetActiveWeapon() );
+ if ( builder && builder->IsPlacingObject() )
+ {
+ m_bCompleted = true;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+class CHintStartBuilding : public CHintItemOrderBase
+{
+ DECLARE_CLASS( CHintStartBuilding, CHintItemOrderBase );
+
+public:
+ CHintStartBuilding( vgui::Panel *parent, const char *panelName );
+
+ virtual void Think( void );
+private:
+};
+
+DECLARE_HINTITEMFACTORY( CHintStartBuilding )
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *parent -
+// *panelName -
+//-----------------------------------------------------------------------------
+CHintStartBuilding::CHintStartBuilding( vgui::Panel *parent, const char *panelName )
+ : BaseClass( parent, panelName )
+{
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CHintStartBuilding::Think( void )
+{
+ BaseClass::Think();
+
+ C_WeaponBuilder *builder = dynamic_cast< C_WeaponBuilder * >( GetActiveWeapon() );
+ if ( builder && builder->IsBuildingObject() )
+ {
+ m_bCompleted = true;
+ }
+}
+
+#define CHECK_FOR_BUILDING_INTERVAL 1.0f
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+class CHintWaitBuilding : public CHintItemObjectBase
+{
+ DECLARE_CLASS( CHintWaitBuilding, CHintItemObjectBase );
+
+public:
+ CHintWaitBuilding( vgui::Panel *parent, const char *panelName );
+
+ virtual void Think( void );
+private:
+
+ float m_flNextCheck;
+};
+
+
+DECLARE_HINTITEMFACTORY( CHintWaitBuilding )
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *parent -
+// *panelName -
+//-----------------------------------------------------------------------------
+CHintWaitBuilding::CHintWaitBuilding( vgui::Panel *parent, const char *panelName )
+ : BaseClass( parent, panelName )
+{
+ m_flNextCheck = 0.0f;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CHintWaitBuilding::Think( void )
+{
+ BaseClass::Think();
+
+ if ( !GetActive() )
+ return;
+
+ C_BaseTFPlayer *player = C_BaseTFPlayer::GetLocalPlayer();
+ if ( !player )
+ return;
+
+ if ( gpGlobals->curtime < m_flNextCheck )
+ return;
+
+ m_flNextCheck = gpGlobals->curtime + CHECK_FOR_BUILDING_INTERVAL;
+
+ // Find resource zone
+ ClientEntityHandle_t e = ClientEntityList().FirstHandle();
+ for ( ; e != ClientEntityList().InvalidHandle(); e = ClientEntityList().NextHandle( e ) )
+ {
+ C_BaseEntity *ent = C_BaseEntity::Instance( e );
+ if ( !ent )
+ continue;
+
+ if ( IsObjectOfType( ent ) )
+ {
+ C_BaseObject *obj = static_cast< C_BaseObject * >( ent );
+
+ Assert( obj );
+
+ if ( obj->GetTeamNumber() == player->GetTeamNumber() && obj->IsOwnedByLocalPlayer() )
+ {
+ m_bCompleted = true;
+ break;
+ }
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+class CHintBuilderSelection : public CHintItemOrderBase
+{
+ DECLARE_CLASS( CHintBuilderSelection, CHintItemOrderBase );
+
+public:
+ CHintBuilderSelection( vgui::Panel *parent, const char *panelName );
+
+ virtual void Think( void );
+ virtual void SetSelection( const char *type );
+ virtual char const *GetSelection( void );
+
+ virtual void ParseItem( KeyValues *pKeyValues );
+
+ virtual bool CheckKeyAndValue( const char *instring, int* keylength, const char **ppOutstring );
+
+private:
+ enum
+ {
+ MAX_SELECTION_NAME = 128,
+ };
+
+ char m_szSelection[ MAX_SELECTION_NAME ];
+};
+
+DECLARE_HINTITEMFACTORY( CHintBuilderSelection )
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *parent -
+// *panelName -
+//-----------------------------------------------------------------------------
+CHintBuilderSelection::CHintBuilderSelection( vgui::Panel *parent, const char *panelName )
+ : BaseClass( parent, panelName )
+{
+ SetSelection( "" );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *instring -
+// keylength -
+// **ppOutstring -
+// Output : Returns true on success, false on failure.
+//-----------------------------------------------------------------------------
+bool CHintBuilderSelection::CheckKeyAndValue( const char *instring, int* keylength, const char **ppOutstring )
+{
+ if ( !Q_strnicmp( instring, "selection", strlen( "selection" ) ) )
+ {
+ *keylength = strlen( "selection" );
+ *ppOutstring = GetSelection();
+ return true;
+ }
+
+ return BaseClass::CheckKeyAndValue( instring, keylength, ppOutstring );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *selection -
+//-----------------------------------------------------------------------------
+void CHintBuilderSelection::SetSelection( const char *selection )
+{
+ Q_strncpy( m_szSelection, selection, MAX_SELECTION_NAME );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Output : char const
+//-----------------------------------------------------------------------------
+const char *CHintBuilderSelection::GetSelection( void )
+{
+ return m_szSelection;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *pKeyValues -
+//-----------------------------------------------------------------------------
+void CHintBuilderSelection::ParseItem( KeyValues *pKeyValues )
+{
+ BaseClass::ParseItem( pKeyValues );
+
+ const char *selection = pKeyValues->GetString( "selection", "" );
+ if ( selection )
+ {
+ SetSelection( selection );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CHintBuilderSelection::Think( void )
+{
+ BaseClass::Think();
+
+ C_BaseTFPlayer *player = C_BaseTFPlayer::GetLocalPlayer();
+ if ( !player )
+ return;
+
+ C_WeaponBuilder *builder = dynamic_cast< C_WeaponBuilder * >( GetActiveWeapon() );
+ if ( !builder )
+ return;
+
+ const char *selection = builder->GetCurrentSelectionObjectName();
+ if ( !selection )
+ return;
+
+ if ( !stricmp( selection, GetSelection() ) )
+ {
+ m_bCompleted = true;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+class CHintBuilderStartAction : public CHintItemOrderBase
+{
+ DECLARE_CLASS( CHintBuilderStartAction, CHintItemOrderBase );
+
+public:
+ CHintBuilderStartAction( vgui::Panel *parent, const char *panelName );
+
+ virtual void Think( void );
+ virtual void SetAction( const char *type );
+ virtual char const *GetAction( void );
+
+ virtual void ParseItem( KeyValues *pKeyValues );
+
+ virtual bool CheckKeyAndValue( const char *instring, int* keylength, const char **ppOutstring );
+
+private:
+ enum
+ {
+ MAX_ACTION_NAME = 128,
+ };
+
+ char m_szAction[ MAX_ACTION_NAME ];
+};
+
+DECLARE_HINTITEMFACTORY( CHintBuilderStartAction )
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *parent -
+// *panelName -
+//-----------------------------------------------------------------------------
+CHintBuilderStartAction::CHintBuilderStartAction( vgui::Panel *parent, const char *panelName )
+ : BaseClass( parent, panelName )
+{
+ SetAction( "" );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *instring -
+// keylength -
+// **ppOutstring -
+// Output : Returns true on success, false on failure.
+//-----------------------------------------------------------------------------
+bool CHintBuilderStartAction::CheckKeyAndValue( const char *instring, int* keylength, const char **ppOutstring )
+{
+ if ( !Q_strnicmp( instring, "action", strlen( "action" ) ) )
+ {
+ *keylength = strlen( "action" );
+ *ppOutstring = GetAction();
+ return true;
+ }
+
+ return BaseClass::CheckKeyAndValue( instring, keylength, ppOutstring );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *action -
+//-----------------------------------------------------------------------------
+void CHintBuilderStartAction::SetAction( const char *action )
+{
+ Q_strncpy( m_szAction, action, MAX_ACTION_NAME );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Output : char const
+//-----------------------------------------------------------------------------
+const char *CHintBuilderStartAction::GetAction( void )
+{
+ return m_szAction;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *pKeyValues -
+//-----------------------------------------------------------------------------
+void CHintBuilderStartAction::ParseItem( KeyValues *pKeyValues )
+{
+ BaseClass::ParseItem( pKeyValues );
+
+ const char *action = pKeyValues->GetString( "action", "" );
+ if ( action )
+ {
+ SetAction( action );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CHintBuilderStartAction::Think( void )
+{
+ BaseClass::Think();
+
+ C_BaseTFPlayer *player = C_BaseTFPlayer::GetLocalPlayer();
+ if ( !player )
+ return;
+
+ C_WeaponBuilder *builder = dynamic_cast< C_WeaponBuilder * >( GetActiveWeapon() );
+ if ( !builder )
+ return;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: A fake hud element used to force the weapon hud element to draw when it's
+// not actually active
+//-----------------------------------------------------------------------------
+class CHudWeaponFlashHelper : public CHudElement, public vgui::Panel
+{
+ DECLARE_CLASS_SIMPLE( CHudWeaponFlashHelper, vgui::Panel );
+public:
+ CHudWeaponFlashHelper( const char *name );
+
+ virtual void Init( void );
+ virtual bool ShouldDraw( void );
+ virtual void Paint();
+ virtual void ApplySchemeSettings( vgui::IScheme *scheme );
+
+ // Associate a weapon
+ void SetFlashWeapon( C_BaseCombatWeapon *weapon );
+
+ // Start/stop flashing
+ void StartFlashing( void );
+ void StopFlashing( void );
+
+ // Get position of weapon icon
+ void GetWeaponIconBounds( C_BaseCombatWeapon *weapon, int& x, int& y, int& w, int& h );
+
+ // Is player using the regular weapon selection UI?
+ bool IsWeaponSelectionActive( void );
+
+private:
+
+ // Currently flashing
+ bool m_bFlashing;
+
+ // The weapon to highlight
+ EHANDLE m_hWeapon;
+
+ // The actual weapon selection hud element
+ CBaseHudWeaponSelection *m_pWeaponSelection;
+};
+
+DECLARE_HUDELEMENT( CHudWeaponFlashHelper )
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *name -
+//-----------------------------------------------------------------------------
+CHudWeaponFlashHelper::CHudWeaponFlashHelper( const char *name )
+ : CHudElement( name ), BaseClass( NULL, "HudWeaponFlashHelper" )
+{
+ vgui::Panel *pParent = g_pClientMode->GetViewport();
+ SetParent( pParent );
+
+ m_bFlashing = false;
+ m_pWeaponSelection = NULL;
+
+ SetHiddenBits( HIDEHUD_MISCSTATUS | HIDEHUD_PLAYERDEAD );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CHudWeaponFlashHelper::Init( void )
+{
+ CHudElement::Init();
+
+ m_pWeaponSelection = GetHudWeaponSelection();
+ Assert( m_pWeaponSelection );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+bool CHudWeaponFlashHelper::ShouldDraw( void )
+{
+ return ( CHudElement::ShouldDraw() && m_bFlashing && m_pWeaponSelection );
+}
+
+void CHudWeaponFlashHelper::ApplySchemeSettings( vgui::IScheme *scheme )
+{
+ BaseClass::ApplySchemeSettings( scheme );
+
+ SetPaintBackgroundEnabled( false );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CHudWeaponFlashHelper::Paint()
+{
+ // Stop immediately if user starts to choose weapons
+ if ( m_pWeaponSelection->IsActive() )
+ {
+ StopFlashing();
+ return;
+ }
+
+ if ( g_pClientMode == ClientModeCommander() )
+ return;
+
+ C_BaseCombatWeapon *w = ( C_BaseCombatWeapon * )( (C_BaseEntity *)m_hWeapon );
+ if ( !w )
+ return;
+
+ C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
+ if ( !pPlayer )
+ return;
+
+ // Redo drawing of Weapon Menu
+ m_pWeaponSelection->DrawWList( pPlayer, w, true, EFFECT_R, EFFECT_G, EFFECT_B, EFFECT_A );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *weapon -
+//-----------------------------------------------------------------------------
+void CHudWeaponFlashHelper::SetFlashWeapon( C_BaseCombatWeapon *weapon )
+{
+ m_hWeapon = weapon;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CHudWeaponFlashHelper::StartFlashing( void )
+{
+ m_bFlashing = true;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CHudWeaponFlashHelper::StopFlashing( void )
+{
+ m_bFlashing = false;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *weapon -
+// x -
+// y -
+// w -
+// h -
+//-----------------------------------------------------------------------------
+void CHudWeaponFlashHelper::GetWeaponIconBounds( C_BaseCombatWeapon *weapon, int& x, int& y,int& w, int& h )
+{
+ x = y = w = h = 0;
+
+ if ( !m_pWeaponSelection || !weapon )
+ return;
+
+ C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
+ if ( !pPlayer )
+ {
+ return;
+ }
+
+ wrect_t outrect;
+ if ( !m_pWeaponSelection->ComputeRect( pPlayer, weapon, &outrect ) )
+ return;
+
+ x = outrect.left;
+ y = outrect.top;
+ w = outrect.right - outrect.left;
+ h = outrect.bottom - outrect.top;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Output : Returns true on success, false on failure.
+//-----------------------------------------------------------------------------
+bool CHudWeaponFlashHelper::IsWeaponSelectionActive( void )
+{
+ if ( m_pWeaponSelection && m_pWeaponSelection->IsActive() )
+ return true;
+
+ return false;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Change to commander view hint
+//-----------------------------------------------------------------------------
+class CHintHudWeaponFlash : public CHintItemBase
+{
+ DECLARE_CLASS( CHintHudWeaponFlash, CHintItemBase );
+
+public:
+ CHintHudWeaponFlash( vgui::Panel *parent, const char *panelName );
+ ~CHintHudWeaponFlash( void );
+
+ virtual void SetKeyValue( const char *key, const char *value );
+
+ void SetWeaponName( const char *name );
+ char const *GetWeaponName( void );
+
+ virtual bool CheckKeyAndValue( const char *instring, int* keylength, const char **ppOutstring );
+
+ virtual void SetActive( bool bActive );
+
+ virtual void Think( void );
+
+private:
+ C_BaseCombatWeapon *GetWeaponOfType( const char *type );
+
+ enum
+ {
+ MAX_WEAPON_NAME = 128,
+ };
+
+ bool m_bWeaponSet;
+
+ EHANDLE m_hWeapon;
+
+ char m_szWeaponName[ MAX_WEAPON_NAME ];
+
+ CHudWeaponFlashHelper *m_pWeaponFlashHelper;
+
+ EFFECT_HANDLE m_hLineEffect;
+};
+
+DECLARE_HINTITEMFACTORY( CHintHudWeaponFlash )
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *parent -
+// *panelName -
+// *text -
+// itemwidth -
+//-----------------------------------------------------------------------------
+CHintHudWeaponFlash::CHintHudWeaponFlash( vgui::Panel *parent, const char *panelName )
+: BaseClass( parent, panelName )
+{
+ m_bWeaponSet = false;
+ SetWeaponName( "" );
+ m_pWeaponFlashHelper = NULL;
+ m_hLineEffect = EFFECT_INVALID_HANDLE;
+
+ CreateFlashEffect( this, parent );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+CHintHudWeaponFlash::~CHintHudWeaponFlash( void )
+{
+ if ( m_pWeaponFlashHelper )
+ {
+ m_pWeaponFlashHelper->StopFlashing();
+ m_pWeaponFlashHelper->SetFlashWeapon( NULL );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *instring -
+// keylength -
+// **ppOutstring -
+// Output : Returns true on success, false on failure.
+//-----------------------------------------------------------------------------
+bool CHintHudWeaponFlash::CheckKeyAndValue( const char *instring, int* keylength, const char **ppOutstring )
+{
+ if ( !Q_strnicmp( instring, "weapon", strlen( "weapon" ) ) )
+ {
+ *keylength = strlen( "weapon" );
+ *ppOutstring = GetWeaponName();
+ return true;
+ }
+
+ return false;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Output : char const
+//-----------------------------------------------------------------------------
+C_BaseCombatWeapon *CHintHudWeaponFlash::GetWeaponOfType( const char *type )
+{
+ CBaseHudWeaponSelection *pHudSelection = GetHudWeaponSelection();
+ if ( !pHudSelection )
+ return NULL;
+
+ C_BasePlayer *player = C_BasePlayer::GetLocalPlayer();
+ if ( player )
+ {
+ for ( int slot = 0; slot < MAX_WEAPON_SLOTS; slot++ )
+ {
+ for ( int iPos = 0; iPos < MAX_WEAPON_POSITIONS; iPos++ )
+ {
+ C_BaseCombatWeapon *weapon = pHudSelection->GetWeaponInSlot( slot, iPos );
+ if ( !weapon )
+ continue;
+
+ if ( !stricmp( weapon->GetName(), type ) )
+ {
+ return weapon;
+ }
+ }
+ }
+ }
+
+ return NULL;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *key -
+// *value -
+//-----------------------------------------------------------------------------
+void CHintHudWeaponFlash::SetKeyValue( const char *key, const char *value )
+{
+ BaseClass::SetKeyValue( key, value );
+
+ if ( !stricmp( key, "weapon" ) )
+ {
+ SetWeaponName( value );
+
+ ComputeTitle();
+ }
+ else if ( !stricmp( key, "weapontype" ) )
+ {
+ // Find the weapon itself
+ C_BaseCombatWeapon *w = GetWeaponOfType( value );
+ if ( w )
+ {
+ m_hWeapon = w;
+
+ // Create open up hud effect, etc.
+ m_pWeaponFlashHelper = GET_HUDELEMENT( CHudWeaponFlashHelper );
+ if ( m_pWeaponFlashHelper )
+ {
+ m_pWeaponFlashHelper->SetFlashWeapon( w );
+
+ int x, y, wide, tall;
+
+ m_pWeaponFlashHelper->GetWeaponIconBounds( w, x, y, wide, tall );
+
+ C_TFBaseHint *hint = static_cast< C_TFBaseHint * >( GetParent() );
+
+ m_hLineEffect = CreateAxialLineEffectToRect( this, hint, x, y, wide, tall );
+
+ hint->SetDesiredPosition( x, y + tall + 50 );
+ }
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CHintHudWeaponFlash::Think( void )
+{
+ BaseClass::Think();
+
+ if ( !m_pWeaponFlashHelper )
+ return;
+
+ if ( m_pWeaponFlashHelper->IsWeaponSelectionActive() )
+ {
+ m_bCompleted = true;
+ }
+
+ bool incommander = ( g_pClientMode == ClientModeCommander() );
+
+ CPanelEffect *effect = g_pTF2RootPanel->FindEffect( m_hLineEffect );
+ if ( effect )
+ {
+ effect->SetVisible( !incommander );
+
+ C_BaseCombatWeapon *w = static_cast< C_BaseCombatWeapon * >( ( C_BaseEntity * )m_hWeapon );
+
+ // Update target rectangle
+ if ( w )
+ {
+ int x, y, wide, tall;
+
+ m_pWeaponFlashHelper->GetWeaponIconBounds( w, x, y, wide, tall );
+
+ effect->SetTargetRect( x, y, wide, tall );
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : bActive -
+//-----------------------------------------------------------------------------
+void CHintHudWeaponFlash::SetActive( bool bActive )
+{
+ BaseClass::SetActive( bActive );
+
+ if ( !m_pWeaponFlashHelper )
+ return;
+
+ if ( bActive )
+ {
+ m_pWeaponFlashHelper->StartFlashing();
+ }
+ else
+ {
+ m_pWeaponFlashHelper->StopFlashing();
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *name -
+//-----------------------------------------------------------------------------
+void CHintHudWeaponFlash::SetWeaponName( const char *name )
+{
+ Q_strncpy( m_szWeaponName, name, MAX_WEAPON_NAME );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Output : char const
+//-----------------------------------------------------------------------------
+const char *CHintHudWeaponFlash::GetWeaponName( void )
+{
+ return m_szWeaponName;
+}
+
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+struct FUNCTIONLIST_t
+{
+ const char *name;
+ HINTCOMPLETIONFUNCTION pfn;
+};
+
+static FUNCTIONLIST_t g_CompletionFunctions[]=
+{
+ { NULL, NULL },
+};
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *name -
+// Output : HINTCOMPLETIONFUNCTION
+//-----------------------------------------------------------------------------
+HINTCOMPLETIONFUNCTION LookupCompletionFunction( const char *name )
+{
+ int i = 0;
+ while ( 1 )
+ {
+ FUNCTIONLIST_t *f = &g_CompletionFunctions[ i ];
+ if ( !f->name )
+ break;
+
+ if ( !stricmp( f->name, name ) )
+ {
+ return f->pfn;
+ }
+ i++;
+ }
+
+ return NULL;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+struct HINTITEM_t
+{
+ const char *name;
+ CHintItemBase *( *pfn )( vgui::Panel *parent, const char *name );
+};
+
+static HINTITEM_t g_HintItems[]=
+{
+ { "CHintChangeToCommander", GET_HINTITEMFACTORY_NAME( CHintChangeToCommander ) },
+ { "CHintGotoObject", GET_HINTITEMFACTORY_NAME( CHintGotoObject ) },
+ { "CHintDeployWeapon", GET_HINTITEMFACTORY_NAME( CHintDeployWeapon ) },
+ { "CHintStartPlacing", GET_HINTITEMFACTORY_NAME( CHintStartPlacing ) },
+ { "CHintStartBuilding", GET_HINTITEMFACTORY_NAME( CHintStartBuilding ) },
+ { "CHintWaitBuilding", GET_HINTITEMFACTORY_NAME( CHintWaitBuilding ) },
+ { "CHintBuilderSelection", GET_HINTITEMFACTORY_NAME( CHintBuilderSelection ) },
+ { "CHintBuilderStartAction", GET_HINTITEMFACTORY_NAME( CHintBuilderStartAction ) },
+ { "CHintHudWeaponFlash", GET_HINTITEMFACTORY_NAME( CHintHudWeaponFlash ) },
+ { NULL, NULL },
+};
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *parent -
+// *name -
+// Output : CHintItemBase
+//-----------------------------------------------------------------------------
+CHintItemBase *CreateHintItem( vgui::Panel *parent, const char *name )
+{
+ int i = 0;
+ while ( 1 )
+ {
+ HINTITEM_t *hi = &g_HintItems[ i ];
+ if ( !hi->name )
+ break;
+
+ if ( !stricmp( hi->name, name ) )
+ {
+ if ( hi->pfn )
+ {
+ return (*hi->pfn)( parent, name );
+ }
+ else
+ {
+ Assert( !"Missing function pointer in CreateHintItem table!" );
+ return NULL;
+ }
+ }
+ i++;
+ }
+
+ return NULL;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+
+CHintData g_HintDatas[] =
+{
+ // Vote
+ { "TF_HINT_VOTEFORTECHNOLOGY", TF_HINT_VOTEFORTECHNOLOGY, 0, NULL, -1 },
+
+ // Build
+ { "TF_HINT_BUILDRESOURCEPUMP", TF_HINT_BUILDRESOURCEPUMP, 0, HintEventFn_BuildObject, OBJ_RESOURCEPUMP },
+ { "TF_HINT_BUILDSENTRYGUN_PLASMA", TF_HINT_BUILDSENTRYGUN_PLASMA, 0, HintEventFn_BuildObject, OBJ_SENTRYGUN_PLASMA },
+
+ // Object interaction
+ { "TF_HINT_REPAIROBJECT", TF_HINT_REPAIROBJECT, 0, NULL, -1 },
+
+ // Technology discovery
+ { "TF_HINT_NEWTECHNOLOGY", TF_HINT_NEWTECHNOLOGY, 0, NULL, -1 },
+ { "TF_HINT_WEAPONRECEIVED", TF_HINT_WEAPONRECEIVED, 0, NULL, -1 },
+
+ // Sentinal
+ { NULL, 0, 0, NULL, -1 },
+};
+
+
+int GetNumHintDatas()
+{
+ return ARRAYSIZE( g_HintDatas );
+}
+
+
+CHintData* GetHintData( int i )
+{
+ return &g_HintDatas[i];
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : id -
+// Output : char const
+//-----------------------------------------------------------------------------
+const char *LookupHintName( int id )
+{
+ int i = 0;
+ while ( 1 )
+ {
+ CHintData *h = &g_HintDatas[ i ];
+ if ( !h->name )
+ break;
+
+ if ( h->id == id )
+ {
+ return h->name;
+ }
+
+ i++;
+ }
+
+ return NULL;
+}
+
+DECLARE_HINTFACTORY( C_TFBaseHint )
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+typedef struct
+{
+ const char *name;
+ C_TFBaseHint *( *pfn )( int id, int entity );
+}
+HINT_t;
+
+static HINT_t g_Hints[]=
+{
+ { "C_TFBaseHint", GET_HINTFACTORY_NAME( C_TFBaseHint ) },
+ { NULL, NULL },
+};
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *name -
+// id -
+// entity -
+// Output : C_TFBaseHint
+//-----------------------------------------------------------------------------
+C_TFBaseHint *FactoryCreateHint( const char *name, int id, int entity )
+{
+ int i = 0;
+ while ( 1 )
+ {
+ HINT_t *hi = &g_Hints[ i ];
+ if ( !hi->name )
+ break;
+
+ if ( !stricmp( hi->name, name ) )
+ {
+ if ( hi->pfn )
+ {
+ return (*hi->pfn)( id, entity );
+ }
+ else
+ {
+ Assert( !"Missing function pointer in FactoryCreateHint table!" );
+ return NULL;
+ }
+ }
+ i++;
+ }
+
+ return NULL;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Generic factory for hints
+// Input : id -
+// entity -
+// Output : C_TFBaseHint
+//-----------------------------------------------------------------------------
+C_TFBaseHint *C_TFBaseHint::CreateHint( int id, const char *subsection, int entity )
+{
+ C_TFBaseHint *hint = NULL;
+ const char *hintname = LookupHintName( id );
+ if ( !hintname )
+ return NULL;
+
+ // See if we should see this hint any more
+ KeyValues *pkvStats = GetHintDisplayStats();
+ if ( pkvStats )
+ {
+ KeyValues *pkvStatSection = pkvStats->FindKey( hintname, true );
+ if ( pkvStatSection )
+ {
+ if ( subsection && subsection[0] )
+ {
+ pkvStatSection = pkvStatSection->FindKey( subsection, true );
+ }
+ }
+
+ if ( !pkvStatSection )
+ {
+ Assert( !"C_TFBaseHint::CreateHint: Problem creating hint subsection" );
+ return NULL;
+ }
+
+ int times_shown = pkvStatSection->GetInt( "times_shown", 0 );
+ pkvStatSection->SetString( "times_shown", VarArgs( "%i", times_shown ) );
+
+ int times_max = pkvStatSection->GetInt( "times_max", 3 );
+ pkvStatSection->SetString( "times_max", VarArgs( "%i", times_max ) );
+
+ if ( times_shown >= times_max )
+ return NULL;
+
+ // Remember that we've seen it again
+ times_shown++;
+ pkvStatSection->SetString( "times_shown", VarArgs( "%i", times_shown ) );
+ }
+
+ // Ask Hint manager API for key values
+ KeyValues *pkvHintSystem = GetHintKeyValues();
+ if ( pkvHintSystem )
+ {
+ //
+ // Parse the list of hints looking for name
+ KeyValues *pkvHint = pkvHintSystem->FindKey( hintname );
+ if ( pkvHint )
+ {
+ // Use classname string to construct hint
+ const char *defaultclass = "C_TFBaseHint";
+ const char *classname = pkvHint->GetString( "classname" );
+ if ( !classname || !classname[ 0 ] || !stricmp( classname, "default" ) )
+ {
+ classname = defaultclass;
+ }
+
+ hint = FactoryCreateHint( classname, id, entity );
+ if ( hint )
+ {
+ hint->ParseFromData( pkvHint );
+ }
+ }
+ }
+
+ return hint;
+}
diff --git a/game/client/tf2/c_tf_hints.h b/game/client/tf2/c_tf_hints.h
new file mode 100644
index 0000000..57615bf
--- /dev/null
+++ b/game/client/tf2/c_tf_hints.h
@@ -0,0 +1,38 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef C_TF_HINTS_H
+#define C_TF_HINTS_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+
+class C_HintEvent_Base;
+class CHintData;
+
+// The HINTNAME_t structures are where data and code are registered for each hint type.
+typedef void (*HintEventFn)( CHintData *pData, C_HintEvent_Base *pHint );
+
+
+class CHintData
+{
+public:
+ char *name;
+ int id;
+ int timesseen;
+
+ HintEventFn m_pEventFn;
+ int m_ObjectType; // If this is a hint about an object, this is the object type.
+};
+
+
+extern int GetNumHintDatas();
+extern CHintData* GetHintData( int i );
+
+
+#endif // C_TF_HINTS_H
diff --git a/game/client/tf2/c_tf_playerclass.cpp b/game/client/tf2/c_tf_playerclass.cpp
new file mode 100644
index 0000000..b907539
--- /dev/null
+++ b/game/client/tf2/c_tf_playerclass.cpp
@@ -0,0 +1,65 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Auto Repair
+//
+// $NoKeywords: $
+//=============================================================================//
+#include "cbase.h"
+#include "c_tf_class_commando.h"
+#include "c_tf_class_defender.h"
+#include "c_tf_class_escort.h"
+#include "c_tf_class_infiltrator.h"
+#include "c_tf_class_medic.h"
+#include "c_tf_class_recon.h"
+#include "c_tf_class_sniper.h"
+#include "c_tf_class_support.h"
+#include "c_tf_class_sapper.h"
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+C_PlayerClass::C_PlayerClass( C_BaseTFPlayer *pPlayer )
+{
+ // Save peer.
+ m_pPlayer = pPlayer;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+C_PlayerClass::~C_PlayerClass()
+{
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+C_PlayerClass *C_PlayerClass::Create( C_BaseTFPlayer *pPlayer, int iClassType )
+{
+ // Create the class type
+ switch ( iClassType )
+ {
+ case TFCLASS_COMMANDO: { return ( new C_PlayerClassCommando( pPlayer ) ); }
+ case TFCLASS_DEFENDER: { return ( new C_PlayerClassDefender( pPlayer ) ); }
+ case TFCLASS_ESCORT: { return ( new C_PlayerClassEscort( pPlayer ) ); }
+ case TFCLASS_INFILTRATOR: { return ( new C_PlayerClassInfiltrator( pPlayer ) ); }
+ case TFCLASS_MEDIC: { return ( new C_PlayerClassMedic( pPlayer ) ); }
+ case TFCLASS_RECON: { return ( new C_PlayerClassRecon( pPlayer ) ); }
+ case TFCLASS_SNIPER: { return ( new C_PlayerClassSniper( pPlayer ) ); }
+ case TFCLASS_SUPPORT: { return ( new C_PlayerClassSupport( pPlayer ) ); }
+ case TFCLASS_SAPPER: { return ( new C_PlayerClassSapper( pPlayer ) ); }
+ default: { return NULL; }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void C_PlayerClass::Destroy( C_PlayerClass *pPlayerClass )
+{
+ if ( pPlayerClass )
+ {
+ delete pPlayerClass;
+ }
+}
diff --git a/game/client/tf2/c_tf_playerclass.h b/game/client/tf2/c_tf_playerclass.h
new file mode 100644
index 0000000..36e4317
--- /dev/null
+++ b/game/client/tf2/c_tf_playerclass.h
@@ -0,0 +1,50 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Auto Repair
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef C_TF_PLAYERCLASS_H
+#define C_TF_PLAYERCLASS_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+class C_BaseTFPlayer;
+class CUserCmd;
+
+class C_PlayerClass
+{
+public:
+
+ DECLARE_CLASS_NOBASE( C_PlayerClass );
+
+ C_PlayerClass( C_BaseTFPlayer *pPlayer );
+ ~C_PlayerClass();
+
+ static C_PlayerClass *Create( C_BaseTFPlayer *pPlayer, int iClassType );
+ static void Destroy( C_PlayerClass *pPlayerClass );
+
+ virtual void PreClassThink( void ) {};
+ virtual void ClassThink( void ) {};
+ virtual void PostClassThink( void ) {};
+
+ virtual void ClassPreDataUpdate( void ) {};
+ virtual void ClassOnDataChanged( void ) {};
+
+ virtual void CreateMove( float flInputSampleTime, CUserCmd *pCmd ) {};
+
+ // Vehicles
+ virtual bool CanGetInVehicle( void ) { return true; }
+
+protected:
+
+ C_BaseTFPlayer *m_pPlayer; // reference to player (peer)
+};
+
+
+#include "TFClassData_Shared.h"
+
+
+#endif // C_TF_PLAYERCLASS_H \ No newline at end of file
diff --git a/game/client/tf2/c_tfcarrier.cpp b/game/client/tf2/c_tfcarrier.cpp
new file mode 100644
index 0000000..c516861
--- /dev/null
+++ b/game/client/tf2/c_tfcarrier.cpp
@@ -0,0 +1,30 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Client's CObjectSentrygun
+//
+// $NoKeywords: $
+//=============================================================================//
+#include "c_base.h
+#include "bone_setup.h"
+#include "CommanderOverlay.h"
+#include "c_ai_basenpc.h"
+#include "c_tfcarrier.h"
+
+IMPLEMENT_CLIENTCLASS_DT(C_TFCarrier, DT_TFCarrier, CTFCarrier)
+ RecvPropInt(RECVINFO(m_iHealth)),
+ RecvPropInt(RECVINFO(m_iMaxHealth)),
+END_RECV_TABLE()
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+C_TFCarrier::C_TFCarrier()
+{
+ CONSTRUCT_MINIMAP_PANEL( "minimap_helicopter", MINIMAP_COLLECTORS );
+}
+
+void C_TFCarrier::SetDormant( bool inside )
+{
+ BaseClass::SetDormant( bDormant );
+ ENTITY_PANEL_ACTIVATE( "helicopter", !bDormant );
+}
diff --git a/game/client/tf2/c_tfcarrier.h b/game/client/tf2/c_tfcarrier.h
new file mode 100644
index 0000000..d49d60a
--- /dev/null
+++ b/game/client/tf2/c_tfcarrier.h
@@ -0,0 +1,43 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef C_TFCARRIER_H
+#define C_TFCARRIER_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "c_rescollector.h"
+#include "hud_minimap.h"
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+class C_TFCarrier : public C_AI_BaseNPC
+{
+ DECLARE_CLASS( C_TFCarrier, C_AI_BaseNPC );
+
+public:
+ DECLARE_CLIENTCLASS();
+ DECLARE_ENTITY_PANEL();
+ DECLARE_MINIMAP_PANEL( );
+
+ C_TFCarrier();
+
+ virtual void SetDormant( bool bDormant );
+ virtual int GetHealth() const { return m_iHealth; }
+ virtual int GetMaxHealth() const { return m_iMaxHealth; }
+
+public:
+ int m_iHealth;
+ int m_iMaxHealth;
+
+private:
+ C_TFCarrier( const C_TFCarrier & );
+};
+
+#endif // C_TFCARRIER_H
diff --git a/game/client/tf2/c_tfplayerlocaldata.h b/game/client/tf2/c_tfplayerlocaldata.h
new file mode 100644
index 0000000..d863ae2
--- /dev/null
+++ b/game/client/tf2/c_tfplayerlocaldata.h
@@ -0,0 +1,50 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Defines the player specific data that is sent only to the player
+// to whom it belongs.
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef C_TFPLAYERLOCALDATA_H
+#define C_TFPLAYERLOCALDATA_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "techtree.h"
+#include "c_baseobject.h"
+
+//-----------------------------------------------------------------------------
+// Purpose: Player specific data ( sent only to local player, too )
+//-----------------------------------------------------------------------------
+class CTFPlayerLocalData
+{
+public:
+ DECLARE_PREDICTABLE();
+
+ int m_nInTacticalView;
+
+ bool m_bKnockedDown;
+ QAngle m_vecKnockDownDir;
+
+ bool m_bThermalVision;
+
+ int m_iIDEntIndex;
+
+ // Resource chunk carrying counts
+ int m_iResourceAmmo[ RESOURCE_TYPES ]; // 0 = Normal resources, 1 = Processed resources
+
+ // Resource bank
+ int m_iBankResources; // Current amounts of resource in my bank
+
+ // Objects
+ CUtlVector< CHandle<C_BaseObject> > m_aObjects;
+
+ // Object sapper placement handling
+ bool m_bAttachingSapper;
+ float m_flSapperAttachmentFrac;
+ bool m_bForceMapOverview;
+};
+
+#endif // C_TFPLAYERLOCALDATA_H
diff --git a/game/client/tf2/c_tfplayerresource.cpp b/game/client/tf2/c_tfplayerresource.cpp
new file mode 100644
index 0000000..edd4292
--- /dev/null
+++ b/game/client/tf2/c_tfplayerresource.cpp
@@ -0,0 +1,30 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: TF's custom C_PlayerResource
+//
+// $NoKeywords: $
+//=============================================================================//
+#include "cbase.h"
+#include "c_tfplayerresource.h"
+#include "hud.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+
+IMPLEMENT_CLIENTCLASS_DT(C_TFPlayerResource, DT_TFPlayerResource, CTFPlayerResource)
+END_RECV_TABLE()
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+C_TFPlayerResource::C_TFPlayerResource()
+{
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+C_TFPlayerResource::~C_TFPlayerResource()
+{
+} \ No newline at end of file
diff --git a/game/client/tf2/c_tfplayerresource.h b/game/client/tf2/c_tfplayerresource.h
new file mode 100644
index 0000000..210b106
--- /dev/null
+++ b/game/client/tf2/c_tfplayerresource.h
@@ -0,0 +1,30 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: TF's custom C_PlayerResource
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef C_TFPLAYERRESOURCE_H
+#define C_TFPLAYERRESOURCE_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "shareddefs.h"
+#include "c_playerresource.h"
+
+class C_TFPlayerResource : public C_PlayerResource
+{
+ DECLARE_CLASS( C_TFPlayerResource, C_PlayerResource );
+public:
+ DECLARE_CLIENTCLASS();
+
+ C_TFPlayerResource();
+ virtual ~C_TFPlayerResource();
+
+public:
+};
+
+
+#endif // C_TFPLAYERRESOURCE_H
diff --git a/game/client/tf2/c_tfteam.cpp b/game/client/tf2/c_tfteam.cpp
new file mode 100644
index 0000000..b1adecd
--- /dev/null
+++ b/game/client/tf2/c_tfteam.cpp
@@ -0,0 +1,217 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Client side C_TFTeam class
+//
+// $NoKeywords: $
+//=============================================================================//
+#include "cbase.h"
+#include "c_tfteam.h"
+#include "c_basetfplayer.h"
+#include "engine/IEngineSound.h"
+#include "hud.h"
+#include "recvproxy.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+
+#define ATTACK_NOTIFICATION_TIME 10.0f
+
+#define MESSAGESTRINGID_RESOURCESHARVESTED (IMessageChars::MESSAGESTRINGID_BASE+0)
+
+//-----------------------------------------------------------------------------
+// Purpose: RecvProxy that converts the Team's object UtlVector to entindexes
+//-----------------------------------------------------------------------------
+void RecvProxy_ObjectList( const CRecvProxyData *pData, void *pStruct, void *pOut )
+{
+ C_TFTeam *pTeam = (C_TFTeam*)pStruct;
+ CBaseHandle *pHandle = (CBaseHandle*)(&(pTeam->m_aObjects[ pData->m_iElement ]));
+ RecvProxy_IntToEHandle( pData, pStruct, pHandle );
+}
+
+
+void RecvProxyArrayLength_TeamObjects( void *pStruct, int objectID, int currentArrayLength )
+{
+ C_TFTeam *pTeam = (C_TFTeam*)pStruct;
+
+ if ( pTeam->m_aObjects.Count() != currentArrayLength )
+ {
+ pTeam->m_aObjects.SetSize( currentArrayLength );
+ }
+}
+
+
+IMPLEMENT_CLIENTCLASS_DT(C_TFTeam, DT_TFTeam, CTFTeam)
+ RecvPropFloat( RECVINFO(m_fResources) ),
+ RecvPropFloat( RECVINFO(m_fPotentialResources) ),
+ RecvPropInt( RECVINFO(m_bHaveZone) ),
+
+ RecvPropArray2(
+ RecvProxyArrayLength_TeamObjects,
+ RecvPropInt( "object_array_element", 0, SIZEOF_IGNORE, 0, RecvProxy_ObjectList ),
+ MAX_OBJECTS_PER_TEAM,
+ 0,
+ "object_array"
+ ),
+END_RECV_TABLE()
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+C_TFTeam::C_TFTeam()
+{
+ m_LastAttackNotificationTime = -10000;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+C_TFTeam::~C_TFTeam()
+{
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void C_TFTeam::NotifyBaseUnderAttack( const Vector &vecPosition, bool bPlaySound, bool bForce )
+{
+ float currentTime = gpGlobals->curtime;
+ if ( bForce || (currentTime - m_LastAttackNotificationTime > ATTACK_NOTIFICATION_TIME) )
+ {
+ m_LastAttackNotificationTime = currentTime;
+
+ if (GetLocalTeam() == this)
+ {
+ // Play a sound.
+ if (bPlaySound)
+ {
+ CLocalPlayerFilter filter;
+ C_BaseEntity::EmitSound( filter, SOUND_FROM_LOCAL_PLAYER, "TFTeam.NotifyBaseUnderAttack" );
+ }
+
+ MinimapCreateTempTrace( "minimap_under_attack", MINIMAP_PERSONAL_ORDERS, vecPosition );
+ }
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+float C_TFTeam::GetTeamResources( void )
+{
+ return m_fResources;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+float C_TFTeam::GetPotentialTeamResources( void )
+{
+ return m_fPotentialResources;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Return true if this team controls a zone of the specified resource type
+//-----------------------------------------------------------------------------
+bool C_TFTeam::GetHaveZone( void )
+{
+ return m_bHaveZone;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+int C_TFTeam::GetNumObjects( int iObjectType )
+{
+ // Asking for a count of a specific object type?
+ if ( iObjectType > 0 )
+ {
+ int iCount = 0;
+ for ( int i = 0; i < GetNumObjects(); i++ )
+ {
+ CBaseObject *pObject = GetObject(i);
+ if ( pObject && pObject->GetType() == iObjectType )
+ {
+ iCount++;
+ }
+ }
+ return iCount;
+ }
+
+ return m_aObjects.Count();
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+C_BaseObject *C_TFTeam::GetObject( int iIndex )
+{
+ Assert( iIndex >= 0 && iIndex < m_aObjects.Size() );
+ return static_cast<C_BaseObject*>((C_BaseEntity*)m_aObjects[iIndex]);
+}
+
+bool C_TFTeam::IsObjectValid( int iIndex )
+{
+ Assert( iIndex >= 0 && iIndex < m_aObjects.Size() );
+ return ((C_BaseEntity const*)m_aObjects[iIndex] != NULL);
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Receive a spawn message from the server
+//-----------------------------------------------------------------------------
+void C_TFTeam::ReceiveMessage( int classID, bf_read &msg )
+{
+ if ( classID != GetClientClass()->m_ClassID )
+ {
+ // message is for subclass
+ BaseClass::ReceiveMessage( classID, msg );
+ return;
+ }
+
+ int iAmount = msg.ReadLong();
+
+ int iYPos;
+
+ // Use appropriate string based on client's team
+ char sResourceString[256];
+ if ( GetLocalTeam() == this )
+ {
+ itoa(iAmount, sResourceString, 10 );
+ Q_strncat( sResourceString, " RESOURCES HARVESTED!", sizeof(sResourceString), COPY_ALL_CHARACTERS );
+ iYPos = ScreenHeight() / 4;
+ }
+ else
+ {
+ char sAmount[256];
+ itoa(iAmount, sAmount, 10 );
+ Q_strncpy( sResourceString, "ENEMY TEAM HAS HARVESTED ", sizeof(sResourceString) );
+ Q_strncat( sResourceString, sAmount, sizeof(sResourceString), COPY_ALL_CHARACTERS );
+ Q_strncat( sResourceString, " RESOURCES!", sizeof(sResourceString), COPY_ALL_CHARACTERS );
+ iYPos = (ScreenHeight() / 4) + 32;
+ }
+
+ // Clear out any old strings with this ID.
+ messagechars->RemoveStringsByID( MESSAGESTRINGID_RESOURCESHARVESTED );
+
+ // Print the string
+ int width, height;
+ messagechars->GetStringLength( g_hFontTrebuchet24, &width, &height, sResourceString );
+ messagechars->DrawStringForTime(
+ 5.0,
+ g_hFontTrebuchet24,
+ (ScreenWidth() - width) / 2,
+ iYPos,
+ 192,
+ 192,
+ 192,
+ 255,
+ sResourceString,
+ MESSAGESTRINGID_RESOURCESHARVESTED );
+}
+
diff --git a/game/client/tf2/c_tfteam.h b/game/client/tf2/c_tfteam.h
new file mode 100644
index 0000000..7ee6d61
--- /dev/null
+++ b/game/client/tf2/c_tfteam.h
@@ -0,0 +1,62 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Client side CTFTeam class
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef C_TFTEAM_H
+#define C_TFTEAM_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "c_team.h"
+#include "shareddefs.h"
+#include "techtree.h"
+#include "imessagechars.h"
+
+class C_BaseEntity;
+class C_BaseObject;
+class CBaseTechnology;
+
+//-----------------------------------------------------------------------------
+// Purpose: TF's Team manager
+//-----------------------------------------------------------------------------
+class C_TFTeam : public C_Team
+{
+ DECLARE_CLASS( C_TFTeam, C_Team );
+public:
+ DECLARE_CLIENTCLASS();
+
+ C_TFTeam();
+ virtual ~C_TFTeam();
+
+ // Data Access
+ virtual float GetTeamResources( void );
+ virtual float GetPotentialTeamResources( void );
+ virtual bool GetHaveZone( void );
+
+ // Objects, note GetObject can return NULL!
+ int GetNumObjects( int iObjectType = -1 );
+ C_BaseObject *GetObject( int iIndex );
+ bool IsObjectValid( int iIndex );
+
+ void NotifyBaseUnderAttack( const Vector &vecPosition, bool bPlaySound = true, bool bForce = false );
+
+ virtual void ReceiveMessage( int classID, bf_read &msg );
+
+public:
+ // Resource UI data
+ bool m_bHaveZone;
+
+ float m_fResources; // Current amounts of resources
+ float m_fPotentialResources; // Potential amounts of each resource when all harvesters have returned
+
+ float m_LastAttackNotificationTime;
+
+ CUtlVector< EHANDLE > m_aObjects;
+};
+
+
+#endif // C_TFTEAM_H
diff --git a/game/client/tf2/c_vehicle_battering_ram.cpp b/game/client/tf2/c_vehicle_battering_ram.cpp
new file mode 100644
index 0000000..e4c68e1
--- /dev/null
+++ b/game/client/tf2/c_vehicle_battering_ram.cpp
@@ -0,0 +1,208 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+#include "cbase.h"
+#include "c_basefourwheelvehicle.h"
+#include "tf_movedata.h"
+#include "ObjectControlPanel.h"
+#include <vgui_controls/Label.h>
+#include "vgui_bitmapbutton.h"
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+class C_VehicleBatteringRam : public C_BaseTFFourWheelVehicle
+{
+ DECLARE_CLASS( C_VehicleBatteringRam, C_BaseTFFourWheelVehicle );
+public:
+ DECLARE_CLIENTCLASS();
+
+ C_VehicleBatteringRam();
+
+public:
+ // IClientVehicle overrides
+ virtual bool IsPassengerUsingStandardWeapons( int nRole );
+ virtual void UpdateViewAngles( C_BasePlayer *pLocalPlayer, CUserCmd *pCmd );
+
+private:
+ C_VehicleBatteringRam( const C_VehicleBatteringRam & ); // not defined, not accessible
+};
+
+IMPLEMENT_CLIENTCLASS_DT(C_VehicleBatteringRam, DT_VehicleBatteringRam, CVehicleBatteringRam)
+END_RECV_TABLE()
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+C_VehicleBatteringRam::C_VehicleBatteringRam()
+{
+}
+
+
+//-----------------------------------------------------------------------------
+// Does the player use his normal weapons while in this mode?
+//-----------------------------------------------------------------------------
+bool C_VehicleBatteringRam::IsPassengerUsingStandardWeapons( int nRole )
+{
+ return (nRole > 1);
+}
+
+//-----------------------------------------------------------------------------
+// Clamps the view angles while manning the gun
+//-----------------------------------------------------------------------------
+void C_VehicleBatteringRam::UpdateViewAngles( C_BasePlayer *pLocalPlayer, CUserCmd *pCmd )
+{
+ int nRole = GetPassengerRole( pLocalPlayer );
+
+ // Restrict the view of the 1st passenger
+ if (nRole == 1)
+ {
+ RestrictView( nRole, -90, 90, pCmd->viewangles );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Control screen
+//-----------------------------------------------------------------------------
+class CVehicleBatteringRamControlPanel : public CObjectControlPanel
+{
+ DECLARE_CLASS( CVehicleBatteringRamControlPanel, CObjectControlPanel );
+
+public:
+ CVehicleBatteringRamControlPanel( vgui::Panel *parent, const char *panelName );
+ virtual bool Init( KeyValues* pKeyValues, VGuiScreenInitData_t* pInitData );
+ virtual void OnTick();
+ virtual void OnCommand( const char *command );
+
+private:
+ void GetInRam( void );
+
+private:
+ vgui::Label *m_pDriverLabel;
+ vgui::Label *m_pPassengerLabel;
+ vgui::Button *m_pOccupyButton;
+};
+
+
+DECLARE_VGUI_SCREEN_FACTORY( CVehicleBatteringRamControlPanel, "vehicle_battering_ram_control_panel" );
+
+
+//-----------------------------------------------------------------------------
+// Constructor:
+//-----------------------------------------------------------------------------
+CVehicleBatteringRamControlPanel::CVehicleBatteringRamControlPanel( vgui::Panel *parent, const char *panelName )
+ : BaseClass( parent, "CVehicleBatteringRamControlPanel" )
+{
+}
+
+
+//-----------------------------------------------------------------------------
+// Initialization
+//-----------------------------------------------------------------------------
+bool CVehicleBatteringRamControlPanel::Init( KeyValues* pKeyValues, VGuiScreenInitData_t* pInitData )
+{
+ m_pDriverLabel = new vgui::Label( this, "DriverReadout", "" );
+ m_pPassengerLabel = new vgui::Label( this, "PassengerReadout", "" );
+ m_pOccupyButton = new CBitmapButton( this, "OccupyButton", "Occupy" );
+
+ if (!BaseClass::Init(pKeyValues, pInitData))
+ return false;
+
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+// Frame-based update
+//-----------------------------------------------------------------------------
+void CVehicleBatteringRamControlPanel::OnTick()
+{
+ BaseClass::OnTick();
+
+ C_BaseObject *pObj = GetOwningObject();
+ if (!pObj)
+ return;
+
+ Assert( dynamic_cast<C_VehicleBatteringRam*>(pObj) );
+ C_VehicleBatteringRam *pRam = static_cast<C_VehicleBatteringRam*>(pObj);
+
+ char buf[256];
+ // Update the currently manned player label
+ if ( pRam->GetDriverPlayer() )
+ {
+ Q_snprintf( buf, sizeof( buf ), "Driven by %s", pRam->GetDriverPlayer()->GetPlayerName() );
+ m_pDriverLabel->SetText( buf );
+ m_pDriverLabel->SetVisible( true );
+ }
+ else
+ {
+ m_pDriverLabel->SetVisible( false );
+ }
+
+ int nPassengerCount = pRam->GetPassengerCount();
+ int nMaxPassengerCount = pRam->GetMaxPassengerCount();
+
+ Q_snprintf( buf, sizeof( buf ), "Passengers %d/%d", nPassengerCount >= 1 ? nPassengerCount - 1 : 0, nMaxPassengerCount - 1 );
+ m_pPassengerLabel->SetText( buf );
+
+ // Update the get in button
+ if ( pRam->IsPlayerInVehicle( C_BaseTFPlayer::GetLocalPlayer() ) )
+ {
+ m_pOccupyButton->SetEnabled( false );
+ return;
+ }
+
+ if ( pRam->GetOwner() == C_BaseTFPlayer::GetLocalPlayer() )
+ {
+ if (nPassengerCount == nMaxPassengerCount)
+ {
+ // Owners can boot other players to get in
+ C_BaseTFPlayer *pPlayer = static_cast<C_BaseTFPlayer*>(pRam->GetPassenger( VEHICLE_ROLE_DRIVER ));
+ Q_snprintf( buf, sizeof( buf ), "Get In (Ejecting %s)", pPlayer->GetPlayerName() );
+ m_pDriverLabel->SetText( buf );
+ m_pOccupyButton->SetEnabled( true );
+ }
+ else
+ {
+ m_pOccupyButton->SetText( "Get In" );
+ m_pOccupyButton->SetEnabled( true );
+ }
+ }
+ else
+ {
+ m_pOccupyButton->SetText( "Get In" );
+ m_pOccupyButton->SetEnabled( pRam->GetPassengerCount() < pRam->GetMaxPassengerCount() );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Handle clicking on the Occupy button
+//-----------------------------------------------------------------------------
+void CVehicleBatteringRamControlPanel::GetInRam( void )
+{
+ C_BaseObject *pObj = GetOwningObject();
+ if (pObj)
+ {
+ pObj->SendClientCommand( "toggle_use" );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Button click handlers
+//-----------------------------------------------------------------------------
+void CVehicleBatteringRamControlPanel::OnCommand( const char *command )
+{
+ if (!Q_strnicmp(command, "Occupy", 7))
+ {
+ GetInRam();
+ return;
+ }
+
+ BaseClass::OnCommand(command);
+}
+
diff --git a/game/client/tf2/c_vehicle_flatbed.cpp b/game/client/tf2/c_vehicle_flatbed.cpp
new file mode 100644
index 0000000..0457d91
--- /dev/null
+++ b/game/client/tf2/c_vehicle_flatbed.cpp
@@ -0,0 +1,183 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+#include "cbase.h"
+#include "c_basefourwheelvehicle.h"
+#include "tf_movedata.h"
+#include "ObjectControlPanel.h"
+#include <vgui_controls/Label.h>
+#include <vgui_controls/Button.h>
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+class C_VehicleFlatbed : public C_BaseTFFourWheelVehicle
+{
+ DECLARE_CLASS( C_VehicleFlatbed, C_BaseTFFourWheelVehicle );
+public:
+ DECLARE_CLIENTCLASS();
+
+ C_VehicleFlatbed();
+
+private:
+ C_VehicleFlatbed( const C_VehicleFlatbed & ); // not defined, not accessible
+
+};
+
+
+IMPLEMENT_CLIENTCLASS_DT(C_VehicleFlatbed, DT_VehicleFlatbed, CVehicleFlatbed)
+END_RECV_TABLE()
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+C_VehicleFlatbed::C_VehicleFlatbed()
+{
+}
+
+
+//-----------------------------------------------------------------------------
+// Control screen
+//-----------------------------------------------------------------------------
+class CVehicleFlatbedControlPanel : public CObjectControlPanel
+{
+ DECLARE_CLASS( CVehicleFlatbedControlPanel, CObjectControlPanel );
+
+public:
+ CVehicleFlatbedControlPanel( vgui::Panel *parent, const char *panelName );
+ virtual bool Init( KeyValues* pKeyValues, VGuiScreenInitData_t* pInitData );
+ virtual void OnTick();
+ virtual void OnCommand( const char *command );
+
+private:
+ void GetInRam( void );
+
+private:
+ vgui::Label *m_pDriverLabel;
+ vgui::Label *m_pPassengerLabel;
+ vgui::Button *m_pOccupyButton;
+};
+
+
+DECLARE_VGUI_SCREEN_FACTORY( CVehicleFlatbedControlPanel, "vehicle_battering_ram_control_panel" );
+
+
+//-----------------------------------------------------------------------------
+// Constructor:
+//-----------------------------------------------------------------------------
+CVehicleFlatbedControlPanel::CVehicleFlatbedControlPanel( vgui::Panel *parent, const char *panelName )
+ : BaseClass( parent, "CVehicleBatteringRamControlPanel" )
+{
+}
+
+
+//-----------------------------------------------------------------------------
+// Initialization
+//-----------------------------------------------------------------------------
+bool CVehicleFlatbedControlPanel::Init( KeyValues* pKeyValues, VGuiScreenInitData_t* pInitData )
+{
+ m_pDriverLabel = new vgui::Label( this, "DriverReadout", "" );
+ m_pPassengerLabel = new vgui::Label( this, "PassengerReadout", "" );
+ m_pOccupyButton = new vgui::Button( this, "OccupyButton", "Occupy" );
+
+ if (!BaseClass::Init(pKeyValues, pInitData))
+ return false;
+
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+// Frame-based update
+//-----------------------------------------------------------------------------
+void CVehicleFlatbedControlPanel::OnTick()
+{
+ BaseClass::OnTick();
+
+ C_BaseObject *pObj = GetOwningObject();
+ if (!pObj)
+ return;
+
+ Assert( dynamic_cast<C_VehicleFlatbed*>(pObj) );
+ C_VehicleFlatbed *pRam = static_cast<C_VehicleFlatbed*>(pObj);
+
+ char buf[256];
+ // Update the currently manned player label
+ if ( pRam->GetDriverPlayer() )
+ {
+ Q_snprintf( buf, sizeof( buf ), "Driven by %s", pRam->GetDriverPlayer()->GetPlayerName() );
+ m_pDriverLabel->SetText( buf );
+ m_pDriverLabel->SetVisible( true );
+ }
+ else
+ {
+ m_pDriverLabel->SetVisible( false );
+ }
+
+ int nPassengerCount = pRam->GetPassengerCount();
+ int nMaxPassengerCount = pRam->GetMaxPassengerCount();
+
+ Q_snprintf( buf, sizeof( buf ), "Passengers %d/%d", nPassengerCount >= 1 ? nPassengerCount - 1 : 0, nMaxPassengerCount - 1 );
+ m_pPassengerLabel->SetText( buf );
+
+ // Update the get in button
+ if ( pRam->IsPlayerInVehicle( C_BaseTFPlayer::GetLocalPlayer() ) )
+ {
+ m_pOccupyButton->SetEnabled( false );
+ return;
+ }
+
+ if ( pRam->GetOwner() == C_BaseTFPlayer::GetLocalPlayer() )
+ {
+ if (nPassengerCount == nMaxPassengerCount)
+ {
+ // Owners can boot other players to get in
+ C_BaseTFPlayer *pPlayer = static_cast<C_BaseTFPlayer*>(pRam->GetPassenger( VEHICLE_ROLE_DRIVER ));
+ Q_snprintf( buf, sizeof( buf ), "Get In (Ejecting %s)", pPlayer->GetPlayerName() );
+ m_pDriverLabel->SetText( buf );
+ m_pOccupyButton->SetEnabled( true );
+ }
+ else
+ {
+ m_pOccupyButton->SetText( "Get In" );
+ m_pOccupyButton->SetEnabled( true );
+ }
+ }
+ else
+ {
+ m_pOccupyButton->SetText( "Get In" );
+ m_pOccupyButton->SetEnabled( pRam->GetPassengerCount() < pRam->GetMaxPassengerCount() );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Handle clicking on the Occupy button
+//-----------------------------------------------------------------------------
+void CVehicleFlatbedControlPanel::GetInRam( void )
+{
+ C_BaseObject *pObj = GetOwningObject();
+ if (pObj)
+ {
+ pObj->SendClientCommand( "toggle_use" );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Button click handlers
+//-----------------------------------------------------------------------------
+void CVehicleFlatbedControlPanel::OnCommand( const char *command )
+{
+ if (!Q_strnicmp(command, "Occupy", 7))
+ {
+ GetInRam();
+ return;
+ }
+
+ BaseClass::OnCommand(command);
+}
+
diff --git a/game/client/tf2/c_vehicle_mortar.cpp b/game/client/tf2/c_vehicle_mortar.cpp
new file mode 100644
index 0000000..844c544
--- /dev/null
+++ b/game/client/tf2/c_vehicle_mortar.cpp
@@ -0,0 +1,869 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+#include "cbase.h"
+#include "c_basefourwheelvehicle.h"
+#include "tf_movedata.h"
+#include "ObjectControlPanel.h"
+#include <vgui_controls/Label.h>
+#include <vgui_controls/Button.h>
+#include "vehicle_mortar_shared.h"
+#include "vgui_rotation_slider.h"
+#include <vgui/ISurface.h>
+#include "vgui_basepanel.h"
+#include "ground_line.h"
+#include "hud_minimap.h"
+#include "vgui_bitmapimage.h"
+#include "iusesmortarpanel.h"
+
+// How long it waits after you've changed the mortar's yaw to draw using the server's value.
+#define CLIENT_MORTAR_YAW_COUNTDOWN 0.5
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+class C_VehicleMortar : public C_BaseTFFourWheelVehicle, public IUsesMortarPanel
+{
+ DECLARE_CLASS( C_VehicleMortar, C_BaseTFFourWheelVehicle );
+public:
+ DECLARE_CLIENTCLASS();
+
+ C_VehicleMortar();
+
+ virtual void ReceiveMessage( int classID, bf_read &msg );
+
+ // Fire off a mortar.
+ void FireMortar();
+
+ virtual void ClientThink();
+
+// C_BaseEntity overrides.
+public:
+ virtual void GetBoneControllers(float controllers[MAXSTUDIOBONECTRLS]);
+
+// IUsesMortarPanel
+public:
+ // Get the data from this mortar needed by the panel
+ virtual void GetMortarData( float *flClientMortarYaw, bool *bAllowedToFire, float *flPower, float *flFiringPower, float *flFiringAccuracy, int *iFiringState );
+ virtual void SendYawCommand( void );
+ virtual void ForceClientYawCountdown( float flTime );
+ virtual void ClickFire( void );
+
+public:
+ // Mortar firing info.
+ int m_iFiringState; // One of the MORTAR_ defines.
+ bool m_bMortarReloading;
+ float m_flPower;
+ bool m_bAllowedToFire;
+
+ // Parameters for the next shot.
+ float m_flFiringPower;
+ float m_flFiringAccuracy;
+
+ float m_flMortarYaw; // What direction the mortar is aimed in.
+ float m_flMortarPitch;
+
+ // This is what is used on the client to draw the ground line and orient the mortar.
+ // It is usually copied right over from m_flClientMortarYaw (which comes from the server),
+ // but this is also used when rotating the mortar so you can see the line move smoothly.
+ float m_flClientMortarYaw;
+
+ // This is set to about 1/4 seconds when you rotate the mortar line so you use the client's
+ // (smooth, non-lagged) yaw changes instead of the server's.
+ float m_flForceClientYawCountdown;
+
+private:
+ C_VehicleMortar( const C_VehicleMortar & ); // not defined, not accessible
+
+};
+
+
+IMPLEMENT_CLIENTCLASS_DT(C_VehicleMortar, DT_VehicleMortar, CVehicleMortar)
+ RecvPropFloat( RECVINFO( m_flMortarYaw ) ),
+ RecvPropFloat( RECVINFO( m_flMortarPitch ) ),
+ RecvPropBool( RECVINFO( m_bAllowedToFire ) )
+END_RECV_TABLE()
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+
+C_VehicleMortar::C_VehicleMortar()
+{
+ m_iFiringState = MORTAR_IDLE;
+ m_bMortarReloading = false;
+ m_flPower = 0;
+
+ m_flMortarYaw = 0;
+ m_flClientMortarYaw = 0;
+ m_flMortarPitch = 0;
+ m_flForceClientYawCountdown = 0;
+ m_bAllowedToFire = true;
+
+ SetNextClientThink( CLIENT_THINK_ALWAYS );
+}
+
+
+void C_VehicleMortar::ReceiveMessage( int classID, bf_read &msg )
+{
+ if ( classID != GetClientClass()->m_ClassID )
+ {
+ // message is for subclass
+ BaseClass::ReceiveMessage( classID, msg );
+ return;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void C_VehicleMortar::ClickFire()
+{
+ switch( m_iFiringState )
+ {
+ case MORTAR_IDLE:
+ m_iFiringState = MORTAR_CHARGING_POWER;
+ break;
+
+ case MORTAR_CHARGING_POWER:
+ m_flFiringPower = m_flPower;
+ m_iFiringState = MORTAR_CHARGING_ACCURACY;
+ break;
+
+ case MORTAR_CHARGING_ACCURACY:
+ m_flFiringAccuracy = m_flPower;
+ m_iFiringState = MORTAR_IDLE;
+
+ FireMortar();
+ break;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void C_VehicleMortar::FireMortar()
+{
+ char cmd[512];
+ Q_snprintf( cmd, sizeof( cmd ), "FireMortar %.2f %.2f", m_flFiringPower, m_flFiringAccuracy );
+ SendClientCommand( cmd );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void C_VehicleMortar::SendYawCommand( void )
+{
+ char szbuf[48];
+ Q_snprintf( szbuf, sizeof( szbuf ), "MortarYaw %0.2f\n", m_flClientMortarYaw );
+ SendClientCommand( szbuf );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void C_VehicleMortar::ForceClientYawCountdown( float flTime )
+{
+ m_flForceClientYawCountdown = flTime;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void C_VehicleMortar::GetMortarData( float *flClientMortarYaw, bool *bAllowedToFire, float *flPower, float *flFiringPower, float *flFiringAccuracy, int *iFiringState )
+{
+ *flClientMortarYaw = m_flClientMortarYaw;
+ *bAllowedToFire = m_bAllowedToFire;
+ *flPower = m_flPower;
+ *flFiringPower = m_flFiringPower;
+ *flFiringAccuracy = m_flFiringAccuracy;
+ *iFiringState = m_iFiringState;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void C_VehicleMortar::ClientThink()
+{
+ m_flForceClientYawCountdown -= gpGlobals->frametime;
+ if ( m_flForceClientYawCountdown <= 0 )
+ {
+ m_flClientMortarYaw = m_flMortarYaw;
+ }
+}
+
+
+void C_VehicleMortar::GetBoneControllers( float controllers[MAXSTUDIOBONECTRLS])
+{
+ BaseClass::GetBoneControllers( controllers);
+
+ controllers[0] = anglemod( m_flClientMortarYaw ) / 360.0;
+ controllers[1] = anglemod( m_flMortarPitch ) / 360.0;
+}
+
+
+//-----------------------------------------------------------------------------
+// CMortarMinimapPanel
+//-----------------------------------------------------------------------------
+CMortarMinimapPanel::CMortarMinimapPanel( vgui::Panel *pParent, const char *pElementName )
+ : CMinimapPanel( pElementName )
+{
+ SetParent( pParent );
+
+ m_bMouseDown = false;
+ m_bFireButtonDown = false;
+ m_LastX = m_LastY = -1;
+
+ m_nTextureId = vgui::surface()->CreateNewTextureID();
+ vgui::surface()->DrawSetTextureFile( m_nTextureId, "hud/minimap/mortar_slider", true, false );
+
+ m_nTextureId_CantFire = vgui::surface()->CreateNewTextureID();
+ vgui::surface()->DrawSetTextureFile( m_nTextureId_CantFire, "hud/minimap/mortar_slider_cantfire", true, false );
+}
+
+
+CMortarMinimapPanel::~CMortarMinimapPanel()
+{
+}
+
+void CMortarMinimapPanel::InitMortarMinimap( C_BaseEntity *pMortar )
+{
+ BaseClass::Init( NULL );
+
+ m_hMortar = pMortar;
+
+ m_MortarButtonUp.Init( GetVPanel(), "hud/minimap/icon_mortarbutton_up" );
+ m_MortarButtonDown.Init( GetVPanel(), "hud/minimap/icon_mortarbutton_dn" );
+ m_MortarButtonCantFire.Init( GetVPanel(), "hud/minimap/icon_mortarbutton_cantfire" );
+
+ m_MortarDirectionImage.Init( GetVPanel(), "hud/minimap/icon_player_arrow" );
+ m_MortarDirectionImage.SetColor( Color( 0, 255, 0, 255 ) );
+}
+
+
+C_BaseEntity *CMortarMinimapPanel::GetMortar() const
+{
+ return (C_BaseEntity*)m_hMortar;
+}
+
+
+void CMortarMinimapPanel::Paint()
+{
+ BaseClass::Paint();
+
+ C_BaseEntity *pMortar = GetMortar();
+ IUsesMortarPanel *pMortarInterface = dynamic_cast< IUsesMortarPanel* >( pMortar );
+ if ( pMortar && pMortarInterface )
+ {
+ float flClientMortarYaw, flPower, flFiringPower, flFiringAccuracy;
+ int iFiringState;
+ bool bAllowedToFire;
+ pMortarInterface->GetMortarData( &flClientMortarYaw, &bAllowedToFire, &flPower, &flFiringPower, &flFiringAccuracy, &iFiringState );
+
+ float yaw = flClientMortarYaw + 90;
+
+ float x, y;
+ if ( WorldToMinimap( MINIMAP_CLAMP, pMortar->GetAbsOrigin(), x, y ) )
+ {
+ int size = 20;
+
+ BitmapImage *pImage = &m_MortarButtonCantFire;
+ if ( bAllowedToFire )
+ {
+ if ( m_bFireButtonDown )
+ pImage = &m_MortarButtonDown;
+ else
+ pImage = &m_MortarButtonUp;
+ }
+
+ pImage->DoPaint( x-size/2, y-size/2, size, size, yaw );
+
+ size = 40;
+ m_MortarDirectionImage.DoPaint( x-size/2, y-size/2, size, size, pMortar->GetAbsAngles()[YAW] + 90 );
+
+
+ // Draw the power bar.
+ float flAngle = pMortar->GetAbsAngles()[YAW] + flClientMortarYaw;
+ Vector vForward( -sin( DEG2RAD( flAngle ) ), cos( DEG2RAD( flAngle ) ), 0 );
+ Vector vRight( vForward.y, -vForward.x, 0 );
+
+ Vector vStartPoint = pMortar->GetAbsOrigin();
+ Vector vEndPoint = vStartPoint + vForward * MORTAR_RANGE_MAX_INITIAL;
+ Vector vInaccuracy = vEndPoint + vRight * (MORTAR_RANGE_MAX_INITIAL * MORTAR_INACCURACY_MAX_INITIAL);
+
+ Vector2D vStart2D, vEnd2D, vInaccuracy2D;
+ WorldToMinimap( MINIMAP_ALWAYS_ACCEPT, vStartPoint, vStart2D.x, vStart2D.y );
+ WorldToMinimap( MINIMAP_ALWAYS_ACCEPT, vEndPoint, vEnd2D.x, vEnd2D.y );
+ WorldToMinimap( MINIMAP_ALWAYS_ACCEPT, vInaccuracy, vInaccuracy2D.x, vInaccuracy2D.y );
+
+ Vector2D vDir = vEnd2D - vStart2D;
+ Vector2DNormalize( vDir );
+
+
+ // These variables control the look.
+ float flLength = (vEnd2D - vStart2D).Length();
+ float flZeroT = 1.0f / 5;
+ float flZero = flLength * flZeroT;
+
+ float flFirePower = MAX( flPower, flFiringPower );
+
+ float flStartFatness = 2;
+ float flEndFatness = flStartFatness;
+
+ float flScalePower = flFiringAccuracy;
+ if ( iFiringState != MORTAR_IDLE )
+ flScalePower = flPower;
+
+ Vector2D vInaccuracyDir = vInaccuracy2D - vEnd2D;
+ flEndFatness *= vInaccuracyDir.Length() * flScalePower * 0.4;
+ flEndFatness = MAX( fabs( flEndFatness ), flStartFatness );
+
+ Vector2D vPerp( vDir.y, -vDir.x );
+ Vector2DNormalize( vPerp );
+
+ Vector2D vStartPerp = vPerp * flStartFatness;
+ Vector2D vEndPerp = vPerp * flEndFatness;
+
+
+ // Draw the red-black power bars.
+ vgui::ISurface *pSurface = vgui::surface();
+ if ( bAllowedToFire )
+ pSurface->DrawSetTexture( m_nTextureId );
+ else
+ pSurface->DrawSetTexture( m_nTextureId_CantFire );
+
+ Vector2D vZeroPerp;
+ Vector2DLerp( vStartPerp, vEndPerp, flZero / flLength, vZeroPerp );
+
+ // Draw a black->red bar from zero to our current power.
+ float flFirePowerDistance = RemapVal( flFirePower, 0, 1, flZero, flLength );
+ Vector2D vPowerPerp;
+ Vector2DLerp( vStartPerp, vEndPerp, RemapVal( flFirePowerDistance, flZero, flLength, flZeroT, 1 ), vPowerPerp );
+
+ vgui::Vertex_t verts[4];
+ verts[0].Init( vStart2D + vDir * flZero - vZeroPerp );
+ verts[1].Init( verts[0].m_Position + vZeroPerp * 2 );
+
+ verts[2].Init( vStart2D + vDir * flFirePowerDistance + vPowerPerp, Vector2D( flFirePower, 0 ) );
+ verts[3] = verts[2];
+ verts[3].m_Position -= vPowerPerp * 2;
+
+ pSurface->DrawSetColor( 255, 255, 255, 255 );
+ pSurface->DrawTexturedPolygon( 4, verts );
+
+
+ // Draw the power slider.
+ pSurface->DrawSetTexture( -1 );
+
+
+ vgui::Vertex_t line[2];
+ line[0].Init( vStart2D + vDir * flFirePowerDistance - vPowerPerp );
+ line[1].Init( line[0].m_Position + vPowerPerp * 2 );
+ pSurface->DrawTexturedLine( line[0], line[1] );
+
+
+
+ // Draw a white outline.
+ pSurface->DrawSetColor( 255, 255, 255, 255 );
+ vgui::Vertex_t pts[4] =
+ {
+ vgui::Vertex_t( vStart2D - vStartPerp ),
+ vgui::Vertex_t( vStart2D + vStartPerp ),
+ vgui::Vertex_t( vEnd2D + vEndPerp ),
+ vgui::Vertex_t( vEnd2D - vEndPerp )
+ };
+ pSurface->DrawTexturedPolyLine( pts, 4 );
+
+
+ // Draw the zero line.
+ line[0].Init( vStart2D + vDir * flZero - vZeroPerp );
+ line[1].Init( line[0].m_Position + vZeroPerp * 2 );
+ pSurface->DrawTexturedLine( line[0], line[1] );
+ }
+ }
+}
+
+
+void CMortarMinimapPanel::OnMousePressed( vgui::MouseCode code )
+{
+ BaseClass::OnMousePressed( code );
+
+ if (code != vgui::MOUSE_LEFT)
+ return;
+
+ C_BaseEntity *pMortar = GetMortar();
+ IUsesMortarPanel *pMortarInterface = dynamic_cast< IUsesMortarPanel* >( pMortar );
+ if ( !pMortar || !pMortarInterface )
+ return;
+
+ float flClientMortarYaw, flPower, flFiringPower, flFiringAccuracy;
+ int iFiringState;
+ bool bAllowedToFire;
+ pMortarInterface->GetMortarData( &flClientMortarYaw, &bAllowedToFire, &flPower, &flFiringPower, &flFiringAccuracy, &iFiringState );
+
+ // See if they clicked the "fire" button.
+ float x, y;
+ if ( WorldToMinimap( MINIMAP_ALWAYS_ACCEPT, pMortar->GetAbsOrigin(), x, y ) &&
+ (Vector2D( x, y ) - Vector2D( m_LastX, m_LastY )).Length() <= 8 )
+ {
+ if ( bAllowedToFire )
+ {
+ // Treat it like they clicked the fire button.
+ m_bFireButtonDown = true;
+ pMortarInterface->ClickFire();
+ }
+ }
+ else
+ {
+ pMortarInterface->ForceClientYawCountdown( 5000000 );
+ }
+
+ m_bMouseDown = true;
+}
+
+
+void CMortarMinimapPanel::OnCursorMoved( int x, int y )
+{
+ m_LastX = x;
+ m_LastY = y;
+
+ if ( !m_bMouseDown || m_bFireButtonDown )
+ return;
+
+ C_BaseEntity *pMortar = GetMortar();
+ IUsesMortarPanel *pMortarInterface = dynamic_cast< IUsesMortarPanel* >( pMortar );
+ if ( !pMortar || !pMortarInterface )
+ return;
+
+ float flClientMortarYaw, flPower, flFiringPower, flFiringAccuracy;
+ int iFiringState;
+ bool bAllowedToFire;
+ pMortarInterface->GetMortarData( &flClientMortarYaw, &bAllowedToFire, &flPower, &flFiringPower, &flFiringAccuracy, &iFiringState );
+
+ float mortarX, mortarY;
+ if ( WorldToMinimap( MINIMAP_ALWAYS_ACCEPT, pMortar->GetAbsOrigin(), mortarX, mortarY ) )
+ {
+ float flAngle = atan2( x - mortarX, mortarY - y );
+ flClientMortarYaw = -anglemod( flAngle * 180.0f / M_PI + pMortar->GetAbsAngles()[YAW] );
+ }
+}
+
+
+void CMortarMinimapPanel::OnMouseReleased( vgui::MouseCode code )
+{
+ BaseClass::OnMouseReleased( code );
+
+ if ( code != vgui::MOUSE_LEFT )
+ return;
+
+ m_bMouseDown = false;
+
+ if ( m_bFireButtonDown )
+ {
+ m_bFireButtonDown = false;
+ }
+ else
+ {
+ C_BaseEntity *pMortar = GetMortar();
+ IUsesMortarPanel *pMortarInterface = dynamic_cast< IUsesMortarPanel* >( pMortar );
+ if ( pMortar && pMortarInterface )
+ {
+ pMortarInterface->SendYawCommand();
+ pMortarInterface->ForceClientYawCountdown( CLIENT_MORTAR_YAW_COUNTDOWN );
+ }
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Control screen
+//-----------------------------------------------------------------------------
+class CVehicleMortarControlPanel : public CObjectControlPanel
+{
+ DECLARE_CLASS( CVehicleMortarControlPanel, CObjectControlPanel );
+
+public:
+
+ CVehicleMortarControlPanel( vgui::Panel *parent, const char *panelName );
+ virtual ~CVehicleMortarControlPanel();
+
+ virtual bool Init( KeyValues* pKeyValues, VGuiScreenInitData_t* pInitData );
+ virtual void OnCommand( const char *command );
+ C_VehicleMortar* GetMortar() const;
+
+
+protected:
+
+ virtual vgui::Panel* TickCurrentPanel();
+
+
+private:
+
+ void OnTickMainPanel();
+ void OnTickDeployPanel( float flDeployTime );
+ void OnTickGunnerPanel();
+
+ void GetInRam( void );
+
+ void StartDeploying();
+ void StopDismantling();
+ bool IsDeploying() const;
+ bool IsUndeploying() const;
+ bool IsDeployed() const;
+
+private:
+ vgui::Label *m_pDriverLabel;
+ vgui::Label *m_pPassengerLabel;
+ vgui::Button *m_pOccupyButton;
+ vgui::Button *m_pCancelDeployButton;
+
+ vgui::Label *m_pDeployMessageLabel; // says "Deployed in" or "Undeployed in"
+ vgui::Label *m_pDeployTimeLabel; // says "N seconds"
+
+ vgui::EditablePanel *m_pDeployPanel;
+ vgui::EditablePanel *m_pGunnerPanel;
+
+ CMortarMinimapPanel *m_pMinimapPanel;
+
+ vgui::Label *m_pReloadingLabel;
+};
+
+
+DECLARE_VGUI_SCREEN_FACTORY( CVehicleMortarControlPanel, "vehicle_mortar_control_panel" );
+
+
+//-----------------------------------------------------------------------------
+// Constructor:
+//-----------------------------------------------------------------------------
+CVehicleMortarControlPanel::CVehicleMortarControlPanel( vgui::Panel *parent, const char *panelName )
+ : BaseClass( parent, "CVehicleMortarControlPanel" )
+{
+ m_pDeployPanel = new CCommandChainingPanel( this, "DeployPanel" );
+ m_pDeployPanel->SetZPos( -1 );
+
+ m_pGunnerPanel = new CCommandChainingPanel( this, "GunnerPanel" );
+ m_pGunnerPanel->SetZPos( -1 );
+
+ m_pMinimapPanel = new CMortarMinimapPanel( m_pGunnerPanel, "MinimapPanel" );
+ m_pMinimapPanel->SetZPos( 10 );
+ m_pMinimapPanel->Init( NULL );
+}
+
+
+CVehicleMortarControlPanel::~CVehicleMortarControlPanel()
+{
+ delete m_pMinimapPanel;
+}
+
+
+//-----------------------------------------------------------------------------
+// Initialization
+//-----------------------------------------------------------------------------
+bool CVehicleMortarControlPanel::Init( KeyValues* pKeyValues, VGuiScreenInitData_t* pInitData )
+{
+ m_pDriverLabel = new vgui::Label( this, "DriverReadout", "" );
+ m_pPassengerLabel = new vgui::Label( this, "PassengerReadout", "" );
+ m_pOccupyButton = new vgui::Button( this, "OccupyButton", "Occupy" );
+
+ m_pDeployMessageLabel = new vgui::Label( m_pDeployPanel, "DeployMessage", "" );
+ m_pDeployTimeLabel = new vgui::Label( m_pDeployPanel, "DeployTime", "" );
+ m_pCancelDeployButton = new vgui::Button( m_pDeployPanel, "CancelDeployButton", "" );
+
+ m_pReloadingLabel = new vgui::Label( m_pGunnerPanel, "ReloadingLabel", "" );
+
+ // Make sure all named panels are created up above because BaseClass::Init initializes them
+ // all from their keyvalues.
+ if ( !BaseClass::Init( pKeyValues, pInitData ) )
+ return false;
+
+ // Init subpanels.
+ int x, y, w, h;
+ GetBounds( x, y, w, h );
+
+ m_pMinimapPanel->LevelInit( engine->GetLevelName() );
+ m_pMinimapPanel->SetVisible( true );
+ m_pMinimapPanel->InitMortarMinimap( GetMortar() );
+
+ m_pDeployPanel->SetBounds( x, y, w, h );
+ m_pDeployPanel->SetVisible( false );
+
+ m_pGunnerPanel->SetBounds( x, y, w, h );
+ m_pGunnerPanel->SetVisible( false );
+
+ m_pReloadingLabel->SetVisible( false );
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+// Frame-based update
+//-----------------------------------------------------------------------------
+
+vgui::Panel* CVehicleMortarControlPanel::TickCurrentPanel()
+{
+ C_VehicleMortar *pMortar = GetMortar();
+ if ( !pMortar )
+ return BaseClass::TickCurrentPanel();
+
+ if ( IsUndeploying() )
+ {
+ OnTickDeployPanel( pMortar->GetDeployFinishTime() );
+ return m_pDeployPanel;
+ }
+ else if ( IsDeploying() )
+ {
+ OnTickDeployPanel( pMortar->GetDeployFinishTime() );
+ return m_pDeployPanel;
+ }
+ else if ( IsDeployed() )
+ {
+ OnTickGunnerPanel();
+ return m_pGunnerPanel;
+ }
+ else
+ {
+ OnTickMainPanel();
+ return BaseClass::TickCurrentPanel();
+ }
+}
+
+
+C_VehicleMortar* CVehicleMortarControlPanel::GetMortar() const
+{
+ return dynamic_cast< C_VehicleMortar* >( GetOwningObject() );
+}
+
+
+void CVehicleMortarControlPanel::OnTickMainPanel()
+{
+ C_BaseObject *pObj = GetOwningObject();
+ if (!pObj)
+ return;
+
+ ShowOwnerLabel( true );
+ ShowHealthLabel( true );
+
+ Assert( dynamic_cast<C_VehicleMortar*>(pObj) );
+ C_VehicleMortar *pRam = static_cast<C_VehicleMortar*>(pObj);
+
+ char buf[256];
+ // Update the currently manned player label
+ if ( pRam->GetDriverPlayer() )
+ {
+ Q_snprintf( buf, sizeof( buf ), "Driven by %s", pRam->GetDriverPlayer()->GetPlayerName() );
+ m_pDriverLabel->SetText( buf );
+ m_pDriverLabel->SetVisible( true );
+ }
+ else
+ {
+ m_pDriverLabel->SetVisible( false );
+ }
+
+ int nPassengerCount = pRam->GetPassengerCount();
+ int nMaxPassengerCount = pRam->GetMaxPassengerCount();
+
+ Q_snprintf( buf, sizeof( buf ), "Passengers %d/%d", nPassengerCount >= 1 ? nPassengerCount - 1 : 0, nMaxPassengerCount - 1 );
+ m_pPassengerLabel->SetText( buf );
+
+ // Update the get in button
+ if ( pRam->IsPlayerInVehicle( C_BaseTFPlayer::GetLocalPlayer() ) )
+ {
+ m_pOccupyButton->SetEnabled( false );
+ return;
+ }
+
+ if ( pRam->GetOwner() == C_BaseTFPlayer::GetLocalPlayer() )
+ {
+ if (nPassengerCount == nMaxPassengerCount)
+ {
+ // Owners can boot other players to get in
+ C_BaseTFPlayer *pPlayer = static_cast<C_BaseTFPlayer*>(pRam->GetPassenger( VEHICLE_ROLE_DRIVER ));
+ Q_snprintf( buf, sizeof( buf ), "Get In (Ejecting %s)", pPlayer->GetPlayerName() );
+ m_pDriverLabel->SetText( buf );
+ m_pOccupyButton->SetEnabled( true );
+ }
+ else
+ {
+ m_pOccupyButton->SetText( "Get In" );
+ m_pOccupyButton->SetEnabled( true );
+ }
+ }
+ else
+ {
+ m_pOccupyButton->SetText( "Get In" );
+ m_pOccupyButton->SetEnabled( pRam->GetPassengerCount() < pRam->GetMaxPassengerCount() );
+ }
+}
+
+
+void CVehicleMortarControlPanel::OnTickDeployPanel( float flDeployTime )
+{
+ ShowDismantleButton( false );
+
+ // Update the countdown.
+ int nSec = (int)(flDeployTime - gpGlobals->curtime + 0.5f);
+ if (nSec < 0)
+ nSec = 0;
+
+ char buf[256];
+ int nLen = Q_snprintf( buf, sizeof( buf ), "%d second", nSec );
+ if (nSec != 1)
+ {
+ buf[nLen] = 's';
+ ++nLen;
+ buf[nLen] = 0;
+ }
+
+ m_pDeployTimeLabel->SetText( buf );
+}
+
+
+void CVehicleMortarControlPanel::OnTickGunnerPanel()
+{
+ C_VehicleMortar *pMortar = GetMortar();
+ if ( !pMortar )
+ return;
+
+ ShowOwnerLabel( false );
+ ShowHealthLabel( false );
+
+ m_pMinimapPanel->Repaint();
+
+ // If it's reloading, tell the player
+ m_pReloadingLabel->SetVisible( pMortar->m_bMortarReloading );
+ if ( pMortar->m_bMortarReloading )
+ {
+ return;
+ }
+
+ float flAccuracySpeed = (1.0 / MORTAR_CHARGE_ACCURACY_RATE);
+
+ // Handle power charging
+ switch( pMortar->m_iFiringState )
+ {
+ case MORTAR_IDLE:
+ pMortar->m_flPower = 0;
+ break;
+
+ case MORTAR_CHARGING_POWER:
+ pMortar->m_flPower = MIN( pMortar->m_flPower + ( (1.0 / MORTAR_CHARGE_POWER_RATE) * gpGlobals->frametime), 1 );
+ pMortar->m_flFiringPower = 0;
+ pMortar->m_flFiringAccuracy = 0;
+ if ( pMortar->m_flPower >= 1.0 )
+ {
+ // Hit Max, start going down
+ pMortar->m_flFiringPower = pMortar->m_flPower;
+ pMortar->m_iFiringState = MORTAR_CHARGING_ACCURACY;
+ }
+ break;
+
+ case MORTAR_CHARGING_ACCURACY:
+ // Calculate accuracy speed
+ if ( pMortar->m_flFiringPower > 0.5 )
+ {
+ // Shots over halfway suffer an increased speed to the accuracy power, making accurate shots harder
+ float flAdjustedPower = (pMortar->m_flFiringPower - 0.5) * 3.0;
+ flAccuracySpeed += (pMortar->m_flFiringPower * flAdjustedPower);
+ }
+
+ pMortar->m_flPower = MAX( pMortar->m_flPower - ( flAccuracySpeed * gpGlobals->frametime), -0.25f);
+ if ( pMortar->m_flPower <= -0.25 )
+ {
+ // Hit Min, fire mortar
+ pMortar->m_flFiringAccuracy = pMortar->m_flPower;
+ pMortar->m_iFiringState = MORTAR_IDLE;
+
+ pMortar->FireMortar();
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Handle clicking on the Occupy button
+//-----------------------------------------------------------------------------
+void CVehicleMortarControlPanel::GetInRam( void )
+{
+ SendToServerObject( "toggle_use" );
+}
+
+//-----------------------------------------------------------------------------
+// Starts/stops deploying
+//-----------------------------------------------------------------------------
+
+bool CVehicleMortarControlPanel::IsDeploying() const
+{
+ C_VehicleMortar *pMortar = GetMortar();
+ if ( !pMortar )
+ return false;
+
+ return !IsDeployed() && pMortar->GetDeployFinishTime() > 0.0f;
+}
+
+bool CVehicleMortarControlPanel::IsUndeploying() const
+{
+ C_VehicleMortar *pMortar = GetMortar();
+ if ( !pMortar )
+ return false;
+
+ return IsDeployed() && pMortar->GetDeployFinishTime() > 0.0f;
+}
+
+bool CVehicleMortarControlPanel::IsDeployed() const
+{
+ C_VehicleMortar *pMortar = GetMortar();
+ if ( pMortar )
+ return pMortar->GetVehicleModeDeploy() == VEHICLE_MODE_DEPLOYED;
+ else
+ return false;
+}
+
+//-----------------------------------------------------------------------------
+// Button click handlers
+//-----------------------------------------------------------------------------
+void CVehicleMortarControlPanel::OnCommand( const char *command )
+{
+ C_VehicleMortar *pMortar = GetMortar();
+ if ( !pMortar )
+ return;
+
+ if (!Q_strnicmp(command, "Occupy", 7))
+ {
+ GetInRam();
+ return;
+ }
+ else if ( !Q_stricmp( command, "Deploy" ) )
+ {
+ m_pDeployMessageLabel->SetText( "Deployed in" );
+ m_pCancelDeployButton->SetVisible( true );
+
+ SendToServerObject( "Deploy" ); // Tell the server.
+ }
+ else if ( !Q_stricmp( command, "CancelDeploy" ) )
+ {
+ SendToServerObject( command );
+ }
+ else if ( !Q_stricmp( command, "Undeploy" ) )
+ {
+ m_pDeployMessageLabel->SetText( "Undeployed in" );
+ m_pCancelDeployButton->SetVisible( false );
+
+ SendToServerObject( "Undeploy" ); // Tell the server.
+ }
+ else if ( !Q_stricmp( command, "FireMortar" ) )
+ {
+ pMortar->ClickFire();
+ }
+
+ BaseClass::OnCommand(command);
+}
+
diff --git a/game/client/tf2/c_vehicle_motorcycle.cpp b/game/client/tf2/c_vehicle_motorcycle.cpp
new file mode 100644
index 0000000..441e74d
--- /dev/null
+++ b/game/client/tf2/c_vehicle_motorcycle.cpp
@@ -0,0 +1,184 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+#include "cbase.h"
+#include "c_basefourwheelvehicle.h"
+#include "tf_movedata.h"
+#include "ObjectControlPanel.h"
+#include <vgui_controls/Label.h>
+#include <vgui_controls/Button.h>
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+class C_VehicleMotorcycle : public C_BaseTFFourWheelVehicle
+{
+ DECLARE_CLASS( C_VehicleMotorcycle, C_BaseTFFourWheelVehicle );
+public:
+ DECLARE_CLIENTCLASS();
+
+ C_VehicleMotorcycle();
+
+private:
+ C_VehicleMotorcycle( const C_VehicleMotorcycle & ); // not defined, not accessible
+
+};
+
+
+IMPLEMENT_CLIENTCLASS_DT(C_VehicleMotorcycle, DT_VehicleMotorcycle, CVehicleMotorcycle)
+END_RECV_TABLE()
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+C_VehicleMotorcycle::C_VehicleMotorcycle()
+{
+}
+
+
+
+//-----------------------------------------------------------------------------
+// Control screen
+//-----------------------------------------------------------------------------
+class CVehicleMotorcycleControlPanel : public CObjectControlPanel
+{
+ DECLARE_CLASS( CVehicleMotorcycleControlPanel, CObjectControlPanel );
+
+public:
+ CVehicleMotorcycleControlPanel( vgui::Panel *parent, const char *panelName );
+ virtual bool Init( KeyValues* pKeyValues, VGuiScreenInitData_t* pInitData );
+ virtual void OnTick();
+ virtual void OnCommand( const char *command );
+
+private:
+ void GetInCycle( void );
+
+private:
+ vgui::Label *m_pDriverLabel;
+ vgui::Label *m_pPassengerLabel;
+ vgui::Button *m_pOccupyButton;
+};
+
+
+DECLARE_VGUI_SCREEN_FACTORY( CVehicleMotorcycleControlPanel, "vehicle_wagon_control_panel" );
+
+
+//-----------------------------------------------------------------------------
+// Constructor:
+//-----------------------------------------------------------------------------
+CVehicleMotorcycleControlPanel::CVehicleMotorcycleControlPanel( vgui::Panel *parent, const char *panelName )
+ : BaseClass( parent, "CVehicleMotorcycleControlPanel" )
+{
+}
+
+
+//-----------------------------------------------------------------------------
+// Initialization
+//-----------------------------------------------------------------------------
+bool CVehicleMotorcycleControlPanel::Init( KeyValues* pKeyValues, VGuiScreenInitData_t* pInitData )
+{
+ m_pDriverLabel = new vgui::Label( this, "DriverReadout", "" );
+ m_pPassengerLabel = new vgui::Label( this, "PassengerReadout", "" );
+ m_pOccupyButton = new vgui::Button( this, "OccupyButton", "Occupy" );
+
+ if (!BaseClass::Init(pKeyValues, pInitData))
+ return false;
+
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+// Frame-based update
+//-----------------------------------------------------------------------------
+void CVehicleMotorcycleControlPanel::OnTick()
+{
+ BaseClass::OnTick();
+
+ C_BaseObject *pObj = GetOwningObject();
+ if (!pObj)
+ return;
+
+ Assert( dynamic_cast<C_VehicleMotorcycle*>(pObj) );
+ C_VehicleMotorcycle *pCycle = static_cast<C_VehicleMotorcycle*>(pObj);
+
+ char buf[256];
+ // Update the currently manned player label
+ if ( pCycle->GetDriverPlayer() )
+ {
+ Q_snprintf( buf, sizeof( buf ), "Driven by %s", pCycle->GetDriverPlayer()->GetPlayerName() );
+ m_pDriverLabel->SetText( buf );
+ m_pDriverLabel->SetVisible( true );
+ }
+ else
+ {
+ m_pDriverLabel->SetVisible( false );
+ }
+
+ int nPassengerCount = pCycle->GetPassengerCount();
+ int nMaxPassengerCount = pCycle->GetMaxPassengerCount();
+
+ Q_snprintf( buf, sizeof( buf ), "Passengers %d/%d", nPassengerCount >= 1 ? nPassengerCount - 1 : 0, nMaxPassengerCount - 1 );
+ m_pPassengerLabel->SetText( buf );
+
+ // Update the get in button
+ if ( pCycle->IsPlayerInVehicle( C_BaseTFPlayer::GetLocalPlayer() ) )
+ {
+ m_pOccupyButton->SetEnabled( false );
+ return;
+ }
+
+ if ( pCycle->GetOwner() == C_BaseTFPlayer::GetLocalPlayer() )
+ {
+ if (nPassengerCount == nMaxPassengerCount)
+ {
+ // Owners can boot other players to get in
+ C_BaseTFPlayer *pPlayer = static_cast<C_BaseTFPlayer*>(pCycle->GetPassenger( VEHICLE_ROLE_DRIVER ));
+ Q_snprintf( buf, sizeof( buf ), "Get In (Ejecting %s)", pPlayer->GetPlayerName() );
+ m_pDriverLabel->SetText( buf );
+ m_pOccupyButton->SetEnabled( true );
+ }
+ else
+ {
+ m_pOccupyButton->SetText( "Get In" );
+ m_pOccupyButton->SetEnabled( true );
+ }
+ }
+ else
+ {
+ m_pOccupyButton->SetText( "Get In" );
+ m_pOccupyButton->SetEnabled( pCycle->GetPassengerCount() < pCycle->GetMaxPassengerCount() );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Handle clicking on the Occupy button
+//-----------------------------------------------------------------------------
+void CVehicleMotorcycleControlPanel::GetInCycle( void )
+{
+ C_BaseObject *pObj = GetOwningObject();
+ if (pObj)
+ {
+ pObj->SendClientCommand( "toggle_use" );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Button click handlers
+//-----------------------------------------------------------------------------
+void CVehicleMotorcycleControlPanel::OnCommand( const char *command )
+{
+ if (!Q_strnicmp(command, "Occupy", 7))
+ {
+ GetInCycle();
+ return;
+ }
+
+ BaseClass::OnCommand(command);
+}
+
diff --git a/game/client/tf2/c_vehicle_siege_tower.cpp b/game/client/tf2/c_vehicle_siege_tower.cpp
new file mode 100644
index 0000000..d82c28a
--- /dev/null
+++ b/game/client/tf2/c_vehicle_siege_tower.cpp
@@ -0,0 +1,261 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Siege Tower Vechicle
+//
+//=============================================================================//
+
+#include "cbase.h"
+#include "c_basefourwheelvehicle.h"
+#include "tf_movedata.h"
+#include "ObjectControlPanel.h"
+#include <vgui_controls/Label.h>
+#include "vgui_bitmapbutton.h"
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+class C_VehicleSiegeTower : public C_BaseTFFourWheelVehicle
+{
+ DECLARE_CLASS( C_VehicleSiegeTower, C_BaseTFFourWheelVehicle );
+
+public:
+
+ DECLARE_CLIENTCLASS();
+
+ C_VehicleSiegeTower();
+
+// C_BaseEntity overrides.
+public:
+
+// virtual void DebugMessages( void );
+
+private:
+
+ C_VehicleSiegeTower( const C_VehicleSiegeTower & ); // not defined, not accessible
+};
+
+IMPLEMENT_CLIENTCLASS_DT( C_VehicleSiegeTower, DT_VehicleSiegeTower, CVehicleSiegeTower )
+END_RECV_TABLE()
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+C_VehicleSiegeTower::C_VehicleSiegeTower()
+{
+}
+
+#if 0
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void C_VehicleSiegeTower::DebugMessages( void )
+{
+ Msg( "Seq: %d, Play: %f, Cycle: %f, Anim %f, Done: %d\n", GetSequence(), m_flPlaybackRate, GetCycle(), m_flAnimTime,
+ ( int )m_fSequenceFinished );
+}
+#endif
+
+//-----------------------------------------------------------------------------
+// Control screen
+//-----------------------------------------------------------------------------
+class CVehicleSiegeTowerControlPanel : public CObjectControlPanel
+{
+ DECLARE_CLASS( CVehicleSiegeTowerControlPanel, CObjectControlPanel );
+
+public:
+
+ CVehicleSiegeTowerControlPanel( vgui::Panel *parent, const char *panelName );
+ virtual bool Init( KeyValues* pKeyValues, VGuiScreenInitData_t* pInitData );
+ virtual void OnTick();
+ virtual void OnCommand( const char *command );
+
+private:
+
+ void GetInTower( void );
+
+private:
+
+ vgui::Label *m_pDriverLabel;
+ vgui::Label *m_pPassengerLabel;
+ vgui::Button *m_pOccupyButton;
+};
+
+DECLARE_VGUI_SCREEN_FACTORY( CVehicleSiegeTowerControlPanel, "vehicle_siege_tower_control_panel" );
+
+//-----------------------------------------------------------------------------
+// Constructor:
+//-----------------------------------------------------------------------------
+CVehicleSiegeTowerControlPanel::CVehicleSiegeTowerControlPanel( vgui::Panel *parent, const char *panelName )
+ : BaseClass( parent, "CVehicleSiegeTowerControlPanel" )
+{
+}
+
+//-----------------------------------------------------------------------------
+// Initialization
+//-----------------------------------------------------------------------------
+bool CVehicleSiegeTowerControlPanel::Init( KeyValues* pKeyValues, VGuiScreenInitData_t* pInitData )
+{
+ m_pDriverLabel = new vgui::Label( this, "DriverReadout", "" );
+ m_pPassengerLabel = new vgui::Label( this, "PassengerReadout", "" );
+ m_pOccupyButton = new CBitmapButton( this, "OccupyButton", "Occupy" );
+
+ if ( !BaseClass::Init( pKeyValues, pInitData ) )
+ return false;
+
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// Frame-based update
+//-----------------------------------------------------------------------------
+void CVehicleSiegeTowerControlPanel::OnTick()
+{
+ BaseClass::OnTick();
+
+ C_BaseObject *pObj = GetOwningObject();
+ if ( !pObj )
+ return;
+
+ Assert( dynamic_cast<C_VehicleSiegeTower*>( pObj ) );
+ C_VehicleSiegeTower *pTower = static_cast<C_VehicleSiegeTower*>( pObj );
+
+ char buf[256];
+ // Update the currently manned player label
+ if ( pTower->GetDriverPlayer() )
+ {
+ Q_snprintf( buf, sizeof( buf ), "Driven by %s", pTower->GetDriverPlayer()->GetPlayerName() );
+ m_pDriverLabel->SetText( buf );
+ m_pDriverLabel->SetVisible( true );
+ }
+ else
+ {
+ m_pDriverLabel->SetVisible( false );
+ }
+
+ int nPassengerCount = pTower->GetPassengerCount();
+ int nMaxPassengerCount = pTower->GetMaxPassengerCount();
+
+ Q_snprintf( buf, sizeof( buf ), "Passengers %d/%d", nPassengerCount >= 1 ? nPassengerCount - 1 : 0, nMaxPassengerCount - 1 );
+ m_pPassengerLabel->SetText( buf );
+
+ // Update the get in button
+ if ( pTower->IsPlayerInVehicle( C_BaseTFPlayer::GetLocalPlayer() ) )
+ {
+ m_pOccupyButton->SetEnabled( false );
+ return;
+ }
+
+ if ( pTower->GetOwner() == C_BaseTFPlayer::GetLocalPlayer() )
+ {
+ if ( nPassengerCount == nMaxPassengerCount )
+ {
+ // Owners can boot other players to get in
+ C_BaseTFPlayer *pPlayer = static_cast<C_BaseTFPlayer*>( pTower->GetPassenger( VEHICLE_ROLE_DRIVER ) );
+ Q_snprintf( buf, sizeof( buf ), "Get In (Ejecting %s)", pPlayer->GetPlayerName() );
+ m_pDriverLabel->SetText( buf );
+ m_pOccupyButton->SetEnabled( true );
+ }
+ else
+ {
+ m_pOccupyButton->SetText( "Get In" );
+ m_pOccupyButton->SetEnabled( true );
+ }
+ }
+ else
+ {
+ m_pOccupyButton->SetText( "Get In" );
+ m_pOccupyButton->SetEnabled( pTower->GetPassengerCount() < pTower->GetMaxPassengerCount() );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Handle clicking on the Occupy button
+//-----------------------------------------------------------------------------
+void CVehicleSiegeTowerControlPanel::GetInTower( void )
+{
+ C_BaseObject *pObj = GetOwningObject();
+ if ( pObj )
+ {
+ pObj->SendClientCommand( "toggle_use" );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Button click handlers
+//-----------------------------------------------------------------------------
+void CVehicleSiegeTowerControlPanel::OnCommand( const char *command )
+{
+ if ( !Q_strnicmp( command, "Occupy", 7 ) )
+ {
+ GetInTower();
+ return;
+ }
+
+ BaseClass::OnCommand( command );
+}
+
+//=============================================================================
+//
+// Siege Ladder
+//
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+class C_ObjectSiegeLadder : public C_BaseAnimating
+{
+ DECLARE_CLASS( C_ObjectSiegeLadder, C_BaseAnimating );
+
+public:
+
+ DECLARE_CLIENTCLASS();
+
+ C_ObjectSiegeLadder();
+
+private:
+ C_ObjectSiegeLadder( const C_ObjectSiegeLadder& ); // not defined, not accessible
+};
+
+IMPLEMENT_CLIENTCLASS_DT( C_ObjectSiegeLadder, DT_ObjectSiegeLadder, CObjectSiegeLadder )
+END_RECV_TABLE()
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+C_ObjectSiegeLadder::C_ObjectSiegeLadder()
+{
+}
+
+
+//=============================================================================
+//
+// Siege Platform
+//
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+class C_ObjectSiegePlatform : public C_BaseAnimating
+{
+ DECLARE_CLASS( C_ObjectSiegePlatform, C_BaseAnimating );
+
+public:
+
+ DECLARE_CLIENTCLASS();
+
+ C_ObjectSiegePlatform();
+
+private:
+ C_ObjectSiegePlatform( const C_ObjectSiegePlatform& ); // not defined, not accessible
+};
+
+IMPLEMENT_CLIENTCLASS_DT( C_ObjectSiegePlatform, DT_ObjectSiegePlatform, CObjectSiegePlatform )
+END_RECV_TABLE()
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+C_ObjectSiegePlatform::C_ObjectSiegePlatform()
+{
+}
+
diff --git a/game/client/tf2/c_vehicle_tank.cpp b/game/client/tf2/c_vehicle_tank.cpp
new file mode 100644
index 0000000..be29039
--- /dev/null
+++ b/game/client/tf2/c_vehicle_tank.cpp
@@ -0,0 +1,150 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#include "cbase.h"
+#include "c_basefourwheelvehicle.h"
+#include "tf_movedata.h"
+#include "ObjectControlPanel.h"
+#include <vgui_controls/Label.h>
+#include <vgui_controls/Button.h>
+#include "vgui_rotation_slider.h"
+#include <vgui/ISurface.h>
+#include "vgui_basepanel.h"
+#include "ground_line.h"
+#include "hud_minimap.h"
+#include "vgui_bitmapimage.h"
+#include "view.h"
+#include "c_basetempentity.h"
+#include "particles_simple.h"
+#include "in_buttons.h"
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+class C_VehicleTank : public C_BaseTFFourWheelVehicle
+{
+ DECLARE_CLASS( C_VehicleTank, C_BaseTFFourWheelVehicle );
+public:
+ DECLARE_CLIENTCLASS();
+
+ C_VehicleTank();
+
+
+ virtual void ClientThink();
+
+ virtual void OnItemPostFrame( CBaseTFPlayer *pDriver );
+
+// C_BaseEntity overrides.
+public:
+ virtual void GetBoneControllers(float controllers[MAXSTUDIOBONECTRLS]);
+
+private:
+ C_VehicleTank( const C_VehicleTank & ); // not defined, not accessible
+
+ float m_flClientYaw;
+ float m_flClientPitch;
+
+ // Sent by the server. This is what we render with.
+ float m_flTurretYaw;
+ float m_flTurretPitch;
+};
+
+
+IMPLEMENT_CLIENTCLASS_DT( C_VehicleTank, DT_VehicleTank, CVehicleTank )
+ RecvPropFloat( RECVINFO( m_flTurretYaw ) ),
+ RecvPropFloat( RECVINFO( m_flTurretPitch ) )
+END_RECV_TABLE()
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+
+C_VehicleTank::C_VehicleTank()
+{
+ m_flClientYaw = 0;
+ m_flClientPitch = 0;
+ m_flTurretYaw = 0;
+ m_flTurretPitch = 0;
+}
+
+
+void C_VehicleTank::ClientThink()
+{
+ if ( GetPassenger( VEHICLE_ROLE_DRIVER ) == C_BasePlayer::GetLocalPlayer() )
+ {
+ // Cast a ray out of the view to see where the player is looking.
+ trace_t trace;
+ UTIL_TraceLine(
+ MainViewOrigin(),
+ MainViewOrigin() + MainViewForward() * 100000,
+ MASK_OPAQUE, NULL,
+ COLLISION_GROUP_NONE,
+ &trace );
+
+ if ( trace.fraction < 1 )
+ {
+ // Figure out what angles our turret needs to be at in order to hit the target.
+
+ Vector vFireOrigin;
+ QAngle dummy;
+ GetAttachment( LookupAttachment( "barrel" ), vFireOrigin, dummy );
+
+ // Get a direction vector that points at the target.
+ Vector vTo = trace.endpos - vFireOrigin;
+
+ // Transform it into the tank's local space.
+ matrix3x4_t tankToWorld;
+ AngleMatrix( GetAbsAngles(), tankToWorld );
+
+ Vector vLocalTo;
+ VectorITransform( vTo, tankToWorld, vLocalTo );
+
+ // Now figure out what the angles are in local space.
+ QAngle localAngles;
+ VectorAngles( vLocalTo, localAngles );
+
+ // Make the angles adhere to the definition in CVehicleTank's header.
+ m_flClientYaw = localAngles[YAW] - 90;
+ m_flClientPitch = anglemod( -localAngles[PITCH] );
+
+
+ char cmd[512];
+ Q_snprintf( cmd, sizeof( cmd ), "TurretAngles %.2f %.2f", m_flClientYaw, m_flClientPitch );
+ SendClientCommand( cmd );
+ }
+ }
+
+ BaseClass::ClientThink();
+}
+
+
+void C_VehicleTank::GetBoneControllers( float controllers[MAXSTUDIOBONECTRLS])
+{
+ BaseClass::GetBoneControllers( controllers );
+
+ controllers[0] = anglemod( m_flTurretYaw ) / 360.0;
+ controllers[1] = anglemod( m_flTurretPitch ) / 360.0;
+}
+
+//-----------------------------------------------------------------------------
+// Here's where we deal with weapons
+//-----------------------------------------------------------------------------
+void C_VehicleTank::OnItemPostFrame( CBaseTFPlayer *pDriver )
+{
+ if ( GetPassengerRole(pDriver) != VEHICLE_ROLE_DRIVER )
+ return;
+
+ if ( pDriver->m_nButtons & IN_ATTACK )
+ {
+ }
+ else if ( pDriver->m_nButtons & (IN_ATTACK2 | IN_SPEED) )
+ {
+ BaseClass::OnItemPostFrame( pDriver );
+ }
+}
+
diff --git a/game/client/tf2/c_vehicle_tank.h b/game/client/tf2/c_vehicle_tank.h
new file mode 100644
index 0000000..7033962
--- /dev/null
+++ b/game/client/tf2/c_vehicle_tank.h
@@ -0,0 +1,14 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#ifndef C_VEHICLE_TANK_H
+#define C_VEHICLE_TANK_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+
+#endif // C_VEHICLE_TANK_H
diff --git a/game/client/tf2/c_vehicle_teleport_station.cpp b/game/client/tf2/c_vehicle_teleport_station.cpp
new file mode 100644
index 0000000..c2cf88a
--- /dev/null
+++ b/game/client/tf2/c_vehicle_teleport_station.cpp
@@ -0,0 +1,168 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+#include "cbase.h"
+#include "c_basefourwheelvehicle.h"
+#include "tf_movedata.h"
+#include "ObjectControlPanel.h"
+#include <vgui_controls/Label.h>
+#include <vgui_controls/Button.h>
+#include "c_vehicle_teleport_station.h"
+
+
+
+IMPLEMENT_CLIENTCLASS_DT(C_VehicleTeleportStation, DT_VehicleTeleportStation, CVehicleTeleportStation)
+END_RECV_TABLE()
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+C_VehicleTeleportStation::C_VehicleTeleportStation()
+{
+}
+
+
+//-----------------------------------------------------------------------------
+// Control screen
+//-----------------------------------------------------------------------------
+class CVehicleTeleportStationControlPanel : public CObjectControlPanel
+{
+ DECLARE_CLASS( CVehicleTeleportStationControlPanel, CObjectControlPanel );
+
+public:
+ CVehicleTeleportStationControlPanel( vgui::Panel *parent, const char *panelName );
+ virtual bool Init( KeyValues* pKeyValues, VGuiScreenInitData_t* pInitData );
+ virtual void OnTick();
+ virtual void OnCommand( const char *command );
+
+private:
+ void GetInVehicle( void );
+
+private:
+ vgui::Label *m_pDriverLabel;
+ vgui::Label *m_pPassengerLabel;
+ vgui::Button *m_pOccupyButton;
+};
+
+
+DECLARE_VGUI_SCREEN_FACTORY( CVehicleTeleportStationControlPanel, "vehicle_teleport_station_control_panel" );
+
+
+//-----------------------------------------------------------------------------
+// Constructor:
+//-----------------------------------------------------------------------------
+CVehicleTeleportStationControlPanel::CVehicleTeleportStationControlPanel( vgui::Panel *parent, const char *panelName )
+ : BaseClass( parent, "CVehicleTeleportStationControlPanel" )
+{
+}
+
+
+//-----------------------------------------------------------------------------
+// Initialization
+//-----------------------------------------------------------------------------
+bool CVehicleTeleportStationControlPanel::Init( KeyValues* pKeyValues, VGuiScreenInitData_t* pInitData )
+{
+ m_pDriverLabel = new vgui::Label( this, "DriverReadout", "" );
+ m_pPassengerLabel = new vgui::Label( this, "PassengerReadout", "" );
+ m_pOccupyButton = new vgui::Button( this, "OccupyButton", "Occupy" );
+
+ if (!BaseClass::Init(pKeyValues, pInitData))
+ return false;
+
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+// Frame-based update
+//-----------------------------------------------------------------------------
+void CVehicleTeleportStationControlPanel::OnTick()
+{
+ BaseClass::OnTick();
+
+ C_BaseObject *pObj = GetOwningObject();
+ if (!pObj)
+ return;
+
+ Assert( dynamic_cast<C_VehicleTeleportStation*>(pObj) );
+ C_VehicleTeleportStation *pVehicle = static_cast<C_VehicleTeleportStation*>(pObj);
+
+ char buf[256];
+ // Update the currently manned player label
+ if ( pVehicle->GetDriverPlayer() )
+ {
+ Q_snprintf( buf, sizeof( buf ), "Driven by %s", pVehicle->GetDriverPlayer()->GetPlayerName() );
+ m_pDriverLabel->SetText( buf );
+ m_pDriverLabel->SetVisible( true );
+ }
+ else
+ {
+ m_pDriverLabel->SetVisible( false );
+ }
+
+ int nPassengerCount = pVehicle->GetPassengerCount();
+ int nMaxPassengerCount = pVehicle->GetMaxPassengerCount();
+
+ Q_snprintf( buf, sizeof( buf ), "Passengers %d/%d", nPassengerCount >= 1 ? nPassengerCount - 1 : 0, nMaxPassengerCount - 1 );
+ m_pPassengerLabel->SetText( buf );
+
+ // Update the get in button
+ if ( pVehicle->IsPlayerInVehicle( C_BaseTFPlayer::GetLocalPlayer() ) )
+ {
+ m_pOccupyButton->SetEnabled( false );
+ return;
+ }
+
+ if ( pVehicle->GetOwner() == C_BaseTFPlayer::GetLocalPlayer() )
+ {
+ if (nPassengerCount == nMaxPassengerCount)
+ {
+ // Owners can boot other players to get in
+ C_BaseTFPlayer *pPlayer = static_cast<C_BaseTFPlayer*>(pVehicle->GetPassenger( VEHICLE_ROLE_DRIVER ));
+ Q_snprintf( buf, sizeof( buf ), "Get In (Ejecting %s)", pPlayer->GetPlayerName() );
+ m_pDriverLabel->SetText( buf );
+ m_pOccupyButton->SetEnabled( true );
+ }
+ else
+ {
+ m_pOccupyButton->SetText( "Get In" );
+ m_pOccupyButton->SetEnabled( true );
+ }
+ }
+ else
+ {
+ m_pOccupyButton->SetText( "Get In" );
+ m_pOccupyButton->SetEnabled( pVehicle->GetPassengerCount() < pVehicle->GetMaxPassengerCount() );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Handle clicking on the Occupy button
+//-----------------------------------------------------------------------------
+void CVehicleTeleportStationControlPanel::GetInVehicle( void )
+{
+ C_BaseObject *pObj = GetOwningObject();
+ if (pObj)
+ {
+ pObj->SendClientCommand( "toggle_use" );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Button click handlers
+//-----------------------------------------------------------------------------
+void CVehicleTeleportStationControlPanel::OnCommand( const char *command )
+{
+ if (!Q_strnicmp(command, "Occupy", 7))
+ {
+ GetInVehicle();
+ return;
+ }
+
+ BaseClass::OnCommand(command);
+}
+
diff --git a/game/client/tf2/c_vehicle_teleport_station.h b/game/client/tf2/c_vehicle_teleport_station.h
new file mode 100644
index 0000000..4796660
--- /dev/null
+++ b/game/client/tf2/c_vehicle_teleport_station.h
@@ -0,0 +1,33 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#ifndef C_VEHICLE_TELEPORT_STATION_H
+#define C_VEHICLE_TELEPORT_STATION_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+
+#include "c_basefourwheelvehicle.h"
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+class C_VehicleTeleportStation : public C_BaseTFFourWheelVehicle
+{
+ DECLARE_CLASS( C_VehicleTeleportStation, C_BaseTFFourWheelVehicle );
+public:
+ DECLARE_CLIENTCLASS();
+
+ C_VehicleTeleportStation();
+
+private:
+ C_VehicleTeleportStation( const C_VehicleTeleportStation & ); // not defined, not accessible
+};
+
+
+#endif // C_VEHICLE_TELEPORT_STATION_H
diff --git a/game/client/tf2/c_vehicle_wagon.cpp b/game/client/tf2/c_vehicle_wagon.cpp
new file mode 100644
index 0000000..475e9f3
--- /dev/null
+++ b/game/client/tf2/c_vehicle_wagon.cpp
@@ -0,0 +1,183 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+#include "cbase.h"
+#include "c_basefourwheelvehicle.h"
+#include "tf_movedata.h"
+#include "ObjectControlPanel.h"
+#include <vgui_controls/Label.h>
+#include <vgui_controls/Button.h>
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+class C_VehicleWagon : public C_BaseTFFourWheelVehicle
+{
+ DECLARE_CLASS( C_VehicleWagon, C_BaseTFFourWheelVehicle );
+public:
+ DECLARE_CLIENTCLASS();
+
+ C_VehicleWagon();
+
+private:
+ C_VehicleWagon( const C_VehicleWagon & ); // not defined, not accessible
+
+};
+
+
+IMPLEMENT_CLIENTCLASS_DT(C_VehicleWagon, DT_VehicleWagon, CVehicleWagon)
+END_RECV_TABLE()
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+C_VehicleWagon::C_VehicleWagon()
+{
+}
+
+
+//-----------------------------------------------------------------------------
+// Control screen
+//-----------------------------------------------------------------------------
+class CVehicleWagonControlPanel : public CObjectControlPanel
+{
+ DECLARE_CLASS( CVehicleWagonControlPanel, CObjectControlPanel );
+
+public:
+ CVehicleWagonControlPanel( vgui::Panel *parent, const char *panelName );
+ virtual bool Init( KeyValues* pKeyValues, VGuiScreenInitData_t* pInitData );
+ virtual void OnTick();
+ virtual void OnCommand( const char *command );
+
+private:
+ void GetInRam( void );
+
+private:
+ vgui::Label *m_pDriverLabel;
+ vgui::Label *m_pPassengerLabel;
+ vgui::Button *m_pOccupyButton;
+};
+
+
+DECLARE_VGUI_SCREEN_FACTORY( CVehicleWagonControlPanel, "vehicle_wagon_control_panel" );
+
+
+//-----------------------------------------------------------------------------
+// Constructor:
+//-----------------------------------------------------------------------------
+CVehicleWagonControlPanel::CVehicleWagonControlPanel( vgui::Panel *parent, const char *panelName )
+ : BaseClass( parent, "CVehicleBatteringRamControlPanel" )
+{
+}
+
+
+//-----------------------------------------------------------------------------
+// Initialization
+//-----------------------------------------------------------------------------
+bool CVehicleWagonControlPanel::Init( KeyValues* pKeyValues, VGuiScreenInitData_t* pInitData )
+{
+ m_pDriverLabel = new vgui::Label( this, "DriverReadout", "" );
+ m_pPassengerLabel = new vgui::Label( this, "PassengerReadout", "" );
+ m_pOccupyButton = new vgui::Button( this, "OccupyButton", "Occupy" );
+
+ if (!BaseClass::Init(pKeyValues, pInitData))
+ return false;
+
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+// Frame-based update
+//-----------------------------------------------------------------------------
+void CVehicleWagonControlPanel::OnTick()
+{
+ BaseClass::OnTick();
+
+ C_BaseObject *pObj = GetOwningObject();
+ if (!pObj)
+ return;
+
+ Assert( dynamic_cast<C_VehicleWagon*>(pObj) );
+ C_VehicleWagon *pWagon = static_cast<C_VehicleWagon*>(pObj);
+
+ char buf[256];
+ // Update the currently manned player label
+ if ( pWagon->GetDriverPlayer() )
+ {
+ Q_snprintf( buf, sizeof( buf ), "Driven by %s", pWagon->GetDriverPlayer()->GetPlayerName() );
+ m_pDriverLabel->SetText( buf );
+ m_pDriverLabel->SetVisible( true );
+ }
+ else
+ {
+ m_pDriverLabel->SetVisible( false );
+ }
+
+ int nPassengerCount = pWagon->GetPassengerCount();
+ int nMaxPassengerCount = pWagon->GetMaxPassengerCount();
+
+ Q_snprintf( buf, sizeof( buf ), "Passengers %d/%d", nPassengerCount >= 1 ? nPassengerCount - 1 : 0, nMaxPassengerCount - 1 );
+ m_pPassengerLabel->SetText( buf );
+
+ // Update the get in button
+ if ( pWagon->IsPlayerInVehicle( C_BaseTFPlayer::GetLocalPlayer() ) )
+ {
+ m_pOccupyButton->SetEnabled( false );
+ return;
+ }
+
+ if ( pWagon->GetOwner() == C_BaseTFPlayer::GetLocalPlayer() )
+ {
+ if (nPassengerCount == nMaxPassengerCount)
+ {
+ // Owners can boot other players to get in
+ C_BaseTFPlayer *pPlayer = static_cast<C_BaseTFPlayer*>(pWagon->GetPassenger( VEHICLE_ROLE_DRIVER ));
+ Q_snprintf( buf, sizeof( buf ), "Get In (Ejecting %s)", pPlayer->GetPlayerName() );
+ m_pDriverLabel->SetText( buf );
+ m_pOccupyButton->SetEnabled( true );
+ }
+ else
+ {
+ m_pOccupyButton->SetText( "Get In" );
+ m_pOccupyButton->SetEnabled( true );
+ }
+ }
+ else
+ {
+ m_pOccupyButton->SetText( "Get In" );
+ m_pOccupyButton->SetEnabled( pWagon->GetPassengerCount() < pWagon->GetMaxPassengerCount() );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Handle clicking on the Occupy button
+//-----------------------------------------------------------------------------
+void CVehicleWagonControlPanel::GetInRam( void )
+{
+ C_BaseObject *pObj = GetOwningObject();
+ if (pObj)
+ {
+ pObj->SendClientCommand( "toggle_use" );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Button click handlers
+//-----------------------------------------------------------------------------
+void CVehicleWagonControlPanel::OnCommand( const char *command )
+{
+ if (!Q_strnicmp(command, "Occupy", 7))
+ {
+ GetInRam();
+ return;
+ }
+
+ BaseClass::OnCommand(command);
+}
+
diff --git a/game/client/tf2/c_walker_base.cpp b/game/client/tf2/c_walker_base.cpp
new file mode 100644
index 0000000..004e9c6
--- /dev/null
+++ b/game/client/tf2/c_walker_base.cpp
@@ -0,0 +1,20 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#include "cbase.h"
+#include "c_walker_base.h"
+
+
+IMPLEMENT_CLIENTCLASS_DT( C_WalkerBase, DT_WalkerBase, CWalkerBase )
+END_RECV_TABLE()
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void C_WalkerBase::OnDataChanged( DataUpdateType_t updateType )
+{
+ BaseClass::OnDataChanged( updateType );
+}
diff --git a/game/client/tf2/c_walker_base.h b/game/client/tf2/c_walker_base.h
new file mode 100644
index 0000000..62205bf
--- /dev/null
+++ b/game/client/tf2/c_walker_base.h
@@ -0,0 +1,33 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#ifndef C_WALKER_BASE_H
+#define C_WALKER_BASE_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+
+#include "basetfvehicle.h"
+#include "client_class.h"
+
+
+class C_WalkerBase : public C_BaseTFVehicle
+{
+public:
+ DECLARE_CLIENTCLASS();
+ DECLARE_CLASS( C_WalkerBase, C_BaseTFVehicle );
+
+ C_WalkerBase() {}
+
+ virtual void OnDataChanged( DataUpdateType_t updateType );
+
+private:
+ C_WalkerBase( const C_WalkerBase &other ) {}
+};
+
+
+#endif // C_WALKER_BASE_H
diff --git a/game/client/tf2/c_walker_ministrider.cpp b/game/client/tf2/c_walker_ministrider.cpp
new file mode 100644
index 0000000..5608c1c
--- /dev/null
+++ b/game/client/tf2/c_walker_ministrider.cpp
@@ -0,0 +1,38 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#include "cbase.h"
+#include "c_walker_ministrider.h"
+#include "beamdraw.h"
+#include "view.h"
+
+
+extern ConVar vehicle_free_pitch, vehicle_free_roll;
+
+
+IMPLEMENT_CLIENTCLASS_DT( C_WalkerMiniStrider, DT_WalkerMiniStrider, CWalkerMiniStrider )
+END_RECV_TABLE()
+
+
+C_WalkerMiniStrider::C_WalkerMiniStrider()
+{
+}
+
+
+C_WalkerMiniStrider::~C_WalkerMiniStrider()
+{
+}
+
+
+void C_WalkerMiniStrider::ClientThink()
+{
+}
+
+
+void C_WalkerMiniStrider::SetupMove( CBasePlayer *pPlayer, CUserCmd *ucmd, IMoveHelper *pHelper, CMoveData *move )
+{
+}
+
diff --git a/game/client/tf2/c_walker_ministrider.h b/game/client/tf2/c_walker_ministrider.h
new file mode 100644
index 0000000..9ff51d8
--- /dev/null
+++ b/game/client/tf2/c_walker_ministrider.h
@@ -0,0 +1,63 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#ifndef C_WALKER_MINISTRIDER_H
+#define C_WALKER_MINISTRIDER_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+
+#include "c_walker_base.h"
+#include "c_rope.h"
+
+
+#define STRIDER_BEAM_LIFETIME 1.0
+#define STRIDER_BEAM_MATERIAL "sprites/physbeam"
+#define STRIDER_BEAM_WIDTH 25
+#define STRIDER_NUM_ROPES 6
+
+
+class CStriderBeamEffect
+{
+public:
+ Vector m_vHitPos;
+ float m_flStartTime;
+};
+
+
+class C_WalkerMiniStrider : public C_WalkerBase
+{
+public:
+ DECLARE_CLIENTCLASS();
+ DECLARE_CLASS( C_WalkerMiniStrider, C_WalkerBase );
+
+ C_WalkerMiniStrider();
+ virtual ~C_WalkerMiniStrider();
+
+
+// IClientThinkable.
+public:
+ virtual void ClientThink();
+
+
+// C_BaseEntity.
+public:
+
+ virtual bool ShouldPredict() { return false; }
+ virtual void SetupMove( CBasePlayer *pPlayer, CUserCmd *ucmd, IMoveHelper *pHelper, CMoveData *move );
+
+
+// C_BaseAnimating.
+public:
+
+
+private:
+ C_WalkerMiniStrider( const C_WalkerMiniStrider &other ) {}
+};
+
+
+#endif // C_WALKER_MINISTRIDER_H
diff --git a/game/client/tf2/c_walker_strider.cpp b/game/client/tf2/c_walker_strider.cpp
new file mode 100644
index 0000000..a723125
--- /dev/null
+++ b/game/client/tf2/c_walker_strider.cpp
@@ -0,0 +1,218 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#include "cbase.h"
+#include "c_walker_strider.h"
+#include "beamdraw.h"
+#include "clienteffectprecachesystem.h"
+
+extern ConVar vehicle_free_pitch, vehicle_free_roll;
+
+
+CLIENTEFFECT_REGISTER_BEGIN( PrecacheWalkerStrider )
+CLIENTEFFECT_MATERIAL( STRIDER_BEAM_MATERIAL )
+CLIENTEFFECT_REGISTER_END()
+
+
+IMPLEMENT_CLIENTCLASS_DT( C_WalkerStrider, DT_WalkerStrider, CWalkerStrider )
+ RecvPropInt( RECVINFO( m_bCrouched ) )
+END_RECV_TABLE()
+LINK_ENTITY_TO_CLASS( walker_strider, C_WalkerStrider );
+
+
+ConVar cl_brush_ropes( "cl_brush_ropes", "0" );
+
+
+C_WalkerStrider::C_WalkerStrider()
+{
+ m_bCrouched = false;
+}
+
+
+C_WalkerStrider::~C_WalkerStrider()
+{
+ for ( int i=0; i < STRIDER_NUM_ROPES; i++ )
+ {
+ if ( m_hRopes[i].Get() )
+ m_hRopes[i]->Release();
+ }
+}
+
+
+float sideDist = 90;
+float downDist = -400;
+#include "studio.h"
+bool C_WalkerStrider::GetAttachment( int iAttachment, matrix3x4_t &attachmentToWorld )
+{
+ //
+ //
+ // This is a TOTAL hack, but we don't have any nodes that work well at all for mounted guns.
+ //
+ //
+ CStudioHdr *pStudioHdr = GetModelPtr( );
+ if ( !pStudioHdr || iAttachment < 1 || iAttachment > pStudioHdr->GetNumAttachments() )
+ {
+ return false;
+ }
+
+ Vector vLocalPos( 0, 0, 0 );
+ const mstudioattachment_t &pAttachment = pStudioHdr->pAttachment( iAttachment-1 );
+ if ( stricmp( pAttachment.pszName(), "build_point_left_gun" ) == 0 )
+ {
+ vLocalPos.y = sideDist;
+ }
+ else if ( stricmp( pAttachment.pszName(), "build_point_right_gun" ) == 0 )
+ {
+ vLocalPos.y = -sideDist;
+ }
+ else if ( stricmp( pAttachment.pszName(), "ThirdPersonCameraOrigin" ) == 0 )
+ {
+ }
+ else
+ {
+ // Ok, it's not one of our magical attachments. Use the regular attachment setup stuff.
+ return BaseClass::GetAttachment( iAttachment, attachmentToWorld );
+ }
+
+ if ( m_bCrouched )
+ {
+ vLocalPos.z += downDist;
+ }
+
+ // Now build the output matrix.
+ matrix3x4_t localMatrix;
+ SetIdentityMatrix( localMatrix );
+ PositionMatrix( vLocalPos, localMatrix );
+
+ ConcatTransforms( EntityToWorldTransform(), localMatrix, attachmentToWorld );
+ return true;
+}
+
+
+void C_WalkerStrider::ReceiveMessage( int classID, bf_read &msg )
+{
+ if ( classID != GetClientClass()->m_ClassID )
+ {
+ // message is for subclass
+ BaseClass::ReceiveMessage( classID, msg );
+ return;
+ }
+
+ Vector vHitPos;
+ msg.ReadBitVec3Coord( vHitPos );
+
+ CStriderBeamEffect eff;
+ eff.m_vHitPos = vHitPos;
+ eff.m_flStartTime = gpGlobals->curtime;
+ m_BeamEffects.AddToTail( eff );
+}
+
+
+float flTestSlack = 280;
+float flTestSlack2 = 380;
+
+void C_WalkerStrider::OnDataChanged( DataUpdateType_t type )
+{
+ BaseClass::OnDataChanged( type );
+
+ if ( type == DATA_UPDATE_CREATED )
+ {
+ if ( cl_brush_ropes.GetInt() )
+ {
+ // Create some ropes and hang them off certain attachments.
+ int indices[7] =
+ {
+ LookupAttachment( "kneeL" ),
+ LookupAttachment( "kneeR" ),
+ LookupAttachment( "kneeB" ),
+
+ LookupAttachment( "MiniGun" ),
+ LookupAttachment( "left foot" ),
+ LookupAttachment( "right foot" ),
+ LookupAttachment( "back foot" )
+ };
+
+ m_hRopes[0] = C_RopeKeyframe::Create( this, this, indices[0], indices[1] );
+ m_hRopes[1] = C_RopeKeyframe::Create( this, this, indices[0], indices[2] );
+ m_hRopes[2] = C_RopeKeyframe::Create( this, this, indices[1], indices[2] );
+
+ for ( int i=0; i < 3; i++ )
+ {
+ if ( m_hRopes[i].Get() )
+ m_hRopes[i]->SetSlack( flTestSlack );
+ }
+
+
+ m_hRopes[3] = C_RopeKeyframe::Create( this, this, indices[3], indices[4] );
+ m_hRopes[4] = C_RopeKeyframe::Create( this, this, indices[3], indices[5] );
+ m_hRopes[5] = C_RopeKeyframe::Create( this, this, indices[3], indices[6] );
+
+ for ( i=3; i < 6; i++ )
+ {
+ if ( m_hRopes[i].Get() )
+ m_hRopes[i]->SetSlack( flTestSlack2 );
+ }
+ }
+ }
+}
+
+
+void C_WalkerStrider::ClientThink()
+{
+ // Retire beam effects.
+ int iNext;
+ for ( int i=m_BeamEffects.Head(); i != m_BeamEffects.InvalidIndex(); i=iNext )
+ {
+ iNext = m_BeamEffects.Next( i );
+
+ if ( gpGlobals->curtime >= (m_BeamEffects[i].m_flStartTime + STRIDER_BEAM_LIFETIME) )
+ {
+ m_BeamEffects.Remove( i );
+ }
+ }
+}
+
+
+int C_WalkerStrider::DrawModel( int flags )
+{
+ BaseClass::DrawModel( flags );
+
+ IMaterial *pMaterial = materials->FindMaterial( STRIDER_BEAM_MATERIAL, TEXTURE_GROUP_CLIENT_EFFECTS );
+
+ Vector vGunPos;
+ QAngle vAngles;
+ BaseClass::GetAttachment( LookupAttachment( "BigGun" ), vGunPos, vAngles );
+
+ // Draw our beam effects.
+ FOR_EACH_LL( m_BeamEffects, i )
+ {
+ CStriderBeamEffect *pEff = &m_BeamEffects[i];
+
+ float flAlpha = (gpGlobals->curtime - pEff->m_flStartTime) / STRIDER_BEAM_LIFETIME;
+ flAlpha = 1.0 - clamp( flAlpha, 0, 1 );
+
+ CBeamSegDraw segDraw;
+ segDraw.Start( 2, pMaterial );
+
+ CBeamSeg seg;
+ seg.m_vColor.Init( 1, 0, 0 );
+ seg.m_flWidth = STRIDER_BEAM_WIDTH;
+ seg.m_flAlpha = flAlpha;
+
+ seg.m_flTexCoord = 0;
+ seg.m_vPos = vGunPos;
+ segDraw.NextSeg( &seg );
+
+ seg.m_flTexCoord = 1;
+ seg.m_vPos = pEff->m_vHitPos;
+ segDraw.NextSeg( &seg );
+
+ segDraw.End();
+ }
+
+ return 1;
+}
+
diff --git a/game/client/tf2/c_walker_strider.h b/game/client/tf2/c_walker_strider.h
new file mode 100644
index 0000000..924e4a9
--- /dev/null
+++ b/game/client/tf2/c_walker_strider.h
@@ -0,0 +1,71 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#ifndef C_WALKER_STRIDER_H
+#define C_WALKER_STRIDER_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+
+#include "c_walker_base.h"
+#include "c_rope.h"
+
+
+#define STRIDER_BEAM_LIFETIME 1.0
+#define STRIDER_BEAM_MATERIAL "sprites/physbeam"
+#define STRIDER_BEAM_WIDTH 25
+#define STRIDER_NUM_ROPES 6
+
+
+class CStriderBeamEffect
+{
+public:
+ Vector m_vHitPos;
+ float m_flStartTime;
+};
+
+
+class C_WalkerStrider : public C_WalkerBase
+{
+public:
+ DECLARE_CLIENTCLASS();
+ DECLARE_CLASS( C_WalkerStrider, C_WalkerBase );
+
+ C_WalkerStrider();
+ virtual ~C_WalkerStrider();
+
+
+// IClientThinkable.
+public:
+ virtual void ClientThink();
+
+
+// C_BaseEntity.
+public:
+ virtual void ReceiveMessage( int classID, bf_read &msg );
+ virtual void OnDataChanged( DataUpdateType_t type );
+ virtual bool ShouldPredict() { return false; }
+
+
+// C_BaseAnimating.
+public:
+ virtual bool GetAttachment( int iAttachment, matrix3x4_t &attachmentToWorld );
+ virtual int DrawModel( int flags );
+
+
+private:
+ C_WalkerStrider( const C_WalkerStrider &other ) {}
+
+ bool m_bCrouched;
+
+ CUtlLinkedList<CStriderBeamEffect,int> m_BeamEffects;
+
+ CHandle<C_RopeKeyframe> m_hRopes[STRIDER_NUM_ROPES];
+};
+
+
+#endif // C_WALKER_STRIDER_H
diff --git a/game/client/tf2/c_weapon__stubs_tf2.cpp b/game/client/tf2/c_weapon__stubs_tf2.cpp
new file mode 100644
index 0000000..6378813
--- /dev/null
+++ b/game/client/tf2/c_weapon__stubs_tf2.cpp
@@ -0,0 +1,32 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+//=============================================================================//
+#include "cbase.h"
+#include "c_tf_basecombatweapon.h"
+#include "c_weapon__stubs.h"
+#include "weapon_basecombatobject.h"
+
+// TODO for 12/22/02
+// weapon_limpetmine
+// weapon_builder: don't do yet, waiting for Robin to change out UI
+
+
+STUB_WEAPON_CLASS( foo_weapon_machinegun, MachineGun, C_BaseCombatWeapon );
+STUB_WEAPON_CLASS( foo_weapon_select_fire_machinegun, SelectFireMachineGun, C_MachineGun );
+STUB_WEAPON_CLASS( foo_weapon_basebludgeonweapon, BaseBludgeonWeapon, C_BaseCombatWeapon );
+
+STUB_WEAPON_CLASS( cycler_weapon, WeaponCycler, C_BaseCombatWeapon );
+
+STUB_WEAPON_CLASS( weapon_assault_rifle, WeaponAssaultRifle, C_TFMachineGun );
+STUB_WEAPON_CLASS( weapon_laserdesignator, WeaponLaserDesignator, C_BaseTFCombatWeapon );
+STUB_WEAPON_CLASS( weapon_laserrifle, WeaponLaserRifle, C_BaseTFCombatWeapon );
+STUB_WEAPON_CLASS( weapon_obj_empgenerator, WeaponObjEMPGenerator, C_WeaponBaseCombatObject );
+STUB_WEAPON_CLASS( weapon_placedcharge, WeaponPlacedCharge, C_BaseTFCombatWeapon );
+STUB_WEAPON_CLASS( weapon_plasmarifle, WeaponPlasmaRifle, C_TFMachineGun );
+STUB_WEAPON_CLASS( weapon_shotgun, WeaponShotgun, C_TFMachineGun );
+STUB_WEAPON_CLASS( weapon_sapper_shotgun, WeaponSapperShotgun, C_WeaponShotgun );
+STUB_WEAPON_CLASS( weapon_cubemap, WeaponCubemap, C_BaseCombatWeapon ); \ No newline at end of file
diff --git a/game/client/tf2/c_weapon_builder.cpp b/game/client/tf2/c_weapon_builder.cpp
new file mode 100644
index 0000000..edb69ab
--- /dev/null
+++ b/game/client/tf2/c_weapon_builder.cpp
@@ -0,0 +1,380 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Client's CWeaponBuilder class
+//
+// $Workfile: $
+// $Date: $
+// $NoKeywords: $
+//=============================================================================//
+#include "cbase.h"
+#include "hud.h"
+#include "in_buttons.h"
+#include "clientmode_tfnormal.h"
+#include "engine/IEngineSound.h"
+#include "c_weapon_builder.h"
+#include "c_weapon__stubs.h"
+#include "iinput.h"
+#include "ObjectControlPanel.h"
+#include <vgui/IVGui.h>
+
+#define BUILD_ICON_SCALE 0.75
+
+#define BUILD_ICON_BOTTOM_OFFSET YRES(160)
+
+//-----------------------------------------------------------------------------
+// Purpose: Draw a material on a quad
+//-----------------------------------------------------------------------------
+void DrawQuadMaterial( IMaterial *pMaterial, int iX, int iY, int iWidth, int iHeight,
+ unsigned char r = 255, unsigned char g = 255, unsigned char b = 255, unsigned char a = 255,
+ float flTextureLeft = 0.0, float flTextureRight = 1.0, bool bRotated = false )
+{
+ IMesh* pMesh = materials->GetDynamicMesh( true, NULL, NULL, pMaterial );
+
+ CMeshBuilder meshBuilder;
+ meshBuilder.Begin( pMesh, MATERIAL_QUADS, 1 );
+
+ meshBuilder.Color4ub( r, g, b, a );
+ if ( bRotated )
+ {
+ meshBuilder.TexCoord2f( 0,flTextureLeft,1 );
+ }
+ else
+ {
+ meshBuilder.TexCoord2f( 0,flTextureLeft,0 );
+ }
+ meshBuilder.Position3f( iX,iY,0 );
+ meshBuilder.AdvanceVertex();
+
+ meshBuilder.Color4ub( r, g, b, a );
+ if ( bRotated )
+ {
+ meshBuilder.TexCoord2f( 0,flTextureLeft,0 );
+ }
+ else
+ {
+ meshBuilder.TexCoord2f( 0,flTextureRight,0 );
+ }
+ meshBuilder.Position3f( iX+iWidth, iY, 0 );
+ meshBuilder.AdvanceVertex();
+
+ meshBuilder.Color4ub( r, g, b, a );
+ if ( bRotated )
+ {
+ meshBuilder.TexCoord2f( 0,flTextureRight,0 );
+ }
+ else
+ {
+ meshBuilder.TexCoord2f( 0,flTextureRight,1 );
+ }
+ meshBuilder.Position3f( iX+iWidth, iY+iHeight, 0 );
+ meshBuilder.AdvanceVertex();
+
+ meshBuilder.Color4ub( r, g, b, a );
+ if ( bRotated )
+ {
+ meshBuilder.TexCoord2f( 0,flTextureRight,1 );
+ }
+ else
+ {
+ meshBuilder.TexCoord2f( 0,flTextureLeft,1 );
+ }
+ meshBuilder.Position3f( iX, iY+iHeight, 0 );
+ meshBuilder.AdvanceVertex();
+
+ meshBuilder.End();
+ pMesh->Draw();
+}
+
+STUB_WEAPON_CLASS_IMPLEMENT( weapon_builder, C_WeaponBuilder );
+
+IMPLEMENT_CLIENTCLASS_DT(C_WeaponBuilder, DT_WeaponBuilder, CWeaponBuilder)
+ RecvPropInt( RECVINFO(m_iBuildState) ),
+ RecvPropInt( RECVINFO(m_iCurrentObject) ),
+ RecvPropInt( RECVINFO(m_iCurrentObjectState) ),
+ RecvPropEHandle( RECVINFO(m_hObjectBeingBuilt) ),
+ RecvPropTime( RECVINFO(m_flStartTime) ),
+ RecvPropTime( RECVINFO(m_flTotalTime) ),
+ RecvPropArray
+ (
+ RecvPropInt( RECVINFO(m_bObjectValidity[0])), m_bObjectValidity
+ ),
+ RecvPropArray
+ (
+ RecvPropInt( RECVINFO(m_bObjectBuildability[0])), m_bObjectBuildability
+ ),
+END_RECV_TABLE()
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+C_WeaponBuilder::C_WeaponBuilder()
+{
+ m_iBuildState = 0;
+ m_iCurrentObject = BUILDER_INVALID_OBJECT;
+ m_iCurrentObjectState = 0;
+ m_flStartTime = 0;
+ m_flTotalTime = 0;
+
+ m_pIconFireToSelect.Init( "Hud/build/firetobuild", TEXTURE_GROUP_VGUI );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+C_WeaponBuilder::~C_WeaponBuilder()
+{
+}
+
+//-----------------------------------------------------------------------------
+// A couple helper methods for drawing builder status
+//-----------------------------------------------------------------------------
+static void DrawTextIcon( IMaterial* pMaterial, int parentWidth, int parentHeight, float r = 1.0f, float g = 1.0f, float b = 1.0f )
+{
+ if ( !pMaterial )
+ return;
+
+ // We're in build selection mode, so draw the current build icon
+ int iWidth = pMaterial->GetMappingWidth();
+ int iHeight = pMaterial->GetMappingHeight();
+ int iX = (parentWidth - iWidth) / 2;
+ int iY = (parentHeight - 216);
+ DrawQuadMaterial( pMaterial, iX, iY, iWidth, iHeight, r * 255, g * 255, b * 255 );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Output : char const
+//-----------------------------------------------------------------------------
+const char *C_WeaponBuilder::GetCurrentSelectionObjectName( void )
+{
+ if ( m_iCurrentObject == -1 || (m_iBuildState == BS_SELECTING) )
+ return "";
+
+ return GetObjectInfo( m_iCurrentObject )->m_pBuilderWeaponName;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void C_WeaponBuilder::Redraw()
+{
+ BaseClass::Redraw();
+
+ // Don't draw if we're hiding the weapons, or the player's dead
+ if ( gHUD.IsHidden( HIDEHUD_WEAPONSELECTION | HIDEHUD_PLAYERDEAD ) )
+ return;
+ C_BaseTFPlayer *pPlayer = C_BaseTFPlayer::GetLocalPlayer();
+ if (!pPlayer)
+ return;
+
+ vgui::Panel *pParent = GetClientModeNormal()->GetViewport();
+ int parentWidth, parentHeight;
+ pParent->GetSize(parentWidth, parentHeight);
+
+ // If we're in placement mode, draw the placement icon
+ switch( m_iBuildState )
+ {
+ case BS_PLACING:
+ case BS_PLACING_INVALID:
+ break;
+
+ default:
+ {
+ if( !inv_demo.GetInt() )
+ {
+ DrawTextIcon( m_pIconFireToSelect, parentWidth, parentHeight );
+ }
+ break;
+ }
+ break;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Output : Returns true on success, false on failure.
+//-----------------------------------------------------------------------------
+bool C_WeaponBuilder::IsPlacingObject( void )
+{
+ if ( m_iBuildState == BS_PLACING || m_iBuildState == BS_PLACING_INVALID )
+ return true;
+ return false;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Output : Returns true on success, false on failure.
+//-----------------------------------------------------------------------------
+bool C_WeaponBuilder::IsBuildingObject( void )
+{
+ if ( m_iBuildState == BS_BUILDING )
+ return true;
+ return false;
+}
+
+#include "vgui_bitmapimage.h"
+#include "vgui_bitmappanel.h"
+
+
+//-----------------------------------------------------------------------------
+// Control screen
+//-----------------------------------------------------------------------------
+class CHumanPDAPanel : public CVGuiScreenPanel
+{
+ DECLARE_CLASS( CHumanPDAPanel, CVGuiScreenPanel );
+
+public:
+ CHumanPDAPanel( vgui::Panel *parent, const char *panelName );
+ ~CHumanPDAPanel();
+ virtual bool Init( KeyValues* pKeyValues, VGuiScreenInitData_t* pInitData );
+ virtual void OnTick();
+
+private:
+ C_BaseCombatWeapon *GetOwningWeapon();
+
+ vgui::Label *m_pObjectName;
+ vgui::Label *m_pObjectCost;
+ vgui::Label *m_pObjectOnTeamCount;
+ vgui::Label *m_pObjectPlacementDetails;
+
+ CBitmapPanel *m_pBitmapPanel;
+
+ BitmapImage *m_pObjectImage;
+
+ int m_nLastObjectID;
+ int m_nLastObjectCount;
+ int m_nLastObjectCost;
+
+};
+
+
+DECLARE_VGUI_SCREEN_FACTORY( CHumanPDAPanel, "human_pda" );
+
+
+//-----------------------------------------------------------------------------
+// Constructor:
+//-----------------------------------------------------------------------------
+CHumanPDAPanel::CHumanPDAPanel( vgui::Panel *parent, const char *panelName )
+ : BaseClass( parent, "CHumanPDAPanel", vgui::scheme()->LoadSchemeFromFileEx( enginevgui->GetPanel( PANEL_CLIENTDLL ), "resource/PDAControlPanelScheme.res", "TFBase" ) )
+{
+ m_pObjectImage = NULL;
+
+ m_pObjectName = new vgui::Label( this, "ObjectName", "" );
+ m_pObjectCost = new vgui::Label( this, "ObjectCost", "" );
+ m_pObjectOnTeamCount = new vgui::Label( this, "ObjectOnTeamCount", "" );
+ m_pObjectPlacementDetails = new vgui::Label( this, "ObjectPlacementDetails", "" );
+
+ m_pBitmapPanel = new CBitmapPanel( this, "ObjectImage" );
+ m_pObjectImage = new BitmapImage();
+ m_pObjectImage->UsePanelRenderSize( m_pBitmapPanel->GetVPanel() );
+ m_pBitmapPanel->SetImage( m_pObjectImage );
+
+ m_nLastObjectID = -1;
+ m_nLastObjectCount = -1;
+ m_nLastObjectCost = -1;
+}
+
+CHumanPDAPanel::~CHumanPDAPanel()
+{
+ if ( m_pObjectImage )
+ {
+ delete m_pObjectImage;
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Initialization
+//-----------------------------------------------------------------------------
+bool CHumanPDAPanel::Init( KeyValues* pKeyValues, VGuiScreenInitData_t* pInitData )
+{
+
+ // Make sure we get ticked...
+ vgui::ivgui()->AddTickSignal( GetVPanel() );
+
+ if (!BaseClass::Init(pKeyValues, pInitData))
+ return false;
+
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// Returns the object it's attached to
+//-----------------------------------------------------------------------------
+C_BaseCombatWeapon *CHumanPDAPanel::GetOwningWeapon()
+{
+ C_BaseEntity *pScreenEnt = GetEntity();
+ if (!pScreenEnt)
+ return NULL;
+
+ C_BaseEntity *pOwner = pScreenEnt->GetOwnerEntity();
+ if (!pOwner)
+ return NULL;
+
+ C_BaseViewModel *pViewModel = dynamic_cast< C_BaseViewModel * >( pOwner );
+ if ( !pViewModel )
+ return NULL;
+
+ return pViewModel->GetOwningWeapon();
+}
+
+//-----------------------------------------------------------------------------
+// Frame-based update
+//-----------------------------------------------------------------------------
+void CHumanPDAPanel::OnTick()
+{
+ BaseClass::OnTick();
+
+ SetVisible( true );
+
+ char buf[256];
+
+ C_BaseCombatWeapon *weapon = GetOwningWeapon();
+ if ( !weapon )
+ return;
+
+ C_WeaponBuilder *builder = dynamic_cast< C_WeaponBuilder * >( weapon );
+ if ( !builder )
+ return;
+
+ CBaseTFPlayer *pOwner = ToBaseTFPlayer( builder->GetOwner() );
+ if ( !pOwner )
+ return;
+
+ // FIXME: Check build state??
+
+ int objectType = builder->m_iCurrentObject;
+ CObjectInfo const *info = GetObjectInfo( objectType );
+ if ( !info )
+ return;
+
+ int numOwned = pOwner->GetNumObjects(objectType);
+ int iCost = CalculateObjectCost( objectType, numOwned, pOwner->GetTeamNumber() );
+
+ if ( m_nLastObjectID == objectType &&
+ m_nLastObjectCount == numOwned &&
+ m_nLastObjectCost == iCost)
+ return;
+
+ m_nLastObjectID = objectType;
+ m_nLastObjectCount = numOwned;
+ m_nLastObjectCost = iCost;
+
+ Q_snprintf( buf, sizeof( buf ), "hud/menu/%s", info->m_pClassName );
+ m_pObjectImage->SetImageFile( buf );
+ m_pObjectImage->SetColor( GetFgColor() );
+
+ Q_snprintf( buf, sizeof( buf ), "%s", info->m_pStatusName );
+ m_pObjectName->SetText( buf );
+
+ Q_snprintf( buf, sizeof( buf ), "Cost: %i", iCost );
+ m_pObjectCost->SetText( buf );
+
+ Q_snprintf( buf, sizeof( buf ), "You own: %i", numOwned );
+ m_pObjectOnTeamCount->SetText( buf );
+
+ Q_snprintf( buf, sizeof( buf ), "%s", info->m_pBuilderPlacementString ? info->m_pBuilderPlacementString : "" );
+ m_pObjectPlacementDetails->SetText( buf );
+ //m_pObjectPlacementDetails->SizeToContents();
+}
diff --git a/game/client/tf2/c_weapon_builder.h b/game/client/tf2/c_weapon_builder.h
new file mode 100644
index 0000000..127e2b2
--- /dev/null
+++ b/game/client/tf2/c_weapon_builder.h
@@ -0,0 +1,63 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef C_WEAPON_BUILDER_H
+#define C_WEAPON_BUILDER_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "c_tf_basecombatweapon.h"
+#include "weapon_combat_usedwithshieldbase.h"
+
+//=============================================================================
+// Purpose: Client version of CWeaponBuiler
+//=============================================================================
+class C_WeaponBuilder : public C_WeaponCombatUsedWithShieldBase
+{
+ DECLARE_CLASS( C_WeaponBuilder, C_WeaponCombatUsedWithShieldBase );
+public:
+ DECLARE_CLIENTCLASS();
+ DECLARE_PREDICTABLE();
+
+ C_WeaponBuilder();
+ ~C_WeaponBuilder();
+
+ virtual void Redraw();
+ virtual bool VisibleInWeaponSelection( void ) { return false; }
+
+ virtual bool IsPlacingObject( void );
+ virtual bool IsBuildingObject( void );
+
+ virtual const char *GetCurrentSelectionObjectName( void );
+
+ C_BaseObject *GetPlacementModel( void ) { return m_hObjectBeingBuilt.Get(); }
+
+public:
+ // Builder Data
+ int m_iBuildState;
+ unsigned int m_iCurrentObject;
+ int m_iCurrentObjectState;
+ float m_flStartTime;
+ float m_flTotalTime;
+ vgui::HFont m_hFont;
+
+ // Our placement model
+ CHandle<C_BaseObject> m_hObjectBeingBuilt;
+
+ // Objects that this builder can build
+ bool m_bObjectValidity[ OBJ_LAST ];
+ // Buildability of each object
+ bool m_bObjectBuildability[ OBJ_LAST ];
+
+ // Materials
+ CMaterialReference m_pIconFireToSelect;
+
+private:
+ C_WeaponBuilder( const C_WeaponBuilder & );
+};
+#endif // C_WEAPON_BUILDER_H
diff --git a/game/client/tf2/c_weapon_chargeableplasma.cpp b/game/client/tf2/c_weapon_chargeableplasma.cpp
new file mode 100644
index 0000000..22e2471
--- /dev/null
+++ b/game/client/tf2/c_weapon_chargeableplasma.cpp
@@ -0,0 +1,358 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+#include "cbase.h"
+#include "iefx.h"
+#include "dlight.h"
+#include "engine/IEngineSound.h"
+#include "view.h"
+#include "beamdraw.h"
+#include "clienteffectprecachesystem.h"
+#include "weapon_combat_usedwithshieldbase.h"
+#include "c_weapon__stubs.h"
+#include <vgui/ISurface.h>
+
+#define BALL_GROW_TIME 1.5
+
+// Precache the effects
+CLIENTEFFECT_REGISTER_BEGIN( PrecacheWeaponCombat_ChargeablePlasma )
+CLIENTEFFECT_MATERIAL( "sprites/chargeball_team1" )
+CLIENTEFFECT_MATERIAL( "sprites/chargeball_team2" )
+CLIENTEFFECT_REGISTER_END()
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+class C_WeaponCombat_ChargeablePlasma : public C_WeaponCombatUsedWithShieldBase
+{
+ DECLARE_CLASS( C_WeaponCombat_ChargeablePlasma, C_WeaponCombatUsedWithShieldBase );
+
+public:
+ DECLARE_CLIENTCLASS();
+ DECLARE_PREDICTABLE();
+
+ C_WeaponCombat_ChargeablePlasma( void );
+ ~C_WeaponCombat_ChargeablePlasma( void );
+
+ virtual void PreDataUpdate( DataUpdateType_t updateType );
+ virtual void OnDataChanged( DataUpdateType_t updateType );
+ virtual bool Holster( CBaseCombatWeapon *pSwitchingTo = NULL );
+ virtual void DrawCrosshair( void );
+ virtual void ClientThink( );
+ virtual int DrawModel( int flags );
+ virtual void ViewModelDrawn( C_BaseViewModel *pBaseViewModel );
+ virtual void NotifyShouldTransmit( ShouldTransmitState_t state );
+ virtual bool IsTransparent( );
+
+private:
+ void StartCharging();
+ void StopCharging();
+ void DrawChargingEffect( float flSize, C_BaseAnimating *pAttachedEnt );
+
+private:
+ bool m_bCharging;
+ bool m_bLastCharging;
+ float m_flPower;
+ float m_flChargeStartTime;
+ CMaterialReference m_hMaterial;
+
+private:
+ C_WeaponCombat_ChargeablePlasma( const C_WeaponCombat_ChargeablePlasma & );
+};
+
+STUB_WEAPON_CLASS_IMPLEMENT( weapon_combat_chargeableplasma, C_WeaponCombat_ChargeablePlasma );
+
+IMPLEMENT_CLIENTCLASS_DT( C_WeaponCombat_ChargeablePlasma, DT_WeaponCombat_ChargeablePlasma, CWeaponCombat_ChargeablePlasma )
+ RecvPropInt( RECVINFO(m_bCharging) ),
+END_RECV_TABLE()
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+C_WeaponCombat_ChargeablePlasma::C_WeaponCombat_ChargeablePlasma( void )
+{
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+C_WeaponCombat_ChargeablePlasma::~C_WeaponCombat_ChargeablePlasma( void )
+{
+ Holster( NULL );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void C_WeaponCombat_ChargeablePlasma::PreDataUpdate( DataUpdateType_t updateType )
+{
+ BaseClass::PreDataUpdate( updateType );
+
+ m_bLastCharging = m_bCharging;
+}
+
+
+void C_WeaponCombat_ChargeablePlasma::NotifyShouldTransmit( ShouldTransmitState_t state )
+{
+ BaseClass::NotifyShouldTransmit(state);
+
+ if (state == SHOULDTRANSMIT_START)
+ {
+ if (m_bCharging)
+ StartCharging();
+ }
+ else if (state == SHOULDTRANSMIT_END)
+ {
+ if (m_bCharging)
+ StopCharging();
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void C_WeaponCombat_ChargeablePlasma::OnDataChanged( DataUpdateType_t updateType )
+{
+ BaseClass::OnDataChanged( updateType );
+
+ switch( updateType )
+ {
+ case DATA_UPDATE_CREATED:
+ // So we can update our lights
+ if ( GetTeamNumber() == 1 )
+ m_hMaterial.Init( "sprites/chargeball_team1" );
+ else
+ m_hMaterial.Init( "sprites/chargeball_team2" );
+
+ break;
+
+ case DATA_UPDATE_DATATABLE_CHANGED:
+ if ( m_bCharging != m_bLastCharging )
+ {
+ if ( m_bCharging )
+ {
+ StartCharging();
+ }
+ else
+ {
+ StopCharging();
+ }
+ }
+ break;
+ };
+
+ if (WeaponState() == WEAPON_IS_ACTIVE)
+ {
+ // Start thinking so we can manipulate the light
+ SetNextClientThink( CLIENT_THINK_ALWAYS );
+ }
+ else
+ {
+ SetNextClientThink( CLIENT_THINK_NEVER );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Deal with dynamic lighting
+//-----------------------------------------------------------------------------
+void C_WeaponCombat_ChargeablePlasma::ClientThink( )
+{
+ BaseClass::ClientThink();
+
+ C_BaseTFPlayer *pPlayer = (C_BaseTFPlayer *)GetOwner();
+ if ( !pPlayer || (pPlayer->GetHealth() <= 0))
+ {
+ SetNextClientThink( CLIENT_THINK_NEVER );
+ return;
+ }
+
+ if (!m_bCharging)
+ return;
+
+ // Determine the ball size...
+ m_flPower = (gpGlobals->curtime - m_flChargeStartTime) / BALL_GROW_TIME;
+ m_flPower = clamp( m_flPower, 0, 1 );
+
+ // FIXME: dl->origin should be based on the attachment point
+ dlight_t *dl = effects->CL_AllocDlight( entindex() );
+ dl->origin = GetRenderOrigin();
+
+ if (GetTeamNumber() == 1)
+ {
+ dl->color.r = 40;
+ dl->color.g = 60;
+ dl->color.b = 250;
+ }
+ else
+ {
+ dl->color.r = 250;
+ dl->color.g = 60;
+ dl->color.b = 40;
+ }
+
+ dl->color.exponent = 5;
+ dl->radius = 20 * m_flPower + 10;
+ dl->die = gpGlobals->curtime + 0.01;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Remove the ball if we're switching away
+//-----------------------------------------------------------------------------
+bool C_WeaponCombat_ChargeablePlasma::Holster( C_BaseCombatWeapon *pSwitchingTo )
+{
+ StopCharging();
+
+ return BaseClass::Holster( pSwitchingTo );
+}
+
+void C_WeaponCombat_ChargeablePlasma::StartCharging()
+{
+ CLocalPlayerFilter filter;
+ EmitSound( filter, SOUND_FROM_LOCAL_PLAYER, "WeaponCombat_ChargeablePlasma.Charging" );
+ m_flChargeStartTime = gpGlobals->curtime;
+}
+
+
+void C_WeaponCombat_ChargeablePlasma::StopCharging()
+{
+ StopSound( SOUND_FROM_LOCAL_PLAYER, "WeaponCombat_ChargeablePlasma.Charging" );
+ m_bCharging = false;
+}
+
+
+//-----------------------------------------------------------------------------
+// We're transparent because we draw a transparent charging effect
+//-----------------------------------------------------------------------------
+bool C_WeaponCombat_ChargeablePlasma::IsTransparent( )
+{
+ if (m_bCharging)
+ return true;
+ return BaseClass::IsTransparent();
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Draws the charging effect
+//-----------------------------------------------------------------------------
+void C_WeaponCombat_ChargeablePlasma::DrawChargingEffect( float flSize, C_BaseAnimating *pAttachedEnt )
+{
+ if (!pAttachedEnt)
+ return;
+
+ Vector vecOrigin;
+ QAngle vecAngles;
+ int iAttachment = pAttachedEnt->LookupAttachment( "muzzle" );
+ if ( pAttachedEnt->GetAttachment( iAttachment, vecOrigin, vecAngles ) )
+ {
+ color32 color = { 255, 255, 255, 255 };
+ materials->Bind( m_hMaterial, (IClientRenderable*)this );
+ DrawSprite( vecOrigin, flSize, flSize, color );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Draws the model
+//-----------------------------------------------------------------------------
+int C_WeaponCombat_ChargeablePlasma::DrawModel( int flags )
+{
+ int retval = BaseClass::DrawModel( flags );
+ if (retval == 0)
+ return 0;
+
+ if (m_bCharging && IsCarrierAlive())
+ {
+ // Draw the charging effect
+ float flSize = 20 * m_flPower + 10;
+
+ DrawChargingEffect( flSize, this );
+ }
+ return retval;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Draws the model
+//-----------------------------------------------------------------------------
+void C_WeaponCombat_ChargeablePlasma::ViewModelDrawn( C_BaseViewModel *pBaseViewModel )
+{
+ if (!m_bCharging)
+ return;
+
+ // Draw the charging effect
+ float flSize = 12 * m_flPower + 6;
+
+ if ( m_iClip1 > 0 )
+ {
+ DrawChargingEffect( flSize, pBaseViewModel );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Draw targeting reticle
+//-----------------------------------------------------------------------------
+void C_WeaponCombat_ChargeablePlasma::DrawCrosshair( void )
+{
+ BaseClass::DrawCrosshair();
+
+ // Find enemy players in front of me
+ C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
+ if ( !pPlayer )
+ return;
+
+ trace_t tr;
+ Vector vecStart, vecEnd;
+ VectorMA( CurrentViewOrigin(), 1500, CurrentViewForward(), vecEnd );
+ VectorMA( CurrentViewOrigin(), 48, CurrentViewForward(), vecStart );
+ UTIL_TraceLine( vecStart, vecEnd, MASK_SOLID, NULL, COLLISION_GROUP_NONE, &tr );
+
+ if ( tr.DidHitNonWorldEntity() )
+ {
+ C_BaseEntity *pEntity = tr.m_pEnt;
+ if ( pEntity && pEntity->IsPlayer() && !pPlayer->InSameTeam( pEntity ) )
+ {
+ // Draw a reticle
+ vgui::Color clr = gHUD.m_clrYellowish;
+ clr[3] = 128;
+
+ // Calculate circle size
+ int iRatio = 30;
+
+ // Draw the circle
+ int iDegrees = 0;
+ Vector vecPoint, vecLastPoint(0,0,0);
+ vecPoint.z = 0.0f;
+ for ( int i = 0; i < 360; i++ )
+ {
+ float flRadians = DEG2RAD( iDegrees );
+ iDegrees += (360 / 360);
+
+ float ca = cos( flRadians );
+ float sa = sin( flRadians );
+
+ // Rotate it around the circle
+ vecPoint.x = (int)((ScreenWidth() / 2) + (iRatio * sa));
+ vecPoint.y = (int)((ScreenHeight() / 2) - (iRatio * ca));
+
+ // Draw the point, if it's not on the previous point, to avoid smaller circles being brighter
+ if ( vecLastPoint != vecPoint )
+ {
+ vgui::surface()->DrawSetColor( clr );
+ vgui::surface()->DrawFilledRect( vecPoint.x, vecPoint.y, vecPoint.x + 1, vecPoint.y + 1 );
+ }
+
+ vecLastPoint = vecPoint;
+ }
+ }
+ }
+}
+
diff --git a/game/client/tf2/c_weapon_mortar.cpp b/game/client/tf2/c_weapon_mortar.cpp
new file mode 100644
index 0000000..ecae3b9
--- /dev/null
+++ b/game/client/tf2/c_weapon_mortar.cpp
@@ -0,0 +1,634 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Client's CWeaponMortar class
+//
+// $Workfile: $
+// $Date: $
+// $NoKeywords: $
+//=============================================================================//
+#include "cbase.h"
+#include "hud.h"
+#include "hudelement.h"
+#include "in_buttons.h"
+#include "ground_line.h"
+#include "clientmode_tfnormal.h"
+#include "vgui_basepanel.h"
+#include "c_tf_basecombatweapon.h"
+#include "engine/IEngineSound.h"
+#include "iinput.h"
+#include "imessagechars.h"
+#include "c_weapon__stubs.h"
+
+//=============================================================================
+// Purpose: Hud Element for Mortar firing
+//=============================================================================
+class CHudMortar : public CHudElement, public vgui::Panel
+{
+ DECLARE_CLASS_SIMPLE( CHudMortar, vgui::Panel );
+
+public:
+ DECLARE_MULTIPLY_INHERITED();
+
+ CHudMortar( const char *pElementName );
+ virtual void Paint( void );
+
+ float m_flPower;
+ float m_flFiringPower;
+ float m_flFiringAccuracy;
+ float m_flReset;
+};
+
+DECLARE_HUDELEMENT( CHudMortar );
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+CHudMortar::CHudMortar( const char *pElementName ) :
+ CHudElement( pElementName ), vgui::Panel( NULL, pElementName )
+{
+ m_flPower = 0;
+ m_flFiringPower = 0;
+ m_flFiringAccuracy = 0;
+ m_flReset = 0;
+ SetPaintBackgroundEnabled( false );
+ SetAutoDelete( false );
+ SetName( "mortar" );
+
+ SetHiddenBits( HIDEHUD_PLAYERDEAD );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CHudMortar::Paint()
+{
+ // Clear out markers
+ if ( m_flReset && m_flReset < gpGlobals->curtime )
+ {
+ m_flFiringPower = 0;
+ m_flFiringAccuracy = 0;
+ m_flReset = 0;
+ }
+
+ int w, h;
+ GetSize( w, h );
+
+ // Use an eighth of the height for each side
+ int iOffset = h / 8;
+ int iBarHeight = h - (2 * iOffset);
+ int iZero = (w / 5);
+ int iMarker = iZero + (m_flPower * (w - iZero));
+ int iPower = iZero + (m_flFiringPower * (w - iZero));
+ int iAccuracy = iZero + (m_flFiringAccuracy * (w - iZero));
+
+ // Shade the bar
+ int alpha = 205;
+ int colorAmt = 255;
+ int nSegs = 20;
+
+ int i;
+ for(i=0; i < nSegs; i++)
+ {
+ int left = iZero + (i*w) / nSegs;
+ int right = iZero + ((i+1)*w) / nSegs;
+
+ // Don't draw past the marker
+ if ( m_flFiringPower && right > iPower )
+ right = iPower;
+ else if ( !m_flFiringPower && right > iMarker )
+ right = iMarker;
+
+ vgui::surface()->DrawSetColor( ((i + 5) * colorAmt) / nSegs, 0, 0, alpha );
+ vgui::surface()->DrawFilledRect( left, iOffset, right, iBarHeight);
+ }
+
+ // Shade back from zero
+ nSegs = 10;
+ for(i=0; i < nSegs; i++)
+ {
+ int left = (i*iZero) / nSegs;
+ int right = ((i+1)*iZero) / nSegs;
+
+ if ( m_flFiringAccuracy && left < iAccuracy )
+ left = iAccuracy;
+ else if ( !m_flFiringAccuracy && left < iMarker )
+ left = iMarker;
+
+ vgui::surface()->DrawSetColor( ((nSegs - i) * colorAmt) / nSegs, 0, 0, alpha );
+ vgui::surface()->DrawFilledRect(left, iOffset, right, iBarHeight);
+ }
+
+ // Draw the zero marker
+ vgui::surface()->DrawSetColor(255,255,255,255);
+ vgui::surface()->DrawFilledRect(iZero-2, iOffset, iZero+2, iBarHeight);
+
+ // Draw the marker
+ vgui::surface()->DrawSetColor(255,255,255,255);
+ vgui::surface()->DrawFilledRect(iMarker-1, 0, iMarker+1, h);
+
+ // Draw the power mark if we've set one
+ if ( m_flFiringPower )
+ {
+ vgui::surface()->DrawSetColor(255,255,255,255);
+ vgui::surface()->DrawFilledRect(iPower-1, iOffset, iPower+1, iBarHeight);
+ }
+
+ // Draw the accuracy mark if we've set one
+ if ( m_flFiringAccuracy )
+ {
+ vgui::surface()->DrawSetColor(255,255,255,255);
+ vgui::surface()->DrawFilledRect(iAccuracy-1, iOffset, iAccuracy+1, iBarHeight);
+ }
+
+ // Draw box
+ vgui::surface()->DrawSetColor(255,255,255,255);
+ vgui::surface()->DrawOutlinedRect(0, iOffset, w, iBarHeight);
+}
+
+static ConVar g_CVMortarGroundLineUpdateInterval( "mortar_groundlineupdateinterval", "0.1", 0, "Number of seconds, mininum, between ground line position updates." );
+
+
+//=============================================================================
+// Purpose: Client version of CWeaponMortar
+//=============================================================================
+class C_WeaponMortar : public C_BaseTFCombatWeapon
+{
+public:
+ DECLARE_CLASS( C_WeaponMortar, C_BaseTFCombatWeapon );
+ DECLARE_CLIENTCLASS();
+ DECLARE_PREDICTABLE();
+
+ C_WeaponMortar();
+ ~C_WeaponMortar();
+
+ void FireMortar( void );
+
+ virtual void PreDataUpdate( DataUpdateType_t updateType );
+ virtual void OnDataChanged( DataUpdateType_t updateType );
+ virtual void HandleInput( void );
+ virtual void Redraw();
+ virtual void OverrideMouseInput( float *x, float *y );
+
+ // Deploy / Holster
+ virtual bool Deploy( void );
+ virtual bool Holster( CBaseCombatWeapon *pSwitchingTo = NULL );
+
+ // Mortar Data
+ bool m_bCarried;
+ bool m_bMortarReloading;
+ Vector m_vecMortarOrigin;
+ Vector m_vecMortarAngles;
+ float m_flPrevMortarServerYaw;
+ float m_flMortarYaw;
+ float m_flPrevMortarYaw;
+
+ // Input Handling
+ float m_flNextClick;
+ float m_flAccuracySpeed;
+ int m_iFiringState;
+ bool m_bRotating;
+
+ CGroundLine *m_pGroundLine;
+ CGroundLine *m_pDarkLine;
+ CHudMortar *m_pPowerBar;
+ IMaterial *m_pRotateIcon;
+
+ vgui::HFont m_hFontText;
+
+private:
+ C_WeaponMortar( const C_WeaponMortar & );
+
+ float m_flLastGroundlineUpdateTime;
+
+};
+
+STUB_WEAPON_CLASS_IMPLEMENT( weapon_mortar, C_WeaponMortar );
+
+IMPLEMENT_CLIENTCLASS_DT(C_WeaponMortar, DT_WeaponMortar, CWeaponMortar)
+ RecvPropInt( RECVINFO(m_bCarried) ),
+ RecvPropInt( RECVINFO(m_bMortarReloading) ),
+ RecvPropVector( RECVINFO(m_vecMortarOrigin) ),
+ RecvPropVector( RECVINFO(m_vecMortarAngles) ),
+END_RECV_TABLE()
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+C_WeaponMortar::C_WeaponMortar()
+{
+ m_bCarried = true;
+ m_bMortarReloading = false;
+ m_iFiringState = MORTAR_IDLE;
+ m_flNextClick = 0;
+ m_flAccuracySpeed = 0;
+ m_bRotating = false;
+ m_pGroundLine = NULL;
+ m_pDarkLine = NULL;
+ m_flMortarYaw = 0;
+ m_flPrevMortarYaw = -1;
+
+ m_pRotateIcon = materials->FindMaterial( "Hud/mortar/mortar_rotate", TEXTURE_GROUP_VGUI );
+ m_pRotateIcon->IncrementReferenceCount();
+
+ m_pPowerBar = GET_HUDELEMENT( CHudMortar );
+
+ m_flLastGroundlineUpdateTime = 0.0f;
+
+ m_hFontText = g_hFontTrebuchet24;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+C_WeaponMortar::~C_WeaponMortar()
+{
+ m_pPowerBar->SetParent( (vgui::Panel *)NULL );
+
+ if ( m_pRotateIcon != NULL )
+ {
+ m_pRotateIcon->DecrementReferenceCount();
+ m_pRotateIcon = NULL;
+ }
+
+ if ( m_pGroundLine )
+ {
+ delete m_pGroundLine;
+ }
+ if ( m_pDarkLine )
+ {
+ delete m_pDarkLine;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void C_WeaponMortar::PreDataUpdate( DataUpdateType_t updateType )
+{
+ BaseClass::PreDataUpdate(updateType);
+
+ m_flPrevMortarServerYaw = m_vecMortarAngles.y;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void C_WeaponMortar::OnDataChanged( DataUpdateType_t updateType )
+{
+ BaseClass::OnDataChanged(updateType);
+
+ // If the mortar's being carried by some other player, don't make a ground line
+ if ( !IsCarriedByLocalPlayer() )
+ return;
+
+ // Draw power chart if the mortar is deployed
+ if ( !m_bCarried && !m_bMortarReloading )
+ {
+ vgui::Panel *pParent = GetClientModeNormal()->GetViewport();
+ int parentWidth, parentHeight;
+ pParent->GetSize(parentWidth, parentHeight);
+
+ int iWidth = 256;
+ int iHeight = 40;
+ int iX = (parentWidth - iWidth) / 2;
+ int iY = (parentHeight - 200);
+
+ // Only show the power bar if the mortar's the active weapon
+ if ( IsActiveByLocalPlayer() )
+ {
+ m_pPowerBar->SetBounds( iX, iY, iWidth, iHeight );
+ m_pPowerBar->SetParent(pParent);
+ }
+ else
+ {
+ m_pPowerBar->SetParent( (vgui::Panel *)NULL );
+ }
+
+ if ( !m_bRotating && m_flPrevMortarServerYaw != m_vecMortarAngles.y )
+ {
+ m_flMortarYaw = m_vecMortarAngles.y;
+ }
+
+ // Create the Ground lines
+ if ( !m_pGroundLine )
+ {
+ m_pGroundLine = new CGroundLine();
+ m_pGroundLine->Init( "player/support/mortarline" );
+ }
+ if ( !m_pDarkLine )
+ {
+ m_pDarkLine = new CGroundLine();
+ m_pDarkLine->Init( "player/support/mortarline" );
+ }
+ }
+ else
+ {
+ m_pPowerBar->SetParent( (vgui::Panel *)NULL );
+
+ if ( m_pGroundLine )
+ {
+ delete m_pGroundLine;
+ m_pGroundLine = NULL;
+ }
+ if ( m_pDarkLine )
+ {
+ delete m_pDarkLine;
+ m_pDarkLine = NULL;
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void C_WeaponMortar::HandleInput( void )
+{
+ // If it's being carried, ignore input
+ if ( m_bCarried )
+ return;
+ // If the player's dead, ignore input
+ C_BaseTFPlayer *pPlayer = C_BaseTFPlayer::GetLocalPlayer();
+ if ( pPlayer == NULL )
+ return;
+ if ( pPlayer->GetHealth() < 1 )
+ return;
+
+ // Ignore input if it's reloading
+ if ( m_bMortarReloading )
+ return;
+
+ // Secondary fire rotates the mortar
+ if ( gHUD.m_iKeyBits & IN_ATTACK2 )
+ {
+ if ( pPlayer->HasPowerup(POWERUP_EMP) )
+ {
+ CLocalPlayerFilter filter;
+ EmitSound( filter, SOUND_FROM_LOCAL_PLAYER, "WeaponMortar.EMPed" );
+ return;
+ }
+ m_bRotating = true;
+
+ gHUD.m_iKeyBits &= ~IN_ATTACK2;
+
+ // Prevent firing while rotating
+ m_pPowerBar->SetParent( (vgui::Panel *)NULL );
+ return;
+ }
+ else
+ {
+ if ( m_bRotating )
+ {
+ // Bring up the firing bar again
+ vgui::Panel *pParent = GetClientModeNormal()->GetViewport();
+ m_pPowerBar->SetParent(pParent);
+ m_bRotating = false;
+ }
+ }
+
+ // Primary fire launches mortars
+ if (gHUD.m_iKeyBits & IN_ATTACK)
+ {
+ if ( pPlayer->HasPowerup(POWERUP_EMP) )
+ {
+ CLocalPlayerFilter filter;
+ EmitSound( filter, SOUND_FROM_LOCAL_PLAYER, "WeaponMortar.EMPed" );
+ return;
+ }
+
+ if ( m_flNextClick <= gpGlobals->curtime )
+ {
+ // Play click animation
+ // SendWeaponAnim( ACT_SLAM_DETONATOR_DETONATE );
+
+ // Switch states
+ switch( m_iFiringState )
+ {
+ case MORTAR_IDLE:
+ m_iFiringState = MORTAR_CHARGING_POWER;
+ break;
+ case MORTAR_CHARGING_POWER:
+ m_pPowerBar->m_flFiringPower = m_pPowerBar->m_flPower;
+ m_iFiringState = MORTAR_CHARGING_ACCURACY;
+ break;
+ case MORTAR_CHARGING_ACCURACY:
+ m_pPowerBar->m_flFiringAccuracy = m_pPowerBar->m_flPower;
+ m_iFiringState = MORTAR_IDLE;
+
+ FireMortar();
+ break;
+ default:
+ break;
+ }
+
+ input->ClearInputButton( IN_ATTACK );
+ gHUD.m_iKeyBits &= ~IN_ATTACK;
+
+ m_flNextClick = gpGlobals->curtime + 0.05;
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void C_WeaponMortar::Redraw()
+{
+ BaseClass::Redraw();
+
+ // If the player's dead, abort
+ C_BaseTFPlayer *pPlayer = C_BaseTFPlayer::GetLocalPlayer();
+ if ( pPlayer == NULL )
+ return;
+ if ( pPlayer->GetHealth() < 1 )
+ {
+ m_iFiringState = MORTAR_IDLE;
+ m_bCarried = true;
+ return;
+ }
+
+ // If it's reloading, tell the player
+ if ( m_bMortarReloading )
+ {
+ int width, height;
+ messagechars->GetStringLength( m_hFontText, &width, &height, "Mortar is reloading..." );
+ messagechars->DrawString( m_hFontText, (ScreenWidth() - width) / 2, YRES(350), 192, 192, 192, 255, "Mortar is reloading...", IMessageChars::MESSAGESTRINGID_NONE );
+ return;
+ }
+
+ // Handle power charging
+ switch( m_iFiringState )
+ {
+ case MORTAR_IDLE:
+ m_pPowerBar->m_flPower = 0;
+ break;
+ case MORTAR_CHARGING_POWER:
+ m_pPowerBar->m_flPower = MIN( m_pPowerBar->m_flPower + ( (1.0 / MORTAR_CHARGE_POWER_RATE) * gpGlobals->curtimeDelta), 1.0f);
+ m_pPowerBar->m_flFiringPower = 0;
+ m_pPowerBar->m_flFiringAccuracy = 0;
+ if ( m_pPowerBar->m_flPower >= 1.0 )
+ {
+ // Hit Max, start going down
+ m_pPowerBar->m_flFiringPower = m_pPowerBar->m_flPower;
+ m_iFiringState = MORTAR_CHARGING_ACCURACY;
+ m_flNextClick = gpGlobals->curtime + 0.25;
+ }
+ break;
+ case MORTAR_CHARGING_ACCURACY:
+ // Calculate accuracy speed
+ m_flAccuracySpeed = (1.0 / MORTAR_CHARGE_ACCURACY_RATE);
+ if ( m_pPowerBar->m_flFiringPower > 0.5 )
+ {
+ // Shots over halfway suffer an increased speed to the accuracy power, making accurate shots harder
+ float flAdjustedPower = (m_pPowerBar->m_flFiringPower - 0.5) * 3.0;
+ m_flAccuracySpeed += (m_pPowerBar->m_flFiringPower * flAdjustedPower);
+ }
+
+ m_pPowerBar->m_flPower = MAX( m_pPowerBar->m_flPower - ( m_flAccuracySpeed * gpGlobals->curtimeDelta), -0.25f);
+ if ( m_pPowerBar->m_flPower <= -0.25 )
+ {
+ // Hit Min, fire mortar
+ m_pPowerBar->m_flFiringAccuracy = m_pPowerBar->m_flPower;
+ m_iFiringState = MORTAR_IDLE;
+
+ FireMortar();
+ m_flNextClick = gpGlobals->curtime + 0.25;
+ }
+ break;
+ default:
+ break;
+ }
+
+ // Draw the rotate icon if the player's rotating the mortar
+ if ( m_bRotating )
+ {
+ vgui::Panel *pParent = GetClientModeNormal()->GetViewport();
+ int parentWidth, parentHeight;
+ pParent->GetSize(parentWidth, parentHeight);
+ int iWidth = 64;
+ int iHeight = 64;
+ int iX = (parentWidth - iWidth) / 2;
+ int iY = (parentHeight - 216);
+
+ IMesh* pMesh = materials->GetDynamicMesh( true, NULL, NULL, m_pRotateIcon );
+
+ CMeshBuilder meshBuilder;
+ meshBuilder.Begin( pMesh, MATERIAL_QUADS, 1 );
+
+ meshBuilder.Color3f( 1.0, 1.0, 1.0 );
+ meshBuilder.TexCoord2f( 0,0,0 );
+ meshBuilder.Position3f( iX,iY,0 );
+ meshBuilder.AdvanceVertex();
+
+ meshBuilder.Color3f( 1.0, 1.0, 1.0 );
+ meshBuilder.TexCoord2f( 0,1,0 );
+ meshBuilder.Position3f( iX+iWidth, iY, 0 );
+ meshBuilder.AdvanceVertex();
+
+ meshBuilder.Color3f( 1.0, 1.0, 1.0 );
+ meshBuilder.TexCoord2f( 0,1,1 );
+ meshBuilder.Position3f( iX+iWidth, iY+iHeight, 0 );
+ meshBuilder.AdvanceVertex();
+
+ meshBuilder.Color3f( 1.0, 1.0, 1.0 );
+ meshBuilder.TexCoord2f( 0,0,1 );
+ meshBuilder.Position3f( iX, iY+iHeight, 0 );
+ meshBuilder.AdvanceVertex();
+
+ meshBuilder.End();
+ pMesh->Draw();
+ }
+
+ // Update the ground line if it's moved
+ if ( !m_bCarried && (m_flPrevMortarYaw != m_flMortarYaw ) &&
+ gpGlobals->curtime > m_flLastGroundlineUpdateTime + g_CVMortarGroundLineUpdateInterval.GetFloat() )
+ {
+ // Create the Ground line start & end points
+ Vector vecForward;
+ AngleVectors( QAngle( 0, m_flMortarYaw, 0 ), &vecForward );
+ Vector vecStart = m_vecMortarOrigin + (vecForward * MORTAR_RANGE_MIN);
+
+ float flRange = MORTAR_RANGE_MAX_INITIAL;
+ if ( pPlayer->HasNamedTechnology( "mortar_range" ) )
+ flRange = MORTAR_RANGE_MAX_UPGRADED;
+ Vector vecEnd = m_vecMortarOrigin + (vecForward * flRange);
+
+ m_pDarkLine->SetParameters( m_vecMortarOrigin, vecStart, Vector( 0.1,0.1,0.1 ), Vector( 0.1,0.1,0.1 ), 0.5, 22 );
+ m_pGroundLine->SetParameters( vecStart, vecEnd, Vector(0,1,0), Vector(1,0,0), 0.5, 22 );
+
+ m_flPrevMortarYaw = m_flMortarYaw;
+
+ m_flLastGroundlineUpdateTime = gpGlobals->curtime;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Capture mouse input for mortar rotation
+//-----------------------------------------------------------------------------
+void C_WeaponMortar::OverrideMouseInput( float *x, float *y )
+{
+ if ( !m_bRotating )
+ return;
+
+ float flX = ( *x ) * 0.05f;
+
+ m_flMortarYaw = anglemod(m_flMortarYaw - flX);
+
+ *x = 0.0f;
+ *y = 0.0f;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Weapon's been deployed
+//-----------------------------------------------------------------------------
+bool C_WeaponMortar::Deploy( void )
+{
+ if ( m_pDarkLine )
+ {
+ m_pDarkLine->SetVisible( true );
+ }
+ if ( m_pGroundLine )
+ {
+ m_pGroundLine->SetVisible( true );
+ }
+
+ return BaseClass::Deploy();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Weapon's been holstered
+//-----------------------------------------------------------------------------
+bool C_WeaponMortar::Holster( C_BaseCombatWeapon *pSwitchingTo )
+{
+ if ( m_pDarkLine )
+ {
+ m_pDarkLine->SetVisible( false );
+ }
+ if ( m_pGroundLine )
+ {
+ m_pGroundLine->SetVisible( false );
+ }
+
+ return BaseClass::Holster( pSwitchingTo );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void C_WeaponMortar::FireMortar( void )
+{
+ // Clamp inaccuracy
+ float flTempAcc = m_pPowerBar->m_flFiringAccuracy;
+ if ( flTempAcc > 0.25 )
+ flTempAcc = 0.25;
+ else if ( flTempAcc < -0.25 )
+ flTempAcc = -0.25;
+
+ // HACKHACK: This is an amazingly bad way to do it. Replace this when the
+ // client DLL can insert commands into the usercmds
+ char szbuf[48];
+ Q_snprintf( szbuf, sizeof( szbuf ), "mortar %0.2f %0.2f %0.2f\n", m_pPowerBar->m_flFiringPower, flTempAcc, m_flMortarYaw );
+ engine->ClientCmd(szbuf);
+
+ // Tell the power bar to reset soon
+ m_pPowerBar->m_flReset = gpGlobals->curtime + 1.0;
+} \ No newline at end of file
diff --git a/game/client/tf2/c_weapon_twohandedcontainer.cpp b/game/client/tf2/c_weapon_twohandedcontainer.cpp
new file mode 100644
index 0000000..8ff85c5
--- /dev/null
+++ b/game/client/tf2/c_weapon_twohandedcontainer.cpp
@@ -0,0 +1,166 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Client's Support "weapon"
+//
+// $NoKeywords: $
+//=============================================================================//
+#include "cbase.h"
+#include "weapon_twohandedcontainer.h"
+
+//-----------------------------------------------------------------------------
+// Purpose: Draws little viewmodel attachments
+//-----------------------------------------------------------------------------
+void C_WeaponTwoHandedContainer::ViewModelDrawn( C_BaseViewModel *pBaseViewModel )
+{
+ BaseClass::ViewModelDrawn( pBaseViewModel );
+
+ if (pBaseViewModel->ViewModelIndex() != 0)
+ {
+ if ( m_hRightWeapon )
+ {
+ m_hRightWeapon->ViewModelDrawn(pBaseViewModel);
+ }
+ }
+ else
+ {
+ if ( m_hLeftWeapon )
+ {
+ m_hLeftWeapon->ViewModelDrawn(pBaseViewModel);
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+bool C_WeaponTwoHandedContainer::OnFireEvent( C_BaseViewModel *pViewModel, const Vector& origin,
+ const QAngle& angles, int event, const char *options )
+{
+ bool bRight = m_hRightWeapon->OnFireEvent( pViewModel, origin, angles, event, options );
+ bool bLeft = m_hLeftWeapon->OnFireEvent( pViewModel, origin, angles, event, options );
+
+ return ( bRight || bLeft );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void C_WeaponTwoHandedContainer::OnDataChanged( DataUpdateType_t updateType )
+{
+ BaseClass::OnDataChanged( updateType );
+
+ // Did we just receive a new weapon?
+ bool rightchanged = m_hOldRightWeapon.Get() != m_hRightWeapon.Get() ? true : false;
+ bool leftchanged = m_hOldLeftWeapon.Get() != m_hLeftWeapon.Get() ? true : false;
+
+ if ( rightchanged || leftchanged )
+ {
+ /*
+ // Tell weapons that they're being holstered
+ if ( m_hRightWeapon != NULL && rightchanged )
+ {
+ m_hRightWeapon->Holster( NULL );
+ }
+ if ( m_hLeftWeapon != NULL && leftchanged )
+ {
+ m_hLeftWeapon->Holster( NULL );
+ }
+ */
+
+ HookWeaponEntities();
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void C_WeaponTwoHandedContainer::HookWeaponEntities( void )
+{
+ m_hOldRightWeapon = m_hRightWeapon;
+ m_hOldLeftWeapon = m_hLeftWeapon;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Never draw the container
+//-----------------------------------------------------------------------------
+bool C_WeaponTwoHandedContainer::ShouldDraw( void )
+{
+ return false;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: This weapon is the active weapon, and it should now draw anything
+// it wants to. This gets called every frame.
+//-----------------------------------------------------------------------------
+void C_WeaponTwoHandedContainer::Redraw()
+{
+ BaseClass::Redraw();
+
+ if ( m_hRightWeapon.Get() )
+ {
+ m_hRightWeapon->Redraw();
+ }
+ if ( m_hLeftWeapon.Get() )
+ {
+ m_hLeftWeapon->Redraw();
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Draw both weapon's ammo's
+//-----------------------------------------------------------------------------
+void C_WeaponTwoHandedContainer::DrawAmmo()
+{
+ // Just tell our active weapon to draw it's ammo, since our offhand doesn't use it
+ if ( m_hLeftWeapon )
+ {
+ m_hLeftWeapon->DrawAmmo();
+ }
+ if ( m_hRightWeapon.Get() )
+ {
+ m_hRightWeapon->DrawAmmo();
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Let each weapon handle input
+//-----------------------------------------------------------------------------
+void C_WeaponTwoHandedContainer::HandleInput( void )
+{
+ BaseClass::HandleInput();
+
+ if ( m_hRightWeapon )
+ {
+ m_hRightWeapon->HandleInput();
+ }
+ if ( m_hLeftWeapon )
+ {
+ m_hLeftWeapon->HandleInput();
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Let each weapon handle input
+//-----------------------------------------------------------------------------
+void C_WeaponTwoHandedContainer::OverrideMouseInput( float *x, float *y )
+{
+ BaseClass::OverrideMouseInput( x,y );
+
+ if ( m_hRightWeapon )
+ {
+ m_hRightWeapon->OverrideMouseInput( x,y );
+ }
+ if ( m_hLeftWeapon )
+ {
+ m_hLeftWeapon->OverrideMouseInput( x,y );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Output : Returns true on success, false on failure.
+//-----------------------------------------------------------------------------
+bool C_WeaponTwoHandedContainer::VisibleInWeaponSelection( void )
+{
+ return false;
+}
diff --git a/game/client/tf2/clientmode_commander.cpp b/game/client/tf2/clientmode_commander.cpp
new file mode 100644
index 0000000..64fb9b7
--- /dev/null
+++ b/game/client/tf2/clientmode_commander.cpp
@@ -0,0 +1,725 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $Workfile: $
+// $NoKeywords: $
+//===========================================================================//
+#include "cbase.h"
+#include "hud_chat.h"
+#include "clientmode_commander.h"
+#include "vgui_int.h"
+#include "ivmodemanager.h"
+#include "iinput.h"
+#include "kbutton.h"
+#include "usercmd.h"
+#include "c_basetfplayer.h"
+#include "view_shared.h"
+#include "in_main.h"
+#include "commanderoverlaypanel.h"
+#include "iviewrender.h"
+#include <vgui/IInput.h>
+#include <vgui/IPanel.h>
+
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+enum
+{
+ VISIBLE_STATIC_PROP_HEIGHT = 7500
+};
+
+extern Vector g_vecRenderOrigin;
+extern QAngle g_vecRenderAngles;
+
+static ConVar Commander_SlueSpeed( "commander_speed", "800.0", 0 );
+static ConVar Commander_MouseSpeed( "commander_mousespeed", "200.0", 0 );
+static ConVar Commander_RightMoveSpeedScale( "commander_rightmovespeedscale", "2.0", 0 );
+static ConVar Commander_InvertMouse( "commander_invertmouse", "1.0", 0 );
+
+// Public version of the commander mode;
+IClientMode *ClientModeCommander()
+{
+ // TF2 Commander View Mode
+ static CClientModeCommander g_ClientModeCommander;
+ return &g_ClientModeCommander;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *commander -
+//-----------------------------------------------------------------------------
+void CCommanderViewportPanel::SetCommanderView( CClientModeCommander *commander )
+{
+ m_pCommanderView = commander;
+
+ if ( m_pOverlayPanel )
+ {
+ m_pOverlayPanel->SetCommanderView( m_pCommanderView );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Output : CCommanderOverlayPanel
+//-----------------------------------------------------------------------------
+CCommanderOverlayPanel *CCommanderViewportPanel::GetCommanderOverlayPanel( void )
+{
+ return m_pOverlayPanel;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+CCommanderViewportPanel::CCommanderViewportPanel( void ) :
+ m_CursorCommander( vgui::dc_arrow ),
+ m_CursorRightMouseMove(vgui::dc_hand)
+{
+ m_pOverlayPanel = new CCommanderOverlayPanel();
+ m_pOverlayPanel->SetParent( this );
+
+ SetPaintEnabled( false );
+ SetPaintBorderEnabled( false );
+ SetPaintBackgroundEnabled( false );
+
+ SetCursor( m_CursorCommander );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+CCommanderViewportPanel::~CCommanderViewportPanel( void )
+{
+}
+
+//-----------------------------------------------------------------------------
+// call these when commander view is enabled/disabled
+//-----------------------------------------------------------------------------
+
+
+void CCommanderViewportPanel::Enable()
+{
+ vgui::VPANEL pRoot = VGui_GetClientDLLRootPanel();
+
+ SetCursor(m_CursorCommander);
+ vgui::surface()->SetCursor( m_CursorCommander );
+
+ // Make the viewport fill the root panel.
+ if ( pRoot)
+ {
+ int wide, tall;
+ vgui::ipanel()->GetSize(pRoot, wide, tall);
+ SetBounds(0, 0, wide, tall);
+ }
+
+ C_BaseEntity *ent = cl_entitylist->GetEnt( 0 );
+
+ if ( m_pOverlayPanel && ent )
+ {
+ m_pOverlayPanel->Enable();
+ }
+
+ SetVisible( true );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CCommanderViewportPanel::Disable()
+{
+ if ( m_pOverlayPanel )
+ {
+ m_pOverlayPanel->Disable();
+ }
+
+ SetVisible( false );
+}
+
+void CCommanderViewportPanel::MinimapClicked( const Vector& clickWorldPos )
+{
+ // Don't use Z... our current z is what we want
+ Vector actualOrigin, offset;
+ VectorCopy( clickWorldPos, actualOrigin );
+ actualOrigin.z = m_pOverlayPanel->TacticalOrigin().z;
+
+ m_pOverlayPanel->ActualToVisibleOffset( offset );
+ VectorSubtract( actualOrigin, offset, actualOrigin );
+ m_pOverlayPanel->BoundOrigin( actualOrigin );
+ m_pOverlayPanel->TacticalOrigin() = actualOrigin;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+CClientModeCommander::CClientModeCommander() : BaseClass()
+{
+ m_pClear = NULL;
+ m_pSkyBox = NULL;
+ m_ScaledSlueSpeed = 10;
+ m_Log_BaseEto2 = 1.4427f; // factor to convert from a logarithm of base E to base 2.
+
+ m_pViewport = new CCommanderViewportPanel;
+ GetCommanderViewport()->SetCommanderView( this );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+CClientModeCommander::~CClientModeCommander()
+{
+
+}
+
+CCommanderViewportPanel *CClientModeCommander::GetCommanderViewport()
+{
+ Assert( m_pViewport );
+ return static_cast< CCommanderViewportPanel * >( m_pViewport );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Called once at dll load time
+//-----------------------------------------------------------------------------
+void CClientModeCommander::Init( void )
+{
+ BaseClass::Init();
+ GetCommanderViewport()->RequestFocus();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Output : vgui::Panel
+//-----------------------------------------------------------------------------
+vgui::Panel *CClientModeCommander::GetMinimapParent( void )
+{
+ return GetCommanderOverlayPanel();
+}
+
+//-----------------------------------------------------------------------------
+// Inherited from IMinimapClient
+//-----------------------------------------------------------------------------
+void CClientModeCommander::MinimapClicked( const Vector& clickWorldPos )
+{
+ if ( GetCommanderViewport() )
+ {
+ GetCommanderViewport()->MinimapClicked( clickWorldPos );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+CCommanderOverlayPanel *CClientModeCommander::GetCommanderOverlayPanel( void )
+{
+ if ( GetCommanderViewport() )
+ {
+ return GetCommanderViewport()->GetCommanderOverlayPanel();
+ }
+ return NULL;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+
+void CClientModeCommander::Enable()
+{
+ // HACK: Find a better place for these
+ m_pClear = (ConVar *)cvar->FindVar( "gl_clear" );
+ m_pSkyBox = (ConVar *)cvar->FindVar( "r_drawskybox" );
+
+ HudCommanderOverlayMgr()->Enable( true );
+
+ BaseClass::Enable();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CClientModeCommander::Disable()
+{
+ BaseClass::Disable();
+
+ ::input->ResetMouse();
+
+ HudCommanderOverlayMgr()->Enable( false );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+
+void CClientModeCommander::Update()
+{
+ if ( !engine->IsInGame() )
+ {
+ // Disable commander view
+ modemanager->SwitchMode( false, false );
+ return;
+ }
+
+ ClientModeTFBase::Update();
+
+ Vector mins, maxs;
+ GetCommanderViewport()->GetCommanderOverlayPanel()->GetVisibleArea( mins, maxs );
+ MapData().SetVisibleArea( mins, maxs );
+
+ HudCommanderOverlayMgr()->Tick( );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CClientModeCommander::Layout()
+{
+ BaseClass::Layout();
+
+ // Force it to recompute it's boundaries
+ GetCommanderViewport()->GetCommanderOverlayPanel()->Disable();
+ GetCommanderViewport()->GetCommanderOverlayPanel()->Enable();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: The mode can choose to not draw fog
+//-----------------------------------------------------------------------------
+bool CClientModeCommander::ShouldDrawFog( void )
+{
+ return false;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Checks map bounds and determines ideal height for tactical view
+// Input : fov -
+// zoom -
+// Output : float
+//-----------------------------------------------------------------------------
+float CClientModeCommander::GetHeightForMap( float zoom )
+{
+ Vector mins, maxs;
+ MapData().GetMapBounds( mins, maxs );
+ return maxs.z + TACTICAL_ZOFFSET;
+}
+
+
+bool CClientModeCommander::GetOrthoParameters(CViewSetup *pSetup)
+{
+ Vector vCenter;
+ float xSize, ySize;
+ GetCommanderViewport()->GetCommanderOverlayPanel()->GetOrthoRenderBox(vCenter, xSize, ySize);
+
+ pSetup->m_bOrtho = true;
+ pSetup->m_OrthoLeft = -xSize;
+ pSetup->m_OrthoTop = -ySize;
+ pSetup->m_OrthoRight = xSize;
+ pSetup->m_OrthoBottom = ySize;
+
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *angles -
+//-----------------------------------------------------------------------------
+void CClientModeCommander::OverrideView( CViewSetup *pSetup )
+{
+ // Turn off vis when in commander mode
+ view->DisableVis();
+ VectorCopy( GetCommanderViewport()->GetCommanderOverlayPanel()->TacticalAngles(), pSetup->angles );
+ VectorCopy( GetCommanderViewport()->GetCommanderOverlayPanel()->TacticalOrigin(), pSetup->origin );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Scale commander slue speed based on viewport zoom factor
+// Output : float
+//-----------------------------------------------------------------------------
+float CClientModeCommander::GetScaledSlueSpeed( void )
+{
+ return m_ScaledSlueSpeed;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Convert move to scaled move
+// Input : in -
+// Output : float
+//-----------------------------------------------------------------------------
+float CClientModeCommander::Commander_ResampleMove( float in )
+{
+ float sign;
+ float move;
+
+ if ( !in )
+ return 0.0;
+
+ sign = in > 0.0 ? 1.0 : -1.0;
+
+ move = GetScaledSlueSpeed();
+
+ return move * sign;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Zero out any movement in the command
+// Input : *cmd -
+//-----------------------------------------------------------------------------
+void CClientModeCommander::ResetCommand( CUserCmd *cmd )
+{
+ cmd->buttons = 0;
+ cmd->forwardmove = 0;
+ cmd->sidemove = 0;
+ cmd->upmove = 0;
+ cmd->viewangles.Init();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: TF2 commander mode movement logic
+//-----------------------------------------------------------------------------
+void CClientModeCommander::IsometricMove( CUserCmd *cmd )
+{
+ int i;
+ Vector wishvel;
+ float fmove, smove;
+ Vector forward, right, up;
+
+ AngleVectors ( cmd->viewangles, &forward, &right, &up); // Determine movement angles
+
+ // Copy movement amounts
+ fmove = cmd->forwardmove;
+ smove = cmd->sidemove;
+
+ // No up / down movement
+ forward.Init(1, 0, 0);
+ right.Init(0, -1, 0);
+
+ wishvel.Init();
+
+ // Determine x and y parts of velocity
+ for (i=0; i < 3; i++)
+ {
+ wishvel[i] = forward[i]*fmove + right[i]*smove;
+ }
+
+ GetCommanderViewport()->GetCommanderOverlayPanel()->TacticalOrigin() += TICK_INTERVAL * wishvel;
+ GetCommanderViewport()->GetCommanderOverlayPanel()->BoundOrigin( GetCommanderViewport()->GetCommanderOverlayPanel()->TacticalOrigin() );
+}
+
+#define WINDOWED_KEEPMOVING_PIXELS 300
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : frametime -
+// *cmd -
+//-----------------------------------------------------------------------------
+void CClientModeCommander::CreateMove( float flInputSampleTime, CUserCmd *cmd )
+{
+ int mx, my;
+ int realx, realy;
+ //int sidex, sidey;
+
+ cmd->upmove = 0;
+
+ // Figure out the speed scale so their perceptual movement speed stays the same.
+ m_ScaledSlueSpeed = Commander_SlueSpeed.GetFloat() * GetCommanderViewport()->GetCommanderOverlayPanel()->WorldUnitsPerPixel();
+ m_ScaledMouseSpeed = Commander_MouseSpeed.GetFloat() * GetCommanderViewport()->GetCommanderOverlayPanel()->WorldUnitsPerPixel();
+
+ // Translate WASD while in commander mode...
+ float temp = cmd->forwardmove;
+ // Swap forward/right
+ cmd->forwardmove = cmd->sidemove;
+ // Invert right/left
+ cmd->sidemove = -temp;
+
+ // Normalize nonzero inputs to scaled speed
+ if ( cmd->forwardmove )
+ {
+ cmd->forwardmove = ( cmd->forwardmove > 0 ) ? GetScaledSlueSpeed() : -GetScaledSlueSpeed();
+ }
+ if ( cmd->sidemove )
+ {
+ cmd->sidemove = ( cmd->sidemove > 0 ) ? GetScaledSlueSpeed() : -GetScaledSlueSpeed();
+ }
+
+ // Sample mouse
+ ::input->GetFullscreenMousePos( &mx, &my, &realx, &realy );
+
+ if( GetCommanderViewport()->GetCommanderOverlayPanel()->IsRightMouseMapMoving() || ( in_commandermousemove.state & 1 ) )
+ {
+ cmd->forwardmove = m_ScaledMouseSpeed * (mx - m_LastMouseX);
+ cmd->sidemove = m_ScaledMouseSpeed * (my - m_LastMouseY);
+
+ if ( Commander_InvertMouse.GetInt() )
+ {
+ cmd->forwardmove *= -1.0f;
+ cmd->sidemove *= -1.0f;
+ }
+
+ //input->SetFullscreenMousePos( m_LastMouseX, m_LastMouseY );
+ mx = m_LastMouseX;
+ my = m_LastMouseY;
+ }
+ /*
+ else if ( input->IsFullscreenMouse() )
+ {
+ if ( abs( realx - mx ) < WINDOWED_KEEPMOVING_PIXELS &&
+ abs( realy - my ) < WINDOWED_KEEPMOVING_PIXELS )
+ {
+ sidex = 2;
+ sidey = 2;
+
+ // Check Size of viewport
+ if ( mx < sidex )
+ {
+ cmd->forwardmove = -GetScaledSlueSpeed();
+ }
+ else if ( mx > ( ScreenWidth() - sidex ))
+ {
+ cmd->forwardmove = GetScaledSlueSpeed();
+ }
+
+ if ( my < sidey )
+ {
+ cmd->sidemove = -GetScaledSlueSpeed();
+ }
+ else if ( my > ( ScreenHeight() - sidey ) )
+ {
+ cmd->sidemove = GetScaledSlueSpeed();
+ }
+ }
+ }
+ */
+
+ m_LastMouseX = mx;
+ m_LastMouseY = my;
+
+ // Look straight down
+ cmd->viewangles.x = 90; // 45;
+ cmd->viewangles.y = 90; //45fmod( 3.0* 360 * (gpGlobals->curtime * 0.01), 360 );
+ cmd->viewangles.z = 0;
+
+ GetCommanderViewport()->GetCommanderOverlayPanel()->TacticalAngles() = cmd->viewangles;
+
+ IsometricMove( cmd );
+
+ // Reset command
+ ResetCommand( cmd );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Makes sure the mouse is over the same world position as it started
+//-----------------------------------------------------------------------------
+
+void CClientModeCommander::MoveMouse( Vector& worldPos )
+{
+ Vector worldCenter;
+ float wworld, hworld;
+ GetCommanderViewport()->GetCommanderOverlayPanel()->GetOrthoRenderBox(worldCenter, wworld, hworld);
+ wworld *= 2; hworld *= 2;
+
+ Vector worldDelta;
+ VectorSubtract( worldPos, worldCenter, worldDelta );
+
+ int w, h;
+ GetCommanderViewport()->GetSize( w, h );
+
+ int mx, my;
+ mx = (worldDelta.x / wworld + 0.5f) * w;
+ my = (0.5f - worldDelta.y / hworld) * h;
+
+ // Clamp
+ if (mx < 0) mx = 0; else if (mx > w) mx = w;
+ if (my < 0) my = 0; else if (my > h) my = h;
+
+ //input->SetFullscreenMousePos( mx, my );
+
+ m_LastMouseX = mx;
+ m_LastMouseY = my;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *newmap -
+//-----------------------------------------------------------------------------
+void CClientModeCommander::LevelInit( const char *newmap )
+{
+ BaseClass::LevelInit( newmap );
+
+ HudCommanderOverlayMgr()->LevelShutdown();
+ MapData().LevelInit( newmap );
+ GetCommanderViewport()->GetCommanderOverlayPanel()->LevelInit( newmap );
+ HudCommanderOverlayMgr()->LevelInit( );
+
+ GetCommanderViewport()->Enable();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CClientModeCommander::LevelShutdown( void )
+{
+ GetCommanderViewport()->Disable();
+
+ MapData().LevelShutdown();
+
+ HudCommanderOverlayMgr()->LevelShutdown();
+
+ GetCommanderViewport()->GetCommanderOverlayPanel()->LevelShutdown();
+
+ BaseClass::LevelShutdown();
+}
+
+//-----------------------------------------------------------------------------
+// returns the viewport panel
+//-----------------------------------------------------------------------------
+vgui::Panel *CClientModeCommander::GetViewport()
+{
+ return m_pViewport;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+bool CClientModeCommander::ShouldDrawEntity(C_BaseEntity *pEnt)
+{
+ return MapData().IsEntityVisibleToTactical(pEnt);
+}
+
+bool CClientModeCommander::ShouldDrawDetailObjects( )
+{
+ return false;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Always draw the local player while in commander mode
+//-----------------------------------------------------------------------------
+bool CClientModeCommander::ShouldDrawLocalPlayer( C_BasePlayer *pPlayer )
+{
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Output : Returns true on success, false on failure.
+//-----------------------------------------------------------------------------
+bool CClientModeCommander::ShouldDrawViewModel( void )
+{
+ return false;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Return false to disable crosshair
+// Output : Returns true on success, false on failure.
+//-----------------------------------------------------------------------------
+bool CClientModeCommander::ShouldDrawCrosshair( void )
+{
+ return false;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Adjust engine rendering viewport rectangle if needed
+// Input : x -
+// y -
+// width -
+// height -
+//-----------------------------------------------------------------------------
+void CClientModeCommander::AdjustEngineViewport( int& x, int& y, int& width, int& height )
+{
+}
+
+
+//-----------------------------------------------------------------------------
+// Should I draw particles
+//-----------------------------------------------------------------------------
+
+bool CClientModeCommander::ShouldDrawParticles( )
+{
+ Vector vCenter;
+ float xSize, ySize;
+ GetCommanderViewport()->GetCommanderOverlayPanel()->GetOrthoRenderBox(vCenter, xSize, ySize);
+
+ // Activate/deactivate particles rendering based on zoom level
+ float maxSize = MAX( xSize, ySize );
+ return (maxSize < VISIBLE_STATIC_PROP_HEIGHT);
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: When in commander mode, force gl_clear and don't draw the skybox
+//-----------------------------------------------------------------------------
+
+void CClientModeCommander::PreRender( CViewSetup *pSetup )
+{
+ if ( !m_pClear || !m_pSkyBox )
+ return;
+
+ m_fOldClear = m_pClear->GetFloat();
+ m_pClear->SetValue( 1.0f );
+ pSetup->clearColor = !!m_pClear->GetInt();
+
+ m_fOldSkybox = m_pSkyBox->GetFloat();
+ m_pSkyBox->SetValue( 0.0f );
+
+ GetOrthoParameters(pSetup);
+ render->DrawTopView( true );
+ Vector2D mins = pSetup->origin.AsVector2D();
+ Vector2D maxs = pSetup->origin.AsVector2D();
+ mins.x += pSetup->m_OrthoLeft;
+ maxs.x += pSetup->m_OrthoRight;
+ mins.y += pSetup->m_OrthoTop;
+ maxs.y += pSetup->m_OrthoBottom;
+ render->TopViewBounds( mins, maxs );
+
+ // Activate/deactivate static prop + particles rendering based on zoom level
+ Vector2D size;
+ Vector2DSubtract( maxs, mins, size );
+ float maxSize = MAX( size.x, size.y );
+ bool showStaticProps = (maxSize < VISIBLE_STATIC_PROP_HEIGHT);
+ ClientLeafSystem()->DrawStaticProps(showStaticProps);
+ ClientLeafSystem()->DrawSmallEntities(showStaticProps);
+
+ BaseClass::PreRender(pSetup);
+}
+
+void CClientModeCommander::PostRenderWorld()
+{
+ render->DrawTopView( false );
+ ClientLeafSystem()->DrawStaticProps(true);
+ ClientLeafSystem()->DrawSmallEntities(true);
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Restore cvar values
+//-----------------------------------------------------------------------------
+void CClientModeCommander::PostRender( void )
+{
+ if ( !m_pClear || !m_pSkyBox )
+ return;
+
+ m_pClear->SetValue( m_fOldClear );
+ m_pSkyBox->SetValue( m_fOldSkybox );
+
+ BaseClass::PostRender();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Swallow mouse wheel when in this view
+// Input : down -
+// keynum -
+// *pszCurrentBinding -
+// Output : int
+//-----------------------------------------------------------------------------
+int CClientModeCommander::KeyInput( int down, ButtonCode_t keynum, const char *pszCurrentBinding )
+{
+ switch ( keynum )
+ {
+ case MOUSE_WHEEL_UP:
+ case MOUSE_WHEEL_DOWN:
+ // Swallow
+ return 0;
+ }
+
+ // Allow engine to process
+ return BaseClass::KeyInput( down, keynum, pszCurrentBinding );
+}
+
diff --git a/game/client/tf2/clientmode_commander.h b/game/client/tf2/clientmode_commander.h
new file mode 100644
index 0000000..871dd0c
--- /dev/null
+++ b/game/client/tf2/clientmode_commander.h
@@ -0,0 +1,146 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $Workfile: $
+// $Date: $
+// $NoKeywords: $
+//=============================================================================//
+#if !defined( CLIENTMODE_COMMANDER_H )
+#define CLIENTMODE_COMMANDER_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "clientmode_tfbase.h"
+#include <vgui/Cursor.h>
+#include "hud_minimap.h"
+#include <vgui_controls/Panel.h>
+
+class IMaterial;
+class CCommanderViewportPanel;
+class Vector;
+class CCommanderOverlayPanel;
+namespace vgui
+{
+ class Panel;
+ class AnimationController;
+}
+
+class CClientModeCommander : public ClientModeTFBase, public IMinimapClient
+{
+ DECLARE_CLASS( CClientModeCommander, ClientModeTFBase );
+
+// IClientMode overrides.
+public:
+
+ CClientModeCommander();
+ virtual ~CClientModeCommander();
+
+ virtual void Init( void );
+
+ virtual void Enable();
+ virtual void Disable();
+
+ virtual void Update();
+ virtual void Layout();
+
+ virtual bool ShouldDrawFog( void );
+ virtual void OverrideView( CViewSetup *pSetup );
+ virtual void CreateMove( float flInputSampleTime, CUserCmd *cmd );
+ virtual void LevelInit( const char *newmap );
+ virtual void LevelShutdown( void );
+ virtual bool ShouldDrawEntity(C_BaseEntity *pEnt);
+ virtual bool ShouldDrawDetailObjects( );
+ virtual bool ShouldDrawLocalPlayer( C_BasePlayer *pPlayer );
+ virtual bool ShouldDrawViewModel( void );
+ virtual bool ShouldDrawCrosshair( void );
+ virtual bool ShouldDrawParticles( );
+
+ virtual void AdjustEngineViewport( int& x, int& y, int& width, int& height );
+ virtual void PreRender( CViewSetup *pSetup );
+ virtual void PostRenderWorld();
+ virtual void PostRender( void );
+ virtual vgui::Panel *GetViewport();
+ virtual vgui::AnimationController *GetViewportAnimationController() { return NULL; }
+
+ // Input
+ virtual int KeyInput( int down, ButtonCode_t keynum, const char *pszCurrentBinding );
+
+ // Makes the mouse sit over a particular world location
+ void MoveMouse( Vector& worldPos );
+
+ // Inherited from IMinimapClient
+ virtual void MinimapClicked( const Vector& clickWorldPos );
+
+ CCommanderOverlayPanel *GetCommanderOverlayPanel( void );
+
+ virtual vgui::Panel *GetMinimapParent( void );
+
+private:
+ float GetScaledSlueSpeed( void );
+ void ResetCommand( CUserCmd *cmd );
+ float Commander_ResampleMove( float in );
+ void IsometricMove( CUserCmd *cmd );
+ float GetHeightForMap( float zoom );
+
+ // Fills in ortho parameters (and near/far Z) in pSetup for how the commander mode renders the world.
+ bool GetOrthoParameters(CViewSetup *pSetup);
+
+ CCommanderViewportPanel *GetCommanderViewport();
+
+private:
+
+ ConVar* m_pClear;
+ ConVar* m_pSkyBox;
+ float m_fOldClear;
+ float m_fOldSkybox;
+
+ int m_LastMouseX;
+ int m_LastMouseY;
+
+ float m_ScaledMouseSpeed;
+ float m_ScaledSlueSpeed;
+ float m_Log_BaseEto2; // scales logarithms from base E to base 2.
+};
+
+
+//-----------------------------------------------------------------------------
+// The panel responsible for rendering the 3D view in orthographic mode
+//-----------------------------------------------------------------------------
+class CCommanderViewportPanel : public CBaseViewport
+{
+ typedef CBaseViewport BaseClass;
+
+// Panel overrides.
+public:
+ CCommanderViewportPanel( void );
+ virtual ~CCommanderViewportPanel( void );
+
+ void Enable( void );
+ void Disable( void );
+ void SetCommanderView( CClientModeCommander *commander );
+ void MinimapClicked( const Vector& clickWorldPos );
+
+ CCommanderOverlayPanel *GetCommanderOverlayPanel( void );
+
+ virtual void ApplySchemeSettings( vgui::IScheme *pScheme )
+ {
+ BaseClass::ApplySchemeSettings( pScheme );
+
+ gHUD.InitColors( pScheme );
+ }
+
+private:
+
+ CCommanderOverlayPanel *m_pOverlayPanel;
+ CClientModeCommander *m_pCommanderView;
+
+ vgui::HCursor m_CursorCommander;
+ vgui::HCursor m_CursorRightMouseMove;
+
+};
+
+IClientMode *ClientModeCommander();
+
+#endif // CLIENTMODE_COMMANDER_H \ No newline at end of file
diff --git a/game/client/tf2/clientmode_tfbase.cpp b/game/client/tf2/clientmode_tfbase.cpp
new file mode 100644
index 0000000..e702129
--- /dev/null
+++ b/game/client/tf2/clientmode_tfbase.cpp
@@ -0,0 +1,223 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//===========================================================================//
+#include "cbase.h"
+#include "clientmode_tfbase.h"
+#include "hud.h"
+#include "c_tf_basecombatweapon.h"
+#include "keydefs.h"
+#include "c_tf_hintmanager.h"
+#include <vgui_controls/Controls.h>
+#include <vgui/IScheme.h>
+#include "filesystem.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+
+CMinimapPanel *ClientModeTFBase::m_pMinimap = NULL;
+vgui::HScheme g_hVGuiObjectScheme = 0;
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+ClientModeTFBase::ClientModeTFBase( void )
+{
+ m_bInitialized = false;
+
+ m_pCVDrawFullSkybox = NULL;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+ClientModeTFBase::~ClientModeTFBase( void )
+{
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Output : CMinimapPanel
+//-----------------------------------------------------------------------------
+CMinimapPanel *ClientModeTFBase::GetMinimap( void )
+{
+ return m_pMinimap;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+
+// FIXME: Remove if this ever becomes true for HL2 (I expect it will)
+ConVar r_radiosity ( "r_radiosity", "2" ); // do full radiosity calc?
+// FIXME: Remove when we reactivate detail props
+extern ConVar r_DrawDetailProps;
+
+void ClientModeTFBase::Init()
+{
+ BaseClass::Init();
+ C_BaseTFCombatWeapon::CreateCrosshairPanels();
+
+ // FIXME: For playtests, turn off detail props. They're causing perf problems
+ r_DrawDetailProps.SetValue("0");
+
+ // Turn lighting into a mode where we use better computation for the ambient
+ // cube on static props, and a cheap one for dynamic entities.
+ r_radiosity.SetValue("3");
+
+ if ( !m_pMinimap )
+ {
+ m_pMinimap = GET_HUDELEMENT( CMinimapPanel );
+ }
+
+ // Load up the object control panel scheme
+ g_hVGuiObjectScheme = vgui::scheme()->LoadSchemeFromFileEx( enginevgui->GetPanel( PANEL_CLIENTDLL ), "resource/ObjectControlPanelScheme.res", "TFBase" );
+ if (!g_hVGuiObjectScheme)
+ {
+ Warning( "Couldn't load control panel scheme!\n" );
+ }
+
+ // Load the objects.txt file.
+ LoadObjectInfos( ::filesystem );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void ClientModeTFBase::Shutdown()
+{
+ C_BaseTFCombatWeapon::DestroyCrosshairPanels();
+ BaseClass::Shutdown();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void ClientModeTFBase::Enable( void )
+{
+ BaseClass::Enable();
+
+ // Hook the minimap traces into the minimap
+ if ( GetMinimap() )
+ {
+ GetMinimap()->Activate();
+ }
+}
+
+void ClientModeTFBase::LevelInit( const char *newmap )
+{
+ BaseClass::LevelInit( newmap );
+
+ // Tell the radar to load the radar's overlay map
+ //g_Radar.LoadMap( newmap );
+ if ( GetMinimap() )
+ {
+ GetMinimap()->LevelInit( newmap );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void ClientModeTFBase::LevelShutdown( void )
+{
+ BaseClass::LevelShutdown();
+
+ if ( GetMinimap() )
+ {
+ GetMinimap()->LevelShutdown();
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *pSetup -
+//-----------------------------------------------------------------------------
+void ClientModeTFBase::PreRender( CViewSetup *pSetup )
+{
+ Initialize();
+
+ if ( !m_pCVDrawFullSkybox )
+ {
+ assert( 0 );
+ return;
+ }
+
+ m_flOldDrawFullSkybox = m_pCVDrawFullSkybox->GetFloat();
+
+ m_pCVDrawFullSkybox->SetValue( 1 );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void ClientModeTFBase::PostRender( void )
+{
+ C_BaseTFPlayer *pl = C_BaseTFPlayer::GetLocalPlayer();
+ if ( pl )
+ {
+ pl->UpdateTargetReticles();
+ }
+
+ if ( !m_pCVDrawFullSkybox )
+ {
+ assert( 0 );
+ return;
+ }
+
+ m_pCVDrawFullSkybox->SetValue( m_flOldDrawFullSkybox );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void ClientModeTFBase::Initialize( void )
+{
+ if ( m_bInitialized )
+ return;
+ m_bInitialized = true;
+
+ m_pCVDrawFullSkybox = (ConVar *)cvar->FindVar( "r_drawfullskybox" );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void ClientModeTFBase::Update( void )
+{
+ BaseClass::Update();
+
+ MapData().Update();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: We've received a keypress from the engine. Return 1 if the engine is allowed to handle it.
+//-----------------------------------------------------------------------------
+int ClientModeTFBase::KeyInput( int down, ButtonCode_t keynum, const char *pszCurrentBinding )
+{
+ if ( engine->Con_IsVisible() == false )
+ {
+ // Let hint system snag first escape key release
+ if ( down && ( keynum == KEY_ENTER ) && HintSystemEscapeKey() )
+ {
+ return 0;
+ }
+
+ // Has the player hit one of his Order keys?
+ if ( pszCurrentBinding && strncmp( pszCurrentBinding, "order", 5 ) == 0 )
+ {
+ if ( down )
+ {
+ //int iOrderNumber = (pszCurrentBinding[6] - '0') - 1;
+ //GetHudOrderList()->SelectOrder( iOrderNumber );
+ }
+ return 0;
+ }
+ }
+
+ return BaseClass::KeyInput( down, keynum, pszCurrentBinding );
+}
+
diff --git a/game/client/tf2/clientmode_tfbase.h b/game/client/tf2/clientmode_tfbase.h
new file mode 100644
index 0000000..f0f5c2a
--- /dev/null
+++ b/game/client/tf2/clientmode_tfbase.h
@@ -0,0 +1,68 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef CLIENTMODE_TFBASE_H
+#define CLIENTMODE_TFBASE_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "clientmode_shared.h"
+
+class ConVar;
+class CMinimapPanel;
+
+namespace vgui
+{
+ typedef unsigned long HScheme;
+}
+
+
+// This class defines the base clientmode behavior in TF. Classes that derive from
+// it and override functions should forward them to the base class.
+class ClientModeTFBase : public ClientModeShared
+{
+ DECLARE_CLASS( ClientModeTFBase, ClientModeShared );
+public:
+ ClientModeTFBase( void );
+ virtual ~ClientModeTFBase( void );
+
+ virtual void Init();
+ virtual void Shutdown();
+
+ virtual void Enable();
+
+ virtual void PreRender( CViewSetup *pSetup );
+ virtual void PostRender();
+ virtual void Update();
+
+ virtual void LevelInit( const char *newmap );
+ virtual void LevelShutdown( void );
+
+ // Input
+ virtual int KeyInput( int down, ButtonCode_t keynum, const char *pszCurrentBinding );
+
+ virtual CMinimapPanel *GetMinimap( void );
+
+ virtual vgui::Panel *GetMinimapParent( void ) = 0;
+
+private:
+ void Initialize( void );
+
+ bool m_bInitialized;
+
+ ConVar *m_pCVDrawFullSkybox;
+
+ float m_flOldDrawFullSkybox;
+
+ static CMinimapPanel *m_pMinimap;
+};
+
+
+extern vgui::HScheme g_hVGuiObjectScheme;
+
+#endif // CLIENTMODE_TFBASE_H
diff --git a/game/client/tf2/clientmode_tfnormal.cpp b/game/client/tf2/clientmode_tfnormal.cpp
new file mode 100644
index 0000000..f766e4e
--- /dev/null
+++ b/game/client/tf2/clientmode_tfnormal.cpp
@@ -0,0 +1,173 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Normal HUD mode
+//
+// $Workfile: $
+// $Date: $
+// $NoKeywords: $
+//=============================================================================//
+#include "cbase.h"
+#include "hud_chat.h"
+#include "clientmode_tfnormal.h"
+#include "clientmode.h"
+#include "hud.h"
+#include "iinput.h"
+#include "c_basetfplayer.h"
+#include "hud_timer.h"
+#include "usercmd.h"
+#include "in_buttons.h"
+#include "c_tf_playerclass.h"
+#include "engine/IEngineSound.h"
+#include <vgui/IInput.h>
+#include <vgui/IPanel.h>
+#include <vgui_controls/AnimationController.h>
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Instance the singleton and expose the interface to it.
+// Output : IClientMode
+//-----------------------------------------------------------------------------
+IClientMode *GetClientModeNormal( void )
+{
+ static ClientModeTFNormal g_ClientModeNormal;
+ return &g_ClientModeNormal;
+}
+
+ClientModeTFNormal::ClientModeTFNormal()
+{
+ m_pViewport = new Viewport();
+ m_pViewport->Start( gameuifuncs, gameeventmanager );
+}
+
+ClientModeTFNormal::Viewport::Viewport()
+{
+ // use a custom scheme for the hud
+ m_bHumanScheme = true;
+ vgui::HScheme scheme = vgui::scheme()->LoadSchemeFromFileEx( enginevgui->GetPanel( PANEL_CLIENTDLL ), "resource/ClientSchemeHuman.res", "HudScheme");
+ SetScheme(scheme);
+}
+
+void ClientModeTFNormal::Viewport::OnThink()
+{
+ BaseClass::OnThink();
+
+ // See if scheme should change
+ C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
+ if(!pPlayer)
+ return;
+ int team = pPlayer->GetTeamNumber();
+ if ( !team )
+ return;
+
+ bool human = ( team == TEAM_HUMANS ) ? true : false;
+ if ( human != m_bHumanScheme )
+ {
+ ReloadScheme();
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void ClientModeTFNormal::Viewport::ReloadScheme()
+{
+ // See if scheme should change
+ C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
+
+ if(!pPlayer)
+ return;
+
+ const char *schemeFile = NULL;
+
+ int team = pPlayer->GetTeamNumber();
+ if ( team )
+ {
+ m_bHumanScheme = ( team == TEAM_HUMANS ) ? true : false;
+
+ if ( m_bHumanScheme )
+ {
+ schemeFile = "resource/ClientSchemeHuman.res";
+ }
+ else
+ {
+ schemeFile = "resource/ClientSchemeAlien.res";
+ }
+ }
+
+// BaseClass::ReloadScheme( schemeFile );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Output : vgui::Panel
+//-----------------------------------------------------------------------------
+vgui::Panel *ClientModeTFNormal::GetMinimapParent( void )
+{
+ return GetViewport();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void ClientModeTFNormal::Update()
+{
+ BaseClass::Update();
+ HudCommanderOverlayMgr()->Tick( );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : frametime -
+// *cmd -
+//-----------------------------------------------------------------------------
+void ClientModeTFNormal::CreateMove( float flInputSampleTime, CUserCmd *cmd )
+{
+ // Let the player override the view.
+ C_BaseTFPlayer *pPlayer = C_BaseTFPlayer::GetLocalPlayer();
+ if(!pPlayer)
+ return;
+
+ // Let the player at it
+ pPlayer->CreateMove( flInputSampleTime, cmd );
+
+ // Handle knockdowns
+ if ( pPlayer->CheckKnockdownAngleOverride() )
+ {
+ QAngle ang;
+ pPlayer->GetKnockdownAngles( ang );
+
+ cmd->viewangles = ang;
+ engine->SetViewAngles( ang );
+
+ cmd->forwardmove = cmd->sidemove = cmd->upmove = 0;
+ // Only keep score if it's down
+ cmd->buttons &= ( IN_SCORE );
+ }
+
+ if ( pPlayer->GetPlayerClass() )
+ {
+ C_PlayerClass *pPlayerClass = pPlayer->GetPlayerClass();
+ pPlayerClass->CreateMove( flInputSampleTime, cmd );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Output : Returns true on success, false on failure.
+//-----------------------------------------------------------------------------
+bool ClientModeTFNormal::ShouldDrawViewModel( void )
+{
+ C_BaseTFPlayer *pPlayer = C_BaseTFPlayer::GetLocalPlayer();
+ if(!pPlayer)
+ return false;
+
+ return pPlayer->ShouldDrawViewModel();
+}
+
+
+
+
+
diff --git a/game/client/tf2/clientmode_tfnormal.h b/game/client/tf2/clientmode_tfnormal.h
new file mode 100644
index 0000000..a2b4a34
--- /dev/null
+++ b/game/client/tf2/clientmode_tfnormal.h
@@ -0,0 +1,64 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $Workfile: $
+// $Date: $
+// $NoKeywords: $
+//=============================================================================//
+
+#include <vgui/Cursor.h>
+#include "clientmode_tfbase.h"
+#include <vgui_controls/EditablePanel.h>
+
+namespace vgui
+{
+ class AnimationController;
+}
+
+
+class ClientModeTFNormal : public ClientModeTFBase
+{
+DECLARE_CLASS( ClientModeTFNormal, ClientModeTFBase );
+
+private:
+
+ class Viewport : public CBaseViewport
+ {
+ typedef CBaseViewport BaseClass;
+ // Panel overrides.
+ public:
+ Viewport();
+ virtual ~Viewport() {}
+
+ virtual void OnThink();
+ void ReloadScheme();
+
+ virtual void ApplySchemeSettings( vgui::IScheme *pScheme )
+ {
+ BaseClass::ApplySchemeSettings( pScheme );
+
+ gHUD.InitColors( pScheme );
+
+ SetPaintBackgroundEnabled( false );
+ }
+
+ virtual void CreateDefaultPanels( void ) { /* don't create any panels yet*/ };
+
+ private:
+ bool m_bHumanScheme;
+ };
+
+// IClientMode overrides.
+public:
+
+ virtual void Update();
+ virtual void CreateMove( float flInputSampleTime, CUserCmd *cmd );
+ virtual bool ShouldDrawViewModel( void );
+
+ virtual vgui::Panel *GetMinimapParent( void );
+
+ ClientModeTFNormal();
+};
+
+extern IClientMode *GetClientModeNormal(); \ No newline at end of file
diff --git a/game/client/tf2/commanderoverlay.cpp b/game/client/tf2/commanderoverlay.cpp
new file mode 100644
index 0000000..3dbed6e
--- /dev/null
+++ b/game/client/tf2/commanderoverlay.cpp
@@ -0,0 +1,220 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $Workfile: $
+// $NoKeywords: $
+//=============================================================================//
+#include "cbase.h"
+#include "CommanderOverlay.h"
+#include "utlsymbol.h"
+
+//-----------------------------------------------------------------------------
+// Purpose: Singleton class responsible for managing overlay elements
+//-----------------------------------------------------------------------------
+
+class CHudCommanderOverlayMgrImp : public IHudCommanderOverlayMgr
+{
+public:
+ // constructor, destructor
+ CHudCommanderOverlayMgrImp();
+ virtual ~CHudCommanderOverlayMgrImp();
+
+ // Call this when the game starts up + shuts down
+ virtual void GameInit();
+ virtual void GameShutdown();
+
+ // Call this when the level starts up + shuts down
+ virtual void LevelInit( );
+ virtual void LevelShutdown();
+
+ // add an overlay element to the commander mode
+ virtual OverlayHandle_t AddOverlay( char const* pOverlayName, C_BaseEntity* pEntity, vgui::Panel *pParent );
+
+ // removes a particular overlay
+ virtual void RemoveOverlay( OverlayHandle_t handle );
+
+ // Call this once a frame...
+ virtual void Tick( );
+
+ // Call this when commander mode is enabled or disabled
+ virtual void Enable( bool enable );
+
+private:
+ struct OverlayPanel_t
+ {
+ unsigned short m_Team;
+ CUtlSymbol m_Name;
+ vgui::Panel *m_pPanel;
+ vgui::Panel *m_pParentPanel;
+ EHANDLE m_hEntity;
+ };
+
+ // Create, destroy panels
+ void CreatePanel( int overlay );
+ void DestroyPanel( int overlay );
+
+ // No copy constructor
+ CHudCommanderOverlayMgrImp( const CHudCommanderOverlayMgrImp& );
+
+ // List of actual overlays currently in service
+ // Linked list used so handle ids don't change
+ CUtlLinkedList< OverlayPanel_t, unsigned short > m_Overlays;
+};
+
+
+//-----------------------------------------------------------------------------
+// Returns the singleton commander overlay interface
+//-----------------------------------------------------------------------------
+IHudCommanderOverlayMgr* HudCommanderOverlayMgr()
+{
+ static CHudCommanderOverlayMgrImp s_OverlayImp;
+ return &s_OverlayImp;
+}
+
+
+//-----------------------------------------------------------------------------
+// constructor, destructor
+//-----------------------------------------------------------------------------
+CHudCommanderOverlayMgrImp::CHudCommanderOverlayMgrImp()
+{
+}
+
+CHudCommanderOverlayMgrImp::~CHudCommanderOverlayMgrImp()
+{
+}
+
+
+//-----------------------------------------------------------------------------
+// Call this when the game starts up or shuts down...
+//-----------------------------------------------------------------------------
+#define OVERLAY_FILE "scripts/commander_overlays.txt"
+
+void CHudCommanderOverlayMgrImp::GameInit()
+{
+ // Read in all overlay metaclasses...
+ PanelMetaClassMgr()->LoadMetaClassDefinitionFile( OVERLAY_FILE );
+}
+
+void CHudCommanderOverlayMgrImp::GameShutdown()
+{
+}
+
+
+//-----------------------------------------------------------------------------
+// Call this when the level starts up + shuts down
+//-----------------------------------------------------------------------------
+void CHudCommanderOverlayMgrImp::LevelInit( )
+{
+}
+
+
+void CHudCommanderOverlayMgrImp::LevelShutdown()
+{
+ // Remove all panels....
+ for( unsigned short i = m_Overlays.Head(); i != m_Overlays.InvalidIndex(); i = m_Overlays.Next(i) )
+ {
+ DestroyPanel(i);
+ }
+ m_Overlays.RemoveAll();
+}
+
+
+//-----------------------------------------------------------------------------
+// Create, destroy panel...
+//-----------------------------------------------------------------------------
+void CHudCommanderOverlayMgrImp::CreatePanel( int overlay )
+{
+ Assert( m_Overlays.IsValidIndex(overlay) );
+ OverlayPanel_t& panel = m_Overlays[overlay];
+
+ // Chain keyvalues with name Team#
+ char pTeamName[6] = "Team ";
+ pTeamName[4] = '0' + panel.m_Team;
+
+ vgui::Panel *pPanel = PanelMetaClassMgr()->CreatePanelMetaClass(
+ panel.m_Name.String(), 0, panel.m_hEntity.Get(), panel.m_pParentPanel, pTeamName );
+ m_Overlays[overlay].m_pPanel = pPanel;
+}
+
+void CHudCommanderOverlayMgrImp::DestroyPanel( int overlay )
+{
+ Assert( m_Overlays.IsValidIndex(overlay) );
+ OverlayPanel_t& panel = m_Overlays[overlay];
+ if (panel.m_pPanel)
+ {
+ PanelMetaClassMgr()->DestroyPanelMetaClass( panel.m_pPanel );
+ m_Overlays[overlay].m_pPanel = NULL;
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// add an overlay element to the commander mode
+//-----------------------------------------------------------------------------
+OverlayHandle_t CHudCommanderOverlayMgrImp::AddOverlay(
+ char const* pOverlayInstance, C_BaseEntity* pEntity, vgui::Panel *pParent )
+{
+ OverlayPanel_t newPanel;
+ newPanel.m_Name = pOverlayInstance;
+ newPanel.m_pPanel = NULL;
+ newPanel.m_Team = (unsigned short)~0;
+ newPanel.m_hEntity = pEntity;
+ newPanel.m_pParentPanel = pParent;
+ return m_Overlays.AddToTail( newPanel );
+}
+
+
+//-----------------------------------------------------------------------------
+// removes a particular overlay
+//-----------------------------------------------------------------------------
+void CHudCommanderOverlayMgrImp::RemoveOverlay( OverlayHandle_t handle )
+{
+ if ((handle == OVERLAY_HANDLE_INVALID) || (!m_Overlays.IsValidIndex(handle)) )
+ return;
+
+ // Deallocate the panel
+ DestroyPanel( handle );
+
+ // Remove it from our list
+ m_Overlays.Remove( handle );
+}
+
+
+//-----------------------------------------------------------------------------
+// make our sprites visible when we are enabled
+//-----------------------------------------------------------------------------
+void CHudCommanderOverlayMgrImp::Enable( bool enable )
+{
+}
+
+
+//-----------------------------------------------------------------------------
+// Call this once a frame...
+//-----------------------------------------------------------------------------
+void CHudCommanderOverlayMgrImp::Tick( )
+{
+ if ( !engine->IsInGame() )
+ return;
+
+ // Iterate through all overlays
+ for( unsigned short i = m_Overlays.Head(); i != m_Overlays.InvalidIndex(); i = m_Overlays.Next(i) )
+ {
+ // Kill panels attached to dead entities...
+ if (!m_Overlays[i].m_hEntity)
+ {
+ DestroyPanel( i );
+ continue;
+ }
+
+ // make sure the panels are up-to-date based on current entity team
+ if (m_Overlays[i].m_Team != m_Overlays[i].m_hEntity->GetTeamNumber())
+ {
+ // Destroy the old team panel, create the new team panel
+ DestroyPanel( i );
+ m_Overlays[i].m_Team = m_Overlays[i].m_hEntity->GetTeamNumber();
+ CreatePanel( i );
+ }
+ }
+}
+
diff --git a/game/client/tf2/commanderoverlay.h b/game/client/tf2/commanderoverlay.h
new file mode 100644
index 0000000..c477c8c
--- /dev/null
+++ b/game/client/tf2/commanderoverlay.h
@@ -0,0 +1,153 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $Workfile: $
+// $NoKeywords: $
+//=============================================================================//
+
+#if !defined( COMMANDEROVERLAY_H )
+#define COMMANDEROVERLAY_H
+
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "panelmetaclassmgr.h"
+
+
+//-----------------------------------------------------------------------------
+// forward declarations
+//-----------------------------------------------------------------------------
+class C_BaseEntity;
+class KeyValues;
+
+
+//-----------------------------------------------------------------------------
+// Overlay handle
+//-----------------------------------------------------------------------------
+
+typedef unsigned short OverlayHandle_t;
+enum
+{
+ OVERLAY_HANDLE_INVALID = (OverlayHandle_t)~0
+};
+
+//-----------------------------------------------------------------------------
+// Purpose: Singleton class responsible for managing overlay elements
+//-----------------------------------------------------------------------------
+class IHudCommanderOverlayMgr
+{
+public:
+// // Call this when the game starts up + shuts down
+ virtual void GameInit() = 0;
+ virtual void GameShutdown() = 0;
+
+ // Call this when the level starts up + shuts down
+ virtual void LevelInit( ) = 0;
+ virtual void LevelShutdown() = 0;
+
+ // add an overlay element to the commander mode, returns a handle to it
+ virtual OverlayHandle_t AddOverlay( char const* pOverlayName, C_BaseEntity* pEntity, vgui::Panel *pParent = NULL ) = 0;
+
+ // removes a particular overlay
+ virtual void RemoveOverlay( OverlayHandle_t handle ) = 0;
+
+ // Call this once a frame...
+ virtual void Tick( ) = 0;
+
+ // Call this when commander mode is enabled or disabled
+ virtual void Enable( bool enable ) = 0;
+
+protected:
+ // Don't delete me!
+ virtual ~IHudCommanderOverlayMgr() {}
+};
+
+
+//-----------------------------------------------------------------------------
+// Returns the singleton commander overlay interface
+//-----------------------------------------------------------------------------
+IHudCommanderOverlayMgr* HudCommanderOverlayMgr();
+
+
+//-----------------------------------------------------------------------------
+// Helper class for entities to join the list of entities to render on screen
+//-----------------------------------------------------------------------------
+class CPanelRegistration
+{
+public:
+ CPanelRegistration( ) : m_Overlay(OVERLAY_HANDLE_INVALID) {}
+
+ ~CPanelRegistration()
+ {
+ HudCommanderOverlayMgr()->RemoveOverlay( m_Overlay );
+ }
+
+ void Activate( C_BaseEntity* pEntity, char const* pOverlayName, bool active )
+ {
+ if( active )
+ {
+ AddOverlay( pEntity, pOverlayName );
+ }
+ else
+ {
+ RemoveOverlay();
+ }
+ }
+
+ void Activate( C_BaseEntity* pEntity, char const* pOverlayName, vgui::Panel *pParent, int sortOrder, bool active )
+ {
+ if( active )
+ {
+ AddOverlay( pEntity, pOverlayName, pParent );
+ }
+ else
+ {
+ RemoveOverlay();
+ }
+ }
+
+
+ void AddOverlay( C_BaseEntity *pEntity, const char *pOverlayName, vgui::Panel *pParent = NULL )
+ {
+ RemoveOverlay();
+ m_Overlay = HudCommanderOverlayMgr()->AddOverlay( pOverlayName, pEntity, pParent );
+ }
+
+ void RemoveOverlay()
+ {
+ if( m_Overlay != OVERLAY_HANDLE_INVALID )
+ {
+ HudCommanderOverlayMgr()->RemoveOverlay( m_Overlay );
+ m_Overlay = OVERLAY_HANDLE_INVALID;
+ }
+ }
+
+
+private:
+ OverlayHandle_t m_Overlay;
+};
+
+
+//-----------------------------------------------------------------------------
+// Macros for help with simple registration of panels
+// Put DECLARE_ENTITY_PANEL() in your class definition
+// and ENTITY_PANEL_ACTIVATE( "name" ) in the entity's SetDormant call
+//-----------------------------------------------------------------------------
+#define DECLARE_ENTITY_PANEL() CPanelRegistration m_OverlayPanel
+#define ENTITY_PANEL_ACTIVATE( _pOverlayName, _active ) m_OverlayPanel.Activate( this, _pOverlayName, _active )
+
+
+//-----------------------------------------------------------------------------
+// Helper macro to make overlay factories one line of code. Use like this:
+// DECLARE_OVERLAY_FACTORY( CEntityImagePanel, "image" );
+//-----------------------------------------------------------------------------
+#define DECLARE_OVERLAY_FACTORY( _PanelClass, _nameString ) \
+ DECLARE_PANEL_FACTORY( _PanelClass, C_BaseEntity, _nameString )
+
+#define DECLARE_OVERLAY_POINT_FACTORY( _PanelClass, _nameString ) \
+ DECLARE_PANEL_FACTORY( _PanelClass, void, _nameString )
+
+
+#endif // COMMANDEROVERLAY_H \ No newline at end of file
diff --git a/game/client/tf2/commanderoverlaypanel.cpp b/game/client/tf2/commanderoverlaypanel.cpp
new file mode 100644
index 0000000..5ef2914
--- /dev/null
+++ b/game/client/tf2/commanderoverlaypanel.cpp
@@ -0,0 +1,1018 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+//=============================================================================//
+
+//-----------------------------------------------------------------------------
+// The panel responsible for rendering the 3D view in orthographic mode
+//-----------------------------------------------------------------------------
+#include "cbase.h"
+#include <vgui/VGUI.h>
+#include <vgui_controls/Controls.h>
+#include <vgui/IVGui.h>
+#include <vgui/IInput.h>
+#include <vgui/ISurface.h>
+#include "clientmode_commander.h"
+#include "vgui_int.h"
+#include "iinput.h"
+#include "kbutton.h"
+#include "hud_minimap.h"
+#include "usercmd.h"
+#include "mapdata.h"
+#include "c_basetfplayer.h"
+#include "view.h"
+#include "view_shared.h"
+#include "CommanderOverlay.h"
+#include "C_TfTeam.h"
+#include <vgui/MouseCode.h>
+#include <vgui/KeyCode.h>
+#include <vgui/IPanel.h>
+#include "commanderoverlaypanel.h"
+#include "PixelWriter.h"
+#include "materialsystem/imaterialvar.h"
+#include "materialsystem/itexture.h"
+#include "vtf/vtf.h"
+#include "engine/ivdebugoverlay.h"
+
+
+static inline int AlphaMapIndex(int x, int y)
+{
+ return y * FOG_ALPHAMAP_SIZE + x;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *commander -
+//-----------------------------------------------------------------------------
+void CCommanderOverlayPanel::SetCommanderView( CClientModeCommander *commander )
+{
+ m_pCommanderView = commander;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+CCommanderOverlayPanel::CCommanderOverlayPanel( void ) :
+ vgui::Panel( NULL, "CommanderOverlayPanel" ),
+ m_CursorCommander(vgui::dc_arrow),
+ m_CursorRightMouseMove(vgui::dc_hand)
+{
+ MakePopup();
+
+ SetPaintBackgroundEnabled( false );
+ m_left.m_bMouseDown = false;
+ m_left.m_nXStart = 0;
+ m_left.m_nYStart = 0;
+
+ m_right.m_bMouseDown = false;
+ m_right.m_nXStart = 0;
+ m_right.m_nYStart = 0;
+
+ m_fZoom = 0;
+
+ m_flPreviousMaxWorldWidth = 0.0f;
+ SetVisible( false );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+CCommanderOverlayPanel::~CCommanderOverlayPanel( void )
+{
+}
+
+
+//-----------------------------------------------------------------------------
+// Initialize rendering origin
+//-----------------------------------------------------------------------------
+void CCommanderOverlayPanel::InitializeRenderOrigin()
+{
+ // Initializes the rendering origin
+ C_BasePlayer *player = C_BasePlayer::GetLocalPlayer();
+ if ( player )
+ {
+ m_vecTacticalOrigin = player->GetAbsOrigin();
+ }
+ else
+ {
+ MapData().GetMapOrigin( m_vecTacticalOrigin );
+ }
+
+ Vector mins, maxs;
+ MapData().GetMapBounds( mins, maxs );
+ m_vecTacticalOrigin.z = maxs.z + TACTICAL_ZOFFSET;
+ m_vecTacticalAngles.Init( 90, 90, 0 );
+ BoundOrigin( m_vecTacticalOrigin );
+}
+
+
+//-----------------------------------------------------------------------------
+// Computes the view range:
+//-----------------------------------------------------------------------------
+void CCommanderOverlayPanel::ComputeZoomRange()
+{
+ // This is
+ m_MinWorldWidth = TACTICAL_MIN_VIEWABLE_SIZE;
+
+ // Get the world size
+ Vector mins, maxs, size;
+ MapData().GetMapBounds( mins, maxs );
+ VectorSubtract( maxs, mins, size );
+ float worldAspect = size[0] / size[1];
+
+// size[ 0 ] *= 1.05f;
+// size[ 1 ] *= 1.05f;
+
+ // Find out the panel aspect ratio
+ int w, h;
+ GetVisibleSize( w, h );
+
+ float panelAspect = (float)w / (float)h;
+
+ // Store off old zoom
+ m_flPreviousMaxWorldWidth = m_MaxWorldWidth;
+
+ if (panelAspect > worldAspect)
+ {
+ // In this case, to see the whole map,
+ // we'll have black areas on the left + right sides
+ // Make sure we choose a width big enough to display the entire height
+ m_MaxWorldWidth = size[1] * panelAspect;
+ }
+ else
+ {
+ // In this case, to see the whole map,
+ // we'll have black areas on the top + bottom
+ // Make sure we choose a width big enough to display the entire height
+ m_MaxWorldWidth = size[0];
+ }
+
+ // if flipping open/close the tech tree, preserver relative zoom amount
+ if ( m_flPreviousMaxWorldWidth )
+ {
+ float ratio = m_MaxWorldWidth / m_flPreviousMaxWorldWidth;
+
+ m_fZoom *= ratio;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Call when the map changes
+//-----------------------------------------------------------------------------
+
+void CCommanderOverlayPanel::LevelInit( char const* pMapName )
+{
+ // Always look at the entire map to start with
+ m_fZoom = 0;
+ m_flPreviousMaxWorldWidth = 0.0f;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CCommanderOverlayPanel::LevelShutdown( void )
+{
+}
+
+//-----------------------------------------------------------------------------
+// call these when commander view is enabled/disabled
+//-----------------------------------------------------------------------------
+void CCommanderOverlayPanel::Enable()
+{
+ vgui::VPANEL pRoot = VGui_GetClientDLLRootPanel();
+
+ SetCursor(m_CursorCommander);
+ SetVisible( true );
+
+ // Make the viewport fill the root panel.
+ if( pRoot)
+ {
+ int wide, tall;
+ vgui::ipanel()->GetSize(pRoot, wide, tall);
+
+ // subtract out the technology UI size
+ tall -= 0;// xxx200
+
+ SetBounds(0, 0, wide, tall);
+ }
+
+ // Cache the orthographic view size range
+ ComputeZoomRange();
+
+ // Start out looking at the whole world
+ if (m_fZoom == 0)
+ m_fZoom = m_MaxWorldWidth;
+
+ // clamp
+ if (m_fZoom < m_MinWorldWidth)
+ m_fZoom = m_MinWorldWidth;
+ else if (m_fZoom > m_MaxWorldWidth)
+ m_fZoom = m_MaxWorldWidth;
+
+ // Figure out where the camera is
+ InitializeRenderOrigin();
+
+ vgui::ivgui()->AddTickSignal( GetVPanel() );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CCommanderOverlayPanel::Disable()
+{
+ SetVisible( false );
+ // FIXME: Need a removeTickSignal!
+// vgui::ivgui()->removeTickSignal( GetVPanel() );
+}
+
+
+//-----------------------------------------------------------------------------
+// called when we're ticked...
+//-----------------------------------------------------------------------------
+void CCommanderOverlayPanel::OnTick()
+{
+ if (!IsLocalPlayerInTactical() || !engine->IsInGame())
+ return;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Returns up to 32 players encoded as a bit per player in a 32 bit unsigned
+// Output : unsigned int
+//-----------------------------------------------------------------------------
+void CCommanderOverlayPanel::GetSelectedPlayerBitField( CBitVec< MAX_PLAYERS >& bits )
+{
+ CMapPlayers *pPlayer;
+
+ bits.ClearAll();
+
+ // draw all the visible players
+ for ( int playerNum = 0; playerNum < MAX_PLAYERS; playerNum++ )
+ {
+ pPlayer = &MapData().m_Players[ playerNum ];
+ if ( pPlayer->m_bSelected )
+ {
+ bits.Set( playerNum );
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Counts how many players are selected
+// Output : int
+//-----------------------------------------------------------------------------
+int CCommanderOverlayPanel::CountSelectedPlayers( void )
+{
+ CMapPlayers *pPlayer;
+
+ // bitfield variable
+ int count = 0;
+
+ // draw all the visible players
+ for ( int playerNum = 0; playerNum < MAX_PLAYERS; playerNum++ )
+ {
+ pPlayer = &MapData().m_Players[ playerNum ];
+ if ( pPlayer->m_bSelected )
+ {
+ count++;
+ }
+ }
+
+ return count;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Called when a key is pressed
+//-----------------------------------------------------------------------------
+void CCommanderOverlayPanel::OnKeyPressed(vgui::KeyCode code)
+{
+ switch(code)
+ {
+ case vgui::KEY_SPACE:
+ if (m_fZoom != m_MaxWorldWidth)
+ {
+ ChangeZoomLevel(m_MaxWorldWidth);
+ }
+ else
+ {
+ Vector mouseWorldPos;
+ CenterOnMouse( mouseWorldPos );
+
+ ChangeZoomLevel(TACTICAL_SPACEBAR_VIEWABLE_SIZE);
+
+ // Place mouse over me
+ m_pCommanderView->MoveMouse( mouseWorldPos );
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: when space is hit, show the entire view
+//-----------------------------------------------------------------------------
+void CCommanderOverlayPanel::ChangeZoomLevel( float newZoom )
+{
+ // Make sure the mouse remains over the thing it started over
+
+ // Figure out worldspace movement based on picking ray
+ Vector rayOrigin, rayForward;
+
+ int mx, my;
+ GetMousePos( mx, my );
+
+ // Need to convert from screen space back to a worldspace ray
+ CreatePickingRay(
+ mx, my,
+ ScreenWidth(), ScreenHeight(),
+ CurrentViewOrigin(),
+ CurrentViewAngles(),
+ rayOrigin,
+ rayForward );
+
+ m_fZoom = newZoom;
+
+ BoundOrigin( m_vecTacticalOrigin );
+
+ // move mouse to center and zero out any delta
+ m_pCommanderView->MoveMouse( rayOrigin );
+// RequestFocus();
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Output : Returns true on success, false on failure.
+//-----------------------------------------------------------------------------
+bool CCommanderOverlayPanel::IsRightMouseMapMoving( void )
+{
+ return m_right.m_bMouseDown;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CCommanderOverlayPanel::RightMouseMapMove( void )
+{
+ /*
+ // Figure out worldspace movement based on picking ray
+ Vector rayForward;
+ Vector vecEndPosCurrent, vecEndPosPrevious;
+
+ // Need to convert from screen space back to a worldspace ray
+ CreatePickingRay(
+ m_right.m_nXCurrent, m_right.m_nYCurrent,
+ ScreenWidth(), ScreenHeight(),
+ g_vecRenderOrigin,
+ g_vecRenderAngles,
+ vecEndPosCurrent,
+ rayForward );
+
+ engine->Con_NPrintf( 8, "x %i y %i hit %.3f %.3f",
+ m_right.m_nXCurrent, m_right.m_nYCurrent, vecEndPosCurrent.x, vecEndPosCurrent.y );
+ */
+
+ if ( !m_right.m_bMouseDown )
+ return;
+
+ /*
+ // See if there is a delta in the current and previous mouse positions
+ //
+ int dx, dy;
+
+ dx = m_right.m_nXCurrent - m_right.m_nXPrev;
+ dy = m_right.m_nYCurrent - m_right.m_nYPrev;
+
+ // No relative move
+ if ( !dx && !dy )
+ return;
+
+ // Figure out worldspace movement based on picking ray
+ Vector rayForward;
+ Vector vecEndPosCurrent, vecEndPosPrevious;
+
+ // Need to convert from screen space back to a worldspace ray
+ CreatePickingRay(
+ m_right.m_nXCurrent, m_right.m_nYCurrent,
+ ScreenWidth(), ScreenHeight(),
+ g_vecRenderOrigin,
+ g_vecRenderAngles,
+ vecEndPosCurrent,
+ rayForward );
+
+ // Now create ray from old position
+ // Need to convert from screen space back to a worldspace ray
+ CreatePickingRay(
+ m_right.m_nXPrev, m_right.m_nYPrev,
+ ScreenWidth(), ScreenHeight(),
+ g_vecRenderOrigin,
+ g_vecRenderAngles,
+ vecEndPosPrevious,
+ rayForward );
+
+ // Remove z component
+ vecEndPosPrevious.z = 0.0;
+ vecEndPosCurrent.z = 0.0;
+
+ // Compute offset
+ Vector viewDelta;
+ VectorSubtract( vecEndPosCurrent, vecEndPosPrevious, viewDelta );
+
+ viewDelta.z = 0.0f;
+
+ VectorAdd( m_vecTacticalOrigin, viewDelta, m_vecTacticalOrigin );
+
+ m_pCommanderView->BoundOrigin( m_vecTacticalOrigin );
+ */
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Right mouse button down
+//-----------------------------------------------------------------------------
+void CCommanderOverlayPanel::RightMousePressed( void )
+{
+ if ( m_left.m_bMouseDown || m_right.m_bMouseDown )
+ return;
+
+ SetCursor(m_CursorRightMouseMove);
+
+ StartMovingMouse( m_right );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CCommanderOverlayPanel::RightMouseReleased( void )
+{
+ if ( !m_right.m_bMouseDown )
+ return;
+
+ m_right.m_bMouseDown = false;
+ int mx, my;
+ GetMousePos( mx, my );
+ UpdateMousePos( mx, my, m_right );
+
+ // Final move
+ RightMouseMapMove();
+
+ vgui::input()->SetMouseCapture( NULL );
+
+ SetCursor(m_CursorCommander);
+
+ // If the player's dead, and doesn't have the special sniper upgrade
+ // then check for respawn stations....
+ C_BaseTFPlayer *pPlayer = C_BaseTFPlayer::GetLocalPlayer();
+ if (!pPlayer)
+ return;
+
+ // If the player's dead, abort
+ if ( pPlayer->PlayerClass() == TFCLASS_SNIPER )
+ {
+ // Sniper's can request a respawn point when dead
+ //
+ Vector rayOrigin, rayForward;
+ Vector vecEndPos;
+
+ // Need to convert from screen space back to a worldspace ray
+ CreatePickingRay(
+ m_right.m_nXCurrent, m_right.m_nYCurrent,
+ ScreenWidth(), ScreenHeight(),
+ CurrentViewOrigin(),
+ CurrentViewAngles(),
+ rayOrigin,
+ rayForward );
+
+ // Now do the trace
+ trace_t tr;
+
+ vecEndPos = rayOrigin + rayForward * MAX_TRACE_LENGTH;
+
+ UTIL_TraceLine( rayOrigin, vecEndPos, MASK_SOLID_BRUSHONLY, NULL, COLLISION_GROUP_NONE, &tr );
+
+ // Didn't hit anything
+ if ( tr.fraction == 1.0 )
+ return;
+
+ char cmd[ 128 ];
+ Q_snprintf( cmd, sizeof( cmd ), "respawnpoint %i %i %i\n",
+ (int)tr.endpos.x,
+ (int)tr.endpos.y,
+ (int)tr.endpos.z );
+
+ engine->ServerCmd( cmd );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : x -
+// y -
+// mouse -
+//-----------------------------------------------------------------------------
+void CCommanderOverlayPanel::UpdateMousePos( int x, int y, MouseDown_t& mouse )
+{
+ // store previous
+ mouse.m_nXPrev = mouse.m_nXCurrent;
+ mouse.m_nYPrev = mouse.m_nYCurrent;
+ // update current
+ mouse.m_nXCurrent = x;
+ mouse.m_nYCurrent = y;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : x -
+// y -
+//-----------------------------------------------------------------------------
+void CCommanderOverlayPanel::OnCursorMoved(int x, int y)
+{
+ UpdateMousePos( x, y, m_left );
+ UpdateMousePos( x, y, m_right );
+
+ RightMouseMapMove();
+// RequestFocus();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : x -
+// y -
+//-----------------------------------------------------------------------------
+void CCommanderOverlayPanel::GetMousePos( int& x, int& y )
+{
+ vgui::input()->GetCursorPos( x, y );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : mouse -
+//-----------------------------------------------------------------------------
+void CCommanderOverlayPanel::StartMovingMouse( MouseDown_t& mouse )
+{
+ mouse.m_bMouseDown = true;
+ GetMousePos( mouse.m_nXStart, mouse.m_nYStart );
+
+ mouse.m_nXCurrent = mouse.m_nXPrev = mouse.m_nXStart;
+ mouse.m_nYCurrent = mouse.m_nYPrev = mouse.m_nYStart;
+
+ vgui::input()->SetMouseCapture( GetVPanel() );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Left mouse button down
+//-----------------------------------------------------------------------------
+void CCommanderOverlayPanel::LeftMousePressed( void )
+{
+ if ( m_left.m_bMouseDown || m_right.m_bMouseDown )
+ return;
+
+ StartMovingMouse( m_left );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : code -
+//-----------------------------------------------------------------------------
+void CCommanderOverlayPanel::OnMousePressed(vgui::MouseCode code)
+{
+ switch ( code )
+ {
+ case vgui::MOUSE_LEFT:
+ LeftMousePressed();
+ break;
+ case vgui::MOUSE_RIGHT:
+ RightMousePressed();
+ break;
+ default:
+ BaseClass::OnMousePressed( code );
+ return;
+ }
+
+// RequestFocus();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : x0 -
+// y0 -
+// x1 -
+// y1 -
+// true -
+//-----------------------------------------------------------------------------
+void CCommanderOverlayPanel::SelectPlayersInRectangle( int x0, int y0, int x1, int y1, bool clearOldSelections /*= true*/ )
+{
+ int num_selected = 0;
+
+ // Assume zero players in selection
+ if ( clearOldSelections )
+ {
+ m_bHaveActiveSelection = false;
+ }
+ else
+ {
+ // Count # selected
+ num_selected = CountSelectedPlayers();
+ }
+
+ CMapPlayers *pPlayer;
+ C_BaseTFPlayer *tf2player;
+
+ // See which players on my team are within the rectangle in screen space
+ //
+ for ( int playerNum = 1; playerNum <= MAX_PLAYERS; playerNum++ )
+ {
+ pPlayer = &MapData().m_Players[ playerNum - 1 ];
+
+ if ( clearOldSelections )
+ {
+ pPlayer->m_bSelected = false;
+ }
+
+ if ( playerNum > gpGlobals->maxClients )
+ {
+ continue;
+ }
+
+ tf2player = dynamic_cast<C_BaseTFPlayer *>( cl_entitylist->GetEnt( playerNum ) );
+ if ( !tf2player )
+ {
+ continue;
+ }
+
+ // Check pvs on this guy
+ // If the entity was in the commander's PVS then show it on the minimap, too
+ //
+ if ( ArePlayersOnSameTeam( engine->GetLocalPlayer(), playerNum ) == false )
+ {
+ continue;
+ }
+
+ // Check their actual draw position
+ int drawX, drawY;
+ Vector pos, screen;
+
+ pos = tf2player->GetAbsOrigin();
+
+ // Transform
+ debugoverlay->ScreenPosition( pos, screen );
+
+ // FIXME: Get the player icon size from where?!?
+ drawX = screen.x - 32;
+ drawY = screen.y - 40;
+ int intersectX = 64;
+ int intersectY = 64;
+
+ // Check for intersection ( with slop )
+ if ( drawX + intersectX < x0 )
+ continue;
+ if ( drawX > x1 )
+ continue;
+ if ( drawY + intersectY < y0 )
+ continue;
+ if ( drawY > y1 )
+ continue;
+
+ // Already selected?
+ if ( !pPlayer->m_bSelected )
+ {
+ // Add to selected list
+ pPlayer->m_bSelected = true;
+ num_selected++;
+ }
+ }
+
+ if ( num_selected != 0 )
+ {
+ m_bHaveActiveSelection = true;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Returns the visible area (not including the tech tree)
+//-----------------------------------------------------------------------------
+void CCommanderOverlayPanel::GetVisibleSize( int& w, int& h )
+{
+ GetSize( w, h );
+
+ // FIXME: Hack to make the map appear above the tech tree
+ h -= 200;
+}
+
+//-----------------------------------------------------------------------------
+// Returns the visible area (not including the tech tree)
+//-----------------------------------------------------------------------------
+void CCommanderOverlayPanel::GetVisibleArea( Vector& mins, Vector& maxs )
+{
+ float w, h;
+ GetVisibleOrthoSize( w, h );
+
+ ActualToVisibleOffset( mins );
+ mins += m_vecTacticalOrigin;
+ maxs = mins;
+ mins.x -= w; maxs.x +=w;
+ mins.y -= h; maxs.y +=h;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: User let go of left mouse button
+//-----------------------------------------------------------------------------
+void CCommanderOverlayPanel::LeftMouseReleased( void )
+{
+ if ( !m_left.m_bMouseDown )
+ return;
+
+ m_left.m_bMouseDown = false;
+
+ int mx, my;
+ GetMousePos( mx, my );
+ UpdateMousePos( mx, my, m_left );
+
+ vgui::input()->SetMouseCapture( NULL );
+
+ // Normalize the rectangle
+ int x0, y0, x1, y1;
+ x0 = MIN( m_left.m_nXStart, m_left.m_nXCurrent );
+ x1 = MAX( m_left.m_nXStart, m_left.m_nXCurrent );
+ y0 = MIN( m_left.m_nYStart, m_left.m_nYCurrent );
+ y1 = MAX( m_left.m_nYStart, m_left.m_nYCurrent );
+
+ bool clearOldStates = true;
+ if ( vgui::input()->IsKeyDown( vgui::KEY_LCONTROL ) )
+ {
+ clearOldStates = false;
+ }
+
+ SelectPlayersInRectangle( x0, y0, x1, y1, clearOldStates );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CCommanderOverlayPanel::GetOrthoRenderBox(Vector &vCenter, float &xSize, float &ySize)
+{
+ vCenter = m_vecTacticalOrigin;
+
+ // min and max depends on the current zoom level
+ int w, h;
+ GetParent()->GetSize( w, h );
+
+ xSize = m_fZoom;
+ ySize = xSize * ( (float)h / (float)w );
+
+ xSize *= 0.5f;
+ ySize *= 0.5f;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CCommanderOverlayPanel::GetVisibleOrthoSize(float &xSize, float &ySize)
+{
+ // min and max depends on the current zoom level
+ int w, h;
+ GetVisibleSize( w, h );
+ xSize = m_fZoom;
+ ySize = xSize * ( (float)h / (float)w );
+
+ xSize *= 0.5f;
+ ySize *= 0.5f;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+float CCommanderOverlayPanel::WorldUnitsPerPixel()
+{
+ int w, h;
+ GetParent()->GetSize( w, h );
+ return m_fZoom / w;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CCommanderOverlayPanel::ActualToVisibleOffset( Vector& offset )
+{
+ // FIXME: This doesn't work arbitrarily; we assume the visible
+ // part is on the top of the screen..
+ int w, h, wact, hact;
+ GetVisibleSize( w, h );
+ GetParent()->GetSize( wact, hact );
+
+ float worldUnitsPerPixel = m_fZoom / wact;
+ float dWorldY = (hact - h) * 0.5f * worldUnitsPerPixel;
+ offset.Init( 0, dWorldY, 0 );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Make sure origin is inside map x, y bounds ( not z )
+//-----------------------------------------------------------------------------
+void CCommanderOverlayPanel::BoundOrigin( Vector& camera )
+{
+ // We're going to do this entire computation assuming the camera
+ // is in the center of the viewable area, which it isn't. At the
+ // end, we'll need to apply a fixup to deal with that
+
+ Vector mins, maxs, halfsize;
+ MapData().GetMapBounds( mins, maxs );
+ VectorSubtract( maxs, mins, halfsize );
+ halfsize *= 0.5f;
+
+ // avoid black edges...
+ float dim[2];
+ GetVisibleOrthoSize( dim[0], dim[1] );
+
+ // Compute the position of the center of the visible area based on
+ // the new suggested camera position
+ Vector actualToVisible, newVisCenter;
+ ActualToVisibleOffset( actualToVisible );
+ VectorAdd( camera, actualToVisible, newVisCenter );
+
+ // Only bound x & y
+ for ( int i = 0; i < 2; i++ )
+ {
+ if (dim[i] > halfsize[i])
+ {
+ newVisCenter[i] = mins[i] + halfsize[i];
+ }
+ else
+ {
+ newVisCenter[ i ] = MAX( newVisCenter[i], mins[i] + dim[i] );
+ newVisCenter[ i ] = MIN( newVisCenter[i], maxs[i] - dim[i] );
+ }
+ }
+
+ // Remember: The viewport takes up the entire screen; but the visible
+ // area only takes up the top half of the screen. Therefore, we need to
+ // set the origin so that the center of what we want lies at the
+ // center of the visible region
+ VectorSubtract( newVisCenter, actualToVisible, camera );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Given mouse/screen positions as well as the current
+// render origin and angles, returns a unit vector through the mouse position
+// that can be used to trace into the world under the mouse click pixel.
+// Input : fov -
+// mousex -
+// mousey -
+// screenwidth -
+// screenheight -
+// vecRenderAngles -
+// c_x -
+// vpn -
+// vup -
+// 360.0 -
+//-----------------------------------------------------------------------------
+void CCommanderOverlayPanel::CreatePickingRay( int mousex, int mousey,
+ int screenwidth, int screenheight,
+ const Vector& vecRenderOrigin,
+ const QAngle& vecRenderAngles,
+ Vector &rayOrigin,
+ Vector &rayDirection
+ )
+{
+ Vector vCenter;
+ float xSize, ySize;
+ GetOrthoRenderBox(vCenter, xSize, ySize);
+
+ float xPos = RemapVal(mousex, 0, screenwidth, vCenter.x-xSize, vCenter.x+xSize);
+ float yPos = RemapVal(mousey, 0, screenheight, vCenter.y+ySize, vCenter.y-ySize); // (flip screen y)
+ rayOrigin.Init(xPos, yPos, vCenter.z);
+ rayDirection.Init(0, 0, -1);
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CCommanderOverlayPanel::OnMouseReleased(vgui::MouseCode code)
+{
+ switch ( code )
+ {
+ case vgui::MOUSE_LEFT:
+ LeftMouseReleased();
+ break;
+ case vgui::MOUSE_RIGHT:
+ RightMouseReleased();
+ break;
+ default:
+ BaseClass::OnMouseReleased( code );
+ return;
+ }
+
+// RequestFocus();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CCommanderOverlayPanel::CenterOnMouse( Vector& mouseWorldPos )
+{
+ // Figure out worldspace movement based on picking ray
+ Vector rayForward;
+ Vector centerOrigin;
+
+ int mx, my;
+ GetMousePos( mx, my );
+
+ // Need to convert from screen space back to a worldspace ray
+ CreatePickingRay(
+ mx, my,
+ ScreenWidth(), ScreenHeight(),
+ CurrentViewOrigin(),
+ CurrentViewAngles(),
+ mouseWorldPos,
+ rayForward );
+
+ CreatePickingRay(
+ ScreenWidth()/2, ScreenHeight()/2,
+ ScreenWidth(), ScreenHeight(),
+ CurrentViewOrigin(),
+ CurrentViewAngles(),
+ centerOrigin,
+ rayForward );
+
+ Vector offset;
+ VectorSubtract( mouseWorldPos, centerOrigin, offset );
+ offset.z = 0.0f;
+ VectorAdd( m_vecTacticalOrigin, offset, m_vecTacticalOrigin );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : delta -
+//-----------------------------------------------------------------------------
+void CCommanderOverlayPanel::OnMouseWheeled(int delta)
+{
+ // Figure out worldspace movement based on picking ray
+ Vector rayOrigin;
+
+ CenterOnMouse( rayOrigin );
+
+ // Gotta do the zoom after picking the ray, or it'll use the wrong zoom factor
+ // for computing the picking ray
+ if ( delta < 0 )
+ {
+ m_fZoom *= 1.25f;
+ }
+ else if ( delta > 0 )
+ {
+ m_fZoom /= 1.25f;
+ }
+
+ m_fZoom = MIN( m_fZoom, m_MaxWorldWidth );
+ m_fZoom = MAX( m_fZoom, m_MinWorldWidth );
+
+ BoundOrigin( m_vecTacticalOrigin );
+
+ // move mouse to center and zero out any delta
+ m_pCommanderView->MoveMouse( rayOrigin );
+
+// RequestFocus();
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CCommanderOverlayPanel::Paint()
+{
+ if ( !m_left.m_bMouseDown )
+ return;
+
+ // Update mouse position, so we don't get the 1 frame lag
+ int mx, my;
+ GetMousePos( mx, my );
+ UpdateMousePos( mx, my, m_left );
+
+ int x0, x1, y0, y1;
+ // Make sure it's normalized
+ x0 = MIN( m_left.m_nXStart, m_left.m_nXCurrent );
+ x1 = MAX( m_left.m_nXStart, m_left.m_nXCurrent );
+ y0 = MIN( m_left.m_nYStart, m_left.m_nYCurrent );
+ y1 = MAX( m_left.m_nYStart, m_left.m_nYCurrent );
+
+ // Draw selection rectangle
+ vgui::surface()->DrawSetColor( 200, 220, 250, 192 );
+ vgui::surface()->DrawOutlinedRect( x0, y0, x1, y1 );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+float CCommanderOverlayPanel::GetZoom( void )
+{
+ return (m_fZoom - m_MinWorldWidth) / (m_MaxWorldWidth - m_MinWorldWidth);
+}
diff --git a/game/client/tf2/commanderoverlaypanel.h b/game/client/tf2/commanderoverlaypanel.h
new file mode 100644
index 0000000..382732a
--- /dev/null
+++ b/game/client/tf2/commanderoverlaypanel.h
@@ -0,0 +1,143 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef COMMANDEROVERLAYPANEL_H
+#define COMMANDEROVERLAYPANEL_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "CommanderOverlay.h"
+#include <vgui_controls/Panel.h>
+
+#define TACTICAL_ZOFFSET 100
+#define TACTICAL_MIN_VIEWABLE_SIZE 1000
+#define TACTICAL_SPACEBAR_VIEWABLE_SIZE 4000
+
+#define FOG_ALPHAMAP_SIZE 64
+
+class C_TFTeam;
+class IVTFTexture;
+class ITexture;
+
+class CCommanderOverlayPanel : public vgui::Panel
+{
+ typedef vgui::Panel BaseClass;
+// Panel overrides.
+public:
+ CCommanderOverlayPanel( void );
+ virtual ~CCommanderOverlayPanel( void );
+
+ virtual void Paint();
+
+ virtual void OnMousePressed(vgui::MouseCode code);
+ virtual void OnMouseReleased(vgui::MouseCode code);
+ virtual void OnCursorMoved(int x, int y);
+ virtual void OnMouseWheeled(int delta);
+ virtual void OnKeyPressed(vgui::KeyCode code);
+
+ // Call on enable
+ void Enable();
+ void Disable();
+
+ // called when we're ticked (updates our state)...
+ void OnTick();
+
+ // Call when the map changes
+ void LevelInit( char const* pMapName );
+ void LevelShutdown( void );
+
+ // Returns the visible area (not including the tech tree)
+ void GetVisibleSize( int& w, int& h );
+
+ // Returns the visible area in world units
+ void GetVisibleArea( Vector& mins, Vector& maxs );
+
+ // Returns the number of world units per pixel
+ float WorldUnitsPerPixel();
+
+ // Fill in the rectangle that the view is rendered from.
+ // It is looking down negative Z, and goes from [vCenter.x-xSize, vCenter.y-ySize] to [vCenter.x+xSize, vCenter.y+ySize].
+ void GetOrthoRenderBox(Vector &vCenter, float &xSize, float &ySize);
+ void GetVisibleOrthoSize(float &xSize, float &ySize);
+ void ActualToVisibleOffset( Vector& offset );
+
+ void BoundOrigin( Vector& camera );
+
+ void CreatePickingRay( int mousex, int mousey,
+ int screenwidth, int screenheight,
+ const Vector& vecRenderOrigin,
+ const QAngle& vecRenderAngles,
+ Vector &rayOrigin,
+ Vector &rayDirection
+ );
+
+ Vector& TacticalOrigin() { return m_vecTacticalOrigin; }
+ QAngle& TacticalAngles() { return m_vecTacticalAngles; }
+
+ float GetZoom( void );
+
+ void SetCommanderView( CClientModeCommander *commander );
+ bool IsRightMouseMapMoving( void );
+
+private:
+ struct MouseDown_t
+ {
+ bool m_bMouseDown;
+ int m_nXStart;
+ int m_nYStart;
+ int m_nXCurrent;
+ int m_nYCurrent;
+ int m_nXPrev;
+ int m_nYPrev;
+ };
+
+ // Compute render origin
+ void InitializeRenderOrigin();
+
+ // Methods relating to zoom
+ void ComputeZoomRange();
+
+ void LeftMousePressed( void );
+ void LeftMouseReleased( void );
+ void RightMousePressed( void );
+ void RightMouseReleased( void );
+ void RightMouseMapMove( void );
+
+ // Shows the entire view
+ void ChangeZoomLevel( float newZoom );
+
+ // Centers the view on the mouse
+ void CenterOnMouse( Vector& mouseWorldPos );
+
+ int CountSelectedPlayers( void );
+ void GetSelectedPlayerBitField( CBitVec< MAX_PLAYERS >& bits );
+ void SelectPlayersInRectangle( int x0, int y0, int x1, int y1, bool clearOldSelections = true );
+
+ void GetMousePos( int& x, int& y );
+ void StartMovingMouse( MouseDown_t& mouse );
+ void UpdateMousePos( int x, int y, MouseDown_t& mouse );
+
+ // camera origin
+ Vector m_vecTacticalOrigin;
+ QAngle m_vecTacticalAngles;
+
+ MouseDown_t m_left, m_right;
+
+ float m_fZoom; // 0 = sitting at world maxs.z. 1 = at maxs.z + (maxs.z-mins.z)*2.
+ float m_MinWorldWidth;
+ float m_MaxWorldWidth;
+ bool m_bHaveActiveSelection;
+ float m_flPreviousMaxWorldWidth;
+
+ CClientModeCommander *m_pCommanderView;
+
+ vgui::HCursor m_CursorCommander;
+ vgui::HCursor m_CursorRightMouseMove;
+};
+
+#endif // COMMANDEROVERLAYPANEL_H
diff --git a/game/client/tf2/env_objecteffects.cpp b/game/client/tf2/env_objecteffects.cpp
new file mode 100644
index 0000000..4342a46
--- /dev/null
+++ b/game/client/tf2/env_objecteffects.cpp
@@ -0,0 +1,137 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+#include "cbase.h"
+#include "particles_simple.h"
+#include "particlemgr.h"
+#include "particle_collision.h"
+#include "env_objecteffects.h"
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CObjectSmokeParticles::Setup( const Vector &origin, const Vector *direction, float angularSpread, float minSpeed, float maxSpeed, float gravity, float dampen, int flags )
+{
+ // See if we've specified a direction
+ m_ParticleCollision.Setup( origin, direction, angularSpread, minSpeed, maxSpeed, gravity, dampen );
+}
+
+void CObjectSmokeParticles::SimulateParticles( CParticleSimulateIterator *pIterator )
+{
+ float timeDelta = pIterator->GetTimeDelta();
+
+ ObjectSmokeParticle *pParticle = (ObjectSmokeParticle*)pIterator->GetFirst();
+ while ( pParticle )
+ {
+ //Update velocity
+ UpdateVelocity( pParticle, timeDelta );
+ pParticle->m_Pos += (pParticle->m_vecVelocity * timeDelta);
+ pParticle->m_vecVelocity += pParticle->m_vecAcceleration * 2 * timeDelta;
+
+ //Should this particle die?
+ pParticle->m_flLifetime += timeDelta;
+ UpdateRoll( pParticle, timeDelta );
+
+ if ( pParticle->m_flLifetime >= pParticle->m_flDieTime )
+ pIterator->RemoveParticle( pParticle );
+
+ pParticle = (ObjectSmokeParticle*)pIterator->GetNext();
+ }
+}
+
+
+void CObjectSmokeParticles::RenderParticles( CParticleRenderIterator *pIterator )
+{
+ const ObjectSmokeParticle *pParticle = (const ObjectSmokeParticle *)pIterator->GetFirst();
+ while ( pParticle )
+ {
+ //Render
+ Vector tPos;
+
+ TransformParticle( ParticleMgr()->GetModelView(), pParticle->m_Pos, tPos );
+ float sortKey = (int) tPos.z;
+
+ //Render it
+ RenderParticle_ColorSizeAngle(
+ pIterator->GetParticleDraw(),
+ tPos,
+ UpdateColor( pParticle ),
+ UpdateAlpha( pParticle ) * GetAlphaDistanceFade( tPos, m_flNearClipMin, m_flNearClipMax ),
+ UpdateScale( pParticle ),
+ pParticle->m_flRoll );
+
+ pParticle = (const ObjectSmokeParticle *)pIterator->GetNext( sortKey );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CObjectFireParticles::Setup( const Vector &origin, const Vector *direction, float angularSpread, float minSpeed, float maxSpeed, float gravity, float dampen, int flags )
+{
+}
+
+void CObjectFireParticles::SimulateParticles( CParticleSimulateIterator *pIterator )
+{
+ float timeDelta = pIterator->GetTimeDelta();
+
+ ObjectFireParticle *pParticle = (ObjectFireParticle*)pIterator->GetFirst();
+ while ( pParticle )
+ {
+ // Lost our parent?
+ if ( !pParticle->m_hParent )
+ {
+ pIterator->RemoveParticle( pParticle );
+ }
+ else
+ {
+ // Update position to match our parent
+ Vector vecFire;
+ QAngle angFire;
+ if ( pParticle->m_hParent->GetAttachment( pParticle->m_iAttachmentPoint, vecFire, angFire ) )
+ {
+ pParticle->m_Pos = vecFire;
+ }
+
+ // Should this particle die?
+ pParticle->m_flLifetime += timeDelta;
+
+ UpdateRoll( pParticle, timeDelta );
+
+ if ( pParticle->m_flLifetime >= pParticle->m_flDieTime )
+ pIterator->RemoveParticle( pParticle );
+ }
+
+ pParticle = (ObjectFireParticle*)pIterator->GetNext();
+ }
+}
+
+
+void CObjectFireParticles::RenderParticles( CParticleRenderIterator *pIterator )
+{
+ const ObjectFireParticle *pParticle = (const ObjectFireParticle *)pIterator->GetFirst();
+ while ( pParticle )
+ {
+ // Render
+ Vector tPos;
+ TransformParticle( ParticleMgr()->GetModelView(), pParticle->m_Pos, tPos );
+ float sortKey = (int) tPos.z;
+
+ // Render it
+ RenderParticle_ColorSizeAngle(
+ pIterator->GetParticleDraw(),
+ tPos,
+ UpdateColor( pParticle ),
+ UpdateAlpha( pParticle ) * GetAlphaDistanceFade( tPos, m_flNearClipMin, m_flNearClipMax ),
+ UpdateScale( pParticle ),
+ pParticle->m_flRoll
+ );
+
+ pParticle = (const ObjectFireParticle *)pIterator->GetNext( sortKey );
+ }
+}
+
+
diff --git a/game/client/tf2/env_objecteffects.h b/game/client/tf2/env_objecteffects.h
new file mode 100644
index 0000000..9457145
--- /dev/null
+++ b/game/client/tf2/env_objecteffects.h
@@ -0,0 +1,73 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#ifndef ENV_OBJECTEFFECTS_H
+#define ENV_OBJECTEFFECTS_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+//-----------------------------------------------------------------------------
+// Purpose: Object smoke particles. They float upward.
+//-----------------------------------------------------------------------------
+class ObjectSmokeParticle : public SimpleParticle
+{
+public:
+ Vector m_vecAcceleration;
+};
+
+//-----------------------------------------------------------------------------
+// Purpose: Object smoke particle emitter.
+//-----------------------------------------------------------------------------
+class CObjectSmokeParticles : public CSimpleEmitter
+{
+public:
+
+ CObjectSmokeParticles( const char *pDebugName ) : CSimpleEmitter( pDebugName ) {}
+ static CSmartPtr<CObjectSmokeParticles> Create( const char *pDebugName ) {return new CObjectSmokeParticles( pDebugName );}
+
+ virtual void SimulateParticles( CParticleSimulateIterator *pIterator );
+ virtual void RenderParticles( CParticleRenderIterator *pIterator );
+
+ //Setup for point emission
+ virtual void Setup( const Vector &origin, const Vector *direction, float angularSpread, float minSpeed, float maxSpeed, float gravity, float dampen, int flags = 0 );
+
+ CParticleCollision m_ParticleCollision;
+
+private:
+ CObjectSmokeParticles( const CObjectSmokeParticles & ); // not defined, not accessible
+};
+
+//-----------------------------------------------------------------------------
+// Purpose: Object fire particles. They know how to attach themselves to heirarchy.
+//-----------------------------------------------------------------------------
+class ObjectFireParticle : public SimpleParticle
+{
+public:
+ EHANDLE m_hParent;
+ int m_iAttachmentPoint;
+};
+
+//-----------------------------------------------------------------------------
+// Purpose: Object smoke particle emitter.
+//-----------------------------------------------------------------------------
+class CObjectFireParticles : public CSimpleEmitter
+{
+public:
+ CObjectFireParticles( const char *pDebugName ) : CSimpleEmitter( pDebugName ) {}
+ static CSmartPtr<CObjectFireParticles> Create( const char *pDebugName ) {return new CObjectFireParticles( pDebugName );}
+
+ virtual void SimulateParticles( CParticleSimulateIterator *pIterator );
+ virtual void RenderParticles( CParticleRenderIterator *pIterator );
+
+ //Setup for point emission
+ virtual void Setup( const Vector &origin, const Vector *direction, float angularSpread, float minSpeed, float maxSpeed, float gravity, float dampen, int flags = 0 );
+
+private:
+ CObjectFireParticles( const CObjectFireParticles & ); // not defined, not accessible
+};
+
+#endif // ENV_OBJECTEFFECTS_H
diff --git a/game/client/tf2/fx_tf2_blood.cpp b/game/client/tf2/fx_tf2_blood.cpp
new file mode 100644
index 0000000..6b7e13a
--- /dev/null
+++ b/game/client/tf2/fx_tf2_blood.cpp
@@ -0,0 +1,347 @@
+//========= 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 "tf_shareddefs.h"
+#include "view.h"
+#include "c_basetfplayer.h"
+
+CLIENTEFFECT_REGISTER_BEGIN( PrecacheEffectTF2BloodSpray )
+CLIENTEFFECT_MATERIAL( "effects/blood_gore" )
+CLIENTEFFECT_MATERIAL( "effects/blood_drop" )
+CLIENTEFFECT_MATERIAL( "effects/blood_puff" )
+CLIENTEFFECT_REGISTER_END()
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : origin -
+// normal -
+// scale -
+//-----------------------------------------------------------------------------
+void FX_TF2_BloodSpray( const Vector &origin, const Vector &normal, float scale, unsigned char r, unsigned char g, unsigned char b, int flags )
+{
+ if ( UTIL_IsLowViolence() )
+ return;
+
+ //debugoverlay->AddLineOverlay( origin, origin + normal * 72, 255, 255, 255, true, 10 );
+
+ float spread = 0.2f;
+ Vector color = Vector( r / 255.0f, g / 255.0f, b / 255.0f );
+ float colorRamp;
+ Vector offset;
+ int i;
+
+ Vector offDir;
+ Vector right;
+ Vector up;
+ Vector vecNormal = normal;
+
+ // Get the distance to the view
+ float flDistance = (origin - MainViewOrigin()).Length();
+ float flLODDistance = 0.25 * (flDistance / 512);
+ float flDistanceScale = 1.0 + flLODDistance;
+
+ if (vecNormal != Vector(0, 0, 1) )
+ {
+ right = vecNormal.Cross( Vector(0, 0, 1) );
+ up = right.Cross( vecNormal );
+ }
+ else
+ {
+ right = Vector(0, 0, 1);
+ up = right.Cross( vecNormal );
+ }
+
+ // If the normal's too close to being along the view, push it out
+ Vector vecForward, vecRight;
+ AngleVectors( MainViewAngles(), &vecForward, &vecRight, NULL );
+ float flDot = DotProduct( vecNormal, vecForward );
+ if ( fabs(flDot) > 0.5 )
+ {
+ float flPush = random->RandomFloat(0.5, 1.5) + flLODDistance;
+ float flRightDot = DotProduct( vecNormal, vecRight );
+ // If we're up close, randomly move it around. If we're at a distance, always push it to the side
+ // Up close, this can move it back towards the view, but the random chance still looks better
+ if ( ( flDistance >= 512 && flRightDot > 0 ) || ( flDistance < 512 && RandomFloat(0,1) > 0.5 ) )
+ {
+ // Turn it to the right
+ vecNormal += (vecRight * flPush);
+ }
+ else
+ {
+ // Turn it to the left
+ vecNormal -= (vecRight * flPush);
+ }
+ }
+
+ //
+ // Dump out drops
+ //
+ // Don't bother with these over midrange distance
+ if (flags & FX_BLOODSPRAY_DROPS && ( flDistance < 1500 ) )
+ {
+ TrailParticle *tParticle;
+
+ CSmartPtr<CTrailParticles> pTrailEmitter = CTrailParticles::Create( "blooddrops" );
+ if ( !pTrailEmitter )
+ return;
+
+ pTrailEmitter->SetSortOrigin( origin );
+
+ // Partial gravity on blood drops.
+ pTrailEmitter->SetGravity( 600.0 );
+
+ // Enable simple collisions with nearby surfaces.
+ pTrailEmitter->Setup(origin, &vecNormal, 1, 10, 100, 600, 0.2, 0 );
+
+ PMaterialHandle hMaterial = ParticleMgr()->GetPMaterial( "effects/blood_drop" );
+
+ //
+ // Long stringy drops of blood.
+ //
+ for ( i = 0; i < 7; i++ )
+ {
+ // Originate from within a circle 'scale' inches in diameter.
+ offset = origin;
+ offset += right * random->RandomFloat( -0.5f, 0.5f ) * scale;
+ offset += up * random->RandomFloat( -0.5f, 0.5f ) * scale;
+
+ tParticle = (TrailParticle *) pTrailEmitter->AddParticle( sizeof(TrailParticle), hMaterial, offset );
+
+ if ( tParticle == NULL )
+ break;
+
+ tParticle->m_flLifetime = 0.0f;
+
+ offDir = vecNormal + RandomVector( -0.3f, 0.3f );
+
+ tParticle->m_vecVelocity = offDir * random->RandomFloat( 4.0f * scale, 40.0f * scale );
+ tParticle->m_vecVelocity[2] += random->RandomFloat( 4.0f, 16.0f ) * scale;
+
+ tParticle->m_flWidth = random->RandomFloat( 0.5f, 1.0f ) * scale * (flDistanceScale * 1.25);
+ tParticle->m_flLength = random->RandomFloat( 0.02f, 0.03f ) * scale * (flDistanceScale * 1.25);
+ tParticle->m_flDieTime = random->RandomFloat( 0.5f, 1.0f );
+
+ // Ramp up the brightness as it gets farther away
+ colorRamp = random->RandomFloat( 0.5f, 0.75f ) + flLODDistance;
+ FloatToColor32( tParticle->m_color, MIN( 1.0, color[0] * colorRamp ), MIN( 1.0, color[1] * colorRamp ), MIN( 1.0, color[2] * colorRamp ), 1.0f );
+ }
+
+ //
+ // Shorter droplets.
+ //
+ // Only do these at short range
+ if ( flDistance < 512 )
+ {
+ for ( i = 0; i < 10; i++ )
+ {
+ // Originate from within a circle 'scale' inches in diameter.
+ offset = origin;
+ offset += right * random->RandomFloat( -0.5f, 0.5f ) * scale;
+ offset += up * random->RandomFloat( -0.5f, 0.5f ) * scale;
+
+ tParticle = (TrailParticle *) pTrailEmitter->AddParticle( sizeof(TrailParticle), hMaterial, offset );
+
+ if ( tParticle == NULL )
+ break;
+
+ tParticle->m_flLifetime = 0.0f;
+
+ offDir = vecNormal + RandomVector( -1.0f, 1.0f );
+ offDir[2] += random->RandomFloat(0, 1.0f);
+
+ tParticle->m_vecVelocity = offDir * random->RandomFloat( 2.0f * scale, 25.0f * scale );
+ tParticle->m_vecVelocity[2] += random->RandomFloat( 4.0f, 16.0f ) * scale;
+
+ tParticle->m_flWidth = random->RandomFloat( 0.25f, 0.375f ) * scale * flDistanceScale;
+ tParticle->m_flLength = random->RandomFloat( 0.0025f, 0.005f ) * scale * flDistanceScale;
+ tParticle->m_flDieTime = random->RandomFloat( 0.5f, 1.0f );
+
+ colorRamp = random->RandomFloat( 0.5f, 0.75f ) + flLODDistance;
+ FloatToColor32( tParticle->m_color, MIN( 1.0, color[0] * colorRamp ), MIN( 1.0, color[1] * colorRamp ), MIN( 1.0, color[2] * colorRamp ), 1.0f );
+ }
+ }
+ }
+
+ if ((flags & FX_BLOODSPRAY_GORE) || (flags & FX_BLOODSPRAY_CLOUD))
+ {
+ CSmartPtr<CBloodSprayEmitter> pSimple = CBloodSprayEmitter::Create( "bloodgore" );
+ if ( !pSimple )
+ return;
+
+ pSimple->SetSortOrigin( origin );
+ pSimple->SetGravity( 0 );
+
+ PMaterialHandle hMaterial;
+
+ //
+ // Tight blossom of blood at the center.
+ //
+ if (flags & FX_BLOODSPRAY_GORE)
+ {
+ hMaterial = ParticleMgr()->GetPMaterial( "effects/blood_gore" );
+
+ SimpleParticle *pParticle;
+
+ for ( i = 0; i < 6; i++ )
+ {
+ // Originate from within a circle 'scale' inches in diameter.
+ offset = origin + ( 0.5 * scale * vecNormal );
+ offset += right * random->RandomFloat( -0.5f, 0.5f ) * scale;
+ offset += up * random->RandomFloat( -0.5f, 0.5f ) * scale;
+
+ pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), hMaterial, offset );
+
+ if ( pParticle != NULL )
+ {
+ pParticle->m_flLifetime = 0.0f;
+ pParticle->m_flDieTime = 0.3f;
+
+ spread = 0.2f;
+ pParticle->m_vecVelocity.Random( -spread, spread );
+ pParticle->m_vecVelocity += vecNormal * random->RandomInt( 10, 100 );
+ //VectorNormalize( pParticle->m_vecVelocity );
+
+ colorRamp = random->RandomFloat( 0.75f, 1.0f ) + flLODDistance;
+
+ 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 = random->RandomFloat( scale, scale * 4 ) * flDistanceScale;
+ pParticle->m_uchEndSize = pParticle->m_uchStartSize * 2 * flDistanceScale;
+
+ pParticle->m_uchStartAlpha = random->RandomInt( 200, 255 );
+ pParticle->m_uchEndAlpha = 0;
+
+ pParticle->m_flRoll = random->RandomInt( 0, 360 );
+ pParticle->m_flRollDelta = random->RandomFloat( -4.0f, 4.0f );
+ }
+ }
+ }
+
+ //
+ // Diffuse cloud just in front of the exit wound.
+ //
+ if (flags & FX_BLOODSPRAY_CLOUD)
+ {
+ hMaterial = ParticleMgr()->GetPMaterial( "effects/blood_puff" );
+
+ SimpleParticle *pParticle;
+
+ for ( i = 0; i < 6; i++ )
+ {
+ // Originate from within a circle '2 * scale' inches in diameter.
+ offset = origin + ( scale * vecNormal * 0.5 );
+ offset += right * random->RandomFloat( -1, 1 ) * scale;
+ offset += up * random->RandomFloat( -1, 1 ) * scale;
+
+ pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), hMaterial, offset );
+
+ if ( pParticle != NULL )
+ {
+ pParticle->m_flLifetime = 0.0f;
+ pParticle->m_flDieTime = random->RandomFloat( 0.5f, 0.8f);
+
+ spread = 0.5f;
+ pParticle->m_vecVelocity.Random( -spread, spread );
+ pParticle->m_vecVelocity += vecNormal * random->RandomInt( 100, 200 );
+
+ 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, color[1] * colorRamp ) * 255.0f;
+ pParticle->m_uchColor[2] = MIN( 1.0f, color[2] * colorRamp ) * 255.0f;
+
+ pParticle->m_uchStartSize = random->RandomFloat( scale * 0.5, scale ) * flDistanceScale;
+ pParticle->m_uchEndSize = pParticle->m_uchStartSize * 4 * flDistanceScale;
+
+ pParticle->m_uchStartAlpha = random->RandomInt( 80, 128 );
+ pParticle->m_uchEndAlpha = 0;
+
+ pParticle->m_flRoll = random->RandomInt( 0, 360 );
+ pParticle->m_flRollDelta = random->RandomFloat( -4.0f, 4.0f );
+ }
+ }
+ }
+ }
+
+ // TODO: Play a sound?
+ //CLocalPlayerFilter filter;
+ //C_BaseEntity::EmitSound( filter, SOUND_FROM_WORLD, CHAN_VOICE, "Physics.WaterSplash", 1.0, ATTN_NORM, 0, 100, &origin );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : bloodtype -
+// r -
+// g -
+// b -
+//-----------------------------------------------------------------------------
+void GetBloodColorForTeam( int iTeam, unsigned char &r, unsigned char &g, unsigned char &b )
+{
+ if ( iTeam == TEAM_ALIENS )
+ {
+ r = 0;
+ g = 255;
+ b = 0;
+ }
+ else if ( iTeam == TEAM_HUMANS )
+ {
+ // Humans
+ r = 255;
+ g = 0;
+ b = 0;
+ }
+ else
+ {
+ // NPCs?
+ r = 200;
+ g = 0;
+ b = 0;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Intercepts the blood spray message.
+//-----------------------------------------------------------------------------
+void TF2BloodSprayCallback( const CEffectData &data )
+{
+ unsigned char r = 0;
+ unsigned char g = 0;
+ unsigned char b = 0;
+
+ // Get the entity we've hit
+ C_BaseEntity *pEntity = ClientEntityList().GetEnt( data.m_nEntIndex );
+ if ( pEntity )
+ {
+ GetBloodColorForTeam( pEntity->GetTeamNumber(), r, g, b );
+ if ( pEntity->IsPlayer() )
+ {
+ C_BaseTFPlayer *pPlayer = (C_BaseTFPlayer *)pEntity;
+ pPlayer->PainSound();
+ }
+ }
+ else
+ {
+ GetBloodColorForTeam( 0, r, g, b );
+ }
+ FX_TF2_BloodSpray( data.m_vOrigin, data.m_vNormal, data.m_flScale, r, g, b, data.m_fFlags );
+}
+
+DECLARE_CLIENT_EFFECT( "tf2blood", TF2BloodSprayCallback );
diff --git a/game/client/tf2/fx_tf2_buildeffects.cpp b/game/client/tf2/fx_tf2_buildeffects.cpp
new file mode 100644
index 0000000..086ba82
--- /dev/null
+++ b/game/client/tf2/fx_tf2_buildeffects.cpp
@@ -0,0 +1,737 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Effects played when objects are building
+//
+//=============================================================================//
+
+#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 "tf_shareddefs.h"
+#include "c_impact_effects.h"
+#include "fx.h"
+#include "iviewrender_beams.h"
+#include "view.h"
+#include "IEffects.h"
+#include "c_tracer.h"
+
+CLIENTEFFECT_REGISTER_BEGIN( PrecacheTF2EffectBuild )
+CLIENTEFFECT_MATERIAL( "effects/blood" )
+CLIENTEFFECT_MATERIAL( "effects/human_build_warp" )
+CLIENTEFFECT_MATERIAL( "effects/tesla_glow_noz" )
+CLIENTEFFECT_MATERIAL( "particle/particle_smokegrenade" )
+CLIENTEFFECT_MATERIAL( "effects/human_tracers/human_sparksprite_A1" )
+CLIENTEFFECT_MATERIAL( "effects/human_tracers/human_sparktracer_A_" )
+CLIENTEFFECT_MATERIAL( "effects/alien_tracers/alien_pbtracer_A_" )
+CLIENTEFFECT_MATERIAL( "effects/alien_tracers/alien_pbsprite_A1" )
+CLIENTEFFECT_REGISTER_END()
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Build impact
+//-----------------------------------------------------------------------------
+void FX_BuildImpact( const Vector &origin, const QAngle &vecAngles, const Vector &vecNormal, float flScale, bool bGround = false, CBaseEntity *pIgnore = NULL )
+{
+ Vector offset;
+ float spread = 0.1f;
+
+ CSmartPtr<CDustParticle> pSimple = CDustParticle::Create( "dust" );
+ pSimple->SetSortOrigin( origin );
+
+ SimpleParticle *pParticle;
+
+ Vector color( 0.35, 0.35, 0.35 );
+ float colorRamp;
+
+ // If we're hitting the ground, try and get the ground color
+ if ( bGround )
+ {
+ trace_t tr;
+ UTIL_TraceLine( origin, origin + Vector(0,0,-32), MASK_SHOT, pIgnore, COLLISION_GROUP_NONE, &tr );
+ GetColorForSurface( &tr, &color );
+ }
+
+ int iNumPuffs = 8;
+ for ( int i = 0; i < iNumPuffs; i++ )
+ {
+ QAngle vecTemp = vecAngles;
+ vecTemp[YAW] += (360 / iNumPuffs) * i;
+ Vector vecForward;
+ AngleVectors( vecTemp, &vecForward );
+
+ pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), g_Mat_DustPuff[0], origin );
+
+ if ( pParticle != NULL )
+ {
+ pParticle->m_flLifetime = 0.0f;
+ pParticle->m_flDieTime = RandomFloat( 0.5f, 1.0f );
+
+ pParticle->m_vecVelocity.Random( -spread, spread );
+ pParticle->m_vecVelocity += ( vecForward * RandomFloat( 1.0f, 6.0f ) );
+
+ VectorNormalize( pParticle->m_vecVelocity );
+
+ float fForce = RandomFloat( 500, 750 );
+
+ // scaled
+ pParticle->m_vecVelocity *= fForce * flScale;
+
+ colorRamp = 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 = flScale * RandomInt( 15, 20 );
+
+ // scaled
+ pParticle->m_uchEndSize = flScale * pParticle->m_uchStartSize * 4;
+
+ pParticle->m_uchStartAlpha = RandomInt( 32, 255 );
+ pParticle->m_uchEndAlpha = 0;
+
+ pParticle->m_flRoll = RandomInt( 0, 360 );
+ pParticle->m_flRollDelta = RandomFloat( -8.0f, 8.0f );
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Large dust impact
+//-----------------------------------------------------------------------------
+void BuildImpactCallback( const CEffectData &data )
+{
+ Vector vecOrigin = data.m_vOrigin;
+ QAngle vecAngles = data.m_vAngles;
+ Vector vecNormal = data.m_vNormal;
+
+ FX_BuildImpact( vecOrigin, vecAngles, vecNormal, 1 );
+
+ // Randomly play sparks
+ if ( RandomFloat() > 0.35 )
+ {
+ // Angle them up
+ vecAngles[PITCH] = -90;
+ Vector vecForward;
+ AngleVectors( vecAngles, &vecForward );
+
+ // Sparks
+ FX_Sparks( vecOrigin, 2, 4, vecForward, 2.5, 48, 64 );
+ }
+}
+
+DECLARE_CLIENT_EFFECT( "BuildImpact", BuildImpactCallback );
+
+//-----------------------------------------------------------------------------
+// Purpose: Small dust impact
+//-----------------------------------------------------------------------------
+void BuildImpactSmallCallback( const CEffectData &data )
+{
+ Vector vecOrigin = data.m_vOrigin;
+ QAngle vecAngles = data.m_vAngles;
+ Vector vecNormal = data.m_vNormal;
+
+ FX_BuildImpact( vecOrigin, vecAngles, vecNormal, 0.65 );
+}
+
+DECLARE_CLIENT_EFFECT( "BuildImpactSmall", BuildImpactSmallCallback );
+
+//-----------------------------------------------------------------------------
+// Purpose: Large dust impact to be used only when something's landed on the ground
+//-----------------------------------------------------------------------------
+void BuildImpactGroundCallback( const CEffectData &data )
+{
+ Vector vecOrigin = data.m_vOrigin;
+ QAngle vecAngles = data.m_vAngles;
+ Vector vecNormal = data.m_vNormal;
+ int iEntIndex = data.m_nEntIndex;
+
+ C_BaseEntity *pEntity = ClientEntityList().GetEnt( iEntIndex );
+ FX_BuildImpact( vecOrigin, vecAngles, vecNormal, 1, true, pEntity );
+}
+
+DECLARE_CLIENT_EFFECT( "BuildImpactGround", BuildImpactGroundCallback );
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Create a tesla effect between two points
+//-----------------------------------------------------------------------------
+void TF2_FX_BuildTesla( C_BaseEntity *pEntity, Vector &vecOrigin, Vector &vecEnd )
+{
+ BeamInfo_t beamInfo;
+ beamInfo.m_nType = TE_BEAMTESLA;
+ beamInfo.m_vecStart = vecOrigin;
+ beamInfo.m_vecEnd = vecEnd;
+ beamInfo.m_pszModelName = "sprites/physbeam.vmt";
+ beamInfo.m_flHaloScale = 0.0;
+ beamInfo.m_flLife = RandomFloat( 0.3, 0.55 );
+ beamInfo.m_flWidth = 5.0;
+ beamInfo.m_flEndWidth = 1;
+ beamInfo.m_flFadeLength = 0.3;
+ beamInfo.m_flAmplitude = 16;
+ beamInfo.m_flBrightness = 200.0;
+ beamInfo.m_flSpeed = 0.0;
+ beamInfo.m_nStartFrame = 0.0;
+ beamInfo.m_flFrameRate = 1.0;
+ beamInfo.m_flRed = 255.0;
+ beamInfo.m_flGreen = 255.0;
+ beamInfo.m_flBlue = 255.0;
+ beamInfo.m_nSegments = 20;
+ beamInfo.m_bRenderable = true;
+ beamInfo.m_nFlags = FBEAM_ONLYNOISEONCE;
+
+ beams->CreateBeamPoints( beamInfo );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Tesla effect
+//-----------------------------------------------------------------------------
+void TF2_BuildTeslaCallback( const CEffectData &data )
+{
+ Vector vecOrigin = data.m_vOrigin;
+ QAngle vecAngles = data.m_vAngles;
+ int iEntIndex = data.m_nEntIndex;
+ C_BaseEntity *pEntity = ClientEntityList().GetEnt( iEntIndex );
+
+ // Send out beams around us
+ int iNumBeamsAround = 4;
+ int iNumRandomBeams = 2;
+ int iTotalBeams = iNumBeamsAround + iNumRandomBeams;
+ float flYawOffset = RandomFloat(0,360);
+ for ( int i = 0; i < iTotalBeams; i++ )
+ {
+ // Make a couple of tries at it
+ int iTries = -1;
+ Vector vecForward;
+ trace_t tr;
+ do
+ {
+ iTries++;
+
+ // Some beams are deliberatly aimed around the point, the rest are random.
+ if ( i < iNumBeamsAround )
+ {
+ QAngle vecTemp = vecAngles;
+ vecTemp[YAW] += anglemod( flYawOffset + ((360 / iTotalBeams) * i) );
+ AngleVectors( vecTemp, &vecForward );
+
+ // Randomly angle it up or down
+ vecForward.z = RandomFloat( -1, 1 );
+ }
+ else
+ {
+ vecForward = RandomVector( -1, 1 );
+ }
+
+ UTIL_TraceLine( vecOrigin, vecOrigin + (vecForward * 192), MASK_SHOT, pEntity, COLLISION_GROUP_NONE, &tr );
+ } while ( tr.fraction >= 1.0 && iTries < 3 );
+
+ Vector vecEnd = tr.endpos - (vecForward * 8);
+
+ // Only spark & glow if we hit something
+ if ( tr.fraction < 1.0 )
+ {
+ if ( !EffectOccluded( tr.endpos ) )
+ {
+ // Move it towards the camera
+ Vector vecFlash = tr.endpos;
+ Vector vecForward;
+ AngleVectors( MainViewAngles(), &vecForward );
+ vecFlash -= (vecForward * 8);
+
+ g_pEffects->EnergySplash( vecFlash, -vecForward, false );
+
+ // End glow
+ CSmartPtr<CSimpleEmitter> pSimple = CSimpleEmitter::Create( "dust" );
+ pSimple->SetSortOrigin( vecFlash );
+ SimpleParticle *pParticle;
+ pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), pSimple->GetPMaterial( "effects/tesla_glow_noz" ), vecFlash );
+ if ( pParticle != NULL )
+ {
+ pParticle->m_flLifetime = 0.0f;
+ pParticle->m_flDieTime = RandomFloat( 0.5, 1 );
+ pParticle->m_vecVelocity = vec3_origin;
+ Vector color( 1,1,1 );
+ float colorRamp = 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;
+ pParticle->m_uchStartSize = RandomFloat( 6,13 );
+ pParticle->m_uchEndSize = pParticle->m_uchStartSize - 2;
+ pParticle->m_uchStartAlpha = 255;
+ pParticle->m_uchEndAlpha = 10;
+ pParticle->m_flRoll = RandomFloat( 0,360 );
+ pParticle->m_flRollDelta = 0;
+ }
+ }
+ }
+
+ // Build the tesla
+ TF2_FX_BuildTesla( pEntity, vecOrigin, tr.endpos );
+ }
+}
+
+DECLARE_CLIENT_EFFECT( "TF2BuildTesla", TF2_BuildTeslaCallback );
+
+//-----------------------------------------------------------------------------
+// Purpose: WarpParticle emitter
+// This is a particle that scales up to its max size in WARPEMMITER_MIDPOINT
+// of it's lifetime, the drops back to its initial size by the end of its life.
+// Alpha scales the same way.
+//-----------------------------------------------------------------------------
+#define WARPEMMITER_MIDPOINT 0.6
+
+class CWarpParticleEmitter : public CSimpleEmitter
+{
+public:
+
+ CWarpParticleEmitter( const char *pDebugName ) : CSimpleEmitter( pDebugName ) {}
+
+ //Create
+ static CWarpParticleEmitter *Create( const char *pDebugName="dust" )
+ {
+ return new CWarpParticleEmitter( pDebugName );
+ }
+
+ // Scale
+ virtual float UpdateScale( const SimpleParticle *pParticle )
+ {
+ float tLifeTime = pParticle->m_flLifetime / pParticle->m_flDieTime;
+
+ // Ramp up for the first 75% of my life, then reduce for the rest
+ if ( tLifeTime < WARPEMMITER_MIDPOINT )
+ {
+ tLifeTime = RemapVal( tLifeTime, 0, WARPEMMITER_MIDPOINT, 0, 1.0 );
+ return (float)pParticle->m_uchStartSize + ( (float)pParticle->m_uchEndSize - (float)pParticle->m_uchStartSize ) * tLifeTime;
+ }
+
+ tLifeTime -= WARPEMMITER_MIDPOINT;
+ tLifeTime = RemapVal( tLifeTime, 0, 1 - WARPEMMITER_MIDPOINT, 0, 1.0 );
+ return (float)pParticle->m_uchEndSize - ( (float)pParticle->m_uchEndSize - (float)pParticle->m_uchStartSize ) * tLifeTime;
+ }
+
+ //Alpha
+ virtual float UpdateAlpha( const SimpleParticle *pParticle )
+ {
+ float tLifeTime = pParticle->m_flLifetime / pParticle->m_flDieTime;
+ float flAlpha = 0;
+
+ // Ramp up for the first 75% of my life, then reduce for the rest
+ if ( tLifeTime < WARPEMMITER_MIDPOINT )
+ {
+ tLifeTime = RemapVal( tLifeTime, 0, WARPEMMITER_MIDPOINT, 0, 1.0 );
+ flAlpha = (float)pParticle->m_uchStartAlpha + ( (float)pParticle->m_uchEndAlpha - (float)pParticle->m_uchStartAlpha ) * tLifeTime;
+ }
+ else
+ {
+ tLifeTime -= WARPEMMITER_MIDPOINT;
+ tLifeTime = RemapVal( tLifeTime, 0, 1 - WARPEMMITER_MIDPOINT, 0, 1.0 );
+ flAlpha = (float)pParticle->m_uchEndAlpha - ( (float)pParticle->m_uchEndAlpha - (float)pParticle->m_uchStartAlpha ) * tLifeTime;
+ }
+
+ flAlpha = flAlpha / 255;
+ return flAlpha;
+ }
+
+private:
+ CWarpParticleEmitter( const CWarpParticleEmitter & ); // not defined, not accessible
+};
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void FX_BuildWarp( Vector &vecOrigin, QAngle &vecAngles, float flScale )
+{
+ if ( EffectOccluded( vecOrigin ) )
+ return;
+
+ CSmartPtr<CSimpleEmitter> pSimple = CSimpleEmitter::Create( "dust" );
+ pSimple->SetSortOrigin( vecOrigin );
+
+ SimpleParticle *pParticle;
+
+ Vector color( 1, 1, 1 );
+ float colorRamp;
+
+ // Big flash
+ pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), pSimple->GetPMaterial( "effects/blueflare2" ), vecOrigin );
+ if ( pParticle != NULL )
+ {
+ pParticle->m_flLifetime = 0.0f;
+ pParticle->m_flDieTime = 0.5;
+ pParticle->m_vecVelocity = vec3_origin;
+ colorRamp = 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;
+ pParticle->m_uchStartSize = RandomFloat( 10,15 );
+ pParticle->m_uchEndSize = pParticle->m_uchStartSize * 8 * flScale;
+ pParticle->m_uchStartAlpha = 48;
+ pParticle->m_uchEndAlpha = 0;
+ pParticle->m_flRoll = 0;
+ pParticle->m_flRollDelta = 0;
+ }
+
+ // Bright light
+ // Move it towards the camera
+ Vector vecForward;
+ AngleVectors( MainViewAngles(), &vecForward );
+ vecOrigin -= (vecForward * 8);
+ CSmartPtr<CWarpParticleEmitter> pWarpEmitter = CWarpParticleEmitter::Create( "dust" );
+ pWarpEmitter->SetSortOrigin( vecOrigin );
+
+ pParticle = (SimpleParticle *) pWarpEmitter->AddParticle( sizeof( SimpleParticle ), pWarpEmitter->GetPMaterial( "effects/human_build_warp" ), vecOrigin );
+ if ( pParticle != NULL )
+ {
+ pParticle->m_flLifetime = 0.0f;
+ pParticle->m_flDieTime = 0.4;
+ pParticle->m_vecVelocity = vec3_origin;
+
+ colorRamp = 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;
+
+ pParticle->m_uchStartSize = RandomInt( 10,13 ) * flScale;
+ pParticle->m_uchEndSize = pParticle->m_uchStartSize * 9;
+
+ pParticle->m_uchStartAlpha = 32;
+ pParticle->m_uchEndAlpha = 192;
+
+ pParticle->m_flRoll = 0;
+ pParticle->m_flRollDelta = 0;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Warp effect
+//-----------------------------------------------------------------------------
+void BuildWarpCallback( const CEffectData &data )
+{
+ Vector vecOrigin = data.m_vOrigin;
+ QAngle vecAngles = data.m_vAngles;
+
+ // Warp effect
+ FX_BuildWarp( vecOrigin, vecAngles, 2 );
+ g_pEffects->EnergySplash( vecOrigin, Vector(0,0,1), false );
+}
+
+DECLARE_CLIENT_EFFECT( "BuildWarp", BuildWarpCallback );
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Small Warp effect
+//-----------------------------------------------------------------------------
+void BuildWarpSmallCallback( const CEffectData &data )
+{
+ Vector vecOrigin = data.m_vOrigin;
+ QAngle vecAngles = data.m_vAngles;
+
+ // Warp effect
+ FX_BuildWarp( vecOrigin, vecAngles, 1.5 );
+ g_pEffects->EnergySplash( vecOrigin, Vector(0,0,1), false );
+}
+
+DECLARE_CLIENT_EFFECT( "BuildWarpSmall", BuildWarpSmallCallback );
+
+//-----------------------------------------------------------------------------
+// Purpose: Spark effects
+//-----------------------------------------------------------------------------
+void BuildSparksCallback( const CEffectData &data )
+{
+ Vector vecOrigin = data.m_vOrigin;
+ QAngle vecAngles = data.m_vAngles;
+
+ // Angle them up
+ vecAngles[PITCH] = -90;
+ Vector vecForward;
+ AngleVectors( vecAngles, &vecForward );
+
+ // Sparks
+ FX_Sparks( vecOrigin, 2, 4, vecForward, 2.5, 48, 64 );
+}
+
+DECLARE_CLIENT_EFFECT( "BuildSparks", BuildSparksCallback );
+
+//-----------------------------------------------------------------------------
+// Purpose: Red Spark effects
+//-----------------------------------------------------------------------------
+void BuildSparksRedCallback( const CEffectData &data )
+{
+ Vector vecOrigin = data.m_vOrigin;
+ QAngle vecAngles = data.m_vAngles;
+
+ // Angle them up
+ vecAngles[PITCH] = -90;
+ Vector vecForward;
+ AngleVectors( vecAngles, &vecForward );
+
+ // Sparks
+ FX_Sparks( vecOrigin, 2, 4, vecForward, 2.5, 48, 64, "effects/spark2" );
+}
+
+DECLARE_CLIENT_EFFECT( "BuildSparksRed", BuildSparksRedCallback );
+
+//-----------------------------------------------------------------------------
+// Purpose: Electric sparks effect
+//-----------------------------------------------------------------------------
+void BuildSparksElectricCallback( const CEffectData &data )
+{
+ Vector vecOrigin = data.m_vOrigin;
+ Vector vecNormal = data.m_vNormal;
+
+ // Sparks
+ FX_ElectricSpark( vecOrigin, 2, 4, &vecNormal );
+}
+
+DECLARE_CLIENT_EFFECT( "BuildSparksElectric", BuildSparksElectricCallback );
+
+//-----------------------------------------------------------------------------
+// Purpose: Metal sparks effect
+//-----------------------------------------------------------------------------
+void BuildSparksMetalCallback( const CEffectData &data )
+{
+ Vector vecOrigin = data.m_vOrigin;
+ Vector vecNormal = data.m_vNormal;
+
+ // Sparks
+ FX_MetalSpark( vecOrigin, vecNormal, vecNormal, 2 );
+}
+
+DECLARE_CLIENT_EFFECT( "BuildSparksMetal", BuildSparksMetalCallback );
+
+//-----------------------------------------------------------------------------
+// Purpose: Metal scrape effect
+//-----------------------------------------------------------------------------
+void BuildMetalScrapeCallback( const CEffectData &data )
+{
+ Vector vecOrigin = data.m_vOrigin;
+ Vector vecNormal = data.m_vNormal;
+
+ // Sparks
+ FX_MetalScrape( vecOrigin, vecNormal );
+}
+
+DECLARE_CLIENT_EFFECT( "BuildMetalScrape", BuildMetalScrapeCallback );
+
+//-----------------------------------------------------------------------------
+// Purpose: Warp effect that looks like it's sucking things to it
+//-----------------------------------------------------------------------------
+void FX_BuildWarpSuck( Vector &vecOrigin, QAngle &vecAngles, float flScale )
+{
+ CSmartPtr<CTrailParticles> pEmitter = CTrailParticles::Create( "BuildWarpSuck" );
+ PMaterialHandle hParticleMaterial = pEmitter->GetPMaterial( "effects/bluespark" );
+ pEmitter->Setup( (Vector &) vecOrigin,
+ NULL,
+ 0.0,
+ 0,
+ 64,
+ 0,
+ 0,
+ bitsPARTICLE_TRAIL_VELOCITY_DAMPEN | bitsPARTICLE_TRAIL_FADE );
+
+ // Add particles
+ int iNumParticles = 60;
+ for ( int i = 0; i < iNumParticles; i++ )
+ {
+ Vector vOffset = RandomVector( -1, 1 );
+ VectorNormalize( vOffset );
+ float flDistance = RandomFloat( 16, 64 ) * flScale;
+ Vector vPos = vecOrigin + (vOffset * flDistance);
+
+ TrailParticle *pParticle = (TrailParticle *) pEmitter->AddParticle( sizeof(TrailParticle), hParticleMaterial, vPos );
+ if ( pParticle )
+ {
+ float flSpeed = RandomFloat(8,16) * (flScale * flScale * flScale);
+ pParticle->m_vecVelocity = vOffset * -flSpeed;
+ pParticle->m_flDieTime = MIN( 3, (flDistance / flSpeed) + RandomFloat(0.0, 0.2) );
+ pParticle->m_flLifetime = 0;
+ pParticle->m_flWidth = RandomFloat( 2, 3 ) * flScale;
+ pParticle->m_flLength = RandomFloat( 1, 2 ) * flScale;
+
+ Color32Init( pParticle->m_color, 255, 255, 255, 255 );
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Warp effect that looks like it's sucking things to it
+//-----------------------------------------------------------------------------
+void BuildWarpSuckCallback( const CEffectData &data )
+{
+ Vector vecOrigin = data.m_vOrigin;
+ QAngle vecAngles = data.m_vAngles;
+
+ FX_BuildWarpSuck( vecOrigin, vecAngles, 1.0 );
+}
+
+DECLARE_CLIENT_EFFECT( "BuildWarpSuck", BuildWarpSuckCallback );
+
+//-----------------------------------------------------------------------------
+// Purpose: Bigger Warp effect that looks like it's sucking things to it
+//-----------------------------------------------------------------------------
+void BuildWarpSuckBigCallback( const CEffectData &data )
+{
+ Vector vecOrigin = data.m_vOrigin;
+ QAngle vecAngles = data.m_vAngles;
+
+ FX_BuildWarpSuck( vecOrigin, vecAngles, 2.0 );
+}
+
+DECLARE_CLIENT_EFFECT( "BuildWarpSuckBig", BuildWarpSuckBigCallback );
+
+//-----------------------------------------------------------------------------
+// Purpose: GasSpurt Emitter
+// This is an emitter that keeps spitting out particles for its lifetime
+// It won't create particles if it's not in view, so it's best when short lived
+//-----------------------------------------------------------------------------
+class CGasSpurtEmitter : public CSimpleEmitter
+{
+ typedef CSimpleEmitter BaseClass;
+public:
+ CGasSpurtEmitter( const char *pDebugName ) : CSimpleEmitter( pDebugName )
+ {
+ m_flDeathTime = 0;
+ m_flLastParticleSpawnTime = 0;
+ }
+
+ // Create
+ static CGasSpurtEmitter *Create( const char *pDebugName="gasspurt" )
+ {
+ return new CGasSpurtEmitter( pDebugName );
+ }
+
+ void SetLifeTime( float flTime )
+ {
+ m_flDeathTime = gpGlobals->curtime + flTime;
+ }
+
+ void SetSpurtAngle( QAngle &vecAngles )
+ {
+ AngleVectors( vecAngles, &m_vecSpurtForward );
+ }
+
+ void SetSpurtColor( const Vector4D &pColor )
+ {
+ for ( int i = 0; i <= 3; i++ )
+ {
+ m_SpurtColor[i] = pColor[i];
+ }
+ }
+
+ void SetSpawnRate( float flRate )
+ {
+ m_flSpawnRate = flRate;
+ }
+
+ void CreateSpurtParticles( void )
+ {
+ SimpleParticle *pParticle;
+
+ // Smoke
+ int numParticles = RandomInt( 1,2 );
+ for ( int i = 0; i < numParticles; i++ )
+ {
+ pParticle = (SimpleParticle *) AddParticle( sizeof( SimpleParticle ), g_Mat_DustPuff[0], m_vSortOrigin );
+ if ( pParticle == NULL )
+ break;
+
+ pParticle->m_flLifetime = 0.0f;
+ pParticle->m_flDieTime = RandomFloat( 0.5, 1.0 );
+
+ // Random velocity around the angles forward
+ Vector vecVelocity;
+ vecVelocity.Random( -0.1f, 0.1f );
+ vecVelocity += m_vecSpurtForward;
+ VectorNormalize( vecVelocity );
+ vecVelocity *= RandomFloat( 16.0f, 64.0f );
+ pParticle->m_vecVelocity = vecVelocity;
+
+ // Randomize the color a little
+ int color[3][2];
+ for( int i = 0; i < 3; ++i )
+ {
+ color[i][0] = MAX( 0, m_SpurtColor[i] - 64 );
+ color[i][1] = MIN( 255, m_SpurtColor[i] + 64 );
+ }
+ pParticle->m_uchColor[0] = random->RandomInt( color[0][0], color[0][1] );
+ pParticle->m_uchColor[1] = random->RandomInt( color[1][0], color[1][1] );
+ pParticle->m_uchColor[2] = random->RandomInt( color[2][0], color[2][1] );
+
+ pParticle->m_uchStartAlpha = m_SpurtColor[3];
+ pParticle->m_uchEndAlpha = 0;
+ pParticle->m_uchStartSize = RandomInt( 1, 2 );
+ pParticle->m_uchEndSize = pParticle->m_uchStartSize*3;
+ pParticle->m_flRoll = RandomFloat( 0, 360 );
+ pParticle->m_flRollDelta = RandomFloat( -4.0f, 4.0f );
+ }
+
+ m_flLastParticleSpawnTime = gpGlobals->curtime + m_flSpawnRate;
+ }
+
+ virtual void SimulateParticles( CParticleSimulateIterator *pIterator )
+ {
+ Particle *pParticle = (Particle*)pIterator->GetFirst();
+ while ( pParticle )
+ {
+ // If our lifetime isn't up, create more particles
+ if ( m_flDeathTime > gpGlobals->curtime )
+ {
+ if ( m_flLastParticleSpawnTime <= gpGlobals->curtime )
+ {
+ CreateSpurtParticles();
+ }
+ }
+
+ pParticle = (Particle*)pIterator->GetNext();
+ }
+
+ BaseClass::SimulateParticles( pIterator );
+ }
+
+
+private:
+ float m_flDeathTime;
+ float m_flLastParticleSpawnTime;
+ float m_flSpawnRate;
+ Vector m_vecSpurtForward;
+ Vector4D m_SpurtColor;
+
+ CGasSpurtEmitter( const CGasSpurtEmitter & ); // not defined, not accessible
+};
+
+//-----------------------------------------------------------------------------
+// Purpose: Small hose gas spurt
+//-----------------------------------------------------------------------------
+void FX_BuildGasSpurt( Vector &vecOrigin, QAngle &vecAngles, float flLifeTime, const Vector4D &pColor )
+{
+ CSmartPtr<CGasSpurtEmitter> pSimple = CGasSpurtEmitter::Create( "FX_Smoke" );
+ pSimple->SetSortOrigin( vecOrigin );
+ pSimple->SetLifeTime( flLifeTime );
+ pSimple->SetSpurtAngle( vecAngles );
+ pSimple->SetSpurtColor( pColor );
+ pSimple->SetSpawnRate( 0.03 );
+ pSimple->CreateSpurtParticles();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Green hose gas spurt
+//-----------------------------------------------------------------------------
+void GasGreenCallback( const CEffectData &data )
+{
+ Vector vecOrigin = data.m_vOrigin;
+ QAngle vecAngles = data.m_vAngles;
+
+ Vector4D color( 50,192,50,255 );
+ FX_BuildGasSpurt( vecOrigin, vecAngles, 1.0, color );
+}
+
+DECLARE_CLIENT_EFFECT( "GasGreen", GasGreenCallback );
diff --git a/game/client/tf2/fx_tf2_impacts.cpp b/game/client/tf2/fx_tf2_impacts.cpp
new file mode 100644
index 0000000..e22c70d
--- /dev/null
+++ b/game/client/tf2/fx_tf2_impacts.cpp
@@ -0,0 +1,453 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Game-specific impact effect hooks
+//
+//=============================================================================//
+#include "cbase.h"
+#include "fx_impact.h"
+#include "decals.h"
+#include "IEffects.h"
+#include "c_breakableprop.h"
+#include "tempent.h"
+#include "c_te_legacytempents.h"
+#include "tf_shareddefs.h"
+#include "fx.h"
+
+void ImpactCreateHurtShards( Vector &vecOrigin, trace_t &tr, Vector &shotDir, int iMaterial, bool bLarge, bool bBlood );
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void MakeHurt( const CEffectData &data, bool bBlood )
+{
+ 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 ) )
+ {
+ // Throw out shards to show the player he's hurting it
+ ImpactCreateHurtShards( vecOrigin, tr, vecShotDir, iMaterial, false, bBlood );
+
+ // Check for custom effects based on the Decal index
+ PerformCustomEffects( vecOrigin, tr, vecShotDir, iMaterial, 1.0 );
+ }
+
+ PlayImpactSound( pEntity, tr, vecOrigin, nSurfaceProp );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Impact for:
+// Bullets hitting targets that CAN be hurt
+//-----------------------------------------------------------------------------
+void ImpactCallback( const CEffectData &data )
+{
+ MakeHurt( data, true );
+}
+
+DECLARE_CLIENT_EFFECT( "Impact", ImpactCallback );
+
+//-----------------------------------------------------------------------------
+// Purpose: Bloodless Impact for:
+// Bullets hitting targets that CAN be hurt
+//-----------------------------------------------------------------------------
+void ImpactNoBloodCallback( const CEffectData &data )
+{
+ MakeHurt( data, false );
+}
+
+DECLARE_CLIENT_EFFECT( "ImpactNoBlood", ImpactNoBloodCallback );
+
+//-----------------------------------------------------------------------------
+// Purpose: Impact for:
+// Bullets hitting targets that CANNOT be hurt
+//-----------------------------------------------------------------------------
+void ImpactUnhurtCallback( 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
+ // Don't decal team members, but decal everything else
+
+ bool bShouldDecal = !( pEntity && pEntity->IsPlayer() );
+ if ( Impact( vecOrigin, vecStart, iMaterial, iDamageType, iHitbox, pEntity, tr, bShouldDecal ? 0 : IMPACT_NODECAL ) )
+ {
+ // Check for custom effects based on the Decal index
+ PerformCustomEffects( vecOrigin, tr, vecShotDir, iMaterial, 0 );
+ }
+
+ PlayImpactSound( pEntity, tr, vecOrigin, nSurfaceProp );
+}
+
+DECLARE_CLIENT_EFFECT( "ImpactUnhurt", ImpactUnhurtCallback );
+
+//-----------------------------------------------------------------------------
+// Purpose: Impact for:
+// Bullets hitting player's handheld shields
+//-----------------------------------------------------------------------------
+void ImpactShieldCallback( const CEffectData &data )
+{
+ trace_t tr;
+ Vector vecOrigin, vecStart, vecShotDir;
+ int iMaterial, iDamageType, iHitbox;
+ short nSurfaceProp;
+ ParseImpactData( data, &vecOrigin, &vecStart, &vecShotDir, nSurfaceProp, iMaterial, iDamageType, iHitbox );
+
+ // Don't call Impact() because we don't want to decal the player
+ Vector reflect = -vecShotDir;
+ reflect[0] += random->RandomFloat( -0.5f, 0.5f );
+ reflect[1] += random->RandomFloat( -0.5f, 0.5f );
+ reflect[2] += random->RandomFloat( 0, 0.5f );
+ FX_MetalSpark( vecOrigin, reflect, -vecShotDir, 3 );
+}
+
+DECLARE_CLIENT_EFFECT( "ImpactShield", ImpactShieldCallback );
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void MakePlasmaHurt( const CEffectData &data, bool bBlood )
+{
+ 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, play our splash
+ if ( Impact( vecOrigin, vecStart, iMaterial, iDamageType, iHitbox, pEntity, tr ) )
+ {
+ // Throw out shards to show the player he's hurting it
+ ImpactCreateHurtShards( vecOrigin, tr, vecShotDir, iMaterial, false, bBlood );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Impact for:
+// Plasma hitting targets that CAN be hurt
+//-----------------------------------------------------------------------------
+void ImpactPlasmaCallback( const CEffectData &data )
+{
+ MakePlasmaHurt( data, true );
+}
+
+DECLARE_CLIENT_EFFECT( "PlasmaHurt", ImpactPlasmaCallback );
+
+//-----------------------------------------------------------------------------
+// Purpose: Impact for:
+// Plasma hitting targets that CAN be hurt
+//-----------------------------------------------------------------------------
+void ImpactPlasmaNoBloodCallback( const CEffectData &data )
+{
+ MakePlasmaHurt( data, false );
+}
+
+DECLARE_CLIENT_EFFECT( "PlasmaHurtNoBlood", ImpactPlasmaNoBloodCallback );
+
+//-----------------------------------------------------------------------------
+// Purpose: Impact for:
+// Plasma hitting targets that CANNOT be hurt
+//-----------------------------------------------------------------------------
+void ImpactPlasmaUnhurtCallback( 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, play our splash
+
+ bool bShouldDecal = !( pEntity && pEntity->IsPlayer() );
+ if ( Impact( vecOrigin, vecStart, iMaterial, iDamageType, iHitbox, pEntity, tr, bShouldDecal ? 0 : IMPACT_NODECAL ) )
+ {
+ g_pEffects->EnergySplash( vecOrigin, tr.plane.normal, false );
+ }
+}
+
+DECLARE_CLIENT_EFFECT( "PlasmaUnhurt", ImpactPlasmaUnhurtCallback );
+
+//-----------------------------------------------------------------------------
+// Purpose: Impact for:
+// Plasma hitting player's handheld shields
+//-----------------------------------------------------------------------------
+void ImpactPlasmaShieldCallback( const CEffectData &data )
+{
+ trace_t tr;
+ Vector vecOrigin, vecStart, vecShotDir;
+ int iMaterial, iDamageType, iHitbox;
+ short nSurfaceProp;
+ ParseImpactData( data, &vecOrigin, &vecStart, &vecShotDir, nSurfaceProp, iMaterial, iDamageType, iHitbox );
+
+ // Bounce sparks away from the shield
+ // Don't call Impact() because we don't want to decal the player
+ Vector offset = vecOrigin - ( vecShotDir * 1.0f );
+ Vector vecDir = -vecShotDir + Vector(0,0,1.5);
+ g_pEffects->Sparks( offset, 2, 2, &vecDir );
+}
+
+DECLARE_CLIENT_EFFECT( "PlasmaShield", ImpactPlasmaShieldCallback );
+
+//-----------------------------------------------------------------------------
+// Purpose: Impact for:
+// Strider hitting anything
+//-----------------------------------------------------------------------------
+void ImpactStriderCallback( 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, play our splash
+ if ( Impact( vecOrigin, vecStart, iMaterial, iDamageType, iHitbox, pEntity, tr ) )
+ {
+ PerformCustomEffects( vecOrigin, tr, vecShotDir, iMaterial, 5 );
+ }
+}
+
+DECLARE_CLIENT_EFFECT( "Strider", ImpactStriderCallback );
+
+
+//=====================================================================================
+// SHARDS.
+// Models for small impact tempents (not vphysics simulated)
+//--------------------------------------------------------------------
+// WOOD
+//--------------------------------------------------------------------
+#define WOOD_SHARDS 5
+const char *ImpactHurtShards_Wood_Small_Models[ WOOD_SHARDS ] =
+{
+"models/props_debris/wood_shard_001.mdl",
+"models/props_debris/wood_shard_002.mdl",
+"models/props_debris/wood_shard_003.mdl",
+"models/props_debris/wood_shard_004.mdl",
+"models/props_debris/wood_shard_005.mdl",
+};
+// Model pointers for the above
+model_t *ImpactHurtShards_Wood_Small[ WOOD_SHARDS ];
+
+//--------------------------------------------------------------------
+// FOLIAGE
+//--------------------------------------------------------------------
+#define FOLIAGE_SHARDS 5
+const char *ImpactHurtShards_Foliage_Small_Models[ FOLIAGE_SHARDS ] =
+{
+"models/props_debris/foliage_shard_001.mdl",
+"models/props_debris/foliage_shard_002.mdl",
+"models/props_debris/foliage_shard_003.mdl",
+"models/props_debris/foliage_shard_004.mdl",
+"models/props_debris/foliage_shard_005.mdl",
+};
+// Model pointers for the above
+model_t *ImpactHurtShards_Foliage_Small[ FOLIAGE_SHARDS ];
+
+//--------------------------------------------------------------------
+// CONCRETE
+//--------------------------------------------------------------------
+#define CONCRETE_SHARDS 1
+const char *ImpactHurtShards_Concrete_Small_Models[ CONCRETE_SHARDS ] =
+{
+"models/props_debris/metal_shard_001.mdl",
+};
+// Model pointers for the above
+model_t *ImpactHurtShards_Concrete_Small[ CONCRETE_SHARDS ];
+
+//--------------------------------------------------------------------
+// METAL
+//--------------------------------------------------------------------
+#define METAL_SHARDS 6
+const char *ImpactHurtShards_Metal_Small_Models[ METAL_SHARDS ] =
+{
+"models/props_debris/metal_shard_001.mdl",
+"models/props_debris/metal_shard_002.mdl",
+"models/props_debris/metal_shard_003.mdl",
+"models/props_debris/metal_shard_004.mdl",
+"models/props_debris/metal_shard_005.mdl",
+"models/props_debris/metal_shard_006.mdl",
+};
+// Model pointers for the above
+model_t *ImpactHurtShards_Metal_Small[ METAL_SHARDS ];
+
+//-----------------------------------------------------------------------------
+// Purpose: Precache all our shards
+//-----------------------------------------------------------------------------
+void PrecacheImpactShards(void *pUser)
+{
+ int i;
+
+ // Wood
+ for ( i = 0; i < WOOD_SHARDS; i++ )
+ {
+ const char *sFile = ImpactHurtShards_Wood_Small_Models[i];
+ ImpactHurtShards_Wood_Small[i] = (model_t *)engine->LoadModel( sFile );
+ }
+
+ // Foliage
+ for ( i = 0; i < FOLIAGE_SHARDS; i++ )
+ {
+ const char *sFile = ImpactHurtShards_Foliage_Small_Models[i];
+ ImpactHurtShards_Foliage_Small[i] = (model_t *)engine->LoadModel( sFile );
+ }
+
+ // Concrete
+ for ( i = 0; i < CONCRETE_SHARDS; i++ )
+ {
+ const char *sFile = ImpactHurtShards_Concrete_Small_Models[i];
+ ImpactHurtShards_Concrete_Small[i] = (model_t *)engine->LoadModel( sFile );
+ }
+
+ // Metal
+ for ( i = 0; i < METAL_SHARDS; i++ )
+ {
+ const char *sFile = ImpactHurtShards_Metal_Small_Models[i];
+ ImpactHurtShards_Metal_Small[i] = (model_t *)engine->LoadModel( sFile );
+ }
+}
+PRECACHE_REGISTER_FN(PrecacheImpactShards);
+
+//-----------------------------------------------------------------------------
+// Purpose: Throw out shards from the impact point to show we can hurt the target
+//-----------------------------------------------------------------------------
+void ImpactCreateHurtShards( Vector &vecOrigin, trace_t &tr, Vector &shotDir, int iMaterial, bool bLarge, bool bBlood )
+{
+ // Throw out the effect if any of these are true
+ if ( tr.surface.flags & (SURF_SKY|SURF_NODRAW|SURF_HINT|SURF_SKIP) )
+ return;
+
+ float flShardSpread = 0.5;
+
+ Vector vecSpawnOrigin = vecOrigin;
+
+ int iNumGibs = random->RandomInt( 1, 2 );
+ for ( int i = 0; i < iNumGibs; i++ )
+ {
+ QAngle vecAngles;
+ vecAngles[0] = random->RandomFloat(-255, 255);
+ vecAngles[1] = random->RandomFloat(-255, 255);
+ vecAngles[2] = random->RandomFloat(-255, 255);
+ Vector vecForceDir;
+ float spreadOfs = random->RandomFloat( 3.0f, 4.0f );
+ vecForceDir[0] = -shotDir[0] + random->RandomFloat( -(flShardSpread*spreadOfs), (flShardSpread*spreadOfs) );
+ vecForceDir[1] = -shotDir[1] + random->RandomFloat( -(flShardSpread*spreadOfs), (flShardSpread*spreadOfs) );
+ vecForceDir[2] = -shotDir[2] + random->RandomFloat( -(flShardSpread*spreadOfs), (flShardSpread*spreadOfs) );
+ // Add some extra vertical height
+ vecForceDir[2] += random->RandomFloat( 0, 5 );
+ vecForceDir *= random->RandomFloat( 30.0,60.0 );
+
+ model_t *pModel = NULL;
+ int iFlags = ( FTENT_COLLIDEWORLD | FTENT_FADEOUT | FTENT_GRAVITY );
+
+ // Select the right chunk for the job
+ switch ( iMaterial )
+ {
+ case CHAR_TEX_WOOD:
+ iFlags |= FTENT_ROTATE;
+ pModel = ImpactHurtShards_Wood_Small[ random->RandomInt(0,WOOD_SHARDS-1) ];
+ break;
+
+ case CHAR_TEX_FOLIAGE:
+ pModel = ImpactHurtShards_Foliage_Small[ random->RandomInt(0,FOLIAGE_SHARDS-1) ];
+ break;
+
+ case CHAR_TEX_METAL:
+ case CHAR_TEX_VENT:
+ case CHAR_TEX_GRATE:
+
+ case CHAR_TEX_CONCRETE:
+ default:
+ pModel = ImpactHurtShards_Metal_Small[ random->RandomInt(0,METAL_SHARDS-1) ];
+ break;
+
+ case CHAR_TEX_FLESH:
+ // Spray some blood out
+ if ( !bBlood )
+ return;
+
+ CEffectData data;
+ data.m_vOrigin = vecOrigin;
+ data.m_vNormal = tr.plane.normal;
+ data.m_flScale = 4;
+ data.m_fFlags = FX_BLOODSPRAY_ALL;
+ data.m_nEntIndex = tr.m_pEnt ? tr.m_pEnt->entindex() : 0;
+ DispatchEffect( "tf2blood", data );
+ return;
+ break;
+ /*
+ case CHAR_TEX_CONCRETE:
+ default:
+ pModel = ImpactHurtShards_Concrete_Small[ random->RandomInt(0,CONCRETE_SHARDS-1) ];
+ break;
+ */
+ }
+ Assert( pModel );
+
+ // ROBIN: Removed until optimized
+ return;
+
+ // Throw it out
+ tempents->SpawnTempModel( pModel, vecSpawnOrigin, vecAngles, vecForceDir, random->RandomFloat(0.5,1.5), iFlags );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Throw out breakable, vphysics gibs from the surface we hit
+//-----------------------------------------------------------------------------
+void ImpactCreateHurtGibs( Vector &vecOrigin, trace_t &tr, Vector &shotDir, int iMaterial, bool bLarge )
+{
+ // Throw out the effect if any of these are true
+ if ( tr.surface.flags & (SURF_SKY|SURF_NODRAW|SURF_HINT|SURF_SKIP) )
+ return;
+
+ Vector vecSpawnOrigin = vecOrigin - (shotDir * 32);
+ float flGibSpread = 0.8;
+
+ // Custom TF2 impact effects
+ if ( iMaterial == CHAR_TEX_FOLIAGE )
+ {
+ int iNumGibs = random->RandomInt( 1, 2 );
+ for ( int i = 0; i < iNumGibs; i++ )
+ {
+ AngularImpulse angVel;
+ angVel.Random( -400.0f, 400.0f );
+ Vector vecForceDir;
+ float spreadOfs = random->RandomFloat( 3.0f, 4.0f );
+ vecForceDir[0] = -shotDir[0] + random->RandomFloat( -(flGibSpread*spreadOfs), (flGibSpread*spreadOfs) );
+ vecForceDir[1] = -shotDir[1] + random->RandomFloat( -(flGibSpread*spreadOfs), (flGibSpread*spreadOfs) );
+ vecForceDir[2] = -shotDir[2] + random->RandomFloat( -(flGibSpread*spreadOfs), (flGibSpread*spreadOfs) );
+ // Add some extra vertical height
+ vecForceDir[2] += 5;
+ vecForceDir *= random->RandomFloat( 10.0,30.0 );
+
+ //C_BreakableProp *pProp = new C_BreakableProp;
+ //pProp->CreateClientsideProp( ImpactHurtGibs_Wood_Small[ random->RandomInt(0,NUM_WOOD_GIBS_SMALL-1) ], vecSpawnOrigin, vecForceDir, angVel );
+ }
+ }
+ else
+ {
+ PerformCustomEffects( vecOrigin, tr, shotDir, iMaterial, 1 );
+ }
+}
diff --git a/game/client/tf2/fx_tf2_tracers.cpp b/game/client/tf2/fx_tf2_tracers.cpp
new file mode 100644
index 0000000..b91552b
--- /dev/null
+++ b/game/client/tf2/fx_tf2_tracers.cpp
@@ -0,0 +1,105 @@
+//========= 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 "clienteffectprecachesystem.h"
+#include "clientsideeffects.h"
+
+// Precache the effects
+CLIENTEFFECT_REGISTER_BEGIN( PrecacheTF2TracerEffects )
+CLIENTEFFECT_MATERIAL( "effects/human_bullet" )
+CLIENTEFFECT_MATERIAL( "effects/alien_laser" )
+CLIENTEFFECT_REGISTER_END()
+
+Vector GetTracerOrigin( const CEffectData &data );
+
+//-----------------------------------------------------------------------------
+// Purpose: Human's laser rifle Tracer
+//-----------------------------------------------------------------------------
+void HLaserTracerCallback( const CEffectData &data )
+{
+ float flVelocity = data.m_flScale;
+ Vector vecStart = GetTracerOrigin( data );
+ Vector vecEnd = data.m_vOrigin;
+ Vector shotDir;
+
+ // Get out shot direction and length
+ VectorSubtract( vecEnd, vecStart, shotDir );
+ float totalDist = VectorNormalize( shotDir );
+
+ // Don't make small tracers
+ if ( totalDist <= 32 )
+ return;
+
+ float length = MAX( 64, random->RandomFloat( 200.0f, 256.0f ) );
+ flVelocity = random->RandomFloat( 5000, 7000 );
+ float life = ( totalDist + length ) / flVelocity;
+ float flWidth = random->RandomFloat( 2.0, 2.5 );
+
+ // Add it
+ FX_AddDiscreetLine( vecStart, shotDir, flVelocity, length, totalDist, flWidth, life, "effects/human_bullet" );
+}
+
+DECLARE_CLIENT_EFFECT( "HLaserTracer", HLaserTracerCallback );
+
+//-----------------------------------------------------------------------------
+// Purpose: Alien's laser rifle Tracer
+//-----------------------------------------------------------------------------
+void ALaserTracerCallback( const CEffectData &data )
+{
+ float flVelocity = data.m_flScale;
+ Vector vecStart = GetTracerOrigin( data );
+ Vector vecEnd = data.m_vOrigin;
+ Vector shotDir;
+
+ // Get out shot direction and length
+ VectorSubtract( vecEnd, vecStart, shotDir );
+ float totalDist = VectorNormalize( shotDir );
+
+ // Don't make small tracers
+ if ( totalDist <= 32 )
+ return;
+
+ float length = MAX( 64, random->RandomFloat( 512.0f, 768.0f ) );
+ flVelocity = random->RandomFloat( 5000, 7000 );
+ float life = ( totalDist + length ) / flVelocity;
+ float flWidth = random->RandomFloat( 2.0, 3.0 );
+
+ // Add it
+ FX_AddDiscreetLine( vecStart, shotDir, flVelocity, length, totalDist, flWidth, life, "effects/alien_laser" );
+}
+
+DECLARE_CLIENT_EFFECT( "ALaserTracer", ALaserTracerCallback );
+
+//-----------------------------------------------------------------------------
+// Purpose: Alien's minigun tracer
+//-----------------------------------------------------------------------------
+void MinigunTracerCallback( const CEffectData &data )
+{
+ float flVelocity = data.m_flScale;
+ Vector vecStart = GetTracerOrigin( data );
+ Vector vecEnd = data.m_vOrigin;
+ Vector shotDir;
+
+ // Get out shot direction and length
+ VectorSubtract( vecEnd, vecStart, shotDir );
+ float totalDist = VectorNormalize( shotDir );
+
+ // Don't make small tracers
+ if ( totalDist <= 32 )
+ return;
+
+ float length = MAX( 64, random->RandomFloat( 200.0f, 256.0f ) );
+ flVelocity = random->RandomFloat( 5000, 7000 );
+ float life = ( totalDist + length ) / flVelocity;
+ float flWidth = random->RandomFloat( 1.5, 2.0 );
+
+ // Add it
+ FX_AddDiscreetLine( vecStart, shotDir, flVelocity, length, totalDist, flWidth, life, "effects/alien_laser" );
+}
+
+DECLARE_CLIENT_EFFECT( "MinigunTracer", MinigunTracerCallback );
diff --git a/game/client/tf2/ground_line.cpp b/game/client/tf2/ground_line.cpp
new file mode 100644
index 0000000..b59cb33
--- /dev/null
+++ b/game/client/tf2/ground_line.cpp
@@ -0,0 +1,418 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+#include "cbase.h"
+#include "ground_line.h"
+#include "mathlib/vplane.h"
+#include "beamdraw.h"
+#include "bitvec.h"
+#include "clientmode_commander.h"
+#include <vgui_controls/Controls.h>
+#include <vgui/ISurface.h>
+#include "clienteffectprecachesystem.h"
+#include "tier0/vprof.h"
+
+#define MAX_DOWN_DIST 300
+#define MAX_UP_DIST 300
+#define XY_PER_SEGMENT 100
+
+CLIENTEFFECT_REGISTER_BEGIN( PrecacheGroundLine )
+CLIENTEFFECT_MATERIAL( "player/support/mortarline" )
+CLIENTEFFECT_REGISTER_END()
+
+static CUtlLinkedList< CGroundLine*, unsigned short > s_GroundLines;
+
+// ---------------------------------------------------------------------- //
+// Helpers.
+// ---------------------------------------------------------------------- //
+
+VPlane VPlaneFromCPlane(const cplane_t &plane)
+{
+ if(plane.signbits)
+ return VPlane(-plane.normal, -plane.dist);
+ else
+ return VPlane(plane.normal, plane.dist);
+}
+
+
+Vector ClipEndPos(const Vector &vStart, const Vector &vEnd, float clipDist, VPlane *pPlane)
+{
+ trace_t trace;
+
+ UTIL_TraceLine(vStart, vEnd, MASK_SOLID_BRUSHONLY, NULL, COLLISION_GROUP_NONE, &trace);
+ if(trace.fraction < 1)
+ {
+ *pPlane = VPlaneFromCPlane(trace.plane);
+ return trace.endpos + pPlane->m_Normal * clipDist;
+ }
+ else
+ {
+ pPlane->m_Normal.Init(0,0,1);
+ pPlane->m_Dist = DotProduct(pPlane->m_Normal, vEnd);
+ return vEnd;
+ }
+}
+
+// Tries to find the closest surface point to the specified point.
+Vector FindBestSurfacePoint(const Vector &vPos)
+{
+ static float stepDist = 500;
+ static float flHeightAboveGround = 20;
+
+ // First, find an inside point.
+
+ // Test upwards.
+ trace_t trace;
+ UTIL_TraceLine(
+ Vector(vPos[0], vPos[1], vPos[2] + stepDist),
+ vPos,
+ MASK_SOLID_BRUSHONLY,
+ NULL,
+ COLLISION_GROUP_NONE,
+ &trace);
+ if(trace.fraction < 1 && trace.fraction != 0)
+ {
+ return Vector(trace.endpos[0], trace.endpos[1], trace.endpos[2] + flHeightAboveGround );
+ }
+
+ // Test down.
+ UTIL_TraceLine(
+ vPos,
+ Vector(vPos[0], vPos[1], vPos[2] - stepDist),
+ MASK_SOLID_BRUSHONLY,
+ NULL,
+ COLLISION_GROUP_NONE,
+ &trace);
+ if(trace.fraction < 1 && trace.fraction != 0)
+ {
+ return Vector(trace.endpos[0], trace.endpos[1], trace.endpos[2] + flHeightAboveGround );
+ }
+
+ return vPos;
+}
+
+
+// Tries to find the place in the world geometry which blocks vStart from the line segment (vEnd1, vEnd2).
+// Uses a binary search so your error is |vEnd2 - vEnd1| ^ (1 / nIterations)
+bool BinSearchSegments(const Vector &vStart, const Vector &vEnd1, const Vector &vEnd2, int nIterations, Vector *out)
+{
+ trace_t trace;
+
+ // If what was passed into us already intersects then there's nothing we can do.
+ UTIL_TraceLine(vStart, vEnd2, MASK_SOLID_BRUSHONLY, NULL, COLLISION_GROUP_NONE, &trace);
+ if(trace.fraction < 1)
+ return false;
+
+ Vector vecs[2] = {vEnd1, vEnd2};
+ int iIntersect = 0; // Which vector intersects.
+ for(int i=0; i < nIterations; i++)
+ {
+ // Test the midpoint.
+ Vector mid = (vecs[0] + vecs[1]) * 0.5f;
+ UTIL_TraceLine(vStart, mid, MASK_SOLID_BRUSHONLY, NULL, COLLISION_GROUP_NONE, &trace);
+ if(trace.fraction < 1)
+ vecs[iIntersect] = mid;
+ else
+ vecs[!iIntersect] = mid;
+ }
+
+ *out = (vecs[0] + vecs[1]) * 0.5f;
+ return true;
+}
+
+// Tries to snap the point to its underlying plane's z.
+Vector SnapToPlane(const Vector &v)
+{
+return v;
+
+ trace_t trace;
+ UTIL_TraceLine(Vector(v[0], v[1], v[2] + 50), Vector(v[0], v[1], v[2] - 50),
+ MASK_SOLID_BRUSHONLY, NULL, COLLISION_GROUP_NONE, &trace);
+ if(trace.fraction < 1)
+ return Vector(v[0], v[1], trace.endpos[2] + 3);
+ else
+ return v;
+}
+
+
+
+// ---------------------------------------------------------------------- //
+// CGroundLine implementation.
+// ---------------------------------------------------------------------- //
+
+CGroundLine::CGroundLine()
+: BaseClass( NULL, "CGroundLine" )
+{
+ m_pMaterial = NULL;
+
+ m_ListHandle = s_GroundLines.AddToHead( this );
+ SetParent( CMinimapPanel::MinimapRootPanel() );
+
+ m_nPoints = 0;
+ SetVisible( true );
+ SetPaintBackgroundEnabled( false );
+}
+
+
+CGroundLine::~CGroundLine()
+{
+ s_GroundLines.Remove( m_ListHandle );
+
+ m_vStart.Init();
+ m_vEnd.Init();
+ m_LineWidth = 1;
+}
+
+
+bool CGroundLine::Init(const char *pMaterialName)
+{
+ m_pMaterial = materials->FindMaterial(pMaterialName, TEXTURE_GROUP_CLIENT_EFFECTS);
+ return !!m_pMaterial;
+}
+
+
+void CGroundLine::SetParameters(
+ const Vector &vStart,
+ const Vector &vEnd,
+ const Vector &vStartColor, // Color values 0-1
+ const Vector &vEndColor,
+ float alpha,
+ float lineWidth
+ )
+{
+ m_vStart = vStart;
+ m_vEnd = vEnd;
+ m_vStartColor = vStartColor;
+ m_vEndColor = vEndColor;
+ m_Alpha = alpha;
+ m_LineWidth = lineWidth;
+
+ Vector vTo( vEnd.x - vStart.x, vEnd.y - vStart.y, 0 );
+ float flXYLen = vTo.Length();
+
+ // Recalculate our segment list.
+ unsigned int nSteps = (int)flXYLen / XY_PER_SEGMENT;
+ nSteps = clamp( nSteps, 8, MAX_GROUNDLINE_SEGMENTS ) & ~1;
+ unsigned int nMaxSteps = nSteps / 2;
+
+ // First generate the sequence. We generate every other point here so it can insert fixup points to prevent
+ // it from crossing world geometry.
+ Vector pt[MAX_GROUNDLINE_SEGMENTS];
+ Vector vStep = (Vector(m_vEnd[0], m_vEnd[1], 0) - Vector(m_vStart[0], m_vStart[1], 0)) / (nMaxSteps-1);
+
+ pt[0] = FindBestSurfacePoint(m_vStart);
+
+ unsigned int i;
+ for(i=1; i < nMaxSteps; i++)
+ pt[i<<1] = FindBestSurfacePoint(pt[(i-1)<<1] + vStep);
+
+
+ CBitVec<MAX_GROUNDLINE_SEGMENTS> pointsUsed;
+ pointsUsed.ClearAll();
+
+ // Now try to make sure they don't intersect the geometry.
+ for(i=0; i < nMaxSteps-1; i++)
+ {
+ Vector &a = pt[i<<1];
+ Vector &b = pt[(i+1)<<1];
+
+ trace_t trace;
+ UTIL_TraceLine(a, b, MASK_SOLID_BRUSHONLY, NULL, COLLISION_GROUP_NONE, &trace);
+ if(trace.fraction < 1)
+ {
+ int cIndex = (i<<1)+1;
+ Vector &c = pt[cIndex];
+
+ // Ok, this line segment intersects the world. Do a binary search to try to find the
+ // point of intersection.
+ Vector hi, lo;
+ if(a.z < b.z)
+ {
+ hi = b;
+ lo = a;
+ }
+ else
+ {
+ hi = a;
+ lo = b;
+ }
+
+ if(BinSearchSegments(lo, hi, Vector(lo[0],lo[1],hi[2]), 15, &c))
+ {
+ pointsUsed.Set( cIndex );
+ }
+ else if(BinSearchSegments(lo, hi, Vector(hi[0],hi[1],hi[2]+500), 15, &c))
+ {
+ pointsUsed.Set( cIndex );
+ }
+ }
+ }
+
+ // Export the points.
+ m_nPoints = 0;
+ for(i=0; i < nSteps; i++)
+ {
+ // Every other point is always active.
+ if( pointsUsed.Get( i ) || !(i & 1) )
+ {
+ m_Points[m_nPoints] = pt[i];
+ ++m_nPoints;
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Set the visibility of the groundline
+//-----------------------------------------------------------------------------
+void CGroundLine::SetVisible( bool bVisible )
+{
+ m_bVisible = bVisible;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Return true if the groundline's visible
+//-----------------------------------------------------------------------------
+bool CGroundLine::IsVisible( void )
+{
+ return m_bVisible;
+}
+
+void CGroundLine::DrawAllGroundLines()
+{
+ VPROF("CGroundLine::DrawAllGroundLines()");
+ unsigned short i;
+ for( i = s_GroundLines.Head(); i != s_GroundLines.InvalidIndex(); i = s_GroundLines.Next(i) )
+ {
+ s_GroundLines[i]->Draw();
+ }
+}
+
+void CGroundLine::Draw()
+{
+ if ( !m_pMaterial || m_nPoints < 2 )
+ return;
+ if ( !IsVisible() )
+ return;
+
+ float flAlpha = m_Alpha;
+ if( g_pClientMode == ClientModeCommander() )
+ {
+ flAlpha = 1; // draw bright..
+ }
+
+ CBeamSegDraw beamDraw;
+ beamDraw.Start( m_nPoints, m_pMaterial );
+
+ for( unsigned int i=0; i < m_nPoints; i++ )
+ {
+ float t = (float)i / (m_nPoints - 1);
+
+ CBeamSeg seg;
+ seg.m_vPos = m_Points[i];
+ VectorLerp( m_vStartColor, m_vEndColor, t, seg.m_vColor );
+ seg.m_flTexCoord = 0;
+ seg.m_flWidth = m_LineWidth;
+ seg.m_flAlpha = m_Alpha;
+
+ beamDraw.NextSeg( &seg );
+ }
+
+ beamDraw.End();
+}
+
+
+static inline bool ClipLine( float &x1, float &y1, float &x2, float &y2, float xClip, float sign )
+{
+ if( x1*sign < (xClip-0.001f)*sign )
+ {
+ if( x2*sign > (xClip+0.001f)*sign )
+ {
+ float t = (xClip-x1) / (x2 - x1);
+ x1 = x1 + (x2 - x1) * t;
+ y1 = y1 + (y2 - y1) * t;
+ }
+ else
+ {
+ return false;
+ }
+ }
+ else if( x2*sign < (xClip-0.001f)*sign )
+ {
+ if( x1*sign > (xClip+0.001f)*sign )
+ {
+ float t = (xClip-x1) / (x2 - x1);
+ x2 = x1 + (x2 - x1) * t;
+ y2 = y1 + (y2 - y1) * t;
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+
+void CGroundLine::Paint( )
+{
+ vgui::Panel *pPanel = GetParent();
+ int wide, tall;
+ pPanel->GetSize( wide, tall );
+
+ float tPrev = 0;
+ float xPrev, yPrev;
+ CMinimapPanel::MinimapPanel()->WorldToMinimap( MINIMAP_NOCLIP, m_vStart, xPrev, yPrev );
+
+ int nSegs = 20;
+ for( int iSeg=1; iSeg <= nSegs; iSeg++ )
+ {
+ float t = (float)iSeg / nSegs;
+
+ Vector v3DPos;
+ VectorLerp( m_vStart, m_vEnd, t, v3DPos );
+
+ float x, y;
+ CMinimapPanel::MinimapPanel()->WorldToMinimap( MINIMAP_NOCLIP, v3DPos, x, y );
+
+ // Clip the line segment on X, then Y.
+ if( ClipLine( xPrev, yPrev, x, y, 0, 1 ) &&
+ ClipLine( xPrev, yPrev, x, y, wide, -1 ) &&
+ ClipLine( yPrev, xPrev, y, x, 0, 1 ) &&
+ ClipLine( yPrev, xPrev, y, x, tall, -1 ) )
+ {
+ Vector vColor;
+ VectorLerp( m_vStartColor, m_vEndColor, t, vColor );
+ vColor *= 255.9f;
+
+ vgui::surface()->DrawSetColor(
+ (unsigned char)RoundFloatToInt( vColor.x ),
+ (unsigned char)RoundFloatToInt( vColor.y ),
+ (unsigned char)RoundFloatToInt( vColor.z ),
+ 255 );
+
+ vgui::surface()->DrawLine( xPrev, yPrev, x, y );
+ }
+
+ tPrev = t;
+ xPrev = x;
+ yPrev = y;
+ }
+
+ // Draw a marker at the endpoint.
+ float xEnd, yEnd;
+ if( CMinimapPanel::MinimapPanel()->WorldToMinimap( MINIMAP_NOCLIP, m_vEnd, xEnd, yEnd ) )
+ {
+ int ix = RoundFloatToInt( xEnd );
+ int iy = RoundFloatToInt( yEnd );
+ int rectSize=1;
+
+ vgui::surface()->DrawSetColor( 255, 255, 255, 255 );
+ vgui::surface()->DrawOutlinedRect( ix-rectSize, iy-rectSize, ix+rectSize, iy+rectSize );
+ }
+}
+
+
diff --git a/game/client/tf2/ground_line.h b/game/client/tf2/ground_line.h
new file mode 100644
index 0000000..4164977
--- /dev/null
+++ b/game/client/tf2/ground_line.h
@@ -0,0 +1,80 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef GROUND_LINE_H
+#define GROUND_LINE_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+
+#include "mathlib/vector.h"
+#include "hud_minimap.h"
+
+
+class IMaterial;
+
+
+#define MAX_GROUNDLINE_SEGMENTS 100
+
+
+// This class will lay out a line of a specified width along the ground. It follows
+// the contour of the ground as well as it can.
+class CGroundLine : public vgui::Panel
+{
+ typedef vgui::Panel BaseClass;
+
+public:
+ CGroundLine();
+ ~CGroundLine();
+
+ // One-time initialization.
+ bool Init(const char *pMaterialName);
+
+ // Setup the line's rendering parameters.
+ void SetParameters(
+ const Vector &vStart,
+ const Vector &vEnd,
+ const Vector &vStartColor, // Color values 0-1
+ const Vector &vEndColor, // Color values 0-1
+ float alpha,
+ float lineWidth
+ );
+
+ // Called by the renderer when it's time to render the ground lines.
+ static void DrawAllGroundLines();
+
+ // Set the visibility
+ void SetVisible( bool bVisible );
+ bool IsVisible( void );
+
+private:
+
+ // Draw a line along the ground.
+ void Draw();
+ void Paint();
+
+private:
+ // Rendering parameters.
+ IMaterial *m_pMaterial;
+ Vector m_vStartColor;
+ Vector m_vEndColor;
+ float m_Alpha;
+ Vector m_vStart;
+ Vector m_vEnd;
+ float m_LineWidth;
+ bool m_bVisible;
+
+ // Points along the line.
+ Vector m_Points[MAX_GROUNDLINE_SEGMENTS];
+ unsigned int m_nPoints;
+
+ unsigned short m_ListHandle;
+};
+
+
+#endif // GROUND_LINE_H
diff --git a/game/client/tf2/hintitembase.cpp b/game/client/tf2/hintitembase.cpp
new file mode 100644
index 0000000..e098306
--- /dev/null
+++ b/game/client/tf2/hintitembase.cpp
@@ -0,0 +1,425 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+#include "cbase.h"
+#include "hintitembase.h"
+#include <vgui_controls/Controls.h>
+#include <vgui_controls/Label.h>
+#include <vgui/IVGui.h>
+#include <vgui/ISurface.h>
+#include <vgui/IScheme.h>
+#include <vgui/ILocalize.h>
+#include <KeyValues.h>
+#include "PanelEffect.h"
+
+//-----------------------------------------------------------------------------
+// Purpose: Constructor
+// Input : *parent -
+// *panelName -
+// *text -
+// itemwidth -
+//-----------------------------------------------------------------------------
+CHintItemBase::CHintItemBase( vgui::Panel *parent, const char *panelName )
+: BaseClass( parent, panelName ), m_pObject( NULL )
+{
+ m_pLabel = new vgui::Label( this, "TFTextHint", "" );
+ m_pLabel->SetContentAlignment( vgui::Label::a_west );
+
+ // m_pIndex = new vgui::Label( this, "TFTextHintIndex", "" );
+ // m_pIndex->setContentAlignment( vgui::Label::a_west );
+ // m_pIndex->SetBounds( 20, 0, 20, 20 );
+ // m_nIndex = 0;
+
+ m_bCompleted = false;
+ m_bActive = false;
+ m_flActivateTime = 0.0f;
+
+ vgui::ivgui()->AddTickSignal( GetVPanel() );
+
+ SetFormatString( "" );
+
+ m_bAutoComplete = false;
+ m_flAutoCompleteTime = 0.0f;
+
+ m_hSmallFont = m_hMarlettFont = 0;
+}
+
+
+//-----------------------------------------------------------------------------
+// Scheme settings
+//-----------------------------------------------------------------------------
+void CHintItemBase::ApplySchemeSettings(vgui::IScheme *pScheme)
+{
+ BaseClass::ApplySchemeSettings(pScheme);
+
+ m_hSmallFont = pScheme->GetFont( "DefaultVerySmall" );
+ m_hMarlettFont = pScheme->GetFont( "Marlett" );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *pKeyValues -
+//-----------------------------------------------------------------------------
+void CHintItemBase::ParseItem( KeyValues *pKeyValues )
+{
+ if ( !pKeyValues )
+ return;
+
+ const char *title = pKeyValues->GetString( "title", "" );
+ if ( title )
+ {
+ SetText( title );
+ }
+
+ const char *fmt = pKeyValues->GetString( "formatstring", "" );
+ if ( fmt )
+ {
+ SetFormatString( fmt );
+ }
+
+ const char *autocomplete = pKeyValues->GetString( "autocomplete" );
+ if ( autocomplete && autocomplete[ 0 ] )
+ {
+ SetAutoComplete( ( float ) atof( autocomplete ) );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : elapsed_time -
+//-----------------------------------------------------------------------------
+void CHintItemBase::SetAutoComplete( float elapsed_time )
+{
+ m_bAutoComplete = true;
+ m_flAutoCompleteTime = elapsed_time;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : newWide -
+// newTall -
+//-----------------------------------------------------------------------------
+void CHintItemBase::OnSizeChanged( int newWide, int newTall )
+{
+ m_pLabel->SetBounds( 20, 0, GetWide() - 20, newTall );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *text -
+//-----------------------------------------------------------------------------
+void CHintItemBase::SetText( const char *text )
+{
+ m_pLabel->SetText( text );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *fmt -
+//-----------------------------------------------------------------------------
+void CHintItemBase::SetFormatString( const char *fmt )
+{
+ Q_strncpy( m_szFormatString, fmt, MAX_TEXT_LENGTH );
+ m_bUseFormatString = fmt[ 0 ] ? true : false;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Output : char const
+//-----------------------------------------------------------------------------
+const char *CHintItemBase::GetFormatString( void )
+{
+ Assert( m_bUseFormatString );
+ return m_szFormatString;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *instring -
+// keylength -
+// **ppOutstring -
+// Output : Returns true on success, false on failure.
+//-----------------------------------------------------------------------------
+bool CHintItemBase::CheckKeyAndValue( const char *instring, int* keylength, const char **ppOutstring )
+{
+ Assert( m_bUseFormatString );
+ return false;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CHintItemBase::ComputeTitle( void )
+{
+ if ( !m_bUseFormatString )
+ return;
+
+ char fixed[ MAX_TEXT_LENGTH ];
+
+ char *in, *out;
+ in = m_szFormatString;
+ out = fixed;
+
+ while ( *in )
+ {
+ if ( *in == '!' && *(in+1) == '!' )
+ {
+ in += 2;
+
+ int length;
+ const char *text;
+
+ if ( CheckKeyAndValue( in, &length, &text ) )
+ {
+ const char *t = text;
+ while ( *t )
+ {
+ *out++ = *t++;
+ }
+
+ in += length;
+ }
+ }
+ else
+ {
+ *out++ = *in++;
+ }
+ }
+
+ *out = 0;
+
+ SetText( fixed );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *binding -
+// Output : const char
+//-----------------------------------------------------------------------------
+const char *CHintItemBase::GetKeyNameForBinding( const char *binding )
+{
+ const char *keyname = engine->Key_LookupBinding( binding );
+ if ( keyname )
+ {
+ return keyname;
+ }
+
+ // Return original string if not bound to a key
+ return binding;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Delete's the hint object
+//-----------------------------------------------------------------------------
+void CHintItemBase::DeleteThis( void )
+{
+ // Remove any associated effects
+ DestroyPanelEffects( this );
+
+ delete this;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : incolor -
+// frac -
+// Output : static int
+//-----------------------------------------------------------------------------
+static int TextHintColorMod( int incolor, float frac )
+{
+ int maxcolor = incolor + (int)( ( 255.0f - (float)incolor ) / 2.0f );
+ int midcolor = ( maxcolor + incolor ) / 2;
+ int range = maxcolor - midcolor;
+
+ int clr = midcolor + range * frac;
+
+ clr = clamp( clr, 0, 255 );
+ return clr;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CHintItemBase::PaintBackground()
+{
+ // force label color
+ if ( m_pLabel )
+ {
+ m_pLabel->SetFgColor( Color( 0, 0, 0, 255 ) );
+ m_pLabel->SetBgColor( Color( 0, 0, 0, 0 ) );
+ }
+
+ int w, h;
+
+ GetSize( w, h );
+
+ float f2 = 0.0f;
+
+ float dt = gpGlobals->curtime - m_flActivateTime;
+
+ if ( dt < 5.0f )
+ {
+ f2 = fmod( gpGlobals->curtime, 1.0f );
+ }
+
+ int r = 80;
+ int g = 105;
+ int b = 90;
+
+ vgui::surface()->DrawSetTextFont( m_hMarlettFont );
+ vgui::surface()->DrawSetTextColor( r, g, b, 255 );
+ vgui::surface()->DrawSetTextPos( 2 + 3 * f2, 3 );
+
+ wchar_t ch[2];
+ g_pVGuiLocalize->ConvertANSIToUnicode( "4", ch, sizeof( ch ) );
+ vgui::surface()->DrawPrintText( ch, 1 );
+
+ if ( m_bAutoComplete )
+ {
+ vgui::surface()->DrawSetTextColor( 0, 0, 0, 63 );
+ vgui::surface()->DrawSetTextFont( m_hSmallFont );
+
+ char sz[ 32 ];
+
+ int len = Q_snprintf( sz, sizeof( sz ), "%i", (int)( m_flAutoCompleteTime + 0.5f ) );
+
+ int x = w - len * 10 - 2;
+ int y = 6;
+
+ wchar_t szconverted[ 32 ];
+ g_pVGuiLocalize->ConvertANSIToUnicode( sz, szconverted, sizeof(szconverted) );
+
+ vgui::surface()->DrawSetTextPos( x, y );
+ vgui::surface()->DrawPrintText( szconverted, wcslen( szconverted ) );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Output : Returns true on success, false on failure.
+//-----------------------------------------------------------------------------
+bool CHintItemBase::GetCompleted( void )
+{
+ return m_bCompleted;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : active -
+//-----------------------------------------------------------------------------
+void CHintItemBase::SetActive( bool active )
+{
+ bool changed = m_bActive != active;
+
+ m_bActive = active;
+
+ if ( !changed )
+ return;
+
+ if ( m_bActive )
+ {
+ m_flActivateTime = gpGlobals->curtime;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Output : Returns true on success, false on failure.
+//-----------------------------------------------------------------------------
+bool CHintItemBase::GetActive( void )
+{
+ return m_bActive;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Output : Returns true on success, false on failure.
+//-----------------------------------------------------------------------------
+bool CHintItemBase::ShouldRenderPanelEffects( void )
+{
+ // By default, render active item's effects.
+ // A hint could have it's effects always render, though
+ return GetActive();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CHintItemBase::Think( void )
+{
+ // Check for completion
+ if ( m_bAutoComplete && GetActive() )
+ {
+ m_flAutoCompleteTime -= gpGlobals->frametime;
+ if ( m_flAutoCompleteTime <= 0.0f )
+ {
+ m_bCompleted = true;
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Output : int
+//-----------------------------------------------------------------------------
+int CHintItemBase::GetHeight( void )
+{
+ return GetTall();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : x -
+// y -
+//-----------------------------------------------------------------------------
+void CHintItemBase::SetPosition( int x, int y )
+{
+ SetPos( x, y );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : index -
+//-----------------------------------------------------------------------------
+void CHintItemBase::SetItemNumber( int index )
+{
+/*
+m_nIndex = index;
+
+ char sz[ 32 ];
+ Q_snprintf( sz, sizeof( sz ), "%i", m_nIndex );
+
+ m_pIndex->setText( sz );
+ */
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : visible -
+//-----------------------------------------------------------------------------
+void CHintItemBase::SetVisible( bool visible )
+{
+ BaseClass::SetVisible( visible );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *panel -
+//-----------------------------------------------------------------------------
+void CHintItemBase::SetHintTarget( vgui::Panel *panel )
+{
+ m_pObject = panel;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *key -
+// *value -
+//-----------------------------------------------------------------------------
+void CHintItemBase::SetKeyValue( const char *key, const char *value )
+{
+}
diff --git a/game/client/tf2/hintitembase.h b/game/client/tf2/hintitembase.h
new file mode 100644
index 0000000..78878ea
--- /dev/null
+++ b/game/client/tf2/hintitembase.h
@@ -0,0 +1,113 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef HINTITEMBASE_H
+#define HINTITEMBASE_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include <vgui_controls/Panel.h>
+#include "itfhintitem.h"
+
+class C_TFBaseHint;
+class CHintItemBase;
+
+namespace vgui
+{
+ class Label;
+}
+
+#define DECLARE_HINTITEMFACTORY( className ) \
+ CHintItemBase *Create_##className##( vgui::Panel *parent, const char *panelName ) \
+ { return new className( parent, panelName ); }
+
+#define GET_HINTITEMFACTORY_NAME( className ) Create_##className
+
+#define DECLARE_HINTFACTORY( className ) \
+ C_TFBaseHint *Create_##className##( int id, int entity ) \
+ { return new className( id, 0, entity, NULL ); }
+
+#define GET_HINTFACTORY_NAME( className ) Create_##className
+
+//-----------------------------------------------------------------------------
+// Purpose: A hint that shows up as a single line o text
+//-----------------------------------------------------------------------------
+class CHintItemBase : public vgui::Panel, public ITFHintItem
+{
+ DECLARE_CLASS_GAMEROOT( CHintItemBase, vgui::Panel );
+
+public:
+ CHintItemBase( vgui::Panel *parent, const char *panelName );
+
+ // Draw some extra stuff in the Bg
+ virtual void PaintBackground();
+ virtual void OnSizeChanged( int newWide, int newTall );
+ virtual void SetText( const char *text );
+
+ virtual void SetFormatString( const char *fmt );
+ virtual const char *GetFormatString( void );
+ // If using format string
+ virtual bool CheckKeyAndValue( const char *instring, int* keylength, const char **ppOutstring );
+ virtual void ComputeTitle( void );
+
+ virtual void SetAutoComplete( float elapsed_time );
+
+ // Scheme settings
+ virtual void ApplySchemeSettings(vgui::IScheme *pScheme);
+
+ // Helper
+ virtual const char *GetKeyNameForBinding( const char *binding );
+
+ // Implement ITFHintItem
+ virtual void ParseItem( KeyValues *pKeyValues );
+ virtual bool GetCompleted( void );
+ virtual void SetActive( bool active );
+ virtual bool GetActive( void );
+ virtual void Think( void );
+ virtual int GetHeight( void );
+ virtual void SetPosition( int x, int y );
+ virtual void DeleteThis( void );
+ virtual void SetItemNumber( int index );
+ virtual void SetVisible( bool visible );
+ virtual void SetHintTarget( vgui::Panel *panel );
+ virtual bool ShouldRenderPanelEffects( void );
+ virtual void SetKeyValue( const char *key, const char *value );
+protected:
+ enum
+ {
+ MAX_TEXT_LENGTH = 256,
+ };
+
+ // Has the hint item been completed
+ bool m_bCompleted;
+ // Is the hint item active
+ bool m_bActive;
+ // Text of hint
+ vgui::Label *m_pLabel;
+ // Depends on type of hint
+ vgui::Panel *m_pObject;
+ // Time the hint was activated
+ float m_flActivateTime;
+
+ // vgui::Label *m_pIndex;
+ // Index of hint
+ //int m_nIndex;
+
+ bool m_bUseFormatString;
+ char m_szFormatString[ MAX_TEXT_LENGTH ];
+
+ bool m_bAutoComplete;
+ float m_flAutoCompleteTime;
+
+ vgui::HFont m_hSmallFont;
+ vgui::HFont m_hMarlettFont;
+};
+
+CHintItemBase *CreateHintItem( vgui::Panel *parent, const char *name );
+
+#endif // HINTITEMBASE_H
diff --git a/game/client/tf2/hintitemobjectbase.cpp b/game/client/tf2/hintitemobjectbase.cpp
new file mode 100644
index 0000000..b5b0c5c
--- /dev/null
+++ b/game/client/tf2/hintitemobjectbase.cpp
@@ -0,0 +1,79 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+#include "cbase.h"
+#include "hintitemobjectbase.h"
+#include <KeyValues.h>
+#include "c_obj_resourcepump.h"
+#include "c_func_resource.h"
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *parent -
+// *panelName -
+//-----------------------------------------------------------------------------
+CHintItemObjectBase::CHintItemObjectBase( vgui::Panel *parent, const char *panelName )
+: BaseClass( parent, panelName )
+{
+ SetObjectType( "" );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *pKeyValues -
+//-----------------------------------------------------------------------------
+void CHintItemObjectBase::ParseItem( KeyValues *pKeyValues )
+{
+ BaseClass::ParseItem( pKeyValues );
+
+ const char *type = pKeyValues->GetString( "type", "" );
+ if ( type )
+ {
+ SetObjectType( type );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *object -
+// Output : Returns true on success, false on failure.
+//-----------------------------------------------------------------------------
+bool CHintItemObjectBase::IsObjectOfType( C_BaseEntity *object )
+{
+ if ( !stricmp( GetObjectType(), "Resource Zone" ) )
+ {
+ return dynamic_cast< C_ResourceZone *>( object ) ? true : false;
+ }
+ else if ( !stricmp( GetObjectType(), "Resource Pump" ) )
+ {
+ return dynamic_cast< C_ObjectResourcePump * >( object) ? true : false;
+ }
+ else if ( !stricmp( GetObjectType(), "BaseObject" ) )
+ {
+ return dynamic_cast< C_BaseObject * >( object) ? true : false;
+ }
+
+ return false;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *type -
+//-----------------------------------------------------------------------------
+void CHintItemObjectBase::SetObjectType( const char *type )
+{
+ Q_strncpy( m_szObjectType, type, MAX_OBJECT_TYPE );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Output : char const
+//-----------------------------------------------------------------------------
+const char *CHintItemObjectBase::GetObjectType( void )
+{
+ return m_szObjectType;
+} \ No newline at end of file
diff --git a/game/client/tf2/hintitemobjectbase.h b/game/client/tf2/hintitemobjectbase.h
new file mode 100644
index 0000000..a55fd9f
--- /dev/null
+++ b/game/client/tf2/hintitemobjectbase.h
@@ -0,0 +1,43 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef HINTITEMOBJECTBASE_H
+#define HINTITEMOBJECTBASE_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "hintitemorderbase.h"
+
+class C_BaseEntity;
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+class CHintItemObjectBase : public CHintItemOrderBase
+{
+ DECLARE_CLASS( CHintItemObjectBase, CHintItemOrderBase );
+
+public:
+ CHintItemObjectBase( vgui::Panel *parent, const char *panelName );
+
+ virtual void ParseItem( KeyValues *pKeyValues );
+ // Is the object of type m_szObjectType
+ virtual bool IsObjectOfType( C_BaseEntity *object );
+ virtual void SetObjectType( const char *type );
+ virtual char const *GetObjectType( void );
+
+private:
+ enum
+ {
+ MAX_OBJECT_TYPE = 128,
+ };
+
+ char m_szObjectType[ MAX_OBJECT_TYPE ];
+};
+
+#endif // HINTITEMOBJECTBASE_H
diff --git a/game/client/tf2/hintitemorderbase.cpp b/game/client/tf2/hintitemorderbase.cpp
new file mode 100644
index 0000000..6b3073d
--- /dev/null
+++ b/game/client/tf2/hintitemorderbase.cpp
@@ -0,0 +1,71 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+#include "cbase.h"
+#include "hintitemorderbase.h"
+#include "paneleffect.h"
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *parent -
+// *panelName -
+//-----------------------------------------------------------------------------
+CHintItemOrderBase::CHintItemOrderBase( vgui::Panel *parent, const char *panelName )
+: BaseClass( parent, panelName )
+{
+ m_bEffects = false;
+ m_LineEffect = EFFECT_INVALID_HANDLE;
+ m_FlashEffect = EFFECT_INVALID_HANDLE;
+
+ DrawAxialLineToOrder();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CHintItemOrderBase::DrawAxialLineToOrder( void )
+{
+ // Derived class already set up effects
+ if ( m_bEffects )
+ return;
+
+ m_bEffects = true;
+
+ // Flash for vote order
+ m_FlashEffect = CreateFlashEffect( this, NULL );
+ // Flash the hint panel itself
+ CreateFlashEffect( this, GetParent() );
+ // Point from hint to vote order panel
+ m_LineEffect = CreateAxialLineEffect( this, GetParent(), NULL );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *panel -
+//-----------------------------------------------------------------------------
+void CHintItemOrderBase::SetHintTarget( vgui::Panel *panel )
+{
+ BaseClass::SetHintTarget( panel );
+
+ if ( !m_bEffects )
+ return;
+
+ // Update effect target
+ if ( !panel || !g_pTF2RootPanel )
+ return;
+
+ CPanelEffect *e = g_pTF2RootPanel->FindEffect( m_LineEffect );
+ if ( e )
+ {
+ e->SetPanelOther( panel );
+ }
+
+ e = g_pTF2RootPanel->FindEffect( m_FlashEffect );
+ if ( e )
+ {
+ e->SetPanel( panel );
+ }
+} \ No newline at end of file
diff --git a/game/client/tf2/hintitemorderbase.h b/game/client/tf2/hintitemorderbase.h
new file mode 100644
index 0000000..d548c38
--- /dev/null
+++ b/game/client/tf2/hintitemorderbase.h
@@ -0,0 +1,37 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef HINTITEMORDERBASE_H
+#define HINTITEMORDERBASE_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "hintitembase.h"
+#include "c_tf2rootpanel.h"
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+class CHintItemOrderBase : public CHintItemBase
+{
+ DECLARE_CLASS( CHintItemOrderBase, CHintItemBase );
+public:
+ CHintItemOrderBase( vgui::Panel *parent, const char *panelName );
+
+ virtual void DrawAxialLineToOrder( void );
+
+ virtual void SetHintTarget( vgui::Panel *panel );
+
+protected:
+ bool m_bEffects;
+
+ EFFECT_HANDLE m_LineEffect;
+ EFFECT_HANDLE m_FlashEffect;
+};
+
+#endif // HINTITEMORDERBASE_H
diff --git a/game/client/tf2/hud_ammo.cpp b/game/client/tf2/hud_ammo.cpp
new file mode 100644
index 0000000..637a20f
--- /dev/null
+++ b/game/client/tf2/hud_ammo.cpp
@@ -0,0 +1,265 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#include "cbase.h"
+#include "hud_numeric.h"
+#include "hud_ammo.h"
+#include "hud.h"
+#include "iclientmode.h"
+#include <vgui_controls/AnimationController.h>
+#include <KeyValues.h>
+
+//-----------------------------------------------------------------------------
+// Singleton
+//-----------------------------------------------------------------------------
+static CHudAmmo g_HudAmmo;
+CHudAmmo* GetHudAmmo()
+{
+ return &g_HudAmmo;
+}
+
+
+//-----------------------------------------------------------------------------
+// Accessor methods to set various state associated with the ammo display
+//-----------------------------------------------------------------------------
+void CHudAmmo::SetPrimaryAmmo( int nAmmoType, int nTotalAmmo, int nClipCount, int nMaxClipCount )
+{
+ m_nAmmoType1 = nAmmoType;
+ m_nTotalAmmo1 = nTotalAmmo;
+ m_nMaxClip1 = nMaxClipCount;
+ m_nClip1 = nClipCount;
+}
+
+void CHudAmmo::SetSecondaryAmmo( int nAmmoType, int nTotalAmmo, int nClipCount, int nMaxClipCount )
+{
+ m_nAmmoType2 = nAmmoType;
+ m_nTotalAmmo2 = nTotalAmmo;
+ m_nMaxClip2 = nMaxClipCount;
+ m_nClip2 = nClipCount;
+}
+
+bool CHudAmmo::ShouldShowPrimaryClip() const
+{
+ if ( m_nAmmoType1 <= 0 )
+ return false;
+
+ if ( m_nClip1 < 0 )
+ return false;
+
+ return true;
+}
+
+bool CHudAmmo::ShouldShowSecondary() const
+{
+ if ( m_nAmmoType2 <= 0 )
+ return false;
+
+ if ( m_nTotalAmmo2 <= 0 )
+ return false;
+
+ return true;
+}
+
+void CHudAmmo::ShowHideHudControls()
+{
+ bool showClip = ShouldShowPrimaryClip();
+ bool showSecondary = ShouldShowSecondary();
+
+ if ( showClip )
+ {
+ if ( showSecondary )
+ {
+ g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( "ShowPrimaryAmmoClipShowSecondaryAmmo" );
+ }
+ else
+ {
+ g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( "ShowPrimaryAmmoClipHideSecondaryAmmo" );
+ }
+ }
+ else
+ {
+ if ( showSecondary )
+ {
+ g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( "HidePrimaryAmmoClipShowSecondaryAmmo" );
+ }
+ else
+ {
+ g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( "HidePrimaryAmmoClipHideSecondaryAmmo" );
+ }
+ }
+}
+
+class CHudAmmoPrimary : public CHudNumeric
+{
+ DECLARE_CLASS_SIMPLE( CHudAmmoPrimary, CHudNumeric );
+public:
+ CHudAmmoPrimary( const char *pElementName ) : CHudNumeric( pElementName, "HudAmmoPrimary" )
+ {
+ SetHiddenBits( HIDEHUD_HEALTH | HIDEHUD_PLAYERDEAD );
+ }
+
+ virtual const char *GetLabelText() { return m_szAmmoLabel; }
+ virtual const char *GetPulseEvent( bool increment ) { return increment ? "PrimaryAmmoIncrement" : "PrimaryAmmoDecrement"; }
+
+ virtual bool GetValue( char *val, int maxlen )
+ {
+ if ( GetHudAmmo()->m_nAmmoType1 <= 0 )
+ return false;
+
+ int count = ( GetHudAmmo()->m_nClip1 >= 0 ) ? GetHudAmmo()->m_nClip1 : GetHudAmmo()->m_nTotalAmmo1;
+ Q_snprintf( val, maxlen, "%i", count );
+ return true;
+ }
+
+ virtual Color GetColor()
+ {
+ // Get our ratio bar information
+ float ammoPerc = 1.0f - ( (float) GetHudAmmo()->m_nClip1 ) / ( (float) GetHudAmmo()->m_nMaxClip1 );
+ bool ammoCaution = ( ammoPerc >= CLIP_PERC_THRESHOLD );
+
+ if ( ammoCaution )
+ return m_TextColorCritical;
+
+ return m_TextColor;
+ }
+
+ virtual void ApplySchemeSettings(vgui::IScheme *scheme)
+ {
+ BaseClass::ApplySchemeSettings( scheme );
+
+ SetPaintBackgroundEnabled( true );
+ }
+
+private:
+ CPanelAnimationStringVar( 128, m_szAmmoLabel, "AmmoLabel", "Ammo" );
+};
+
+DECLARE_HUDELEMENT( CHudAmmoPrimary );
+
+class CHudAmmoPrimaryClip : public CHudNumeric
+{
+ DECLARE_CLASS_SIMPLE( CHudAmmoPrimaryClip, CHudNumeric );
+
+public:
+ CHudAmmoPrimaryClip( const char *pElementName ) : BaseClass( pElementName, "HudAmmoPrimaryClip" )
+ {
+ SetDrawLabel( false );
+
+ m_nPrevVisible = -1;
+
+ SetHiddenBits( HIDEHUD_HEALTH | HIDEHUD_PLAYERDEAD );
+ }
+
+ virtual const char *GetLabelText() { return m_szAmmoClipLabel; }
+ virtual const char *GetPulseEvent( bool increment ) { return increment ? "PrimaryAmmoClipIncrement" : "PrimaryAmmoClipDecrement"; }
+
+ virtual bool GetValue( char *val, int maxlen )
+ {
+ int iret = _GetValue( val, maxlen ) ? 1 : 0;
+
+ if ( iret != m_nPrevVisible )
+ {
+ GetHudAmmo()->ShowHideHudControls();
+ m_nPrevVisible = iret;
+ }
+
+ return true;
+ }
+
+ virtual bool _GetValue( char *val, int maxlen )
+ {
+ Q_snprintf( val, maxlen, "" );
+
+ if ( !GetHudAmmo()->ShouldShowPrimaryClip() )
+ return false;
+
+ int count = GetHudAmmo()->m_nTotalAmmo1;
+ Q_snprintf( val, maxlen, "%i", count );
+ return true;
+ }
+
+ virtual Color GetColor()
+ {
+ if ( GetHudAmmo()->ShouldShowPrimaryClip() )
+ {
+ if ( GetHudAmmo()->m_nTotalAmmo1 <= GetHudAmmo()->m_nMaxClip1 )
+ {
+ return m_TextColorCritical;
+ }
+ }
+
+ return m_TextColor;
+ }
+
+private:
+ int m_nPrevVisible;
+ CPanelAnimationStringVar( 128, m_szAmmoClipLabel, "AmmoClipLabel", "PrimaryAmmoClip" );
+};
+
+DECLARE_HUDELEMENT( CHudAmmoPrimaryClip );
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+class CHudAmmoSecondary : public CHudNumeric
+{
+ DECLARE_CLASS_SIMPLE( CHudAmmoSecondary, CHudNumeric );
+
+public:
+ CHudAmmoSecondary( const char *pElementName ) : CHudNumeric( pElementName, "HudAmmoSecondary" )
+ {
+ SetDrawLabel( false );
+
+ m_nPrevVisible = -1;
+
+ SetHiddenBits( HIDEHUD_HEALTH | HIDEHUD_PLAYERDEAD );
+ }
+
+ virtual const char *GetLabelText() { return m_szAmmoSecondaryLabel; }
+ virtual const char *GetPulseEvent( bool increment ) { return increment ? "SecondaryAmmoIncrement" : "SecondaryAmmoDecrement"; }
+
+ virtual bool GetValue( char *val, int maxlen )
+ {
+ int iret = _GetValue( val, maxlen ) ? 1 : 0;
+
+ if ( iret != m_nPrevVisible )
+ {
+ // Shift primary and clip left/right as needed
+ GetHudAmmo()->ShowHideHudControls();
+ m_nPrevVisible = iret;
+ }
+
+ return iret ? true : false;
+ }
+
+ virtual bool _GetValue( char *val, int maxlen )
+ {
+ if ( !GetHudAmmo()->ShouldShowSecondary() )
+ return false;
+
+ int count = GetHudAmmo()->m_nTotalAmmo2;
+ Q_snprintf( val, maxlen, "%i", count );
+ return true;
+ }
+
+ virtual Color GetColor()
+ {
+ if ( GetHudAmmo()->m_nAmmoType2 > 0 &&
+ GetHudAmmo()->m_nTotalAmmo2 == 1 )
+ {
+ return m_TextColorCritical;
+ }
+
+ return m_TextColor;
+ }
+
+private:
+ int m_nPrevVisible;
+ CPanelAnimationStringVar( 128, m_szAmmoSecondaryLabel, "AmmoSecondaryLabel", "AmmoSecondary" );
+};
+
+DECLARE_HUDELEMENT( CHudAmmoSecondary );
diff --git a/game/client/tf2/hud_ammo.h b/game/client/tf2/hud_ammo.h
new file mode 100644
index 0000000..0c24d08
--- /dev/null
+++ b/game/client/tf2/hud_ammo.h
@@ -0,0 +1,52 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+//=============================================================================//
+
+#ifndef HUD_AMMO_H
+#define HUD_AMMO_H
+
+#ifdef _WIN32
+#pragma once
+#endif
+
+// This is *like* a hud element, but isn't actually a hud element.
+// It's meant to be called from hud drawing methods in various places in the code
+class CHudAmmo
+{
+public:
+ // Accessor methods to set various state associated with the ammo display
+ void SetPrimaryAmmo( int nAmmoType, int nTotalAmmo, int nClipCount = -1, int nMaxClipCount = -1 );
+ void SetSecondaryAmmo( int nAmmoType, int nTotalAmmo, int nClipCount = -1, int nMaxClipCount = -1 );
+
+ bool ShouldShowPrimaryClip() const;
+ bool ShouldShowSecondary() const;
+
+ void ShowHideHudControls();
+
+private:
+ int m_nClip1;
+ int m_nMaxClip1;
+ int m_nTotalAmmo1;
+ int m_nAmmoType1;
+
+ int m_nClip2;
+ int m_nMaxClip2;
+ int m_nTotalAmmo2;
+ int m_nAmmoType2;
+
+friend class CHudAmmoPrimary;
+friend class CHudAmmoPrimaryClip;
+friend class CHudAmmoSecondary;
+};
+
+//-----------------------------------------------------------------------------
+// Singleton...
+//-----------------------------------------------------------------------------
+CHudAmmo* GetHudAmmo();
+
+#endif // HUD_AMMO_H
+
diff --git a/game/client/tf2/hud_commander_statuspanel.cpp b/game/client/tf2/hud_commander_statuspanel.cpp
new file mode 100644
index 0000000..46cb908
--- /dev/null
+++ b/game/client/tf2/hud_commander_statuspanel.cpp
@@ -0,0 +1,414 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Flyover/Tooltip hint area for commander
+//
+// $NoKeywords: $
+//=============================================================================//
+#include "cbase.h"
+#include <stdarg.h>
+#include "hud_commander_statuspanel.h"
+#include "techtree.h"
+#include <vgui/IVGui.h>
+#include "VGuiMatSurface/IMatSystemSurface.h"
+#include <vgui_controls/Controls.h>
+#include <vgui/ISurface.h>
+#include <vgui/IScheme.h>
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+static CCommanderStatusPanel *g_pCommanderStatusPanel = NULL;
+
+//
+#define ALPHA_ADJUST_TIME 0.1f
+#define MAX_FILLED_INFO_ALPHA 127.0f
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+CCommanderStatusPanel::CCommanderStatusPanel( void ) :
+ BaseClass( NULL, "CCommanderStatusPanel" )
+{
+ m_hFont = m_hFontText = 0;
+ m_nLeftEdge = 0;
+ m_nBottomEdge = 0;
+
+// m_pBorder = new vgui::LineBorder( 2, vgui::Color( 127, 127, 127, 255 ) );
+// setBorder( m_pBorder );
+
+ SetBgColor( Color( 0, 0, 0, 100 ) );
+
+ // we need updating
+ vgui::ivgui()->AddTickSignal( GetVPanel() );
+
+ InternalClear();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+CCommanderStatusPanel::~CCommanderStatusPanel( void )
+{
+// delete m_pBorder;
+}
+
+//-----------------------------------------------------------------------------
+// Scheme settings
+//-----------------------------------------------------------------------------
+void CCommanderStatusPanel::ApplySchemeSettings(vgui::IScheme *pScheme)
+{
+ BaseClass::ApplySchemeSettings(pScheme);
+
+ m_hFont = pScheme->GetFont( "Trebuchet20" );
+ // FIXME: Outline, weight 1000
+ m_hFontText = pScheme->GetFont( "Trebuchet18" );
+ // FIXME: Outline, weight 700
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CCommanderStatusPanel::OnTick()
+{
+ // Simulate alpha
+ float dt = gpGlobals->frametime;
+ float maxmove = 1.0f / ALPHA_ADJUST_TIME;
+ float moverequested = dt * maxmove;
+
+ float remaining = m_flGoalAlpha - m_flCurrentAlpha;
+ if ( fabs( remaining ) < 0.01f )
+ {
+ if ( m_flCurrentAlpha < 0.01f )
+ {
+ InternalClear();
+ return;
+ }
+ }
+
+ if ( moverequested > fabs( remaining ) )
+ {
+ moverequested = fabs( remaining );
+ }
+
+ if ( remaining > 0.0f )
+ {
+ m_flCurrentAlpha += moverequested;
+ }
+ else
+ {
+ m_flCurrentAlpha -= moverequested;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CCommanderStatusPanel::Paint()
+{
+ if ( m_flCurrentAlpha <= 0.0f )
+ return;
+
+ int wide, tall;
+ GetSize( wide, tall );
+
+ int x = 2;
+ int y = 2;
+
+ wide -= 4;
+ tall -= 4;
+
+ int alpha = 255.0f * m_flCurrentAlpha;
+
+ if ( m_Type == TYPE_INFO && m_nTitlePos != -1 )
+ {
+ m_szText[ m_nTitlePos ] = 0;
+
+ g_pMatSystemSurface->DrawColoredTextRect( m_hFont, x, y, wide, tall, 220, 220, 255, alpha, "%s", m_szText );
+
+ m_szText[ m_nTitlePos ] = '\n';
+
+ y += vgui::surface()->GetFontTall( m_hFont );
+ tall -= vgui::surface()->GetFontTall( m_hFont );
+
+ // Start after title
+ g_pMatSystemSurface->DrawColoredTextRect( m_hFontText, x, y, wide, tall, 255, 255, 255, alpha, "%s", &m_szText[ m_nTitlePos + 1 ] );
+
+ if ( m_bShowTechnology && m_pTechnology )
+ {
+ int x = 0;
+ int y = tall;
+ int size;
+ int r, g, b;
+ r = g = 192;
+ b = 255;
+
+ float fResourceCost = m_pTechnology->GetResourceCost();
+ float fResourceLevel = m_pTechnology->GetResourceLevel();
+
+ int techLevel = m_pTechnology->GetLevel();
+ x = 5;
+ g_pMatSystemSurface->DrawColoredText( m_hFontText, x, y, r, g, b, alpha, "Level <%i>", techLevel );
+
+ x = wide - 5;
+
+ if ( m_pTechnology->GetActive() )
+ {
+ size = g_pMatSystemSurface->DrawTextLen( m_hFontText, "Already owned" );
+
+ x -= size;
+
+ g_pMatSystemSurface->DrawColoredText( m_hFontText, x, y, r, g, b, alpha, "Already owned" );
+ }
+ else
+ {
+ if ( !fResourceCost )
+ {
+ size = g_pMatSystemSurface->DrawTextLen( m_hFontText, "Cost: Free" );
+
+ x -= size;
+
+ g_pMatSystemSurface->DrawColoredText( m_hFontText, x, y, r, g, b, alpha, "Cost: Free" );
+ }
+ else
+ {
+ int sizecost = g_pMatSystemSurface->DrawTextLen( m_hFontText, "WWW: 000 (000)" ) + 5;
+
+ size = g_pMatSystemSurface->DrawTextLen( m_hFontText, "Cost: " );
+
+ x = wide - size - 4 * sizecost;
+
+ r = 255;
+ g = 255;
+ b = 255;
+ g_pMatSystemSurface->DrawColoredText( m_hFontText, x, y, r, g, b, alpha, "Cost: " );
+
+ x += size;
+
+ char szCostString[64];
+
+ // Draw cost string backward to right justify it
+ if ( fResourceCost )
+ {
+ if ( fResourceLevel )
+ Q_snprintf( szCostString, sizeof( szCostString ), "A: %i (%i)", (int)fResourceLevel, (int)fResourceCost );
+ else
+ Q_snprintf( szCostString, sizeof( szCostString ), "A: %i", (int)fResourceCost );
+ g_pMatSystemSurface->DrawColoredText( m_hFontText, x, y, sResourceColor.r, sResourceColor.g, sResourceColor.b, alpha, "%s", szCostString );
+ sizecost = g_pMatSystemSurface->DrawTextLen( m_hFontText, "%s", szCostString ) + 2;
+ }
+ x += sizecost;
+ }
+ }
+ }
+ }
+ else
+ {
+ g_pMatSystemSurface->DrawColoredTextRect( m_hFont,
+ x,
+ y + tall - vgui::surface()->GetFontTall( m_hFont ) - 4,
+ wide,
+ vgui::surface()->GetFontTall( m_hFont ) + 2,
+ 220, 220, 255, alpha,
+ "%s",
+ m_szText );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CCommanderStatusPanel::PaintBackground()
+{
+ if ( m_flCurrentAlpha <= 0.0f )
+ return;
+
+ if ( m_Type == TYPE_INFO )
+ {
+ int alpha = MAX_FILLED_INFO_ALPHA * m_flCurrentAlpha;
+
+ SetBgColor( Color( 0, 0, 0, alpha ) );
+
+ alpha += ( 255 - alpha ) / 2;
+
+// m_pBorder->SetColor( vgui::Color( 120, 120, 180, alpha ) );
+ }
+ else
+ {
+ SetBgColor( Color( 0, 0, 0, 0 ) );
+// m_pBorder->SetColor( vgui::Color( 0, 0, 0, 0 ) );
+ }
+ BaseClass::PaintBackground();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CCommanderStatusPanel::Clear( void )
+{
+ m_flGoalAlpha = 0.0f;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *fmt -
+// ... -
+//-----------------------------------------------------------------------------
+void CCommanderStatusPanel::SetText( STATUSTYPE type, const char *fmt, ... )
+{
+ va_list argptr;
+ va_start( argptr, fmt );
+ _vsnprintf(m_szText, MAX_STATUS_TEXT, fmt, argptr);
+ va_end(argptr);
+ m_szText[ MAX_STATUS_TEXT - 1 ] = 0;
+
+ m_Type = type;
+ SetVisible( true );
+
+ m_nTitlePos = -1;
+
+ if ( m_Type == TYPE_INFO )
+ {
+ // Search for first \n
+ char *p = m_szText;
+ while ( *p && *p != '\n' )
+ {
+ p++;
+ }
+
+ if ( *p == '\n' )
+ {
+ m_nTitlePos = p - m_szText;
+ }
+ }
+
+ m_flCurrentAlpha = MAX( m_flCurrentAlpha, 0.01f );
+ m_flGoalAlpha = 1.0f;
+ m_bShowTechnology = false;
+ m_pTechnology = NULL;
+
+ RecomputeBounds();
+}
+
+void CCommanderStatusPanel::SetTechnology( CBaseTechnology *technology )
+{
+ m_bShowTechnology = true;
+ m_pTechnology = technology;
+}
+
+void CCommanderStatusPanel::InternalClear( void )
+{
+ m_Type = TYPE_UNKNOWN;
+ m_szText[ 0 ] = 0;
+ m_nTitlePos = -1;
+
+ m_flCurrentAlpha = 0.0f;
+ m_flGoalAlpha = 0.0f;
+
+ m_bShowTechnology = false;
+ m_pTechnology = NULL;
+
+ SetVisible( false );
+ SetPaintBackgroundEnabled( false );
+ SetPaintBorderEnabled( false );
+}
+
+void CCommanderStatusPanel::RecomputeBounds( void )
+{
+ int maxlines = 5;
+ int lineheight = vgui::surface()->GetFontTall( m_hFont );
+
+ int height;
+ height = lineheight + ( maxlines - 1 ) * vgui::surface()->GetFontTall( m_hFontText );
+ height += 4; // 2 pixels top and bottom
+
+ SetBounds( m_nLeftEdge, m_nBottomEdge - height, ScreenWidth() * 0.6, height );
+ SetPaintBackgroundEnabled( true );
+ SetPaintBorderEnabled( true );
+}
+
+void CCommanderStatusPanel::SetLeftBottom( int l, int b )
+{
+ m_nLeftEdge = l;
+ m_nBottomEdge = b;
+
+ RecomputeBounds();
+}
+
+//////////////////////////////////////////
+//
+// Status Panel Creation/Destruction and public api
+//
+//////////////////////////////////////////
+void StatusCreate( vgui::Panel *parent, int treetoprow )
+{
+ Assert( !g_pCommanderStatusPanel );
+ g_pCommanderStatusPanel = new CCommanderStatusPanel();
+ g_pCommanderStatusPanel->SetAutoDelete( false );
+ g_pCommanderStatusPanel->SetParent( parent );
+ g_pCommanderStatusPanel->SetLeftBottom( 0, treetoprow - 10 );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : treeetoprow -
+//-----------------------------------------------------------------------------
+void StatusSetTopRow( int treetoprow )
+{
+ Assert( g_pCommanderStatusPanel );
+ g_pCommanderStatusPanel->SetLeftBottom( 0, treetoprow - 10 );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void StatusDestroy( void )
+{
+ delete g_pCommanderStatusPanel;
+ g_pCommanderStatusPanel = NULL;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : type -
+// *fmt -
+// ... -
+//-----------------------------------------------------------------------------
+void StatusPrint( STATUSTYPE type, const char *fmt, ... )
+{
+ char text[ CCommanderStatusPanel::MAX_STATUS_TEXT ];
+
+ va_list argptr;
+ va_start( argptr, fmt );
+ _vsnprintf(text, CCommanderStatusPanel::MAX_STATUS_TEXT, fmt, argptr);
+ va_end(argptr);
+ text[ CCommanderStatusPanel::MAX_STATUS_TEXT - 1 ] = 0;
+
+ if ( g_pCommanderStatusPanel )
+ {
+ g_pCommanderStatusPanel->SetText( type, text );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void StatusClear( void )
+{
+ if ( g_pCommanderStatusPanel )
+ {
+ g_pCommanderStatusPanel->Clear();
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *technology -
+//-----------------------------------------------------------------------------
+void StatusTechnology( CBaseTechnology *technology )
+{
+ if ( g_pCommanderStatusPanel )
+ {
+ g_pCommanderStatusPanel->SetTechnology(technology );
+ }
+} \ No newline at end of file
diff --git a/game/client/tf2/hud_commander_statuspanel.h b/game/client/tf2/hud_commander_statuspanel.h
new file mode 100644
index 0000000..9acc888
--- /dev/null
+++ b/game/client/tf2/hud_commander_statuspanel.h
@@ -0,0 +1,93 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef COMMANDER_STATUSPANEL_H
+#define COMMANDER_STATUSPANEL_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include <vgui_controls/Panel.h>
+
+typedef enum
+{
+ TYPE_UNKNOWN = 0,
+ TYPE_INFO, // More invloved, with box and grayed background
+ // If it has a \n, the lines after the first aren't as large
+ TYPE_INFONOTITLE, // Don't treat first line with a \n specially
+ TYPE_HINT // Single line flyover
+} STATUSTYPE;
+
+namespace vgui
+{
+ class LineBorder;
+}
+
+class CBaseTechnology;
+
+//-----------------------------------------------------------------------------
+// Purpose: The status line appears along the bottom of the screen and shows
+// tooltip style help
+//-----------------------------------------------------------------------------
+class CCommanderStatusPanel : public vgui::Panel
+{
+public:
+ typedef vgui::Panel BaseClass;
+
+ enum { MAX_STATUS_TEXT = 4096 };
+
+
+ CCommanderStatusPanel( void );
+ virtual ~CCommanderStatusPanel( void );
+
+ virtual void ApplySchemeSettings(vgui::IScheme *pScheme);
+
+ virtual void Paint();
+ virtual void PaintBackground();
+ virtual void OnTick();
+
+ // Set status text
+ virtual void SetText( STATUSTYPE type, PRINTF_FORMAT_STRING const char *fmt, ... );
+ virtual void SetTechnology( CBaseTechnology *technology );
+ virtual void Clear();
+
+ virtual void SetLeftBottom( int l, int b );
+
+private:
+ void RecomputeBounds( void );
+ void InternalClear();
+
+private:
+ float m_flCurrentAlpha;
+ float m_flGoalAlpha;
+
+ int m_nLeftEdge;
+ int m_nBottomEdge;
+
+ vgui::HFont m_hFont;
+ vgui::HFont m_hFontText;
+ vgui::LineBorder *m_pBorder;
+
+ // Position of the first '\n' character
+ char m_nTitlePos;
+
+
+ STATUSTYPE m_Type;
+ char m_szText[ MAX_STATUS_TEXT ];
+ bool m_bShowTechnology;
+ CBaseTechnology *m_pTechnology;
+};
+
+void StatusCreate( vgui::Panel *parent, int treetoprow );
+void StatusDestroy( void );
+void StatusSetTopRow( int treetoprow );
+
+void StatusPrint( STATUSTYPE type, PRINTF_FORMAT_STRING const char *fmt, ... );
+void StatusTechnology( CBaseTechnology *technology );
+void StatusClear( void );
+
+#endif // COMMANDER_STATUSPANEL_H
diff --git a/game/client/tf2/hud_damageindicator.cpp b/game/client/tf2/hud_damageindicator.cpp
new file mode 100644
index 0000000..40cbc55
--- /dev/null
+++ b/game/client/tf2/hud_damageindicator.cpp
@@ -0,0 +1,322 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Hud element that indicates the direction of damage taken by the player
+//
+//=============================================================================//
+#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"
+
+using namespace vgui;
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+class CHudDamageIndicator : public CHudElement, public vgui::Panel
+{
+ DECLARE_CLASS_SIMPLE( CHudDamageIndicator, vgui::Panel );
+public:
+ CHudDamageIndicator( const char *pElementName );
+ void Init( void );
+ void VidInit( void );
+ void Reset( void );
+ virtual bool ShouldDraw( void );
+
+ // Handler for our message
+ void MsgFunc_Damage( bf_read &msg );
+
+private:
+ virtual void OnThink();
+ virtual void Paint();
+ virtual void ApplySchemeSettings(vgui::IScheme *pScheme);
+
+ // Painting
+ void GetDamagePosition( const Vector &vecDelta, float flRadius, int *xpos, int *ypos, float *flRotation );
+ void DrawDamageIndicator(int x0, int y0, int x1, int y1, float alpha, float flRotation );
+
+private:
+ // Indication times
+
+ CPanelAnimationVarAliasType( float, m_flMinimumWidth, "MinimumWidth", "10", "proportional_float" );
+ CPanelAnimationVarAliasType( float, m_flMaximumWidth, "MaximumWidth", "100", "proportional_float" );
+ CPanelAnimationVarAliasType( float, m_flMinimumHeight, "MinimumHeight", "20", "proportional_float" );
+ CPanelAnimationVarAliasType( float, m_flMaximumHeight, "MaximumHeight", "100", "proportional_float" );
+ CPanelAnimationVarAliasType( float, m_flStartRadius, "StartRadius", "140", "proportional_float" );
+ CPanelAnimationVarAliasType( float, m_flEndRadius, "EndRadius", "120", "proportional_float" );
+
+ CPanelAnimationVar( float, m_iMaximumDamage, "MaximumDamage", "50" );
+ CPanelAnimationVar( float, m_flMinimumTime, "MinimumTime", "1" );
+ CPanelAnimationVar( float, m_flMaximumTime, "MaximumTime", "6" );
+ CPanelAnimationVar( float, m_flTravelTime, "TravelTime", ".1" );
+ CPanelAnimationVar( float, m_flFadeOutPercentage, "FadeOutPercentage", "0.7" );
+ CPanelAnimationVar( float, m_flNoise, "Noise", "0.1" );
+
+ // List of damages we've taken
+ struct damage_t
+ {
+ int iScale;
+ float flLifeTime;
+ float flStartTime;
+ Vector vecDelta; // Damage origin relative to the player
+ };
+ CUtlVector<damage_t> m_vecDamages;
+};
+
+DECLARE_HUDELEMENT( CHudDamageIndicator );
+DECLARE_HUD_MESSAGE( CHudDamageIndicator, Damage );
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+CHudDamageIndicator::CHudDamageIndicator( const char *pElementName ) :
+ CHudElement( pElementName ), BaseClass(NULL, "DamageIndicator")
+{
+ vgui::Panel *pParent = g_pClientMode->GetViewport();
+ SetParent( pParent );
+
+ SetHiddenBits( HIDEHUD_HEALTH );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CHudDamageIndicator::Init( void )
+{
+ HOOK_HUD_MESSAGE( CHudDamageIndicator, Damage );
+ Reset();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CHudDamageIndicator::Reset( void )
+{
+ m_vecDamages.Purge();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CHudDamageIndicator::VidInit( void )
+{
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CHudDamageIndicator::OnThink()
+{
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+bool CHudDamageIndicator::ShouldDraw( void )
+{
+ if ( !CHudElement::ShouldDraw() )
+ return false;
+
+ // Don't draw if we don't have any damage to indicate
+ if ( !m_vecDamages.Count() )
+ return false;
+
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Convert a damage position in world units to the screen's units
+//-----------------------------------------------------------------------------
+void CHudDamageIndicator::GetDamagePosition( const Vector &vecDelta, float flRadius, int *xpos, int *ypos, float *flRotation )
+{
+ // 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);
+ *xpos = flRadius * -side;
+ *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: Draw a single damage indicator
+//-----------------------------------------------------------------------------
+void CHudDamageIndicator::DrawDamageIndicator(int x0, int y0, int x1, int y1, float alpha, float flRotation )
+{
+ IMaterial *pMat = materials->FindMaterial( "hud/health/indicator", TEXTURE_GROUP_VGUI );
+ CMatRenderContextPtr pRenderContext( materials );
+ IMesh *pMesh = pRenderContext->GetDynamicMesh( true, NULL, NULL, pMat );
+
+ // Get the corners, since they're being rotated
+ int wide = x1 - x0;
+ int tall = y1 - y0;
+ Vector2D vecCorners[4];
+ Vector2D center( x0 + (wide * 0.5f), y0 + (tall * 0.5f) );
+ float yawRadians = -flRotation * M_PI / 180.0f;
+ Vector2D axis[2];
+ axis[0].x = cos(yawRadians);
+ axis[0].y = sin(yawRadians);
+ axis[1].x = -axis[0].y;
+ axis[1].y = axis[0].x;
+ Vector2DMA( center, -0.5f * wide, axis[0], vecCorners[0] );
+ Vector2DMA( vecCorners[0], -0.5f * tall, axis[1], vecCorners[0] );
+ Vector2DMA( vecCorners[0], wide, axis[0], vecCorners[1] );
+ Vector2DMA( vecCorners[1], tall, axis[1], vecCorners[2] );
+ Vector2DMA( vecCorners[0], tall, axis[1], vecCorners[3] );
+
+ // Draw the sucker
+ CMeshBuilder meshBuilder;
+ meshBuilder.Begin( pMesh, MATERIAL_QUADS, 1 );
+
+ int iAlpha = alpha * 255;
+ meshBuilder.Color4ub( 255,255,255, iAlpha );
+ meshBuilder.TexCoord2f( 0,0,0 );
+ meshBuilder.Position3f( vecCorners[0].x,vecCorners[0].y,0 );
+ meshBuilder.AdvanceVertex();
+
+ meshBuilder.Color4ub( 255,255,255, iAlpha );
+ meshBuilder.TexCoord2f( 0,1,0 );
+ meshBuilder.Position3f( vecCorners[1].x,vecCorners[1].y,0 );
+ meshBuilder.AdvanceVertex();
+
+ meshBuilder.Color4ub( 255,255,255, iAlpha );
+ meshBuilder.TexCoord2f( 0,1,1 );
+ meshBuilder.Position3f( vecCorners[2].x,vecCorners[2].y,0 );
+ meshBuilder.AdvanceVertex();
+
+ meshBuilder.Color4ub( 255,255,255, iAlpha );
+ meshBuilder.TexCoord2f( 0,0,1 );
+ meshBuilder.Position3f( vecCorners[3].x,vecCorners[3].y,0 );
+ meshBuilder.AdvanceVertex();
+
+ meshBuilder.End();
+ pMesh->Draw();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CHudDamageIndicator::Paint()
+{
+ // Iterate backwards, because we might remove them as we go
+ int iSize = m_vecDamages.Count();
+ for (int i = iSize-1; i >= 0; i--)
+ {
+ // Scale size to the damage
+ int clampedDamage = clamp( m_vecDamages[i].iScale, 0, m_iMaximumDamage );
+
+ int iWidth = RemapVal(clampedDamage, 0, m_iMaximumDamage, m_flMinimumWidth, m_flMaximumWidth) * 0.5;
+ int iHeight = RemapVal(clampedDamage, 0, m_iMaximumDamage, m_flMinimumHeight, m_flMaximumHeight) * 0.5;
+
+ // Find the place to draw it
+ int xpos, ypos;
+ float flRotation;
+ float flTimeSinceStart = ( gpGlobals->curtime - m_vecDamages[i].flStartTime );
+ float flRadius = RemapVal( MIN( flTimeSinceStart, m_flTravelTime ), 0, m_flTravelTime, m_flStartRadius, m_flEndRadius );
+ GetDamagePosition( m_vecDamages[i].vecDelta, flRadius, &xpos, &ypos, &flRotation );
+
+ // Calculate life left
+ float flLifeLeft = ( m_vecDamages[i].flLifeTime - gpGlobals->curtime );
+ if ( flLifeLeft > 0 )
+ {
+ float flPercent = flTimeSinceStart / (m_vecDamages[i].flLifeTime - m_vecDamages[i].flStartTime);
+ float alpha;
+ if ( flPercent <= m_flFadeOutPercentage )
+ {
+ alpha = 1.0;
+ }
+ else
+ {
+ alpha = 1.0 - RemapVal( flPercent, m_flFadeOutPercentage, 1.0, 0.0, 1.0 );
+ }
+ DrawDamageIndicator( xpos-iWidth, ypos-iHeight, xpos+iWidth, ypos+iHeight, alpha, flRotation );
+ }
+ else
+ {
+ m_vecDamages.Remove(i);
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Message handler for Damage message
+//-----------------------------------------------------------------------------
+void CHudDamageIndicator::MsgFunc_Damage( bf_read &msg )
+{
+ damage_t damage;
+ damage.iScale = msg.ReadByte();
+ if ( damage.iScale > m_iMaximumDamage )
+ {
+ damage.iScale = m_iMaximumDamage;
+ }
+ Vector vecOrigin;
+ vecOrigin.x = msg.ReadFloat();
+ vecOrigin.y = msg.ReadFloat();
+ vecOrigin.z = msg.ReadFloat();
+ damage.flStartTime = gpGlobals->curtime;
+ damage.flLifeTime = gpGlobals->curtime + RemapVal(damage.iScale, 0, m_iMaximumDamage, m_flMinimumTime, m_flMaximumTime);
+
+ if ( vecOrigin == vec3_origin )
+ {
+ vecOrigin = MainViewOrigin();
+ }
+
+ damage.vecDelta = (vecOrigin - MainViewOrigin());
+ VectorNormalize( damage.vecDelta );
+
+ // Add some noise
+ damage.vecDelta[0] += random->RandomFloat( -m_flNoise, m_flNoise );
+ damage.vecDelta[1] += random->RandomFloat( -m_flNoise, m_flNoise );
+ damage.vecDelta[2] += random->RandomFloat( -m_flNoise, m_flNoise );
+ VectorNormalize( damage.vecDelta );
+
+ m_vecDamages.AddToTail( damage );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: hud scheme settings
+//-----------------------------------------------------------------------------
+void CHudDamageIndicator::ApplySchemeSettings(vgui::IScheme *pScheme)
+{
+ BaseClass::ApplySchemeSettings(pScheme);
+ SetPaintBackgroundEnabled(false);
+
+ // set our size
+ int screenWide, screenTall;
+ int x, y;
+ GetPos(x, y);
+ GetHudSize(screenWide, screenTall);
+ SetBounds(0, y, screenWide, screenTall - y);
+}
diff --git a/game/client/tf2/hud_deathnotice.cpp b/game/client/tf2/hud_deathnotice.cpp
new file mode 100644
index 0000000..3810bb4
--- /dev/null
+++ b/game/client/tf2/hud_deathnotice.cpp
@@ -0,0 +1,378 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Draws TF2's death notices
+//
+// $NoKeywords: $
+//=============================================================================//
+#include "cbase.h"
+#include "hud_macros.h"
+#include "hudelement.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 <game/client/iviewport.h>
+#include <KeyValues.h>
+#include "c_baseplayer.h"
+#include "c_team.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+static ConVar hud_deathnotice_time( "hud_deathnotice_time", "6", 0 );
+
+// Player entries in a death notice
+struct DeathNoticePlayer
+{
+ char szName[MAX_PLAYER_NAME_LENGTH];
+ int iEntIndex;
+};
+
+// Contents of each entry in our list of death notices
+struct DeathNoticeItem
+{
+ DeathNoticePlayer Killer;
+ DeathNoticePlayer Victim;
+ DeathNoticePlayer Assist;
+ CHudTexture *iconDeath;
+ int iSuicide;
+ int iTeamKill;
+ float flDisplayTime;
+};
+
+//-----------------------------------------------------------------------------
+// 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( C_BasePlayer *pPlayer, int iTeamNumber );
+ void RetireExpiredDeathNotices( void );
+ void MsgFunc_DeathMsg( bf_read &msg );
+
+private:
+
+ CPanelAnimationVarAliasType( float, m_flLineHeight, "LineHeight", "15", "proportional_float" );
+
+ CPanelAnimationVar( float, m_flMaxDeathNotices, "MaxDeathNotices", "4" );
+ CPanelAnimationVar( bool, m_bRightJustify, "RightJustify", "1" );
+
+ CPanelAnimationVar( Color, m_clrFriendlyText, "FriendlyTextColor", "FriendlyTextColor" );
+ CPanelAnimationVar( Color, m_clrEnemyText, "EnemyTextColor", "EnemyTextColor" );
+ CPanelAnimationVar( Color, m_clrMyKillsText, "MyKillsTextColor", "MyKillsTextColor" );
+
+ CPanelAnimationVar( vgui::HFont, m_hTextFont, "TextFont", "HudNumbersTimer" );
+
+ // Texture for skull symbol
+ CHudTexture *m_iconD_skull;
+
+ CUtlVector<DeathNoticeItem> m_DeathNotices;
+};
+
+using namespace vgui;
+
+DECLARE_HUDELEMENT( CHudDeathNotice );
+// DECLARE_HUD_MESSAGE( CHudDeathNotice, DeathMsg );
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+CHudDeathNotice::CHudDeathNotice( const char *pElementName ) :
+ CHudElement( pElementName ), BaseClass( NULL, "HudDeathNotice" )
+{
+ vgui::Panel *pParent = g_pClientMode->GetViewport();
+ SetParent( pParent );
+
+ SetHiddenBits( HIDEHUD_MISCSTATUS );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CHudDeathNotice::ApplySchemeSettings( IScheme *scheme )
+{
+ BaseClass::ApplySchemeSettings( scheme );
+ SetPaintBackgroundEnabled( false );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CHudDeathNotice::Init( void )
+{
+//FIXME!!!!
+//HOOK_MESSAGE( DeathMsg );
+
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CHudDeathNotice::VidInit( void )
+{
+ m_iconD_skull = gHUD.GetIcon( "d_skull" );
+ 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:
+//-----------------------------------------------------------------------------
+void CHudDeathNotice::SetColorForNoticePlayer( C_BasePlayer *pPlayer, int iTeamNumber )
+{
+ // Set the right color
+ if ( pPlayer == C_BasePlayer::GetLocalPlayer() )
+ {
+ surface()->DrawSetTextColor( m_clrMyKillsText );
+ }
+ else if ( GetLocalTeam() && GetLocalTeam()->GetTeamNumber() == iTeamNumber )
+ {
+ surface()->DrawSetTextColor( m_clrFriendlyText );
+ }
+ else
+ {
+ surface()->DrawSetTextColor( m_clrEnemyText );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CHudDeathNotice::Paint()
+{
+ surface()->DrawSetTextFont( m_hTextFont );
+ surface()->DrawSetTextColor( m_clrFriendlyText );
+
+ int iCount = m_DeathNotices.Count();
+ for ( int i = 0; i < iCount; i++ )
+ {
+ CHudTexture *icon = m_DeathNotices[i].iconDeath;
+ if ( !icon )
+ continue;
+
+ wchar_t victim[ 256 ];
+ wchar_t killer[ 256 ];
+ wchar_t assist[ 256 ];
+
+ g_pVGuiLocalize->ConvertANSIToUnicode( m_DeathNotices[i].Victim.szName, victim, sizeof( victim ) );
+ g_pVGuiLocalize->ConvertANSIToUnicode( m_DeathNotices[i].Killer.szName, killer, sizeof( killer ) );
+ g_pVGuiLocalize->ConvertANSIToUnicode( m_DeathNotices[i].Assist.szName, assist, sizeof( assist ) );
+
+ // Get the team numbers for the players involved
+ C_BasePlayer *pKiller = static_cast<C_BasePlayer*>(cl_entitylist->GetEnt( m_DeathNotices[i].Killer.iEntIndex ));
+ int iKillerTeam = pKiller ? pKiller->GetTeamNumber() : 0;
+ C_BasePlayer *pAssist = NULL;
+ if ( m_DeathNotices[i].Assist.iEntIndex )
+ {
+ pAssist = static_cast<C_BasePlayer*>(cl_entitylist->GetEnt( m_DeathNotices[i].Assist.iEntIndex ));
+ }
+ C_BasePlayer *pVictim = static_cast<C_BasePlayer*>(cl_entitylist->GetEnt( m_DeathNotices[i].Victim.iEntIndex ));
+ int iVictimTeam = pVictim ? pVictim->GetTeamNumber() : 0;
+
+ // Get the local position for this notice
+ int len = UTIL_ComputeStringWidth( m_hTextFont, victim );
+ int y = (m_flLineHeight * i);
+ int x;
+ if ( m_bRightJustify )
+ {
+ x = GetWide() - len - icon->Width() - 5;
+ }
+ else
+ {
+ x = 0;
+ }
+
+ // Only draw killers name if it wasn't a suicide
+ if ( !m_DeathNotices[i].iSuicide )
+ {
+ if ( m_bRightJustify )
+ {
+ x -= UTIL_ComputeStringWidth( m_hTextFont, killer );
+ if ( pAssist )
+ {
+ x -= UTIL_ComputeStringWidth( m_hTextFont, L" + " );
+ x -= UTIL_ComputeStringWidth( m_hTextFont, killer );
+ }
+ }
+
+ SetColorForNoticePlayer( pKiller, iKillerTeam );
+
+ // Draw killer's name
+ surface()->DrawSetTextPos( x, y );
+ surface()->DrawUnicodeString( killer );
+ surface()->DrawGetTextPos( x, y );
+
+ // Did we have an assistant?
+ if ( pAssist )
+ {
+ // Draw the conjuction
+ const wchar_t *sAnd = L" + ";
+ surface()->DrawSetTextPos( x, y );
+ surface()->DrawUnicodeString( sAnd );
+ surface()->DrawUnicodeString( assist );
+ surface()->DrawGetTextPos( x, y );
+ }
+ }
+
+ Color iconColor( 255, 80, 0, 255 );
+ if ( m_DeathNotices[i].iTeamKill )
+ {
+ // display it in sickly green
+ iconColor = Color( 10, 240, 10, 255 );
+ }
+
+ // Draw death weapon
+ icon->DrawSelf( x, y, iconColor );
+ x += icon->Width();
+
+ SetColorForNoticePlayer( pVictim, iVictimTeam );
+
+ // Draw victims name
+ surface()->DrawSetTextPos( x, y );
+ surface()->DrawUnicodeString( victim );
+ }
+
+ // Now retire any death notices that have expired
+ RetireExpiredDeathNotices();
+}
+
+//-----------------------------------------------------------------------------
+// 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::MsgFunc_DeathMsg( bf_read &msg )
+{
+ if (!g_PR)
+ return;
+
+ int killer = msg.ReadByte();
+ int assist = msg.ReadByte();
+ int victim = msg.ReadByte();
+
+ char killedwith[32];
+ char fullkilledwith[128];
+ msg.ReadString( killedwith, sizeof(killedwith) );
+
+ 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 *assist_name = g_PR->GetPlayerName( assist );
+ const char *victim_name = g_PR->GetPlayerName( victim );
+ if ( !killer_name )
+ killer_name = "";
+ if ( !assist_name )
+ assist_name = "";
+ if ( !victim_name )
+ victim_name = "";
+
+ // Make a new death notice
+ DeathNoticeItem deathMsg;
+ deathMsg.Killer.iEntIndex = killer;
+ deathMsg.Assist.iEntIndex = assist;
+ deathMsg.Victim.iEntIndex = victim;
+ Q_strncpy( deathMsg.Killer.szName, killer_name, MAX_PLAYER_NAME_LENGTH );
+ Q_strncpy( deathMsg.Assist.szName, assist_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.iSuicide = ( !killer || killer == victim );
+ deathMsg.iTeamKill = ( !strcmp( fullkilledwith, "d_teammate" ) );
+
+ // 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 );
+
+ char sDeathMsg[512];
+
+ // Record the death notice in the console
+ if ( deathMsg.iSuicide )
+ {
+ if ( !strcmp( fullkilledwith, "d_world" ) )
+ {
+ Q_snprintf( sDeathMsg, sizeof( sDeathMsg ), "%s died.\n", deathMsg.Victim.szName );
+ }
+ else
+ {
+ Q_snprintf( sDeathMsg, sizeof( sDeathMsg ), "%s suicided.\n", deathMsg.Victim.szName );
+ }
+ }
+ else if ( deathMsg.iTeamKill )
+ {
+ Q_snprintf( sDeathMsg, sizeof( sDeathMsg ), "%s teamkilled %s", deathMsg.Killer.szName, deathMsg.Victim.szName );
+ }
+ else
+ {
+ if ( assist )
+ {
+ Q_snprintf( sDeathMsg, sizeof( sDeathMsg ), "%s and %s killed %s", deathMsg.Killer.szName, deathMsg.Assist.szName, deathMsg.Victim.szName );
+ }
+ else
+ {
+ Q_snprintf( sDeathMsg, sizeof( sDeathMsg ), "%s killed %s", deathMsg.Killer.szName, deathMsg.Victim.szName );
+ }
+ }
+
+ if ( fullkilledwith && *fullkilledwith && (*fullkilledwith > 13 ) && strcmp( fullkilledwith, "d_world" ) && !deathMsg.iTeamKill )
+ {
+ Q_strncat( sDeathMsg, VarArgs( " with %s.\n", fullkilledwith+2 ), sizeof( sDeathMsg ), COPY_ALL_CHARACTERS );
+ }
+
+ Msg( sDeathMsg );
+}
+
+
+
diff --git a/game/client/tf2/hud_emp.cpp b/game/client/tf2/hud_emp.cpp
new file mode 100644
index 0000000..f97fa3a
--- /dev/null
+++ b/game/client/tf2/hud_emp.cpp
@@ -0,0 +1,195 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+#include "cbase.h"
+#include "hud.h"
+#include "hudelement.h"
+#include <vgui_controls/Panel.h>
+#include "c_basetfplayer.h"
+#include "tf_shareddefs.h"
+#include "iclientmode.h"
+#include "clientmode_tfnormal.h"
+#include "materialsystem/imaterial.h"
+#include "materialsystem/imesh.h"
+#include "materialsystem/imaterialvar.h"
+#include <vgui_controls/Controls.h>
+#include <vgui/ISurface.h>
+#include "clienteffectprecachesystem.h"
+
+// EMP level positions
+#define HUDEMP_LEFT ((ScreenWidth() / 2)- XRES(40))
+#define HUDEMP_WIDTH XRES(16)
+#define HUDEMP_TOP YRES(210)
+#define HUDEMP_HEIGHT YRES(16)
+
+// Changes per second
+#define HUDEMP_FRAMERATE 30.0f
+
+CLIENTEFFECT_REGISTER_BEGIN( PrecacheHudDamage )
+CLIENTEFFECT_MATERIAL( "Hud/emp/emp_damage" )
+CLIENTEFFECT_REGISTER_END()
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+bool GetEMPDamage()
+{
+ C_BaseTFPlayer *pPlayer;
+ pPlayer = C_BaseTFPlayer::GetLocalPlayer();
+ if ( !pPlayer )
+ return false;
+
+ return pPlayer->HasPowerup(POWERUP_EMP) ? true : false;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Icon showing EMP damage is occuring
+//-----------------------------------------------------------------------------
+class CHudEMP : public CHudElement, public vgui::Panel
+{
+ DECLARE_CLASS_SIMPLE( CHudEMP, vgui::Panel );
+
+public:
+ DECLARE_MULTIPLY_INHERITED();
+
+ CHudEMP( const char *pElementName );
+ ~CHudEMP();
+
+ // vgui::Panel overrides.
+ virtual void Paint( void );
+
+ // CHudElement overrides.
+ virtual bool ShouldDraw( void );
+ virtual void Init( void );
+
+protected:
+ IMaterial *m_pEMPIcon;
+ IMaterialVar *m_pFrameVar;
+
+ float m_flNextFrameChange;
+ int m_nNumFrames;
+};
+
+//DECLARE_HUDELEMENT( CHudEMP, CHudEMP );
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+CHudEMP::CHudEMP( const char *pElementName ) :
+ CHudElement( pElementName ), vgui::Panel( NULL, pElementName )
+{
+ m_pEMPIcon = NULL;
+ m_pFrameVar = NULL;
+ m_flNextFrameChange = 0.0f;
+ m_nNumFrames = 1;
+ //SetPaintBackgroundEnabled( false );
+ SetAutoDelete( false );
+ SetName( "emp" );
+
+ SetHiddenBits( HIDEHUD_HEALTH );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+CHudEMP::~CHudEMP( void )
+{
+ if ( m_pEMPIcon )
+ {
+ m_pEMPIcon->DecrementReferenceCount();
+ m_pEMPIcon = NULL;
+ }
+ SetParent( (vgui::Panel *)NULL );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Attach the jetpack bar to the main panel
+//-----------------------------------------------------------------------------
+void CHudEMP::Init( void )
+{
+ if ( !m_pEMPIcon )
+ {
+ m_pEMPIcon = materials->FindMaterial( "Hud/emp/emp_damage", TEXTURE_GROUP_VGUI );
+ assert( m_pEMPIcon );
+ m_pEMPIcon->IncrementReferenceCount();
+
+ m_pFrameVar = m_pEMPIcon->FindVar( "$frame", NULL, false );
+ m_nNumFrames = m_pEMPIcon->GetNumAnimationFrames();
+ }
+
+ SetPos( HUDEMP_LEFT, HUDEMP_TOP );
+ SetSize( HUDEMP_WIDTH, HUDEMP_HEIGHT );
+
+ vgui::Panel *pParent = GetClientModeNormal()->GetViewport();
+ SetParent(pParent);
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+bool CHudEMP::ShouldDraw( void )
+{
+ return ( CHudElement::ShouldDraw() && GetEMPDamage() );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Draw the jetpack level
+//-----------------------------------------------------------------------------
+void CHudEMP::Paint()
+{
+ // Rush label
+ int iX, iY;
+ GetPos( iX, iY );
+ int iWidth = XRES(16);
+ int iHeight = YRES(16);
+
+ if ( m_pFrameVar )
+ {
+ float curtime = gpGlobals->curtime;
+
+ if ( curtime >= m_flNextFrameChange )
+ {
+ m_flNextFrameChange = curtime + ( 1.0f / HUDEMP_FRAMERATE );
+
+ int frame = m_pFrameVar->GetIntValue();
+ frame++;
+ if ( frame >= m_nNumFrames )
+ {
+ frame = 0;
+ }
+ m_pFrameVar->SetIntValue(frame);
+ }
+ }
+
+ IMesh* pMesh = materials->GetDynamicMesh( true, NULL, NULL, m_pEMPIcon );
+
+ CMeshBuilder meshBuilder;
+ meshBuilder.Begin( pMesh, MATERIAL_QUADS, 1 );
+
+ meshBuilder.Color3f( 1.0, 1.0, 1.0 );
+ meshBuilder.TexCoord2f( 0,0,0 );
+ meshBuilder.Position3f( iX,iY,0 );
+ meshBuilder.AdvanceVertex();
+
+ meshBuilder.Color3f( 1.0, 1.0, 1.0 );
+ meshBuilder.TexCoord2f( 0,1,0 );
+ meshBuilder.Position3f( iX+iWidth, iY, 0 );
+ meshBuilder.AdvanceVertex();
+
+ meshBuilder.Color3f( 1.0, 1.0, 1.0 );
+ meshBuilder.TexCoord2f( 0,1,1 );
+ meshBuilder.Position3f( iX+iWidth, iY+iHeight, 0 );
+ meshBuilder.AdvanceVertex();
+
+ meshBuilder.Color3f( 1.0, 1.0, 1.0 );
+ meshBuilder.TexCoord2f( 0,0,1 );
+ meshBuilder.Position3f( iX, iY+iHeight, 0 );
+ meshBuilder.AdvanceVertex();
+
+ meshBuilder.End();
+ pMesh->Draw();
+}
+
diff --git a/game/client/tf2/hud_health.cpp b/game/client/tf2/hud_health.cpp
new file mode 100644
index 0000000..474bc90
--- /dev/null
+++ b/game/client/tf2/hud_health.cpp
@@ -0,0 +1,217 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: TF2's Hud health display
+//
+// $NoKeywords: $
+//=============================================================================//
+#include "cbase.h"
+#include "hud.h"
+#include "hud_numeric.h"
+#include "c_basetfplayer.h"
+#include "basetfvehicle.h"
+#include <vgui_controls/AnimationController.h>
+#include <KeyValues.h>
+#include "iclientmode.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+//-----------------------------------------------------------------------------
+// Purpose: Local player health
+//-----------------------------------------------------------------------------
+class CHudHealth : public CHudNumeric
+{
+ DECLARE_CLASS_SIMPLE( CHudHealth, CHudNumeric );
+
+public:
+ CHudHealth( const char *pElementName );
+
+ virtual const char *GetLabelText() { return m_szHealthLabel; }
+ virtual const char *GetPulseEvent( bool increment ) { return increment ? "HealthIncrement" : "HealthDecrement"; }
+ virtual bool GetValue( char *val, int maxlen );
+
+ virtual Color GetColor();
+ virtual Color GetBoxColor();
+
+private:
+ bool GetHealth( int& value );
+
+ CPanelAnimationStringVar( 128, m_szHealthLabel, "HealthLabel", "Health" );
+};
+
+DECLARE_HUDELEMENT( CHudHealth );
+
+using namespace vgui;
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+CHudHealth::CHudHealth( const char *pElementName ) :
+ CHudNumeric( pElementName, "HudHealth" )
+{
+ SetHiddenBits( HIDEHUD_HEALTH | HIDEHUD_PLAYERDEAD | HIDEHUD_NEEDSUIT );
+}
+
+bool CHudHealth::GetHealth( int& value )
+{
+ C_BaseTFPlayer *pPlayer = C_BaseTFPlayer::GetLocalPlayer();
+ if ( !pPlayer )
+ return false;
+
+ value = pPlayer->GetHealth();
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : value -
+// Output : Returns true on success, false on failure.
+//-----------------------------------------------------------------------------
+bool CHudHealth::GetValue( char *val, int maxlen )
+{
+ int value = 0;
+ if ( !GetHealth( value ) )
+ return false;
+
+ Q_snprintf( val, maxlen, "%i", value );
+ return true;
+}
+
+Color CHudHealth::GetColor()
+{
+ int value = 0;
+ if ( !GetHealth( value ) || value > 25 )
+ return m_TextColor;
+
+ return m_TextColorCritical;
+}
+
+Color CHudHealth::GetBoxColor()
+{
+ int value = 0;
+ if ( !GetHealth( value ) || value > 25 )
+ return m_BoxColor;
+ return m_BoxColorCritical;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Local player's vehicle health, if in one
+//-----------------------------------------------------------------------------
+class CHudVehicleHealth : public CHudNumeric
+{
+ DECLARE_CLASS_SIMPLE( CHudVehicleHealth, CHudNumeric );
+
+public:
+ CHudVehicleHealth( const char *pElementName );
+
+ virtual const char *GetLabelText() { return m_szVehicleHealthLabel; }
+ virtual const char *GetPulseEvent( bool increment ) { return increment ? "HealthVehicleIncrement" : "HealthVehicleDecrement"; }
+ virtual bool GetValue( char *val, int maxlen );
+
+ virtual Color GetColor();
+ virtual Color GetBoxColor();
+
+private:
+ bool GetHealth( int& value );
+
+ CPanelAnimationVar( float, m_flLingerTime, "exit_vehicle_linger_time", "2.0" );
+
+ bool m_bPrevHealth;
+ float m_flLingerFinish;
+ int m_nLastHealth;
+
+ CPanelAnimationStringVar( 128, m_szVehicleHealthLabel, "VehicleHealthLabel", "Vehicle Health" );
+};
+
+DECLARE_HUDELEMENT( CHudVehicleHealth );
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+CHudVehicleHealth::CHudVehicleHealth( const char *pElementName ) :
+ CHudNumeric( pElementName, "HudVehicleHealth" )
+{
+ m_bPrevHealth = false;
+ m_flLingerFinish = 0.0f;
+ m_flLingerTime = 2.0f;
+ m_nLastHealth = 0;
+
+ SetHiddenBits( HIDEHUD_HEALTH | HIDEHUD_PLAYERDEAD );
+}
+
+bool CHudVehicleHealth::GetHealth( int& value )
+{
+ C_BaseTFPlayer *pPlayer = C_BaseTFPlayer::GetLocalPlayer();
+ if ( pPlayer )
+ {
+ // Draw the vehicle health:
+ C_BaseTFVehicle *pVehicleEnt = ( C_BaseTFVehicle* )pPlayer->GetVehicle();
+ if( pVehicleEnt )
+ {
+ value = pVehicleEnt->GetHealth();
+ m_nLastHealth = value;
+ bool changed = m_bPrevHealth != true;
+
+ if ( changed )
+ {
+ g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( "HealthVehicleEnterVehicle" );
+ }
+
+ m_bPrevHealth = true;
+ return true;
+ }
+ }
+
+ bool changed = m_bPrevHealth != false;
+ if ( changed )
+ {
+ g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( "HealthVehicleExitVehicle" );
+ m_flLingerFinish = gpGlobals->curtime + m_flLingerTime;
+ }
+
+ m_bPrevHealth = false;
+
+ if ( gpGlobals->curtime < m_flLingerFinish )
+ {
+ value = m_nLastHealth;
+ return true;
+ }
+
+ m_flLingerFinish = 0.0f;
+ return false;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : value -
+// Output : Returns true on success, false on failure.
+//-----------------------------------------------------------------------------
+bool CHudVehicleHealth::GetValue( char *val, int maxlen )
+{
+ int value = 0;
+ bool show = GetHealth( value );
+ if ( !show )
+ {
+ return false;
+ }
+
+ Q_snprintf( val, maxlen, "%i", value );
+ return true;
+}
+
+Color CHudVehicleHealth::GetColor()
+{
+ int value = 0;
+ if ( !GetHealth( value ) || value > 75 )
+ return m_TextColor;
+
+ return m_TextColorCritical;
+}
+
+Color CHudVehicleHealth::GetBoxColor()
+{
+ int value = 0;
+ if ( !GetHealth( value ) || value > 75 )
+ return m_BoxColor;
+ return m_BoxColorCritical;
+}
diff --git a/game/client/tf2/hud_minimap.cpp b/game/client/tf2/hud_minimap.cpp
new file mode 100644
index 0000000..dded27a
--- /dev/null
+++ b/game/client/tf2/hud_minimap.cpp
@@ -0,0 +1,1367 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $Workfile: $
+// $NoKeywords: $
+//=============================================================================//
+#include "cbase.h"
+#include "hud_minimap.h"
+#include <vgui_controls/Controls.h>
+#include <vgui/ISurface.h>
+#include <vgui/IVGui.h>
+#include <vgui/IInput.h>
+#include <vgui_controls/AnimationController.h>
+#include "vgui_bitmapimage.h"
+#include "clientmode_tfbase.h"
+#include "clientmode_tfnormal.h"
+#include "hud.h"
+#include "hud_commander_statuspanel.h"
+#include "view.h"
+#include "filesystem.h"
+#include "imessagechars.h"
+#include "hud_macros.h"
+#include "c_tfteam.h"
+#include "c_info_act.h"
+#include "engine/IEngineSound.h"
+#include "iinput.h"
+#include "in_buttons.h"
+#include "c_basetfplayer.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+static ConVar minimap_visible( "minimap_visible", "1", 0, "Draw minimap?" );
+ConVar minimap_zoomtime( "minimap_zoomtime", "0.4", 0, "How long it takes to resize the minimap." );
+
+
+static ConVar current_team( "current_team", "-1", 0 );
+
+// Start out new maps at this zoom level
+#define DEFAULT_ZOOM_LEVEL 0
+
+using namespace vgui;
+
+//-----------------------------------------------------------------------------
+// Instantiate a temporary trace (position based, or entity based)
+//-----------------------------------------------------------------------------
+void MinimapCreateTempTrace( const char* pMetaClassName, int sortOrder, const Vector &vecPosition )
+{
+ MinimapInitData_t initData;
+ initData.m_vecPosition = vecPosition;
+
+ PanelMetaClassMgr()->CreatePanelMetaClass(
+ pMetaClassName, sortOrder, &initData, CMinimapPanel::MinimapRootPanel() );
+}
+
+void MinimapCreateTempTrace( const char* pMetaClassName, int sortOrder, C_BaseEntity *pEntity, const Vector &vecOffset )
+{
+ MinimapInitData_t initData;
+ initData.m_pEntity = pEntity;
+ initData.m_vecPosition = vecOffset;
+
+ PanelMetaClassMgr()->CreatePanelMetaClass(
+ pMetaClassName, sortOrder, &initData, CMinimapPanel::MinimapRootPanel() );
+}
+
+//-----------------------------------------------------------------------------
+// dummy root panel for all minimap traces
+//-----------------------------------------------------------------------------
+class CMinimapRootPanel : public Panel
+{
+ typedef Panel BaseClass;
+
+public:
+ CMinimapRootPanel( Panel *pParent = NULL )
+ : BaseClass( pParent,"CMinimapRootPanel" )
+ {
+ SetPaintBackgroundEnabled( false );
+ SetPaintEnabled( false );
+ SetAutoDelete( false );
+ }
+};
+
+class CTextHelpPanel : public vgui::Panel
+{
+ DECLARE_CLASS_SIMPLE( CTextHelpPanel, vgui::Panel )
+
+public:
+
+ CTextHelpPanel();
+
+ virtual void Paint();
+ virtual void PaintBackground();
+
+ void SetImage( BitmapImage *image );
+
+ virtual void ApplySettings( KeyValues *inResourceData )
+ {
+ BaseClass::ApplySettings( inResourceData );
+ }
+
+private:
+
+ BitmapImage *m_pImage;
+
+ CPanelAnimationVar( Color, m_OverlayColor, "OverlayColor", "White" );
+ CPanelAnimationVar( Color, m_BorderColor, "BorderColor", "BrightFg" );
+ CPanelAnimationVar( Color, m_BackgroundColor, "BackgroundColor", "Black" );
+};
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+CTextHelpPanel::CTextHelpPanel()
+: BaseClass( NULL, "HudMinimapTextHelpPanel" )
+{
+ Panel *pParent = g_pClientMode->GetViewport();
+ SetParent( pParent );
+
+ SetVisible( false );
+ SetZPos( 1 );
+
+ m_pImage = NULL;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTextHelpPanel::PaintBackground()
+{
+ // Get alpha from image
+ if ( m_pImage )
+ {
+ Color bg = m_BackgroundColor;
+ int r, g, b, a;
+ m_pImage->GetColor( r, g, b, a );
+ bg[3] = a;
+ SetBgColor( bg );
+
+ BaseClass::PaintBackground();
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTextHelpPanel::Paint()
+{
+ BaseClass::Paint();
+
+ if ( !m_pImage )
+ return;
+
+ m_pImage->SetColor( m_OverlayColor );
+ m_pImage->DoPaint( GetVPanel() );
+
+ int w, h;
+ GetSize( w, h );
+
+ surface()->DrawSetColor( m_BorderColor );
+ surface()->DrawOutlinedRect( 0, 0, w, h );
+ surface()->DrawOutlinedRect( 1, 1, w-1, h-1 );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *image -
+// x -
+// y -
+// w -
+// h -
+//-----------------------------------------------------------------------------
+void CTextHelpPanel::SetImage( BitmapImage *image )
+{
+ m_pImage = image;
+}
+
+//-----------------------------------------------------------------------------
+// globals
+//-----------------------------------------------------------------------------
+
+
+//-----------------------------------------------------------------------------
+// All traces are children of this panel
+//-----------------------------------------------------------------------------
+Panel *CMinimapPanel::MinimapRootPanel()
+{
+ static CMinimapRootPanel s_MinimapRootPanel;
+ return &s_MinimapRootPanel;
+}
+
+CMinimapPanel *CMinimapPanel::MinimapPanel()
+{
+ ClientModeTFBase *pBasemode = ( ClientModeTFBase * )g_pClientMode;
+ if ( !pBasemode )
+ return NULL;
+
+ return pBasemode->GetMinimap();
+}
+
+DECLARE_HUDELEMENT( CMinimapPanel );
+DECLARE_HUD_MESSAGE( CMinimapPanel, MinimapPulse );
+
+//-----------------------------------------------------------------------------
+// Purpose: Placeholder for small overview map with viewport rectangle/selector
+//-----------------------------------------------------------------------------
+CMinimapPanel::CMinimapPanel( const char *pElementName )
+: CHudElement( pElementName ), BaseClass( NULL, "HudMinimap" )
+{
+ Panel *pParent = g_pClientMode->GetViewport();
+ SetParent( pParent );
+
+ SetAutoDelete( false );
+ for ( int i = 0; i < MAX_ACT_TEAMS; i++ )
+ {
+ m_pBackground[ i ] = 0;
+ }
+ memset( m_rgOverlays, 0, sizeof( m_rgOverlays ) );
+
+ m_flExpansionFrac = 0.0f;
+
+ // Minimap zoom
+ m_bMinimapZoomed = false;
+ m_nZoomLevel = DEFAULT_ZOOM_LEVEL;
+
+ m_vecCurrentOrigin.Init();
+ m_vecMapCenter.Init();
+ m_flMapAspectRatio = 1.0f;
+ m_flViewportAspectRatio = 1.0f;
+ m_flAspectAdjustment = 1.0f;
+ m_flNormalizedXScale = 1.0f;
+ m_flNormalizedYScale = 1.0f;
+ m_flNormalizedXOffset = 0.0f;
+ m_flNormalizedYOffset = 0.0f;
+
+ m_nCurrentAct = ACT_NONE_SPECIFIED;
+
+ m_pTextPanel = new CTextHelpPanel();
+ m_pBackgroundPanel = new Panel( NULL, "BackgroundPanel" );
+
+ // We're gonna manage the lifetime of the text panel
+ // since we change it's hierarchical connections from time to time
+ m_pTextPanel->SetAutoDelete( false );
+ m_pBackgroundPanel->SetAutoDelete( false );
+ SetAutoDelete( false );
+
+ m_pClient = NULL;
+
+ m_flZoomAdjust = 1.0f;
+ m_flPrevZoomAmount = 0.01f;
+
+ SetZPos( 10 );
+
+ ivgui()->AddTickSignal( GetVPanel() );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+CMinimapPanel::~CMinimapPanel( void )
+{
+ delete m_pTextPanel;
+ delete m_pBackgroundPanel;
+
+ for ( int i = 0; i < MAX_ACT_TEAMS; i++ )
+ {
+ delete m_pBackground[ i ];
+ }
+
+ ShutdownOverlays();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *scheme -
+//-----------------------------------------------------------------------------
+void CMinimapPanel::ApplySchemeSettings( IScheme *scheme )
+{
+ BaseClass::ApplySchemeSettings( scheme );
+ SetPaintBackgroundEnabled( false );
+}
+
+
+//-----------------------------------------------------------------------------
+// initialization
+//-----------------------------------------------------------------------------
+void CMinimapPanel::Init( IMinimapClient* pClient )
+{
+ m_pClient = pClient;
+}
+
+//-----------------------------------------------------------------------------
+// Call this when the minimap panel is going to be drawn...
+//-----------------------------------------------------------------------------
+void CMinimapPanel::Activate()
+{
+ // The panel is a view into the minimap root panel
+ MinimapRootPanel()->SetParent( this );
+
+ Panel *pParent = g_pClientMode->GetViewport();
+
+ if ( pParent && m_pBackgroundPanel )
+ {
+ m_pBackgroundPanel->SetParent( pParent );
+ m_pBackgroundPanel->SetBounds( XRES( 0 ), YRES( 0 ), XRES( 640 ), YRES( 480 ) );
+ m_pBackgroundPanel->SetVisible( false );
+ m_pBackgroundPanel->SetZPos( 0 );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : w -
+// h -
+//-----------------------------------------------------------------------------
+void CMinimapPanel::OnSizeChanged( int w, int h )
+{
+ BaseClass::OnSizeChanged( w, h );
+
+ MinimapRootPanel()->SetSize( w, h );
+
+ // Make sure icons are snapped to current window size
+ InvokeOnTickOnChildren( this );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Output : float
+//-----------------------------------------------------------------------------
+float CMinimapPanel::GetAdjustedZoom( void )
+{
+ return m_flZoomAmount * m_flZoomAdjust;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Output : float
+//-----------------------------------------------------------------------------
+float CMinimapPanel::GetTrueZoom()
+{
+ return m_flZoomAmount;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : center -
+// scale -
+//-----------------------------------------------------------------------------
+void CMinimapPanel::GetMapOriginAndScale( Vector& origin, float& scale )
+{
+ origin = m_vecCurrentOrigin;
+ scale = GetAdjustedZoom();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : clip -
+// pos -
+// outx -
+// outy -
+// Output : Returns true on success, false on failure.
+//-----------------------------------------------------------------------------
+bool CMinimapPanel::WorldToMinimap( MinimapPosType_t posType, const Vector& pos, float& outx, float& outy )
+{
+ Vector origin;
+ float zoomscale;
+
+ GetMapOriginAndScale( origin, zoomscale );
+
+ return InternalWorldToMinimap( posType, pos, origin, zoomscale, outx, outy );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : x -
+// y -
+//-----------------------------------------------------------------------------
+void CMinimapPanel::AdjustNormalizedPositionForAspectRatio( float& x, float& y )
+{
+ x = m_flNormalizedXOffset + x * m_flNormalizedXScale;
+ y = m_flNormalizedYOffset + y * m_flNormalizedYScale;
+}
+
+//-----------------------------------------------------------------------------
+// Converts a world-space position to a coordinate in minimap panel space
+//-----------------------------------------------------------------------------
+bool CMinimapPanel::InternalWorldToMinimap( MinimapPosType_t posType, const Vector &pos, const Vector& origin, float zoomscale, float& outx, float& outy )
+{
+ int wide, tall;
+ MinimapRootPanel()->GetSize( wide, tall );
+
+ Vector worldmins, worldmaxs;
+ MapData().GetMapBounds( worldmins, worldmaxs );
+ Vector worldsize = worldmaxs - worldmins;
+
+ Vector test = ( pos - origin );
+
+ float xfraction = 0.0f;
+
+ if ( worldsize.x > 0 )
+ {
+ xfraction = (test.x - worldmins.x) / (worldmaxs.x - worldmins.x);
+ }
+
+ float yfraction = 0.0f;
+
+ if ( worldsize.y > 0 )
+ {
+ yfraction = (test.y - worldmins.y) / (worldmaxs.y - worldmins.y);
+ }
+
+ xfraction = ( xfraction - 0.5f ) * zoomscale + 0.5f;
+ yfraction = ( yfraction - 0.5f ) * zoomscale + 0.5f;
+
+ yfraction = 1.0f - yfraction;
+
+ // Adjust in case not all of map can be shown
+ AdjustNormalizedPositionForAspectRatio( xfraction, yfraction );
+
+ // Normalize?
+ bool inside = true;
+ switch ( posType )
+ {
+ case MINIMAP_CLIP:
+ {
+ // Clip the vector from minimap center to object
+ // to the minimap bounds and put the object on the edge
+ Vector2D delta( xfraction - 0.5f, yfraction - 0.5f );
+ Vector2D fdelta( fabs(delta.x), fabs(delta.y) );
+ if (fdelta.x > fdelta.y)
+ {
+ // It's more horizontal than vertical..
+ if (fdelta.x >= 0.5f)
+ {
+ float flRatio = delta.y / delta.x;
+ xfraction = clamp(xfraction, 0, 1);
+ yfraction = (xfraction - 0.5f) * flRatio + 0.5f;
+ }
+ }
+ else
+ {
+ if (fdelta.y >= 0.5f)
+ {
+ // It's more vertical than horizontal
+ float flRatio = delta.x / delta.y;
+ yfraction = clamp(yfraction, 0, 1);
+ xfraction = (yfraction - 0.5f) * flRatio + 0.5f;
+ }
+ }
+ }
+ break;
+
+ case MINIMAP_CLAMP:
+ {
+ // Clamp the position to lie within the minimap
+ xfraction = clamp(xfraction, 0, 1);
+ yfraction = clamp(yfraction, 0, 1);
+ }
+ break;
+
+ case MINIMAP_NOCLIP:
+ {
+ // See if it's off screen
+ if ( xfraction < 0.0 || xfraction > 1.0 ||
+ yfraction < 0.0 || yfraction > 1.0 )
+ {
+ inside = false;
+ }
+ }
+ break;
+ }
+
+ outx = xfraction * wide;
+ outy = yfraction * tall;
+
+ return inside;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *mapname -
+//-----------------------------------------------------------------------------
+void CMinimapPanel::LevelInit( const char *mapname )
+{
+ SetBackgroundMaterials( MapData().m_Minimap.m_szBackgroundMaterial );
+
+ m_nZoomLevel = DEFAULT_ZOOM_LEVEL;
+
+ HOOK_HUD_MESSAGE( CMinimapPanel, MinimapPulse );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Play a pulse on the minimap
+//-----------------------------------------------------------------------------
+void CMinimapPanel::MsgFunc_MinimapPulse( bf_read &msg )
+{
+ Vector vecPosition;
+ msg.ReadBitVec3Coord( vecPosition );
+ C_TFTeam *pTeam = (C_TFTeam *)GetLocalTeam();
+ if ( pTeam )
+ {
+ pTeam->NotifyBaseUnderAttack( vecPosition, false );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CMinimapPanel::LevelShutdown( void )
+{
+}
+
+//-----------------------------------------------------------------------------
+// Sets the background material
+//-----------------------------------------------------------------------------
+void CMinimapPanel::SetBackgroundMaterials( const char *pMaterialName )
+{
+ int i;
+ for ( i = 0; i < MAX_ACT_TEAMS; i++ )
+ {
+ delete m_pBackground[ i ];
+ m_pBackground[ i ] = NULL;
+ }
+
+ if ( pMaterialName[ 0 ] )
+ {
+ for ( i = 0; i < MAX_ACT_TEAMS; i++ )
+ {
+ char teammaterial[ 512 ];
+
+ Q_snprintf( teammaterial, sizeof( teammaterial ), "%s_team%i",
+ pMaterialName, i + 1 );
+
+ // If a _team# version exists, use that, otherwise, use the default
+ if ( g_pFullFileSystem->FileExists( VarArgs( "materials/%s.vmt", teammaterial ) ) )
+ {
+ m_pBackground[ i ] = new BitmapImage( GetVPanel(), teammaterial );
+ }
+ else
+ {
+ m_pBackground[ i ] = new BitmapImage( GetVPanel(), pMaterialName );
+ }
+ }
+ }
+
+ if ( m_pTextPanel )
+ {
+ m_pTextPanel->SetImage( NULL );
+ }
+
+ ShutdownOverlays();
+ InitOverlays( pMaterialName );
+}
+
+//-----------------------------------------------------------------------------
+// Called when the mouse is hit
+//-----------------------------------------------------------------------------
+void CMinimapPanel::OnMousePressed(MouseCode code)
+{
+ if ((code == MOUSE_LEFT) && m_pClient)
+ {
+ // Convert mouse position to world position
+ int x, y;
+ vgui::input()->GetCursorPos( x, y );
+
+ int w, h;
+ GetSize( w, h );
+
+ Vector worldPos;
+ worldPos.x = (float) x / (float) w;
+ worldPos.y = 1.0f - (float) y / (float) h;
+ worldPos.z = 0; // z isn't used
+
+ Vector worldMins, worldMaxs;
+ MapData().GetMapBounds( worldMins, worldMaxs );
+ worldPos *= (worldMaxs - worldMins);
+ worldPos += worldMins;
+
+ m_pClient->MinimapClicked( worldPos );
+ }
+}
+
+void CMinimapPanel::SetBackgroundViewport( float minx, float miny, float maxx, float maxy, bool includedetails )
+{
+ int i;
+ int x, y, w, h;
+
+ x = 0;
+ y = 0;
+ w = GetWide();
+ h = GetTall();
+
+ if ( minx < 0.0f || maxx > 1.0f ||
+ miny < 0.0f || maxy > 1.0f )
+ {
+ float x0 = 0.0f;
+ float y0 = 0.0f;
+ float x1 = 1.0f;
+ float y1 = 1.0f;
+
+ float xrange = maxx - minx;
+ float yrange = maxy - miny;
+
+ if ( minx < 0.0f )
+ {
+ x0 = -minx / xrange;
+ //xrange += minx;
+ maxx -= minx;
+ minx = 0.0f;
+ }
+ if ( maxx > 1.0f )
+ {
+ x1 = 1.0f - ( maxx - 1.0f ) / xrange;
+ maxx = 1.0f;
+ }
+ if ( miny < 0.0f )
+ {
+ y0 = -miny / yrange;
+ //yrange += miny;
+ maxy -= miny;
+ miny = 0.0f;
+ }
+ if ( maxy > 1.0f )
+ {
+ y1 = 1.0f - ( maxy - 1.0f ) / yrange;
+ maxy = 1.0f;
+ }
+
+ x = x0 * w;
+ y = y0 * h;
+ w = x1 * w;
+ h = y1 * h;
+ }
+
+ for ( i = 0; i < MAX_ACT_TEAMS; i++ )
+ {
+ if ( m_pBackground[ i ] )
+ {
+ m_pBackground[ i ]->SetPos( x, y );
+ m_pBackground[ i ]->SetRenderSize( w, h );
+ m_pBackground[ i ]->SetViewport( true, minx, miny, maxx, maxy );
+ }
+ }
+
+ if ( includedetails )
+ {
+ int t;
+ for ( t = 0; t < MAX_ACT_TEAMS; t++ )
+ {
+ for ( i = 0; i < MAX_ACTS; i++ )
+ {
+ Overlays *p = &m_rgOverlays[ t ][ i ];
+ if ( !p->m_bInUse )
+ continue;
+
+ if ( !p->m_pOverlay )
+ continue;
+
+ p->m_pOverlay->SetPos( x, y );
+ p->m_pOverlay->SetRenderSize( w, h );
+ p->m_pOverlay->SetViewport( true, minx, miny, maxx, maxy );
+ }
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CMinimapPanel::PaintActOverlays( int teamIndex, int alpha )
+{
+ Assert( teamIndex >= 0 && teamIndex < MAX_ACT_TEAMS );
+
+ bool textshowing = false;
+
+ int i = GetCurrentActNumber();
+ if ( i != ACT_NONE_SPECIFIED )
+ {
+ i = clamp( i, 0, MAX_ACTS - 1 );
+ Overlays *p = &m_rgOverlays[ teamIndex ][ i ];
+ if ( p->m_bInUse )
+ {
+ int r, g, b, a;
+
+ if ( p->m_pOverlay )
+ {
+ p->m_pOverlay->GetColor( r, g, b, a );
+ Color clr( r, g, b, alpha );
+ p->m_pOverlay->SetColor( clr );
+ p->m_pOverlay->DoPaint( NULL, 0, (float)alpha/255.0f );
+ }
+
+ if ( p->m_pText && m_pTextPanel )
+ {
+ p->m_pText->GetColor( r, g, b, a );
+ Color clr( r, g, b, alpha );
+ p->m_pText->SetColor( clr );
+
+ m_pTextPanel->SetImage( p->m_pText );
+
+ clr = m_BackgroundColor;
+ clr[3] = alpha;
+ m_pBackgroundPanel->SetBgColor( clr );
+
+ textshowing = true;
+ }
+ }
+ }
+
+ if ( !textshowing )
+ {
+ m_pTextPanel->SetVisible( false );
+ m_pTextPanel->SetImage( NULL );
+ m_pBackgroundPanel->SetVisible( false );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CMinimapPanel::OnThink()
+{
+ BaseClass::OnThink();
+
+ C_BaseTFPlayer *local = C_BaseTFPlayer::GetLocalPlayer();
+ if ( local )
+ {
+ if ( local->m_TFLocal.m_bForceMapOverview && m_bMinimapZoomed != local->m_TFLocal.m_bForceMapOverview )
+ {
+ SetMinimapZoom( local->m_TFLocal.m_bForceMapOverview );
+ }
+ }
+
+ if ( !IsVisible() )
+ return;
+
+ if ( m_flZoomAmount != m_flPrevZoomAmount )
+ {
+ m_flPrevZoomAmount = m_flZoomAmount;
+ ComputeMapOrigin( m_vecCurrentOrigin );
+ InvokeOnTickOnChildren( this );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CMinimapPanel::Paint()
+{
+ if ( gHUD.IsHidden( HIDEHUD_MISCSTATUS ) )
+ {
+ // Remove the minimap zoom if the hud's hidden
+ SetMinimapZoom( false );
+ return;
+ }
+
+ C_BasePlayer *local = C_BasePlayer::GetLocalPlayer();
+ int team = 0;
+ if ( local )
+ {
+ team = local->GetTeamNumber();
+ }
+
+ int w, h;
+ GetSize( w, h );
+
+ int alpha;
+ bool shouldDrawDetails = ShouldDrawZoomDetails( alpha );
+
+ if ( m_pTextPanel && m_pBackgroundPanel )
+ {
+ m_pTextPanel->SetVisible( shouldDrawDetails );
+ m_pBackgroundPanel->SetVisible( shouldDrawDetails );
+ }
+
+ // DEBUGGING: Allow cvar override
+ if ( current_team.GetInt() >= 0 )
+ {
+ team = current_team.GetInt();
+ }
+
+ // Can can be 0 through MAX_ACT_TEAMS
+ team = clamp( team, 0, MAX_ACT_TEAMS );
+
+ // Array index is 0 to MAX_ACT_TEAMS - 1 where a team of zero means no team and won't be indexed
+ // due to logic that checks team > 0
+ int teamIndex = clamp( team - 1, 0, MAX_ACT_TEAMS - 1 );
+
+ if ( m_pBackground[ teamIndex ] )
+ {
+ if ( shouldDrawDetails )
+ {
+ Color clr = m_BackgroundColor;
+ clr[3] *= alpha / 255.0f;
+ surface()->DrawSetColor( clr );
+ surface()->DrawFilledRect( 0, 0, w, h );
+ }
+
+ float offsetx, offsety;
+
+ // Need to translate m_vecCurrentOrigin into minimap space
+ InternalWorldToMinimap(
+ MINIMAP_NOCLIP,
+ m_vecCurrentOrigin,
+ -m_vecMapCenter,
+ 1,
+ offsetx, offsety );
+
+ // Scale to 0.0f to 1.0f
+ offsetx /= (float)w;
+ offsety /= (float)h;
+
+ float minx, maxx, miny, maxy;
+
+ float xscale = 1.0f;
+ float yscale = 1.0f;
+ float startx = 0.0f;
+ float starty = 0.0f;
+
+ Assert( m_flAspectAdjustment > 0.0f );
+
+ // Note, the scale sense is inverted here
+ float invaspect = 1.0f / m_flAspectAdjustment;
+
+ if ( m_flAspectAdjustment < 1.0f )
+ {
+ xscale = invaspect;
+ startx = ( 1.0f - xscale ) * 0.5f;
+ }
+ else
+ {
+ yscale = m_flAspectAdjustment;
+ starty = ( 1.0f - yscale ) * 0.5f;
+ }
+
+ float halfzoom = ( 1.0f / GetAdjustedZoom() ) * 0.5f;
+
+ // zoom scale is already normalized, so just take half in one direction, half the other
+ minx = startx + xscale * ( offsetx - halfzoom );
+ miny = starty + yscale * ( offsety - halfzoom );
+ maxx = startx + xscale * ( offsetx + halfzoom );
+ maxy = starty + yscale * ( offsety + halfzoom );
+
+ SetBackgroundViewport( minx, miny, maxx, maxy, shouldDrawDetails );
+
+ m_pBackground[ teamIndex ]->DoPaint( NULL );
+
+ if ( shouldDrawDetails && ( team > 0 ) )
+ {
+ PaintActOverlays( teamIndex, alpha );
+ }
+ }
+ else
+ {
+ Color clr = m_BackgroundColor;
+ clr[3] *= alpha * 0.9f / 255.0f;
+
+ surface()->DrawSetColor( clr );
+ surface()->DrawFilledRect( 0, 0, w, h );
+ }
+
+ // Dumb place to do this
+ if ( !shouldDrawDetails && CurrentActIsAWaitingAct() )
+ {
+ char *cmsg = "Wait for game start...";
+ int width, height;
+ messagechars->GetStringLength( g_hFontTrebuchet24, &width, &height, cmsg );
+ messagechars->DrawString( g_hFontTrebuchet24, XRES(16), ScreenHeight() - (height * 6), 255, 255, 245, 255, cmsg, IMessageChars::MESSAGESTRINGID_NONE );
+ }
+
+ Color border = m_BorderColor;
+ border[3] = border[3] * ( alpha * 0.9f ) / 255.0f;
+
+ //border = vgui::Color( 255, 0, 120, 255 );
+
+ surface()->DrawSetColor( border );
+ surface()->DrawOutlinedRect( 0, 0, w, h );
+ surface()->DrawOutlinedRect( 1, 1, w-1, h-1 );
+}
+
+void CMinimapPanel::InvokeOnTickOnChildren( vgui::Panel *parent )
+{
+ if ( !parent )
+ return;
+
+ int c = parent->GetChildCount();
+ int i;
+ for ( i = 0; i < c; i++ )
+ {
+ vgui::Panel *child = parent->GetChild( i );
+ child->OnTick();
+ InvokeOnTickOnChildren( child );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CMinimapPanel::OnTick()
+{
+ // See if the act's changed. If it has, bring up the act overlays.
+ if ( m_nCurrentAct != GetCurrentActNumber() )
+ {
+ // g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( "MinimapActChanged" );
+ // SetMinimapZoom( true );
+ m_nCurrentAct = GetCurrentActNumber();
+ }
+
+ // Cache these only once per frame if in a valid game
+ if ( C_BasePlayer::GetLocalPlayer() && minimap_visible.GetBool() )
+ {
+ SetVisible( true );
+ ComputeMapOrigin( m_vecCurrentOrigin );
+ }
+ else
+ {
+ SetVisible( false );
+ }
+
+ InvokeOnTickOnChildren( this );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : alpha -
+// Output : Returns true on success, false on failure.
+//-----------------------------------------------------------------------------
+bool CMinimapPanel::ShouldDrawZoomDetails( int& alpha )
+{
+ alpha = (int)m_flDetailsAlpha;
+ alpha = clamp( alpha, 0, 255 );
+
+ if ( !alpha )
+ return false;
+
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : center -
+//-----------------------------------------------------------------------------
+void CMinimapPanel::ComputeMapOrigin( Vector& origin )
+{
+ Vector worldmins, worldmaxs, worldsize;
+ MapData().GetMapBounds( worldmins, worldmaxs );
+ VectorSubtract( worldmaxs, worldmins, worldsize );
+
+ // Cache true map center
+ m_vecMapCenter = ( worldmins + worldmaxs ) * 0.5f;
+
+ C_BasePlayer* pPlayer = C_BasePlayer::GetLocalPlayer();
+
+ Vector playerOrigin;
+
+ if( !pPlayer )
+ {
+ playerOrigin = m_vecMapCenter;
+ }
+ else
+ {
+ playerOrigin = pPlayer->GetAbsOrigin();
+ }
+
+ origin.Init();
+
+ playerOrigin.z = m_vecMapCenter.z = 0.0f;
+
+ Vector delta = playerOrigin - m_vecMapCenter;
+
+ // Map center pointer is biased toward player origin as we become zoomed in to 1.0x to 2.5x and toward true world center as we zoom all the way out
+ VectorScale( delta, m_flCenterOnPlayer, origin );
+
+ int vw, vh;
+ GetSize( vw, vh );
+
+ m_flMapAspectRatio = 1.0f;
+ m_flViewportAspectRatio = 1.0f;
+ m_flAspectAdjustment = 1.0f;
+
+ if ( vh > 0 )
+ {
+ m_flViewportAspectRatio = ( float )vw / ( float )vh;
+ }
+
+ if ( worldsize.y > 0 )
+ {
+ m_flMapAspectRatio = worldsize.x / worldsize.y;
+ }
+
+ if ( m_flViewportAspectRatio > 0 )
+ {
+ m_flAspectAdjustment = m_flMapAspectRatio / m_flViewportAspectRatio;
+ }
+
+ float fittedworldunitsperpixel;
+ float zoomedworldunitsperpixel;
+ float zooomedoutworldunitsperpixel;
+ float actualworldunitsperpixel;
+
+ if ( m_flAspectAdjustment > 1.0f )
+ {
+ // World height fits exactly in minimap height at zoom 1x
+ fittedworldunitsperpixel = worldsize.y / (float)( vh );
+
+ // At higher zoom we get less world units per pixel
+ zoomedworldunitsperpixel = fittedworldunitsperpixel / m_flZoomAmount;
+
+ // at fully zoomed back view, world width fits window width instead
+ zooomedoutworldunitsperpixel = worldsize.x / (float)( vw );
+
+ // As we center more on player, we move away from zoomed out units and toward zoomed units per pixel
+ actualworldunitsperpixel = zooomedoutworldunitsperpixel + m_flCenterOnPlayer * ( zoomedworldunitsperpixel - zooomedoutworldunitsperpixel );
+
+ m_flZoomAdjust = (1-m_flCenterOnPlayer) + m_flCenterOnPlayer * ( 1/m_flViewportAspectRatio );
+ }
+ else
+ {
+ // World width fits exactly in minimap width at zoom 1x
+ fittedworldunitsperpixel = worldsize.x / (float)( vw );
+
+ // At higher zoom we get less world units per pixel
+ zoomedworldunitsperpixel = fittedworldunitsperpixel / m_flZoomAmount;
+
+ // at fully zoomed back view, world height fits window height instead
+ zooomedoutworldunitsperpixel = worldsize.y / (float)( vh );
+
+ // As we center more on player, we move away from zoomed out units and toward zoomed units per pixel
+ actualworldunitsperpixel = zooomedoutworldunitsperpixel + m_flCenterOnPlayer * ( zoomedworldunitsperpixel - zooomedoutworldunitsperpixel );
+
+ m_flZoomAdjust = (1-m_flCenterOnPlayer) + m_flCenterOnPlayer * ( 1/m_flAspectAdjustment );
+ }
+
+ Vector preOrigin = origin;
+
+ float inset_pixels = m_flInsetPixels;
+
+ float viewport_width_world_units = ( float )( vw - 2 * inset_pixels ) * actualworldunitsperpixel;
+ float viewport_height_world_units = ( float )( vh - 2 * inset_pixels ) * actualworldunitsperpixel;
+
+ // Insets apply when centering on player
+ m_flWorldSpaceInsets[ 0 ] = MIN( m_vecMapCenter.x, worldmins.x + m_flCenterOnPlayer * ( viewport_width_world_units ) * 0.5f );
+ m_flWorldSpaceInsets[ 1 ] = MIN( m_vecMapCenter.y, worldmins.y + m_flCenterOnPlayer * ( viewport_height_world_units ) * 0.5f );
+ m_flWorldSpaceInsets[ 2 ] = MAX( m_vecMapCenter.x, worldmaxs.x - m_flCenterOnPlayer * ( viewport_width_world_units ) * 0.5f );
+ m_flWorldSpaceInsets[ 3 ] = MAX( m_vecMapCenter.y, worldmaxs.y - m_flCenterOnPlayer * ( viewport_height_world_units ) * 0.5f );
+
+ // Assuming origin is at center of view, compute world space left, top, right, bottom
+ m_flWorldSpaceBounds[ 0 ] = m_vecMapCenter.x + origin.x - viewport_width_world_units * 0.5f;
+ m_flWorldSpaceBounds[ 1 ] = m_vecMapCenter.y + origin.y - viewport_height_world_units * 0.5f;
+ m_flWorldSpaceBounds[ 2 ] = m_vecMapCenter.x + origin.x + viewport_width_world_units * 0.5f;
+ m_flWorldSpaceBounds[ 3 ] = m_vecMapCenter.y + origin.y + viewport_height_world_units * 0.5f;
+
+ // Clip these bounds
+ m_flClippedWorldSpaceBounds[ 0 ] = MAX( worldmins.x, m_flWorldSpaceBounds[ 0 ] );
+ m_flClippedWorldSpaceBounds[ 1 ] = MAX( worldmins.y, m_flWorldSpaceBounds[ 1 ] );
+ m_flClippedWorldSpaceBounds[ 2 ] = MIN( worldmaxs.x, m_flWorldSpaceBounds[ 2 ] );
+ m_flClippedWorldSpaceBounds[ 3 ] = MIN( worldmaxs.y, m_flWorldSpaceBounds[ 3 ] );
+
+ // Clip origin to inserts
+ origin.x = clamp( origin.x, m_flWorldSpaceInsets[ 0 ] - m_vecMapCenter.x, m_flWorldSpaceInsets[ 2 ] - m_vecMapCenter.x );
+ origin.y = clamp( origin.y, m_flWorldSpaceInsets[ 1 ] - m_vecMapCenter.y, m_flWorldSpaceInsets[ 3 ] - m_vecMapCenter.y );
+
+ /*
+ engine->Con_NPrintf( 1, "map bounds left %i top %i right %i bottom %i",
+ (int)worldmins.x,
+ (int)worldmins.y,
+ (int)worldmaxs.x,
+ (int)worldmaxs.y );
+
+ engine->Con_NPrintf( 2, "world space bounds left %i top %i right %i bottom %i",
+ (int)m_flWorldSpaceBounds[ 0 ],
+ (int)m_flWorldSpaceBounds[ 1 ],
+ (int)m_flWorldSpaceBounds[ 2 ],
+ (int)m_flWorldSpaceBounds[ 3 ] );
+
+ engine->Con_NPrintf( 3, "world space insets left %i top %i right %i bottom %i",
+ (int)m_flWorldSpaceInsets[ 0 ],
+ (int)m_flWorldSpaceInsets[ 1 ],
+ (int)m_flWorldSpaceInsets[ 2 ],
+ (int)m_flWorldSpaceInsets[ 3 ] );
+
+ engine->Con_NPrintf( 4, "world space clipping left %i top %i right %i bottom %i",
+ (int)m_flClippedWorldSpaceBounds[ 0 ],
+ (int)m_flClippedWorldSpaceBounds[ 1 ],
+ (int)m_flClippedWorldSpaceBounds[ 2 ],
+ (int)m_flClippedWorldSpaceBounds[ 3 ] );
+
+
+ engine->Con_NPrintf( 5, "world center %i %i",
+ (int)m_vecMapCenter.x, (int)m_vecMapCenter.y );
+
+ engine->Con_NPrintf( 6, "player origin %i %i",
+ (int)playerOrigin.x, (int)playerOrigin.y );
+
+ engine->Con_NPrintf( 7, "desired map center %i %i",
+ (int)( m_vecMapCenter.x + preOrigin.x ), (int)( preOrigin.y + m_vecMapCenter.x ) );
+
+ engine->Con_NPrintf( 8, "actual map center %i %i",
+ (int)( m_vecMapCenter.x + origin.x ), (int)( origin.y + m_vecMapCenter.y ) );
+
+ engine->Con_NPrintf( 9, "viewport (%ix%i) aspect %.2f world (%ix%i) aspect %f",
+ vw, vh, m_flViewportAspectRatio, (int)worldsize.x, (int)worldsize.y, m_flMapAspectRatio );
+
+ engine->Con_NPrintf( 10, "zoom %.3f zoom adjust %.3f",
+ m_flZoomAmount, m_flZoomAdjust );
+
+ engine->Con_NPrintf( 11, "viewport %i x %i",
+ (int)viewport_width_world_units, (int)viewport_height_world_units );
+ */
+
+ // Assume 100% scale and no x or y offset to make up for aspect ration diff
+ m_flNormalizedXScale = 1.0f;
+ m_flNormalizedYScale = 1.0f;
+ m_flNormalizedXOffset = 0.0f;
+ m_flNormalizedYOffset = 0.0f;
+
+ if ( m_flAspectAdjustment < 1.0f )
+ {
+ m_flNormalizedXScale = m_flAspectAdjustment;
+ // Offset 0->1 version of x value
+ m_flNormalizedXOffset = ( 1.0f - m_flNormalizedXScale ) * 0.5f;
+ }
+ else
+ {
+ m_flNormalizedYScale = 1.0f / m_flAspectAdjustment;
+ // Offset 0->1 version of y value
+ m_flNormalizedYOffset = ( 1.0f - m_flNormalizedYScale ) * 0.5f;
+ }
+}
+
+void CMinimapPanel::InitOverlays( const char *materialrootname )
+{
+ if ( !materialrootname || !materialrootname[0] )
+ return;
+
+ int t;
+ for ( t = 0; t < MAX_ACT_TEAMS; t++ )
+ {
+ char teamnum[ 2 ];
+ Q_snprintf( teamnum, sizeof( teamnum ), "%01i", t + 1 );
+
+ int i;
+ for ( i = 0; i < MAX_ACTS; i++ )
+ {
+ char actnum[ 3 ];
+
+ char filename[ 512 ];
+
+ Q_snprintf( actnum, sizeof( actnum ), "%02i", i );
+
+ Overlays *p = &m_rgOverlays[ t ][ i ];
+ Assert( p && !p->m_bInUse );
+
+ Q_snprintf( filename, sizeof( filename ), "%s_act%s_overlay_team%s",
+ materialrootname, actnum, teamnum );
+
+ // Check if file exists
+ if ( g_pFullFileSystem->FileExists( VarArgs( "materials/%s.vmt", filename ) ) )
+ {
+ p->m_pOverlay = new BitmapImage( GetVPanel(), filename );
+ p->m_bInUse = true;
+ }
+ else
+ {
+ // Try it without the team number
+ Q_snprintf( filename, sizeof( filename ), "%s_act%s_overlay",
+ materialrootname, actnum );
+
+ if ( g_pFullFileSystem->FileExists( VarArgs( "materials/%s.vmt", filename ) ) )
+ {
+ p->m_pOverlay = new BitmapImage( GetVPanel(), filename );
+ p->m_bInUse = true;
+ }
+ }
+
+ Q_snprintf( filename, sizeof( filename ), "%s_act%s_text_team%s",
+ materialrootname, actnum, teamnum );
+
+ // Check if file exists
+ if ( g_pFullFileSystem->FileExists( VarArgs( "materials/%s.vmt", filename ) ) )
+ {
+ p->m_pText = new BitmapImage( GetTextPaintPanel()->GetVPanel(), filename );
+ p->m_bInUse = true;
+ }
+ else
+ {
+ // Try it without the team number
+ Q_snprintf( filename, sizeof( filename ), "%s_act%s_text",
+ materialrootname, actnum );
+
+ // Check if file exists
+ if ( g_pFullFileSystem->FileExists( VarArgs( "materials/%s.vmt", filename ) ) )
+ {
+ p->m_pText = new BitmapImage( GetTextPaintPanel()->GetVPanel(), filename );
+ p->m_bInUse = true;
+ }
+ }
+ }
+ }
+}
+
+void CMinimapPanel::ShutdownOverlays( void )
+{
+ int t;
+ for ( t = 0; t < MAX_ACT_TEAMS; t++ )
+ {
+
+ int i;
+ for ( i = 0; i < MAX_ACTS; i++ )
+ {
+ Overlays *p = &m_rgOverlays[ t ][ i ];
+ Assert( p );
+ if ( !p->m_bInUse )
+ continue;
+
+ delete p->m_pOverlay;
+ delete p->m_pText;
+ p->m_bInUse = false;
+ p->m_pOverlay = NULL;
+ p->m_pText = NULL;
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Output : Panel
+//-----------------------------------------------------------------------------
+Panel *CMinimapPanel::GetTextPaintPanel( void )
+{
+ ClientModeTFBase *basemode = ( ClientModeTFBase * )g_pClientMode;
+ if ( !basemode )
+ {
+ Assert( 0 );
+ return NULL;
+ }
+
+ return basemode->GetMinimapParent();
+}
+
+void CMinimapPanel::ZoomIn( void )
+{
+ if ( m_flDetailsAlpha > 0 )
+ {
+ if ( m_nZoomLevel != 0 )
+ {
+ // g_pClientMode->GetViewportAnimationController()->StartAnimationSequence(
+ // "MinimapZoomLevel0" );
+ }
+
+ // Full window
+ m_nZoomLevel = 0;
+ }
+ else
+ {
+ m_nZoomLevel = ( m_nZoomLevel + 1 ) % ( NUM_WIDTHS );
+ m_nZoomLevel = clamp( m_nZoomLevel, 0, NUM_WIDTHS - 1 );
+
+ g_pClientMode->GetViewportAnimationController()->StartAnimationSequence(
+ m_nZoomLevel == 0 ?
+ "MinimapZoomLevel0" :
+ "MinimapZoomLevel1" );
+ }
+}
+
+void CMinimapPanel::Zoom_Minimap_f( void )
+{
+ ClientModeTFBase *basemode = ( ClientModeTFBase * )g_pClientMode;
+ if ( !basemode )
+ return;
+
+ CMinimapPanel *minimap = basemode->GetMinimap();
+ if ( !minimap )
+ return;
+
+ minimap->ZoomIn();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CMinimapPanel::ToggleMinimap( void )
+{
+ int iKeybits = ::input->GetButtonBits( 0 );
+ bool hitting_button = ( iKeybits & (IN_ATTACK | IN_ATTACK2 | IN_JUMP) ) ? true : false;
+ if ( hitting_button && !m_bMinimapZoomed )
+ {
+ CLocalPlayerFilter filter;
+ C_BaseEntity::EmitSound( filter, SOUND_FROM_LOCAL_PLAYER, "ClientModeTFNormal.ToggleMinimap" );
+ }
+
+ SetMinimapZoom( !m_bMinimapZoomed );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void Toggle_Minimap_f( void )
+{
+ ClientModeTFBase *basemode = ( ClientModeTFBase * )g_pClientMode;
+ if ( !basemode )
+ return;
+
+ CMinimapPanel *minimap = basemode->GetMinimap();
+ if ( !minimap )
+ return;
+ minimap->ToggleMinimap();
+}
+
+static ConCommand minimap( "minimap", Toggle_Minimap_f, "Toggle size of the tf2 minimap." );
+
+//-----------------------------------------------------------------------------
+// Purpose: Set the state of the minimap's zoom
+//-----------------------------------------------------------------------------
+void CMinimapPanel::SetMinimapZoom( bool bZoom )
+{
+ C_BaseTFPlayer *local = C_BaseTFPlayer::GetLocalPlayer();
+ if ( local && local->m_TFLocal.m_bForceMapOverview )
+ {
+ bZoom = true;
+ }
+
+ bool changed = bZoom != m_bMinimapZoomed;
+ m_bMinimapZoomed = bZoom;
+ if ( bZoom )
+ {
+ m_nZoomLevel = 0;
+ }
+
+ if ( changed )
+ {
+ g_pClientMode->GetViewportAnimationController()->StartAnimationSequence(
+ m_bMinimapZoomed ?
+ "MinimapZoomToFullScreen" :
+ "MinimapZoomToCorner");
+
+ CLocalPlayerFilter filter;
+ C_BaseEntity::EmitSound( filter, SOUND_FROM_LOCAL_PLAYER, m_bMinimapZoomed ? "Minimap.ZoomIn" : "Minimap.ZoomOut" );
+
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Get at input data before it's used
+//-----------------------------------------------------------------------------
+void CMinimapPanel::ProcessInput()
+{
+ int iKeybits = ::input->GetButtonBits( 0 );
+
+ bool hitting_button = ( iKeybits & (IN_ATTACK | IN_ATTACK2 | IN_JUMP) ) ? true : false;
+
+ // While the minimap's zoomed,
+ if ( m_bMinimapZoomed && hitting_button )
+ {
+ SetMinimapZoom( false );
+ ::input->ClearInputButton( (IN_ATTACK | IN_ATTACK2 | IN_JUMP) );
+ }
+
+ CHudElement::ProcessInput();
+}
+
+static ConCommand zoom_minimap( "zoom_minimap", CMinimapPanel::Zoom_Minimap_f, "Zoom in on minimap." );
+
+
+
+
diff --git a/game/client/tf2/hud_minimap.h b/game/client/tf2/hud_minimap.h
new file mode 100644
index 0000000..a0c6ab1
--- /dev/null
+++ b/game/client/tf2/hud_minimap.h
@@ -0,0 +1,272 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $Workfile: $
+// $NoKeywords: $
+//=============================================================================//
+#if !defined( HUD_MINIMAP_H )
+#define HUD_MINIMAP_H
+
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "mathlib/vector.h"
+#include "cdll_client_int.h"
+#include "hudelement.h"
+#include "utllinkedlist.h"
+#include "CommanderOverlay.h"
+#include "MapData.h"
+
+class BitmapImage;
+class CTextHelpPanel;
+
+//-----------------------------------------------------------------------------
+// This interfaces gets called when a click occurs in the minimap
+//-----------------------------------------------------------------------------
+class IMinimapClient
+{
+public:
+ virtual void MinimapClicked( const Vector& clickWorldPos ) = 0;
+};
+
+
+//-----------------------------------------------------------------------------
+// Ways to perform WorldToMinimap
+//-----------------------------------------------------------------------------
+enum MinimapPosType_t
+{
+ MINIMAP_NOCLIP = 0, // Don't draw things off the minimap
+ MINIMAP_CLAMP, // Clamp the position to lie within the minimap
+ MINIMAP_CLIP, // Clip the vector from minimap center to object
+ // to the minimap bounds and put the object on the edge
+ MINIMAP_ALWAYS_ACCEPT // Just do the scaling and return a value - don't worry about clipping.
+};
+
+
+//-----------------------------------------------------------------------------
+// Purpose: On the left side of the screen is an overview map and a highlight
+// rectangle showing the current viewport
+//
+// NOTE: The minimap panel is architected in such a way as to view some global
+// state. There can be many instances of the minimap panel
+//-----------------------------------------------------------------------------
+class CMinimapPanel : public CHudElement, public vgui::Panel
+{
+ DECLARE_CLASS_SIMPLE( CMinimapPanel, vgui::Panel );
+
+public:
+ enum
+ {
+ STABLE = 0,
+ GROWING,
+ SHRINKING
+ };
+
+ CMinimapPanel( const char *pElementName );
+ virtual ~CMinimapPanel( void );
+
+ void Init( IMinimapClient* pClient = NULL );
+
+ virtual void LevelInit( const char *mapname );
+ virtual void LevelShutdown( void );
+
+ virtual void ApplySchemeSettings( vgui::IScheme *scheme );
+
+ virtual void OnMousePressed(vgui::MouseCode code);
+
+ virtual void Paint();
+
+ virtual void OnTick();
+ virtual void OnThink();
+
+ virtual void OnSizeChanged( int w, int h );
+
+ // Converts a world-space position to a coordinate in minimap panel space
+ bool WorldToMinimap( MinimapPosType_t posType, const Vector &pos, float& outx, float& outy );
+
+ // The following methods deal with management of the minimap data
+ static vgui::Panel *MinimapRootPanel();
+ static CMinimapPanel *MinimapPanel();
+
+ // Call this when the minimap panel is going to be drawn...
+ void Activate();
+
+ // 0 is minimized and won't draw zoom details, 1.0 is fully maximized
+ bool ShouldDrawZoomDetails( int& alpha );
+
+ bool InternalWorldToMinimap( MinimapPosType_t posType, const Vector &pos, const Vector& origin, float zoomscale, float& outx, float& outy );
+
+ static void Zoom_Minimap_f( void );
+ void ZoomIn( void );
+
+ void ToggleMinimap( void );
+ void SetMinimapZoom( bool bZoom);
+
+ virtual void ProcessInput( void );
+
+ float GetAdjustedZoom( void );
+ float GetTrueZoom( void );
+
+ // Handler for our message
+ void MsgFunc_MinimapPulse( bf_read &msg );
+
+private:
+ void SetBackgroundMaterials( char const* pMaterialName );
+
+ void GetMapOriginAndScale( Vector& origin, float& scale );
+
+ void SetBackgroundViewport( float minx, float miny, float maxx, float maxy, bool includedetails );
+ void PaintActOverlays( int teamIndex, int alpha );
+ void AdjustNormalizedPositionForAspectRatio( float& x, float& y );
+
+ void DrawVisibleArea( void );
+
+ void ComputeMapOrigin( Vector& origin );
+
+ void InitOverlays( const char *materialrootname );
+ void ShutdownOverlays( void );
+
+ vgui::Panel *GetTextPaintPanel( void );
+
+ void InvokeOnTickOnChildren( vgui::Panel *parent );
+
+ bool m_DrawVisibleArea;
+ IMinimapClient *m_pClient;
+
+ CPanelAnimationVar( float, m_flExpansionFrac, "ExpansionFrac", "0" );
+ CPanelAnimationVar( float, m_flDetailsAlpha, "DetailsAlpha", "0" );
+ CPanelAnimationVar( float, m_flMapScale, "MapScale", "2000" );
+ CPanelAnimationVar( float, m_flZoomAmount, "ZoomAmount", "1.0" );
+ CPanelAnimationVar( float, m_flCenterOnPlayer, "CenterOnPlayer", "1" );
+
+ CPanelAnimationVar( float, m_flInsetPixels, "InsetPixels", "16" );
+
+ float m_flPrevZoomAmount;
+
+ CPanelAnimationVar( Color, m_BackgroundColor, "BackgroundColor", "Black" );
+ CPanelAnimationVar( Color, m_BorderColor, "BorderColor", "FgColor" );
+
+ int m_nZoomLevel;
+ bool m_bMinimapZoomed;
+ int m_nCurrentAct;
+
+ float m_flZoomAdjust; // Adjustment needed to get map to fit exactly into box in one dimension assuming
+ // m_flZoomAmount == 1.0f
+
+
+ enum
+ {
+ NUM_WIDTHS = 2,
+ };
+
+
+ // Calculated once per frame and cached
+ Vector m_vecCurrentOrigin;
+ Vector m_vecMapCenter;
+ float m_flMapAspectRatio;
+ float m_flViewportAspectRatio;
+ // map aspect / viewport aspect
+ float m_flAspectAdjustment;
+
+ float m_flNormalizedXScale;
+ float m_flNormalizedYScale;
+ float m_flNormalizedXOffset;
+ float m_flNormalizedYOffset;
+
+
+ // These are the wordspace corners of the minimap
+ float m_flWorldSpaceBounds[ 4 ];
+ // These are the above, except clamped to actual world mins/maxs
+ float m_flClippedWorldSpaceBounds[ 4 ];
+ // These are used to clamp the map origin to keep the zoomed map from scrolling off screen
+ float m_flWorldSpaceInsets[ 4 ];
+
+ enum
+ {
+ MAX_ACTS = 16,
+ MAX_ACT_TEAMS = 2
+ };
+
+ struct Overlays
+ {
+ bool m_bInUse;
+ BitmapImage *m_pOverlay;
+ BitmapImage *m_pText;
+ };
+
+ BitmapImage *m_pBackground[ MAX_ACT_TEAMS ];
+ Overlays m_rgOverlays[ MAX_ACT_TEAMS ][ MAX_ACTS ];
+
+ CTextHelpPanel *m_pTextPanel;
+ vgui::Panel *m_pBackgroundPanel;
+};
+
+
+//-----------------------------------------------------------------------------
+// minimap render order
+//-----------------------------------------------------------------------------
+enum
+{
+ MINIMAP_GROUND_LINES = 0,
+ MINIMAP_RESOURCE_ZONES,
+ MINIMAP_OBJECTS,
+ MINIMAP_SPY_CAMERAS,
+ MINIMAP_COLLECTORS,
+ MINIMAP_MAP_GOALS,
+ MINIMAP_PLAYERS,
+ MINIMAP_LOCAL_PLAYER,
+ MINIMAP_SNIPER_RESPAWN,
+ MINIMAP_PERSONAL_ORDERS
+};
+
+
+//-----------------------------------------------------------------------------
+// Instantiate a temporary trace (position based, or entity based)
+//-----------------------------------------------------------------------------
+void MinimapCreateTempTrace( const char* pMetaClassName, int sortOrder, const Vector &vecPosition );
+void MinimapCreateTempTrace( const char* pMetaClassName, int sortOrder, C_BaseEntity *pEntity, const Vector &vecOffset );
+
+
+//-----------------------------------------------------------------------------
+// Helper macro to make overlay factories one line of code. Use like this:
+// DECLARE_MINIMAP_FACTORY( CEntityImagePanel, "image" );
+//-----------------------------------------------------------------------------
+struct MinimapInitData_t
+{
+ C_BaseEntity *m_pEntity;
+ Vector m_vecPosition; // relative to m_pEntity if it's specified, otherwise absolute position
+
+ MinimapInitData_t() : m_pEntity(NULL), m_vecPosition( 0, 0, 0 ) {}
+ MinimapInitData_t( C_BaseEntity *pEntity ) : m_pEntity(pEntity), m_vecPosition( 0, 0, 0 ) {}
+};
+
+#define DECLARE_MINIMAP_FACTORY( _PanelClass, _nameString ) \
+ DECLARE_PANEL_FACTORY( _PanelClass, MinimapInitData_t, _nameString )
+
+
+//-----------------------------------------------------------------------------
+// Macros for help with simple registration of minimap
+// Put DECLARE_MINIMAP_PANEL() in your class definition
+// and CONSTRUCT_MINIMAP_PANEL( "panelname", SORT_ORDER ) in your class constructor
+//-----------------------------------------------------------------------------
+#define DECLARE_MINIMAP_PANEL( ) DECLARE_METACLASS_PANEL( m_MinimapTrace )
+#define CONSTRUCT_MINIMAP_PANEL( _name, _sortorder ) \
+ MinimapInitData_t _traceInit( this ); \
+ CONSTRUCT_METACLASS_PANEL( m_MinimapTrace, _name, CMinimapPanel::MinimapRootPanel(), _sortorder, &_traceInit )
+#define DESTRUCT_MINIMAP_PANEL( ) \
+ DESTRUCT_METACLASS_PANEL( m_MinimapTrace )
+#define IS_MINIMAP_PANEL_DEFINED( ) ( m_MinimapTrace.GetPanel() != NULL )
+
+// Kind of a hack; assumes all minimap panels inherit from CMinimapTracePanel, but that's reasonable..
+#define SET_MINIMAP_PANEL_VISIBILITY( _visible ) \
+ do \
+ { \
+ if (m_MinimapTrace.GetPanel()) \
+ { \
+ static_cast<CMinimapTracePanel*>(m_MinimapTrace.GetPanel())->SetTraceVisibility( _visible ); \
+ } \
+ } while (0)
+
+#endif // HUD_MINIMAP_H \ No newline at end of file
diff --git a/game/client/tf2/hud_numeric.cpp b/game/client/tf2/hud_numeric.cpp
new file mode 100644
index 0000000..3d2937c
--- /dev/null
+++ b/game/client/tf2/hud_numeric.cpp
@@ -0,0 +1,978 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+//=============================================================================//
+#include "cbase.h"
+#include "hud.h"
+#include "hud_numeric.h"
+#include "iclientmode.h"
+#include <KeyValues.h>
+#include <vgui/ISurface.h>
+#include <vgui/IScheme.h>
+#include <vgui_controls/AnimationController.h>
+#include "ctype.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+using namespace vgui;
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *pElementName -
+// *panelName -
+//-----------------------------------------------------------------------------
+CHudNumeric::CHudNumeric( const char *pElementName, const char *panelName )
+ : CHudElement( pElementName ), BaseClass( NULL, panelName )
+{
+ // Make sure we have the lookups built
+ BuildPrintablesList();
+
+ vgui::Panel *pParent = g_pClientMode->GetViewport();
+ SetParent( pParent );
+
+ SetActive( true );
+ SetAutoDelete( false );
+
+ m_nTextLen = 0;
+ Q_memset( m_szPreviousValue, 0, sizeof( m_szPreviousValue ) );
+ Q_memset( m_szLatchedValue, 0, sizeof( m_szLatchedValue ) );
+
+ m_bDrawLabel = true;
+ m_bSendPulses = true;
+ m_bPulseForced = true;
+
+ m_flRotaryTime = 0.0f;
+ m_flRotaryStartTime = 0.0f;
+ m_flActualCharactersPerSecond = 7.0f;
+}
+
+bool CHudNumeric::s_bPrintablesBuilt;
+CUtlRBTree< int, int > CHudNumeric::m_Printables( 0, 0, DefLessFunc( int ) );
+
+//-----------------------------------------------------------------------------
+// Purpose: Builds a list of printable characters
+//-----------------------------------------------------------------------------
+void CHudNumeric::BuildPrintablesList( void )
+{
+ if ( s_bPrintablesBuilt )
+ return;
+
+ s_bPrintablesBuilt = true;
+ int i;
+ for ( i = 0; i < 256; i++ )
+ {
+ if ( isalnum( i ) ) // isprint or isgraph?
+ {
+ m_Printables.Insert( i );
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Find the index of a printable character
+// Input : ch -
+// Output : int
+//-----------------------------------------------------------------------------
+int CHudNumeric::FindPrintableIndex( int ch )
+{
+ int idx = m_Printables.Find( ch );
+ return idx;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *scheme -
+//-----------------------------------------------------------------------------
+void CHudNumeric::ApplySchemeSettings(IScheme *scheme)
+{
+ BaseClass::ApplySchemeSettings(scheme);
+
+ m_flActualCharactersPerSecond = (float)m_flDesiredCharactersPerSecond;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Output : Returns true on success, false on failure.
+//-----------------------------------------------------------------------------
+bool CHudNumeric::IsRotating( void ) const
+{
+ if ( gpGlobals->curtime >= m_flRotaryStartTime &&
+ gpGlobals->curtime <= ( m_flRotaryStartTime + m_flRotaryTime ) )
+ {
+ return true;
+ }
+
+ return false;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : frac -
+// startchar -
+// endchar -
+// prevchar -
+// nextchar -
+// subfrac -
+//-----------------------------------------------------------------------------
+void CHudNumeric::GetRotatedChar( float frac, char startchar, char endchar, char& prevchar, char& nextchar, float& subfrac )
+{
+ // Recast into database of printable characters
+ int startidx = FindPrintableIndex( startchar );
+ int endidx = FindPrintableIndex( endchar );
+
+ float diff = ( float )endidx - ( float )startidx;
+
+ // No delta
+ if ( diff == 0.0f ||
+ startidx == m_Printables.InvalidIndex() ||
+ endidx == m_Printables.InvalidIndex() )
+ {
+ prevchar = startchar;
+ nextchar = startchar;
+ subfrac = 0.0f;
+
+ return;
+ }
+
+ bool reverse = false;
+ // Going backwards is same as forward except frac is reversed
+ if ( diff < 0.0f )
+ {
+ reverse = true;
+ frac = 1.0f - frac;
+ int temp = startidx;
+ startidx = endidx;
+ endidx = temp;
+ diff = -diff;
+ }
+
+ float foutindex = (float)startidx;
+ int outindex;
+ float fnextindex;
+ int nextindex;
+
+ int maxdelta = (int)diff;
+
+ if ( m_nRotaryMaxDelta != 0 )
+ {
+ maxdelta = MIN( m_nRotaryMaxDelta, maxdelta );
+ }
+
+ // Quantize steps
+ // Map frac into maxdelta discrete intervals
+ float indicesperstep = diff / (float)maxdelta;
+ float fnumstepstaken = clamp( frac * (float)maxdelta, 0.0f, (float)( maxdelta -0.001f ) );
+ int numstepstaken = (int)(fnumstepstaken);
+
+ foutindex = (float)startidx + (float)numstepstaken * indicesperstep;
+ foutindex = clamp( foutindex, (float)startidx, (float)endidx );
+
+ outindex = ( int )foutindex;
+
+ fnextindex = (float)startidx + (float)( numstepstaken + 1 ) * indicesperstep;
+ fnextindex = clamp( fnextindex, (float)startidx, (float)endidx );
+
+ nextindex = (int)fnextindex;
+
+ subfrac = fnumstepstaken - (float)numstepstaken;
+
+ if ( !m_Printables.IsValidIndex( outindex ) ||
+ !m_Printables.IsValidIndex( nextindex ) )
+ {
+ prevchar = startchar;
+ nextchar = startchar;
+ subfrac = 0.0f;
+ return;
+ }
+
+ if ( reverse )
+ {
+ subfrac = 1.0f - subfrac;
+ prevchar = m_Printables[ nextindex ];
+ nextchar = m_Printables[ outindex ];
+ }
+ else
+ {
+ prevchar = m_Printables[ outindex ];
+ nextchar = m_Printables[ nextindex ];
+ }
+}
+
+void CHudNumeric::PaintRotatedCharacterHoriz( int x, int y, vgui::HFont& font, int prevchar, int nextchar, float frac )
+{
+ frac = 3 * frac * frac - 2 * frac * frac * frac;
+
+ int abcA, abcB, abcC;
+ surface()->GetCharABCwide( font, prevchar, abcA, abcB, abcC );
+ // int fontTall = surface()->GetFontTall( font );
+
+ CharRenderInfo info;
+ if ( frac < 0.5f )
+ {
+ surface()->DrawSetTextPos( x, y );
+
+ // Paint the right half of the prevchar still
+ if ( surface()->DrawGetUnicodeCharRenderInfo( prevchar, info ) )
+ {
+ // Shift tex coord and y position half way down glyph
+ info.verts[0].m_Position.x = Lerp( 0.5f, info.verts[0].m_Position.x, info.verts[1].m_Position.x );
+ info.verts[0].m_TexCoord.x = Lerp( 0.5f, info.verts[0].m_TexCoord.x, info.verts[1].m_TexCoord.x );
+ surface()->DrawRenderCharFromInfo( info );
+ }
+
+ surface()->DrawSetTextPos( x, y );
+
+ // Paint up to frac from left of next char
+ if ( surface()->DrawGetUnicodeCharRenderInfo( nextchar, info ) )
+ {
+ // Shift tex coord and y position part way up glyph
+ info.verts[1].m_Position.x = Lerp( frac, info.verts[0].m_Position.x, info.verts[1].m_Position.x );
+ info.verts[1].m_TexCoord.x = Lerp( frac, info.verts[0].m_TexCoord.x, info.verts[1].m_TexCoord.x );
+ surface()->DrawRenderCharFromInfo( info );
+ }
+
+ // Paint divider
+
+ surface()->DrawSetTextPos( x, y );
+
+ // Paint from frac to 0.5 of prevchar on the left
+ if ( surface()->DrawGetUnicodeCharRenderInfo( prevchar, info ) )
+ {
+ // Shift tex coord and y position half way up glyph
+ vgui::Vertex_t save[2];
+
+ save[0] = info.verts[0];
+ save[1] = info.verts[1];
+
+ info.verts[0].m_Position.x = Lerp( frac, save[0].m_Position.x, save[1].m_Position.x );
+ //info.verts[0].m_TexCoord.x = Lerp( frac, save[0].m_TexCoord.x, save[1].m_TexCoord.x );
+
+ info.verts[1].m_Position.x = Lerp( 0.5f, save[0].m_Position.x, save[1].m_Position.x );
+ info.verts[1].m_TexCoord.x = Lerp( 0.5f, save[0].m_TexCoord.x, save[1].m_TexCoord.x );
+
+ surface()->DrawRenderCharFromInfo( info );
+ }
+ }
+ else if ( frac > 0.5f )
+ {
+ surface()->DrawSetTextPos( x, y );
+
+ // Paint entire left half of next char
+ if ( surface()->DrawGetUnicodeCharRenderInfo( nextchar, info ) )
+ {
+ // Shift tex coord and y position half way down glyph
+ info.verts[1].m_Position.x = Lerp( 0.5f, info.verts[0].m_Position.x, info.verts[1].m_Position.x );
+ info.verts[1].m_TexCoord.x = Lerp( 0.5f, info.verts[0].m_TexCoord.x, info.verts[1].m_TexCoord.x );
+ surface()->DrawRenderCharFromInfo( info );
+ }
+
+ surface()->DrawSetTextPos( x, y );
+
+ // paint a bit of the previous char at far right
+ if ( surface()->DrawGetUnicodeCharRenderInfo( prevchar, info ) )
+ {
+ // Shift tex coord and y position part way up glyph
+ info.verts[0].m_Position.x = Lerp( frac, info.verts[0].m_Position.x, info.verts[1].m_Position.x );
+ info.verts[0].m_TexCoord.x = Lerp( frac, info.verts[0].m_TexCoord.x, info.verts[1].m_TexCoord.x );
+ surface()->DrawRenderCharFromInfo( info );
+ }
+
+ // Paint divider
+
+ surface()->DrawSetTextPos( x, y );
+
+ // Paint from 0.5 to frac of next char
+ if ( surface()->DrawGetUnicodeCharRenderInfo( nextchar, info ) )
+ {
+ vgui::Vertex_t save[2];
+
+ save[0] = info.verts[0];
+ save[1] = info.verts[1];
+
+ info.verts[0].m_Position.x = Lerp( 0.5f, save[0].m_Position.x, save[1].m_Position.x );
+ info.verts[0].m_TexCoord.x = Lerp( 0.5f, save[0].m_TexCoord.x, save[1].m_TexCoord.x );
+
+ info.verts[1].m_Position.x = Lerp( frac, save[0].m_Position.x, save[1].m_Position.x );
+ //info.verts[1].m_TexCoord.x = Lerp( frac, save[0].m_TexCoord.x, save[1].m_TexCoord.x );
+
+ surface()->DrawRenderCharFromInfo( info );
+ }
+ }
+
+ x += ( abcA + abcB + abcC );
+ surface()->DrawSetTextPos( x, y );
+}
+
+void CHudNumeric::PaintRotatedCharacterSpeedomter( int x, int y, vgui::HFont& font, int prevchar, int nextchar, float frac )
+{
+ frac = 3 * frac * frac - 2 * frac * frac * frac;
+
+ int abcA, abcB, abcC;
+ surface()->GetCharABCwide( font, prevchar, abcA, abcB, abcC );
+ // int fontTall = surface()->GetFontTall( font );
+
+ CharRenderInfo info;
+ if ( frac <= 0.0f )
+ {
+ surface()->DrawSetTextPos( x, y );
+
+ // Paint the whole previous char
+ if ( surface()->DrawGetUnicodeCharRenderInfo( prevchar, info ) )
+ {
+ surface()->DrawRenderCharFromInfo( info );
+ }
+ }
+ else if ( frac >= 1.0f )
+ {
+ surface()->DrawSetTextPos( x, y );
+
+ // Paint the whole previous char
+ if ( surface()->DrawGetUnicodeCharRenderInfo( nextchar, info ) )
+ {
+ surface()->DrawRenderCharFromInfo( info );
+ }
+ }
+ else
+ {
+ // Draw part of previous and part of next
+ surface()->DrawSetTextPos( x, y );
+
+ if ( surface()->DrawGetUnicodeCharRenderInfo( prevchar, info ) )
+ {
+ // Shift tex coord and y position part way up glyph
+ info.verts[1].m_Position.y = Lerp( frac, info.verts[0].m_Position.y, info.verts[1].m_Position.y );
+ info.verts[1].m_TexCoord.y = Lerp( frac, info.verts[0].m_TexCoord.y, info.verts[1].m_TexCoord.y );
+ surface()->DrawRenderCharFromInfo( info );
+ }
+
+ // Paint divider
+
+ surface()->DrawSetTextPos( x, y );
+
+ if ( surface()->DrawGetUnicodeCharRenderInfo( nextchar, info ) )
+ {
+ // Shift tex coord and y position part way up glyph
+ info.verts[0].m_Position.y = Lerp( frac, info.verts[0].m_Position.y, info.verts[1].m_Position.y );
+ info.verts[0].m_TexCoord.y = Lerp( frac, info.verts[0].m_TexCoord.y, info.verts[1].m_TexCoord.y );
+ surface()->DrawRenderCharFromInfo( info );
+ }
+ }
+
+ x += ( abcA + abcB + abcC );
+ surface()->DrawSetTextPos( x, y );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : x -
+// y -
+// font -
+// prevchar -
+// nextchar -
+// frac -
+//-----------------------------------------------------------------------------
+void CHudNumeric::PaintRotatedCharacter( int x, int y, HFont& font, int prevchar, int nextchar, float frac )
+{
+ frac = SimpleSpline( frac );
+
+ int abcA[2], abcB[2], abcC[2];
+ surface()->GetCharABCwide( font, prevchar, abcA[0], abcB[0], abcC[0] );
+ surface()->GetCharABCwide( font, nextchar, abcA[1], abcB[1], abcC[1] );
+
+ int w0 = abcA[0] + abcB[0] + abcC[0];
+ int w1 = abcA[1] + abcB[1] + abcC[1];
+
+ int cellwidth = MAX( w0, w1 );
+
+ int fontTall = surface()->GetFontTall( font );
+
+ int dividery = y + clamp( Lerp( frac, 0, fontTall ), 2, fontTall - 2 );
+
+ int xprev = x;
+ int xnext = x;
+
+ int diff = abs( abcB[0] - abcB[1] ) * 0.5f;
+
+ if ( diff != 0 )
+ {
+ // Prev is wider than next, push next right a bit
+ if ( w0 > w1 )
+ {
+ xnext += diff;
+ }
+ else
+ {
+ xprev += diff;
+ }
+ }
+
+ CharRenderInfo info;
+ if ( frac < 0.5f )
+ {
+ surface()->DrawSetTextPos( xprev, y );
+
+ // Paint the bottom half of the prevchar still
+ if ( surface()->DrawGetUnicodeCharRenderInfo( prevchar, info ) )
+ {
+ // Shift tex coord and y position half way down glyph
+ info.verts[0].m_Position.y = Lerp( 0.5f, info.verts[0].m_Position.y, info.verts[1].m_Position.y );
+ info.verts[0].m_TexCoord.y = Lerp( 0.5f, info.verts[0].m_TexCoord.y, info.verts[1].m_TexCoord.y );
+ surface()->DrawRenderCharFromInfo( info );
+ }
+
+ surface()->DrawSetTextPos( xnext, y );
+
+ // Paint up to frac from top of prev char
+ if ( surface()->DrawGetUnicodeCharRenderInfo( nextchar, info ) )
+ {
+ // Shift tex coord and y position part way up glyph
+ info.verts[1].m_Position.y = Lerp( frac, info.verts[0].m_Position.y, info.verts[1].m_Position.y );
+ info.verts[1].m_TexCoord.y = Lerp( frac, info.verts[0].m_TexCoord.y, info.verts[1].m_TexCoord.y );
+ surface()->DrawRenderCharFromInfo( info );
+ }
+
+ // Paint divider
+ if ( frac > 0.0f )
+ {
+ surface()->DrawSetColor( m_CharBgBorder );
+ surface()->DrawLine( x - abcA[0] + 1, dividery, x + abcB[0] + abcC[0] - 1, dividery );
+ }
+
+ surface()->DrawSetTextPos( xprev, y );
+
+ // Paint from frac to 0.5 of nextchar on the top
+ if ( surface()->DrawGetUnicodeCharRenderInfo( prevchar, info ) )
+ {
+ // Shift tex coord and y position half way up glyph
+ vgui::Vertex_t save[2];
+
+ save[0] = info.verts[0];
+ save[1] = info.verts[1];
+
+ info.verts[0].m_Position.y = Lerp( frac, save[0].m_Position.y, save[1].m_Position.y );
+ //info.verts[0].m_TexCoord.y = Lerp( frac, save[0].m_TexCoord.y, save[1].m_TexCoord.y );
+
+ info.verts[1].m_Position.y = Lerp( 0.5f, save[0].m_Position.y, save[1].m_Position.y );
+ info.verts[1].m_TexCoord.y = Lerp( 0.5f, save[0].m_TexCoord.y, save[1].m_TexCoord.y );
+
+ surface()->DrawRenderCharFromInfo( info );
+ }
+ }
+ else if ( frac >= 0.5f )
+ {
+ surface()->DrawSetTextPos( xnext, y );
+
+ // Paint entire top half of next char
+ if ( surface()->DrawGetUnicodeCharRenderInfo( nextchar, info ) )
+ {
+ // Shift tex coord and y position half way down glyph
+ info.verts[1].m_Position.y = Lerp( 0.5f, info.verts[0].m_Position.y, info.verts[1].m_Position.y );
+ info.verts[1].m_TexCoord.y = Lerp( 0.5f, info.verts[0].m_TexCoord.y, info.verts[1].m_TexCoord.y );
+ surface()->DrawRenderCharFromInfo( info );
+ }
+
+ surface()->DrawSetTextPos( xprev, y );
+
+ // paint a bit of the previous char at the bottom
+ if ( surface()->DrawGetUnicodeCharRenderInfo( prevchar, info ) )
+ {
+ // Shift tex coord and y position part way up glyph
+ info.verts[0].m_Position.y = Lerp( frac, info.verts[0].m_Position.y, info.verts[1].m_Position.y );
+ info.verts[0].m_TexCoord.y = Lerp( frac, info.verts[0].m_TexCoord.y, info.verts[1].m_TexCoord.y );
+ surface()->DrawRenderCharFromInfo( info );
+ }
+
+ // Paint divider
+ if ( frac < 1.0f )
+ {
+ surface()->DrawSetColor( m_CharBgBorder );
+ surface()->DrawLine( x - abcA[0] + 1, dividery, x + abcB[0] + abcC[0] - 1, dividery );
+ }
+
+ surface()->DrawSetTextPos( xnext, y );
+
+ // Paint from 0.5 to frac of next char
+ if ( surface()->DrawGetUnicodeCharRenderInfo( nextchar, info ) )
+ {
+ // Shift tex coord and y position half way up glyph
+ vgui::Vertex_t save[2];
+
+ save[0] = info.verts[0];
+ save[1] = info.verts[1];
+
+ info.verts[0].m_Position.y = Lerp( 0.5f, save[0].m_Position.y, save[1].m_Position.y );
+ info.verts[0].m_TexCoord.y = Lerp( 0.5f, save[0].m_TexCoord.y, save[1].m_TexCoord.y );
+
+ info.verts[1].m_Position.y = Lerp( frac, save[0].m_Position.y, save[1].m_Position.y );
+ //info.verts[1].m_TexCoord.y = Lerp( frac, save[0].m_TexCoord.y, save[1].m_TexCoord.y );
+
+ surface()->DrawRenderCharFromInfo( info );
+ }
+ }
+
+ x += cellwidth;
+ surface()->DrawSetTextPos( x, y );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *prev -
+// *next -
+// Output : float
+//-----------------------------------------------------------------------------
+float CHudNumeric::MaxCharacterDiff( const char *prev, const char *next )
+{
+ float maxdiff = 0.0f;
+
+ int textlen = Q_strlen( next );
+ int prevlen = Q_strlen( prev );
+ int ch;
+ for ( ch = 0; ch < textlen; ch++ )
+ {
+ int charfromend = textlen - ch;
+ char c = next[ ch ];
+ char prevc = prev[ MAX( 0, prevlen - charfromend ) ];
+ if ( prevc == 0 )
+ {
+ int tempindex = FindPrintableIndex( c );
+ if ( tempindex != m_Printables.InvalidIndex() )
+ {
+ tempindex = MAX( 0, tempindex - 3 );
+ prevc = m_Printables[ tempindex ];
+ }
+ else
+ {
+ prevc = c;
+ }
+ }
+
+ float diff = (float)fabs( FindPrintableIndex( c ) - FindPrintableIndex( prevc ) );
+
+ if ( diff > maxdiff )
+ {
+ maxdiff = diff;
+ }
+ }
+
+ float maxdelta = maxdiff;
+
+ if ( m_nRotaryMaxDelta != 0 )
+ {
+ maxdelta = MIN( (float)m_nRotaryMaxDelta, maxdelta );
+ }
+
+ return maxdelta;
+}
+
+int CHudNumeric::ComputePixelsRequired( vgui::HFont& font, const char *text, int textlen )
+{
+ int pixels = 0;
+ for ( int ch = 0; ch < textlen; ch++ )
+ {
+ char c = text[ ch ];
+ pixels += surface()->GetCharacterWidth( font, c );
+ }
+ return pixels;
+}
+
+void CHudNumeric::DrawCharacterBackground( const char *text, int textlen, HFont& font, int x, int y )
+{
+ int abcA, abcB, abcC;
+ int fontTall = surface()->GetFontTall( font );
+
+ int ch;
+ int curx = x - ComputePixelsRequired( font, text, textlen );
+ for ( ch = 0; ch < textlen; ch++ )
+ {
+ char c = text[ ch ];
+
+ surface()->GetCharABCwide( font, c, abcA, abcB, abcC );
+
+ curx += abcA;
+
+ surface()->DrawSetColor( m_CharBg );
+ surface()->DrawFilledRect( curx - abcA, y + 2, curx + abcB + abcC, y + fontTall - 2 );
+
+ if ( m_bDrawCharacterBackgroundBorder )
+ {
+ surface()->DrawSetColor( m_CharBgBorder );
+ surface()->DrawOutlinedRect( curx - abcA, y + 2, curx + abcB + abcC, y + fontTall - 2 );
+ }
+
+ curx += ( abcB + abcC );
+ }
+}
+
+void CHudNumeric::DrawCharacterForeground( const char *text, int textlen, HFont& font, int x, int y )
+{
+ if ( m_nRotaryEffect == ROTARY_EFFECT_NONE ||
+ m_nRotaryEffect == ROTARY_EFFECT_SPEEDOMETER )
+ return;
+
+ int abcA, abcB, abcC;
+ int fontTall = surface()->GetFontTall( font );
+
+ int ch;
+ int curx = x - ComputePixelsRequired( font, text, textlen );
+ for ( ch = 0; ch < textlen; ch++ )
+ {
+ char c = text[ ch ];
+
+ surface()->GetCharABCwide( font, c, abcA, abcB, abcC );
+
+ curx += abcA;
+
+ switch ( m_nRotaryEffect )
+ {
+ default:
+ case ROTARY_EFFECT_VERTICAL_ALARM:
+ {
+ surface()->DrawSetColor( m_CharFg );
+ surface()->DrawLine( curx - abcA + 1, y + fontTall / 2, curx + abcB + abcC - 1, y + fontTall / 2 );
+ }
+ break;
+ case ROTARY_EFFECT_HORIZONTAL_ALARM:
+ {
+ surface()->DrawSetColor( m_CharFg );
+ int avex = curx + ( - abcA + abcB + abcC ) / 2;
+ surface()->DrawLine( avex, y + 2, avex, y + fontTall - 2 );
+ }
+ break;
+ }
+
+ curx += ( abcB + abcC );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *text -
+// textlen -
+// font -
+// x -
+// y -
+//-----------------------------------------------------------------------------
+void CHudNumeric::PaintStringRotary( float t, const char *text, int textlen, HFont& font, int x, int y )
+{
+ surface()->DrawSetTextFont( font );
+ int ch;
+
+ int prevlen = Q_strlen( m_szLatchedValue );
+
+ // Compute pixels actually required
+ int pixels = 0;
+
+ for ( ch = 0; ch < textlen; ch++ )
+ {
+ int charfromend = textlen - ch;
+ char c = text[ ch ];
+ char prevc = m_szLatchedValue[ MAX( 0, prevlen - charfromend ) ];
+ if ( prevc == 0 )
+ {
+ int tempindex = FindPrintableIndex( c );
+ if ( tempindex != m_Printables.InvalidIndex() )
+ {
+ tempindex = MAX( 0, tempindex - 3 );
+ prevc = m_Printables[ tempindex ];
+ }
+ else
+ {
+ prevc = c;
+ }
+ }
+
+ float diff = (float)fabs( FindPrintableIndex( c ) - FindPrintableIndex( prevc ) );
+
+ if ( m_nRotaryMaxDelta != 0 )
+ {
+ diff = MIN( (float)m_nRotaryMaxDelta, diff );
+ }
+
+ float dt = diff / m_flActualCharactersPerSecond;
+
+ float frac = 1.0f;
+ if ( dt > 0.0f )
+ {
+ frac = t / MIN( dt, m_flRotaryTime );
+ }
+ frac = clamp( frac, 0.0f, 1.0f );
+
+ float s;
+ char chstart, chend;
+ GetRotatedChar( frac, prevc, c, chstart, chend, s );
+
+ int w0 = surface()->GetCharacterWidth( font, chstart );
+ int w1 = surface()->GetCharacterWidth( font, chend );
+
+ pixels += MAX( w0, w1 );
+ }
+
+ surface()->DrawSetTextPos( x - pixels, y );
+
+ // Now render
+ for ( ch = 0; ch < textlen; ch++ )
+ {
+ int charfromend = textlen - ch;
+ char c = text[ ch ];
+ char prevc = m_szLatchedValue[ MAX( 0, prevlen - charfromend ) ];
+ if ( prevc == 0 )
+ {
+ int tempindex = FindPrintableIndex( c );
+ if ( tempindex != m_Printables.InvalidIndex() )
+ {
+ tempindex = MAX( 0, tempindex - 3 );
+ prevc = m_Printables[ tempindex ];
+ }
+ else
+ {
+ prevc = c;
+ }
+ }
+
+ float diff = (float)fabs( FindPrintableIndex( c ) - FindPrintableIndex( prevc ) );
+
+ if ( m_nRotaryMaxDelta != 0 )
+ {
+ diff = MIN( (float)m_nRotaryMaxDelta, diff );
+ }
+
+ float dt = diff / m_flActualCharactersPerSecond;
+
+ float frac = 1.0f;
+ if ( dt > 0.0f )
+ {
+ frac = t / MIN( dt, m_flRotaryTime );
+ }
+ frac = clamp( frac, 0.0f, 1.0f );
+
+ float s;
+ char chstart, chend;
+ GetRotatedChar( frac, prevc, c, chstart, chend, s );
+ int outx, outy;
+ surface()->DrawGetTextPos( outx, outy );
+ switch ( m_nRotaryEffect )
+ {
+ default:
+ case ROTARY_EFFECT_VERTICAL_ALARM:
+ {
+ PaintRotatedCharacter( outx, outy, font, chstart, chend, s );
+ }
+ break;
+ case ROTARY_EFFECT_HORIZONTAL_ALARM:
+ {
+ PaintRotatedCharacterHoriz( outx, outy, font, chstart, chend, s );
+ }
+ break;
+ case ROTARY_EFFECT_SPEEDOMETER:
+ {
+ PaintRotatedCharacterSpeedomter( outx, outy, font, chstart, chend, s );
+ }
+ break;
+ }
+
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *text -
+// textlen -
+// font -
+// x -
+// y -
+//-----------------------------------------------------------------------------
+void CHudNumeric::PaintString( const char *text, int textlen, HFont& font, int x, int y )
+{
+ if ( m_nRotaryEffect != ROTARY_EFFECT_NONE &&
+ IsRotating() &&
+ m_flRotaryTime > 0.0f )
+ {
+ float rotation_time = gpGlobals->curtime - m_flRotaryStartTime;
+
+ PaintStringRotary( rotation_time, text, textlen, font, x, y );
+
+ return;
+ }
+ PaintStringNormal( text, textlen, font, x, y );
+}
+
+void CHudNumeric::PaintStringNormal( const char *text, int textlen, vgui::HFont& font, int x, int y )
+{
+ surface()->DrawSetTextFont( font );
+ int ch;
+ surface()->DrawSetTextPos( x - ComputePixelsRequired( font, text, textlen ), y );
+
+ for ( ch = 0; ch < textlen; ch++ )
+ {
+ char c = text[ ch ];
+ surface()->DrawUnicodeChar( c );
+ }
+}
+
+void CHudNumeric::PaintBackground( void )
+{
+ char value[ MAX_VALUE_LENGTH ];
+
+ if ( !GetValue( value, sizeof( value ) ) )
+ return;
+
+ float alpha = m_flAlphaOverride / 255.0f;
+
+ Color boxColor = GetBoxColor();
+ boxColor[3] *= alpha;
+
+ SetBgColor( boxColor );
+
+ BaseClass::PaintBackground();
+
+ if ( !m_bUseIcon )
+ return;
+
+ CHudTexture *tex = m_hIcon;
+ if ( !tex )
+ return;
+
+ Color iconColor = m_IconColor;
+ iconColor[3] *= alpha;
+
+ tex->DrawSelf( m_flIconXPos, m_flIconYPos, m_flIconWidth, m_flIconHeight, iconColor );
+}
+
+void CHudNumeric::PaintValue( const char *value, int textlen, int wide, int tall, Color& clr )
+{
+ float alpha = m_flAlphaOverride / 255.0f;
+
+ Color boxColor = GetBoxColor();
+ boxColor[3] *= alpha;
+
+ SetBgColor( boxColor );
+
+ Color useColor = clr;
+ useColor[3] *= alpha;
+
+ surface()->DrawSetTextColor( useColor );
+
+ int x = wide - label_xpos_right;
+ int y = label_ypos;
+
+ if ( m_bDrawLabel )
+ {
+ // Label
+ PaintStringNormal( GetLabelText(), Q_strlen( GetLabelText() ), m_hLabelFont, x, y );
+ }
+
+ x = wide - value_xpos_right;
+ y = value_ypos;
+
+ if ( m_nRotaryEffect != ROTARY_EFFECT_NONE &&
+ (bool)m_bDrawCharacterBackground )
+ {
+ DrawCharacterBackground( value, textlen, m_hTextFont, x, y );
+ }
+
+ PaintString( value, textlen, m_hTextFont, x, y );
+
+ if ( m_nRotaryEffect != ROTARY_EFFECT_NONE &&
+ (bool)m_bDrawCharacterForeground )
+ {
+ DrawCharacterForeground( value, textlen, m_hTextFont, x, y );
+ }
+
+ // draw the overbright blur
+ for (float fl = m_flBlur; fl > 0.0f; fl -= 1.0f)
+ {
+ if (fl >= 1.0f)
+ {
+ PaintString( value, textlen, m_hTextFontPulsing, x, y );
+ }
+ else
+ {
+ // draw a percentage of the last one
+ Color col = useColor;
+ col[3] *= fl;
+ surface()->DrawSetTextColor(col);
+ PaintString( value, textlen, m_hTextFontPulsing, x, y );
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Output : vgui::Color
+//-----------------------------------------------------------------------------
+Color CHudNumeric::GetColor()
+{
+ return m_TextColor;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Output : vgui::Color
+//-----------------------------------------------------------------------------
+Color CHudNumeric::GetBoxColor()
+{
+ return m_BoxColor;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Redraw
+//-----------------------------------------------------------------------------
+void CHudNumeric::Paint( void )
+{
+ char value[ MAX_VALUE_LENGTH ];
+
+ if ( !GetValue( value, sizeof( value ) ) )
+ return;
+
+ int w, h;
+ GetSize( w, h );
+
+ bool dopulse = ( Q_strcmp( value, m_szPreviousValue ) != 0 ) || ( m_bPulseForced );
+ bool increment = false;
+ if ( dopulse )
+ {
+ if ( atof( m_szPreviousValue ) <= atof( value ) )
+ {
+ increment = true;
+ }
+
+ Q_strncpy( m_szLatchedValue, m_szPreviousValue, sizeof( m_szLatchedValue ) );
+ m_nTextLen = Q_strlen( value );
+
+ m_flRotaryStartTime = gpGlobals->curtime;
+ float maxdiff = MaxCharacterDiff( m_szLatchedValue, value );
+ float timerequired = maxdiff / m_flDesiredCharactersPerSecond;
+ m_flActualCharactersPerSecond = (float)m_flDesiredCharactersPerSecond;
+ m_flRotaryTime = MIN( m_flRotaryTimeMax, timerequired );
+ if ( m_flRotaryTime < timerequired )
+ {
+ // Speed up rotation since we're moving so far
+ m_flActualCharactersPerSecond = ( timerequired / m_flRotaryTime ) * m_flDesiredCharactersPerSecond;
+ }
+ }
+
+ Q_strncpy( m_szPreviousValue, value, sizeof( m_szPreviousValue ) );
+
+ Color clr = GetColor();
+ PaintValue( value, m_nTextLen, w, h, clr );
+
+ if ( dopulse && m_bSendPulses )
+ {
+ // Start with a short pulse
+ g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( GetPulseEvent( increment ) );
+
+ m_bPulseForced = false;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Derived class has forced a pulse
+//-----------------------------------------------------------------------------
+void CHudNumeric::ForcePulse( void )
+{
+ m_bPulseForced = true;
+}
diff --git a/game/client/tf2/hud_numeric.h b/game/client/tf2/hud_numeric.h
new file mode 100644
index 0000000..20db7f5
--- /dev/null
+++ b/game/client/tf2/hud_numeric.h
@@ -0,0 +1,140 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef HUD_NUMERIC_H
+#define HUD_NUMERIC_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "hudelement.h"
+#include <vgui_controls/Panel.h>
+
+class CHudNumeric : public CHudElement, public vgui::Panel
+{
+ DECLARE_CLASS_SIMPLE( CHudNumeric, vgui::Panel );
+
+public:
+
+ CHudNumeric( const char *pElementName, const char *panelName );
+
+ void SetDrawLabel( bool draw ) { m_bDrawLabel = draw; }
+ void SetDoPulses( bool dopulses ) { m_bSendPulses = dopulses; }
+ void ForcePulse( void );
+
+ void SetRotaryEffect( int rotary ) { m_nRotaryEffect = rotary; }
+ void SetRotaryTimeMax( float maxTime ) { m_flRotaryTimeMax = maxTime; }
+ void SetRotaryCharsPerSecond( float cps ) { m_flDesiredCharactersPerSecond = cps; }
+
+ // vgui::Panel overrides.
+ virtual void Paint( void );
+ virtual void PaintBackground( void );
+
+ virtual void ApplySchemeSettings(vgui::IScheme *pScheme);
+
+ virtual const char *GetLabelText() = 0;
+ virtual const char *GetPulseEvent( bool increment ) = 0;
+ virtual bool GetValue( char *val, int maxlen ) = 0;
+
+ virtual Color GetColor();
+ virtual Color GetBoxColor();
+
+ static void BuildPrintablesList( void );
+ static int FindPrintableIndex( int ch );
+
+protected:
+ enum
+ {
+ ROTARY_EFFECT_NONE = 0,
+ ROTARY_EFFECT_VERTICAL_ALARM,
+ ROTARY_EFFECT_HORIZONTAL_ALARM,
+ ROTARY_EFFECT_SPEEDOMETER
+ };
+
+ enum
+ {
+ MAX_VALUE_LENGTH = 128,
+ };
+
+ void PaintValue( const char *value, int textlen, int wide, int tall, Color& clr );
+ void PaintString( const char *text, int textlen, vgui::HFont& font, int x, int y );
+ void PaintStringNormal( const char *text, int textlen, vgui::HFont& font, int x, int y );
+
+ void PaintStringRotary( float t, const char *text, int textlen, vgui::HFont& font, int x, int y );
+
+ void GetRotatedChar( float frac, char startchar, char endchar,
+ char& prevchar, char& nextchar, float& subfrac );
+ void PaintRotatedCharacter( int x, int y, vgui::HFont& font, int prevchar, int nextchar, float frac );
+ void PaintRotatedCharacterHoriz( int x, int y, vgui::HFont& font, int prevchar, int nextchar, float frac );
+ void PaintRotatedCharacterSpeedomter( int x, int y, vgui::HFont& font, int prevchar, int nextchar, float frac );
+
+ bool IsRotating( void ) const;
+
+ float MaxCharacterDiff( const char *prev, const char *next );
+ void DrawCharacterBackground( const char *text, int textlen, vgui::HFont& font, int x, int y );
+ void DrawCharacterForeground( const char *text, int textlen, vgui::HFont& font, int x, int y );
+
+ int ComputePixelsRequired( vgui::HFont& font, const char *text, int textlen );
+
+ int m_nTextLen;
+ char m_szPreviousValue[ MAX_VALUE_LENGTH ];
+ char m_szLatchedValue[ MAX_VALUE_LENGTH ];
+
+ bool m_bDrawLabel;
+ bool m_bSendPulses;
+ bool m_bPulseForced;
+
+ float m_flRotaryTime;
+ float m_flRotaryStartTime;
+ float m_flActualCharactersPerSecond;
+
+ static CUtlRBTree< int, int > m_Printables;
+ static bool s_bPrintablesBuilt;
+
+ CPanelAnimationVar( int, m_nRotaryEffect, "Rotary", "0" );
+ CPanelAnimationVar( int, m_nRotaryMaxDelta, "RotaryMaxDelta", "0" );
+ CPanelAnimationVar( float, m_flRotaryTimeMax, "RotaryMaxTime", "2.0" );
+ CPanelAnimationVar( float, m_flDesiredCharactersPerSecond, "RotarySpeed", "7.0" );
+
+ CPanelAnimationVar( bool, m_bDrawCharacterBackground, "DrawCharacterBackground", "false" );
+ CPanelAnimationVar( bool, m_bDrawCharacterForeground, "DrawCharacterForeground", "false" );
+ CPanelAnimationVar( bool, m_bDrawCharacterBackgroundBorder, "DrawCharacterBackgroundBorder", "false" );
+
+ CPanelAnimationVar( float, m_flBlur, "Blur", "0" );
+ CPanelAnimationVar( float, m_flAlphaOverride, "Alpha", "255" );
+
+ CPanelAnimationVar( Color, m_TextColor, "TextColor", "NumericText" );
+ CPanelAnimationVar( Color, m_TextColorWarning, "TextColorWarning", "NumericTextWarning" );
+ CPanelAnimationVar( Color, m_TextColorCritical, "TextColorCritical", "NumericTextCritical" );
+
+ CPanelAnimationVar( Color, m_BoxColor, "BoxColor", "NumericBox" );
+ CPanelAnimationVar( Color, m_BoxColorWarning, "BoxColorWarning", "NumericBoxWarning" );
+ CPanelAnimationVar( Color, m_BoxColorCritical, "BoxColorCritical", "NumericBoxCritical" );
+
+ CPanelAnimationVar( Color, m_CharBg, "CharBackground", "NumericCharBg" );
+ CPanelAnimationVar( Color, m_CharBgBorder, "CharBackgroundBorder", "NumericCharBgBorder" );
+ CPanelAnimationVar( Color, m_CharFg, "CharForeground", "NumericCharFg" );
+
+ CPanelAnimationVar( vgui::HFont, m_hLabelFont, "LabelFont", "HudNumbersLabelFont" );
+ CPanelAnimationVar( vgui::HFont, m_hTextFont, "TextFont", "HudNumbersSmall" );
+ CPanelAnimationVar( vgui::HFont, m_hTextFontPulsing, "TextFontPulsing", "HudNumbersSmallGlow" );
+
+ CPanelAnimationVarAliasType( float, label_ypos, "label_ypos", "2", "proportional_float" );
+ CPanelAnimationVarAliasType( float, label_xpos_right, "label_xpos_right", "5", "proportional_float" );
+ CPanelAnimationVarAliasType( float, value_ypos, "value_ypos", "12", "proportional_float" );
+ CPanelAnimationVarAliasType( float, value_xpos_right, "value_xpos_right", "5", "proportional_float" );
+
+ CPanelAnimationVar( bool, m_bUseIcon, "UseIcon", "false" );
+ CPanelAnimationVarAliasType( float, m_flIconWidth, "IconWidth", "60", "proportional_float" );
+ CPanelAnimationVarAliasType( float, m_flIconHeight, "IconHeight", "30", "proportional_float" );
+ CPanelAnimationVarAliasType( float, m_flIconXPos, "IconXPos", "10", "proportional_float" );
+ CPanelAnimationVarAliasType( float, m_flIconYPos, "IconYPos", "4", "proportional_float" );
+ CPanelAnimationVar( CHudTextureHandle, m_hIcon, "IconTexture", "" );
+ CPanelAnimationVar( Color, m_IconColor, "IconColor", "NumericText" );
+};
+
+#endif // HUD_NUMERIC_H
diff --git a/game/client/tf2/hud_orders.cpp b/game/client/tf2/hud_orders.cpp
new file mode 100644
index 0000000..30f2ec3
--- /dev/null
+++ b/game/client/tf2/hud_orders.cpp
@@ -0,0 +1,278 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Order window
+//
+// $NoKeywords: $
+//=============================================================================//
+#include "cbase.h"
+#include "hud_orders.h"
+#include "hud.h"
+#include "c_basetfplayer.h"
+#include "clientmode_tfnormal.h"
+#include "VGUI_BasePanel.h"
+#include <vgui/IScheme.h>
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CHudLabel::SetSelected( bool bSelected )
+{
+ m_bSelected = bSelected;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+CHudOrderList *GetHudOrderList( void )
+{
+ return GET_HUDELEMENT( CHudOrderList );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+CHudOrder::CHudOrder( int x,int y,int wide,int tall ) : vgui::Panel( NULL, "CHudOrder")
+{
+ SetBounds( x, y, wide, tall );
+ SetAutoDelete( false );
+ m_pOrder = NULL;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+CHudOrder::~CHudOrder( void )
+{
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CHudOrder::Init( void )
+{
+ SetSize( ORDERS_ELEMENT_WIDTH, ORDERS_ELEMENT_HEIGHT );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Called every frame
+//-----------------------------------------------------------------------------
+void CHudOrder::Paint( void )
+{
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CHudOrder::SetOrder( C_Order *pOrder )
+{
+ // If we had an order, tell it to clean up
+ if ( m_pOrder )
+ {
+ m_pOrder->DestroyStatus();
+ }
+
+ m_pOrder = pOrder;
+
+ // Tell the order to create it's elements
+ if ( m_pOrder )
+ {
+ m_pOrder->CreateStatus( this );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+C_Order *CHudOrder::GetOrder( void )
+{
+ return m_pOrder;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CHudOrder::UpdateOrder( void )
+{
+ if ( m_pOrder == NULL )
+ return;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Our order has been deleted.
+//-----------------------------------------------------------------------------
+void CHudOrder::OrderRemoved( void )
+{
+ m_pOrder = NULL;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CHudOrder::ApplySchemeSettings(vgui::IScheme *pScheme)
+{
+ Panel::ApplySchemeSettings(pScheme);
+
+ if ( m_pOrder && m_pOrder->IsPersonalOrder() )
+ {
+ SetBgColor( GetSchemeColor("HudStatusSelectedBgColor", pScheme) );
+ }
+ else
+ {
+ SetBgColor( GetSchemeColor("HudStatusBgColor", pScheme) );
+ }
+}
+
+//================================================================================================================
+// LARGE STATUS PANEL.
+//================================================================================================================
+// Purpose:
+//-----------------------------------------------------------------------------
+CHudOrderList::CHudOrderList( const char *pElementName ) :
+ CHudElement( pElementName ), vgui::Panel( NULL, "HudOrderList" )
+{
+ vgui::Panel *pParent = g_pClientMode->GetViewport();
+ SetParent( pParent );
+
+ SetPaintBackgroundEnabled( false );
+ for (int i = 0; i < MAX_HUD_ORDERS; i++)
+ {
+ m_pOrderPanels[i] = NULL;
+ m_pOrderLabels[i] = NULL;
+ }
+
+ SetHiddenBits( HIDEHUD_MISCSTATUS | HIDEHUD_PLAYERDEAD );
+}
+
+DECLARE_HUDELEMENT( CHudOrderList );
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+CHudOrderList::~CHudOrderList( void )
+{
+ for (int i = 0; i < MAX_HUD_ORDERS; i++)
+ {
+ if ( m_pOrderPanels[i] )
+ {
+ delete m_pOrderPanels[i];
+ delete m_pOrderLabels[i];
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CHudOrderList::LevelInit( void )
+{
+ SetPos( ORDERS_LEFT, ORDERS_TOP );
+ SetSize( ORDERS_WIDTH, ORDERS_HEIGHT );
+
+ for ( int i = 0; i < MAX_HUD_ORDERS; i++ )
+ {
+ m_pOrderPanels[i] = new CHudOrder( ORDERS_ELEMENT_LEFT - ORDERS_LEFT, ORDERS_ELEMENT_HEIGHT * i, ORDERS_ELEMENT_WIDTH, ORDERS_ELEMENT_HEIGHT );
+ m_pOrderPanels[i]->Init();
+
+ m_pOrderLabels[i] = new CHudLabel( NULL, "orderlabels", " " );
+ m_pOrderLabels[i]->SetBounds( 0, ORDERS_ELEMENT_HEIGHT * i, ORDERS_ELEMENT_LEFT - ORDERS_LEFT, ORDERS_ELEMENT_HEIGHT );
+ m_pOrderLabels[i]->SetContentAlignment( vgui::Label::a_northwest );
+ m_pOrderLabels[i]->SetTextInset( 4, 0 );
+
+ // Start all of them hidden
+ m_pOrderPanels[i]->SetParent( (vgui::Panel *)NULL );
+ m_pOrderLabels[i]->SetParent( (vgui::Panel *)NULL );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CHudOrderList::LevelShutdown( void )
+{
+ for ( int i = 0; i < MAX_HUD_ORDERS; i++ )
+ {
+ delete m_pOrderPanels[i];
+ m_pOrderPanels[i] = NULL;
+ delete m_pOrderLabels[i];
+ m_pOrderLabels[i] = NULL;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CHudOrderList::OnThink( void )
+{
+ // Call update for all active objects
+ for (int i = 0; i < MAX_HUD_ORDERS; i++)
+ {
+ if ( m_pOrderPanels[i] && m_pOrderPanels[i]->GetOrder() )
+ {
+ m_pOrderPanels[i]->UpdateOrder();
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CHudOrderList::Paint( void )
+{
+// vgui::surface()->DrawSetColor( 255,0,0, 64 );
+// vgui::surface()->DrawOutlinedRect( 0,0, GetWide(), GetTall() );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Insert the specified order into the slot
+//-----------------------------------------------------------------------------
+void CHudOrderList::InsertOrder( C_Order *pOrder, int iSlot )
+{
+ // Personal Orders don't have selection keys
+ if ( pOrder->IsPersonalOrder() )
+ {
+ m_pOrderLabels[iSlot]->SetText("");
+ }
+ else
+ {
+ // Check the key binding
+ char binding[64];
+ Q_snprintf(binding, sizeof( binding ), "order %d", iSlot+1);
+ const char *pBinding = engine->Key_LookupBinding( binding );
+ if ( pBinding && strcmp(pBinding,"") )
+ {
+ m_pOrderLabels[iSlot]->SetText( pBinding );
+ }
+ }
+
+ // Only insert it if it's not there already
+ if ( m_pOrderPanels[iSlot]->GetOrder() != pOrder )
+ {
+ m_pOrderPanels[iSlot]->SetOrder( pOrder );
+ m_pOrderPanels[iSlot]->SetParent( this );
+ m_pOrderLabels[iSlot]->SetParent( this );
+ m_pOrderLabels[iSlot]->SetSelected( pOrder->IsPersonalOrder() );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: We've received a new order, or a modified old one. Figure out what to do.
+//-----------------------------------------------------------------------------
+void CHudOrderList::RecalculateOrderList( void )
+{
+ C_BaseTFPlayer *pPlayer = C_BaseTFPlayer::GetLocalPlayer();
+
+ // Does this player have a personal order?
+ C_Order *pOrder = pPlayer->PersonalOrder();
+ if( pOrder )
+ {
+ // Highlight the selected order (and the personal order always)
+ m_pOrderPanels[0]->SetBgColor( Color( 0,0,0, 192) );
+ m_pOrderLabels[0]->SetBgColor( Color( 0,0,0, 192) );
+ }
+}
+
diff --git a/game/client/tf2/hud_orders.h b/game/client/tf2/hud_orders.h
new file mode 100644
index 0000000..4015b30
--- /dev/null
+++ b/game/client/tf2/hud_orders.h
@@ -0,0 +1,87 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Order window
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef ORDERS_H
+#define ORDERS_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include <vgui_controls/Panel.h>
+#include <vgui_controls/Label.h>
+#include "c_order.h"
+#include "hudelement.h"
+
+class CHudLabel;
+
+#define MAX_HUD_ORDERS 1 // Number of orders to show in the HUD
+
+//-----------------------------------------------------------------------------
+// Purpose: Panel used to display the status for an order
+//-----------------------------------------------------------------------------
+class CHudOrder : public vgui::Panel
+{
+public:
+ CHudOrder( int x,int y,int wide,int tall );
+ ~CHudOrder( void );
+
+ virtual void Init( void );
+ virtual void Paint( void );
+
+ // Order handling
+ virtual void SetOrder( C_Order *pOrder );
+ virtual C_Order *GetOrder( void );
+ virtual void UpdateOrder( void );
+ virtual void OrderRemoved( void );
+ virtual void ApplySchemeSettings( vgui::IScheme *pScheme );
+
+private:
+ C_Order *m_pOrder; // Order that this panel holds
+};
+
+//-----------------------------------------------------------------------------
+// Purpose: Panel that holds all the individual order panels
+//-----------------------------------------------------------------------------
+class CHudOrderList : public CHudElement, public vgui::Panel
+{
+ DECLARE_CLASS_SIMPLE( CHudOrderList, vgui::Panel );
+public:
+ DECLARE_MULTIPLY_INHERITED();
+
+ CHudOrderList( const char *pElementName );
+ ~CHudOrderList( void );
+
+ virtual void LevelInit( void );
+ virtual void LevelShutdown( void );
+ virtual void OnThink( void );
+ virtual void Paint( void );
+
+ // Order handling
+ void RecalculateOrderList( void );
+ void InsertOrder( C_Order *pOrder, int iSlot );
+
+private:
+ CHudOrder *m_pOrderPanels[ MAX_HUD_ORDERS ];
+ CHudLabel *m_pOrderLabels[ MAX_HUD_ORDERS ];
+};
+
+extern CHudOrderList *GetHudOrderList( void );
+
+// Position & Size
+// X
+#define ORDERS_LEFT (ScreenWidth() - 5 - XRES(112))
+#define ORDERS_RIGHT (ScreenWidth() - 5 )
+#define ORDERS_WIDTH (ORDERS_RIGHT - ORDERS_LEFT)
+#define ORDERS_ELEMENT_LEFT XRES(32)
+#define ORDERS_ELEMENT_WIDTH (ORDERS_RIGHT - ORDERS_ELEMENT_LEFT)
+// Y
+#define ORDERS_BOTTOM YRES(412)
+#define ORDERS_ELEMENT_HEIGHT YRES(32)
+#define ORDERS_TOP (ORDERS_BOTTOM - (ORDERS_ELEMENT_HEIGHT * MAX_HUD_ORDERS))
+#define ORDERS_HEIGHT (ORDERS_BOTTOM - ORDERS_TOP)
+
+#endif // ORDER_H
diff --git a/game/client/tf2/hud_resources.cpp b/game/client/tf2/hud_resources.cpp
new file mode 100644
index 0000000..8b0a1ca
--- /dev/null
+++ b/game/client/tf2/hud_resources.cpp
@@ -0,0 +1,131 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Hud display of the local player's resource counts
+//
+// $NoKeywords: $
+//=============================================================================//
+#include "cbase.h"
+#include "hud_numeric.h"
+#include "c_basetfplayer.h"
+#include "hud_macros.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+class CHudResources : public CHudNumeric
+{
+ DECLARE_CLASS_SIMPLE( CHudResources, CHudNumeric )
+public:
+ CHudResources( const char *pElementName );
+
+ virtual const char *GetLabelText() { return m_szResourcesLabel; }
+ virtual const char *GetPulseEvent( bool increment ) { return increment ? "ResourceIncrement" : "ResourceDecrement"; }
+ virtual bool GetValue( char *val, int maxlen );
+
+private:
+ bool GetResourceCount( int& value );
+
+ CPanelAnimationStringVar( 128, m_szResourcesLabel, "ResourcesLabel", "Resources" );
+};
+
+DECLARE_HUDELEMENT( CHudResources );
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+CHudResources::CHudResources( const char *pElementName ) : CHudNumeric( pElementName, "HudResources")
+{
+ SetHiddenBits( HIDEHUD_HEALTH | HIDEHUD_PLAYERDEAD );
+}
+
+bool CHudResources::GetValue( char *val, int maxlen )
+{
+ int bank = 0;
+ if ( !GetResourceCount( bank ) )
+ return false;
+
+ Q_snprintf( val, maxlen, "%i", bank );
+ return true;
+}
+
+bool CHudResources::GetResourceCount( int& value )
+{
+ C_BaseTFPlayer *pPlayer = C_BaseTFPlayer::GetLocalPlayer();
+ if ( !pPlayer )
+ return false;
+ if ( pPlayer->GetTeamNumber() == 0)
+ return false;
+
+ value = pPlayer->m_TFLocal.m_iBankResources;
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+class CHudResourcesPickup : public CHudNumeric
+{
+ DECLARE_CLASS_SIMPLE( CHudResourcesPickup, CHudNumeric )
+public:
+ CHudResourcesPickup( const char *pElementName );
+
+ virtual void Init( void );
+ virtual const char *GetLabelText() { return m_szResourcesPickupLabel; }
+ virtual const char *GetPulseEvent( bool increment ) { return "ResourcePickup"; }
+ virtual bool GetValue( char *val, int maxlen );
+
+ // Handler for our message
+ void MsgFunc_PickupRes( bf_read &msg );
+
+private:
+ int m_iPickupAmount;
+
+ CPanelAnimationStringVar( 128, m_szResourcesPickupLabel, "ResourcesPickupLabel", "" );
+};
+
+DECLARE_HUDELEMENT( CHudResourcesPickup );
+DECLARE_HUD_MESSAGE( CHudResourcesPickup, PickupRes );
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+CHudResourcesPickup::CHudResourcesPickup( const char *pElementName ) : CHudNumeric( pElementName, "HudResourcesPickup")
+{
+ m_iPickupAmount = 0;
+
+ SetHiddenBits( HIDEHUD_HEALTH | HIDEHUD_PLAYERDEAD );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CHudResourcesPickup::Init( void )
+{
+ HOOK_HUD_MESSAGE( CHudResourcesPickup, PickupRes );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+bool CHudResourcesPickup::GetValue( char *val, int maxlen )
+{
+ if ( !m_iPickupAmount )
+ return false;
+
+ Q_snprintf( val, maxlen, "+%i", m_iPickupAmount );
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Message handler for PickupRes message
+//-----------------------------------------------------------------------------
+void CHudResourcesPickup::MsgFunc_PickupRes( bf_read &msg )
+{
+ m_iPickupAmount = msg.ReadByte();
+
+ ForcePulse();
+} \ No newline at end of file
diff --git a/game/client/tf2/hud_target_id.cpp b/game/client/tf2/hud_target_id.cpp
new file mode 100644
index 0000000..46abca8
--- /dev/null
+++ b/game/client/tf2/hud_target_id.cpp
@@ -0,0 +1,230 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: HUD Target ID element
+//
+// $NoKeywords: $
+//=============================================================================//
+#include "cbase.h"
+#include "hud.h"
+#include "hudelement.h"
+#include "imessagechars.h"
+#include "c_basetfplayer.h"
+#include "c_playerresource.h"
+#include "vgui_EntityPanel.h"
+#include "vgui_healthbar.h"
+#include "commanderoverlay.h"
+#include "c_baseobject.h"
+#include "iclientmode.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)
+
+
+//-----------------------------------------------------------------------------
+// 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;
+ char m_sIDString[ MAX_ID_STRING ];
+};
+
+DECLARE_HUDELEMENT( CTargetID );
+
+//-----------------------------------------------------------------------------
+// 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;
+ m_sIDString[0] = 0;
+
+ SetHiddenBits( HIDEHUD_MISCSTATUS );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Setup
+//-----------------------------------------------------------------------------
+void CTargetID::Init( void )
+{
+};
+
+void CTargetID::ApplySchemeSettings( vgui::IScheme *scheme )
+{
+ BaseClass::ApplySchemeSettings( scheme );
+
+ SetPaintBackgroundEnabled( false );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: clear out string etc between levels
+//-----------------------------------------------------------------------------
+void CTargetID::VidInit()
+{
+ CHudElement::VidInit();
+
+ m_flLastChangeTime = 0;
+ m_iLastEntIndex = 0;
+ m_sIDString[0] = 0;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Draw function for the element
+//-----------------------------------------------------------------------------
+void CTargetID::Paint()
+{
+ C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
+ if ( !pPlayer )
+ return;
+
+ // No id if still choosing class
+ if ( C_BaseTFPlayer::GetLocalPlayer()->GetClass() == TFCLASS_UNDECIDED )
+ return;
+
+ // Get our target's ent index
+ int iEntIndex = C_BaseTFPlayer::GetLocalPlayer()->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;
+ m_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_BaseTFPlayer *pPlayer = static_cast<C_BaseTFPlayer*>(cl_entitylist->GetEnt( iEntIndex ));
+ C_BaseTFPlayer *pLocalPlayer = C_BaseTFPlayer::GetLocalPlayer();
+
+ // Some entities we always want to check, cause the text may change
+ // even while we're looking at it
+ // Is it a player?
+ if ( IsPlayerIndex( iEntIndex ) )
+ {
+ if ( pPlayer->InSameTeam(pLocalPlayer) )
+ {
+ // Check distance to other player, and if the player is on the same team
+ float flDistSq = pPlayer->GetRenderOrigin().DistToSqr( pLocalPlayer->GetRenderOrigin() );
+ if ( flDistSq < PLAYER_HINT_DISTANCE_SQ )
+ {
+ Q_snprintf( m_sIDString, sizeof(m_sIDString), "%s\nHealth: %.0f percent\nUse to donate resources",
+ pPlayer->GetPlayerName(), ((float)pPlayer->GetHealth() / (float)pPlayer->GetMaxHealth() ) * 100 );
+ }
+ else
+ {
+ Q_snprintf( m_sIDString, sizeof(m_sIDString), "%s\nHealth: %.0f percent",
+ pPlayer->GetPlayerName(), ((float)pPlayer->GetHealth() / (float)pPlayer->GetMaxHealth() ) * 100 );
+ }
+ }
+ else if (( pPlayer->GetHealth() == 0) && (pLocalPlayer->GetClass() == TFCLASS_INFILTRATOR) )
+ {
+ Q_snprintf( m_sIDString, sizeof(m_sIDString), "%s\nUse to disguise as this player", pPlayer->GetPlayerName() );
+ }
+ else
+ {
+ m_sIDString[0] = 0;
+ m_iLastEntIndex = 0;
+ }
+ }
+ else
+ {
+ // Objects
+ C_BaseEntity *pEnt = cl_entitylist->GetEnt( iEntIndex );
+ if ( !pEnt || !pEnt->InSameTeam(pLocalPlayer) )
+ {
+ // This can happen because the object was destroyed
+ m_sIDString[0] = 0;
+ m_iLastEntIndex = 0;
+ }
+ else
+ {
+ // Don't check validity if it's sent by the server
+ Q_strncpy( m_sIDString, pEnt->GetIDString(), sizeof(m_sIDString) );
+ m_iLastEntIndex = iEntIndex;
+ }
+ }
+ }
+
+ // Draw our ID string
+ if ( m_sIDString[0] )
+ {
+ int width, height;
+ int ypos = YRES(300);
+
+ // Messagechars can't handle multiple line strings, so parse out the \n's and give it one line at a time
+ char *ch = m_sIDString;
+ while ( *ch )
+ {
+ // Find the next newline
+ char *next_line;
+ for ( next_line = ch; *next_line != '\n' && *next_line != 0; next_line++ )
+ {
+ }
+
+ // Stomp the newline
+ char *top = next_line;
+ if ( *top == '\n' )
+ {
+ *top = 0;
+ }
+ else
+ {
+ top = NULL;
+ }
+
+ // Draw the line
+ messagechars->GetStringLength( m_hFont, &width, &height, ch );
+ messagechars->DrawString( m_hFont, (ScreenWidth() - width) / 2, ypos, 255, 255, 245, 255, ch, IMessageChars::MESSAGESTRINGID_NONE );
+
+ ypos += height;
+
+ // Restore the newline
+ if ( top )
+ {
+ *top = '\n';
+ }
+
+ // Move to the next line
+ ch = next_line;
+ if ( *ch == '\n' )
+ {
+ ch++;
+ }
+ }
+ }
+}
diff --git a/game/client/tf2/hud_targetreticle.cpp b/game/client/tf2/hud_targetreticle.cpp
new file mode 100644
index 0000000..5f4349c
--- /dev/null
+++ b/game/client/tf2/hud_targetreticle.cpp
@@ -0,0 +1,183 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Target reticle hud element
+//
+// $NoKeywords: $
+//=============================================================================//
+#include "cbase.h"
+#include "hud.h"
+#include "c_basetfplayer.h"
+#include "tf_shareddefs.h"
+#include "iclientmode.h"
+#include "clientmode_tfnormal.h"
+#include "materialsystem/imaterial.h"
+#include "materialsystem/imesh.h"
+#include "hud_targetreticle.h"
+#include "model_types.h"
+#include "view_scene.h"
+#include "view.h"
+#include <vgui/Cursor.h>
+#include <vgui_controls/Controls.h>
+#include <vgui/ISurface.h>
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+CTargetReticle::CTargetReticle( void )
+: BaseClass( NULL, "CTargetReticle" ),
+ m_CursorNone(vgui::dc_none)
+{
+ SetCursor( m_CursorNone );
+
+ SetPaintBackgroundEnabled( false );
+ SetAutoDelete( false );
+ m_hTargetEntity = NULL;
+ m_pTargetLabel = NULL;
+ m_iReticleId = 0;
+ m_iReticleLeftId = 0;
+ m_iReticleRightId = 0;
+ m_iRenderTextureId = 0;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+CTargetReticle::~CTargetReticle()
+{
+ if ( m_pTargetLabel != NULL )
+ {
+ delete m_pTargetLabel;
+ m_pTargetLabel = NULL;
+ }
+
+ SetParent( (vgui::Panel *)NULL );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTargetReticle::Init( C_BaseEntity *pEntity, const char *sName )
+{
+ vgui::Panel *pParent = GetClientModeNormal()->GetViewport();
+ SetParent( pParent );
+ SetCursor( pParent->GetCursor() );
+
+ if ( !m_pTargetLabel )
+ {
+ m_pTargetLabel = new vgui::Label( pParent, "TargetLabel", "Unnamed" );
+ m_pTargetLabel->SetPos( 0, 0 );
+ m_pTargetLabel->SetFgColor( Color( 255, 170, 0, 255 ) );
+ m_pTargetLabel->SetPaintBackgroundEnabled( false );
+ m_pTargetLabel->SetAutoDelete( false );
+ m_pTargetLabel->SetCursor( m_CursorNone );
+ }
+
+ SetSize( XRES(32),YRES(32) );
+ m_hTargetEntity = pEntity;
+ m_pTargetLabel->SetText( sName );
+
+ int contentW, contentH;
+ m_pTargetLabel->GetContentSize( contentW, contentH );
+ m_pTargetLabel->SetWide( contentW );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+C_BaseEntity *CTargetReticle::GetTarget( void )
+{
+ return m_hTargetEntity;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTargetReticle::Update( void )
+{
+ if ( !m_hTargetEntity )
+ {
+ C_BaseTFPlayer *pPlayer = C_BaseTFPlayer::GetLocalPlayer();
+ pPlayer->Remove_Target( this );
+ return;
+ }
+
+ // Load our textures..
+ if ( !m_iReticleId )
+ {
+ m_iReticleId = vgui::surface()->CreateNewTextureID();
+ vgui::surface()->DrawSetTextureFile( m_iReticleId, "Hud/target_reticle" , true, false);
+ }
+
+ if ( !m_iReticleLeftId )
+ {
+ m_iReticleLeftId = vgui::surface()->CreateNewTextureID();
+ vgui::surface()->DrawSetTextureFile( m_iReticleLeftId, "Hud/target_reticle_left", true, false );
+ }
+
+ if ( !m_iReticleRightId )
+ {
+ m_iReticleRightId = vgui::surface()->CreateNewTextureID();
+ vgui::surface()->DrawSetTextureFile( m_iReticleRightId, "Hud/target_reticle_right" , true, false);
+ }
+
+ int iX, iY;
+ GetTargetInScreenSpace( m_hTargetEntity, iX, iY );
+
+ int halfWidth = GetWide() / 2;
+ halfWidth = MAX( halfWidth, m_pTargetLabel->GetWide() / 2 );
+
+ m_iRenderTextureId = m_iReticleId;
+ if( iX < halfWidth || iX > ScreenWidth()-halfWidth )
+ {
+ // It's off the screen. See what side it's on.
+ Vector vCenter = m_hTargetEntity->WorldSpaceCenter( );
+
+ if( CurrentViewRight().Dot( vCenter - CurrentViewOrigin() ) > 0 )
+ {
+ m_iRenderTextureId = m_iReticleRightId;
+ iX = ScreenWidth() - halfWidth;
+ }
+ else
+ {
+ m_iRenderTextureId = m_iReticleLeftId;
+ iX = halfWidth;
+ }
+
+ // Put Y in the center of the screen.
+ iY = ScreenHeight() / 2;
+ }
+
+ // Move the icon there
+ SetPos( iX - (GetWide() / 2), iY - (GetTall() / 2) );
+
+ // Center the text under it
+ m_pTargetLabel->SetPos( iX - (m_pTargetLabel->GetWide() / 2), iY + (GetTall() / 2) );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTargetReticle::Paint()
+{
+ if ( !m_hTargetEntity || !m_iRenderTextureId )
+ return;
+
+ C_BaseTFPlayer *pPlayer = C_BaseTFPlayer::GetLocalPlayer();
+ if ( pPlayer == NULL || pPlayer->GetHealth() < 1 )
+ return;
+
+ // Show hide label based on EMP state
+ bool suppress_reticle = pPlayer->HasPowerup(POWERUP_EMP);
+
+ m_pTargetLabel->SetVisible( suppress_reticle ? false : true );
+
+ // Don't draw the reticle either
+ if ( suppress_reticle )
+ return;
+
+ vgui::surface()->DrawSetTexture( m_iRenderTextureId );
+ vgui::surface()->DrawSetColor( 255, 255, 255, 255 );
+ vgui::surface()->DrawTexturedRect( 0, 0, GetWide(), GetTall() );
+}
+
diff --git a/game/client/tf2/hud_targetreticle.h b/game/client/tf2/hud_targetreticle.h
new file mode 100644
index 0000000..dfee449
--- /dev/null
+++ b/game/client/tf2/hud_targetreticle.h
@@ -0,0 +1,53 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Targeting reticle
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef TARGETRETICLE_H
+#define TARGETRETICLE_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include <vgui_controls/Panel.h>
+#include <vgui_controls/Label.h>
+#include <vgui/Cursor.h>
+
+class IMaterial;
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+class CTargetReticle : public vgui::Panel
+{
+ typedef vgui::Panel BaseClass;
+public:
+ CTargetReticle( void );
+ ~CTargetReticle();
+
+ void Update();
+
+ // vgui::Panel overrides.
+ virtual void Paint( void );
+
+ void Init( C_BaseEntity *pEntity, const char *sName );
+ C_BaseEntity* GetTarget( void );
+
+
+protected:
+
+ EHANDLE m_hTargetEntity;
+ vgui::Label *m_pTargetLabel;
+
+ int m_iReticleId;
+ int m_iReticleLeftId; // When it's hanging off the edge of the screen.
+ int m_iReticleRightId;
+
+ int m_iRenderTextureId;
+
+ vgui::HCursor m_CursorNone;
+};
+
+#endif // TARGETRETICLE_H
diff --git a/game/client/tf2/hud_technologytreedoc.cpp b/game/client/tf2/hud_technologytreedoc.cpp
new file mode 100644
index 0000000..5ec1859
--- /dev/null
+++ b/game/client/tf2/hud_technologytreedoc.cpp
@@ -0,0 +1,175 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+#include "cbase.h"
+#include "hud_technologytreedoc.h"
+#include "hud.h"
+#include "hud_macros.h"
+#include "techtree.h"
+#include "iclientmode.h"
+#include "hud_commander_statuspanel.h"
+#include "clientmode_commander.h"
+#include "commanderoverlaypanel.h"
+#include "tf_hints.h"
+#include "c_tf_hintmanager.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+static CTechnologyTreeDoc s_TechnologyTreeDoc;
+
+// Hook network messages
+DECLARE_MESSAGE( s_TechnologyTreeDoc, Technology )
+
+// Create object singleton on stack
+CTechnologyTreeDoc& GetTechnologyTreeDoc()
+{
+ return s_TechnologyTreeDoc;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Construction
+//-----------------------------------------------------------------------------
+CTechnologyTreeDoc::CTechnologyTreeDoc( void )
+{
+ m_pTree = NULL;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Destruction
+//-----------------------------------------------------------------------------
+CTechnologyTreeDoc::~CTechnologyTreeDoc( void )
+{
+ delete m_pTree;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Initialize the panel
+//-----------------------------------------------------------------------------
+void CTechnologyTreeDoc::Init( void )
+{
+ ReloadTechTree();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTechnologyTreeDoc::LevelInit( void )
+{
+ if ( m_pTree )
+ {
+ m_pTree->SetPreferredTechnology( NULL );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTechnologyTreeDoc::LevelShutdown( void )
+{
+ if ( m_pTree )
+ {
+ m_pTree->SetPreferredTechnology( NULL );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTechnologyTreeDoc::ReloadTechTree( void )
+{
+ // FIXME, CTechnologyTreeDoc should be an entity /MO
+ HOOK_HUD_MESSAGE( s_TechnologyTreeDoc, Technology );
+
+ // Reconstruct the tech tree
+ delete m_pTree;
+
+ // FIXME: If we reactivate this, we'll need to revisit team number here...
+ m_pTree = new CTechnologyTree( ::filesystem, 0);
+ Assert( m_pTree );
+
+ m_pTree->SetPreferredTechnology( NULL );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Receive hud update message from server
+// Input : *pszName -
+// iSize -
+// *pbuf -
+// Output : int
+//-----------------------------------------------------------------------------
+int CTechnologyTreeDoc::MsgFunc_Technology(bf_read &msg)
+{
+ int index;
+ int available;
+ int voters;
+ float resourcelevel;
+ bool preferred;
+
+ // Which tech
+ index = msg.ReadByte();
+ // Available to this team?
+ available = msg.ReadByte();
+ // # of players indicating this as their preferred tech for new spending
+ voters = msg.ReadByte();
+
+ preferred = ( voters & 0x80 ) ? true : false;
+ voters &= 0x7f;
+
+ resourcelevel = (float)msg.ReadShort();
+
+ // Look it up by index
+ CBaseTechnology *item = m_pTree->GetTechnology( index );
+ if ( item )
+ {
+ bool wasactive = item->GetActive();
+
+ bool justactivated = !wasactive && available;
+
+ // Set data elements
+ item->SetActive( available ? true : false );
+ item->SetVoters( voters );
+ item->SetResourceLevel( resourcelevel );
+
+ // If this is the tech I am voting for, clear my vote
+ if ( preferred )
+ {
+ // Sets the flag on the item, too
+ m_pTree->SetPreferredTechnology( item );
+ }
+ else
+ {
+ // Force deselection in case there is no active preference on the server any more
+ item->SetPreferred( false );
+ }
+
+ if ( justactivated && item->GetLevel() > 0 && !item->GetHintsGiven( TF_HINT_NEWTECHNOLOGY ) )
+ {
+ // So we only give this hint once this game, even if we respawn, etc.
+ item->SetHintsGiven( TF_HINT_NEWTECHNOLOGY, true );
+ // Note, only show a max of three or 4 newtechnology hints at a time
+ CreateGlobalHint( TF_HINT_NEWTECHNOLOGY, item->GetPrintName(), index, 3 );
+ }
+ }
+
+ return 1;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Add a file of technologies to the technology tree
+//-----------------------------------------------------------------------------
+void CTechnologyTreeDoc::AddTechnologyFile( char *sFilename )
+{
+ // Add the technologies to the tech list
+ if ( m_pTree )
+ {
+ // FIXME: If we reactivate this, we'll need to revisit team number here...
+ m_pTree->AddTechnologyFile( ::filesystem, 0, sFilename );
+ }
+}
diff --git a/game/client/tf2/hud_technologytreedoc.h b/game/client/tf2/hud_technologytreedoc.h
new file mode 100644
index 0000000..c9d74a4
--- /dev/null
+++ b/game/client/tf2/hud_technologytreedoc.h
@@ -0,0 +1,49 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+#if !defined( TF_TECHNOLOGYTREEDOC_H )
+#define TF_TECHNOLOGYTREEDOC_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+// Forward declarations
+class CTechnologyTree;
+
+//-----------------------------------------------------------------------------
+// Purpose: Container for views into technology tree
+//-----------------------------------------------------------------------------
+class CTechnologyTreeDoc
+{
+public:
+ // Construction
+ CTechnologyTreeDoc( void );
+ virtual ~CTechnologyTreeDoc( void );
+
+ virtual void Init( void );
+ virtual void ReloadTechTree( void );
+
+ virtual void LevelInit( void );
+ virtual void LevelShutdown( void );
+
+ inline CTechnologyTree *GetTechnologyTree() {return m_pTree;}
+
+ void AddTechnologyFile( char *sFilename );
+
+ // Network input
+ int MsgFunc_Technology( bf_read &msg );
+ int MsgFunc_Resource( bf_read &msg );
+
+private:
+ // The underlying technology data tree
+ CTechnologyTree *m_pTree;
+};
+
+// Expose Document to rest of dll
+extern CTechnologyTreeDoc& GetTechnologyTreeDoc();
+
+
+#endif // TF_TECHNOLOGYTREEDOC_H \ No newline at end of file
diff --git a/game/client/tf2/hud_timer.cpp b/game/client/tf2/hud_timer.cpp
new file mode 100644
index 0000000..a5b6b6a
--- /dev/null
+++ b/game/client/tf2/hud_timer.cpp
@@ -0,0 +1,298 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: HUD Timer
+//
+// $Workfile: $
+// $Date: $
+// $NoKeywords: $
+//=============================================================================//
+#include "cbase.h"
+#include "hud.h"
+#include "hud_macros.h"
+#include "hud_numeric.h"
+#include "c_basetfplayer.h"
+#include "hud_timer.h"
+#include "iclientmode.h"
+#include <vgui_controls/AnimationController.h>
+
+#define MIN_TIMER_ALPHA 192
+
+using namespace vgui;
+
+DECLARE_HUDELEMENT( CHudTimer );
+DECLARE_HUD_MESSAGE( CHudTimer, StartTimer );
+DECLARE_HUD_MESSAGE( CHudTimer, SetTimer );
+DECLARE_HUD_MESSAGE( CHudTimer, UpdateTimer );
+
+//-----------------------------------------------------------------------------
+// Purpose: Create the Timer
+//-----------------------------------------------------------------------------
+CHudTimer::CHudTimer( const char *pElementName ) : CHudNumeric( pElementName, "HudTimer" )
+{
+ SetDrawLabel( false );
+ SetDoPulses( false );
+
+ SetHiddenBits( HIDEHUD_MISCSTATUS );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Reset Timer values
+//-----------------------------------------------------------------------------
+void CHudTimer::Init( void )
+{
+ m_iAlpha = MIN_TIMER_ALPHA;
+ m_flCurrentTime = 0.0;
+ m_flStartTime = 0.0;
+ m_flPrevTimeSlice = 0.0;
+ m_iPaused = false;
+ m_bFixedTime = true;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Set the Timer's start time, and tells the timer to go into fixed time mode.
+//-----------------------------------------------------------------------------
+void CHudTimer::SetFixedTimer( float flStartTime, float flTimeLimit )
+{
+ Init();
+
+ // Setup the Timer values
+ m_flStartTime = flStartTime;
+ m_flTimeLimit = flTimeLimit;
+ m_bFixedTime = true;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Set the Timer to a Time, and tells the timer to go into no fixed time mode.
+//-----------------------------------------------------------------------------
+void CHudTimer::SetNoFixedTimer( float flTime )
+{
+ Init();
+
+ // Setup the Timer values
+ m_flStartTime = m_flCurrentTime = flTime;
+ m_bFixedTime = false;
+
+ // Timer starts paused
+ StopTimer();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Updates the Timer to a specific timer without doing anything else
+//-----------------------------------------------------------------------------
+void CHudTimer::UpdateTimer( float flTime )
+{
+ m_flCurrentTime = flTime;
+ m_flPrevTimeSlice = gpGlobals->curtime;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Start the Timer
+//-----------------------------------------------------------------------------
+void CHudTimer::StartTimer( void )
+{
+ // Ignore start / stop if I'm in fixed time mode
+ if ( m_bFixedTime )
+ return;
+ if ( !m_iPaused )
+ return;
+
+ // Start timer
+ m_flPrevTimeSlice = gpGlobals->curtime;
+ m_iPaused = false;
+
+ // Start with a short pulse
+ g_pClientMode->GetViewportAnimationController()->StartAnimationSequence("TimerPulse");
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Stop the Timer, without resetting it
+//-----------------------------------------------------------------------------
+void CHudTimer::StopTimer( void )
+{
+ // Ignore start / stop if I'm in fixed time mode
+ if ( m_bFixedTime )
+ return;
+ if ( m_iPaused )
+ return;
+
+ // Pause timer values
+ m_iPaused = true;
+
+ // Stop with a short pulse
+ g_pClientMode->GetViewportAnimationController()->StartAnimationSequence("TimerPulse");
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Get back a color for the timer from a Green <-> Yellow <-> Red ramp
+//-----------------------------------------------------------------------------
+Color CHudTimer::GetColor( void )
+{
+ Color clr = Color( 0, 0, 0, 0 );
+
+ float flPercentagePassed = 1 - (m_flCurrentTime / m_flTimeLimit);
+
+ if ( flPercentagePassed < 0.75 )
+ {
+ clr = m_TextColor;
+ }
+ else if ( flPercentagePassed < 0.9 )
+ {
+ clr = m_TextColorWarning;
+ }
+ else
+ {
+ clr = m_TextColorCritical;
+ }
+
+ // Handle pulses ( which brighten the timer & change the font )
+ clr[3] = clamp( MIN_TIMER_ALPHA + ( m_flBlur ) * 128, 0, 255 );
+
+ // Low timer always overrides to make it bright
+ if ( flPercentagePassed > 0.99 )
+ {
+ clr[3] = 255;
+ }
+
+ return clr;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Get back a color for the timer from a Green <-> Yellow <-> Red ramp
+//-----------------------------------------------------------------------------
+Color CHudTimer::GetBoxColor()
+{
+ Color boxColor = Color( 0, 0, 0, 0 );
+
+ float flPercentagePassed = 1 - (m_flCurrentTime / m_flTimeLimit);
+ if ( flPercentagePassed < 0.75 )
+ {
+ boxColor = m_BoxColor;
+ }
+ else if ( flPercentagePassed < 0.9 )
+ {
+ boxColor = m_BoxColorWarning;
+ }
+ else
+ {
+ boxColor = m_BoxColorCritical;
+ }
+
+ return boxColor;
+}
+
+bool CHudTimer::GetValue( char *value, int maxlen )
+{
+ if ( m_flStartTime == 0.0 )
+ return false;
+
+ // Convert time to Minutes and Seconds (prevent negative times)
+ int iTimerMinutes = MAX( 0, ((int)m_flCurrentTime) / 60 );
+ int iTimerSeconds = MAX( 0, ((int)m_flCurrentTime) % 60 );
+
+ Q_snprintf( value, maxlen, "%02d:%.2d", iTimerMinutes, iTimerSeconds );
+ return true;
+}
+
+void CHudTimer::OnThink( void )
+{
+ if ( m_flStartTime == 0.0 )
+ return;
+
+ // If we're in fixed time mode, calculate the current time
+ if ( m_bFixedTime )
+ {
+ // Don't paint at all if we have no timelimit
+ if ( !m_flTimeLimit )
+ return;
+
+ m_flCurrentTime = gpGlobals->curtime - m_flStartTime;
+
+ // If we have a timelimit, count down
+ if ( m_flTimeLimit )
+ {
+ m_flCurrentTime = m_flTimeLimit - m_flCurrentTime;
+ }
+
+ CheckForPulse();
+ }
+
+ // Increment the time if the Timer's going, and we're not in fixed time mode.
+ if ( !m_iPaused && !m_bFixedTime )
+ {
+ m_flCurrentTime -= gpGlobals->curtime - m_flPrevTimeSlice;
+ m_flPrevTimeSlice = gpGlobals->curtime;
+
+ // Hit the end?
+ if ( m_flCurrentTime <= 0.0 )
+ {
+ StopTimer();
+ m_flCurrentTime = 0.0;
+ }
+ }
+
+ m_flLastTime = m_flCurrentTime;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Check to see if the Timer should pulse
+//-----------------------------------------------------------------------------
+void CHudTimer::CheckForPulse( void )
+{
+ int pulseInterval = 60;
+ if ( m_flCurrentTime <= 60 )
+ {
+ pulseInterval = 10;
+ }
+
+ // See if we've crossed a minute boundary
+ int iLastTimerMinutes = ((int)m_flLastTime) / pulseInterval;
+ // will we get there in next half second
+ int iTimerMinutes = ((int)m_flCurrentTime - 0.5f ) / pulseInterval;
+ if ( iLastTimerMinutes != iTimerMinutes )
+ {
+ g_pClientMode->GetViewportAnimationController()->StartAnimationSequence("TimerPulse");
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Message Handler for the Timer Set
+//-----------------------------------------------------------------------------
+int CHudTimer::MsgFunc_SetTimer(bf_read &msg)
+{
+ float flTimeToSetTo = msg.ReadBitCoord();
+ SetNoFixedTimer( flTimeToSetTo );
+
+ return 1;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Message Handler for the Timer Update
+// Updates are like sets, but they don't re-evaluate the start time
+// They're used to just ensure the Client Timers don't get too far out of synch with the server's timer
+//-----------------------------------------------------------------------------
+int CHudTimer::MsgFunc_UpdateTimer(bf_read &msg)
+{
+ float flTimeToSetTo = msg.ReadBitCoord();
+ UpdateTimer( flTimeToSetTo );
+
+ return 1;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Message Handler for the Timer Start/Stop
+//-----------------------------------------------------------------------------
+int CHudTimer::MsgFunc_StartTimer( bf_read &msg )
+{
+ if ( msg.ReadByte() )
+ {
+ // Start the Timer
+ StartTimer();
+ }
+ else
+ {
+ // Pause the Timer
+ StopTimer();
+ }
+
+ return 1;
+} \ No newline at end of file
diff --git a/game/client/tf2/hud_timer.h b/game/client/tf2/hud_timer.h
new file mode 100644
index 0000000..b7645ad
--- /dev/null
+++ b/game/client/tf2/hud_timer.h
@@ -0,0 +1,70 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef HUD_TIMER_H
+#define HUD_TIMER_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "hud_numeric.h"
+#include <vgui_controls/Panel.h>
+
+
+//-----------------------------------------------------------------------------
+// Purpose: TF2 Countdown Timer
+//-----------------------------------------------------------------------------
+class CHudTimer : public CHudNumeric
+{
+ DECLARE_CLASS_SIMPLE( CHudTimer, CHudNumeric )
+public:
+ CHudTimer( const char *pElementName );
+
+ virtual void Init( void );
+ virtual void OnThink( void );
+
+ virtual const char *GetLabelText() { return m_szTimerLabel; }
+ virtual const char *GetPulseEvent( bool increment ) { return ""; }
+ virtual bool GetValue( char *val, int maxlen );
+
+ virtual Color GetColor();
+ virtual Color GetBoxColor();
+
+ // Handling
+ void SetNoFixedTimer( float flTime );
+ void SetFixedTimer( float flStartTime, float flTimeLimit );
+ void UpdateTimer( float flTime );
+ void StartTimer( void );
+ void StopTimer( void );
+ void CheckForPulse( void );
+ int MsgFunc_SetTimer( bf_read &msg );
+ int MsgFunc_StartTimer( bf_read &msg );
+ int MsgFunc_UpdateTimer( bf_read &msg );
+
+public:
+ int m_iAlpha;
+ int m_iPaused;
+ float m_flCurrentTime;
+ float m_flStartTime;
+ float m_flPrevTimeSlice;
+ float m_flPulseTime;
+ float m_flTimeLimit;
+ float m_flLastTime;
+
+ // The Timer has two modes of operation:
+ // m_bFixedTime == true: Timer can't be paused. Time displayed is an offset from the originally specified start time.
+ // m_bFixedTime == false: Timer can be stopped & started. Time displayed is calculated on the client, and regularly updated by the server
+ // to ensure it doesn't get too far off the server's time.
+ bool m_bFixedTime;
+
+private:
+ float m_flOpenCloseTime;
+
+ CPanelAnimationStringVar( 128, m_szTimerLabel, "TimerLabel", "" );
+};
+
+#endif // HUD_TIMER_H
diff --git a/game/client/tf2/hud_vehicle_role.cpp b/game/client/tf2/hud_vehicle_role.cpp
new file mode 100644
index 0000000..2ba956d
--- /dev/null
+++ b/game/client/tf2/hud_vehicle_role.cpp
@@ -0,0 +1,80 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#include "cbase.h"
+#include "hud_vehicle_role.h"
+#include "iclientmode.h"
+#include <vgui_controls/Controls.h>
+#include <vgui/ISurface.h>
+#include <KeyValues.h>
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+
+DECLARE_HUDELEMENT( CVehicleRoleHudElement );
+
+using namespace vgui;
+
+CVehicleRoleHudElement::CVehicleRoleHudElement( const char *pElementName ) :
+ CHudElement( pElementName ), BaseClass( NULL, "VehicleRoleHudElement" )
+{
+ vgui::Panel *pParent = g_pClientMode->GetViewport();
+ SetParent( pParent );
+
+ m_iRole = -1;
+
+ SetHiddenBits( HIDEHUD_HEALTH | HIDEHUD_PLAYERDEAD );
+}
+
+void CVehicleRoleHudElement::ApplySchemeSettings( IScheme *scheme )
+{
+ BaseClass::ApplySchemeSettings( scheme );
+
+ m_hTextFont = scheme->GetFont( "Trebuchet24" );
+
+ SetPaintBackgroundEnabled( false );
+}
+
+
+void CVehicleRoleHudElement::ShowVehicleRole( int iRole )
+{
+ m_iRole = iRole;
+}
+
+
+void CVehicleRoleHudElement::Paint()
+{
+ if ( m_iRole == -1 )
+ return;
+
+ surface()->DrawSetTextFont( m_hTextFont );
+ surface()->DrawSetTextColor( GetFgColor() );
+
+ char str[512];
+ if ( m_iRole == VEHICLE_ROLE_DRIVER )
+ {
+ Q_strncpy( str, "Driver", sizeof( str ) );
+ }
+ else
+ {
+ Q_snprintf( str, sizeof( str ), "Passenger %d", m_iRole );
+ }
+
+ int pixels = UTIL_ComputeStringWidth( m_hTextFont, str );
+ int x = ( GetWide() - pixels ) / 2;
+
+ surface()->DrawSetTextPos( x, 0 );
+
+ char *p = str;
+ while ( *p )
+ {
+ surface()->DrawUnicodeChar( *p );
+ p++;
+ }
+}
+
+
diff --git a/game/client/tf2/hud_vehicle_role.h b/game/client/tf2/hud_vehicle_role.h
new file mode 100644
index 0000000..ddee87f
--- /dev/null
+++ b/game/client/tf2/hud_vehicle_role.h
@@ -0,0 +1,34 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#ifndef HUD_VEHICLE_ROLE_H
+#define HUD_VEHICLE_ROLE_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+
+#include "hudelement.h"
+#include <vgui_controls/Controls.h>
+#include <vgui_controls/Panel.h>
+
+class CVehicleRoleHudElement : public CHudElement, public vgui::Panel
+{
+ DECLARE_CLASS_SIMPLE( CVehicleRoleHudElement, vgui::Panel );
+public:
+ CVehicleRoleHudElement( const char *pElementName );
+ virtual void ApplySchemeSettings( vgui::IScheme *scheme );
+ virtual void Paint( void );
+
+ // Set which role to display on the hud.
+ void ShowVehicleRole( int iRole );
+private:
+ int m_iRole;
+ vgui::HFont m_hTextFont;
+};
+
+
+#endif // HUD_VEHICLE_ROLE_H
diff --git a/game/client/tf2/hud_weaponselection.cpp b/game/client/tf2/hud_weaponselection.cpp
new file mode 100644
index 0000000..4b21750
--- /dev/null
+++ b/game/client/tf2/hud_weaponselection.cpp
@@ -0,0 +1,1671 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//===========================================================================//
+
+#include "cbase.h"
+#include "weapon_selection.h"
+#include "iclientmode.h"
+#include "basetfcombatweapon_shared.h"
+#include "weapon_objectselection.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 "keydefs.h"
+
+#include <vgui/IVGui.h>
+
+#include "weapon_twohandedcontainer.h"
+#ifdef CLIENT_DLL
+#include "c_weapon_builder.h"
+#include "iinput.h"
+#else
+#include "weapon_builder.h"
+#endif
+
+using namespace vgui;
+
+class CHudWeaponSelection;
+
+typedef enum
+{
+ IMAGE_BACKGROUND = 0,
+ IMAGE_CURRENT,
+ IMAGE_INVALID
+} WeaponBoxType_t;
+
+enum
+{
+ HUMAN_WEAPON_SELECTION = 0,
+ ALIEN_WEAPON_SELECTION,
+};
+
+struct CSlotInfo
+{
+ bool active;
+ bool valid;
+ CHudTexture const *icon;
+ bool drawAmmo;
+ float ammoPerc;
+ bool ammoCaution;
+ char printname[ 128 ];
+ CHandle< C_BaseCombatWeapon > weapon;
+};
+
+struct CWeaponMenuItem
+{
+ // If true, it's a dummy item
+ bool buildslot;
+ int priority;
+ int hotkey;
+ int openbuildmenu;
+ bool isvalidmenuitem;
+ CHandle< C_BaseCombatWeapon > weapon;
+};
+
+class WeaponMenu
+{
+public:
+ WeaponMenu() : items( 0, 0, WeaponLessFunc )
+ {
+ m_bIsBuildMenu = false;
+ m_nActiveItem = 0;
+ }
+
+ void SetActiveItem( int item )
+ {
+ bool changed = ( m_nActiveItem != item );
+
+ m_nActiveItem = item;
+
+ if ( !changed )
+ return;
+
+ const char *prefix = m_bIsBuildMenu ? "WeaponHiliteBuildMenu" : "WeaponHiliteWeaponMenu";
+
+ if ( m_nActiveItem >= 1 )
+ {
+ char slotSequence[ 128 ];
+ Q_snprintf( slotSequence, sizeof( slotSequence ), "%s%i", prefix, m_nActiveItem );
+
+ g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( slotSequence );
+ }
+ }
+
+ int GetActiveItem()
+ {
+ return m_nActiveItem;
+ }
+
+ static bool WeaponLessFunc( const CWeaponMenuItem& w1, const CWeaponMenuItem& w2 )
+ {
+ return w1.priority < w2.priority;
+ }
+
+ CUtlRBTree< CWeaponMenuItem, int > items;
+ int m_nActiveItem;
+ bool m_bIsBuildMenu;
+};
+
+class CHudWeaponItemPanel : public vgui::Panel
+{
+ DECLARE_CLASS_SIMPLE( CHudWeaponItemPanel, vgui::Panel );
+
+public:
+ CHudWeaponItemPanel( vgui::Panel *parent, const char *panelName );
+
+ CPanelAnimationVarAliasType( float, m_flIconWidth, "IconWidth", "60", "proportional_float" );
+ CPanelAnimationVarAliasType( float, m_flIconHeight, "IconHeight", "30", "proportional_float" );
+ CPanelAnimationVarAliasType( float, m_flIconXPos, "IconXPos", "10", "proportional_float" );
+ CPanelAnimationVarAliasType( float, m_flIconYPos, "IconYPos", "4", "proportional_float" );
+ CPanelAnimationVarAliasType( float, m_flTextXPos, "TextXPos", "10", "proportional_float" );
+ CPanelAnimationVarAliasType( float, m_flTextYPos, "TextYPos", "35", "proportional_float" );
+ CPanelAnimationVarAliasType( float, m_flAmmoBarX, "AmmoBarX", "75", "proportional_float" );
+ CPanelAnimationVarAliasType( float, m_flAmmoBarWide, "AmmoBarWide", "4", "proportional_float" );
+ CPanelAnimationVarAliasType( float, m_flSelectionNumberXPos, "SelectionNumberXPos", "4", "proportional_float" );
+ CPanelAnimationVarAliasType( float, m_flSelectionNumberYPos, "SelectionNumberYPos", "4", "proportional_float" );
+
+ CPanelAnimationVarAliasType( float, m_flPriceXEndPos, "PriceXEndPos", "4", "proportional_float" );
+ CPanelAnimationVarAliasType( float, m_flPriceYEndPos, "PriceYEndPos", "4", "proportional_float" );
+
+ CPanelAnimationVar( float, m_flGrowFraction, "GrowFraction", "1.0" );
+
+ bool m_bInUse;
+
+ bool m_bDrawNumbers;
+ int m_nSlotNumber;
+ bool m_bBuildMenu;
+
+ // Copies of data
+ CSlotInfo info;
+ CWeaponMenuItem menuItem;
+
+ virtual void Paint();
+
+ virtual void ApplySchemeSettings( vgui::IScheme *scheme );
+
+ void SetupIcons();
+
+ enum
+ {
+ NUM_SLOT_TEAMS = 2,
+ NUM_MENU_TYPES = 3,
+ };
+
+ CHudTexture *m_BackgroundIcons[ NUM_SLOT_TEAMS ][ NUM_MENU_TYPES ];
+
+private:
+ void TranslateColor( float percent, Color& clr );
+ void DrawBox( bool isbuildmenu, int x, int y, int wide, int tall, bool isactive, bool isvalid, float normalizedAlpha, int number );
+ int GetTeamIndex();
+ void OnWeaponSelectionDrawn( CHudWeaponSelection *selection, C_WeaponObjectSelection *weapon, bool bCurrentlySelected,
+ int wide, int tall, Color& clr );
+};
+
+//-----------------------------------------------------------------------------
+// Purpose: tf2 weapon selection hud element
+//-----------------------------------------------------------------------------
+class CHudWeaponSelection : public CBaseHudWeaponSelection, public vgui::Panel
+{
+ DECLARE_CLASS_SIMPLE( CHudWeaponSelection, vgui::Panel );
+
+public:
+
+ CHudWeaponSelection(const char *pElementName );
+
+ virtual bool ShouldDraw( void );
+
+ virtual void VidInit(void);
+
+ virtual void CycleToNextWeapon( void );
+ virtual void CycleToPrevWeapon( void );
+ virtual void SwitchToLastWeapon( void );
+
+ virtual C_BaseCombatWeapon *GetWeaponInSlot( int iSlot, int iSlotPos );
+ virtual void SelectWeaponSlot( int iSlot );
+
+ virtual void OnWeaponPickup( C_BaseCombatWeapon *pWeapon );
+
+ virtual void SelectWeapon( void );
+
+ virtual C_BaseCombatWeapon *GetSelectedWeapon( void );
+
+ virtual void OpenSelection( void );
+
+ virtual int KeyInput( int down, ButtonCode_t keynum, const char *pszCurrentBinding );
+
+ virtual void HideSelection( void );
+
+protected:
+ virtual void OnTick();
+ virtual void ApplySchemeSettings(vgui::IScheme *pScheme);
+ virtual void ApplySettings( KeyValues *resourceData );
+private:
+
+ // Offensive
+ // Defensive
+ // General Purpose
+ enum
+ {
+ BUILD_OFFENSIVE = 0,
+ BUILD_DEFENSIVE,
+ BUILD_GENERAL_PURPOSE,
+
+ NUM_BUILD_MENUS,
+ };
+
+ enum
+ {
+ MAX_WEAPON_MENU_ITEMS = 7,
+ MAX_BUILD_MENU_ITEMS = 6,
+ };
+
+ void SetupWeaponMenu( WeaponMenu& menu, C_BaseCombatWeapon *activeItem, bool drawNumbers );
+ void SetupBuildMenu( WeaponMenu& menu, C_BaseCombatWeapon *activeItem );
+
+ void DrawBox( bool isbuildmenu, int x, int y, int wide, int tall, bool current, bool isvalid, float normalizedAlpha, int number );
+
+ void TranslateColor( float percent, Color& clr );
+
+ void ShowBuildMenu( int buildmenu );
+ void ShowBuildMenu( WeaponMenu& buildMenu );
+ void HideBuildMenu( void );
+ WeaponMenu& GetActiveMenu();
+ int GetLowIndex( WeaponMenu& menu );
+ void WrapIndexToRange( int& index, int low, int high );
+ int FindSlotForHotKey( WeaponMenu& menu, int hotkey );
+ int FindNextSelectableWeaponInMenu( WeaponMenu& menu, int startindex, int direction );
+ int CountSelectableItems( WeaponMenu& menu );
+ CWeaponMenuItem *GetFirstSelectableWeapon( WeaponMenu& menu );
+ const char *GetBuildMenuName( int slot );
+ const char *GetBuildMenuMaterial( int slot );
+
+ void SelectBuildMenuSlot( WeaponMenu& buildMenu );
+
+ void CreateWeaponItemPanels();
+
+ void ClearBuildMenu();
+ void RebuildMenus();
+ void AssignSlots( WeaponMenu& menu, int firstindex );
+ void CollapseSingleItemBuildMenus();
+
+ void GetSlotInfo( const CWeaponMenuItem *w, C_BaseCombatWeapon *active, CSlotInfo& info );
+
+ int GetTeamIndex();
+
+ void SetupIcons();
+
+ CPanelAnimationVar( float, m_flAlphaOverride, "Alpha", "255.0" );
+ CPanelAnimationVar( float, m_flSelectionAlphaOverride, "SelectionAlpha", "255.0" );
+
+ CPanelAnimationVar( Color, m_TextColor, "TextColor", "SelectionTextFg" );
+ CPanelAnimationVar( Color, m_InvalidActiveColor, "InvalidActiveColor", "InvalidActiveSlotFg" );
+ CPanelAnimationVar( Color, m_InvalidActiveTextColor, "InvalidActiveTextColor", "InvalidActiveSlotText" );
+ CPanelAnimationVar( Color, m_InvalidColor, "InvalidColor", "InvalidSlotFg" );
+ CPanelAnimationVar( Color, m_InvalidTextColor, "InvalidTextColor", "InvalidSlotText" );
+ CPanelAnimationVar( Color, m_OtherColor, "OtherColor", "OtherSlotFg" );
+ CPanelAnimationVar( Color, m_OtherTextColor, "OtherTextColor", "OtherSlotText" );
+ CPanelAnimationVar( Color, m_AmmoNormalColor, "AmmoNormalColor", "AmmoNormal" );
+ CPanelAnimationVar( Color, m_AmmoCautionColor, "AmmoCautionColor", "AmmoCaution" );
+
+ CPanelAnimationVar( vgui::HFont, m_hNumberFont, "NumberFont", "HudSelectionNumbers" );
+ CPanelAnimationVar( vgui::HFont, m_hTextFont, "TextFont", "HudSelectionText" );
+ CPanelAnimationVar( vgui::HFont, m_hTextFontSmall, "TextFontSmall", "HudSelectionTextSmall" );
+ CPanelAnimationVar( vgui::HFont, m_hPriceFont, "PriceFont", "HudSelectionTextSmall" );
+
+ CPanelAnimationVar( float, m_flGrowFraction, "GrowFraction", "0.0" );
+
+ CHandle<C_BaseCombatWeapon> m_hLastPickedUpWeapon;
+ bool m_bInSelectionMode;
+ int m_nLastBuildTick;
+ bool m_bInBuildMenu;
+ int m_nActiveBuildMenu;
+
+ WeaponMenu *m_PreviousBuildMenu;
+
+ WeaponMenu m_Weapons;
+ WeaponMenu m_BuildObjects[ NUM_BUILD_MENUS ];
+
+ CHudWeaponItemPanel *m_pWeaponPanels[ MAX_WEAPON_MENU_ITEMS ];
+ CHudWeaponItemPanel *m_pBuildPanels[ MAX_BUILD_MENU_ITEMS ];
+
+ CWeaponMenuItem *FindWeapon( WeaponMenu& menu, int hotkey );
+
+ friend class CHudWeaponItemPanel;
+};
+
+DECLARE_HUDELEMENT( CHudWeaponSelection );
+
+void CHudWeaponSelection::VidInit(void)
+{
+ CBaseHudWeaponSelection::VidInit();
+
+ SetupIcons();
+}
+
+void CHudWeaponSelection::SetupIcons()
+{
+ int i;
+
+ for ( i = 0; i < MAX_WEAPON_MENU_ITEMS; i++ )
+ {
+ m_pWeaponPanels[ i ]->SetupIcons();
+ }
+
+ for ( i = 0; i < MAX_BUILD_MENU_ITEMS; i++ )
+ {
+ m_pBuildPanels[ i ]->SetupIcons();
+ }
+}
+
+
+void CHudWeaponSelection::AssignSlots( WeaponMenu& menu, int firstindex )
+{
+ int slot = firstindex;
+
+ for ( int i = menu.items.FirstInorder(); i != menu.items.InvalidIndex(); i = menu.items.NextInorder( i ) )
+ {
+ CWeaponMenuItem *w = &menu.items[ i ];
+ w->hotkey = slot++;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CHudWeaponSelection::CreateWeaponItemPanels()
+{
+ int i;
+ char sz[ 128 ];
+ for ( i = 0; i < MAX_WEAPON_MENU_ITEMS; i++ )
+ {
+ Q_snprintf( sz, sizeof( sz ), "WeaponMenu%i", i + 1 );
+ m_pWeaponPanels[ i ] = new CHudWeaponItemPanel( this, sz );
+ m_pWeaponPanels[ i ]->m_nSlotNumber = i;
+ m_pWeaponPanels[ i ]->m_bBuildMenu = false;
+ }
+
+ for ( i = 0; i < MAX_BUILD_MENU_ITEMS; i++ )
+ {
+ Q_snprintf( sz, sizeof( sz ), "BuildMenu%i", i + 1 );
+ m_pBuildPanels[ i ] = new CHudWeaponItemPanel( this, sz );
+ m_pBuildPanels[ i ]->m_nSlotNumber = i;
+ m_pBuildPanels[ i ]->m_bBuildMenu = true;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CHudWeaponSelection::RebuildMenus()
+{
+ int i;
+
+ if ( gpGlobals->tickcount == m_nLastBuildTick )
+ return;
+
+ m_nLastBuildTick = gpGlobals->tickcount;
+
+
+ C_BasePlayer *player = C_BasePlayer::GetLocalPlayer();
+ if ( !player )
+ return;
+
+ m_Weapons.items.RemoveAll();
+ for ( i = 0; i < NUM_BUILD_MENUS; i++ )
+ {
+ m_BuildObjects[ i ].items.RemoveAll();
+ }
+
+ CWeaponMenuItem item;
+
+ int c = MAX_WEAPONS;
+ for ( i = 0; i < c; i++ )
+ {
+ C_BaseCombatWeapon *pWeapon = player->GetWeapon( i );
+ if ( !pWeapon )
+ {
+ continue;
+ }
+
+ if ( !pWeapon->VisibleInWeaponSelection() )
+ {
+ continue;
+ }
+
+ item.priority = pWeapon->GetSlot() * 10 + pWeapon->GetPosition();
+ item.buildslot = false;
+ item.openbuildmenu = -1;
+ item.weapon = pWeapon;
+ item.isvalidmenuitem = true;
+
+ if ( dynamic_cast< C_WeaponObjectSelection * >( pWeapon ) )
+ {
+ // HACK
+ int firstbuildslot = 4;
+ int whichBuildMenu = clamp( pWeapon->GetSlot() - firstbuildslot, 0, NUM_BUILD_MENUS - 1 );
+
+ m_BuildObjects[ whichBuildMenu ].items.Insert( item );
+ }
+ else
+ {
+ m_Weapons.items.Insert( item );
+ }
+ }
+
+ while ( m_Weapons.items.Count() < 3 )
+ {
+ // Add build item menus
+ item.priority = 999;
+ item.buildslot = false;
+ item.openbuildmenu = -1;
+ item.weapon = NULL;
+ item.isvalidmenuitem = false;
+ m_Weapons.items.Insert( item );
+
+ m_Weapons.m_bIsBuildMenu = false;
+ }
+
+ for ( i = 0; i < NUM_BUILD_MENUS; i++ )
+ {
+ // Add build item menus
+ item.priority = 999;
+ item.buildslot = true;
+ item.openbuildmenu = i;
+ item.weapon = NULL;
+ item.isvalidmenuitem = CountSelectableItems( m_BuildObjects[ i ] ) > 0 ? true : false;
+ m_Weapons.items.Insert( item );
+
+ // Assign build menu slots
+ AssignSlots( m_BuildObjects[ i ], 0 );
+
+ m_BuildObjects[ i ].m_bIsBuildMenu = true;
+ }
+
+ // Now walk in order and assign hotkeys
+ AssignSlots( m_Weapons, 1 );
+
+ // Merge single item build menus into main menu
+ CollapseSingleItemBuildMenus();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CHudWeaponSelection::CollapseSingleItemBuildMenus()
+{
+ for ( int i = 0; i < NUM_BUILD_MENUS; i++ )
+ {
+ int count = m_BuildObjects[ i ].items.Count();
+
+ // Not an issue
+ if ( count > 1 )
+ continue;
+
+ CWeaponMenuItem *mainItem = FindWeapon( m_Weapons, 4 + i );
+ if ( !mainItem )
+ continue;
+
+ // It's empty, need to make main item a disabled slot
+ if ( count == 0 )
+ {
+ // Add build item menus
+ mainItem->isvalidmenuitem = false;
+ }
+ else
+ {
+ // Only one item in sub menu, copy it over
+ CWeaponMenuItem *buildItem = &m_BuildObjects[ i ].items[ 0 ];
+ mainItem->buildslot = false;
+ mainItem->openbuildmenu = -1;
+ mainItem->isvalidmenuitem = true;
+ mainItem->weapon = buildItem->weapon;
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CHudWeaponSelection::ClearBuildMenu()
+{
+ for ( int i = 0; i < MAX_BUILD_MENU_ITEMS; i++ )
+ {
+ m_pBuildPanels[ i ]->m_bInUse = false;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Constructor
+//-----------------------------------------------------------------------------
+CHudWeaponSelection::CHudWeaponSelection(const char *pElementName ) :
+ CBaseHudWeaponSelection(pElementName), BaseClass(NULL, "HudWeaponSelection")
+{
+ vgui::Panel *pParent = g_pClientMode->GetViewport();
+ SetParent( pParent );
+
+ m_nLastBuildTick = -1;
+
+ m_hNumberFont = NULL;
+ m_bInSelectionMode = false;
+
+ CreateWeaponItemPanels();
+
+ vgui::ivgui()->AddTickSignal( GetVPanel() );
+}
+
+void CHudWeaponSelection::ShowBuildMenu( int buildmenu )
+{
+ bool wasinbuild = m_bInBuildMenu;
+
+ int mainItem = buildmenu + 4;
+ m_Weapons.SetActiveItem( mainItem );
+
+ m_bInBuildMenu = true;
+ m_nActiveBuildMenu = buildmenu;
+ GetActiveMenu().SetActiveItem( GetLowIndex( GetActiveMenu() ) );
+
+ if ( !wasinbuild )
+ {
+ g_pClientMode->GetViewportAnimationController()->StartAnimationSequence("WeaponOpenBuildSubMenu");
+
+ switch ( buildmenu )
+ {
+ default:
+ case BUILD_OFFENSIVE:
+ g_pClientMode->GetViewportAnimationController()->StartAnimationSequence("WeaponOpenBuildOffensive");
+ break;
+ case BUILD_DEFENSIVE:
+ g_pClientMode->GetViewportAnimationController()->StartAnimationSequence("WeaponOpenBuildDefensive");
+ break;
+ case BUILD_GENERAL_PURPOSE:
+ g_pClientMode->GetViewportAnimationController()->StartAnimationSequence("WeaponOpenBuildGeneral");
+ break;
+ }
+ }
+}
+
+void CHudWeaponSelection::ShowBuildMenu( WeaponMenu& buildMenu )
+{
+ int c = m_Weapons.items.Count();
+ for ( int i = 0; i < c; i++ )
+ {
+ CWeaponMenuItem *item = &m_Weapons.items[ i ];
+ if ( !item || !item->buildslot )
+ continue;
+
+ WeaponMenu &menu = m_BuildObjects[ item->openbuildmenu ];
+ if ( &menu == &buildMenu )
+ {
+ ShowBuildMenu( item->openbuildmenu );
+ return;
+ }
+ }
+
+ Assert( 0 );
+}
+
+void CHudWeaponSelection::HideBuildMenu( void )
+{
+ bool wasinbuild = m_bInBuildMenu;
+
+ GetActiveMenu().SetActiveItem( GetLowIndex( GetActiveMenu() ) );
+ m_bInBuildMenu = false;
+
+ if ( wasinbuild )
+ {
+ g_pClientMode->GetViewportAnimationController()->StartAnimationSequence("WeaponCloseBuildSubMenu");
+ }
+
+ m_nActiveBuildMenu = -1;
+}
+
+WeaponMenu& CHudWeaponSelection::GetActiveMenu()
+{
+ return m_bInBuildMenu ? m_BuildObjects[ m_nActiveBuildMenu ] : m_Weapons;
+}
+
+int CHudWeaponSelection::GetLowIndex( WeaponMenu& menu )
+{
+ if ( menu.items.Count() == 0 )
+ return 1;
+
+ int lowindex = menu.items[ menu.items.FirstInorder() ].hotkey;
+ return lowindex;
+}
+
+void CHudWeaponSelection::WrapIndexToRange( int& index, int low, int high )
+{
+ int delta = ( high - low ) + 1;
+ while ( index < low )
+ {
+ index += delta;
+ }
+
+ while ( index > high )
+ {
+ index -= delta;
+ }
+}
+
+int CHudWeaponSelection::FindSlotForHotKey( WeaponMenu& menu, int hotkey )
+{
+ int count = menu.items.Count();
+ for ( int i = 0; i < count;i++ )
+ {
+ if ( menu.items[ i ].hotkey == hotkey )
+ return i;
+ }
+
+ return 0;
+}
+
+int CHudWeaponSelection::FindNextSelectableWeaponInMenu( WeaponMenu& menu, int startindex, int direction )
+{
+ direction = direction > 0 ? 1 : -1;
+
+ int count = menu.items.Count();
+ int lowindex = GetLowIndex( menu );
+ int highindex = lowindex + count - 1;
+
+ for ( int offset = 1; offset <= count; offset++ )
+ {
+ int current = startindex + offset * direction;
+
+ WrapIndexToRange( current, lowindex, highindex );
+
+ //int slot = FindSlotForHotKey( menu, current );
+
+ //C_BaseCombatWeapon *w = menu.items[ slot ].weapon;
+ //if ( w && !w->CanBeSelected() )
+ // continue;
+
+ return current;
+ }
+
+ return startindex;
+}
+
+int CHudWeaponSelection::CountSelectableItems( WeaponMenu& menu )
+{
+ int count = 0;
+ int c = menu.items.Count();
+ for ( int i = 0; i < c; i++ )
+ {
+ C_BaseCombatWeapon *w = menu.items[ i ].weapon;
+ if ( w && w->CanBeSelected() )
+ {
+ count++;
+ }
+ }
+ return count;
+}
+
+CWeaponMenuItem *CHudWeaponSelection::GetFirstSelectableWeapon( WeaponMenu& menu )
+{
+ int c = menu.items.Count();
+ for ( int i = 0; i < c; i++ )
+ {
+ C_BaseCombatWeapon *w = menu.items[ i ].weapon;
+ if ( w && w->CanBeSelected() )
+ {
+ return &menu.items[ i ];
+ }
+ }
+ return NULL;
+}
+
+const char *CHudWeaponSelection::GetBuildMenuName( int slot )
+{
+ switch ( slot )
+ {
+ default:
+ case BUILD_OFFENSIVE:
+ return "Offensive Object";
+ case BUILD_DEFENSIVE:
+ return "Defensive Object";
+ case BUILD_GENERAL_PURPOSE:
+ return "General Purpose";
+ }
+
+ return "General Purpose";
+}
+
+const char *CHudWeaponSelection::GetBuildMenuMaterial( int slot )
+{
+ switch ( slot )
+ {
+ default:
+ case BUILD_OFFENSIVE:
+ return "weapon_selection_offensive";
+ case BUILD_DEFENSIVE:
+ return "weapon_selection_defensive";
+ case BUILD_GENERAL_PURPOSE:
+ return "weapon_selection_general";
+ }
+
+ return "hud/menu/weapon_selection_general";
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: sets up display for showing weapon pickup
+//-----------------------------------------------------------------------------
+void CHudWeaponSelection::OnWeaponPickup( C_BaseCombatWeapon *pWeapon )
+{
+ // Nothing in TF2
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: returns true if the panel should draw
+//-----------------------------------------------------------------------------
+bool CHudWeaponSelection::ShouldDraw()
+{
+ C_BaseTFPlayer *pPlayer = C_BaseTFPlayer::GetLocalPlayer();
+ if ( !pPlayer || pPlayer->GetPlayerClass() == NULL )
+ {
+ if ( IsInSelectionMode() )
+ {
+ HideSelection();
+ }
+ return false;
+ }
+
+ bool bret = CBaseHudWeaponSelection::ShouldDraw();
+
+ if ( !bret )
+ return false;
+
+ return ( m_bSelectionVisible || ( m_flGrowFraction > 0.0f ) ) ? true : false;
+}
+
+void CHudWeaponSelection::TranslateColor( float percent, Color& clr )
+{
+ if ( percent >= 1.0f )
+ return;
+
+ if ( percent <= 0.75f )
+ {
+ clr = Color( 0, 0, 0, 0 );
+ }
+ else
+ {
+ float frac = ( percent - 0.75f ) / 0.25f;
+
+ clr = Color( clr[0] * frac,
+ clr[1] * frac,
+ clr[2] * frac,
+ clr[3] * frac );
+ }
+}
+
+void CHudWeaponSelection::GetSlotInfo( const CWeaponMenuItem *w, C_BaseCombatWeapon *active, CSlotInfo& info )
+{
+ if ( w->buildslot )
+ {
+ info.active = !m_bInBuildMenu && ( GetActiveMenu().GetActiveItem() == w->hotkey );
+ info.valid = w->isvalidmenuitem;
+ info.icon = gHUD.GetIcon( GetBuildMenuMaterial( w->openbuildmenu ) );
+ info.drawAmmo = false;
+ info.ammoCaution = false;
+ Q_snprintf( info.printname, sizeof( info.printname ), GetBuildMenuName( w->openbuildmenu ) );
+ info.weapon = NULL;
+ }
+ else if ( !w->weapon )
+ {
+ info.active =false;
+ info.valid = false;
+ info.icon = NULL;
+ info.drawAmmo = false;
+ info.ammoCaution = false;
+ info.printname[0]=0;
+ info.weapon = NULL;
+ }
+ else
+ {
+ C_BaseCombatWeapon *pWeapon = w->weapon;
+ Assert( pWeapon );
+
+ info.active = active == pWeapon;
+ info.valid = pWeapon->CanBeSelected();
+ info.icon = info.active ? pWeapon->GetSpriteActive() : pWeapon->GetSpriteInactive();
+
+ info.drawAmmo = false;
+ info.ammoPerc = 1.0f;
+ // Don't know the max ammo, so if I don't use clips, just go red on no ammo left
+ if ( pWeapon->UsesClipsForAmmo1() || pWeapon->HasAmmo() )
+ {
+ info.ammoPerc = 1.0f - ( (float) pWeapon->Clip1() ) / ( (float)pWeapon->GetMaxClip1() );
+ info.drawAmmo = true;
+ }
+ info.ammoCaution = ( info.ammoPerc >= CLIP_PERC_THRESHOLD ) ? true : false;
+
+ Q_snprintf( info.printname, sizeof( info.printname ), "%s", pWeapon->GetPrintName() );
+ info.weapon = pWeapon;
+ }
+
+ strupr(info.printname);
+}
+
+void CHudWeaponSelection::SetupWeaponMenu( WeaponMenu& menu, C_BaseCombatWeapon *activeItem, bool drawNumbers )
+{
+ int panelPosition = 0;
+ for ( int item = menu.items.FirstInorder(); item != menu.items.InvalidIndex() && panelPosition < MAX_WEAPON_MENU_ITEMS; item = menu.items.NextInorder( item ) )
+ {
+ CWeaponMenuItem *w = &menu.items[ item ];
+ Assert( w );
+
+ CSlotInfo info;
+ GetSlotInfo( w, activeItem, info );
+
+ CHudWeaponItemPanel *panel = m_pWeaponPanels[ panelPosition++ ];
+ if ( !panel )
+ {
+ Assert( 0 );
+ continue;
+ }
+
+ panel->m_bInUse = true;
+ panel->info = info;
+ panel->menuItem = *w;
+ panel->m_bDrawNumbers = drawNumbers;
+ }
+
+ for ( ; panelPosition < MAX_WEAPON_MENU_ITEMS; )
+ {
+ CHudWeaponItemPanel *panel = m_pWeaponPanels[ panelPosition++ ];
+ panel->m_bInUse = false;
+ }
+}
+
+void CHudWeaponSelection::SetupBuildMenu( WeaponMenu& menu, C_BaseCombatWeapon *activeItem )
+{
+ int panelPosition = 0;
+ for ( int item = menu.items.FirstInorder(); item != menu.items.InvalidIndex() && panelPosition < MAX_BUILD_MENU_ITEMS; item = menu.items.NextInorder( item ) )
+ {
+ CWeaponMenuItem *w = &menu.items[ item ];
+ Assert( w );
+
+ CSlotInfo info;
+ GetSlotInfo( w, activeItem, info );
+
+ CHudWeaponItemPanel *panel = m_pBuildPanels[ panelPosition++ ];
+ if ( !panel )
+ {
+ Assert( 0 );
+ continue;
+ }
+
+ panel->m_bInUse = true;
+ panel->info = info;
+ panel->menuItem = *w;
+ panel->m_bDrawNumbers = false;
+ }
+
+ for ( ; panelPosition < MAX_BUILD_MENU_ITEMS; )
+ {
+ CHudWeaponItemPanel *panel = m_pBuildPanels[ panelPosition++ ];
+ panel->m_bInUse = false;
+ }
+}
+
+void CHudWeaponSelection::OnTick()
+{
+ C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
+ if ( !pPlayer )
+ return;
+
+ RebuildMenus();
+
+ int x, y;
+ GetPos(x, y);
+
+ C_BaseCombatWeapon *wpn = GetSelectedWeapon();
+
+ // Draw main menu
+ SetupWeaponMenu( m_Weapons, wpn, true );
+
+ CWeaponMenuItem *item = FindWeapon( GetActiveMenu(), GetActiveMenu().GetActiveItem() );
+
+ WeaponMenu* otherMenu = NULL;
+ int buildMenuNumber= 0;
+
+ // Drawing build menu
+ if ( m_bInBuildMenu )
+ {
+ otherMenu = &m_BuildObjects[ m_nActiveBuildMenu ];
+ buildMenuNumber = m_nActiveBuildMenu;
+ }
+ else if ( item && item->buildslot && item->hotkey == GetActiveMenu().GetActiveItem() )
+ {
+ otherMenu = &m_BuildObjects[ item->openbuildmenu ];
+ buildMenuNumber = item->openbuildmenu;
+ }
+ else if ( m_nActiveBuildMenu >= 0 )
+ {
+ otherMenu = &m_BuildObjects[ m_nActiveBuildMenu ];
+ buildMenuNumber = m_nActiveBuildMenu;
+ }
+
+ if ( otherMenu )
+ {
+ SetupBuildMenu( *otherMenu, wpn );
+ }
+ else
+ {
+ ClearBuildMenu();
+ }
+
+ if ( otherMenu != m_PreviousBuildMenu )
+ {
+ m_PreviousBuildMenu = otherMenu;
+
+ if ( otherMenu )
+ {
+ switch ( buildMenuNumber )
+ {
+ default:
+ case BUILD_OFFENSIVE:
+ g_pClientMode->GetViewportAnimationController()->StartAnimationSequence("WeaponOpenBuildOffensive");
+ break;
+ case BUILD_DEFENSIVE:
+ g_pClientMode->GetViewportAnimationController()->StartAnimationSequence("WeaponOpenBuildDefensive");
+ break;
+ case BUILD_GENERAL_PURPOSE:
+ g_pClientMode->GetViewportAnimationController()->StartAnimationSequence("WeaponOpenBuildGeneral");
+ break;
+ }
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: hud scheme settings
+//-----------------------------------------------------------------------------
+void CHudWeaponSelection::ApplySchemeSettings(vgui::IScheme *pScheme)
+{
+ BaseClass::ApplySchemeSettings(pScheme);
+ SetPaintBackgroundEnabled(false);
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Select the next item in the weapon list
+//-----------------------------------------------------------------------------
+void CHudWeaponSelection::CycleToNextWeapon( void )
+{
+ // Get the local player.
+ C_BaseTFPlayer *pPlayer = C_BaseTFPlayer::GetLocalPlayer();
+ if ( !pPlayer || !pPlayer->GetPlayerClass() )
+ return;
+
+ // Make it active
+ bool justopened = false;
+ if ( !IsInSelectionMode() )
+ {
+ OpenSelection();
+ justopened = true;
+ }
+
+ RebuildMenus();
+
+ WeaponMenu& menu = GetActiveMenu();
+ int c = menu.items.Count();
+ if ( c != 0 && !justopened )
+ {
+ GetActiveMenu().SetActiveItem( FindNextSelectableWeaponInMenu( menu, GetActiveMenu().GetActiveItem(), +1 ) );
+ }
+
+ // Play the "cycle to next weapon" sound
+ pPlayer->EmitSound( "Player.WeaponSelectionMoveSlot" );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Selects the previous item in the menu
+//-----------------------------------------------------------------------------
+void CHudWeaponSelection::CycleToPrevWeapon( void )
+{
+ C_BaseTFPlayer *pPlayer = C_BaseTFPlayer::GetLocalPlayer();
+ if ( !pPlayer || !pPlayer->GetPlayerClass() )
+ return;
+
+ // Make it active
+ bool justopened = false;
+ if ( !IsInSelectionMode() )
+ {
+ OpenSelection();
+ justopened = true;
+ }
+
+ RebuildMenus();
+
+ WeaponMenu& menu = GetActiveMenu();
+ int c = menu.items.Count();
+ if ( c != 0 && !justopened )
+ {
+ GetActiveMenu().SetActiveItem( FindNextSelectableWeaponInMenu( menu, GetActiveMenu().GetActiveItem(), -1 ) );
+ }
+
+ // Play the "cycle to next weapon" sound
+ pPlayer->EmitSound( "Player.WeaponSelectionMoveSlot" );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Switches the last weapon the player was using
+//-----------------------------------------------------------------------------
+void CHudWeaponSelection::SwitchToLastWeapon( void )
+{
+ // Get the player's last weapon
+ C_BaseTFPlayer *pPlayer = C_BaseTFPlayer::GetLocalPlayer();
+ if ( !pPlayer )
+ return;
+
+ // If we're currently using the builder weapon, switch to the weapon we were
+ // using before we started using it.
+ C_BaseCombatWeapon *pActiveWeapon = pPlayer->GetActiveWeapon();
+ // Handle the twohanded weapon container
+ CWeaponTwoHandedContainer *pContainer = dynamic_cast< CWeaponTwoHandedContainer * >( pActiveWeapon );
+ if ( pContainer )
+ {
+ pActiveWeapon = pContainer->GetLeftWeapon();
+ }
+
+ if ( dynamic_cast< C_WeaponBuilder* >( pActiveWeapon ) )
+ {
+ ::input->MakeWeaponSelection( pPlayer->GetLastWeaponBeforeObject() );
+ return;
+ }
+
+ // Switch to previous weapon normally
+ ::input->MakeWeaponSelection( pPlayer->GetLastWeapon() );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+CWeaponMenuItem *CHudWeaponSelection::FindWeapon( WeaponMenu& menu, int hotkey )
+{
+ RebuildMenus();
+
+ int c = menu.items.Count();
+
+ for ( int i = 0; i < c; i++ )
+ {
+ CWeaponMenuItem *item = &menu.items[ i ];
+ if ( item->hotkey == hotkey )
+ return item;
+ }
+
+ return NULL;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+C_BaseCombatWeapon *CHudWeaponSelection::GetWeaponInSlot( int iSlot, int iSlotPos )
+{
+ CWeaponMenuItem *item = FindWeapon( GetActiveMenu(), iSlot );
+ if ( item )
+ {
+ return item->weapon;
+ }
+
+ return NULL;
+}
+
+C_BaseCombatWeapon *CHudWeaponSelection::GetSelectedWeapon( void )
+{
+ RebuildMenus();
+
+ return GetWeaponInSlot( GetActiveMenu().GetActiveItem(), 0 );
+}
+
+void CHudWeaponSelection::SelectBuildMenuSlot( WeaponMenu& buildMenu )
+{
+ // Get the local player.
+ C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
+ if ( !pPlayer )
+ return;
+
+ int numSelectable = CountSelectableItems( buildMenu );
+
+ if ( numSelectable >= 1 )
+ {
+ // Single item, just fast switch to it
+ CWeaponMenuItem *fastSwitchItem = GetFirstSelectableWeapon( buildMenu );
+ C_BaseCombatWeapon *w = fastSwitchItem ? fastSwitchItem->weapon : NULL;
+
+ Assert( w && w->CanBeSelected() );
+ if ( 0 && numSelectable == 1 && w && w->CanBeSelected() )
+ {
+ ShowBuildMenu( buildMenu );
+
+ m_hSelectedWeapon = w;
+ GetActiveMenu().SetActiveItem( fastSwitchItem->hotkey );
+
+ // There's only one active item in bucket, so change directly to weapon
+ SetWeaponSelected();
+ engine->ClientCmd( "cancelselect\n" );
+ }
+ else
+ {
+ // Play the "open weapon selection" sound
+ pPlayer->EmitSound( "Player.WeaponSelectionOpen" );
+
+ ShowBuildMenu( buildMenu );
+ }
+ }
+ else
+ {
+ pPlayer->EmitSound( "Player.DenyWeaponSelection" );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Weapon selection code
+//-----------------------------------------------------------------------------
+void CHudWeaponSelection::SelectWeaponSlot( int iSlot )
+{
+ // Get the local player.
+ C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
+ if ( !pPlayer )
+ return;
+
+ // Make sure the player's allowed to switch weapons
+ if ( pPlayer->IsAllowedToSwitchWeapons() == false )
+ return;
+
+ // Make it active
+ if ( !IsInSelectionMode() )
+ {
+ OpenSelection();
+ }
+
+ RebuildMenus();
+ CWeaponMenuItem *item = FindWeapon( GetActiveMenu(), iSlot );
+
+ C_BaseCombatWeapon *weapon = item ? item->weapon : NULL;
+
+ if ( item && item->buildslot )
+ {
+ SelectBuildMenuSlot( m_BuildObjects[ item->openbuildmenu ] );
+ return;
+ }
+
+ if ( m_bInBuildMenu )
+ {
+ CWeaponMenuItem *mainItem = FindWeapon( m_Weapons, iSlot );
+ if ( mainItem )
+ {
+ if ( mainItem->buildslot )
+ {
+ if ( mainItem->openbuildmenu == m_nActiveBuildMenu )
+ {
+ CycleToNextWeapon();
+ }
+ else
+ {
+ SelectBuildMenuSlot( m_BuildObjects[ mainItem->openbuildmenu ] );
+ }
+ }
+ else if ( mainItem->weapon )
+ {
+ // Play the "open weapon selection" sound
+ pPlayer->EmitSound( "Player.WeaponSelectionOpen" );
+
+ m_bInBuildMenu = false;
+ m_hSelectedWeapon = mainItem->weapon;
+ GetActiveMenu().SetActiveItem( mainItem->hotkey );
+
+ // Check for fast weapon switch mode
+ if ( GetSelectedWeapon() && GetSelectedWeapon()->CanBeSelected() )
+ {
+ // There's only one active item in bucket, so change directly to weapon
+ SetWeaponSelected();
+ engine->ClientCmd( "cancelselect\n" );
+ return;
+ }
+ }
+ }
+ return;
+ }
+
+ if ( item && weapon )
+ {
+ // Play the "open weapon selection" sound
+ pPlayer->EmitSound( "Player.WeaponSelectionOpen" );
+
+ if ( !weapon->CanBeSelected() )
+ {
+ if ( GetActiveMenu().GetActiveItem() == item->hotkey )
+ {
+ pPlayer->EmitSound( "Player.DenyWeaponSelection" );
+ }
+ }
+
+ m_hSelectedWeapon = weapon;
+ GetActiveMenu().SetActiveItem( item->hotkey );
+
+ // Check for fast weapon switch mode
+ if ( GetSelectedWeapon() && GetSelectedWeapon()->CanBeSelected() )
+ {
+ // There's only one active item in bucket, so change directly to weapon
+ SetWeaponSelected();
+ engine->ClientCmd( "cancelselect\n" );
+ return;
+ }
+ }
+ else
+ {
+ pPlayer->EmitSound( "Player.DenyWeaponSelection" );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Player has chosen to draw the currently selected weapon
+//-----------------------------------------------------------------------------
+void CHudWeaponSelection::SelectWeapon( void )
+{
+ C_BasePlayer *player = C_BasePlayer::GetLocalPlayer();
+ if ( !player )
+ return;
+
+ CWeaponMenuItem *item = FindWeapon( GetActiveMenu(), GetActiveMenu().GetActiveItem() );
+ if ( !item )
+ {
+ engine->ClientCmd( "cancelselect\n" );
+ return;
+ }
+
+ if ( item->buildslot )
+ {
+ SelectBuildMenuSlot( m_BuildObjects[ item->openbuildmenu ] );
+ return;
+ }
+
+ CBaseHudWeaponSelection::SelectWeapon();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : down -
+// keynum -
+// *pszCurrentBinding -
+//-----------------------------------------------------------------------------
+int CHudWeaponSelection::KeyInput( int down, ButtonCode_t keynum, const char *pszCurrentBinding )
+{
+ if ( !down )
+ return 1;
+
+ if ( keynum != KEY_ESCAPE )
+ return 1;
+
+ C_BasePlayer *player = C_BasePlayer::GetLocalPlayer();
+ if ( !player )
+ return 1;
+
+ if ( !IsInSelectionMode() )
+ return 1;
+
+ if ( !m_bInBuildMenu )
+ {
+ engine->ClientCmd( "cancelselect\n" );
+ return 0;
+ }
+
+ // Play the "open weapon selection" sound
+ player->EmitSound( "Player.WeaponSelectionOpen" );
+
+ HideBuildMenu();
+
+ // Swallow the key
+ return 0;
+}
+
+void CHudWeaponSelection::OpenSelection( void )
+{
+ HideBuildMenu();
+ m_nActiveBuildMenu = -1;
+
+ CBaseHudWeaponSelection::OpenSelection();
+
+ g_pClientMode->GetViewportAnimationController()->StartAnimationSequence("WeaponOpenWeaponMenu");
+}
+
+void CHudWeaponSelection::HideSelection( void )
+{
+ CBaseHudWeaponSelection::HideSelection();
+
+ if ( m_bInBuildMenu )
+ {
+ HideBuildMenu();
+ }
+
+ g_pClientMode->GetViewportAnimationController()->StartAnimationSequence("WeaponCloseWeaponMenu");
+}
+
+int CHudWeaponSelection::GetTeamIndex()
+{
+ C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
+ if(!pPlayer)
+ return HUMAN_WEAPON_SELECTION;
+ int team = pPlayer->GetTeamNumber();
+ if ( !team )
+ return HUMAN_WEAPON_SELECTION;
+
+ bool human = ( team == TEAM_HUMANS ) ? true : false;
+ return human ? HUMAN_WEAPON_SELECTION : ALIEN_WEAPON_SELECTION;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: serializes settings from a resource data container
+//-----------------------------------------------------------------------------
+void CHudWeaponSelection::ApplySettings( KeyValues *resourceData )
+{
+ BaseClass::ApplySettings( resourceData );
+
+ // loop through all the keys, applying them wherever
+ for (KeyValues *controlKeys = resourceData->GetFirstSubKey(); controlKeys != NULL; controlKeys = controlKeys->GetNextKey())
+ {
+ // Skip keys that are atomic..
+ if (controlKeys->GetDataType() != KeyValues::TYPE_NONE)
+ continue;
+
+ Panel *panel = FindChildByName( controlKeys->GetName() );
+ if ( !panel )
+ continue;
+
+ // apply the settings
+ panel->ApplySettings(controlKeys);
+ }
+}
+
+
+
+
+
+
+
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *parent -
+// *panelName -
+//-----------------------------------------------------------------------------
+CHudWeaponItemPanel::CHudWeaponItemPanel( vgui::Panel *parent, const char *panelName )
+ : BaseClass( parent, panelName )
+{
+ m_bInUse = false;
+ m_bDrawNumbers = false;
+ m_nSlotNumber = 0;
+
+ // Copies of data
+ memset( &info, 0, sizeof( info ) );
+ memset( &menuItem, 0, sizeof( menuItem ) );
+
+ memset( m_BackgroundIcons, 0, sizeof( m_BackgroundIcons ) );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *scheme -
+//-----------------------------------------------------------------------------
+void CHudWeaponItemPanel::ApplySchemeSettings( vgui::IScheme *scheme )
+{
+ BaseClass::ApplySchemeSettings( scheme );
+ SetPaintBackgroundEnabled( false );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CHudWeaponItemPanel::Paint()
+{
+ if ( !m_bInUse )
+ return;
+
+ CHudWeaponSelection *selection = static_cast< CHudWeaponSelection * >( GetParent() );
+ if ( !selection )
+ return;
+
+ int wide, tall;
+ GetSize( wide, tall );
+
+ float transparencyfrac = m_flGrowFraction;
+
+ float sizefracw = m_flGrowFraction;
+ float sizefrach = m_flGrowFraction;
+ float sizefrac = m_flGrowFraction;
+
+ bool buildMenu = m_bBuildMenu;
+
+ bool isactive = info.active;
+ bool isvalid = info.valid;
+
+ Color iconColor = selection->GetFgColor();
+ Color textColor = selection->m_TextColor;
+ if ( isactive )
+ {
+ if ( !isvalid )
+ {
+ iconColor = selection->m_InvalidActiveColor;
+ textColor = selection->m_InvalidActiveTextColor;
+ }
+ }
+ else
+ {
+ if ( isvalid )
+ {
+ iconColor = selection->m_OtherColor;
+ textColor = selection->m_OtherTextColor;
+ }
+ else
+ {
+ iconColor = selection->m_InvalidColor;
+ textColor = selection->m_InvalidTextColor;
+ }
+ }
+
+ Color ammoColor = info.ammoCaution ? selection->m_AmmoCautionColor : selection->m_AmmoNormalColor;
+
+ TranslateColor( transparencyfrac, iconColor );
+ TranslateColor( transparencyfrac, textColor );
+ TranslateColor( transparencyfrac, ammoColor );
+
+ // Draw box
+ DrawBox( buildMenu, 0, 0, wide, tall, isactive, isvalid, m_flGrowFraction * 255, m_bDrawNumbers ? menuItem.hotkey : -1 );
+
+ // icons use old system, drawing in screen space
+ int iconXPos = m_flIconXPos;
+ int iconYPos = m_flIconYPos;
+ int iconWide = m_flIconWidth;
+ int iconTall = m_flIconHeight;
+
+ if ( info.icon )
+ {
+ info.icon->DrawSelf( sizefracw * iconXPos, sizefrach * iconYPos, sizefracw * iconWide, sizefrach * iconTall,
+ iconColor );
+ }
+
+ surface()->DrawSetTextColor( textColor );
+ HFont textFont = sizefrac < 1.0 ? selection->m_hTextFontSmall : selection->m_hTextFont;
+ surface()->DrawSetTextFont( textFont );
+ //int slen = UTIL_ComputeStringWidth( textFont, info.printname );
+ int charCount = Q_strlen( info.printname );
+
+ int textYPos = m_flTextYPos;
+ int textXPos = m_flTextXPos;
+
+ surface()->DrawSetTextPos( sizefracw * textXPos, sizefrach * textYPos );
+ for (char *pch = info.printname; charCount > 0; pch++, charCount--)
+ {
+ surface()->DrawUnicodeChar(*pch);
+ }
+
+ if ( info.drawAmmo )
+ {
+ int ammoBarX = m_flAmmoBarX;
+ int ammoBarWide = m_flAmmoBarWide;
+
+ // Draw the clip ratio bar
+ gHUD.DrawProgressBar(
+ sizefracw * ammoBarX, sizefrach * iconYPos,
+ sizefracw * ammoBarWide, sizefrach * iconTall, info.ammoPerc,
+ ammoColor, CHud::HUDPB_VERTICAL );
+ }
+
+ // Let the weapon draw stuff too
+ if ( info.weapon )
+ {
+ C_WeaponObjectSelection *selectionWeapon = dynamic_cast< C_WeaponObjectSelection * >( info.weapon.Get() );
+ if ( selectionWeapon )
+ {
+ OnWeaponSelectionDrawn( selection, selectionWeapon, isactive, wide, tall, textColor );
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: We've just been drawn in the weapon selection
+//-----------------------------------------------------------------------------
+void CHudWeaponItemPanel::OnWeaponSelectionDrawn( CHudWeaponSelection *selection, C_WeaponObjectSelection *weapon,
+ bool bCurrentlySelected, int wide, int tall, Color& clr )
+{
+ CBaseTFPlayer *pOwner = ToBaseTFPlayer( weapon->GetOwner() );
+ if ( !pOwner )
+ return;
+
+ // Draw our resource cost
+ int fontHeight = vgui::surface()->GetFontTall( selection->m_hPriceFont );
+ int iCost = CalculateObjectCost( weapon->GetSubType(), pOwner->GetNumObjects(weapon->GetSubType()), pOwner->GetTeamNumber() );
+
+ int x = wide - m_flPriceXEndPos;
+ int y = tall - m_flPriceYEndPos - fontHeight;
+
+ char text[ 32 ];
+ Q_snprintf( text, sizeof( text ), "%i", iCost );
+
+ // Compute pixels needed so we can right justify it
+ int pixels = 0;
+ char *pch;
+ for (pch = text; *pch != 0; pch++)
+ {
+ pixels += vgui::surface()->GetCharacterWidth( selection->m_hPriceFont, *pch );
+ }
+
+ vgui::surface()->DrawSetTextFont( selection->m_hPriceFont );
+ vgui::surface()->DrawSetTextPos( x - pixels, y );
+ vgui::surface()->DrawSetTextColor( clr );
+ for ( pch = text; *pch; pch++ )
+ {
+ vgui::surface()->DrawUnicodeChar(*pch);
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : percent -
+// clr -
+//-----------------------------------------------------------------------------
+void CHudWeaponItemPanel::TranslateColor( float percent, Color& clr )
+{
+ if ( percent >= 1.0f )
+ return;
+
+ if ( percent <= 0.75f )
+ {
+ clr = Color( 0, 0, 0, 0 );
+ }
+ else
+ {
+ float frac = ( percent - 0.75f ) / 0.25f;
+
+ clr = Color( clr[0] * frac,
+ clr[1] * frac,
+ clr[2] * frac,
+ clr[3] * frac );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: draws a selection box
+//-----------------------------------------------------------------------------
+void CHudWeaponItemPanel::DrawBox( bool isbuildmenu, int x, int y, int wide, int tall, bool isactive, bool isvalid, float normalizedAlpha, int number )
+{
+ CHudWeaponSelection *selection = static_cast< CHudWeaponSelection * >( GetParent() );
+ if ( !selection )
+ {
+ Assert( 0 );
+ return;
+ }
+
+ int team = GetTeamIndex();
+
+ Color boxColor = Color( 255, 255, 255, 255 );
+ boxColor[3] *= ( normalizedAlpha / 255.0f );
+
+ Color numberColor = selection->m_TextColor;
+
+ CHudTexture *texture;
+
+ texture = m_BackgroundIcons[ team ][ (int)IMAGE_BACKGROUND ];
+ if ( texture )
+ {
+ texture->DrawSelf( x, y, wide, tall, boxColor );
+ }
+
+ if ( isactive )
+ {
+ if ( !isvalid )
+ {
+ texture = m_BackgroundIcons[ team ][ (int)IMAGE_INVALID ];
+ if ( texture )
+ {
+ texture->DrawSelf( x, y, wide, tall, boxColor );
+ }
+
+ numberColor = selection->m_InvalidActiveColor;
+ }
+ else
+ {
+ texture = m_BackgroundIcons[ team ][ (int)IMAGE_CURRENT ];
+ if ( texture )
+ {
+ texture->DrawSelf( x, y, wide, tall, boxColor );
+ }
+
+ numberColor = selection->m_OtherColor;
+ }
+ }
+ else
+ {
+ if ( !isvalid )
+ {
+ numberColor = selection->m_InvalidColor;
+ }
+ else
+ {
+ numberColor = selection->m_OtherColor;
+ }
+ }
+
+ // draw the number
+ if (number >= 0)
+ {
+ numberColor[3] *= ( normalizedAlpha / 255.0f );
+ surface()->DrawSetTextColor(numberColor);
+ surface()->DrawSetTextFont(selection->m_hNumberFont);
+ wchar_t wch = '0' + number;
+ surface()->DrawSetTextPos(x + m_flSelectionNumberXPos, y + m_flSelectionNumberYPos);
+ surface()->DrawUnicodeChar(wch);
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Output : int
+//-----------------------------------------------------------------------------
+int CHudWeaponItemPanel::GetTeamIndex()
+{
+ C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
+ if(!pPlayer)
+ return HUMAN_WEAPON_SELECTION;
+ int team = pPlayer->GetTeamNumber();
+ if ( !team )
+ return HUMAN_WEAPON_SELECTION;
+
+ bool human = ( team == TEAM_HUMANS ) ? true : false;
+ return human ? HUMAN_WEAPON_SELECTION : ALIEN_WEAPON_SELECTION;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CHudWeaponItemPanel::SetupIcons()
+{
+ memset( m_BackgroundIcons, 0, sizeof( m_BackgroundIcons ) );
+
+ const char *menutypestr = m_bBuildMenu ? "build" : "selection";
+
+ for ( int team = 0; team < NUM_SLOT_TEAMS; team++ )
+ {
+ const char *teamtype = team == 0 ? "human" : "alien";
+
+ for ( int type = 0; type < NUM_MENU_TYPES; type++ )
+ {
+ const char *slottype = type == 0 ? "background" : type == 1 ? "current" : "invalid";
+
+ char sz[ 256 ];
+ Q_snprintf( sz, sizeof( sz ), "%s_weapon_%s_%s_%i",
+ teamtype, menutypestr, slottype, m_nSlotNumber + 1 );
+
+ m_BackgroundIcons[ team ][ type ] = gHUD.GetIcon( sz );;
+ }
+ }
+}
diff --git a/game/client/tf2/infiltratorcamomaterialproxy.cpp b/game/client/tf2/infiltratorcamomaterialproxy.cpp
new file mode 100644
index 0000000..9d099fe
--- /dev/null
+++ b/game/client/tf2/infiltratorcamomaterialproxy.cpp
@@ -0,0 +1,84 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+#include "cbase.h"
+#include "proxyentity.h"
+#include "materialsystem/imaterial.h"
+#include "materialsystem/imaterialvar.h"
+#include "materialsystem/imaterialsystem.h"
+#include "c_basetfplayer.h"
+#include "c_tf_basecombatweapon.h"
+
+class CInfiltratorCamoMaterialProxy : public CEntityMaterialProxy
+{
+public:
+ CInfiltratorCamoMaterialProxy();
+ virtual ~CInfiltratorCamoMaterialProxy();
+ virtual bool Init( IMaterial *pMaterial, KeyValues* pKeyValues );
+ virtual void OnBind( C_BaseEntity *pC_BaseEntity );
+
+private:
+ IMaterialVar *m_CamoVar;
+};
+
+CInfiltratorCamoMaterialProxy::CInfiltratorCamoMaterialProxy()
+{
+ m_CamoVar = NULL;
+}
+
+CInfiltratorCamoMaterialProxy::~CInfiltratorCamoMaterialProxy()
+{
+}
+
+
+bool CInfiltratorCamoMaterialProxy::Init( IMaterial *pMaterial, KeyValues* pKeyValues )
+{
+ bool foundVar;
+
+ m_CamoVar = pMaterial->FindVar( "$alpha", &foundVar, false );
+ if( !foundVar )
+ {
+ m_CamoVar = NULL;
+ return false;
+ }
+ return true;
+}
+
+void CInfiltratorCamoMaterialProxy::OnBind( C_BaseEntity *pEnt )
+{
+ if( !m_CamoVar )
+ return;
+
+ C_BaseTFPlayer *player = dynamic_cast< C_BaseTFPlayer * >( pEnt );
+ if ( player )
+ {
+ float amount = 1 - player->ComputeCamoEffectAmount();
+ m_CamoVar->SetFloatValue( amount );
+ }
+ else
+ {
+ // Weapon model?
+ C_BaseTFCombatWeapon *pWeapon = dynamic_cast< C_BaseTFCombatWeapon * >( pEnt );
+ if ( pWeapon )
+ {
+ float amount = 1 - ((C_BaseTFPlayer *)pWeapon->GetOwner())->ComputeCamoEffectAmount();
+ m_CamoVar->SetFloatValue( amount );
+ }
+ else
+ {
+ C_BaseViewModel *pViewmodel = dynamic_cast< C_BaseViewModel * >( pEnt );
+ if ( pViewmodel )
+ {
+ // Get the local player's values
+ player = C_BaseTFPlayer::GetLocalPlayer();
+ float amount = 1 - player->ComputeCamoEffectAmount();
+ m_CamoVar->SetFloatValue( amount );
+ }
+ }
+ }
+}
+
+EXPOSE_INTERFACE( CInfiltratorCamoMaterialProxy, IMaterialProxy, "InfiltratorCamo" IMATERIAL_PROXY_INTERFACE_VERSION );
diff --git a/game/client/tf2/itfhintitem.h b/game/client/tf2/itfhintitem.h
new file mode 100644
index 0000000..218b1f7
--- /dev/null
+++ b/game/client/tf2/itfhintitem.h
@@ -0,0 +1,58 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef ITFHINTITEM_H
+#define ITFHINTITEM_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+namespace vgui
+{
+ class Panel;
+}
+
+class KeyValues;
+
+//-----------------------------------------------------------------------------
+// Purpose: All TF Hint Item Panels multiply inheret from this interface
+//-----------------------------------------------------------------------------
+class ITFHintItem
+{
+public:
+ virtual void ParseItem( KeyValues *pKeyValues ) = 0;
+
+ // Delete the hint
+ virtual void DeleteThis( void ) = 0;
+
+ // Returns true if the hint criteria have been met
+ virtual bool GetCompleted( void ) = 0;
+ // Mark the hint as active
+ virtual void SetActive( bool active ) = 0;
+ // Determine if the hint is the current, active hint
+ virtual bool GetActive( void ) = 0;
+ // Allow hint to run code
+ virtual void Think( void ) = 0;
+ // Determine height of hint
+ virtual int GetHeight( void ) = 0;
+ // Set screen position of hint
+ virtual void SetPosition( int x, int y ) = 0;
+ // Tell hint where it sits in current list of hints
+ virtual void SetItemNumber( int index ) = 0;
+ // Set the hint visible/invisible
+ virtual void SetVisible( bool visible ) = 0;
+ // Change the target (Panel) of the hint
+ virtual void SetHintTarget( vgui::Panel *panel ) = 0;
+ // Return true if hint should render this frame (default returns true if GetActive() is true)
+ virtual bool ShouldRenderPanelEffects( void ) = 0;
+ // Allow item to change title text
+ virtual void ComputeTitle( void ) = 0;
+ // Allow outside influence over keyvalues
+ virtual void SetKeyValue( const char *key, const char *value ) = 0;
+};
+
+#endif // ITFHINTITEM_H
diff --git a/game/client/tf2/iusesmortarpanel.h b/game/client/tf2/iusesmortarpanel.h
new file mode 100644
index 0000000..3a3e23f
--- /dev/null
+++ b/game/client/tf2/iusesmortarpanel.h
@@ -0,0 +1,69 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#ifndef IUSESMORTARPANEL_H
+#define IUSESMORTARPANEL_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "hud_minimap.h"
+
+// Derive from this if your entity wants to use the mortar firing panel
+class IUsesMortarPanel
+{
+public:
+ // Get the data from this mortar needed by the panel
+ virtual void GetMortarData( float *flClientMortarYaw, bool *bAllowedToFire, float *flPower, float *flFiringPower, float *flFiringAccuracy, int *iFiringState ) = 0;
+
+ // Tell the server the mortar's been rotated
+ virtual void SendYawCommand( void ) = 0;
+
+ // Panel's overriding client yaw
+ virtual void ForceClientYawCountdown( float flTime ) = 0;
+
+ // Start firing
+ virtual void ClickFire( void ) = 0;
+};
+
+// Mortar firing panel
+class CMortarMinimapPanel : public CMinimapPanel
+{
+public:
+
+ DECLARE_CLASS( CMortarMinimapPanel, CMinimapPanel );
+
+ CMortarMinimapPanel( vgui::Panel *pParent, const char *pElementName );
+ virtual ~CMortarMinimapPanel();
+
+ void InitMortarMinimap( C_BaseEntity *pMortar );
+ C_BaseEntity *GetMortar() const;
+
+ virtual void Paint();
+
+ void OnMousePressed( vgui::MouseCode code );
+ void OnCursorMoved( int x, int y );
+ void OnMouseReleased( vgui::MouseCode code );
+
+
+public:
+
+ EHANDLE m_hMortar;
+ BitmapImage m_MortarButtonUp;
+ BitmapImage m_MortarButtonDown;
+ BitmapImage m_MortarButtonCantFire;
+ BitmapImage m_MortarDirectionImage;
+
+ bool m_bMouseDown;
+ bool m_bFireButtonDown;
+ int m_LastX, m_LastY;
+
+ // The red-black fade material for the slider.
+ int m_nTextureId;
+ int m_nTextureId_CantFire;
+};
+
+#endif // IUSESMORTARPANEL_H
diff --git a/game/client/tf2/mapdata.cpp b/game/client/tf2/mapdata.cpp
new file mode 100644
index 0000000..cc1c3c5
--- /dev/null
+++ b/game/client/tf2/mapdata.cpp
@@ -0,0 +1,372 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $Workfile: $
+// $NoKeywords: $
+//=============================================================================//
+#include "cbase.h"
+#include "mapdata.h"
+#include "hud.h"
+#include "hud_macros.h"
+#include <KeyValues.h>
+#include "playeroverlay.h"
+#include "iclientmode.h"
+#include "hud_technologytreedoc.h"
+#include "C_World.h"
+#include "c_basetfplayer.h"
+#include "c_team.h"
+#include "c_tfteam.h"
+#include "c_func_resource.h"
+#include "vgui_bitmapimage.h"
+#include "C_Shield.h"
+#include "c_obj_respawn_station.h"
+
+bool IsEntityVisibleToTactical( int iLocalTeamNumber, int iLocalTeamPlayers,
+ int iLocalTeamObjects, int iEntIndex, const char *pEntName, int pEntTeamNumber, const Vector &pEntOrigin );
+
+// All of the parsing occurs mapdata_parse.cpp
+bool ParseMinimapData( const char *filename, MinimapData_t *pMinimap, CMapZones *pZones, CMapTeamColors *pTeamColors, KeyValues *pKV );
+
+
+//-----------------------------------------------------------------------------
+// Gets at the singleton map data
+//-----------------------------------------------------------------------------
+
+static CMapData g_MapData;
+CMapData& MapData()
+{
+ // Singleton object
+ return g_MapData;
+}
+
+IMapData *g_pMapData = &g_MapData;
+
+DECLARE_COMMAND( g_MapData, ForceMapReload );
+
+//-----------------------------------------------------------------------------
+// Purpose: This is a total hack, but should allow reloading the mapfile.txt stuff on the fly
+//-----------------------------------------------------------------------------
+void CMapData::UserCmd_ForceMapReload( void )
+{
+ if ( m_szMap[0] )
+ {
+ LevelInit( m_szMap );
+ // Force other data to reinit itself
+ GetTechnologyTreeDoc().Init();
+
+ // Force any needed viewport fixups
+ g_pClientMode->Disable();
+ g_pClientMode->Enable();
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+CMapData::CMapData( void )
+{
+ m_szMap[0]=0;
+
+ int i, j;
+ m_Minimap.m_szBackgroundMaterial[0] = 0;
+
+ for ( i = 0; i < MAX_ZONES; i++ )
+ {
+ m_Zones[ i ].m_pZoneImage = NULL;
+ m_Zones[ i ].m_nControllingTeam = -1;
+ }
+
+ for ( i = 0; i < MAX_PLAYERS; i++ )
+ {
+ m_Players[ i ].m_pImage = NULL;
+ m_Players[ i ].m_nTeam = 0;
+ m_Players[ i ].m_bSelected = false;
+ m_Players[ i ].m_nSquadNumber = 0;
+
+ }
+
+ for ( i = 0; i <= MAX_MAP_TEAMS; i++ )
+ {
+ m_TeamColors[ i ].m_pImage = NULL;
+
+ for ( j = 0; j < MAX_CLASSES; j++ )
+ {
+ if ( m_TeamColors[ i ].m_ClassColors[ j ].m_pClassImage )
+ {
+ m_TeamColors[ i ].m_ClassColors[ j ].m_pClassImage = NULL;
+ }
+ }
+ }
+
+ UseDefaults();
+}
+
+HOOK_COMMAND( forcemapreload, ForceMapReload );
+
+//-----------------------------------------------------------------------------
+// Purpose: One time init
+//-----------------------------------------------------------------------------
+void CMapData::Init( void )
+{
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Delete all dynamic images, but leave rest of data structures
+//-----------------------------------------------------------------------------
+void CMapData::Clear( void )
+{
+ int i, j;
+
+ // Delete old zones...
+ for ( i = 0; i < MAX_ZONES; i++ )
+ {
+ delete m_Zones[ i ].m_pZoneImage;
+ m_Zones[ i ].m_pZoneImage = NULL;
+ }
+
+ for ( i = 0; i <= MAX_MAP_TEAMS; i++ )
+ {
+ delete m_TeamColors[ i ].m_pImage;
+ m_TeamColors[ i ].m_pImage = NULL;
+
+ for ( j = 0; j < MAX_CLASSES; j++ )
+ {
+ delete m_TeamColors[ i ].m_ClassColors[ j ].m_pClassImage;
+ m_TeamColors[ i ].m_ClassColors[ j ].m_pClassImage = NULL;
+ }
+ }
+
+ m_Minimap.m_szBackgroundMaterial[0] = 0;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+CMapData::~CMapData( void )
+{
+ Clear();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Set a team's default colors
+//-----------------------------------------------------------------------------
+void CMapData::SetTeamDefaultColor( int iTeamNumber, int r, int g, int b )
+{
+ m_TeamColors[ iTeamNumber ].m_clrBlip.SetColor( r,g,b, 0 );
+ m_TeamColors[ iTeamNumber ].m_clrTeam.SetColor( r,g,b, 128 );
+
+ for ( int j = 0; j < MAX_CLASSES; j++ )
+ {
+ m_TeamColors[ iTeamNumber ].m_ClassColors->m_clrClass.SetColor( r,g,b, 0 );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Fill in placeholder colors, etc.
+//-----------------------------------------------------------------------------
+void CMapData::UseDefaults( void )
+{
+ // Init colors for all teams
+ SetTeamDefaultColor( 1, 255, 0, 0 );
+ SetTeamDefaultColor( 2, 0, 0, 255 );
+ SetTeamDefaultColor( 3, 0, 0, 0 );
+ SetTeamDefaultColor( 4, 0, 0, 0 );
+ SetTeamDefaultColor( 5, 0, 0, 0 );
+ SetTeamDefaultColor( 6, 0, 0, 0 );
+ SetTeamDefaultColor( 7, 0, 0, 0 );
+ SetTeamDefaultColor( 8, 0, 0, 0 );
+
+ m_Minimap.m_szBackgroundMaterial[0] = 0;
+}
+
+
+//-----------------------------------------------------------------------------
+// Get the bounding box of the world
+//-----------------------------------------------------------------------------
+void CMapData::GetMapBounds(Vector &mins, Vector& maxs)
+{
+ C_BaseEntity *ent = cl_entitylist->GetEnt( 0 );
+ C_World* pWorld = dynamic_cast<C_World*>(ent);
+ if (pWorld)
+ {
+ VectorCopy( pWorld->m_WorldMins, mins );
+ VectorCopy( pWorld->m_WorldMaxs, maxs );
+
+ // Backward compatability...
+ if ((mins.LengthSqr() == 0.0f) && (maxs.LengthSqr() == 0.0f))
+ {
+ mins.Init( -6500, -6500, -6500 );
+ maxs.Init( 6500, 6500, 6500 );
+ }
+ }
+ else
+ {
+ Assert(0);
+ mins.Init( 0, 0, 0 );
+ maxs.Init( 1, 1, 1 );
+ }
+}
+
+void CMapData::GetMapOrigin(Vector &org)
+{
+ Vector mins, maxs;
+ GetMapBounds( mins, maxs );
+ VectorAdd( mins, maxs, org );
+ VectorMultiply( org, 0.5, org );
+}
+
+void CMapData::GetMapSize(Vector &size)
+{
+ Vector mins, maxs;
+ GetMapBounds( mins, maxs );
+ VectorSubtract( maxs, mins, size );
+}
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void CMapData::Get3DSkyboxOrigin( Vector &vecOrigin )
+{
+ // NOTE: If the player hasn't been created yet -- this doesn't work!!!
+ // We need to pass the data along in the map - requires a tool change.
+ C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
+ if ( pPlayer )
+ {
+ CPlayerLocalData *pLocalData = &pPlayer->m_Local;
+ VectorCopy( pLocalData->m_skybox3d.origin, vecOrigin );
+ }
+ else
+ {
+ // Debugging!
+ Assert( 0 );
+ vecOrigin.Init();
+ }
+}
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+float CMapData::Get3DSkyboxScale( void )
+{
+ // NOTE: If the player hasn't been created yet -- this doesn't work!!!
+ // We need to pass the data along in the map - requires a tool change.
+ C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
+ if ( pPlayer )
+ {
+ CPlayerLocalData *pLocalData = &pPlayer->m_Local;
+ return pLocalData->m_skybox3d.scale;
+ }
+ else
+ {
+ // Debugging!
+ Assert( 0 );
+ return ( 1.0f );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// What's my visible area?
+//-----------------------------------------------------------------------------
+void CMapData::SetVisibleArea( const Vector& mins, const Vector& maxs )
+{
+ m_VisibleMins = mins;
+ m_VisibleMaxs = maxs;
+}
+
+void CMapData::GetVisibleArea( Vector& mins, Vector& maxs )
+{
+ mins = m_VisibleMins;
+ maxs = m_VisibleMaxs;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: The client is about to change maps
+// Input : *map - name of the new map
+//-----------------------------------------------------------------------------
+void CMapData::LevelInit( const char *map )
+{
+ Q_strncpy( m_szMap, map, MINIMAP_STRING_SIZE );
+
+ // Clear leftover data
+ Clear();
+
+ // The name of the background material for the map is well-defined
+ Q_snprintf( m_Minimap.m_szBackgroundMaterial, MINIMAP_MATERIAL_STRING_SIZE,
+ "hud/minimap/%s/%s", map, map );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CMapData::LevelShutdown( void )
+{
+ Clear();
+}
+
+
+//-----------------------------------------------------------------------------
+// Update fog of war
+//-----------------------------------------------------------------------------
+void CMapData::Update( void )
+{
+}
+
+
+//-----------------------------------------------------------------------------
+// Is entity visible to tactical?
+//-----------------------------------------------------------------------------
+bool CMapData::IsEntityVisibleToTactical( C_BaseEntity* pEnt ) const
+{
+ C_BaseTFPlayer *pPlayer = C_BaseTFPlayer::GetLocalPlayer();
+ if (!pPlayer)
+ return false;
+
+ // If the local player hasn't chosen a class or a team, nothing's visible
+ if ((pPlayer->GetClass() == TFCLASS_UNDECIDED) || (pPlayer->GetTeamNumber() == 0))
+ return false;
+
+ C_TFTeam *pTeam = (C_TFTeam *)pPlayer->GetTeam();
+ if (!pTeam)
+ return false;
+
+ // Local player is always visible, as long as he's chosen a class.
+ if (pEnt == pPlayer)
+ return true;
+
+ int iNumberObjects = 0;
+ int iNumberPlayers = 0;
+ if ( pTeam )
+ {
+ iNumberObjects = pTeam->GetNumObjects();
+ iNumberPlayers = pTeam->Get_Number_Players();
+ }
+
+ int localteam = pPlayer->GetTeamNumber();
+
+ // If on our team, not on a team, or is a resource zone, can't be cloaked
+ if ( !pEnt->GetTeamNumber() || pEnt->GetTeamNumber() == localteam )
+ {
+ return true;
+ }
+
+ // NOTE: The global IsEntityVisibleToTactical returns true in situations
+ // where the entity would otherwise not be visible
+ bool bRet = ::IsEntityVisibleToTactical( localteam, iNumberPlayers,
+ iNumberObjects, pEnt->entindex(), pEnt->GetClassname(), pEnt->GetTeamNumber(), pEnt->GetAbsOrigin() );
+
+ if ( bRet )
+ {
+ return true;
+ }
+
+ // Make sure it's within a well-defined radius of the local player...
+ Vector2D dist;
+ Vector2DSubtract( pEnt->GetAbsOrigin().AsVector2D(), pPlayer->GetAbsOrigin().AsVector2D(), dist );
+
+ // Cloaked by this object?
+ if ( dist.LengthSqr() > LOCAL_PLAYER_SCANNER_RANGE * LOCAL_PLAYER_SCANNER_RANGE )
+ return false;
+
+ // On other team, and not cloaked by technician
+ return true;
+}
diff --git a/game/client/tf2/mapdata.h b/game/client/tf2/mapdata.h
new file mode 100644
index 0000000..a251b9b
--- /dev/null
+++ b/game/client/tf2/mapdata.h
@@ -0,0 +1,128 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $Workfile: $
+// $NoKeywords: $
+//=============================================================================//
+#if !defined( MAPDATA_H )
+#define MAPDATA_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include <vgui_controls/Panel.h>
+#include <vgui/IImage.h>
+#include "mathlib/vector.h"
+#include "mapdata_shared.h"
+#include "sharedinterface.h"
+
+#define MAX_ZONES 32
+#define MAX_CLASSES 32
+#define MAX_MAP_TEAMS 8
+#define MINIMAP_MATERIAL_STRING_SIZE 64
+#define MINIMAP_STRING_SIZE 128
+
+class Vector;
+class C_BaseEntity;
+class BitmapImage;
+
+class CMapClassColors
+{
+public:
+ BitmapImage *m_pClassImage;
+ Color m_clrClass;
+};
+
+class CMapTeamColors
+{
+public:
+ CMapClassColors m_ClassColors[ MAX_CLASSES ];
+
+ BitmapImage *m_pImage;
+ Color m_clrBlip;
+ Color m_clrTeam;
+};
+
+class CMapPlayers
+{
+public:
+ int m_nTeam;
+ bool m_bVisible;
+ bool m_bSelected;
+ int m_nSquadNumber;
+ int m_nXPos, m_nYPos;
+
+ BitmapImage *m_pImage;
+ Color m_clrPlayer;
+};
+
+class CMapZones
+{
+public:
+ int m_nControllingTeam;
+
+ BitmapImage *m_pZoneImage;
+};
+
+struct MinimapData_t
+{
+ char m_szBackgroundMaterial[MINIMAP_MATERIAL_STRING_SIZE];
+};
+
+class CMapData : public IMapData
+{
+public:
+ CMapData( void );
+ virtual ~CMapData( void );
+
+ void Init( void );
+ void Clear( void );
+ void LevelInit( const char *map );
+ void LevelShutdown( void );
+
+ void Update( );
+ bool IsEntityVisibleToTactical( C_BaseEntity* pEnt ) const;
+
+ void UseDefaults( void );
+ void SetTeamDefaultColor( int iTeamNumber, int r, int g, int b );
+
+ void UserCmd_ForceMapReload( void );
+
+ // map dimensions
+ void GetMapBounds(Vector& mins, Vector& maxs);
+ void GetMapOrigin(Vector& org);
+ void GetMapSize(Vector& size);
+
+ // 3d skybox
+ void Get3DSkyboxOrigin( Vector &vecOrigin );
+ float Get3DSkyboxScale( void );
+
+ // Indicates the area currently visible in commander mode
+ void SetVisibleArea( const Vector& mins, const Vector& maxs );
+ void GetVisibleArea( Vector& mins, Vector& maxs );
+
+public:
+ CMapZones m_Zones[ MAX_ZONES ];
+ CMapPlayers m_Players[ MAX_PLAYERS ];
+ CMapTeamColors m_TeamColors[ MAX_MAP_TEAMS+1 ];
+ MinimapData_t m_Minimap;
+
+private:
+ char m_szMap[ MINIMAP_STRING_SIZE ];
+
+ // World size + visible size in commander mode
+ Vector m_WorldMins;
+ Vector m_WorldMaxs;
+ Vector m_VisibleMins;
+ Vector m_VisibleMaxs;
+};
+
+
+//-----------------------------------------------------------------------------
+// Gets at the singleton map data
+//-----------------------------------------------------------------------------
+CMapData& MapData();
+
+
+#endif // MAPDATA_H \ No newline at end of file
diff --git a/game/client/tf2/minimap_players.cpp b/game/client/tf2/minimap_players.cpp
new file mode 100644
index 0000000..dcf1cbb
--- /dev/null
+++ b/game/client/tf2/minimap_players.cpp
@@ -0,0 +1,250 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+#include "cbase.h"
+#include "hud.h"
+#include "c_basetfplayer.h"
+#include "minimap_trace.h"
+#include "vgui_entityimagepanel.h"
+#include <KeyValues.h>
+#include "vgui_bitmapimage.h"
+#include "ViewConeImage.h"
+#include "VGuiMatSurface/IMatSystemSurface.h"
+#include "shareddefs.h"
+#include "voice_status.h"
+#include "iclientvehicle.h"
+
+//-----------------------------------------------------------------------------
+// Minimap panel representing players
+//-----------------------------------------------------------------------------
+class CMinimapPlayerPanel : public CMinimapTracePanel
+{
+ DECLARE_CLASS( CMinimapPlayerPanel, CMinimapTracePanel );
+
+public:
+ CMinimapPlayerPanel( vgui::Panel *parent, const char *panelName )
+ : BaseClass( parent, "CMinimapPlayerPanel" )
+ {
+ }
+
+ virtual bool Init( KeyValues* pKeyValues, MinimapInitData_t* pInitData );
+ virtual void Paint( );
+ virtual void OnTick( );
+
+private:
+ // Parse class image data from the file
+ bool InitClassImages( KeyValues* pKeyValues, MinimapInitData_t* pInitData );
+
+ CTeamBitmapImage m_DeadImage;
+ CTeamBitmapImage m_AliveImage;
+ CTeamBitmapImage m_LocalAliveImage;
+ CTeamBitmapImage m_ArrowImage;
+ CTeamBitmapImage m_pClassAliveImages[TFCLASS_CLASS_COUNT];
+ BitmapImage m_VoiceImage;
+ bool m_bHasClassImage[TFCLASS_CLASS_COUNT];
+ int m_LocalOffsetX, m_LocalOffsetY;
+ int m_LocalSizeX, m_LocalSizeY;
+ int m_VoiceOffsetX, m_VoiceOffsetY;
+ int m_VoiceSizeX, m_VoiceSizeY;
+ float m_flVoiceAlpha;
+};
+
+DECLARE_MINIMAP_FACTORY( CMinimapPlayerPanel, "minimap_player_panel" );
+
+
+//-----------------------------------------------------------------------------
+// Parse class image data from the file
+//-----------------------------------------------------------------------------
+bool CMinimapPlayerPanel::InitClassImages( KeyValues* pKeyValues, MinimapInitData_t* pInitData )
+{
+ memset( m_bHasClassImage, 0, TFCLASS_CLASS_COUNT * sizeof(bool) );
+
+ for (int i = 1; i < TFCLASS_CLASS_COUNT; ++i)
+ {
+ KeyValues *pClassSection = pKeyValues->FindKey( GetTFClassInfo(i)->m_pClassName );
+ if (!pClassSection)
+ continue;
+
+ m_bHasClassImage[i] = true;
+ if (!InitializeTeamImage( pKeyValues, GetTFClassInfo( i )->m_pClassName, this, pInitData->m_pEntity, &m_pClassAliveImages[i] ))
+ return false;
+ }
+
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+// Parse data from the file
+//-----------------------------------------------------------------------------
+bool CMinimapPlayerPanel::Init( KeyValues* pKeyValues, MinimapInitData_t* pInitData )
+{
+ // Must be applied to players
+ Assert( dynamic_cast< C_BaseTFPlayer * >( pInitData->m_pEntity ) );
+
+ if (!BaseClass::Init( pKeyValues, pInitData ))
+ return false;
+
+ if (!InitializeTeamImage( pKeyValues, "localaliveimage", this, pInitData->m_pEntity, &m_LocalAliveImage))
+ return false;
+
+ if (!InitializeTeamImage( pKeyValues, "aliveimage", this, pInitData->m_pEntity, &m_AliveImage ))
+ return false;
+
+ if (!InitializeTeamImage( pKeyValues, "arrowimage", this, pInitData->m_pEntity, &m_ArrowImage ))
+ return false;
+
+ if (!InitializeTeamImage( pKeyValues, "deadimage", this, pInitData->m_pEntity, &m_DeadImage ))
+ return false;
+
+ if (!InitializeImage( pKeyValues, "voiceimage", this, &m_VoiceImage ))
+ return false;
+
+ // Load class-specific images
+ if (!InitClassImages( pKeyValues, pInitData ) )
+ return false;
+
+ // Modify the size if this is the local player
+ if (!ParseCoord(pKeyValues, "localplayeroffset", m_LocalOffsetX, m_LocalOffsetY))
+ return false;
+
+ if (!ParseCoord(pKeyValues, "localplayersize", m_LocalSizeX, m_LocalSizeY ))
+ return false;
+
+ if (!ParseCoord(pKeyValues, "voiceoffset", m_VoiceOffsetX, m_VoiceOffsetY ))
+ return false;
+
+ if (!ParseCoord(pKeyValues, "voicesize", m_VoiceSizeX, m_VoiceSizeY ))
+ return false;
+
+ m_flVoiceAlpha = 0.0f;
+ SetCursor( NULL );
+
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+// Render
+//-----------------------------------------------------------------------------
+void CMinimapPlayerPanel::OnTick( )
+{
+ // Modify position and size if we're the local player
+ // It's too bad, but we can't do this during Init() because
+ // C_BaseTFPlayer::GetLocalPlayer() doesn't return the correct value at that time
+ if ( C_BaseTFPlayer::GetLocalPlayer() == GetEntity() )
+ {
+ m_OffsetX = m_LocalOffsetX;
+ m_OffsetY = m_LocalOffsetY;
+
+ m_SizeW = m_LocalSizeX;
+ m_SizeH = m_LocalSizeY;
+
+ // Make sure the local player draws on top
+ SetZPos( MINIMAP_LOCAL_PLAYER );
+
+ SetSize( m_LocalSizeX, m_LocalSizeY );
+ }
+
+ BaseClass::OnTick();
+}
+
+
+//-----------------------------------------------------------------------------
+// Render
+//-----------------------------------------------------------------------------
+void CMinimapPlayerPanel::Paint( )
+{
+ if ( gHUD.IsHidden( HIDEHUD_MISCSTATUS ) )
+ return;
+
+ C_BaseEntity* pEntity = GetEntity();
+ Assert( pEntity );
+
+ // Don't render players if they aren't on a team
+ if( pEntity->GetTeamNumber() == 0 )
+ return;
+
+ C_BaseTFPlayer *local = C_BaseTFPlayer::GetLocalPlayer();
+ C_BaseTFPlayer *pPlayer = static_cast< C_BaseTFPlayer * >( pEntity );
+ Assert( pPlayer );
+
+ if (!m_bClipToMap)
+ g_pMatSystemSurface->DisableClipping( true );
+
+ // Set the fade amount (only for alive players)...
+// m_AliveImage.SetAlpha( pPlayer->GetOverlayAlpha() );
+// m_LocalAliveImage.SetAlpha( pPlayer->GetOverlayAlpha() );
+
+ bool isLocalPlayer = ( pEntity == local );
+
+ bool isAlive = pPlayer->GetHealth() > 0 ? true : false;
+ if ( isAlive )
+ {
+ if ( pPlayer->IsPlayerDead() )
+ {
+ isAlive = false;
+ }
+ }
+
+ float yaw = pPlayer->EyeAngles().y;
+ if ( pPlayer->InLocalTeam() && GetClientVoiceMgr()->IsPlayerSpeaking( pPlayer->entindex() ) &&
+ GetClientVoiceMgr()->IsPlayerAudible( pPlayer->entindex() ) )
+ {
+ m_flVoiceAlpha = 1.0f;
+ }
+ else if (m_flVoiceAlpha != 0.0f)
+ {
+ m_flVoiceAlpha *= 0.8f;
+ if (m_flVoiceAlpha < 0.005)
+ m_flVoiceAlpha = 0.0f;
+ }
+
+ if ( m_flVoiceAlpha != 0.0f )
+ {
+ int x = (int)(m_VoiceOffsetX - m_OffsetX + 0.5f);
+ int y = (int)(m_VoiceOffsetY - m_OffsetY + 0.5f);
+
+ g_pMatSystemSurface->DisableClipping( true );
+ m_VoiceImage.DoPaint( x, y, m_VoiceSizeX, m_VoiceSizeY, 0, m_flVoiceAlpha );
+ if (m_bClipToMap)
+ g_pMatSystemSurface->DisableClipping( false );
+ }
+
+ // Draw dead guys with a different icon
+ if ( isAlive )
+ {
+ if (isLocalPlayer)
+ {
+ m_LocalAliveImage.Paint( );
+ m_ArrowImage.Paint( yaw );
+ }
+ else
+ {
+ int nPlayerClass = pPlayer->GetClass();
+ if (pPlayer->InLocalTeam() && m_bHasClassImage[nPlayerClass])
+ {
+ m_pClassAliveImages[nPlayerClass].Paint( );
+ m_ArrowImage.Paint( yaw );
+ }
+ else
+ {
+ m_AliveImage.Paint( );
+ m_ArrowImage.Paint( yaw );
+ }
+ }
+ }
+ else
+ {
+ m_DeadImage.Paint();
+ }
+
+ g_pMatSystemSurface->DisableClipping( false );
+}
+
+
+
+
diff --git a/game/client/tf2/minimap_resourcezone.cpp b/game/client/tf2/minimap_resourcezone.cpp
new file mode 100644
index 0000000..56bbdc9
--- /dev/null
+++ b/game/client/tf2/minimap_resourcezone.cpp
@@ -0,0 +1,95 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+#include "cbase.h"
+#include "hud.h"
+#include "c_func_resource.h"
+#include "vgui_bitmapimage.h"
+#include <KeyValues.h>
+#include "minimap_trace.h"
+#include "techtree.h"
+#include "shareddefs.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+class CMinimapResourceZonePanel : public CMinimapTracePanel
+{
+ DECLARE_CLASS( CMinimapResourceZonePanel, CMinimapTracePanel );
+
+public:
+ CMinimapResourceZonePanel( vgui::Panel *parent, const char *panelName );
+ virtual ~CMinimapResourceZonePanel();
+
+ virtual bool Init( KeyValues* pKeyValues, MinimapInitData_t* pInitData );
+ virtual void Paint( );
+
+private:
+ BitmapImage *m_ppImage;
+};
+
+DECLARE_MINIMAP_FACTORY( CMinimapResourceZonePanel, "minimap_resource_zone_panel" );
+
+
+CMinimapResourceZonePanel::CMinimapResourceZonePanel( vgui::Panel *parent, const char *panelName )
+: BaseClass( parent, "CMinimapResourceZonePanel" )
+{
+ m_ppImage = NULL;
+}
+
+CMinimapResourceZonePanel::~CMinimapResourceZonePanel()
+{
+ if ( m_ppImage )
+ {
+ delete m_ppImage;
+ m_ppImage = NULL;
+ }
+}
+
+bool CMinimapResourceZonePanel::Init( KeyValues* pKeyValues, MinimapInitData_t* pInitData )
+{
+ // Can only be applied to resource zones...
+ C_ResourceZone* pResource = dynamic_cast<C_ResourceZone*>( pInitData->m_pEntity );
+ if (!pResource)
+ return false;
+
+ if (!BaseClass::Init(pKeyValues, pInitData))
+ return false;
+
+ // Read in the images for the resource zone...
+ // Default to null
+ m_ppImage = NULL;
+
+ char const* pMaterialName = pKeyValues->GetString( "material" );
+ if ( !pMaterialName || !pMaterialName[ 0 ] )
+ return false;
+
+ // modulation color
+ Color color;
+ if (!ParseRGBA( pKeyValues, "color", color ))
+ color.SetColor( 255, 255, 255, 255 );
+
+ // hook in the bitmap
+ m_ppImage = new BitmapImage( GetVPanel(), pMaterialName );
+ m_ppImage->SetColor( color );
+
+ return true;
+}
+
+void CMinimapResourceZonePanel::Paint( )
+{
+ if ( gHUD.IsHidden( HIDEHUD_MISCSTATUS ) )
+ return;
+
+ // Paint the image for the zone type
+ if ( m_ppImage )
+ {
+ m_ppImage->Paint();
+ }
+}
+
+
+
diff --git a/game/client/tf2/minimap_trace.cpp b/game/client/tf2/minimap_trace.cpp
new file mode 100644
index 0000000..c75afa3
--- /dev/null
+++ b/game/client/tf2/minimap_trace.cpp
@@ -0,0 +1,323 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+#include "cbase.h"
+#include "hud.h"
+#include "minimap_trace.h"
+#include "c_basetfplayer.h"
+#include "mapdata.h"
+#include "model_types.h"
+#include "clientmode_tfnormal.h"
+#include <vgui/IVGui.h>
+#include "vgui_bitmapimage.h"
+#include <KeyValues.h>
+#include "VGuiMatSurface/IMatSystemSurface.h"
+#include "shareddefs.h"
+#include "engine/ivmodelinfo.h"
+
+//-----------------------------------------------------------------------------
+// Constructor, destructor
+//-----------------------------------------------------------------------------
+CMinimapTracePanel::CMinimapTracePanel( vgui::Panel *parent, const char *panelName)
+ : BaseClass( parent, "CMinimapTracePanel" )
+{
+ m_pEntity = NULL;
+ SetPaintBackgroundEnabled( false );
+ m_bCanScale = true;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+CMinimapTracePanel::~CMinimapTracePanel()
+{
+}
+
+//-----------------------------------------------------------------------------
+// Initialization
+//-----------------------------------------------------------------------------
+bool CMinimapTracePanel::Init( KeyValues* pKeyValues, MinimapInitData_t* pInitData )
+{
+ // NOTE: Can't use a EHANDLE here because the EHANDLE for pEntity is set up
+ // when AddEntity is called; this gets called before that happens
+ m_pEntity = pInitData->m_pEntity;
+ m_vecPosition = pInitData->m_vecPosition;
+
+ int w, h;
+ if (!ParseCoord(pKeyValues, "offset", m_OffsetX, m_OffsetY))
+ return false;
+
+ if (!ParseCoord(pKeyValues, "size", w, h ))
+ return false;
+
+ // Lifetime of the minimap trace
+ float flLifeTime = pKeyValues->GetFloat("lifetime", -1.0f);
+ if (flLifeTime > 0.0f)
+ m_flDeletionTime = gpGlobals->curtime + flLifeTime;
+ else
+ m_flDeletionTime = -1.0f;
+
+ // Optional parameters
+ m_bVisibleWhenZoomedIn = (pKeyValues->GetInt( "detail", 0 ) == 0 );
+ m_bClampToMap = (pKeyValues->GetInt( "clamp", 0 ) != 0);
+ m_bClipToMap = (pKeyValues->GetInt( "noclip", 0 ) == 0);
+ m_bCanScale = (pKeyValues->GetInt( "noscale", 0 ) == 0);
+ m_bVisible = true;
+
+ m_SizeW = w;
+ m_SizeH = h;
+
+ SetSize( w, h );
+
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+// Entity accessor
+//-----------------------------------------------------------------------------
+C_BaseEntity* CMinimapTracePanel::GetEntity()
+{
+ return m_pEntity;
+}
+
+void CMinimapTracePanel::SetEntity( C_BaseEntity* pEntity )
+{
+ m_pEntity = pEntity;
+}
+
+//-----------------------------------------------------------------------------
+// Sets the position of the trace in world space
+//-----------------------------------------------------------------------------
+void CMinimapTracePanel::SetPosition( const Vector &vecPosition )
+{
+ m_vecPosition = vecPosition;
+}
+
+
+//-----------------------------------------------------------------------------
+// Computes the entity position
+//-----------------------------------------------------------------------------
+bool CMinimapTracePanel::GetEntityPosition( float &x, float &y )
+{
+ C_BaseEntity *pEntity = GetEntity();
+
+ Vector pos;
+ if (!pEntity)
+ {
+ pos = m_vecPosition;
+ }
+ else
+ {
+ if (pEntity == C_BaseTFPlayer::GetLocalPlayer())
+ {
+ // Use the predicted position...
+ pos = pEntity->GetAbsOrigin();
+ }
+ else if ( !pEntity->GetModel() || modelinfo->GetModelType( pEntity->GetModel() ) != mod_brush )
+ {
+ // If it's not a brush model, use the origin
+ pos = pEntity->GetRenderOrigin();
+ }
+ else
+ {
+ Vector mins, maxs;
+ pEntity->GetRenderBounds( mins, maxs );
+ pos = (mins + maxs) * 0.5f;
+ }
+
+ // Position is an offset when there's an entity
+ pos += m_vecPosition;
+ }
+
+ return CMinimapPanel::MinimapPanel()->WorldToMinimap( m_bClampToMap ? MINIMAP_CLIP : MINIMAP_NOCLIP, pos, x, y );
+}
+
+
+//-----------------------------------------------------------------------------
+// Causes the minimap panel to not be visible
+//-----------------------------------------------------------------------------
+void CMinimapTracePanel::SetTraceVisibility( bool bVisible )
+{
+ m_bVisible = bVisible;
+}
+
+
+//-----------------------------------------------------------------------------
+// Call this before rendering to see if the entity should be rendered
+// and to get the rendering position
+//-----------------------------------------------------------------------------
+bool CMinimapTracePanel::ComputeVisibility( )
+{
+ if (!m_bVisible)
+ return false;
+
+ C_BaseEntity* pEntity = GetEntity();
+
+ // No entity? We must be a positional trace
+ if (!pEntity)
+ return true;
+
+ // Don't draw if it's not in the PVS
+ if ( pEntity->IsDormant() )
+ return false;
+
+ // Check visible to tactical
+ if( !MapData().IsEntityVisibleToTactical(pEntity) )
+ return false;
+
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// called when we're ticked...
+//-----------------------------------------------------------------------------
+void CMinimapTracePanel::OnTick()
+{
+ // Don't do anything when not in a game
+ if ( !engine->IsInGame() )
+ {
+ SetVisible( false );
+ return;
+ }
+
+ // Update our current position
+ float sx, sy;
+ bool onMap = GetEntityPosition( sx, sy );
+
+ int ofsx, ofsy;
+ ofsx = m_OffsetX;
+ ofsy = m_OffsetY;
+
+ if ( m_bCanScale )
+ {
+ int w, h;
+ GetSize( w, h );
+
+ float scale = CMinimapPanel::MinimapPanel()->GetTrueZoom();
+ if ( 1 || scale != 1.0f )
+ {
+ ofsx *= scale;
+ ofsy *= scale;
+
+ int sizew = m_SizeW * scale;
+ int sizeh = m_SizeH * scale;
+
+ SetPos( (int)(sx + ofsx + 0.5f), (int)(sy + ofsy + 0.5f));
+ SetSize( sizew, sizeh );
+ }
+ else
+ {
+ SetPos( (int)(sx + ofsx + 0.5f), (int)(sy + ofsy + 0.5f));
+ }
+ }
+ else
+ {
+ SetPos( (int)(sx + ofsx + 0.5f), (int)(sy + ofsy + 0.5f));
+ }
+
+ // Update our visibility
+ if (!onMap)
+ SetVisible( false );
+ else
+ SetVisible( ComputeVisibility( ) );
+
+ if ((m_flDeletionTime >= 0.0f) && (gpGlobals->curtime >= m_flDeletionTime))
+ {
+ MarkForDeletion();
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Computes a panel alpha based on zoom level...
+//-----------------------------------------------------------------------------
+float CMinimapTracePanel::ComputePanelAlpha()
+{
+ if (m_bVisibleWhenZoomedIn)
+ return 1.0f;
+
+ int a;
+ if (!CMinimapPanel::MinimapPanel())
+ return 0.0f;
+
+ if (!CMinimapPanel::MinimapPanel()->ShouldDrawZoomDetails( a ))
+ return 0.0f;
+
+ return a / 255.0f;
+}
+
+
+//-----------------------------------------------------------------------------
+//
+// A standard minimap panel that displays a bitmap
+//
+//-----------------------------------------------------------------------------
+DECLARE_MINIMAP_FACTORY( CMinimapTraceBitmapPanel, "minimap_image_panel" );
+
+
+//-----------------------------------------------------------------------------
+// Sets the bitmap and size
+//-----------------------------------------------------------------------------
+bool CMinimapTraceBitmapPanel::Init( KeyValues* pKeyValues, MinimapInitData_t* pInitData )
+{
+ if (!BaseClass::Init(pKeyValues, pInitData))
+ return false;
+
+ return m_Image.Init( GetVPanel(), pKeyValues );
+}
+
+
+//-----------------------------------------------------------------------------
+// Performs the rendering...
+//-----------------------------------------------------------------------------
+void CMinimapTraceBitmapPanel::Paint( )
+{
+ if ( gHUD.IsHidden( HIDEHUD_MISCSTATUS ) )
+ return;
+
+ if (!m_bClipToMap)
+ g_pMatSystemSurface->DisableClipping( true );
+ m_Image.DoPaint( GetVPanel(), 0, ComputePanelAlpha() );
+ g_pMatSystemSurface->DisableClipping( false );
+}
+
+
+
+//-----------------------------------------------------------------------------
+//
+// A standard minimap renderable that displays a bitmap that changes when team changes
+//
+//-----------------------------------------------------------------------------
+DECLARE_MINIMAP_FACTORY( CMinimapTraceTeamBitmapPanel, "minimap_team_image_panel" );
+
+
+//-----------------------------------------------------------------------------
+// Sets the bitmap and size
+//-----------------------------------------------------------------------------
+bool CMinimapTraceTeamBitmapPanel::Init( KeyValues* pKeyValues, MinimapInitData_t* pInitData )
+{
+ if (!BaseClass::Init(pKeyValues, pInitData))
+ return false;
+
+ return m_TeamImage.Init( this, pKeyValues, pInitData->m_pEntity );
+}
+
+
+//-----------------------------------------------------------------------------
+// Performs the rendering...
+//-----------------------------------------------------------------------------
+void CMinimapTraceTeamBitmapPanel::Paint( )
+{
+ if ( gHUD.IsHidden( HIDEHUD_MISCSTATUS ) )
+ return;
+
+ if (!m_bClipToMap)
+ g_pMatSystemSurface->DisableClipping( true );
+ m_TeamImage.SetAlpha( ComputePanelAlpha() );
+ m_TeamImage.Paint();
+ g_pMatSystemSurface->DisableClipping( false );
+}
diff --git a/game/client/tf2/minimap_trace.h b/game/client/tf2/minimap_trace.h
new file mode 100644
index 0000000..cc644cf
--- /dev/null
+++ b/game/client/tf2/minimap_trace.h
@@ -0,0 +1,153 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef MINIMAP_ENTITY_H
+#define MINIMAP_ENTITY_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+
+#include "hud_minimap.h"
+#include "TeamBitmapImage.h"
+#include "vgui_bitmapimage.h"
+#include <vgui_controls/Panel.h>
+
+
+// FIXME: Need to put the team color somewhere...
+// Get the team color...
+extern int g_TeamColor[3][3];
+
+
+//-----------------------------------------------------------------------------
+// A base minimap panel meant to be attached to an entity.
+// NOTE: paint() will never be called unless the entity is currently valid
+//-----------------------------------------------------------------------------
+class C_BaseEntity;
+
+class CMinimapTracePanel : public vgui::Panel
+{
+ DECLARE_CLASS_GAMEROOT( CMinimapTracePanel, vgui::Panel );
+
+public:
+ CMinimapTracePanel( vgui::Panel *parent, const char *panelName );
+ virtual ~CMinimapTracePanel();
+
+ bool Init( KeyValues* pKeyValues, MinimapInitData_t* pMinimapData );
+
+ // Causes the minimap panel to not be visible
+ void SetTraceVisibility( bool bVisible );
+
+ // called when we're ticked...
+ virtual void OnTick( void );
+
+protected:
+ // Can be overridden; it's called once a frame and returns true if the
+ // object is visible to the minimap or not. X and Y are the position of the
+ // entity in minimap space
+ virtual bool ComputeVisibility( );
+
+ // Computes a panel alpha based on zoom level...
+ float ComputePanelAlpha();
+
+ // Called by derived classes before drawing to determine if the entity is visible.
+ // Also sets the vgui surface color based on the team.
+ bool BeginRender( CMinimapPanel* pPanel, float &x, float &y, int &team ) { return false; }
+
+ // Computes the entity position in minimap panel coordinates
+ bool GetEntityPosition( float &x, float &y );
+
+ // Sets the position of the trace in world space
+ void SetPosition( const Vector &vecPosition );
+
+ // Entity accessors
+ C_BaseEntity* GetEntity();
+ void SetEntity( C_BaseEntity* pEntity );
+
+protected:
+ // Bitmap positional offset
+ int m_OffsetX;
+ int m_OffsetY;
+
+ int m_SizeW;
+ int m_SizeH;
+
+ // Indicates we should clip to the map
+ bool m_bClipToMap;
+
+ bool m_bCanScale;
+
+private:
+ // Indicates if we're faded out when zoomed in
+ bool m_bVisibleWhenZoomedIn;
+
+ // Indicates we should always draw, even if we're off the map
+ bool m_bClampToMap;
+
+ // Are we invisible because the entity wants us invisible?
+ bool m_bVisible;
+
+ // This is the entity to which we're attached
+ C_BaseEntity *m_pEntity;
+
+ // This is the location of the panel in world space
+ Vector m_vecPosition;
+
+ // lifetime of the minimap panel
+ float m_flDeletionTime;
+};
+
+
+//-----------------------------------------------------------------------------
+// A standard minimap panel that displays a bitmap
+//-----------------------------------------------------------------------------
+class CMinimapTraceBitmapPanel : public CMinimapTracePanel
+{
+ DECLARE_CLASS( CMinimapTraceBitmapPanel, CMinimapTracePanel );
+
+public:
+ CMinimapTraceBitmapPanel( vgui::Panel *parent, const char *panelName )
+ : BaseClass ( parent, panelName )
+ {
+ }
+
+ // Sets the bitmap and size
+ virtual bool Init( KeyValues* pKeyValues, MinimapInitData_t* pInitData );
+
+ // Performs the rendering...
+ virtual void Paint();
+
+protected:
+ BitmapImage m_Image;
+};
+
+
+//-----------------------------------------------------------------------------
+// A standard minimap panel that displays a bitmap based on entity team
+//-----------------------------------------------------------------------------
+class CMinimapTraceTeamBitmapPanel : public CMinimapTracePanel
+{
+ DECLARE_CLASS( CMinimapTraceTeamBitmapPanel, CMinimapTracePanel );
+
+public:
+ CMinimapTraceTeamBitmapPanel( vgui::Panel *parent, const char *panelName )
+ : BaseClass ( parent, panelName )
+ {
+ }
+
+ // Sets the bitmap and size
+ virtual bool Init( KeyValues* pKeyValues, MinimapInitData_t* pInitData );
+
+ // Performs the rendering...
+ virtual void Paint();
+
+protected:
+ CTeamBitmapImage m_TeamImage;
+};
+
+
+#endif // MINIMAP_ENTITY_H
diff --git a/game/client/tf2/overlay_orders.cpp b/game/client/tf2/overlay_orders.cpp
new file mode 100644
index 0000000..ff8f830
--- /dev/null
+++ b/game/client/tf2/overlay_orders.cpp
@@ -0,0 +1,25 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $Workfile: $
+// $NoKeywords: $
+//=============================================================================//
+#include "cbase.h"
+#include "vgui_entityimagepanel.h"
+#include "CommanderOverlay.h"
+
+
+
+class COrderStatusPanel : public CEntityImagePanel
+{
+ DECLARE_CLASS( COrderStatusPanel, CEntityImagePanel );
+public:
+ COrderStatusPanel( vgui::Panel *parent, const char *panelName )
+ : BaseClass( parent, "COrderStatusPanel" )
+ {
+ }
+};
+
+
+DECLARE_OVERLAY_FACTORY( COrderStatusPanel, "personal_order" );
diff --git a/game/client/tf2/panel_effects.cpp b/game/client/tf2/panel_effects.cpp
new file mode 100644
index 0000000..505d2d6
--- /dev/null
+++ b/game/client/tf2/panel_effects.cpp
@@ -0,0 +1,1094 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#include "cbase.h"
+#include "hud.h"
+#include "c_tf2rootpanel.h"
+#include "paneleffect.h"
+#include <vgui_controls/Controls.h>
+#include <vgui/ISurface.h>
+
+#define EFFECT_FLASH_TIME 0.7f
+
+#define EFFECT_R 100
+#define EFFECT_G 150
+#define EFFECT_B 220
+#define EFFECT_A 255
+
+#define ARROW_R 130
+#define ARROW_G 190
+#define ARROW_B 240
+#define ARROW_A 255
+
+#define AXIALLINE_R 220
+#define AXIALLINE_G 220
+#define AXIALLINE_B 255
+#define AXIALLINE_A 255
+
+//-----------------------------------------------------------------------------
+// Purpose: Helper for drawing line segments
+//-----------------------------------------------------------------------------
+class CConnectingLine
+{
+public:
+ int m_ptStart[ 2 ];
+ int m_ptEnd[ 2 ];
+};
+
+//-----------------------------------------------------------------------------
+// Purpose: Fill in the intersection between the two rectangles.
+// Input : *pRect1 -
+// *pRect2 -
+// *pOut -
+// Output : inline bool
+//-----------------------------------------------------------------------------
+inline bool GetRectIntersection( wrect_t const *pRect1, wrect_t const *pRect2, wrect_t *pOut )
+{
+ pOut->left = MAX( pRect1->left, pRect2->left );
+ pOut->right = MIN( pRect1->right, pRect2->right );
+ if( pOut->left >= pOut->right )
+ return false;
+
+ pOut->bottom = MIN( pRect1->bottom, pRect2->bottom );
+ pOut->top = MAX( pRect1->top, pRect2->top );
+ if( pOut->top >= pOut->bottom )
+ return false;
+
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Edge to use
+//-----------------------------------------------------------------------------
+typedef enum
+{
+ TOPCENTER = 0,
+ RIGHTCENTER,
+ BOTTOMCENTER,
+ LEFTCENTER
+} LINEEDGE_t;
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : x -
+// y -
+// rect -
+// edge -
+// border -
+//-----------------------------------------------------------------------------
+static void GetCenterPoint( int& x, int& y, const wrect_t& rect, LINEEDGE_t edge, int border )
+{
+ int xcenter;
+ int ycenter;
+
+ xcenter = ( rect.left + rect.right ) / 2;
+ ycenter = ( rect.top + rect.bottom ) / 2;
+
+ switch ( edge )
+ {
+ default:
+ case TOPCENTER:
+ x = xcenter;
+ y = rect.top - border;
+ break;
+ case RIGHTCENTER:
+ x = rect.right + border;
+ y = ycenter;
+ break;
+ case BOTTOMCENTER:
+ x = xcenter;
+ y = rect.bottom + border;
+ break;
+ case LEFTCENTER:
+ x = rect.left - border;
+ y = ycenter;
+ break;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Given two rectangles, finds a direct line between the two rectangles, unless
+// they overlap, in which case no line is output.
+// Input : x1 -
+// y1 -
+// w1 -
+// h1 -
+// x2 -
+// y2 -
+// w2 -
+// h2 -
+// output -
+//-----------------------------------------------------------------------------
+static void FindConnectingLines_Straight(
+ int x1, int y1, int w1, int h1,
+ int x2, int y2, int w2, int h2,
+ CUtlVector< CConnectingLine >& output )
+{
+ // Reset output
+ output.RemoveAll();
+
+ // If the rectangles intersect, no line needed
+ wrect_t r1;
+ r1.left = x1;
+ r1.top = y1;
+ r1.right = x1 + w1;
+ r1.bottom = y1 + h1;
+
+ wrect_t r2;
+ r2.left = x2;
+ r2.top = y2;
+ r2.right = x2 + w2;
+ r2.bottom = y2 + h2;
+
+ wrect_t dummy;
+
+ if ( GetRectIntersection( &r1, &r2, &dummy ) )
+ return;
+
+ int center1[2];
+ int center2[2];
+
+ center1[ 0 ] = x1 + w1/2;
+ center1[ 1 ] = y1 + h1/2;
+
+ center2[ 0 ] = x2 + w2/2;
+ center2[ 1 ] = y2 + h2/2;
+
+ int gaph;
+ int gapv;
+
+ LINEEDGE_t edge1 = TOPCENTER;
+ LINEEDGE_t edge2 = BOTTOMCENTER;
+
+ // Top
+ gaph = MAX( r2.left - r1.right, r1.left - r2.right );
+ gapv = MAX( r1.top - r2.bottom, r2.top - r1.bottom );
+
+ if ( gapv > gaph )
+ {
+ // vertical
+ if ( ( r1.top - r2.bottom ) > ( r2.top - r1.bottom ) )
+ {
+ edge2 = BOTTOMCENTER;
+ edge1 = TOPCENTER;
+ }
+ else
+ {
+ edge2 = TOPCENTER;
+ edge1 = BOTTOMCENTER;
+ }
+ }
+ else
+ {
+ if ( ( r1.left - r2.right ) > ( r2.left - r1.right ) )
+ {
+ // horizontal
+ edge2 = RIGHTCENTER;
+ edge1 = LEFTCENTER;
+ }
+ else
+ {
+ edge2 = LEFTCENTER;
+ edge1 = RIGHTCENTER;
+ }
+ }
+
+ int pt1[ 2 ];
+ int pt2[ 2 ];
+
+ GetCenterPoint( pt1[ 0 ], pt1[ 1 ], r1, edge1, 3 );
+ GetCenterPoint( pt2[ 0 ], pt2[ 1 ], r2, edge2, 3 );
+
+ CConnectingLine line;
+ line.m_ptStart[ 0 ] = pt1[ 0 ];
+ line.m_ptStart[ 1 ] = pt1[ 1 ];
+ line.m_ptEnd[ 0 ] = pt2[ 0 ];
+ line.m_ptEnd[ 1 ] = pt2[ 1 ];
+
+ output.AddToTail( line );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Given two non-intersecting rectangles, finds one, two or three segments
+// which connect the midpoints of two of the sides of the items together with only
+// axial lines.
+// Input : x1 -
+// y1 -
+// w1 -
+// h1 -
+// x2 -
+// y2 -
+// w2 -
+// h2 -
+// output -
+//-----------------------------------------------------------------------------
+static void FindConnectingLines_Axial(
+ int x1, int y1, int w1, int h1,
+ int x2, int y2, int w2, int h2,
+ CUtlVector< CConnectingLine >& output )
+{
+ // Reset output
+ output.RemoveAll();
+
+ // If the rectangles intersect, no line needed
+ wrect_t r1;
+ r1.left = x1;
+ r1.top = y1;
+ r1.right = x1 + w1;
+ r1.bottom = y1 + h1;
+
+ wrect_t r2;
+ r2.left = x2;
+ r2.top = y2;
+ r2.right = x2 + w2;
+ r2.bottom = y2 + h2;
+ wrect_t dummy;
+
+ if ( GetRectIntersection( &r1, &r2, &dummy ) )
+ return;
+
+ int center1[2];
+ int center2[2];
+
+ center1[ 0 ] = x1 + w1/2;
+ center1[ 1 ] = y1 + h1/2;
+
+ center2[ 0 ] = x2 + w2/2;
+ center2[ 1 ] = y2 + h2/2;
+
+ int gaph;
+ int gapv;
+
+ LINEEDGE_t edge1 = TOPCENTER;
+ LINEEDGE_t edge2 = BOTTOMCENTER;
+
+ // Top
+ gaph = MAX( r2.left - r1.right, r1.left - r2.right );
+ gapv = MAX( r1.top - r2.bottom, r2.top - r1.bottom );
+
+ if ( gapv > gaph )
+ {
+ // vertical
+ if ( ( r1.top - r2.bottom ) > ( r2.top - r1.bottom ) )
+ {
+ edge2 = BOTTOMCENTER;
+ edge1 = TOPCENTER;
+ }
+ else
+ {
+ edge2 = TOPCENTER;
+ edge1 = BOTTOMCENTER;
+ }
+ }
+ else
+ {
+ if ( ( r1.left - r2.right ) > ( r2.left - r1.right ) )
+ {
+ // horizontal
+ edge2 = RIGHTCENTER;
+ edge1 = LEFTCENTER;
+ }
+ else
+ {
+ edge2 = LEFTCENTER;
+ edge1 = RIGHTCENTER;
+ }
+ }
+
+ int pt1[ 2 ];
+ int pt2[ 2 ];
+
+ GetCenterPoint( pt1[ 0 ], pt1[ 1 ], r1, edge1, 3 );
+ GetCenterPoint( pt2[ 0 ], pt2[ 1 ], r2, edge2, 3 );
+
+ CConnectingLine line;
+
+ int mid[ 2 ];
+ int size1[ 2 ];
+ int size2[ 2 ];
+
+ mid[ 0 ] = ( pt1[ 0 ] + pt2[ 0 ] ) / 2;
+ mid[ 1 ] = ( pt1[ 1 ] + pt2[ 1 ] ) / 2;
+
+ size1[ 0 ] = r1.right - r1.left;
+ size1[ 1 ] = r1.bottom - r1.top;
+
+ size2[ 0 ] = r2.right - r2.left;
+ size2[ 1 ] = r2.bottom - r2.top;
+
+ float sizefrac = 0.25f;
+
+ if ( edge1 == TOPCENTER || edge1 == BOTTOMCENTER )
+ {
+ int dx = abs( mid[ 0 ] - pt1[ 0 ] );
+ if ( dx < ( sizefrac * size1[ 0 ] ) &&
+ dx < ( sizefrac * size2[ 0 ] ) )
+ {
+ // Gap is small, just use midpoint to align both
+ line.m_ptStart[ 0 ] = mid[ 0 ];
+ line.m_ptStart[ 1 ] = pt1[ 1 ];
+ line.m_ptEnd[ 0 ] = mid[ 0 ];
+ line.m_ptEnd[ 1 ] = pt2[ 1 ];
+
+ output.AddToTail( line );
+ }
+ else
+ {
+ // Draw an L
+ line.m_ptStart[ 0 ] = pt1[ 0 ];
+ line.m_ptStart[ 1 ] = pt1[ 1 ];
+ line.m_ptEnd[ 0 ] = pt1[ 0 ];
+ line.m_ptEnd[ 1 ] = mid[ 1 ];
+
+ output.AddToTail( line );
+
+ line.m_ptStart[ 0 ] = pt1[ 0 ];
+ line.m_ptStart[ 1 ] = mid[ 1 ];
+ line.m_ptEnd[ 0 ] = pt2[ 0 ];
+ line.m_ptEnd[ 1 ] = mid[ 1 ];
+
+ output.AddToTail( line );
+
+ line.m_ptStart[ 0 ] = pt2[ 0 ];
+ line.m_ptStart[ 1 ] = mid[ 1 ];
+ line.m_ptEnd[ 0 ] = pt2[ 0 ];
+ line.m_ptEnd[ 1 ] = pt2[ 1 ];
+
+ output.AddToTail( line );
+ }
+ }
+ else
+ {
+ int dy = abs( mid[ 1 ] - pt1[ 1 ] );
+ if ( dy < ( sizefrac * size1[ 1] ) &&
+ dy < ( sizefrac * size2[ 1 ] ) )
+ {
+ // Gap is small, just use midpoint to align both
+ line.m_ptStart[ 0 ] = pt1[ 0 ];
+ line.m_ptStart[ 1 ] = mid[ 1 ];
+ line.m_ptEnd[ 0 ] = pt2[ 0 ];
+ line.m_ptEnd[ 1 ] = mid[ 1 ];
+
+ output.AddToTail( line );
+ }
+ else
+ {
+ // Draw an L
+ line.m_ptStart[ 0 ] = pt1[ 0 ];
+ line.m_ptStart[ 1 ] = pt1[ 1 ];
+ line.m_ptEnd[ 0 ] = mid[ 0 ];
+ line.m_ptEnd[ 1 ] = pt1[ 1 ];
+
+ output.AddToTail( line );
+
+ line.m_ptStart[ 0 ] = mid[ 0 ];
+ line.m_ptStart[ 1 ] = pt1[ 1 ];
+ line.m_ptEnd[ 0 ] = mid[ 0 ];
+ line.m_ptEnd[ 1 ] = pt2[ 1 ];
+
+ output.AddToTail( line );
+
+ line.m_ptStart[ 0 ] = mid[ 0 ];
+ line.m_ptStart[ 1 ] = pt2[ 1 ];
+ line.m_ptEnd[ 0 ] = pt2[ 0 ];
+ line.m_ptEnd[ 1 ] = pt2[ 1 ];
+
+ output.AddToTail( line );
+ }
+ }
+
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Map input panel rectangle into space of output panel and return extents in xywh
+// Input : x -
+// y -
+// w -
+// h -
+// *output -
+// *input -
+//-----------------------------------------------------------------------------
+void PanelToPanelRectangle( int& x, int& y, int& w, int& h, vgui::Panel *output, vgui::Panel *input )
+{
+ input->GetSize( w, h );
+ w += 2;
+ h += 2;
+
+ x = y = 0;
+ input->LocalToScreen( x, y );
+ output->ScreenToLocal( x, y );
+
+ x--;
+ y--;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Cycle between in/2 and in centered at 3/4in
+// Input : in -
+// f - ranges from -1 to 1
+// Output : static int
+//-----------------------------------------------------------------------------
+static int EffectResampleColor( int in, float f )
+{
+ int base = in / 2;
+ int midpoint = ( in + base ) / 2;
+ float range = (float)( in - midpoint );
+
+ int color = midpoint + (int)( f * range );
+ return clamp( color, 0, 255 );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Border flashing effect
+//-----------------------------------------------------------------------------
+class CFlashBorderPanelEffect : public CPanelEffect
+{
+ DECLARE_CLASS( CFlashBorderPanelEffect, CPanelEffect );
+public:
+
+ CFlashBorderPanelEffect( ITFHintItem *owner );
+ virtual void doPaint( vgui::Panel *panel );
+};
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *owner -
+//-----------------------------------------------------------------------------
+CFlashBorderPanelEffect::CFlashBorderPanelEffect( ITFHintItem *owner )
+ : CPanelEffect( owner )
+{
+ // Mark type field
+ SetType( FLASHBORDER );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Paint the effect
+// Input : *panel -
+//-----------------------------------------------------------------------------
+void CFlashBorderPanelEffect::doPaint( vgui::Panel *panel )
+{
+ vgui::Panel *p = m_hPanel;
+ if ( !p || !IsVisibleIncludingParent( p ) )
+ return;
+
+ int w, h;
+ p->GetSize( w, h );
+
+ // Convert top,left to local coordinates
+ int x = 0, y = 0;
+ p->LocalToScreen( x, y );
+ panel->ScreenToLocal( x, y );
+
+ x--;
+ y--;
+ w+=2;
+ h+=2;
+
+ float frac = fmod( gpGlobals->curtime, EFFECT_FLASH_TIME );
+ frac *= 2 * M_PI;
+ frac = cos( frac );
+
+ int r, g, b;
+
+ r = EffectResampleColor( m_r, frac );
+ g = EffectResampleColor( m_g, frac );
+ b = EffectResampleColor( m_b, frac );
+
+ vgui::surface()->DrawSetColor( r, g, b, m_a );
+
+ for ( int gap = 0; gap < 3; gap++ )
+ {
+ vgui::surface()->DrawOutlinedRect( x - gap, y - gap, x + w + gap, y + h + gap );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Creates an arry from m_hPanel to m_hOtherPanel
+//-----------------------------------------------------------------------------
+class CArrowPanelEffect : public CPanelEffect
+{
+ DECLARE_CLASS( CArrowPanelEffect, CPanelEffect );
+public:
+
+ CArrowPanelEffect( ITFHintItem *owner );
+
+ virtual void doPaint( vgui::Panel *panel );
+
+ void SetDrawBorder( bool drawborder );
+ void SetFlashing( bool flashing );
+
+protected:
+ void DrawArrow( int startx, int starty, int endx, int endy, int r, int g, int b, int a );
+ void DrawLine( int startx, int starty, int endx, int endy, int r, int g, int b, int a );
+ void ComputeBestPoint( int& px, int &py, vgui::Panel *output, vgui::Panel *from, vgui::Panel *to );
+
+protected:
+
+ bool m_bDrawBorder;
+ bool m_bFlashing;
+};
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *owner -
+//-----------------------------------------------------------------------------
+CArrowPanelEffect::CArrowPanelEffect( ITFHintItem *owner )
+ : CPanelEffect( owner )
+{
+ SetType( ARROW );
+
+ m_bDrawBorder = true;
+ m_bFlashing = true;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : drawborder -
+//-----------------------------------------------------------------------------
+void CArrowPanelEffect::SetDrawBorder( bool drawborder )
+{
+ m_bDrawBorder = drawborder;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : flashing -
+//-----------------------------------------------------------------------------
+void CArrowPanelEffect::SetFlashing( bool flashing )
+{
+ m_bFlashing = flashing;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : startx -
+// starty -
+// endx -
+// endy -
+// r -
+// g -
+// b -
+// a -
+//-----------------------------------------------------------------------------
+void CArrowPanelEffect::DrawArrow( int startx, int starty, int endx, int endy, int r, int g, int b, int a )
+{
+ vgui::surface()->DrawSetColor( r, g, b, a );
+
+ // Draw an arrow
+
+ Vector start( startx, starty, 0.0f );
+ Vector end( endx, endy, 0.0f );
+
+ Vector delta = end - start;
+
+ Vector right;
+
+ right.x = delta.y;
+ right.y = -delta.x;
+ right.z = 0.0f;
+
+ VectorNormalize( right );
+ Vector base;
+
+ float length = VectorNormalize( delta );
+
+ float size = MIN( length / 2.0f, 15.0f );
+
+ base = start + ( length - size ) * delta;
+
+ Vector baseLeft = base + size * 0.25f * right;
+ Vector baseRight = base - size * 0.25f * right;
+
+ vgui::surface()->DrawLine( end.x, end.y, baseLeft.x, baseLeft.y );
+ vgui::surface()->DrawLine( end.x, end.y, baseRight.x, baseRight.y );
+
+ base = start + ( length - size + size * 0.3f ) * delta;
+
+ vgui::surface()->DrawLine( base.x, base.y, baseLeft.x, baseLeft.y );
+ vgui::surface()->DrawLine( base.x, base.y, baseRight.x, baseRight.y );
+
+ vgui::surface()->DrawLine( startx, starty, base.x, base.y );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : startx -
+// starty -
+// endx -
+// endy -
+// r -
+// g -
+// b -
+// a -
+//-----------------------------------------------------------------------------
+void CArrowPanelEffect::DrawLine( int startx, int starty, int endx, int endy, int r, int g, int b, int a )
+{
+ vgui::surface()->DrawSetColor( r, g, b, a );
+ vgui::surface()->DrawLine( startx, starty, endx, endy );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *panel -
+//-----------------------------------------------------------------------------
+void CArrowPanelEffect::doPaint( vgui::Panel *panel )
+{
+ vgui::Panel *from = m_hPanel;
+ if ( !from || !IsVisibleIncludingParent( from ) )
+ return;
+
+ int r, g, b;
+ // Determine flash amount
+ if ( m_bFlashing )
+ {
+ float frac = fmod( gpGlobals->curtime, EFFECT_FLASH_TIME );
+ frac *= 2 * M_PI;
+ frac = cos( frac );
+
+ // Resample color
+
+ r = EffectResampleColor( m_r, frac );
+ g = EffectResampleColor( m_g, frac );
+ b = EffectResampleColor( m_b, frac );
+ }
+ else
+ {
+ r = m_r;
+ g = m_g;
+ b = m_b;
+ }
+
+ int startx, starty, startw, starth;
+ int endx, endy, endw, endh;
+
+ PanelToPanelRectangle( startx, starty, startw, starth, panel, from );
+
+ if ( !GetTargetRectangle( panel, endx, endy, endw, endh ) )
+ return;
+
+ CUtlVector< CConnectingLine > lines;
+
+ FindConnectingLines_Straight( startx, starty, startw, starth, endx, endy, endw, endh, lines );
+
+ int i;
+
+ if ( m_bDrawBorder )
+ {
+ for ( i = 0; i < lines.Size(); i++ )
+ {
+ CConnectingLine *l = &lines[ i ];
+
+ // Make it thicker
+ int hstep = 0;
+ int vstep = 0;
+
+ if ( abs( l->m_ptEnd[ 1 ] - l->m_ptStart[ 1 ] ) > abs( l->m_ptEnd[ 0 ] - l->m_ptStart[ 0 ] ) )
+ {
+ // Taller so draw horizontally
+ hstep = 1;
+ }
+ else
+ {
+ vstep = 1;
+ }
+
+ // Draw a black border
+ for ( int x = -1; x <= 1 + hstep; x ++ )
+ {
+ for ( int y = -1; y <= 1 + vstep; y ++ )
+ {
+ if ( !x && !y )
+ continue;
+
+ if ( i == lines.Size() - 1 )
+ {
+ DrawArrow( l->m_ptStart[ 0 ] + x, l->m_ptStart[1] + y, l->m_ptEnd[0] + x, l->m_ptEnd[1] + y, 0, 0, 0, m_a );
+ }
+ else
+ {
+ DrawLine( l->m_ptStart[ 0 ] + x, l->m_ptStart[1] + y, l->m_ptEnd[0] + x, l->m_ptEnd[1] + y, 0, 0, 0, m_a );
+ }
+ }
+ }
+ }
+ }
+
+ for ( i = 0; i < lines.Size(); i++ )
+ {
+ CConnectingLine *l = &lines[ i ];
+
+ // Make it thicker
+ int hstep = 0;
+ int vstep = 0;
+
+ if ( abs( l->m_ptEnd[ 1 ] - l->m_ptStart[ 1 ] ) > abs( l->m_ptEnd[ 0 ] - l->m_ptStart[ 0 ] ) )
+ {
+ // Taller so draw horizontally
+ hstep = 1;
+ }
+ else
+ {
+ vstep = 1;
+ }
+
+ if ( i == lines.Size() - 1 )
+ {
+ // Draw arrow
+ DrawArrow( l->m_ptStart[ 0 ], l->m_ptStart[ 1 ], l->m_ptEnd[ 0 ], l->m_ptEnd[ 1 ], r, g, b, m_a );
+ // Draw a second time, but thicker
+ DrawArrow( l->m_ptStart[ 0 ] + hstep, l->m_ptStart[ 1 ] + vstep, l->m_ptEnd[ 0 ] + hstep, l->m_ptEnd[ 1 ] + vstep, r, g, b, m_a );
+ }
+ else
+ {
+ // Draw arrow
+ DrawLine( l->m_ptStart[ 0 ], l->m_ptStart[ 1 ], l->m_ptEnd[ 0 ], l->m_ptEnd[ 1 ], r, g, b, m_a );
+ // Draw a second time, but thicker
+ DrawLine( l->m_ptStart[ 0 ] + hstep, l->m_ptStart[ 1 ] + vstep, l->m_ptEnd[ 0 ] + hstep, l->m_ptEnd[ 1 ] + vstep, r, g, b, m_a );
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : px -
+// &py -
+// *output -
+// *from -
+// *to -
+//-----------------------------------------------------------------------------
+void CArrowPanelEffect::ComputeBestPoint( int& px, int &py, vgui::Panel *output, vgui::Panel *from, vgui::Panel *to )
+{
+ int fw, fh;
+ int tw, th;
+ from->GetSize( fw, fh );
+ to->GetSize( tw, th );
+
+ // Convert top,left to local coordinates
+ int fx = 0, fy = 0;
+ int tx = 0, ty = 0;
+ from->LocalToScreen( fx, fy );
+ output->ScreenToLocal( fx, fy );
+
+ to->LocalToScreen( tx, ty );
+ output->ScreenToLocal( tx, ty );
+
+ fx--;
+ fy--;
+ tx--;
+ ty--;
+ fw+=2;
+ fh+=2;
+ tw+=2;
+ th+=2;
+
+ int type = 0;
+
+ // is to totally below from
+ if ( ty > ( fy + fh ) )
+ {
+ type = 0;
+ }
+ // is to totally above from
+ else if ( ty + th < fy )
+ {
+ type = 2;
+ }
+ // is to totally to the left of from
+ else if ( tx + tw < fx )
+ {
+ type = 3;
+ }
+ // is to totally to the rigth of from
+ else if ( tx > fx + fw )
+ {
+ type = 1;
+ }
+ else
+ {
+ type = 2;
+ }
+
+ int border = 1;
+
+ switch ( type )
+ {
+ // unknown, just use object center point
+ default:
+ case 4:
+ //
+ px = fx + fw / 2;
+ py = fy + fh / 2;
+ break;
+ //bottom
+ case 0:
+ px = fx + fw / 2;
+ py = fy + fh + border;
+ break;
+ // right
+ case 1:
+ px = fx + fw + border;
+ py = fy + fh / 2;
+ break;
+ // top
+ case 2:
+ px = fx + fw / 2;
+ py = fy - border;
+ break;
+ // left
+ case 3:
+ px = fx - border;
+ py = fy + fh / 2;
+ break;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Creates an axial line effect between the two specified panels
+//-----------------------------------------------------------------------------
+class CAxialLinePanelEffect : public CArrowPanelEffect
+{
+DECLARE_CLASS( CAxialLinePanelEffect, CArrowPanelEffect );
+public:
+ CAxialLinePanelEffect( ITFHintItem *owner );
+
+ virtual void doPaint( vgui::Panel *panel );
+};
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *owner -
+//-----------------------------------------------------------------------------
+CAxialLinePanelEffect::CAxialLinePanelEffect( ITFHintItem *owner )
+: CArrowPanelEffect( owner )
+{
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *panel -
+//-----------------------------------------------------------------------------
+void CAxialLinePanelEffect::doPaint( vgui::Panel *panel )
+{
+ vgui::Panel *from = m_hPanel;
+ if ( !from || !IsVisibleIncludingParent( from ) )
+ return;
+
+ int r, g, b;
+
+ if ( m_bFlashing )
+ {
+ // Determine flash amount
+ float frac = fmod( gpGlobals->curtime, EFFECT_FLASH_TIME );
+ frac *= 2 * M_PI;
+ frac = cos( frac );
+
+ // Resample color
+ r = EffectResampleColor( m_r, frac );
+ g = EffectResampleColor( m_g, frac );
+ b = EffectResampleColor( m_b, frac );
+ }
+ else
+ {
+ r = m_r;
+ g = m_g;
+ b = m_b;
+ }
+
+ int startx, starty, startw, starth;
+ int endx, endy, endw, endh;
+
+ PanelToPanelRectangle( startx, starty, startw, starth, panel, from );
+
+ if ( !GetTargetRectangle( panel, endx, endy, endw, endh ) )
+ return;
+
+ CUtlVector< CConnectingLine > lines;
+
+ FindConnectingLines_Axial( startx, starty, startw, starth, endx, endy, endw, endh, lines );
+
+ int i;
+
+ if ( m_bDrawBorder )
+ {
+ for ( i = 0; i < lines.Size(); i++ )
+ {
+ CConnectingLine *l = &lines[ i ];
+
+ // Draw a black border
+ for ( int x = -1; x <= 1; x ++ )
+ {
+ for ( int y = -1; y <= 1; y ++ )
+ {
+ if ( !x && !y )
+ continue;
+
+ DrawLine( l->m_ptStart[ 0 ] + x, l->m_ptStart[1] + y, l->m_ptEnd[0] + x, l->m_ptEnd[1] + y, 0, 0, 0, m_a );
+ }
+ }
+ }
+ }
+
+ // Draw actual lines
+ for ( i = 0; i < lines.Size(); i++ )
+ {
+ CConnectingLine *l = &lines[ i ];
+ DrawLine( l->m_ptStart[ 0 ], l->m_ptStart[ 1 ], l->m_ptEnd[ 0 ], l->m_ptEnd[ 1 ], r, g, b, m_a );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *owner -
+// *target -
+// Output : EFFECT_HANDLE
+//-----------------------------------------------------------------------------
+EFFECT_HANDLE CreateFlashEffect( ITFHintItem *owner, vgui::Panel *target )
+{
+ if ( !g_pTF2RootPanel )
+ return EFFECT_INVALID_HANDLE;
+
+ CFlashBorderPanelEffect *e = new CFlashBorderPanelEffect( owner );
+
+ e->SetColor( EFFECT_R, EFFECT_G, EFFECT_B, EFFECT_A );
+ // e->SetEndTime( gpGlobals->curtime + 15.0f );
+ e->SetPanel( target );
+
+ g_pTF2RootPanel->AddEffect( e );
+
+ return e->GetHandle();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *owner -
+// *from -
+// *to -
+// Output : EFFECT_HANDLE
+//-----------------------------------------------------------------------------
+EFFECT_HANDLE CreateArrowEffect( ITFHintItem *owner, vgui::Panel *from, vgui::Panel *to )
+{
+ if ( !g_pTF2RootPanel )
+ return EFFECT_INVALID_HANDLE;
+
+ CArrowPanelEffect *e = new CArrowPanelEffect( owner );
+
+ e->SetColor( ARROW_R, ARROW_G, ARROW_B, ARROW_A );
+ e->SetPanel( from );
+ e->SetPanelOther( to );
+
+ g_pTF2RootPanel->AddEffect( e );
+
+ return e->GetHandle();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *owner -
+// *from -
+// *to -
+// Output : EFFECT_HANDLE
+//-----------------------------------------------------------------------------
+EFFECT_HANDLE CreateAxialLineEffect( ITFHintItem *owner, vgui::Panel *from, vgui::Panel *to )
+{
+ if ( !g_pTF2RootPanel )
+ return EFFECT_INVALID_HANDLE;
+
+ CAxialLinePanelEffect *e = new CAxialLinePanelEffect( owner );
+
+ e->SetColor( AXIALLINE_R, AXIALLINE_G, AXIALLINE_B, AXIALLINE_A );
+ e->SetPanel( from );
+ e->SetPanelOther( to );
+
+ e->SetFlashing( false );
+ e->SetDrawBorder( false );
+
+ g_pTF2RootPanel->AddEffect( e );
+
+ return e->GetHandle();
+}
+
+EFFECT_HANDLE CreateArrowEffectToPoint( ITFHintItem *owner, vgui::Panel *from, int x, int y )
+{
+ if ( !g_pTF2RootPanel )
+ return EFFECT_INVALID_HANDLE;
+
+ CArrowPanelEffect *e = new CArrowPanelEffect( owner );
+
+ e->SetColor( ARROW_R, ARROW_G, ARROW_B, ARROW_A );
+ e->SetPanel( from );
+ e->SetTargetPoint( x, y );
+
+ g_pTF2RootPanel->AddEffect( e );
+
+ return e->GetHandle();
+}
+
+EFFECT_HANDLE CreateAxialLineEffectToPoint( ITFHintItem *owner, vgui::Panel *from, int x, int y )
+{
+ if ( !g_pTF2RootPanel )
+ return EFFECT_INVALID_HANDLE;
+
+ CAxialLinePanelEffect *e = new CAxialLinePanelEffect( owner );
+
+ e->SetColor( AXIALLINE_R, AXIALLINE_G, AXIALLINE_B, AXIALLINE_A );
+ e->SetPanel( from );
+ e->SetTargetPoint( x, y );
+
+ e->SetFlashing( false );
+ e->SetDrawBorder( false );
+
+ g_pTF2RootPanel->AddEffect( e );
+
+ return e->GetHandle();
+}
+
+EFFECT_HANDLE CreateArrowEffectToRect( ITFHintItem *owner, vgui::Panel *from, int x, int y, int w, int h )
+{
+ if ( !g_pTF2RootPanel )
+ return EFFECT_INVALID_HANDLE;
+
+ CArrowPanelEffect *e = new CArrowPanelEffect( owner );
+
+ e->SetColor( ARROW_R, ARROW_G, ARROW_B, ARROW_A );
+ e->SetPanel( from );
+ e->SetTargetRect( x, y, w, h );
+
+ g_pTF2RootPanel->AddEffect( e );
+
+ return e->GetHandle();
+}
+
+EFFECT_HANDLE CreateAxialLineEffectToRect( ITFHintItem *owner, vgui::Panel *from, int x, int y, int w, int h )
+{
+ if ( !g_pTF2RootPanel )
+ return EFFECT_INVALID_HANDLE;
+
+ CAxialLinePanelEffect *e = new CAxialLinePanelEffect( owner );
+
+ e->SetColor( AXIALLINE_R, AXIALLINE_G, AXIALLINE_B, AXIALLINE_A );
+ e->SetPanel( from );
+ e->SetTargetRect( x, y, w, h );
+
+ e->SetFlashing( false );
+ e->SetDrawBorder( false );
+
+ g_pTF2RootPanel->AddEffect( e );
+
+ return e->GetHandle();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *owner -
+//-----------------------------------------------------------------------------
+void DestroyPanelEffects( ITFHintItem *owner )
+{
+ if ( !g_pTF2RootPanel )
+ return;
+
+ g_pTF2RootPanel->DestroyPanelEffects( owner );
+} \ No newline at end of file
diff --git a/game/client/tf2/paneleffect.cpp b/game/client/tf2/paneleffect.cpp
new file mode 100644
index 0000000..8db00b1
--- /dev/null
+++ b/game/client/tf2/paneleffect.cpp
@@ -0,0 +1,414 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#include "cbase.h"
+#include "PanelEffect.h"
+#include "vgui_int.h"
+#include <vgui_controls/Panel.h>
+#include <vgui/IPanel.h>
+
+void PanelToPanelRectangle( int& x, int& y, int& w, int& h, vgui::Panel *output, vgui::Panel *input );
+
+// Global panel counter for effects
+EFFECT_HANDLE CPanelEffect::m_nHandleCount = 0;
+
+//-----------------------------------------------------------------------------
+// Purpose: Base panel effect
+// Input : *owner -
+//-----------------------------------------------------------------------------
+CPanelEffect::CPanelEffect( ITFHintItem *owner )
+ : m_pOwner( owner )
+{
+ // Assign it a unique handle index
+ m_Handle = ++m_nHandleCount;
+
+ SetType( UNKNOWN );
+ SetPanel( NULL );
+ SetPanelOther( NULL );
+ SetColor( 0, 0, 0, 255 );
+ SetEndTime( 0.0f );
+ SetShouldRemove( false );
+ SetUsingOffset( false, 0, 0 );
+ SetTargetType( ENDPOINT_UNKNOWN );
+ SetVisible( true );
+
+ m_ptX = 0;
+ m_ptY = 0;
+ m_rectX = 0;
+ m_rectY = 0;
+ m_rectW = 0;
+ m_rectH = 0;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+CPanelEffect::~CPanelEffect()
+{
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *owner -
+//-----------------------------------------------------------------------------
+void CPanelEffect::SetOwner( ITFHintItem *owner )
+{
+ m_pOwner = owner;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Output : ITFHintItem
+//-----------------------------------------------------------------------------
+ITFHintItem *CPanelEffect::GetOwner( void )
+{
+ return m_pOwner;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Output : EFFECT_HANDLE
+//-----------------------------------------------------------------------------
+EFFECT_HANDLE CPanelEffect::GetHandle( void )
+{
+ return m_Handle;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Override for specific painting effects
+// Input : *panel -
+//-----------------------------------------------------------------------------
+void CPanelEffect::doPaint( vgui::Panel *panel )
+{
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Default think checks for panels that have a specific lifetime
+//-----------------------------------------------------------------------------
+void CPanelEffect::Think( void )
+{
+ if ( !m_flEndTime )
+ return;
+
+ if ( gpGlobals->curtime > m_flEndTime )
+ {
+ SetShouldRemove( true );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Output : Returns true on success, false on failure.
+//-----------------------------------------------------------------------------
+bool CPanelEffect::ShouldRemove( void )
+{
+ return m_bShouldRemove;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : remove -
+//-----------------------------------------------------------------------------
+void CPanelEffect::SetShouldRemove( bool remove )
+{
+ m_bShouldRemove = remove;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : type -
+//-----------------------------------------------------------------------------
+void CPanelEffect::SetType( int type )
+{
+ m_nType = type;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Output : int
+//-----------------------------------------------------------------------------
+int CPanelEffect::GetType( void )
+{
+ return m_nType;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *panel -
+//-----------------------------------------------------------------------------
+void CPanelEffect::SetPanel( vgui::Panel *panel )
+{
+ m_hPanel = panel;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Output : vgui::Panel
+//-----------------------------------------------------------------------------
+vgui::Panel *CPanelEffect::GetPanel( void )
+{
+ return m_hPanel;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *panel -
+//-----------------------------------------------------------------------------
+void CPanelEffect::SetPanelOther( vgui::Panel *panel )
+{
+ SetTargetType( ENDPOINT_PANEL );
+ m_hOtherPanel = panel;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Output : vgui::Panel
+//-----------------------------------------------------------------------------
+vgui::Panel *CPanelEffect::GetPanelOther( void )
+{
+ return m_hOtherPanel;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : r -
+// g -
+// b -
+// a -
+//-----------------------------------------------------------------------------
+void CPanelEffect::SetColor( int r, int g, int b, int a )
+{
+ m_r = r;
+ m_g = g;
+ m_b = b;
+ m_a = a;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : r -
+// g -
+// b -
+// a -
+//-----------------------------------------------------------------------------
+void CPanelEffect::GetColor( int& r, int& g, int& b, int& a )
+{
+ r = m_r;
+ g = m_g;
+ b = m_b;
+ a = m_a;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : time -
+//-----------------------------------------------------------------------------
+void CPanelEffect::SetEndTime( float time )
+{
+ m_flEndTime = time;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Output : float
+//-----------------------------------------------------------------------------
+float CPanelEffect::GetEndTime( void )
+{
+ return m_flEndTime;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : active -
+// x -
+// y -
+//-----------------------------------------------------------------------------
+void CPanelEffect::SetUsingOffset( bool active, int x, int y )
+{
+ m_bEndpointIsCoordinate = active;
+ m_nOffset[ 0 ] = x;
+ m_nOffset[ 1 ] = y;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Output : Returns true on success, false on failure.
+//-----------------------------------------------------------------------------
+bool CPanelEffect::GetUsingOffset( void )
+{
+ return m_bEndpointIsCoordinate;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : x -
+// y -
+//-----------------------------------------------------------------------------
+void CPanelEffect::GetOffset( int& x, int& y )
+{
+ x = m_nOffset[ 0 ];
+ y = m_nOffset[ 1 ];
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Returns false if the panel is not visible or is the child of a not visible
+// parent
+// assumes panel hierarchy stops at the client .dll root panel
+// If parent is some other panel, then this will return false
+// Input : *panel -
+// Output : Returns true on success, false on failure.
+//-----------------------------------------------------------------------------
+bool CPanelEffect::IsVisibleIncludingParent( vgui::Panel *panel )
+{
+ vgui::VPANEL p = panel->GetVPanel();
+ while ( p )
+ {
+ if ( !vgui::ipanel()->IsVisible(p) )
+ return false;
+
+ if ( p == VGui_GetClientDLLRootPanel() )
+ {
+ return true;
+ }
+
+ p = vgui::ipanel()->GetParent(p);
+ }
+
+ return false;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Output : int
+//-----------------------------------------------------------------------------
+int CPanelEffect::GetTargetType( void )
+{
+ return m_TargetType;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : type -
+//-----------------------------------------------------------------------------
+void CPanelEffect::SetTargetType( int type )
+{
+ m_TargetType = type;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *outpanel -
+// int&x -
+// int&y -
+// int&w -
+// int&h -
+// Output : Returns true on success, false on failure.
+//-----------------------------------------------------------------------------
+bool CPanelEffect::GetTargetRectangle( vgui::Panel *outpanel, int&x, int&y, int&w, int&h )
+{
+ x = y = 0;
+ w = h = 1;
+
+ switch ( m_TargetType )
+ {
+ default:
+ return false;
+ break;
+ case ENDPOINT_PANEL:
+ {
+ vgui::Panel *to = m_hOtherPanel;
+ if ( !to )
+ return false;
+
+ if ( !IsVisibleIncludingParent( to ) )
+ {
+ return false;
+ }
+
+ PanelToPanelRectangle( x, y, w, h, outpanel, to );
+
+ // Using an offset into a panel
+ if ( GetUsingOffset() )
+ {
+ int ofsx, ofsy;
+
+ GetOffset( ofsx, ofsy );
+
+ x = x + ofsx-3;
+ w = 6;
+ y = y + ofsy-3;
+ h = 6;
+ }
+ }
+ break;
+ case ENDPOINT_RECTANGLE:
+ {
+ x = m_rectX;
+ y = m_rectY;
+ w = m_rectW;
+ h = m_rectH;
+ }
+ break;
+ case ENDPOINT_POINT:
+ {
+ x = m_ptX;
+ y = m_ptY;
+ w = 1;
+ h = 1;
+ }
+ break;
+ }
+
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : x -
+// y -
+//-----------------------------------------------------------------------------
+void CPanelEffect::SetTargetPoint( int x, int y )
+{
+ SetTargetType( ENDPOINT_POINT );
+ m_ptX = x;
+ m_ptY = y;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : x -
+// y -
+// w -
+// h -
+//-----------------------------------------------------------------------------
+void CPanelEffect::SetTargetRect( int x, int y, int w, int h )
+{
+ SetTargetType( ENDPOINT_RECTANGLE );
+ m_rectX = x;
+ m_rectY = y;
+ m_rectW = w;
+ m_rectH = h;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : visible -
+//-----------------------------------------------------------------------------
+void CPanelEffect::SetVisible( bool visible )
+{
+ m_bVisible = visible;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Output : Returns true on success, false on failure.
+//-----------------------------------------------------------------------------
+bool CPanelEffect::GetVisible( void )
+{
+ return m_bVisible;
+}
+
diff --git a/game/client/tf2/paneleffect.h b/game/client/tf2/paneleffect.h
new file mode 100644
index 0000000..a5860a7
--- /dev/null
+++ b/game/client/tf2/paneleffect.h
@@ -0,0 +1,166 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef PANELEFFECT_H
+#define PANELEFFECT_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+namespace vgui
+{
+ class Panel;
+}
+
+class ITFHintItem;
+
+#include <vgui_controls/PHandle.h>
+
+// Serial under of effect, for safe lookup
+typedef unsigned int EFFECT_HANDLE;
+#define EFFECT_INVALID_HANDLE (EFFECT_HANDLE)(~0)
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+class CPanelEffect
+{
+public:
+ DECLARE_CLASS_NOBASE( CPanelEffect );
+
+ enum
+ {
+ UNKNOWN = 0,
+ FLASHBORDER,
+ ARROW,
+ };
+
+ enum
+ {
+ ENDPOINT_UNKNOWN = 0,
+ ENDPOINT_PANEL,
+ ENDPOINT_POINT,
+ ENDPOINT_RECTANGLE,
+ ENDPOINT_ENTITY,
+ };
+
+
+ CPanelEffect( ITFHintItem *owner );
+ virtual ~CPanelEffect();
+
+ virtual void doPaint( vgui::Panel *panel );
+
+ virtual void Think( void );
+
+ virtual bool ShouldRemove( void );
+ virtual void SetShouldRemove( bool remove );
+
+ virtual EFFECT_HANDLE GetHandle( void );
+
+ virtual void SetType( int type );
+ virtual int GetType( void );
+
+ virtual void SetPanel( vgui::Panel *panel );
+ virtual vgui::Panel *GetPanel( void );
+
+ virtual void SetPanelOther( vgui::Panel *panel );
+ virtual vgui::Panel *GetPanelOther( void );
+
+ virtual void SetTargetPoint( int x, int y );
+ virtual void SetTargetRect( int x, int y, int w, int h );
+
+ virtual void SetColor( int r, int g, int b, int a );
+ virtual void GetColor( int& r, int& g, int& b, int& a );
+
+ virtual void SetEndTime( float time );
+ virtual float GetEndTime( void );
+
+ virtual void SetOwner( ITFHintItem *owner );
+ virtual ITFHintItem *GetOwner( void );
+
+ virtual void SetUsingOffset( bool active, int x, int y );
+ virtual bool GetUsingOffset( void );
+ virtual void GetOffset( int& x, int& y );
+
+ virtual int GetTargetType( void );
+ virtual void SetTargetType( int type );
+ virtual bool GetTargetRectangle( vgui::Panel *outpanel, int&x, int&y, int&w, int&h );
+
+ virtual void SetVisible( bool visible );
+ virtual bool GetVisible( void );
+
+private:
+
+ static EFFECT_HANDLE m_nHandleCount;
+
+protected:
+
+ virtual bool IsVisibleIncludingParent( vgui::Panel *panel );
+
+ EFFECT_HANDLE m_Handle;
+
+ ITFHintItem *m_pOwner;
+
+ // Data
+
+ // type of effect
+ int m_nType;
+
+ // effect targets
+ vgui::PHandle m_hPanel;
+ vgui::PHandle m_hOtherPanel;
+
+ // effect color
+ int m_r, m_g, m_b, m_a;
+
+ float m_flEndTime;// 0.0f for no end time
+
+ // true if we should offset endpoint of arrow/lines into m_hOtherPanel by m_nOffset amount
+ bool m_bEndpointIsCoordinate;
+ // x, y offset into destination panel
+ int m_nOffset[ 2 ];
+
+ bool m_bShouldRemove;
+
+ int m_TargetType;
+ int m_ptX;
+ int m_ptY;
+ int m_rectX;
+ int m_rectY;
+ int m_rectW;
+ int m_rectH;
+
+ bool m_bVisible;
+};
+
+#define EFFECT_FLASH_TIME 0.7f
+
+#define EFFECT_R 100
+#define EFFECT_G 150
+#define EFFECT_B 220
+#define EFFECT_A 255
+
+#define ARROW_R 130
+#define ARROW_G 190
+#define ARROW_B 240
+#define ARROW_A 255
+
+#define AXIALLINE_R 220
+#define AXIALLINE_G 220
+#define AXIALLINE_B 255
+#define AXIALLINE_A 255
+
+// Panel effect APIs
+void DestroyPanelEffects( ITFHintItem *owner );
+EFFECT_HANDLE CreateFlashEffect( ITFHintItem *owner, vgui::Panel *target );
+EFFECT_HANDLE CreateArrowEffect( ITFHintItem *owner, vgui::Panel *from, vgui::Panel *to );
+EFFECT_HANDLE CreateAxialLineEffect( ITFHintItem *owner, vgui::Panel *from, vgui::Panel *to );
+EFFECT_HANDLE CreateArrowEffectToPoint( ITFHintItem *owner, vgui::Panel *from, int x, int y );
+EFFECT_HANDLE CreateAxialLineEffectToPoint( ITFHintItem *owner, vgui::Panel *from, int x, int y );
+EFFECT_HANDLE CreateArrowEffectToRect( ITFHintItem *owner, vgui::Panel *from, int x, int y, int w, int h );
+EFFECT_HANDLE CreateAxialLineEffectToRect( ITFHintItem *owner, vgui::Panel *from, int x, int y, int w, int h );
+
+#endif // PANELEFFECT_H
diff --git a/game/client/tf2/playerandobjectenumerator.cpp b/game/client/tf2/playerandobjectenumerator.cpp
new file mode 100644
index 0000000..a037b6d
--- /dev/null
+++ b/game/client/tf2/playerandobjectenumerator.cpp
@@ -0,0 +1,69 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#include "cbase.h"
+#include "playerandobjectenumerator.h"
+#include "tf_shareddefs.h"
+
+// Enumator class for ragdolls being affected by explosive forces
+CPlayerAndObjectEnumerator::CPlayerAndObjectEnumerator( float radius )
+{
+ m_flRadiusSquared = radius * radius;
+ m_Objects.RemoveAll();
+ m_pLocal = C_BasePlayer::GetLocalPlayer();
+}
+
+int CPlayerAndObjectEnumerator::GetObjectCount()
+{
+ return m_Objects.Size();
+}
+
+C_BaseEntity *CPlayerAndObjectEnumerator::GetObject( int index )
+{
+ if ( index < 0 || index >= GetObjectCount() )
+ return NULL;
+
+ return m_Objects[ index ];
+}
+
+// Actual work code
+IterationRetval_t CPlayerAndObjectEnumerator::EnumElement( IHandleEntity *pHandleEntity )
+{
+ if ( !m_pLocal )
+ return ITERATION_STOP;
+
+ C_BaseEntity *pEnt = ClientEntityList().GetBaseEntityFromHandle( pHandleEntity->GetRefEHandle() );
+ if ( pEnt == NULL )
+ return ITERATION_CONTINUE;
+
+ if ( pEnt == m_pLocal )
+ return ITERATION_CONTINUE;
+
+ if ( !pEnt->IsPlayer() &&
+ !pEnt->IsBaseObject() )
+ {
+ return ITERATION_CONTINUE;
+ }
+
+ // Ignore vehicles, since they have vcollide collisions that's push me away
+ if ( pEnt->GetCollisionGroup() == COLLISION_GROUP_VEHICLE )
+ return ITERATION_CONTINUE;
+
+ // If it's solid to player movement, don't steer around it since we'll just bump into it
+ if ( pEnt->GetCollisionGroup() == TFCOLLISION_GROUP_OBJECT_SOLIDTOPLAYERMOVEMENT )
+ return ITERATION_CONTINUE;
+
+ Vector deltaPos = pEnt->GetAbsOrigin() - m_pLocal->GetAbsOrigin();
+ if ( deltaPos.LengthSqr() > m_flRadiusSquared )
+ return ITERATION_CONTINUE;
+
+ CHandle< C_BaseEntity > h;
+ h = pEnt;
+ m_Objects.AddToTail( h );
+
+ return ITERATION_CONTINUE;
+} \ No newline at end of file
diff --git a/game/client/tf2/playerandobjectenumerator.h b/game/client/tf2/playerandobjectenumerator.h
new file mode 100644
index 0000000..0f6fa2d
--- /dev/null
+++ b/game/client/tf2/playerandobjectenumerator.h
@@ -0,0 +1,44 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef PLAYERANDOBJECTENUMERATOR_H
+#define PLAYERANDOBJECTENUMERATOR_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "utlvector.h"
+#include "ehandle.h"
+#include "ispatialpartition.h"
+
+class C_BaseEntity;
+class C_BasePlayer;
+
+// Enumator class for finding other players and objects close to the
+// local player
+class CPlayerAndObjectEnumerator : public IPartitionEnumerator
+{
+ DECLARE_CLASS_NOBASE( CPlayerAndObjectEnumerator );
+public:
+ //Forced constructor
+ CPlayerAndObjectEnumerator( float radius );
+
+ //Actual work code
+ virtual IterationRetval_t EnumElement( IHandleEntity *pHandleEntity );
+
+ int GetObjectCount();
+ C_BaseEntity *GetObject( int index );
+
+public:
+ //Data members
+ float m_flRadiusSquared;
+
+ CUtlVector< CHandle< C_BaseEntity > > m_Objects;
+ C_BasePlayer *m_pLocal;
+};
+
+#endif // PLAYERANDOBJECTENUMERATOR_H
diff --git a/game/client/tf2/playeroverlay.cpp b/game/client/tf2/playeroverlay.cpp
new file mode 100644
index 0000000..1ef91ae
--- /dev/null
+++ b/game/client/tf2/playeroverlay.cpp
@@ -0,0 +1,368 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $Workfile: $
+// $NoKeywords: $
+//=============================================================================//
+#include "cbase.h"
+#include "playeroverlay.h"
+#include "playeroverlayhealth.h"
+#include "playeroverlayname.h"
+#include "playeroverlayclass.h"
+#include "playeroverlayselected.h"
+#include "playeroverlaysquad.h"
+#include "hud_minimap.h"
+#include "c_basetfplayer.h"
+#include "mapdata.h"
+#include "c_playerresource.h"
+#include "c_team.h"
+#include "commanderoverlay.h"
+#include <KeyValues.h>
+#include <vgui/IVGui.h>
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+//-----------------------------------------------------------------------------
+// Class factory
+//-----------------------------------------------------------------------------
+
+DECLARE_OVERLAY_FACTORY( CHudPlayerOverlay, "player" );
+
+
+// THE ACTUAL OVERLAY
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Output :
+//-----------------------------------------------------------------------------
+CHudPlayerOverlay::CHudPlayerOverlay( vgui::Panel *parent, const char *panelName )
+: BaseClass( parent, "CHudPlayerOverlay" )
+{
+ m_pHealth = 0;
+ m_pName = 0;
+ m_pClass = 0;
+ m_pSquad = 0;
+ m_pSelected = 0;
+
+ SetAutoDelete( false );
+
+ m_hPlayer = NULL;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Output :
+//-----------------------------------------------------------------------------
+CHudPlayerOverlay::~CHudPlayerOverlay( void )
+{
+ Clear();
+}
+
+void CHudPlayerOverlay::Clear( void )
+{
+ delete m_pHealth;
+ delete m_pName;
+ delete m_pClass;
+ delete m_pSelected;
+ delete m_pSquad;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+bool CHudPlayerOverlay::Init( KeyValues* pInitData, C_BaseEntity* pEntity )
+{
+ Clear();
+
+ m_hPlayer = dynamic_cast< C_BaseTFPlayer * >( pEntity );
+ if (!m_hPlayer.Get())
+ return false;
+
+ if (!BaseClass::Init( pInitData, pEntity ))
+ return false;
+
+ if (!ParseRGBA(pInitData, "fgcolor", m_fgColor ))
+ return false;
+
+ if (!ParseRGBA(pInitData, "bgcolor", m_bgColor ))
+ return false;
+
+ if (!ParseCoord(pInitData, "offset", m_OffsetX, m_OffsetY ))
+ return false;
+
+ int w, h;
+ if (!ParseCoord(pInitData, "size", w, h ))
+ return false;
+
+ SetSize( w, h );
+ SetVisible( false );
+
+ m_iOrgWidth = w;
+ m_iOrgHeight = h;
+ m_iOrgOffsetX = m_OffsetX;
+ m_iOrgOffsetY = m_OffsetY;
+
+ const char *mouseover = pInitData->GetString( "mousehint", "" );
+ if ( mouseover && mouseover[ 0 ] )
+ {
+ Q_strncpy( m_szMouseOverText, mouseover, sizeof( m_szMouseOverText ) );
+ }
+
+ m_pHealth = new CHudPlayerOverlayHealth( this );
+ KeyValues* pHealthValue = pInitData->FindKey("HealthBar");
+ if (!m_pHealth->Init( pHealthValue ))
+ return false;
+
+ m_pHealth->SetVisible( false );
+ m_pHealth->SetParent( this );
+
+ m_pName = new CHudPlayerOverlayName( this, "" );
+ KeyValues* pNameValue = pInitData->FindKey("Name");
+ if (!m_pName->Init( pNameValue ))
+ return false;
+
+ m_pName->SetVisible( false );
+ m_pName->SetParent( this );
+
+ m_pClass = new CHudPlayerOverlayClass( this );
+ KeyValues* pClassValue = pInitData->FindKey("Class");
+ if (!m_pClass->Init( pClassValue ))
+ return false;
+
+ m_pClass->SetVisible( false );
+ m_pClass->SetParent( this );
+
+ m_pSquad = new CHudPlayerOverlaySquad( this, "" );
+ KeyValues* pSquadValue = pInitData->FindKey("Squad");
+ if (!m_pSquad->Init( pSquadValue ))
+ return false;
+
+ m_pSquad->SetVisible( false );
+ m_pSquad->SetParent( this );
+
+ m_pSelected = new CHudPlayerOverlaySelected( this );
+ KeyValues* pSelectedValue = pInitData->FindKey("Selection");
+ if (!m_pSelected->Init( pSelectedValue ))
+ return false;
+
+ m_pSelected->SetVisible( false );
+ m_pSelected->SetParent( this );
+
+ // Um, is there a better way?
+ m_PlayerNum = GetEntity() ? GetEntity()->index : 0;
+ if (m_PlayerNum == 0)
+ return false;
+
+ return true;
+}
+
+void CHudPlayerOverlay::Hide( void )
+{
+ SetVisible( false );
+ if ( m_pHealth )
+ {
+ m_pHealth->SetVisible( false);
+ }
+
+ if ( m_pName )
+ {
+ m_pName->SetVisible( false );
+ }
+
+ if ( m_pClass )
+ {
+ m_pClass->SetVisible( false );
+ }
+
+ if ( m_pSquad )
+ {
+ m_pSquad->SetVisible( false );
+ }
+
+ if ( m_pSelected )
+ {
+ m_pSelected->SetVisible( false );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : playerNum -
+//-----------------------------------------------------------------------------
+
+void CHudPlayerOverlay::OnTick( )
+{
+ BaseClass::OnTick();
+
+ if (!IsLocalPlayerInTactical() || !engine->IsInGame())
+ {
+ Hide();
+ return;
+ }
+
+ // Don't draw if I'm not visible in the tactical map
+ if ( MapData().IsEntityVisibleToTactical( GetEntity() ) == false )
+ {
+ Hide();
+ return;
+ }
+
+ // Don't draw it if I'm on team 0 (haven't decided on a team)
+ C_BaseTFPlayer *pPlayer = m_hPlayer.Get();
+ if (!pPlayer || (pPlayer->GetTeamNumber() == 0) || (pPlayer->GetClass() == TFCLASS_UNDECIDED))
+ {
+ Hide();
+ return;
+ }
+
+ SetVisible( true );
+
+ const char *pName = g_PR->GetPlayerName( m_PlayerNum );
+ if ( pName )
+ {
+ m_pName->SetName( pName );
+ }
+ else
+ {
+ Hide();
+ return;
+ }
+
+ Vector pos, screen;
+
+ C_BaseTFPlayer *tf2player = dynamic_cast<C_BaseTFPlayer *>( GetEntity() );
+ int iteam = 0;
+ int iclass = 0;
+ if ( tf2player )
+ {
+ iteam = tf2player->GetTeamNumber();
+ iclass = tf2player->PlayerClass();
+
+ // FIXME: Get max health for player
+ m_pHealth->SetHealth( (float)tf2player->GetHealth() / (float)100.0f );
+ }
+
+ m_pClass->SetImage( 0 );
+ if ( iteam != 0 && iclass != TFCLASS_UNDECIDED )
+ m_pClass->SetTeamAndClass( iteam, iclass );
+
+ // Update our position on screen
+ int sx, sy;
+ GetEntityPosition( sx, sy );
+
+ // Set the position
+ SetPos( (int)(sx + m_OffsetX + 0.5f), (int)(sy + m_OffsetY + 0.5f));
+
+ // Add it in
+ m_pHealth->SetVisible( true );
+ m_pName->SetVisible( true );
+ m_pClass->SetVisible( true );
+
+ if ( MapData().m_Players[ m_PlayerNum - 1 ].m_bSelected )
+ {
+ m_pSelected->SetVisible( true );
+ }
+ else
+ {
+ m_pSelected->SetVisible( false );
+ }
+
+ if ( MapData().m_Players[ m_PlayerNum - 1 ].m_nSquadNumber != 0 )
+ {
+ char sz[ 32 ];
+ Q_snprintf( sz, sizeof( sz ), "%i", MapData().m_Players[ m_PlayerNum - 1 ].m_nSquadNumber );
+
+ m_pSquad->SetSquad( sz );
+ m_pSquad->SetVisible( true );
+ }
+ else
+ {
+ m_pSquad->SetVisible( false );
+ }
+
+ // Hide details if it's an enemy
+ if ( ArePlayersOnSameTeam( engine->GetLocalPlayer(), m_PlayerNum ) == false )
+ {
+ m_pHealth->SetVisible( false );
+ m_pName->SetVisible( false );
+ m_pSelected->SetVisible( false );
+ m_pSquad->SetVisible( false );
+
+ // Only show class icon
+ m_pClass->SetVisible( true );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CHudPlayerOverlay::Paint()
+{
+ // Don't draw if I'm not visible in the tactical map
+ if ( MapData().IsEntityVisibleToTactical( GetEntity() ) == false )
+ return;
+
+ // Don't draw if if I haven't chosen a class...
+
+ SetFgColor( m_fgColor );
+ SetBgColor( m_bgColor );
+
+ BaseClass::Paint();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *panel -
+// fg -
+// bg -
+//-----------------------------------------------------------------------------
+void CHudPlayerOverlay::SetColorLevel( vgui::Panel *panel, Color& fg, Color& bg )
+{
+ float frac = GetAlphaFrac();
+
+ if ( frac == 1.0f )
+ {
+ panel->SetFgColor( fg );
+ panel->SetBgColor( bg );
+ return;
+ }
+
+ Color foreground;
+ Color background;
+
+ foreground = fg;
+ background = bg;
+
+ int r, g, b, a;
+ foreground.GetColor( r, g, b, a );
+ foreground.SetColor( r, g, b, (int)( ( float )a * frac ) );
+
+ panel->SetFgColor( foreground );
+
+ background.GetColor( r, g, b, a );
+ background.SetColor( r, g, b, (int)( ( float )a * frac ) );
+
+ panel->SetBgColor( background );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Output : int
+//-----------------------------------------------------------------------------
+float CHudPlayerOverlay::GetAlphaFrac( void )
+{
+ //
+ // return fmod( gpGlobals->curtime, 1.0f );
+
+ C_BaseTFPlayer *local = C_BaseTFPlayer::GetLocalPlayer();
+ if ( !local )
+ return 1.0;
+
+ C_BaseTFPlayer *pPlayer = m_hPlayer.Get();
+ if (!pPlayer || (pPlayer->GetTeamNumber() == local->GetTeamNumber()) )
+ return 1.0f;
+
+ return pPlayer->GetOverlayAlpha();
+}
diff --git a/game/client/tf2/playeroverlay.h b/game/client/tf2/playeroverlay.h
new file mode 100644
index 0000000..3864a6f
--- /dev/null
+++ b/game/client/tf2/playeroverlay.h
@@ -0,0 +1,68 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $Workfile: $
+// $NoKeywords: $
+//=============================================================================//
+#if !defined( PLAYEROVERLAY_H )
+#define PLAYEROVERLAY_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include <vgui/VGUI.h>
+
+#include "vgui_entitypanel.h"
+
+class CHudPlayerOverlayName;
+class CHudPlayerOverlayHealth;
+class CHudPlayerOverlayClass;
+class CHudPlayerOverlaySquad;
+class CHudPlayerOverlaySelected;
+class KeyValues;
+class C_BaseTFPlayer;
+//-----------------------------------------------------------------------------
+// Purpose: Container for overlay elements
+//-----------------------------------------------------------------------------
+
+class CHudPlayerOverlay : public CEntityPanel
+{
+public:
+ DECLARE_CLASS( CHudPlayerOverlay, CEntityPanel );
+
+ CHudPlayerOverlay( vgui::Panel *parent, const char *panelName );
+ virtual ~CHudPlayerOverlay( void );
+
+ virtual void Clear( void );
+
+ virtual bool Init( KeyValues* pInitData, C_BaseEntity* pEntity );
+ virtual void OnTick( );
+
+ virtual void Hide( void );
+
+ virtual void Paint();
+
+ // Global fade amount
+ float GetAlphaFrac( void );
+ void SetColorLevel( vgui::Panel *panel, Color& fg, Color& bg );
+
+private:
+ CHudPlayerOverlayName *m_pName;
+ CHudPlayerOverlayHealth *m_pHealth;
+ CHudPlayerOverlayClass *m_pClass;
+ CHudPlayerOverlaySquad *m_pSquad;
+ CHudPlayerOverlaySelected *m_pSelected;
+
+ int m_OffsetX, m_OffsetY;
+ int m_PlayerNum;
+
+ Color m_fgColor;
+ Color m_bgColor;
+
+ // These are only associated with tf players
+ CHandle<C_BaseTFPlayer> m_hPlayer;
+};
+
+
+#endif // PLAYEROVERLAY_H \ No newline at end of file
diff --git a/game/client/tf2/playeroverlayclass.cpp b/game/client/tf2/playeroverlayclass.cpp
new file mode 100644
index 0000000..12684eb
--- /dev/null
+++ b/game/client/tf2/playeroverlayclass.cpp
@@ -0,0 +1,269 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $Workfile: $
+// $Date: $
+// $NoKeywords: $
+//=============================================================================//
+#include "cbase.h"
+#include "playeroverlayclass.h"
+#include "playeroverlay.h"
+#include <KeyValues.h>
+#include "commanderoverlay.h"
+#include "clientmode_tfnormal.h"
+#include "tf_shareddefs.h"
+#include "hud_commander_statuspanel.h"
+#include "vgui_bitmapimage.h"
+#include "igamesystem.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+
+//-----------------------------------------------------------------------------
+// Class info. Only load it once.
+//-----------------------------------------------------------------------------
+
+CHudPlayerOverlayClass::CMapClassColors** CHudPlayerOverlayClass::s_ppClassInfo = 0;
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+class CCleanupPlayerOverlayClass : public CAutoGameSystem
+{
+public:
+ virtual void Shutdown()
+ {
+ if ( !CHudPlayerOverlayClass::s_ppClassInfo )
+ return;
+
+ for (int i = 0; i <= MAX_TF_TEAMS; ++i)
+ {
+ for ( int j = 0; j < TFCLASS_CLASS_COUNT; j++ )
+ {
+ delete CHudPlayerOverlayClass::s_ppClassInfo[i][j].m_pClassImage;
+ }
+ delete[] CHudPlayerOverlayClass::s_ppClassInfo[i];
+ }
+ delete[] CHudPlayerOverlayClass::s_ppClassInfo;
+ }
+};
+
+static CCleanupPlayerOverlayClass g_CleanupPlayerOverlayClass;
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+
+CHudPlayerOverlayClass::CHudPlayerOverlayClass( CHudPlayerOverlay *baseOverlay )
+: BaseClass( NULL, "CHudPlayerOverlayClass" )
+{
+ m_pBaseOverlay = baseOverlay;
+
+ m_pImage = NULL;
+ SetPaintBackgroundEnabled( false );
+
+ // Send mouse inputs (but not cursorenter/exit for now) up to parent
+ SetReflectMouse( true );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+
+CHudPlayerOverlayClass::~CHudPlayerOverlayClass( void )
+{
+ delete m_pImage;
+}
+
+
+//-----------------------------------------------------------------------------
+// Parse class icons
+//-----------------------------------------------------------------------------
+
+bool CHudPlayerOverlayClass::ParseTeamClassInfo( KeyValues *pClassIcons, const char *classname, CMapClassColors *pClassColors )
+{
+ const char *classimage;
+ KeyValues *pClass;
+ pClass = pClassIcons->FindKey( classname );
+ if ( !pClass )
+ return false;
+
+ classimage = pClass->GetString( "material" );
+ if ( classimage && classimage[ 0 ] )
+ {
+ pClassColors->m_pClassImage = new BitmapImage( NULL, classimage );
+ }
+ else
+ {
+ return( false );
+ }
+
+ return ParseRGBA( pClass, "color", pClassColors->m_clrClass );
+}
+
+bool CHudPlayerOverlayClass::ParseTeamClassIcons( CMapClassColors *pT, KeyValues *pTeam )
+{
+ if ( !ParseTeamClassInfo( pTeam, "Recon", &pT[ TFCLASS_RECON ] ) )
+ return false;
+ if ( !ParseTeamClassInfo( pTeam, "Sniper", &pT[ TFCLASS_SNIPER ] ) )
+ return false;
+ if ( !ParseTeamClassInfo( pTeam, "Commando", &pT[ TFCLASS_COMMANDO ] ) )
+ return false;
+ if ( !ParseTeamClassInfo( pTeam, "Support", &pT[ TFCLASS_SUPPORT ] ) )
+ return false;
+ if ( !ParseTeamClassInfo( pTeam, "Medic", &pT[ TFCLASS_MEDIC ] ) )
+ return false;
+ if ( !ParseTeamClassInfo( pTeam, "Escort", &pT[ TFCLASS_ESCORT ] ) )
+ return false;
+ if ( !ParseTeamClassInfo( pTeam, "Defender", &pT[ TFCLASS_DEFENDER ] ) )
+ return false;
+ if ( !ParseTeamClassInfo( pTeam, "Sapper", &pT[ TFCLASS_SAPPER ] ) )
+ return false;
+ if ( !ParseTeamClassInfo( pTeam, "Infiltrator", &pT[ TFCLASS_INFILTRATOR ] ) )
+ return false;
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// Initialization
+//-----------------------------------------------------------------------------
+
+bool CHudPlayerOverlayClass::InitClassInfo( KeyValues* pKeyValues )
+{
+ if (s_ppClassInfo)
+ return true;
+
+ char teamkey[ 128 ];
+ s_ppClassInfo = new CMapClassColors*[MAX_TF_TEAMS+1];
+ for (int i = 0; i <= MAX_TF_TEAMS; ++i)
+ {
+ s_ppClassInfo[i] = new CMapClassColors[TFCLASS_CLASS_COUNT];
+ Q_snprintf( teamkey, sizeof( teamkey ), "Team%i", i );
+ KeyValues *pTeam = pKeyValues->FindKey( teamkey );
+ if (pTeam)
+ {
+ if (!ParseTeamClassIcons( s_ppClassInfo[i], pTeam ))
+ return false;
+ }
+ }
+
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// Initialization
+//-----------------------------------------------------------------------------
+
+bool CHudPlayerOverlayClass::Init( KeyValues* pKeyValues )
+{
+ if (!pKeyValues)
+ return false;
+
+ int x, y, w, h;
+ if (!ParseRect(pKeyValues, "friendlyposition", x, y, w, h ))
+ return false;
+
+ if (!InitClassInfo( pKeyValues ))
+ return false;
+
+ SetPos( x, y );
+ SetSize( w, h );
+
+ SetImage( 0 );
+
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : pImage - Class specific image
+//-----------------------------------------------------------------------------
+void CHudPlayerOverlayClass::SetImage( BitmapImage *pImage )
+{
+ m_pImage = pImage;
+ if (m_pImage)
+ {
+ // Make sure the image size is correct
+ int w,h;
+ GetSize(w,h);
+ }
+}
+
+void CHudPlayerOverlayClass::SetTeamAndClass( int team, int playerclass )
+{
+ if (!s_ppClassInfo)
+ return;
+
+ CMapClassColors *pCC = &s_ppClassInfo[ team ][ playerclass ];
+ if ( pCC )
+ {
+ int r, g, b, a;
+ pCC->m_clrClass.GetColor( r, g, b, a );
+ SetColor( r, g, b, a );
+ SetImage( pCC->m_pClassImage );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// If this guy changes size, so must the associated image
+//-----------------------------------------------------------------------------
+
+void CHudPlayerOverlayClass::SetSize( int w, int h )
+{
+ // chain...
+ Panel::SetSize( w, h );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : r -
+// g -
+// b -
+// a -
+//-----------------------------------------------------------------------------
+void CHudPlayerOverlayClass::SetColor( int r, int g, int b, int a )
+{
+ m_r = r;
+ m_g = g;
+ m_b = b;
+ m_a = a;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CHudPlayerOverlayClass::Paint( void )
+{
+ int w, h;
+
+ m_pBaseOverlay->SetColorLevel( this, m_fgColor, m_bgColor );
+
+ GetSize( w, h );
+ vgui::surface()->DrawSetColor( m_r, m_g, m_b, m_a * m_pBaseOverlay->GetAlphaFrac() );
+
+ if ( !m_pImage )
+ return;
+
+ Color color;
+ color.SetColor( m_r, m_g, m_b, m_a * m_pBaseOverlay->GetAlphaFrac() );
+ m_pImage->SetColor( color );
+ m_pImage->DoPaint( GetVPanel() );
+}
+
+void CHudPlayerOverlayClass::OnCursorEntered()
+{
+ if ( m_pBaseOverlay->GetMouseOverText() )
+ {
+ StatusPrint( TYPE_HINT, "%s", m_pBaseOverlay->GetMouseOverText() );
+ }
+}
+
+void CHudPlayerOverlayClass::OnCursorExited()
+{
+ if ( m_pBaseOverlay->GetMouseOverText() )
+ {
+ StatusClear();
+ }
+} \ No newline at end of file
diff --git a/game/client/tf2/playeroverlayclass.h b/game/client/tf2/playeroverlayclass.h
new file mode 100644
index 0000000..ab4483d
--- /dev/null
+++ b/game/client/tf2/playeroverlayclass.h
@@ -0,0 +1,72 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $Workfile: $
+// $Date: $
+// $NoKeywords: $
+//=============================================================================//
+
+#if !defined( PLAYEROVERLAYCLASS_H )
+#define PLAYEROVERLAYCLASS_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "vgui_basepanel.h"
+
+class BitmapImage;
+class KeyValues;
+class CHudPlayerOverlay;
+
+class CHudPlayerOverlayClass : public CBasePanel
+{
+public:
+ DECLARE_CLASS( CHudPlayerOverlayClass, CBasePanel );
+
+ CHudPlayerOverlayClass( CHudPlayerOverlay *baseOverlay );
+ virtual ~CHudPlayerOverlayClass( void );
+
+ bool Init( KeyValues* pKeyValues );
+
+ void SetColor( int r, int g, int b, int a );
+ void SetImage( BitmapImage *pImage );
+ void SetTeamAndClass( int team, int playerclass );
+
+ // Keeps the image size correct
+ virtual void SetSize( int w, int h );
+
+ virtual void Paint( void );
+
+ virtual void OnCursorEntered();
+ virtual void OnCursorExited();
+
+private:
+ class CMapClassColors
+ {
+ public:
+ CMapClassColors() : m_pClassImage(0) {}
+
+ BitmapImage *m_pClassImage;
+ Color m_clrClass;
+ };
+
+ // Initialize class info only once
+ static bool InitClassInfo( KeyValues* pKeyValues );
+ static bool ParseTeamClassInfo( KeyValues *pClassIcons, const char *classname, CMapClassColors *pClassColors );
+ static bool ParseTeamClassIcons( CMapClassColors *pT, KeyValues *pTeam );
+
+ static CMapClassColors** s_ppClassInfo;
+
+ int m_r, m_g, m_b, m_a;
+ BitmapImage *m_pImage;
+
+ Color m_fgColor;
+ Color m_bgColor;
+
+ CHudPlayerOverlay *m_pBaseOverlay;
+
+ friend class CCleanupPlayerOverlayClass;
+};
+
+#endif // PLAYEROVERLAYCLASS_H \ No newline at end of file
diff --git a/game/client/tf2/playeroverlayhealth.cpp b/game/client/tf2/playeroverlayhealth.cpp
new file mode 100644
index 0000000..0ae023e
--- /dev/null
+++ b/game/client/tf2/playeroverlayhealth.cpp
@@ -0,0 +1,123 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $Workfile: $
+// $Date: $
+//
+//-----------------------------------------------------------------------------
+// $Log: $
+//
+// $NoKeywords: $
+//=============================================================================//
+#include "cbase.h"
+#include "playeroverlayhealth.h"
+#include "playeroverlay.h"
+#include "CommanderOverlay.h"
+#include "hud_commander_statuspanel.h"
+//-----------------------------------------------------------------------------
+// Purpose:
+// Output :
+//-----------------------------------------------------------------------------
+CHudPlayerOverlayHealth::CHudPlayerOverlayHealth( CHudPlayerOverlay *baseOverlay )
+: BaseClass( NULL, "CHudPlayerOverlayHealth" )
+{
+ m_pBaseOverlay = baseOverlay;
+
+ SetHealth( 0 );
+
+ SetPaintBackgroundEnabled( false );
+ // Send mouse inputs (but not cursorenter/exit for now) up to parent
+ SetReflectMouse( true );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Output :
+//-----------------------------------------------------------------------------
+CHudPlayerOverlayHealth::~CHudPlayerOverlayHealth( void )
+{
+}
+
+//-----------------------------------------------------------------------------
+// Parse values from the file
+//-----------------------------------------------------------------------------
+
+bool CHudPlayerOverlayHealth::Init( KeyValues* pInitData )
+{
+ if (!pInitData)
+ return false;
+
+ if (!ParseRGBA(pInitData, "fgcolor", m_fgColor ))
+ return false;
+
+ if (!ParseRGBA(pInitData, "bgcolor", m_bgColor ))
+ return false;
+
+ int x, y, w, h;
+ if (!ParseRect(pInitData, "position", x, y, w, h ))
+ return false;
+ SetPos( x, y );
+ SetSize( w, h );
+
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : health -
+//-----------------------------------------------------------------------------
+
+void CHudPlayerOverlayHealth::SetHealth( float health )
+{
+ m_Health = health;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CHudPlayerOverlayHealth::Paint( void )
+{
+ int w, h;
+
+ GetSize( w, h );
+
+ m_pBaseOverlay->SetColorLevel( this, m_fgColor, m_bgColor );
+
+ // Use a color related to health value....
+ vgui::surface()->DrawSetColor( 0, 255, 0, 255 * m_pBaseOverlay->GetAlphaFrac() );
+
+ int drawwidth;
+
+ float frac = m_Health;
+ frac = MIN( 1.0, m_Health );
+ frac = MAX( 0.0, m_Health );
+
+ drawwidth = frac * w;
+
+ vgui::surface()->DrawFilledRect( 0, 0, drawwidth, h/2 );
+
+ // This is the hurt part
+ if (w != drawwidth)
+ {
+ vgui::surface()->DrawSetColor( 255, 64, 64, 255 * m_pBaseOverlay->GetAlphaFrac() );
+ vgui::surface()->DrawFilledRect( drawwidth, 0, w, h/2 );
+ }
+}
+
+void CHudPlayerOverlayHealth::OnCursorEntered()
+{
+ if ( m_pBaseOverlay->GetMouseOverText() )
+ {
+ StatusPrint( TYPE_HINT, "%s", m_pBaseOverlay->GetMouseOverText() );
+ }
+}
+
+void CHudPlayerOverlayHealth::OnCursorExited()
+{
+ if ( m_pBaseOverlay->GetMouseOverText() )
+ {
+ StatusClear();
+ }
+} \ No newline at end of file
diff --git a/game/client/tf2/playeroverlayhealth.h b/game/client/tf2/playeroverlayhealth.h
new file mode 100644
index 0000000..9dc7edd
--- /dev/null
+++ b/game/client/tf2/playeroverlayhealth.h
@@ -0,0 +1,47 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $Workfile: $
+// $Date: $
+// $NoKeywords: $
+//=============================================================================//
+#if !defined( PLAYEROVERLAYHEALTH_H )
+#define PLAYEROVERLAYHEALTH_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "vgui_basepanel.h"
+
+class KeyValues;
+
+class CHudPlayerOverlay;
+
+class CHudPlayerOverlayHealth : public CBasePanel
+{
+public:
+ DECLARE_CLASS( CHudPlayerOverlayHealth, CBasePanel );
+
+ CHudPlayerOverlayHealth( CHudPlayerOverlay *baseOverlay );
+ virtual ~CHudPlayerOverlayHealth( void );
+
+ bool Init( KeyValues* pInitData );
+ void SetHealth( float health );
+
+ virtual void Paint( void );
+
+ virtual void OnCursorEntered();
+ virtual void OnCursorExited();
+
+private:
+ float m_Health;
+
+ Color m_fgColor;
+ Color m_bgColor;
+
+ CHudPlayerOverlay *m_pBaseOverlay;
+
+};
+
+#endif // PLAYEROVERLAYHEALTH_H \ No newline at end of file
diff --git a/game/client/tf2/playeroverlayname.cpp b/game/client/tf2/playeroverlayname.cpp
new file mode 100644
index 0000000..8d3f602
--- /dev/null
+++ b/game/client/tf2/playeroverlayname.cpp
@@ -0,0 +1,183 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $Workfile: $
+// $Date: $
+//
+//-----------------------------------------------------------------------------
+// $Log: $
+//
+// $NoKeywords: $
+//=============================================================================//
+#include "cbase.h"
+#include <KeyValues.h>
+#include "playeroverlay.h"
+#include "playeroverlayname.h"
+#include <KeyValues.h>
+#include "commanderoverlay.h"
+#include "hud_commander_statuspanel.h"
+#include <vgui/IVGui.h>
+#include <vgui/IScheme.h>
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *name -
+//-----------------------------------------------------------------------------
+CHudPlayerOverlayName::CHudPlayerOverlayName( CHudPlayerOverlay *baseOverlay, const char *name ) :
+vgui::Label( (vgui::Panel *)NULL, "OverlayName", name )
+{
+ m_pBaseOverlay = baseOverlay;
+
+ Q_strncpy( m_szName, name, sizeof( m_szName ) );
+
+ SetPaintBackgroundEnabled( false );
+
+ // Send mouse inputs (but not cursorenter/exit for now) up to parent
+ SetReflectMouse( true );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+CHudPlayerOverlayName::~CHudPlayerOverlayName( void )
+{
+}
+
+bool CHudPlayerOverlayName::Init( KeyValues* pInitData )
+{
+ if (!pInitData)
+ return false;
+
+ if (!ParseRGBA(pInitData, "fgcolor", m_fgColor ))
+ return false;
+
+ if (!ParseRGBA(pInitData, "bgcolor", m_bgColor ))
+ return false;
+
+ int x, y, w, h;
+ if (!ParseRect(pInitData, "position", x, y, w, h ))
+ return false;
+ SetPos( x, y );
+ SetSize( w, h );
+
+ SetContentAlignment( vgui::Label::a_west );
+
+ return true;
+}
+
+void CHudPlayerOverlayName::ApplySchemeSettings( vgui::IScheme *pScheme )
+{
+ BaseClass::ApplySchemeSettings( pScheme );
+ SetFont( pScheme->GetFont( "primary" ) );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *name -
+//-----------------------------------------------------------------------------
+void CHudPlayerOverlayName::SetName( const char *name )
+{
+ Q_strncpy( m_szName, name, sizeof( m_szName ) );
+ SetText( name );
+}
+
+void CHudPlayerOverlayName::Paint()
+{
+ m_pBaseOverlay->SetColorLevel( this, m_fgColor, m_bgColor );
+
+ BaseClass::Paint();
+}
+
+void CHudPlayerOverlayName::SetReflectMouse( bool reflect )
+{
+ m_bReflectMouse = true;
+}
+
+void CHudPlayerOverlayName::OnCursorMoved(int x,int y)
+{
+ if ( !m_bReflectMouse )
+ return;
+
+ if ( !GetParent() )
+ return;
+
+ LocalToScreen( x, y );
+
+ vgui::ivgui()->PostMessage(
+ GetParent()->GetVPanel(),
+ new KeyValues( "CursorMoved", "xpos", x, "ypos", y ),
+ GetVPanel() );
+}
+
+void CHudPlayerOverlayName::OnMousePressed(vgui::MouseCode code)
+{
+ if ( !m_bReflectMouse )
+ return;
+
+ if ( !GetParent() )
+ return;
+
+ vgui::ivgui()->PostMessage(
+ GetParent()->GetVPanel(),
+ new KeyValues( "MousePressed", "code", code ),
+ GetVPanel() );
+}
+
+void CHudPlayerOverlayName::OnMouseDoublePressed(vgui::MouseCode code)
+{
+ if ( !m_bReflectMouse )
+ return;
+
+ if ( !GetParent() )
+ return;
+
+ vgui::ivgui()->PostMessage(
+ GetParent()->GetVPanel(),
+ new KeyValues( "MouseDoublePressed", "code", code ),
+ GetVPanel() );
+}
+
+void CHudPlayerOverlayName::OnMouseReleased(vgui::MouseCode code)
+{
+ if ( !m_bReflectMouse )
+ return;
+
+ if ( !GetParent() )
+ return;
+
+ vgui::ivgui()->PostMessage(
+ GetParent()->GetVPanel(),
+ new KeyValues( "MouseReleased", "code", code ),
+ GetVPanel() );
+}
+
+void CHudPlayerOverlayName::OnMouseWheeled(int delta)
+{
+ if ( !m_bReflectMouse )
+ return;
+
+ if ( !GetParent() )
+ return;
+
+ vgui::ivgui()->PostMessage(
+ GetParent()->GetVPanel(),
+ new KeyValues( "MouseWheeled", "delta", delta ),
+ GetVPanel() );
+}
+
+void CHudPlayerOverlayName::OnCursorEntered()
+{
+ if ( m_pBaseOverlay->GetMouseOverText() )
+ {
+ StatusPrint( TYPE_HINT, "%s", m_pBaseOverlay->GetMouseOverText() );
+ }
+}
+
+void CHudPlayerOverlayName::OnCursorExited()
+{
+ if ( m_pBaseOverlay->GetMouseOverText() )
+ {
+ StatusClear();
+ }
+} \ No newline at end of file
diff --git a/game/client/tf2/playeroverlayname.h b/game/client/tf2/playeroverlayname.h
new file mode 100644
index 0000000..4fe7a4f
--- /dev/null
+++ b/game/client/tf2/playeroverlayname.h
@@ -0,0 +1,59 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $Workfile: $
+// $Date: $
+//
+//-----------------------------------------------------------------------------
+// $Log: $
+//
+// $NoKeywords: $
+//=============================================================================//
+#if !defined( PLAYEROVERLAYNAME_H )
+#define PLAYEROVERLAYNAME_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include <vgui_controls/Label.h>
+
+class KeyValues;
+class CHudPlayerOverlay;
+class CHudPlayerOverlayName : public vgui::Label
+{
+public:
+ typedef vgui::Label BaseClass;
+
+ CHudPlayerOverlayName( CHudPlayerOverlay *baseOverlay, const char *name );
+ virtual ~CHudPlayerOverlayName( void );
+
+ bool Init( KeyValues* pInitData );
+
+ void SetName( const char *name );
+
+ virtual void ApplySchemeSettings( vgui::IScheme *pScheme );
+ virtual void Paint();
+
+ virtual void SetReflectMouse( bool reflect );
+ // If reflect mouse is true, then pass these up to parent
+ virtual void OnCursorMoved(int x,int y);
+ virtual void OnMousePressed(vgui::MouseCode code);
+ virtual void OnMouseDoublePressed(vgui::MouseCode code);
+ virtual void OnMouseReleased(vgui::MouseCode code);
+ virtual void OnMouseWheeled(int delta);
+
+ virtual void OnCursorEntered();
+ virtual void OnCursorExited();
+private:
+
+ char m_szName[ 64 ];
+ Color m_fgColor;
+ Color m_bgColor;
+
+ CHudPlayerOverlay *m_pBaseOverlay;
+
+ bool m_bReflectMouse;
+};
+
+#endif // PLAYEROVERLAYNAME_H \ No newline at end of file
diff --git a/game/client/tf2/playeroverlayselected.cpp b/game/client/tf2/playeroverlayselected.cpp
new file mode 100644
index 0000000..f52912a
--- /dev/null
+++ b/game/client/tf2/playeroverlayselected.cpp
@@ -0,0 +1,130 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $Workfile: $
+// $Date: $
+//
+//-----------------------------------------------------------------------------
+// $Log: $
+//
+// $NoKeywords: $
+//=============================================================================//
+#include "cbase.h"
+#include "playeroverlay.h"
+#include "playeroverlayselected.h"
+#include <KeyValues.h>
+#include "commanderoverlay.h"
+#include "hud_commander_statuspanel.h"
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+CHudPlayerOverlaySelected::CHudPlayerOverlaySelected( CHudPlayerOverlay *baseOverlay )
+ : BaseClass( NULL, "CHudPlayerOverlaySelected" )
+{
+ m_pBaseOverlay = baseOverlay;
+
+ int i;
+ for ( i = 0; i < 4; i++ )
+ {
+ m_pImages[ i ] = NULL;
+ }
+
+ SetPaintBackgroundEnabled( false );
+
+ // Send mouse inputs (but not cursorenter/exit for now) up to parent
+ SetReflectMouse( true );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+CHudPlayerOverlaySelected::~CHudPlayerOverlaySelected( void )
+{
+}
+
+//-----------------------------------------------------------------------------
+// Initialization
+//-----------------------------------------------------------------------------
+
+bool CHudPlayerOverlaySelected::Init( KeyValues* pInitData )
+{
+ if (!pInitData)
+ return false;
+
+ if (!ParseRGBA(pInitData, "fgcolor", m_fgColor ))
+ return false;
+
+ if (!ParseRGBA(pInitData, "bgcolor", m_bgColor ))
+ return false;
+
+ int x, y, w, h;
+ if (!ParseRect(pInitData, "position", x, y, w, h ))
+ return false;
+ SetPos( x, y );
+ SetSize( w, h );
+
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: NOTE: This is not hooked up yet.
+// Input : pImage -- the four corner images
+//-----------------------------------------------------------------------------
+void CHudPlayerOverlaySelected::SetImages( BitmapImage *pImage[4] )
+{
+ int i;
+ for ( i = 0 ; i < 4; i++ )
+ {
+ m_pImages[ i ] = pImage[ i ];
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: FIXME: Use materials for corners, not just procedural drawing?
+//-----------------------------------------------------------------------------
+void CHudPlayerOverlaySelected::Paint( void )
+{
+ int w, h;
+
+ m_pBaseOverlay->SetColorLevel( this, m_fgColor, m_bgColor );
+
+ GetSize( w, h );
+ int r, g, b, a;
+ Color clr = GetFgColor();
+ clr.GetColor( r, g, b, a );
+ vgui::surface()->DrawSetColor( r, g, b, a );
+
+ // Draw corners
+ int inSetSize = 6;
+ int thickness = 2;
+
+ vgui::surface()->DrawFilledRect( 0, 0, inSetSize, thickness );
+ vgui::surface()->DrawFilledRect( 0, 0, thickness, inSetSize );
+
+ vgui::surface()->DrawFilledRect( w-inSetSize, 0, w, thickness );
+ vgui::surface()->DrawFilledRect( w-thickness, 0, w, inSetSize );
+
+ vgui::surface()->DrawFilledRect( w-inSetSize, h-thickness, w, h );
+ vgui::surface()->DrawFilledRect( w-thickness, h-inSetSize, w, h );
+
+ vgui::surface()->DrawFilledRect( 0, h-thickness, inSetSize, h );
+ vgui::surface()->DrawFilledRect( 0, h-inSetSize, thickness, h );
+}
+
+void CHudPlayerOverlaySelected::OnCursorEntered()
+{
+ if ( m_pBaseOverlay->GetMouseOverText() )
+ {
+ StatusPrint( TYPE_HINT, "%s", m_pBaseOverlay->GetMouseOverText() );
+ }
+}
+
+void CHudPlayerOverlaySelected::OnCursorExited()
+{
+ if ( m_pBaseOverlay->GetMouseOverText() )
+ {
+ StatusClear();
+ }
+} \ No newline at end of file
diff --git a/game/client/tf2/playeroverlayselected.h b/game/client/tf2/playeroverlayselected.h
new file mode 100644
index 0000000..723b2ee
--- /dev/null
+++ b/game/client/tf2/playeroverlayselected.h
@@ -0,0 +1,46 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $Workfile: $
+// $Date: $
+// $NoKeywords: $
+//=============================================================================//
+#if !defined( PLAYEROLVERLAYSELECTED_H )
+#define PLAYEROLVERLAYSELECTED_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "vgui_basepanel.h"
+
+class BitmapImage;
+class KeyValues;
+class CHudPlayerOverlay;
+class CHudPlayerOverlaySelected : public CBasePanel
+{
+public:
+ DECLARE_CLASS( CHudPlayerOverlaySelected, CBasePanel );
+
+ CHudPlayerOverlaySelected( CHudPlayerOverlay *baseOverlay );
+ virtual ~CHudPlayerOverlaySelected( void );
+
+ bool Init( KeyValues* pInitData );
+
+ void SetImages( BitmapImage *pImage[4] );
+
+ virtual void Paint( void );
+
+ virtual void OnCursorEntered();
+ virtual void OnCursorExited();
+
+
+private:
+ BitmapImage *m_pImages[4];
+
+ Color m_fgColor;
+ Color m_bgColor;
+ CHudPlayerOverlay *m_pBaseOverlay;
+};
+
+#endif // PLAYEROLVERLAYSELECTED_H \ No newline at end of file
diff --git a/game/client/tf2/playeroverlaysquad.cpp b/game/client/tf2/playeroverlaysquad.cpp
new file mode 100644
index 0000000..f646706
--- /dev/null
+++ b/game/client/tf2/playeroverlaysquad.cpp
@@ -0,0 +1,187 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $Workfile: $
+// $NoKeywords: $
+//=============================================================================//
+#include "cbase.h"
+#include <KeyValues.h>
+#include "playeroverlay.h"
+#include "playeroverlaysquad.h"
+#include <KeyValues.h>
+#include "panelmetaclassmgr.h"
+#include "hud_commander_statuspanel.h"
+#include <vgui/IScheme.h>
+#include <vgui/IVGui.h>
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *name -
+//-----------------------------------------------------------------------------
+CHudPlayerOverlaySquad::CHudPlayerOverlaySquad( CHudPlayerOverlay *baseOverlay, const char *squadname ) :
+vgui::Label( (vgui::Panel *)NULL, "OverlaySquad", squadname )
+{
+ m_pBaseOverlay = baseOverlay;
+
+ Q_strncpy( m_szSquad, squadname, sizeof( m_szSquad ) );
+
+ SetPaintBackgroundEnabled( false );
+
+ // Send mouse inputs (but not cursorenter/exit for now) up to parent
+ SetReflectMouse( true );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+CHudPlayerOverlaySquad::~CHudPlayerOverlaySquad( void )
+{
+}
+
+
+//-----------------------------------------------------------------------------
+// Initialization
+//-----------------------------------------------------------------------------
+bool CHudPlayerOverlaySquad::Init( KeyValues* pInitData )
+{
+ if (!pInitData)
+ return false;
+
+ SetContentAlignment( vgui::Label::a_west );
+
+ if (!ParseRGBA(pInitData, "fgcolor", m_fgColor ))
+ return false;
+
+ if (!ParseRGBA(pInitData, "bgcolor", m_bgColor))
+ return false;
+
+ int x, y, w, h;
+ if (!ParseRect(pInitData, "position", x, y, w, h ))
+ return false;
+ SetPos( x, y );
+ SetSize( w, h );
+
+ return true;
+}
+
+void CHudPlayerOverlaySquad::ApplySchemeSettings( vgui::IScheme *pScheme )
+{
+ BaseClass::ApplySchemeSettings( pScheme );
+ SetFont( pScheme->GetFont( "primary" ) );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *name -
+//-----------------------------------------------------------------------------
+void CHudPlayerOverlaySquad::SetSquad( const char *squadname )
+{
+ Q_strncpy( m_szSquad, squadname, sizeof( m_szSquad ) );
+ SetText( squadname );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CHudPlayerOverlaySquad::Paint()
+{
+ m_pBaseOverlay->SetColorLevel( this, m_fgColor, m_bgColor );
+
+ BaseClass::Paint();
+}
+
+void CHudPlayerOverlaySquad::SetReflectMouse( bool reflect )
+{
+ m_bReflectMouse = true;
+}
+
+void CHudPlayerOverlaySquad::OnCursorMoved(int x,int y)
+{
+ if ( !m_bReflectMouse )
+ return;
+
+ if ( !GetParent() )
+ return;
+
+ LocalToScreen( x, y );
+
+ vgui::ivgui()->PostMessage(
+ GetParent()->GetVPanel(),
+ new KeyValues( "CursorMoved", "xpos", x, "ypos", y ),
+ GetVPanel() );
+}
+
+void CHudPlayerOverlaySquad::OnMousePressed(vgui::MouseCode code)
+{
+ if ( !m_bReflectMouse )
+ return;
+
+ if ( !GetParent() )
+ return;
+
+ vgui::ivgui()->PostMessage(
+ GetParent()->GetVPanel(),
+ new KeyValues( "MousePressed", "code", code ),
+ GetVPanel() );
+}
+
+void CHudPlayerOverlaySquad::OnMouseDoublePressed(vgui::MouseCode code)
+{
+ if ( !m_bReflectMouse )
+ return;
+
+ if ( !GetParent() )
+ return;
+
+ vgui::ivgui()->PostMessage(
+ GetParent()->GetVPanel(),
+ new KeyValues( "MouseDoublePressed", "code", code ),
+ GetVPanel() );
+}
+
+void CHudPlayerOverlaySquad::OnMouseReleased(vgui::MouseCode code)
+{
+ if ( !m_bReflectMouse )
+ return;
+
+ if ( !GetParent() )
+ return;
+
+ vgui::ivgui()->PostMessage(
+ GetParent()->GetVPanel(),
+ new KeyValues( "MouseReleased", "code", code ),
+ GetVPanel() );
+}
+
+void CHudPlayerOverlaySquad::OnMouseWheeled(int delta)
+{
+ if ( !m_bReflectMouse )
+ return;
+
+ if ( !GetParent() )
+ return;
+
+ vgui::ivgui()->PostMessage(
+ GetParent()->GetVPanel(),
+ new KeyValues( "MouseWheeled", "delta", delta ),
+ GetVPanel() );
+}
+
+
+void CHudPlayerOverlaySquad::OnCursorEntered()
+{
+ if ( m_pBaseOverlay->GetMouseOverText() )
+ {
+ StatusPrint( TYPE_HINT, "%s", m_pBaseOverlay->GetMouseOverText() );
+ }
+}
+
+void CHudPlayerOverlaySquad::OnCursorExited()
+{
+ if ( m_pBaseOverlay->GetMouseOverText() )
+ {
+ StatusClear();
+ }
+} \ No newline at end of file
diff --git a/game/client/tf2/playeroverlaysquad.h b/game/client/tf2/playeroverlaysquad.h
new file mode 100644
index 0000000..b097c59
--- /dev/null
+++ b/game/client/tf2/playeroverlaysquad.h
@@ -0,0 +1,54 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $Workfile: $
+// $Date: $
+// $NoKeywords: $
+//=============================================================================//
+#if !defined( PLAYEROVERLAYSQUAD_H )
+#define PLAYEROVERLAYSQUAD_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include <vgui_controls/Label.h>
+
+class KeyValues;
+class CHudPlayerOverlay;
+class CHudPlayerOverlaySquad : public vgui::Label
+{
+public:
+ typedef vgui::Label BaseClass;
+
+ CHudPlayerOverlaySquad( CHudPlayerOverlay *baseOverlay, const char *squadname );
+ virtual ~CHudPlayerOverlaySquad( void );
+
+ bool Init( KeyValues* pInitData );
+
+ void SetSquad( const char *squadname );
+
+ virtual void Paint();
+ virtual void ApplySchemeSettings( vgui::IScheme *pScheme );
+ virtual void SetReflectMouse( bool reflect );
+ // If reflect mouse is true, then pass these up to parent
+ virtual void OnCursorMoved(int x,int y);
+ virtual void OnMousePressed(vgui::MouseCode code);
+ virtual void OnMouseDoublePressed(vgui::MouseCode code);
+ virtual void OnMouseReleased(vgui::MouseCode code);
+ virtual void OnMouseWheeled(int delta);
+
+ virtual void OnCursorEntered();
+ virtual void OnCursorExited();
+
+private:
+
+ char m_szSquad[ 64 ];
+ Color m_fgColor;
+ Color m_bgColor;
+ CHudPlayerOverlay *m_pBaseOverlay;
+
+ bool m_bReflectMouse;
+};
+
+#endif // PLAYEROVERLAYSQUAD_H \ No newline at end of file
diff --git a/game/client/tf2/proxy_objpower.cpp b/game/client/tf2/proxy_objpower.cpp
new file mode 100644
index 0000000..e9f36a9
--- /dev/null
+++ b/game/client/tf2/proxy_objpower.cpp
@@ -0,0 +1,56 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Proxy to hook into an object's powered state
+//
+//=============================================================================//
+
+#include "cbase.h"
+#include "materialsystem/imaterial.h"
+#include "materialsystem/imaterialsystem.h"
+#include <KeyValues.h>
+#include "materialsystem/imaterialvar.h"
+#include "C_BaseTFPlayer.h"
+#include "functionproxy.h"
+#include "c_baseobject.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+class CTFObjectPowerProxy : public CResultProxy
+{
+public:
+ virtual bool Init( IMaterial *pMaterial, KeyValues *pKeyValues );
+ virtual void OnBind( void *pEnt );
+};
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+bool CTFObjectPowerProxy::Init( IMaterial *pMaterial, KeyValues *pKeyValues )
+{
+ if ( !CResultProxy::Init( pMaterial, pKeyValues ) )
+ return false;
+
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFObjectPowerProxy::OnBind( void *pArg )
+{
+ C_BaseEntity *pEntity = BindArgToEntity( pArg );
+ if (!pEntity)
+ return;
+
+ C_BaseObject *pObject = dynamic_cast<C_BaseObject*>( pEntity );
+ Assert( pObject );
+
+ float flPoweredState = (float)(!pObject->IsBuilding() && !pObject->IsPlacing() && pObject->IsPowered());
+
+ Assert( m_pResult );
+ SetFloatResult( flPoweredState );
+}
+
+
+EXPOSE_INTERFACE( CTFObjectPowerProxy, IMaterialProxy, "TFObjectPower" IMATERIAL_PROXY_INTERFACE_VERSION );
diff --git a/game/client/tf2/proxy_shield.cpp b/game/client/tf2/proxy_shield.cpp
new file mode 100644
index 0000000..214a579
--- /dev/null
+++ b/game/client/tf2/proxy_shield.cpp
@@ -0,0 +1,313 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#include "cbase.h"
+#include "materialsystem/imaterial.h"
+#include "materialsystem/imaterialsystem.h"
+#include <KeyValues.h>
+#include "materialsystem/imaterialvar.h"
+#include "C_BaseTFPlayer.h"
+#include "functionproxy.h"
+#include "C_PlayerResource.h"
+#include "Weapon_CombatShield.h"
+
+// for the 2/5/03 demo
+#include "c_demo_entities.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+
+//-----------------------------------------------------------------------------
+// Shield proxy base class
+//-----------------------------------------------------------------------------
+class CTFShieldProxy : public CResultProxy
+{
+protected:
+ C_WeaponCombatShield *BindArgToShield( void *pArg );
+};
+
+
+//-----------------------------------------------------------------------------
+// Gets the shield
+//-----------------------------------------------------------------------------
+C_WeaponCombatShield *CTFShieldProxy::BindArgToShield( void *pArg )
+{
+ C_BaseEntity *pEntity = BindArgToEntity( pArg );
+ if (!pEntity)
+ return NULL;
+
+ if (dynamic_cast<C_BaseViewModel*>(pEntity))
+ {
+ // If this is the view model, snack the state from the local player...
+ C_BaseTFPlayer* pPlayer = C_BaseTFPlayer::GetLocalPlayer();
+ return pPlayer->GetShield();
+ }
+
+ if ( dynamic_cast<C_BaseTFPlayer*>(pEntity) )
+ {
+ C_BaseTFPlayer* pPlayer = dynamic_cast<C_BaseTFPlayer*>( pEntity );
+ return pPlayer->GetShield();
+ }
+
+ return dynamic_cast<C_WeaponCombatShield*>( pEntity );
+}
+
+
+//=============================================================================
+//
+// TF Shield raising proxy.
+//
+class CTFShieldRaiseProxy : public CTFShieldProxy
+{
+public:
+
+ virtual bool Init( IMaterial *pMaterial, KeyValues *pKeyValues );
+ virtual void OnBind( void *pEnt );
+
+private:
+ CFloatInput m_Factor;
+};
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+bool CTFShieldRaiseProxy::Init( IMaterial *pMaterial, KeyValues *pKeyValues )
+{
+ if ( !CResultProxy::Init( pMaterial, pKeyValues ) )
+ return false;
+
+ // Init shield raise times.
+ if ( !m_Factor.Init( pMaterial, pKeyValues, "scale", 1 ) )
+ return false;
+
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void CTFShieldRaiseProxy::OnBind( void *pArg )
+{
+ float flTimeSinceRaised = 0.0f;
+ C_WeaponCombatShield *pShield = BindArgToShield( pArg );
+ if (pShield)
+ {
+ flTimeSinceRaised = pShield->GetRaisingTime();
+ }
+
+ // Return the time in seconds from when we started raising.
+ SetFloatResult( flTimeSinceRaised * m_Factor.GetFloat() );
+}
+
+EXPOSE_INTERFACE( CTFShieldRaiseProxy, IMaterialProxy, "TFShieldRaise" IMATERIAL_PROXY_INTERFACE_VERSION );
+
+//=============================================================================
+//
+// TF Shield lowering proxy.
+//
+class CTFShieldLowerProxy : public CTFShieldProxy
+{
+public:
+
+ virtual bool Init( IMaterial *pMaterial, KeyValues *pKeyValues );
+ virtual void OnBind( void *pEnt );
+
+private:
+ CFloatInput m_Factor;
+};
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+bool CTFShieldLowerProxy::Init( IMaterial *pMaterial, KeyValues *pKeyValues )
+{
+ if ( !CResultProxy::Init( pMaterial, pKeyValues ) )
+ return false;
+
+ // Init shield raise times.
+ if ( !m_Factor.Init( pMaterial, pKeyValues, "scale", 1 ) )
+ return false;
+
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void CTFShieldLowerProxy::OnBind( void *pArg )
+{
+ float flTimeSinceLowered = 0.0f;
+ C_WeaponCombatShield *pShield = BindArgToShield( pArg );
+ if ( pShield )
+ {
+ flTimeSinceLowered = pShield->GetLoweringTime();
+ }
+ else
+ {
+ // NOTE: This is for the Feb 5 03 demo only
+ C_BaseEntity *pEntity = BindArgToEntity( pArg );
+ C_Cycler_TF2Commando *pDemoCommando = dynamic_cast<C_Cycler_TF2Commando*>( pEntity );
+ if (pDemoCommando)
+ {
+ flTimeSinceLowered = pDemoCommando->GetShieldLowerTime();
+ }
+ }
+
+ // Return the time in seconds from when we started lowering.
+ Assert( m_pResult );
+ SetFloatResult( flTimeSinceLowered * m_Factor.GetFloat() );
+
+// Msg( "Lowering = %f\n", flTimeSinceLowered );
+}
+
+EXPOSE_INTERFACE( CTFShieldLowerProxy, IMaterialProxy, "TFShieldLower" IMATERIAL_PROXY_INTERFACE_VERSION );
+
+//=============================================================================
+//
+// TF Shield raising proxy.
+//
+class CTFShieldVisibilityProxy : public CTFShieldProxy
+{
+public:
+ virtual bool Init( IMaterial *pMaterial, KeyValues *pKeyValues );
+ virtual void OnBind( void *pEnt );
+
+private:
+ CFloatInput m_RaiseFactor;
+ CFloatInput m_LowerFactor;
+};
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+bool CTFShieldVisibilityProxy::Init( IMaterial *pMaterial, KeyValues *pKeyValues )
+{
+ if ( !CResultProxy::Init( pMaterial, pKeyValues ) )
+ return false;
+
+ // Init shield raise times.
+ if ( !m_RaiseFactor.Init( pMaterial, pKeyValues, "raisescale", 1 ) )
+ return false;
+
+ if ( !m_LowerFactor.Init( pMaterial, pKeyValues, "lowerscale", 1 ) )
+ return false;
+
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void CTFShieldVisibilityProxy::OnBind( void *pArg )
+{
+ float flAlpha = 0.0f;
+ C_WeaponCombatShield *pShield = BindArgToShield( pArg );
+ if ( pShield )
+ {
+ if (pShield->GetRaisingTime() != 0.0f)
+ {
+ flAlpha = pShield->GetRaisingTime() * m_RaiseFactor.GetFloat();
+ flAlpha = clamp( flAlpha, 0, 1 );
+ }
+ else
+ {
+ flAlpha = 1.0f - pShield->GetLoweringTime() * m_LowerFactor.GetFloat();
+ flAlpha = clamp( flAlpha, 0, 1 );
+ }
+ }
+
+ // Return the time in seconds from when we started lowering.
+ Assert( m_pResult );
+ SetFloatResult( flAlpha );
+}
+
+EXPOSE_INTERFACE( CTFShieldVisibilityProxy, IMaterialProxy, "TFShieldVisibility" IMATERIAL_PROXY_INTERFACE_VERSION );
+
+
+//=============================================================================
+//
+// TF Shield active proxy.
+//
+class CTFShieldActiveProxy : public CTFShieldProxy
+{
+public:
+
+ virtual bool Init( IMaterial *pMaterial, KeyValues *pKeyValues );
+ virtual void OnBind( void *pEnt );
+};
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+bool CTFShieldActiveProxy::Init( IMaterial *pMaterial, KeyValues *pKeyValues )
+{
+ if ( !CResultProxy::Init( pMaterial, pKeyValues ) )
+ return false;
+
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void CTFShieldActiveProxy::OnBind( void *pArg )
+{
+ bool bIsShieldUp = false;
+ C_WeaponCombatShield *pShield = BindArgToShield( pArg );
+ if ( pShield )
+ {
+ bIsShieldUp = ( pShield->IsUp() == 1.0f );
+ }
+ else
+ {
+ // NOTE: This is for the Feb 5 03 demo only
+ C_BaseEntity *pEntity = BindArgToEntity( pArg );
+ C_Cycler_TF2Commando *pDemoCommando = dynamic_cast<C_Cycler_TF2Commando*>( pEntity );
+ if (pDemoCommando)
+ {
+ bIsShieldUp = pDemoCommando->IsShieldActive();
+ }
+ }
+
+ Assert( m_pResult );
+ SetFloatResult( ( float )bIsShieldUp );
+
+// Msg( "Active = %d\n", bIsShieldUp );
+}
+
+EXPOSE_INTERFACE( CTFShieldActiveProxy, IMaterialProxy, "TFShieldActive" IMATERIAL_PROXY_INTERFACE_VERSION );
+
+//=============================================================================
+//
+// TF Shield health proxy.
+//
+class CTFShieldHealthProxy : public CTFShieldProxy
+{
+public:
+
+ virtual bool Init( IMaterial *pMaterial, KeyValues *pKeyValues );
+ virtual void OnBind( void *pEnt );
+};
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+bool CTFShieldHealthProxy::Init( IMaterial *pMaterial, KeyValues *pKeyValues )
+{
+ if ( !CResultProxy::Init( pMaterial, pKeyValues ) )
+ return false;
+
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void CTFShieldHealthProxy::OnBind( void *pArg )
+{
+ float flShieldHealth = 1;
+ C_WeaponCombatShield *pShield = BindArgToShield( pArg );
+ if ( pShield )
+ {
+ flShieldHealth = pShield->GetShieldHealth();
+ }
+
+ Assert( m_pResult );
+ SetFloatResult( flShieldHealth );
+}
+
+EXPOSE_INTERFACE( CTFShieldHealthProxy, IMaterialProxy, "TFShieldHealth" IMATERIAL_PROXY_INTERFACE_VERSION );
diff --git a/game/client/tf2/proxy_sunroof.cpp b/game/client/tf2/proxy_sunroof.cpp
new file mode 100644
index 0000000..894bfbc
--- /dev/null
+++ b/game/client/tf2/proxy_sunroof.cpp
@@ -0,0 +1,72 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#include "cbase.h"
+#include "materialsystem/imaterial.h"
+#include "materialsystem/imaterialsystem.h"
+#include <KeyValues.h>
+#include "materialsystem/imaterialvar.h"
+#include "C_BaseTFPlayer.h"
+#include "functionproxy.h"
+#include "C_PlayerResource.h"
+#include "Weapon_CombatShield.h"
+
+// for the 2/5/03 demo
+#include "c_demo_entities.h"
+#include "c_basefourwheelvehicle.h"
+
+//=============================================================================
+//
+// TF Shield raising proxy.
+//
+class CTFSunroofProxy : public CResultProxy
+{
+public:
+
+ virtual bool Init( IMaterial *pMaterial, KeyValues *pKeyValues );
+ virtual void OnBind( void *pEnt );
+
+private:
+
+ CFloatInput m_Factor;
+};
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+
+bool CTFSunroofProxy::Init( IMaterial *pMaterial, KeyValues *pKeyValues )
+{
+ if ( !CResultProxy::Init( pMaterial, pKeyValues ) )
+ return false;
+
+ // Init shield raise times.
+ //if ( !m_Factor.Init( pMaterial, pKeyValues, "scale", 1 ) )
+ // return false;
+
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void CTFSunroofProxy::OnBind( void *pArg )
+{
+ C_BaseEntity *pEntity = BindArgToEntity( pArg );
+ C_BaseTFFourWheelVehicle* pVehicle = dynamic_cast<C_BaseTFFourWheelVehicle*>(pEntity);
+ if( !pVehicle )
+ return;
+
+ if( pVehicle->GetPassengerCount() )
+ {
+ SetFloatResult(0.f);
+ }
+ else
+ {
+ SetFloatResult(1.f);
+ }
+}
+
+EXPOSE_INTERFACE( CTFSunroofProxy, IMaterialProxy, "TFSunroof" IMATERIAL_PROXY_INTERFACE_VERSION );
diff --git a/game/client/tf2/resourcezoneoverlay.cpp b/game/client/tf2/resourcezoneoverlay.cpp
new file mode 100644
index 0000000..97a7d51
--- /dev/null
+++ b/game/client/tf2/resourcezoneoverlay.cpp
@@ -0,0 +1,249 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $Revision: $
+// $NoKeywords: $
+//=============================================================================//
+#include "cbase.h"
+#include <VGUI_EntityPanel.h>
+#include <KeyValues.h>
+#include "commanderoverlay.h"
+#include "clientmode_tfnormal.h"
+#include "tf_shareddefs.h"
+#include "shareddefs.h"
+#include "c_func_resource.h"
+#include "techtree.h"
+#include "c_basetfplayer.h"
+#include "vgui_HealthBar.h"
+#include "vgui_bitmapimage.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+class CResourceZoneOverlay : public CEntityPanel
+{
+ DECLARE_CLASS( CResourceZoneOverlay, CEntityPanel );
+
+public:
+ CResourceZoneOverlay( vgui::Panel *parent, const char *panelName );
+ virtual ~CResourceZoneOverlay( void );
+
+ bool Init( KeyValues* pKeyValues, C_BaseEntity* pEntity );
+ bool InitResourceBitmaps( KeyValues* pKeyValues );
+
+ void SetColor( int r, int g, int b, int a );
+ void SetImage( BitmapImage *pImage );
+
+ virtual void OnTick();
+
+ virtual void Paint( void );
+ virtual void PaintBackground( void ) {}
+
+private:
+ class CResourceBitmaps
+ {
+ public:
+ CResourceBitmaps() : m_pImage(0) {}
+
+ BitmapImage *m_pImage;
+ Color m_Color;
+ };
+
+ struct Rect_t
+ {
+ int x, y, w, h;
+ };
+
+ bool ParseSingleResourceBitmap( KeyValues *pKeyValues,
+ const char *pResourceName, CResourceBitmaps *pResourceBitmap );
+ bool ParseTeamResourceBitmaps( CResourceBitmaps *pT, KeyValues *pTeam );
+
+ int m_r, m_g, m_b, m_a;
+ CHealthBarPanel m_UsageBar;
+ Rect_t m_Icon;
+ C_ResourceZone *m_pResourceZone;
+ CResourceBitmaps m_pResourceBitmap;
+ BitmapImage *m_pImage;
+
+};
+
+
+//-----------------------------------------------------------------------------
+// Class factory
+//-----------------------------------------------------------------------------
+
+DECLARE_OVERLAY_FACTORY( CResourceZoneOverlay, "resourcezone" );
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+
+CResourceZoneOverlay::CResourceZoneOverlay( vgui::Panel *parent, const char *panelName )
+: BaseClass( parent, "CResourceZoneOverlay" )
+{
+ m_pImage = 0;
+ SetPaintBackgroundEnabled( false );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+
+CResourceZoneOverlay::~CResourceZoneOverlay( void )
+{
+ if ( m_pResourceBitmap.m_pImage )
+ {
+ delete m_pResourceBitmap.m_pImage;
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Parse class icons
+//-----------------------------------------------------------------------------
+
+bool CResourceZoneOverlay::ParseSingleResourceBitmap( KeyValues *pKeyValues,
+ const char *pResourceName, CResourceBitmaps *pResourceBitmap )
+{
+ const char *image;
+ KeyValues *pResource;
+ pResource = pKeyValues->FindKey( pResourceName );
+ if ( !pResource )
+ return false;
+
+ image = pResource->GetString( "material" );
+ if ( image && image[ 0 ] )
+ {
+ pResourceBitmap->m_pImage = new BitmapImage( GetVPanel(), image );
+ }
+ else
+ {
+ return( false );
+ }
+
+ return ParseRGBA( pResource, "color", pResourceBitmap->m_Color );
+}
+
+bool CResourceZoneOverlay::ParseTeamResourceBitmaps( CResourceBitmaps *pT, KeyValues *pTeam )
+{
+ if ( !ParseSingleResourceBitmap( pTeam, "Alpha", pT ) )
+ return false;
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// Initialization
+//-----------------------------------------------------------------------------
+
+bool CResourceZoneOverlay::InitResourceBitmaps( KeyValues* pKeyValues )
+{
+// char teamkey[ 128 ];
+// for (int i = 0; i < 3; ++i)
+// {
+// Q_snprintf( teamkey, sizeof( teamkey ), "Team%i", i );
+// KeyValues *pTeam = pKeyValues->getSection( teamkey );
+// if (pTeam)
+ {
+ if (!ParseTeamResourceBitmaps( &m_pResourceBitmap, pKeyValues ))
+ return false;
+ }
+// }
+
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// Initialization
+//-----------------------------------------------------------------------------
+
+bool CResourceZoneOverlay::Init( KeyValues* pKeyValues, C_BaseEntity* pEntity )
+{
+ if (!BaseClass::Init( pKeyValues, pEntity))
+ return false;
+
+ if (!pKeyValues)
+ return false;
+
+ // We gotta be attached to a resource zone
+ m_pResourceZone = dynamic_cast<C_ResourceZone*>(GetEntity());
+ if (!m_pResourceZone)
+ return false;
+
+ KeyValues* pUsage = pKeyValues->FindKey("Usage");
+ if (!m_UsageBar.Init( pUsage ))
+ return false;
+ m_UsageBar.SetParent( this );
+
+ // get the icon info...
+ if (!ParseRect( pKeyValues, "iconposition", m_Icon.x, m_Icon.y, m_Icon.w, m_Icon.h ))
+ return false;
+
+ if (!InitResourceBitmaps( pKeyValues ))
+ return false;
+
+ SetImage( 0 );
+ SetColor( m_pResourceBitmap.m_Color[0], m_pResourceBitmap.m_Color[1], m_pResourceBitmap.m_Color[2], m_pResourceBitmap.m_Color[3] );
+
+ // we need updating
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+// called when we're ticked...
+//-----------------------------------------------------------------------------
+
+void CResourceZoneOverlay::OnTick()
+{
+ // Update position
+ CEntityPanel::OnTick();
+
+ SetImage( m_pResourceBitmap.m_pImage );
+ int r, g, b, a;
+ m_pResourceBitmap.m_Color.GetColor( r, g, b, a );
+ SetColor( r, g, b, a );
+
+ m_UsageBar.SetHealth( m_pResourceZone->m_flClientResources );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : pImage - Class specific image
+//-----------------------------------------------------------------------------
+
+void CResourceZoneOverlay::SetImage( BitmapImage *pImage )
+{
+ m_pImage = pImage;
+}
+
+//-----------------------------------------------------------------------------
+// Sets the draw color
+//-----------------------------------------------------------------------------
+
+void CResourceZoneOverlay::SetColor( int r, int g, int b, int a )
+{
+ m_r = r;
+ m_g = g;
+ m_b = b;
+ m_a = a;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+
+void CResourceZoneOverlay::Paint( void )
+{
+ if ( !m_pImage )
+ return;
+
+ ComputeAndSetSize();
+
+ Color color;
+ color.SetColor( m_r, m_g, m_b, m_a );
+ m_pImage->SetPos( m_Icon.x, m_Icon.y );
+ m_pImage->SetColor( color );
+ m_pImage->DoPaint( GetVPanel() );
+} \ No newline at end of file
diff --git a/game/client/tf2/teammaterialproxy.cpp b/game/client/tf2/teammaterialproxy.cpp
new file mode 100644
index 0000000..9fcc923
--- /dev/null
+++ b/game/client/tf2/teammaterialproxy.cpp
@@ -0,0 +1,71 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+#include "cbase.h"
+#include "proxyentity.h"
+#include "materialsystem/imaterial.h"
+#include "materialsystem/imaterialvar.h"
+#include "c_team.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+// $sineVar : name of variable that controls the alpha level (float)
+class CTeamMaterialProxy : public CEntityMaterialProxy
+{
+public:
+ CTeamMaterialProxy();
+ virtual ~CTeamMaterialProxy();
+ virtual bool Init( IMaterial *pMaterial, KeyValues* pKeyValues );
+ virtual void OnBind( C_BaseEntity *pEnt );
+
+private:
+ IMaterialVar* m_FrameVar;
+};
+
+
+//-----------------------------------------------------------------------------
+// Constructor, destructor
+//-----------------------------------------------------------------------------
+
+CTeamMaterialProxy::CTeamMaterialProxy()
+{
+ m_FrameVar = 0;
+}
+
+CTeamMaterialProxy::~CTeamMaterialProxy()
+{
+}
+
+
+//-----------------------------------------------------------------------------
+// Init baby...
+//-----------------------------------------------------------------------------
+bool CTeamMaterialProxy::Init( IMaterial *pMaterial, KeyValues* pKeyValues )
+{
+ bool foundVar;
+ m_FrameVar = pMaterial->FindVar( "$frame", &foundVar, false );
+ if( !foundVar )
+ m_FrameVar = 0;
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// Set the appropriate texture...
+//-----------------------------------------------------------------------------
+void CTeamMaterialProxy::OnBind( C_BaseEntity *pEnt )
+{
+ if( !m_FrameVar )
+ return;
+
+ int team = pEnt->GetRenderTeamNumber();
+ team--;
+
+ // Use that as an animated frame number
+ m_FrameVar->SetIntValue( team );
+}
+
+EXPOSE_INTERFACE( CTeamMaterialProxy, IMaterialProxy, "TeamTexture" IMATERIAL_PROXY_INTERFACE_VERSION );
diff --git a/game/client/tf2/tf_clientmode.cpp b/game/client/tf2/tf_clientmode.cpp
new file mode 100644
index 0000000..5f125b2
--- /dev/null
+++ b/game/client/tf2/tf_clientmode.cpp
@@ -0,0 +1,188 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+//=============================================================================//
+#include "cbase.h"
+#include "hud.h"
+#include "hud_macros.h"
+#include "clientmode_tfnormal.h"
+#include "clientmode.h"
+#include "clientmode_commander.h"
+#include "ivmodemanager.h"
+#include "hud_timer.h"
+#include "hud_technologytreedoc.h"
+#include "CommanderOverlay.h"
+#include "c_tf2rootpanel.h"
+#include "c_info_act.h"
+
+// default FOV for TF2
+ConVar default_fov( "default_fov", "90", FCVAR_CHEAT );
+
+//-----------------------------------------------------------------------------
+// Purpose: Handles switching to/from commander mode
+//-----------------------------------------------------------------------------
+class CTFModeManager : public IVModeManager
+{
+public:
+ virtual void Init( void );
+ virtual void SwitchMode( bool commander, bool force );
+ virtual void LevelInit( const char *newmap );
+ virtual void LevelShutdown( void );
+
+ CTFModeManager( void );
+ virtual ~CTFModeManager( void );
+
+ void UserCmd_Commander( void );
+ void UserCmd_Normal( void );
+
+};
+
+static CTFModeManager g_ModeManager;
+IVModeManager *modemanager = ( IVModeManager * )&g_ModeManager;
+
+// The current client mode. Always ClientModeNormal in HL.
+IClientMode *g_pClientMode = NULL;
+
+DECLARE_COMMAND( g_ModeManager, Commander );
+DECLARE_COMMAND( g_ModeManager, Normal );
+
+HOOK_COMMAND( commander, Commander );
+HOOK_COMMAND( normal, Normal );
+
+void __MsgFunc_ActBegin(bf_read &msg);
+void __MsgFunc_ActEnd(bf_read &msg);
+
+#define MINIMAP_FILE "scripts/minimap_overlays.txt"
+#define SCREEN_FILE "scripts/vgui_screens.txt"
+
+//-----------------------------------------------------------------------------
+// Purpose: Intialize the mode manager
+//-----------------------------------------------------------------------------
+void CTFModeManager::Init( void )
+{
+ g_pClientMode = ClientModeCommander();
+ g_pClientMode = GetClientModeNormal();
+
+ // These define the panels that can be used by the engine
+ PanelMetaClassMgr()->LoadMetaClassDefinitionFile( MINIMAP_FILE );
+ PanelMetaClassMgr()->LoadMetaClassDefinitionFile( SCREEN_FILE );
+
+ // FIXME: Turn these into client systems
+ HudCommanderOverlayMgr()->GameInit();
+ MapData().Init();
+ GetTechnologyTreeDoc().Init();
+
+ HOOK_MESSAGE( ActBegin );
+ HOOK_MESSAGE( ActEnd );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Output :
+//-----------------------------------------------------------------------------
+CTFModeManager::CTFModeManager( void )
+{
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Output :
+//-----------------------------------------------------------------------------
+CTFModeManager::~CTFModeManager( void )
+{
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFModeManager::UserCmd_Commander( void )
+{
+ engine->ServerCmd( "tactical 1\n" );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFModeManager::UserCmd_Normal( void )
+{
+ engine->ServerCmd( "tactical 0\n" );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Switch to / from commander mode ( won't change if current mode is already
+// correct
+// Input : commander -
+//-----------------------------------------------------------------------------
+void CTFModeManager::SwitchMode( bool commander, bool force )
+{
+ if ( commander && ( ( g_pClientMode != ClientModeCommander() ) || force ) )
+ {
+ g_pClientMode->Disable();
+ g_pClientMode = ClientModeCommander();
+ g_pClientMode->Enable();
+ }
+ else if ( !commander && ( ( g_pClientMode != GetClientModeNormal() ) || force ) )
+ {
+ g_pClientMode->Disable();
+ g_pClientMode = GetClientModeNormal();
+ g_pClientMode->Enable();
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *newmap -
+//-----------------------------------------------------------------------------
+void CTFModeManager::LevelInit( const char *newmap )
+{
+ GetTechnologyTreeDoc().LevelInit();
+ g_pTF2RootPanel->LevelInit();
+
+ CHudTimer *timer = GET_HUDELEMENT( CHudTimer );
+ if ( timer )
+ {
+ timer->Init();
+ }
+
+ // Tell all modes about the map change
+ ClientModeCommander()->LevelInit( newmap );
+ GetClientModeNormal()->LevelInit( newmap );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFModeManager::LevelShutdown( void )
+{
+ GetClientModeNormal()->LevelShutdown();
+ ClientModeCommander()->LevelShutdown();
+
+ g_pTF2RootPanel->LevelShutdown();
+ GetTechnologyTreeDoc().LevelShutdown();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: A new act has just begun
+//-----------------------------------------------------------------------------
+void __MsgFunc_ActBegin(bf_read &msg)
+{
+ int iActNumber = (char)msg.ReadByte();
+ float flStartTime = msg.ReadFloat();
+
+ StartAct( iActNumber, flStartTime );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: An act has just ended
+//-----------------------------------------------------------------------------
+void __MsgFunc_ActEnd(bf_read &msg)
+{
+ CHudTimer *timer = GET_HUDELEMENT( CHudTimer );
+ if ( timer )
+ {
+ timer->SetNoFixedTimer( 0.0f );
+ }
+}
diff --git a/game/client/tf2/tf_in_main.cpp b/game/client/tf2/tf_in_main.cpp
new file mode 100644
index 0000000..f7ccd63
--- /dev/null
+++ b/game/client/tf2/tf_in_main.cpp
@@ -0,0 +1,36 @@
+//========= 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 CTFInput : public CInput
+{
+public:
+ int GetButtonBits( int );
+};
+
+static CTFInput g_Input;
+
+// Expose this interface
+IInput *input = ( IInput * )&g_Input;
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Remove Jump from the input bits
+//-----------------------------------------------------------------------------
+int CTFInput::GetButtonBits( int bResetState )
+{
+ int iBits = CInput::GetButtonBits( bResetState );
+
+ //iBits &= ~IN_JUMP;
+
+ return iBits;
+}
diff --git a/game/client/tf2/tf_prediction.cpp b/game/client/tf2/tf_prediction.cpp
new file mode 100644
index 0000000..8ab5608
--- /dev/null
+++ b/game/client/tf2/tf_prediction.cpp
@@ -0,0 +1,245 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+#include "cbase.h"
+#include "prediction.h"
+#include "tf_movedata.h"
+#include "c_basetfplayer.h"
+#include "c_tf_class_recon.h"
+#include "c_tf_class_commando.h"
+
+static CTFMoveData g_TFMoveData;
+CMoveData *g_pMoveData = &g_TFMoveData;
+
+
+class CTFPrediction : public CPrediction
+{
+DECLARE_CLASS( CTFPrediction, CPrediction );
+
+public:
+ virtual void SetupMove( C_BasePlayer *player, CUserCmd *ucmd, IMoveHelper *pHelper, CMoveData *move );
+ virtual void FinishMove( C_BasePlayer *player, CUserCmd *ucmd, CMoveData *move );
+
+private:
+
+ void SetupMoveRecon( CUserCmd *ucmd, C_BaseTFPlayer *pTFPlayer, IMoveHelper *pHelper,
+ CTFMoveData *pTFMove );
+ void SetupMoveCommando( CUserCmd *ucmd, C_BaseTFPlayer *pTFPlayer, IMoveHelper *pHelper,
+ CTFMoveData *pTFMove );
+
+ void FinishMoveRecon( CTFMoveData *pTFMove, C_BaseTFPlayer *pTFPlayer );
+ void FinishMoveCommando( CTFMoveData *pTFMove, C_BaseTFPlayer *pTFPlayer );
+};
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFPrediction::SetupMove( C_BasePlayer *player, CUserCmd *ucmd, IMoveHelper *pHelper,
+ CMoveData *move )
+{
+ // Call the default SetupMove code.
+ BaseClass::SetupMove( player, ucmd, pHelper, move );
+
+ //
+ // Convert to TF2 data.
+ //
+ C_BaseTFPlayer *pTFPlayer = static_cast<C_BaseTFPlayer*>( player );
+ Assert( pTFPlayer );
+
+ CTFMoveData *pTFMove = static_cast<CTFMoveData*>( move );
+ Assert( pTFMove );
+
+ //
+ // Handle player class specific setup.
+ //
+ pTFMove->m_nClassID = pTFPlayer->PlayerClass();
+ switch( pTFPlayer->GetClass() )
+ {
+ case TFCLASS_RECON:
+ {
+ SetupMoveRecon( ucmd, pTFPlayer, pHelper, pTFMove );
+ break;
+ }
+ case TFCLASS_COMMANDO:
+ {
+ SetupMoveCommando( ucmd, pTFPlayer, pHelper, pTFMove );
+ break;
+ }
+ default:
+ {
+// pTFMove->m_nClassID = TFCLASS_UNDECIDED;
+ break;
+ }
+ }
+
+ //
+ // Player movement data.
+ //
+
+ // Copy the position delta.
+ pTFMove->m_vecPosDelta = pTFPlayer->m_vecPosDelta;
+
+ // Copy the momentum data.
+ pTFMove->m_iMomentumHead = pTFPlayer->m_iMomentumHead;
+ for ( int iMomentum = 0; iMomentum < CTFMoveData::MOMENTUM_MAXSIZE; iMomentum++ )
+ {
+ pTFMove->m_aMomentum[iMomentum] = pTFPlayer->m_aMomentum[iMomentum];
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFPrediction::SetupMoveRecon( CUserCmd *ucmd, C_BaseTFPlayer *pTFPlayer, IMoveHelper *pHelper,
+ CTFMoveData *pTFMove )
+{
+ C_PlayerClassRecon *pRecon = static_cast<C_PlayerClassRecon*>( pTFPlayer->GetPlayerClass() );
+ if ( pRecon )
+ {
+ PlayerClassReconData_t *pReconData = pRecon->GetClassData();
+ if ( pReconData )
+ {
+ pTFMove->ReconData().m_nJumpCount = pReconData->m_nJumpCount;
+ pTFMove->ReconData().m_flSuppressionJumpTime = pReconData->m_flSuppressionJumpTime;
+ pTFMove->ReconData().m_flSuppressionImpactTime = pReconData->m_flSuppressionImpactTime;
+ pTFMove->ReconData().m_flActiveJumpTime = pReconData->m_flActiveJumpTime;
+ pTFMove->ReconData().m_flStickTime = pReconData->m_flStickTime;
+ pTFMove->ReconData().m_flImpactDist = pReconData->m_flImpactDist;
+ pTFMove->ReconData().m_vecImpactNormal = pReconData->m_vecImpactNormal;
+ pTFMove->ReconData().m_vecUnstickVelocity = pReconData->m_vecUnstickVelocity;
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFPrediction::SetupMoveCommando( CUserCmd *ucmd, C_BaseTFPlayer *pTFPlayer, IMoveHelper *pHelper,
+ CTFMoveData *pTFMove )
+{
+ C_PlayerClassCommando *pCommando = static_cast<C_PlayerClassCommando*>( pTFPlayer->GetPlayerClass() );
+ if ( pCommando )
+ {
+ PlayerClassCommandoData_t *pCommandoData = pCommando->GetClassData();
+ if ( pCommandoData )
+ {
+ pTFMove->CommandoData().m_bCanBullRush = pCommandoData->m_bCanBullRush;
+ pTFMove->CommandoData().m_bBullRush = pCommandoData->m_bBullRush;
+ pTFMove->CommandoData().m_vecBullRushDir = pCommandoData->m_vecBullRushDir;
+ pTFMove->CommandoData().m_vecBullRushViewDir = pCommandoData->m_vecBullRushViewDir;
+ pTFMove->CommandoData().m_vecBullRushViewGoalDir = pCommandoData->m_vecBullRushViewGoalDir;
+ pTFMove->CommandoData().m_flBullRushTime = pCommandoData->m_flBullRushTime;
+ pTFMove->CommandoData().m_flDoubleTapForwardTime = pCommandoData->m_flDoubleTapForwardTime;
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFPrediction::FinishMove( C_BasePlayer *player, CUserCmd *ucmd, CMoveData *move )
+{
+ // Call the default FinishMove code.
+ BaseClass::FinishMove( player, ucmd, move );
+
+ //
+ // Convert to TF2 data.
+ //
+ C_BaseTFPlayer *pTFPlayer = static_cast<C_BaseTFPlayer*>( player );
+ Assert( pTFPlayer );
+
+ CTFMoveData *pTFMove = static_cast<CTFMoveData*>( move );
+ Assert( pTFMove );
+
+ //
+ // Handle player class specific setup.
+ //
+ switch( pTFPlayer->PlayerClass() )
+ {
+ case TFCLASS_RECON:
+ {
+ FinishMoveRecon( pTFMove, pTFPlayer );
+ break;
+ }
+ case TFCLASS_COMMANDO:
+ {
+ FinishMoveCommando( pTFMove, pTFPlayer );
+ break;
+ }
+ default:
+ {
+ break;
+ }
+ }
+
+ //
+ // Player movement data.
+ //
+
+ // Copy the position delta.
+ pTFPlayer->m_vecPosDelta = pTFMove->m_vecPosDelta;
+
+ // Copy the momentum data back (the movement may have updated it!).
+ pTFPlayer->m_iMomentumHead = pTFMove->m_iMomentumHead;
+ for ( int iMomentum = 0; iMomentum < CTFMoveData::MOMENTUM_MAXSIZE; iMomentum++ )
+ {
+ pTFPlayer->m_aMomentum[iMomentum] = pTFMove->m_aMomentum[iMomentum];
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFPrediction::FinishMoveRecon( CTFMoveData *pTFMove, C_BaseTFPlayer *pTFPlayer )
+{
+ C_PlayerClassRecon *pRecon = static_cast<C_PlayerClassRecon*>( pTFPlayer->GetPlayerClass() );
+ if ( pRecon )
+ {
+ PlayerClassReconData_t *pReconData = pRecon->GetClassData();
+ if ( pReconData )
+ {
+ pReconData->m_nJumpCount = pTFMove->ReconData().m_nJumpCount;
+ pReconData->m_flSuppressionJumpTime = pTFMove->ReconData().m_flSuppressionJumpTime;
+ pReconData->m_flSuppressionImpactTime = pTFMove->ReconData().m_flSuppressionImpactTime;
+ pReconData->m_flActiveJumpTime = pTFMove->ReconData().m_flActiveJumpTime;
+ pReconData->m_flStickTime = pTFMove->ReconData().m_flStickTime;
+ pReconData->m_flImpactDist = pTFMove->ReconData().m_flImpactDist;
+ pReconData->m_vecImpactNormal = pTFMove->ReconData().m_vecImpactNormal;
+ pReconData->m_vecUnstickVelocity = pTFMove->ReconData().m_vecUnstickVelocity;
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFPrediction::FinishMoveCommando( CTFMoveData *pTFMove, C_BaseTFPlayer *pTFPlayer )
+{
+ C_PlayerClassCommando *pCommando = static_cast<C_PlayerClassCommando*>( pTFPlayer->GetPlayerClass() );
+ if ( pCommando )
+ {
+ PlayerClassCommandoData_t *pCommandoData = pCommando->GetClassData();
+ if ( pCommandoData )
+ {
+ pCommandoData->m_bCanBullRush = pTFMove->CommandoData().m_bCanBullRush;
+ pCommandoData->m_bBullRush = pTFMove->CommandoData().m_bBullRush;
+ pCommandoData->m_vecBullRushDir = pTFMove->CommandoData().m_vecBullRushDir;
+ pCommandoData->m_vecBullRushViewDir = pTFMove->CommandoData().m_vecBullRushViewDir;
+ pCommandoData->m_vecBullRushViewGoalDir = pTFMove->CommandoData().m_vecBullRushViewGoalDir;
+ pCommandoData->m_flBullRushTime = pTFMove->CommandoData().m_flBullRushTime;
+ pCommandoData->m_flDoubleTapForwardTime = pTFMove->CommandoData().m_flDoubleTapForwardTime;
+ }
+ }
+}
+
+// Expose interface to engine
+// Expose interface to engine
+static CTFPrediction g_Prediction;
+
+EXPOSE_SINGLE_INTERFACE_GLOBALVAR( CTFPrediction, IPrediction, VCLIENT_PREDICTION_INTERFACE_VERSION, g_Prediction );
+
+CPrediction *prediction = &g_Prediction;
+
diff --git a/game/client/tf2/vgui_healthbar.cpp b/game/client/tf2/vgui_healthbar.cpp
new file mode 100644
index 0000000..83e9768
--- /dev/null
+++ b/game/client/tf2/vgui_healthbar.cpp
@@ -0,0 +1,134 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $Workfile: $
+// $Date: $
+// $NoKeywords: $
+//=============================================================================//
+#include "cbase.h"
+#include "vgui_HealthBar.h"
+#include "CommanderOverlay.h"
+#include <vgui_controls/Controls.h>
+#include <vgui/ISurface.h>
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Output :
+//-----------------------------------------------------------------------------
+CHealthBarPanel::CHealthBarPanel( vgui::Panel *pParent ) : vgui::Panel(pParent, "CHealthBarPanel" )
+{
+ SetHealth( 0.0f );
+ SetPaintBackgroundEnabled( false );
+ SetVertical( false );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+CHealthBarPanel::~CHealthBarPanel( void )
+{
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Parse values from the file
+//-----------------------------------------------------------------------------
+bool CHealthBarPanel::Init( KeyValues* pInitData )
+{
+ if (!pInitData)
+ return false;
+
+ if (!ParseRGBA(pInitData, "okcolor", m_Ok ))
+ return false;
+
+ if (!ParseRGBA(pInitData, "badcolor", m_Bad ))
+ return false;
+
+ int x, y, w, h;
+ if (!ParseRect(pInitData, "position", x, y, w, h ))
+ return false;
+ SetPos( x, y );
+ SetSize( w, h );
+ SetCursor( NULL );
+
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CHealthBarPanel::SetGoodColor( int r, int g, int b, int a )
+{
+ m_Ok.SetColor( r,g,b,a );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CHealthBarPanel::SetBadColor( int r, int g, int b, int a )
+{
+ m_Bad.SetColor( r,g,b,a );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CHealthBarPanel::SetHealth( float health )
+{
+ m_Health = health;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CHealthBarPanel::SetVertical( bool bVertical )
+{
+ m_bVertical = bVertical;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CHealthBarPanel::Paint( void )
+{
+ int w, h;
+ GetSize( w, h );
+
+ float frac;
+ frac = MIN( 1.0, m_Health );
+ frac = MAX( 0.0, m_Health );
+
+ vgui::surface()->DrawSetColor( 255,255,255,255 );
+ vgui::surface()->DrawOutlinedRect( 0,0, w,h );
+
+ int drawwidth = frac * w;
+ int drawheight = frac * h;
+
+ // Draw the Ok section
+ vgui::surface()->DrawSetColor( m_Ok[0], m_Ok[1], m_Ok[2], m_Ok[3] );
+ if ( m_bVertical )
+ {
+ vgui::surface()->DrawFilledRect( 0, h - drawheight, w, h );
+ }
+ else
+ {
+ vgui::surface()->DrawFilledRect( 0, 0, drawwidth, h );
+ }
+
+ vgui::surface()->DrawSetColor( m_Bad[0], m_Bad[1], m_Bad[2], m_Bad[3] );
+ // Draw the Bad section
+ if ( m_bVertical )
+ {
+ if (h != drawheight)
+ {
+ vgui::surface()->DrawFilledRect( 0, 0, w, h - drawheight );
+ }
+ }
+ else
+ {
+ if (w != drawwidth)
+ {
+ vgui::surface()->DrawFilledRect( drawwidth, 0, w, h );
+ }
+ }
+} \ No newline at end of file
diff --git a/game/client/tf2/vgui_healthbar.h b/game/client/tf2/vgui_healthbar.h
new file mode 100644
index 0000000..4b68f26
--- /dev/null
+++ b/game/client/tf2/vgui_healthbar.h
@@ -0,0 +1,46 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $Workfile: $
+// $Date: $
+// $NoKeywords: $
+//=============================================================================//
+#ifndef VGUI_HEALTHBAR_H
+#define VGUI_HEALTHBAR_H
+
+#ifdef _WIN32
+#pragma once
+#endif
+
+
+#include <vgui_controls/Panel.h>
+
+class KeyValues;
+
+class CHealthBarPanel : public vgui::Panel
+{
+public:
+ CHealthBarPanel( vgui::Panel *pParent = NULL );
+ virtual ~CHealthBarPanel( void );
+
+ // Setup
+ bool Init( KeyValues* pInitData );
+ void SetGoodColor( int r, int g, int b, int a );
+ void SetBadColor( int r, int g, int b, int a );
+ void SetVertical( bool bVertical );
+
+ // Health is expected to go from 0 to 1
+ void SetHealth( float health );
+
+ virtual void Paint( void );
+ virtual void PaintBackground( void ) {}
+
+private:
+ float m_Health;
+ Color m_Ok;
+ Color m_Bad;
+ bool m_bVertical; // True if this bar should be vertical
+};
+
+#endif // VGUI_HEALTHBAR_H \ No newline at end of file
diff --git a/game/client/tf2/vgui_rootpanel_tf2.cpp b/game/client/tf2/vgui_rootpanel_tf2.cpp
new file mode 100644
index 0000000..b6bc6c9
--- /dev/null
+++ b/game/client/tf2/vgui_rootpanel_tf2.cpp
@@ -0,0 +1,41 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+#include "cbase.h"
+#include "vgui_int.h"
+#include "ienginevgui.h"
+#include "c_tf2rootpanel.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+C_TF2RootPanel *g_pTF2RootPanel = NULL;
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void VGUI_CreateClientDLLRootPanel( void )
+{
+ g_pTF2RootPanel = new C_TF2RootPanel( enginevgui->GetPanel( PANEL_CLIENTDLL ) );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void VGUI_DestroyClientDLLRootPanel( void )
+{
+ delete g_pTF2RootPanel;
+ g_pTF2RootPanel = NULL;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Game specific root panel
+// Output : vgui::Panel
+//-----------------------------------------------------------------------------
+vgui::VPANEL VGui_GetClientDLLRootPanel( void )
+{
+ return g_pTF2RootPanel->GetVPanel();
+} \ No newline at end of file
diff --git a/game/client/tf2/vgui_rotation_slider.cpp b/game/client/tf2/vgui_rotation_slider.cpp
new file mode 100644
index 0000000..e1ee1e6
--- /dev/null
+++ b/game/client/tf2/vgui_rotation_slider.cpp
@@ -0,0 +1,74 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#include "cbase.h"
+#include <vgui/MouseCode.h>
+#include "vgui_rotation_slider.h"
+
+
+CRotationSlider::CRotationSlider( vgui::Panel *pParent, const char *pName ) :
+ BaseClass( pParent, pName )
+{
+ AddActionSignalTarget( this );
+ SetRange( -180, 180 );
+ SetTickCaptions("-180", "180");
+ SetValue( 0 );
+ m_flYaw = 0;
+}
+
+void CRotationSlider::SetControlledObject( C_BaseObject *pObject )
+{
+ m_hObject.Set( pObject );
+}
+
+//-----------------------------------------------------------------------------
+// When the slider is activated, deactivated, or moves
+//-----------------------------------------------------------------------------
+void CRotationSlider::OnMousePressed( vgui::MouseCode code )
+{
+ BaseClass::OnMousePressed( code );
+
+ if (code != vgui::MOUSE_LEFT)
+ return;
+
+ C_BaseObject *pObj = m_hObject.Get();
+ if (pObj)
+ {
+ m_flInitialYaw = pObj->GetAbsAngles().y;
+ pObj->PreviewYaw( m_flInitialYaw );
+ pObj->ActivateYawPreview( true );
+ }
+}
+
+void CRotationSlider::OnSliderMoved( int position )
+{
+ C_BaseObject *pObj = m_hObject.Get();
+ if (pObj && pObj->IsPreviewingYaw())
+ {
+ m_flYaw = anglemod(position);
+ pObj->PreviewYaw( m_flInitialYaw - m_flYaw );
+ }
+}
+
+void CRotationSlider::OnMouseReleased( vgui::MouseCode code )
+{
+ BaseClass::OnMouseReleased( code );
+
+ if (code != vgui::MOUSE_LEFT)
+ return;
+
+ C_BaseObject *pObj = m_hObject.Get();
+ if (pObj)
+ {
+ char szbuf[48];
+ Q_snprintf( szbuf, sizeof( szbuf ), "yaw %0.2f\n", m_flInitialYaw - m_flYaw );
+ pObj->SendClientCommand( szbuf );
+ pObj->ActivateYawPreview( false );
+ SetValue(0);
+ m_flYaw = 0;
+ }
+}
diff --git a/game/client/tf2/vgui_rotation_slider.h b/game/client/tf2/vgui_rotation_slider.h
new file mode 100644
index 0000000..549068a
--- /dev/null
+++ b/game/client/tf2/vgui_rotation_slider.h
@@ -0,0 +1,43 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef VGUI_ROTATION_SLIDER_H
+#define VGUI_ROTATION_SLIDER_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+
+#include <vgui_controls/Slider.h>
+#include "c_baseobject.h"
+
+
+//-----------------------------------------------------------------------------
+//
+// Slider for object control
+//
+//-----------------------------------------------------------------------------
+class CRotationSlider : public vgui::Slider
+{
+ DECLARE_CLASS_SIMPLE( CRotationSlider, vgui::Slider );
+
+public:
+ CRotationSlider( vgui::Panel *pParent, const char *pName );
+ void SetControlledObject( C_BaseObject *pObject );
+
+ virtual void OnMousePressed( vgui::MouseCode code );
+ virtual void OnMouseReleased( vgui::MouseCode code );
+ MESSAGE_FUNC_INT( OnSliderMoved, "SliderMoved", position );
+
+private:
+ CHandle<C_BaseObject> m_hObject;
+ float m_flInitialYaw;
+ float m_flYaw;
+};
+
+
+#endif // VGUI_ROTATION_SLIDER_H
diff --git a/game/client/tf2/ztestmaterialproxy.cpp b/game/client/tf2/ztestmaterialproxy.cpp
new file mode 100644
index 0000000..102cd34
--- /dev/null
+++ b/game/client/tf2/ztestmaterialproxy.cpp
@@ -0,0 +1,64 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+#include "cbase.h"
+#include "materialsystem/imaterialproxy.h"
+#include "materialsystem/imaterial.h"
+#include "materialsystem/imaterialvar.h"
+
+// $sineVar : name of variable that controls the alpha level (float)
+class CzTestMaterialProxy : public IMaterialProxy
+{
+public:
+ CzTestMaterialProxy();
+ virtual ~CzTestMaterialProxy();
+ virtual bool Init( IMaterial *pMaterial, KeyValues *pKeyValues );
+ virtual void OnBind( void *pC_BaseEntity );
+ virtual void Release( void ) { delete this; }
+private:
+ C_BaseEntity *BindArgToEntity( void *pArg );
+
+ IMaterialVar *m_AlphaVar;
+};
+
+CzTestMaterialProxy::CzTestMaterialProxy()
+{
+ m_AlphaVar = NULL;
+}
+
+CzTestMaterialProxy::~CzTestMaterialProxy()
+{
+}
+
+C_BaseEntity *CzTestMaterialProxy::BindArgToEntity( void *pArg )
+{
+ IClientRenderable *pRend = (IClientRenderable *)pArg;
+ return pRend->GetIClientUnknown()->GetBaseEntity();
+}
+
+bool CzTestMaterialProxy::Init( IMaterial *pMaterial, KeyValues *pKeyValues )
+{
+ bool foundVar;
+ m_AlphaVar = pMaterial->FindVar( "$alpha", &foundVar, false );
+ return foundVar;
+}
+
+void CzTestMaterialProxy::OnBind( void *pC_BaseEntity )
+{
+ C_BaseEntity *pEnt = BindArgToEntity( pC_BaseEntity );
+ if( !pEnt )
+ {
+ return;
+ }
+
+ if (m_AlphaVar)
+ {
+ m_AlphaVar->SetFloatValue( pEnt->m_clrRender.a );
+ }
+
+}
+
+EXPOSE_INTERFACE( CzTestMaterialProxy, IMaterialProxy, "zTest" IMATERIAL_PROXY_INTERFACE_VERSION );